line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package AnyEvent::HTTPD::Request; |
2
|
12
|
|
|
12
|
|
71
|
use common::sense; |
|
12
|
|
|
|
|
24
|
|
|
12
|
|
|
|
|
102
|
|
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
=head1 NAME |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
AnyEvent::HTTPD::Request - A web application request handle for L<AnyEvent::HTTPD> |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
=head1 DESCRIPTION |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
This is the request object as generated by L<AnyEvent::HTTPD> and given |
11
|
|
|
|
|
|
|
in the request callbacks. |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=head1 METHODS |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=over 4 |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
=cut |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
sub new { |
20
|
18
|
|
|
18
|
0
|
75
|
my $this = shift; |
21
|
18
|
|
33
|
|
|
241
|
my $class = ref($this) || $this; |
22
|
18
|
|
|
|
|
175
|
my $self = { @_ }; |
23
|
18
|
|
|
|
|
98
|
bless $self, $class |
24
|
|
|
|
|
|
|
} |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
=item B<url> |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
This method returns the URL of the current request as L<URI> object. |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
=cut |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
sub url { |
33
|
2
|
|
|
2
|
1
|
54
|
my ($self) = @_; |
34
|
2
|
|
|
|
|
8
|
my $url = $self->{url}; |
35
|
2
|
|
|
|
|
10
|
my $u = URI->new ($url); |
36
|
2
|
|
|
|
|
171
|
$u |
37
|
|
|
|
|
|
|
} |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
=item B<respond ([$res])> |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
C<$res> can be: |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
=over 4 |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
=item * an array reference |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
Then the array reference has these elements: |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
my ($code, $message, $header_hash, $content) = |
50
|
|
|
|
|
|
|
[200, 'ok', { 'Content-Type' => 'text/html' }, '<h1>Test</h1>' }] |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
You can remove most headers added by default (like C<Cache-Control>, |
53
|
|
|
|
|
|
|
C<Expires>, and C<Content-Length>) by setting them to undef, like so: |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
$req->respond([ |
56
|
|
|
|
|
|
|
200, 'OK', { |
57
|
|
|
|
|
|
|
'Content-Type' => 'text/html', |
58
|
|
|
|
|
|
|
'Cache-Control' => 'max-age=3600', |
59
|
|
|
|
|
|
|
'Expires' => undef, |
60
|
|
|
|
|
|
|
}, |
61
|
|
|
|
|
|
|
'This data will be cached for one hour.' |
62
|
|
|
|
|
|
|
]); |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
=item * a hash reference |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
If it was a hash reference the hash is first searched for the C<redirect> |
67
|
|
|
|
|
|
|
key and if that key does not exist for the C<content> key. |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
The value for the C<redirect> key should contain the URL that you want to redirect |
70
|
|
|
|
|
|
|
the request to. |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
The value for the C<content> key should contain an array reference with the first |
73
|
|
|
|
|
|
|
value being the content type and the second the content. |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
=back |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
Here is an example: |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
$httpd->reg_cb ( |
80
|
|
|
|
|
|
|
'/image/elmex' => sub { |
81
|
|
|
|
|
|
|
my ($httpd, $req) = @_; |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
open IMG, "$ENV{HOME}/media/images/elmex.png" |
84
|
|
|
|
|
|
|
or $req->respond ( |
85
|
|
|
|
|
|
|
[404, 'not found', { 'Content-Type' => 'text/plain' }, 'not found'] |
86
|
|
|
|
|
|
|
); |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
$req->respond ({ content => ['image/png', do { local $/; <IMG> }] }); |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
); |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
B<How to send large files:> |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
For longer responses you can give a callback instead of a string to |
95
|
|
|
|
|
|
|
the response function for the value of the C<$content>. |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
$req->respond ({ content => ['video/x-ms-asf', sub { |
98
|
|
|
|
|
|
|
my ($data_cb) = @_; |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
# start some async retrieve operation, for example use |
101
|
|
|
|
|
|
|
# IO::AIO (with AnyEvent::AIO). Or retrieve chunks of data |
102
|
|
|
|
|
|
|
# to send somehow else. |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
} }); |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
The given callback will receive as first argument either another callback |
107
|
|
|
|
|
|
|
(C<$data_cb> in the above example) or an undefined value, which means that |
108
|
|
|
|
|
|
|
there is no more data required and the transfer has been completed (either by |
109
|
|
|
|
|
|
|
you sending no more data, or by a disconnect of the client). |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
The callback given to C<respond> will be called whenever the send queue of the |
112
|
|
|
|
|
|
|
HTTP connection becomes empty (meaning that the data is written out to the |
113
|
|
|
|
|
|
|
kernel). If it is called you have to start delivering the next chunk of data. |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
That doesn't have to be immediately, before the callback returns. This means |
116
|
|
|
|
|
|
|
that you can initiate for instance an L<IO::AIO> request (see also |
117
|
|
|
|
|
|
|
L<AnyEvent::AIO>) and send the data later. That is what the C<$data_cb> |
118
|
|
|
|
|
|
|
callback is for. You have to call it once you got the next chunk of data. Once |
119
|
|
|
|
|
|
|
you sent a chunk of data via C<$data_cb> you can just wait until your callback |
120
|
|
|
|
|
|
|
is called again to deliver the next chunk. |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
If you are done transferring all data call the C<$data_cb> with an empty string |
123
|
|
|
|
|
|
|
or with no argument at all. |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
Please consult the example script C<large_response_example> from the |
126
|
|
|
|
|
|
|
C<samples/> directory of the L<AnyEvent::HTTPD> distribution for an example of |
127
|
|
|
|
|
|
|
how to use this mechanism. |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
B<NOTE:> You should supply a 'Content-Length' header if you are going to send a |
130
|
|
|
|
|
|
|
larger file. If you don't do that the client will have no chance to know if the |
131
|
|
|
|
|
|
|
transfer was complete. To supply additional header fields the hash argument |
132
|
|
|
|
|
|
|
format will not work. You should use the array argument format for this case. |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=cut |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
sub respond { |
137
|
18
|
|
|
18
|
1
|
244
|
my ($self, $res) = @_; |
138
|
|
|
|
|
|
|
|
139
|
18
|
50
|
|
|
|
103
|
return unless $self->{resp}; |
140
|
|
|
|
|
|
|
|
141
|
18
|
|
|
|
|
54
|
my $rescb = delete $self->{resp}; |
142
|
|
|
|
|
|
|
|
143
|
18
|
100
|
|
|
|
104
|
if (ref $res eq 'HASH') { |
144
|
15
|
|
|
|
|
27
|
my $h = $res; |
145
|
15
|
50
|
|
|
|
80
|
if ($h->{redirect}) { |
|
|
50
|
|
|
|
|
|
146
|
0
|
|
|
|
|
0
|
$res = [ |
147
|
|
|
|
|
|
|
301, 'redirected', { Location => $h->{redirect} }, |
148
|
|
|
|
|
|
|
"Redirected to <a href=\"$h->{redirect}\">here</a>" |
149
|
|
|
|
|
|
|
]; |
150
|
|
|
|
|
|
|
} elsif ($h->{content}) { |
151
|
15
|
|
|
|
|
90
|
$res = [ |
152
|
|
|
|
|
|
|
200, 'ok', { 'Content-Type' => $h->{content}->[0] }, |
153
|
|
|
|
|
|
|
$h->{content}->[1] |
154
|
|
|
|
|
|
|
]; |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
|
159
|
18
|
|
|
|
|
49
|
$self->{responded} = 1; |
160
|
|
|
|
|
|
|
|
161
|
18
|
|
|
|
|
58
|
my $no_body = $self->method eq 'HEAD'; |
162
|
|
|
|
|
|
|
|
163
|
18
|
50
|
|
|
|
66
|
if (not defined $res) { |
164
|
0
|
|
|
|
|
0
|
$rescb->(404, "ok", { 'Content-Type' => 'text/html' }, "<h1>No content</h1>", $no_body); |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
} else { |
167
|
18
|
|
|
|
|
73
|
$rescb->(@$res, $no_body); |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
=item B<responded> |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
Returns true if this request already has been responded to. |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
=cut |
176
|
|
|
|
|
|
|
|
177
|
0
|
|
|
0
|
1
|
0
|
sub responded { $_[0]->{responded} } |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
=item B<parm ($key)> |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
Returns the first value of the form parameter C<$key> or undef. |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
=cut |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
sub parm { |
186
|
4
|
|
|
4
|
1
|
80
|
my ($self, $key) = @_; |
187
|
|
|
|
|
|
|
|
188
|
4
|
50
|
|
|
|
33
|
if (exists $self->{parm}->{$key}) { |
189
|
4
|
|
|
|
|
20
|
return $self->{parm}->{$key}->[0]->[0] |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
|
192
|
0
|
|
|
|
|
0
|
return undef; |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
=item B<params> |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
Returns list of parameter names. |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
=cut |
200
|
|
|
|
|
|
|
|
201
|
0
|
0
|
|
0
|
1
|
0
|
sub params { keys %{$_[0]->{parm} || {}} } |
|
0
|
|
|
|
|
0
|
|
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
=item B<vars> |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
Returns a hash of form parameters. The value is either the |
206
|
|
|
|
|
|
|
value of the parameter, and in case there are multiple values |
207
|
|
|
|
|
|
|
present it will contain an array reference of values. |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
=cut |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
sub vars { |
212
|
1
|
|
|
1
|
1
|
26
|
my ($self) = @_; |
213
|
|
|
|
|
|
|
|
214
|
1
|
|
|
|
|
5
|
my $p = $self->{parm}; |
215
|
|
|
|
|
|
|
|
216
|
4
|
|
|
|
|
5
|
my %v = map { |
217
|
1
|
|
|
|
|
5
|
my $k = $_; |
218
|
4
|
|
|
|
|
16
|
$k => |
219
|
2
|
|
|
|
|
11
|
@{$p->{$k}} > 1 |
220
|
4
|
100
|
|
|
|
6
|
? [ map { $_->[0] } @{$p->{$k}} ] |
|
1
|
|
|
|
|
3
|
|
221
|
|
|
|
|
|
|
: $p->{$k}->[0]->[0] |
222
|
|
|
|
|
|
|
} keys %$p; |
223
|
|
|
|
|
|
|
|
224
|
1
|
|
|
|
|
8
|
%v |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
=item B<method> |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
This method returns the method of the current request. |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
=cut |
232
|
|
|
|
|
|
|
|
233
|
55
|
|
|
55
|
1
|
1862
|
sub method { $_[0]{method} } |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
=item B<content> |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
Returns the request content or undef if only parameters for a form |
238
|
|
|
|
|
|
|
were transmitted. |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
=cut |
241
|
|
|
|
|
|
|
|
242
|
1
|
|
|
1
|
1
|
9
|
sub content { $_[0]->{content} } |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
=item B<headers> |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
This method will return a hash reference containing the HTTP headers for this |
247
|
|
|
|
|
|
|
HTTP request. |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
=cut |
250
|
|
|
|
|
|
|
|
251
|
1
|
|
|
1
|
1
|
28
|
sub headers { $_[0]->{hdr} } |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
=item B<client_host> |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
This method returns the host/IP of the HTTP client this request was received |
256
|
|
|
|
|
|
|
from. |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
=cut |
259
|
|
|
|
|
|
|
|
260
|
1
|
|
|
1
|
1
|
9
|
sub client_host { $_[0]->{host} } |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
=item B<client_port> |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
This method returns the TCP port number of the HTTP client this |
265
|
|
|
|
|
|
|
request was received from. |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
=cut |
268
|
|
|
|
|
|
|
|
269
|
1
|
|
|
1
|
1
|
7
|
sub client_port { $_[0]->{port} } |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
=back |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
Copyright 2008-2011 Robin Redeker, all rights reserved. |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
278
|
|
|
|
|
|
|
under the same terms as Perl itself. |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
=cut |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
1; |