| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Eve::HttpDispatcher; |
|
2
|
|
|
|
|
|
|
|
|
3
|
8
|
|
|
8
|
|
50
|
use parent qw(Eve::Class); |
|
|
8
|
|
|
|
|
18
|
|
|
|
8
|
|
|
|
|
82
|
|
|
4
|
|
|
|
|
|
|
|
|
5
|
8
|
|
|
8
|
|
537
|
use strict; |
|
|
8
|
|
|
|
|
23
|
|
|
|
8
|
|
|
|
|
535
|
|
|
6
|
8
|
|
|
8
|
|
46
|
use warnings; |
|
|
8
|
|
|
|
|
14
|
|
|
|
8
|
|
|
|
|
231
|
|
|
7
|
|
|
|
|
|
|
|
|
8
|
8
|
|
|
8
|
|
4128
|
use Eve::Event::HttpResponseReady; |
|
|
8
|
|
|
|
|
19
|
|
|
|
8
|
|
|
|
|
205
|
|
|
9
|
8
|
|
|
8
|
|
43
|
use Eve::Exception; |
|
|
8
|
|
|
|
|
14
|
|
|
|
8
|
|
|
|
|
8557
|
|
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=head1 NAME |
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
B - an event handler for HTTP request events. |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
use Eve::HttpDispatcher; |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
my $dispatcher = Eve::HttpDispatcher->new( |
|
20
|
|
|
|
|
|
|
request_constructor => $request_constructor, |
|
21
|
|
|
|
|
|
|
response => $response, |
|
22
|
|
|
|
|
|
|
base_uri => $base_uri, |
|
23
|
|
|
|
|
|
|
alias_base_uri_list => [$alias_base_uri, $another_alias_base_uri], |
|
24
|
|
|
|
|
|
|
event_map => $event_map); |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
$dispatcher->bind( |
|
27
|
|
|
|
|
|
|
name => $name |
|
28
|
|
|
|
|
|
|
pattern => $pattern, |
|
29
|
|
|
|
|
|
|
resource_constructor => $resource_constructor); |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
$dispatcher->bind( |
|
32
|
|
|
|
|
|
|
name => $name_404 |
|
33
|
|
|
|
|
|
|
pattern => $pattern_404, |
|
34
|
|
|
|
|
|
|
resource_constructor => $resource_constructor_404, |
|
35
|
|
|
|
|
|
|
exception => 'Eve::Exception::Http::404NotFound'); |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
$dispatcher->handle(event => $event); |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
B class is a central component to a web |
|
42
|
|
|
|
|
|
|
service application. |
|
43
|
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=head3 Constructor arguments |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
=over 4 |
|
47
|
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
=item C |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
a code reference that returns an HTTP request object when passed an |
|
51
|
|
|
|
|
|
|
environment hash |
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
=item C |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
an HTTP response object |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
=item C |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
an event map object. |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
=item C |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
a base URI object used for resource binding. |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
=item C |
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
(optional) a reference to a list of additional base URI objects that |
|
68
|
|
|
|
|
|
|
will be used for resource matching. |
|
69
|
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
=back |
|
71
|
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
=head1 METHODS |
|
73
|
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
=head2 B |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
=cut |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
sub init { |
|
79
|
0
|
|
|
0
|
1
|
|
my ($self, %arg_hash) = @_; |
|
80
|
0
|
|
|
|
|
|
Eve::Support::arguments( |
|
81
|
|
|
|
|
|
|
\%arg_hash, |
|
82
|
|
|
|
|
|
|
my ($request_constructor, $response, $event_map, $base_uri), |
|
83
|
|
|
|
|
|
|
my $alias_base_uri_list = []); |
|
84
|
|
|
|
|
|
|
|
|
85
|
0
|
|
|
|
|
|
$self->{'_request_constructor'} = $request_constructor; |
|
86
|
0
|
|
|
|
|
|
$self->{'_response'} = $response; |
|
87
|
0
|
|
|
|
|
|
$self->{'_event_map'} = $event_map; |
|
88
|
0
|
|
|
|
|
|
$self->{'_base_uri'} = $base_uri; |
|
89
|
|
|
|
|
|
|
|
|
90
|
0
|
|
|
|
|
|
$self->{'_base_uri_list'} = [$base_uri, @{$alias_base_uri_list}]; |
|
|
0
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
|
|
92
|
0
|
|
|
|
|
|
$self->{'_uri_map'} = {}; |
|
93
|
0
|
|
|
|
|
|
$self->{'_name_map'} = {}; |
|
94
|
0
|
|
|
|
|
|
$self->{'_exception_name_hash'} = {}; |
|
95
|
|
|
|
|
|
|
|
|
96
|
0
|
|
|
|
|
|
return; |
|
97
|
|
|
|
|
|
|
} |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
=head2 B |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
Binds an HTTP resource. |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
=head3 Arguments |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
=over 4 |
|
106
|
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
=item C |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
a name identifying the binding |
|
110
|
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
=item C |
|
112
|
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
an URI pattern string that can contain placeholders |
|
114
|
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
=item C |
|
116
|
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
a URI object that represents a base URL for the binding resource |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
=item C |
|
120
|
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
a code reference that returns an HTTP resource object |
|
122
|
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
=item C |
|
124
|
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
(optional) an HTTP exception class name that the bound resource should |
|
126
|
|
|
|
|
|
|
be used to handle. B: there can be only one resource bound to |
|
127
|
|
|
|
|
|
|
handle a certain exception. |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
=back |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
=head3 Throws |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
=over 3 |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
=item C |
|
136
|
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
if either name or compound URI or exception class name is not unique. |
|
138
|
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
=back |
|
140
|
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=cut |
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
sub bind { |
|
144
|
0
|
|
|
0
|
1
|
|
my ($self, %arg_hash) = @_; |
|
145
|
0
|
|
|
|
|
|
Eve::Support::arguments( |
|
146
|
|
|
|
|
|
|
\%arg_hash, my ($name, $pattern, $resource_constructor), |
|
147
|
|
|
|
|
|
|
my $exception = \undef); |
|
148
|
|
|
|
|
|
|
|
|
149
|
0
|
0
|
|
|
|
|
if (exists $self->_uri_map->{$pattern}) { |
|
150
|
0
|
|
|
|
|
|
Eve::Error::HttpDispatcher->throw( |
|
151
|
|
|
|
|
|
|
message => 'Binding URI must be unique: '.$pattern); |
|
152
|
|
|
|
|
|
|
} |
|
153
|
|
|
|
|
|
|
|
|
154
|
0
|
0
|
|
|
|
|
if (exists $self->_name_map->{$name}) { |
|
155
|
0
|
|
|
|
|
|
Eve::Error::HttpDispatcher->throw( |
|
156
|
|
|
|
|
|
|
message => 'Binding name must be unique: '.$name); |
|
157
|
|
|
|
|
|
|
} |
|
158
|
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
# Constructing all possible URIs that this resource is supposed to match |
|
160
|
|
|
|
|
|
|
# using the base URI as well as possible aliases |
|
161
|
0
|
|
|
|
|
|
my $uri_list = []; |
|
162
|
0
|
|
|
|
|
|
for my $uri (@{$self->_base_uri_list}) { |
|
|
0
|
|
|
|
|
|
|
|
163
|
0
|
|
|
|
|
|
my $map_uri = $uri->clone(); |
|
164
|
0
|
|
|
|
|
|
$map_uri->path_concat(string => $pattern); |
|
165
|
|
|
|
|
|
|
|
|
166
|
0
|
|
|
|
|
|
push(@{$uri_list}, $map_uri); |
|
|
0
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
} |
|
168
|
|
|
|
|
|
|
|
|
169
|
0
|
|
|
|
|
|
$self->_uri_map->{$pattern} = { |
|
170
|
|
|
|
|
|
|
'resource' => $resource_constructor->(), |
|
171
|
|
|
|
|
|
|
'uri_list' => $uri_list}; |
|
172
|
|
|
|
|
|
|
|
|
173
|
0
|
|
|
|
|
|
$self->_name_map->{$name} = { |
|
174
|
|
|
|
|
|
|
'pattern' => $pattern, 'uri_list' => $uri_list}; |
|
175
|
|
|
|
|
|
|
|
|
176
|
0
|
0
|
|
|
|
|
if (defined $exception) { |
|
177
|
0
|
0
|
|
|
|
|
if (exists $self->_exception_name_hash->{$exception}) { |
|
178
|
0
|
|
|
|
|
|
Eve::Error::HttpDispatcher->throw( |
|
179
|
|
|
|
|
|
|
message => 'Exception name must be unique: ' . $exception); |
|
180
|
|
|
|
|
|
|
} |
|
181
|
0
|
|
|
|
|
|
$self->_exception_name_hash->{$exception} = $pattern; |
|
182
|
|
|
|
|
|
|
} |
|
183
|
|
|
|
|
|
|
|
|
184
|
0
|
|
|
|
|
|
return; |
|
185
|
|
|
|
|
|
|
} |
|
186
|
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
=head2 B |
|
188
|
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
=head3 Arguments |
|
190
|
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
=over 4 |
|
192
|
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
=item C |
|
194
|
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
a name identifying the binding |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
=back |
|
198
|
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
=head3 Returns |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
A URI bound to the resource name. |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
=head3 Throws |
|
204
|
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
=over 3 |
|
206
|
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
=item C |
|
208
|
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
When there is no resource with the requested name. |
|
210
|
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
=back |
|
212
|
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
=cut |
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
sub get_uri { |
|
216
|
0
|
|
|
0
|
1
|
|
my ($self, %arg_hash) = @_; |
|
217
|
0
|
|
|
|
|
|
Eve::Support::arguments(\%arg_hash, my $name); |
|
218
|
|
|
|
|
|
|
|
|
219
|
0
|
0
|
|
|
|
|
if (not exists $self->_name_map->{$name}) { |
|
220
|
0
|
|
|
|
|
|
Eve::Error::HttpDispatcher->throw( |
|
221
|
|
|
|
|
|
|
message => 'There is no resource with such name: '.$name); |
|
222
|
|
|
|
|
|
|
} |
|
223
|
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
# We are relying on the fact that the page URI generated by the |
|
225
|
|
|
|
|
|
|
# base URI is always the first in the uri list for the specified |
|
226
|
|
|
|
|
|
|
# name. |
|
227
|
0
|
|
|
|
|
|
return $self->_name_map->{$name}->{'uri_list'}->[0]; |
|
228
|
|
|
|
|
|
|
} |
|
229
|
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
=head2 B |
|
231
|
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
Chooses a resource using the request URI and delegates control to the |
|
233
|
|
|
|
|
|
|
resource's C method. It also passes placeholder matches |
|
234
|
|
|
|
|
|
|
into this method. |
|
235
|
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
=head3 Arguments |
|
237
|
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
=over 4 |
|
239
|
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
=item C |
|
241
|
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
a C object. |
|
243
|
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
=back |
|
245
|
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
=head3 Throws |
|
247
|
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
=over 3 |
|
249
|
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
=item C |
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
if no resources match the request and no resources that handle the |
|
253
|
|
|
|
|
|
|
C are bound. |
|
254
|
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
=back |
|
256
|
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
=cut |
|
258
|
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
sub handle { |
|
260
|
0
|
|
|
0
|
1
|
|
my ($self, %arg_hash) = @_; |
|
261
|
0
|
|
|
|
|
|
Eve::Support::arguments(\%arg_hash, my $event); |
|
262
|
|
|
|
|
|
|
|
|
263
|
0
|
|
|
|
|
|
$self->{'_request'} = |
|
264
|
|
|
|
|
|
|
$self->_request_constructor->(env_hash => $event->env_hash); |
|
265
|
|
|
|
|
|
|
|
|
266
|
0
|
|
|
|
|
|
my $response; |
|
267
|
|
|
|
|
|
|
|
|
268
|
0
|
|
|
|
|
|
eval { |
|
269
|
0
|
|
|
|
|
|
for my $key (keys %{$self->_uri_map}) { |
|
|
0
|
|
|
|
|
|
|
|
270
|
0
|
|
|
|
|
|
my $request_uri = $self->_request->get_uri(); |
|
271
|
|
|
|
|
|
|
|
|
272
|
0
|
|
|
|
|
|
for my $uri (@{$self->_uri_map->{$key}->{'uri_list'}}) { |
|
|
0
|
|
|
|
|
|
|
|
273
|
0
|
|
|
|
|
|
my $match_hash = $uri->match(uri => $request_uri); |
|
274
|
0
|
0
|
|
|
|
|
if ($match_hash) { |
|
275
|
0
|
|
|
|
|
|
$response = $self->_uri_map->{$key}->{'resource'}->process( |
|
276
|
|
|
|
|
|
|
matches_hash => $match_hash, |
|
277
|
|
|
|
|
|
|
request => $self->_request); |
|
278
|
0
|
|
|
|
|
|
return; |
|
279
|
|
|
|
|
|
|
} |
|
280
|
|
|
|
|
|
|
} |
|
281
|
|
|
|
|
|
|
} |
|
282
|
|
|
|
|
|
|
|
|
283
|
0
|
|
|
|
|
|
Eve::Exception::Http::404NotFound->throw(); |
|
284
|
|
|
|
|
|
|
}; |
|
285
|
|
|
|
|
|
|
|
|
286
|
0
|
|
|
|
|
|
my $e; |
|
287
|
0
|
0
|
|
|
|
|
if ($e = Eve::Exception::Base->caught()) { |
|
|
|
0
|
|
|
|
|
|
|
288
|
0
|
0
|
|
|
|
|
if (defined $self->_exception_name_hash->{ref $e}){ |
|
289
|
|
|
|
|
|
|
my $resource = |
|
290
|
|
|
|
|
|
|
$self->_uri_map->{$self->_exception_name_hash->{ref $e}}->{ |
|
291
|
0
|
|
|
|
|
|
'resource'}; |
|
292
|
|
|
|
|
|
|
|
|
293
|
0
|
|
|
|
|
|
$response = $resource->process( |
|
294
|
|
|
|
|
|
|
matches_hash => {'exception' => $e}, |
|
295
|
|
|
|
|
|
|
request => $self->_request); |
|
296
|
|
|
|
|
|
|
} else { |
|
297
|
0
|
|
|
|
|
|
$e->throw(); |
|
298
|
|
|
|
|
|
|
} |
|
299
|
|
|
|
|
|
|
} elsif ($e = Exception::Class->caught()) { |
|
300
|
0
|
0
|
|
|
|
|
ref $e ? $e->rethrow() : die $e; |
|
301
|
|
|
|
|
|
|
} |
|
302
|
|
|
|
|
|
|
|
|
303
|
0
|
|
|
|
|
|
$event->response = $response; |
|
304
|
|
|
|
|
|
|
|
|
305
|
0
|
|
|
|
|
|
return; |
|
306
|
|
|
|
|
|
|
} |
|
307
|
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
309
|
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
=over 4 |
|
311
|
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
=item L |
|
313
|
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
=item L |
|
315
|
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
=item L |
|
317
|
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
=item L |
|
319
|
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
=back |
|
321
|
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT |
|
323
|
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
Copyright 2012 Igor Zinovyev. |
|
325
|
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
|
327
|
|
|
|
|
|
|
under the terms of either: the GNU General Public License as published |
|
328
|
|
|
|
|
|
|
by the Free Software Foundation; or the Artistic License. |
|
329
|
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
See http://dev.perl.org/licenses/ for more information. |
|
331
|
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
=head1 AUTHOR |
|
334
|
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
=over 4 |
|
336
|
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
=item L |
|
338
|
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
=item L |
|
340
|
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
=back |
|
342
|
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
=cut |
|
344
|
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
1; |