File Coverage

blib/lib/AnyEvent/HTTPD/Request.pm
Criterion Covered Total %
statement 39 45 86.6
branch 9 16 56.2
condition 1 3 33.3
subroutine 11 13 84.6
pod 11 12 91.6
total 71 89 79.7


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;