File Coverage

blib/lib/Dancer/Request.pm
Criterion Covered Total %
statement 336 354 94.9
branch 106 138 76.8
condition 51 67 76.1
subroutine 69 71 97.1
pod 37 37 100.0
total 599 667 89.8


line stmt bran cond sub pod time code
1             package Dancer::Request;
2             our $AUTHORITY = 'cpan:SUKRIA';
3             #ABSTRACT: interface for accessing incoming requests
4             $Dancer::Request::VERSION = '1.3520';
5 182     182   921555 use strict;
  182         495  
  182         5311  
6 182     182   929 use warnings;
  182         423  
  182         4285  
7 182     182   936 use Carp;
  182         1490  
  182         10019  
8              
9 182     182   1183 use base 'Dancer::Object';
  182         480  
  182         26540  
10              
11 182     182   8790 use Dancer::Config 'setting';
  182         474  
  182         10280  
12 182     182   82433 use Dancer::Request::Upload;
  182         469  
  182         4611  
13 182     182   73515 use Dancer::SharedData;
  182         710  
  182         6081  
14 182     182   81616 use Dancer::Session;
  182         591  
  182         6486  
15 182     182   1278 use Dancer::Exception qw(:all);
  182         458  
  182         22949  
16 182     182   1347 use Encode;
  182         651  
  182         15064  
17 182     182   89594 use HTTP::Body;
  182         3622111  
  182         7069  
18 182     182   1516 use URI;
  182         746  
  182         5123  
19 182     182   1082 use URI::Escape;
  182         468  
  182         328228  
20              
21             my @http_env_keys = (
22             'user_agent', 'accept_language', 'accept_charset',
23             'accept_encoding', 'keep_alive', 'connection', 'accept',
24             'accept_type', 'referer', #'host', managed manually
25             );
26             my $count = 0;
27              
28             __PACKAGE__->attributes(
29              
30             # query
31             'env', 'path', 'method',
32             'content_type', 'content_length',
33             'id',
34             'uploads', 'headers', 'path_info',
35             'ajax', 'is_forward',
36             @http_env_keys,
37             );
38              
39             sub new {
40 611     611 1 81464 my ($self, @args) = @_;
41 611 50       1740 if (@args == 1) {
42 0         0 @args = ('env' => $args[0]);
43 0         0 Dancer::Deprecation->deprecated(
44             fatal => 1,
45             feature => 'Calling Dancer::Request->new($env)',
46             version => 1.3059,
47             reason => 'Please use Dancer::Request->new( env => $env ) instead',
48             );
49             }
50 611         2882 $self->SUPER::new(@args);
51             }
52              
53             # aliases
54 1     1 1 5 sub agent { $_[0]->user_agent }
55 19     19 1 59 sub remote_address { $_[0]->address }
56 1 50   1 1 6 sub forwarded_for_address { $_[0]->env->{'X_FORWARDED_FOR'} || $_[0]->env->{'HTTP_X_FORWARDED_FOR'} }
57             sub address {
58             setting('behind_proxy')
59             ? $_[0]->forwarded_for_address()
60             : $_[0]->env->{REMOTE_ADDR}
61 19 50   19 1 51 }
62             sub host {
63 34 50   34 1 99 if (@_==2) {
64 0         0 $_[0]->{host} = $_[1];
65             } else {
66 34         58 my $host;
67 34 100 33     114 $host = ($_[0]->env->{X_FORWARDED_HOST} || $_[0]->env->{HTTP_X_FORWARDED_HOST}) if setting('behind_proxy');
68 34 100 100     343 $host || $_[0]->{host} || $_[0]->env->{HTTP_HOST};
69             }
70             }
71 0     0 1 0 sub remote_host { $_[0]->env->{REMOTE_HOST} }
72 1     1 1 5 sub protocol { $_[0]->env->{SERVER_PROTOCOL} }
73 1     1 1 5 sub port { $_[0]->env->{SERVER_PORT} }
74 617     617 1 2425 sub request_uri { $_[0]->env->{REQUEST_URI} }
75 1     1 1 9 sub user { $_[0]->env->{REMOTE_USER} }
76 622     622 1 1744 sub script_name { $_[0]->env->{SCRIPT_NAME} }
77 1 50   1 1 5 sub request_base { $_[0]->env->{REQUEST_BASE} || $_[0]->env->{HTTP_REQUEST_BASE} }
78             sub scheme {
79 33     33 1 54 my $scheme;
80 33 100       122 if (setting('behind_proxy')) {
81             # PSGI specs say that X_FORWARDED_PROTO will
82             # be converted into HTTP_X_FORWARDED_PROTO
83             # but Dancer::Test doesn't use PSGI (for now)
84             $scheme = $_[0]->env->{'HTTP_X_FORWARDED_PROTO'}
85             || $_[0]->env->{'X_FORWARDED_PROTOCOL'}
86             || $_[0]->env->{'HTTP_X_FORWARDED_PROTOCOL'}
87             || $_[0]->env->{'HTTP_FORWARDED_PROTO'}
88 5   100     13 || $_[0]->env->{'X_FORWARDED_PROTO'}
89             || ""
90             }
91             return $scheme
92             || $_[0]->env->{'psgi.url_scheme'}
93 33   50     731 || $_[0]->env->{'PSGI.URL_SCHEME'}
94             || "";
95             }
96 1     1 1 4 sub secure { $_[0]->scheme eq 'https' }
97 3     3 1 13 sub uri { $_[0]->request_uri }
98              
99 18     18 1 83 sub is_head { $_[0]->{method} eq 'HEAD' }
100 10     10 1 71 sub is_post { $_[0]->{method} eq 'POST' }
101 2     2 1 14 sub is_get { $_[0]->{method} eq 'GET' }
102 15     15 1 89 sub is_put { $_[0]->{method} eq 'PUT' }
103 2     2 1 34 sub is_delete { $_[0]->{method} eq 'DELETE' }
104 1     1 1 25 sub is_patch { $_[0]->{method} eq 'PATCH' }
105 7     7 1 30 sub header { $_[0]->{headers}->header($_[1]) }
106              
107             # We used to store the whole raw unparsed body; this was a big problem for large
108             # file uploads (Issue 1129).
109             # The original fix was to stop doing so, and replace the accessor with one that
110             # would read it out of the temp file returned by HTTP::Body->body - but that
111             # doesn't work for e.g. parsed form submissions, only certain types.
112             # So, back to the older way - we may have a request body squirreled away
113             # in memory if the config included the raw_request_body_in_ram boolean
114 17     17 1 102 sub body { $_[0]->{body} }
115              
116             # public interface compat with CGI.pm objects
117 1     1 1 5 sub request_method { method(@_) }
118 2     2 1 7 sub Vars { params(@_) }
119 615 100   615 1 1942 sub input_handle { $_[0]->env->{'psgi.input'} || $_[0]->env->{'PSGI.INPUT'} }
120              
121             sub init {
122 611     611 1 1343 my ($self) = @_;
123              
124 611   50     2105 $self->{env} ||= {};
125 611         2109 $self->{path} = undef;
126 611         1147 $self->{method} = undef;
127 611         1549 $self->{params} = {};
128 611   100     3084 $self->{is_forward} ||= 0;
129 611   100     2166 $self->{content_length} = $self->env->{CONTENT_LENGTH} || 0;
130 611   100     1545 $self->{content_type} = $self->env->{CONTENT_TYPE} || '';
131 611         2061 $self->{id} = ++$count;
132 611         1439 $self->{_chunk_size} = 4096;
133 611         1062 $self->{_read_position} = 0;
134 611         1272 $self->{_body_params} = undef;
135 611         1041 $self->{_query_params} = undef;
136 611         1475 $self->{_route_params} = {};
137              
138 611         1897 $self->_build_headers();
139 611         1867 $self->_build_request_env();
140 611 50       1780 $self->_build_path() unless $self->path;
141 611 50       1926 $self->_build_path_info() unless $self->path_info;
142 611 50       1806 $self->_build_method() unless $self->method;
143              
144             $self->{_http_body}
145 611         1892 = HTTP::Body->new($self->content_type, $self->content_length);
146 611         45846 $self->{_http_body}->cleanup(1);
147 611         4308 $self->{body} = ''; # default, because we might not store it now.
148 611         2510 $self->_build_params();
149 611 50       2186 $self->_build_uploads unless $self->uploads;
150 611         1847 $self->{ajax} = $self->is_ajax;
151              
152 611         1501 return $self;
153             }
154              
155             sub to_string {
156 1     1 1 3 my ($self) = @_;
157 1         5 return "[#" . $self->id . "] " . $self->method . " " . $self->path;
158             }
159              
160             # helper for building a request object by hand
161             # with the given method, path, params, body and headers.
162             sub new_for_request {
163 571     571 1 3601 my ($class, $method, $uri, $params, $body, $headers, $extra_env) = @_;
164 571   100     2523 $params ||= {};
165 571   100     1863 $extra_env ||= {};
166 571         1339 $method = uc($method);
167              
168 571         3771 my ( $path, $query_string ) = ( $uri =~ /([^?]*)(?:\?(.*))?/s ); #from HTTP::Server::Simple
169              
170             my $env = {
171             %ENV,
172 571         14619 %{$extra_env},
173             PATH_INFO => $path,
174 571   100     5156 QUERY_STRING => $query_string || $ENV{QUERY_STRING} || '',
175             REQUEST_METHOD => $method
176             };
177 571 100       3533 $env->{CONTENT_LENGTH} = defined($body) ? length($body) : 0 if !exists $env->{CONTENT_LENGTH};
    100          
178 571         1938 my $req = $class->new(env => $env);
179 571         927 $req->{params} = {%{$req->{params}}, %{$params}};
  571         1251  
  571         1298  
180 571         1629 $req->_build_params();
181 571         1222 $req->{_query_params} = $req->{params};
182 571         2013 my $store_raw_body = setting('raw_request_body_in_ram');
183 571 50       1422 $store_raw_body = defined $store_raw_body ? $store_raw_body : 1;
184 571 50       1266 if ($store_raw_body) {
185 571         1056 $req->{body} = $body;
186             }
187 571   66     1735 $req->{headers} = $headers || HTTP::Headers->new;
188              
189 571         2693 return $req;
190             }
191              
192             #Create a new request which is a clone of the current one, apart
193             #from the path location, which points instead to the new location
194             sub forward {
195 16     16 1 40 my ($class, $request, $to_data) = @_;
196              
197 16         43 my $env = $request->env;
198 16         37 $env->{PATH_INFO} = $to_data->{to_url};
199              
200 16         45 my $new_request = $class->new(env => $env, is_forward => 1);
201             my $new_params = _merge_params(scalar($request->params),
202 16   100     51 $to_data->{params} || {});
203              
204 16 100       49 if (exists($to_data->{options}{method})) {
205 2 50       23 die unless _valid_method($to_data->{options}{method});
206 2         5 $new_request->{method} = uc $to_data->{options}{method};
207             }
208              
209 16         27 $new_request->{params} = $new_params;
210 16         34 $new_request->{_body_params} = $request->{_body_params};
211 16         31 $new_request->{_query_params} = $request->{_query_params};
212 16         34 $new_request->{_route_params} = $request->{_route_params};
213 16         28 $new_request->{_params_are_decoded} = 1;
214 16         41 $new_request->{headers} = $request->headers;
215              
216 16 100 66     74 if( my $session = Dancer::Session->engine
217             && Dancer::Session->get_current_session ) {
218 15         33 my $name = $session->session_name;
219              
220             # make sure that COOKIE is populated
221 15   33     77 $new_request->{env}{COOKIE} ||= $new_request->{env}{HTTP_COOKIE};
222              
223 182     182   1729 no warnings; # COOKIE can be undef
  182         798  
  182         535215  
224 15 50       138 unless ( $new_request->{env}{COOKIE} =~ /$name\s*=/ ) {
225             $new_request->{env}{COOKIE} = join ';',
226 30         85 grep { $_ }
227             $new_request->{env}{COOKIE},
228 15         54 join '=', $name, Dancer::Session->get_current_session->id;
229             }
230             }
231              
232 16         58 $new_request->{uploads} = $request->uploads;
233              
234 16         59 return $new_request;
235             }
236              
237             sub _valid_method {
238 2     2   8 my $method = shift;
239 2         21 return $method =~ /^(?:head|post|get|put|delete)$/i;
240             }
241              
242             sub _merge_params {
243 16     16   34 my ($params, $to_add) = @_;
244              
245 16 50       40 die unless ref $to_add eq "HASH";
246 16         44 for my $key (keys %$to_add) {
247 4         11 $params->{$key} = $to_add->{$key};
248             }
249 16         32 return $params;
250             }
251              
252             sub base {
253 29     29 1 1632 my $self = shift;
254 29         82 my $uri = $self->_common_uri;
255              
256 29         103 return $uri->canonical;
257             }
258              
259             sub _common_uri {
260 32     32   51 my $self = shift;
261              
262 32   100     94 my $path = $self->env->{SCRIPT_NAME} || '';
263 32         79 my $port = $self->env->{SERVER_PORT};
264 32         89 my $server = $self->env->{SERVER_NAME};
265 32         100 my $host = $self->host;
266 32         131 my $scheme = $self->scheme;
267              
268 32         157 my $uri = URI->new;
269 32         41840 $uri->scheme($scheme);
270 32   66     36026 $uri->authority($host || "$server:$port");
271 32 100       1627 if (setting('behind_proxy')) {
272 5   100     16 my $request_base = $self->env->{REQUEST_BASE} || $self->env->{HTTP_REQUEST_BASE} || '';
273 5   100     40 $uri->path($request_base . $path || '/');
274             }
275             else {
276 27   100     334 $uri->path($path || '/');
277             }
278              
279 32         1257 return $uri;
280             }
281              
282             sub uri_base {
283 3     3 1 29 my $self = shift;
284 3         10 my $uri = $self->_common_uri;
285 3         14 my $canon = $uri->canonical;
286              
287 3 100       428 if ( $uri->path eq '/' ) {
288 2         30 $canon =~ s{/$}{};
289             }
290              
291 3         53 return $canon;
292             }
293              
294             sub uri_for {
295 26     26 1 6847 my ($self, $part, $params, $dont_escape) = @_;
296 26         78 my $uri = $self->base;
297              
298             # Make sure there's exactly one slash between the base and the new part
299 26         2816 my $base = $uri->path;
300 26         305 $base =~ s|/$||;
301 26         79 $part =~ s|^/||;
302 26         107 $uri->path("$base/$part");
303              
304 26 100       946 $uri->query_form($params) if $params;
305              
306 26 100       1124 return $dont_escape ? uri_unescape($uri->canonical) : $uri->canonical;
307             }
308              
309             sub params {
310 436     436 1 1672 my ($self, $source) = @_;
311              
312 436         1400 my @caller = caller;
313              
314 436 100       1450 if (not $self->{_params_are_decoded}) {
315 289         915 $self->{params} = _decode($self->{params});
316 289         714 $self->{_body_params} = _decode($self->{_body_params});
317 289         665 $self->{_query_params} = _decode($self->{_query_params});
318 289         826 $self->{_route_params} = _decode($self->{_route_params});
319 289         1430 $self->{_params_are_decoded} = 1;
320             }
321              
322 436 100 100     1222 return %{$self->{params}} if wantarray && @_ == 1;
  15         128  
323 421 100       2270 return $self->{params} if @_ == 1;
324              
325 19 100       108 if ($source eq 'query') {
    50          
326 4 100       17 return %{$self->{_query_params}} if wantarray;
  2         16  
327 2         9 return $self->{_query_params};
328             }
329             elsif ($source eq 'body') {
330 15 50       64 return %{$self->{_body_params}} if wantarray;
  0         0  
331 15         66 return $self->{_body_params};
332             }
333 0 0       0 if ($source eq 'route') {
334 0 0       0 return %{$self->{_route_params}} if wantarray;
  0         0  
335 0         0 return $self->{_route_params};
336             }
337             else {
338 0         0 raise core_request => "Unknown source params \"$source\".";
339             }
340             }
341              
342             sub _decode {
343 2538     2538   7662 my ($h) = @_;
344 2538 100       4942 return if not defined $h;
345              
346 2526 100 100     6161 if (!ref($h) && !utf8::is_utf8($h)) {
347 622         2564 return decode('UTF-8', $h);
348             }
349              
350 1904 100       4163 if (ref($h) eq 'HASH') {
351 1793         5494 while (my ($k, $v) = each(%$h)) {
352 631         8218 $h->{$k} = _decode($v);
353             }
354 1793         22388 return $h;
355             }
356              
357 111 100       255 if (ref($h) eq 'ARRAY') {
358 83         146 return [ map { _decode($_) } @$h ];
  140         2548  
359             }
360              
361 28         93 return $h;
362             }
363              
364             sub is_ajax {
365 614     614 1 1038 my $self = shift;
366              
367             # when using Plack::Builder headers are not set
368             # so we're checking if it's actually there with PSGI plain headers
369 614 50       1495 if ( defined $self->{x_requested_with} ) {
370 0 0       0 if ( $self->{x_requested_with} eq "XMLHttpRequest" ) {
371 0         0 return 1;
372             }
373             }
374              
375 614 100       1515 return 0 unless defined $self->headers;
376 4 100       23 return 0 unless defined $self->header('X-Requested-With');
377 1 50       41 return 0 if $self->header('X-Requested-With') ne 'XMLHttpRequest';
378 1         44 return 1;
379             }
380              
381             # context-aware accessor for uploads
382             sub upload {
383 8     8 1 986 my ($self, $name) = @_;
384 8         22 my $res = $self->{uploads}{$name};
385              
386 8 100       30 return $res unless wantarray;
387 3 100       9 return () unless defined $res;
388 2 100       12 return (ref($res) eq 'ARRAY') ? @$res : $res;
389             }
390              
391             # Some Dancer's core components sometimes need to alter
392             # the parsed request params, these protected accessors are provided
393             # for this purpose
394             sub _set_route_params {
395 649     649   1271 my ($self, $params) = @_;
396 649         1496 $self->{_route_params} = $params;
397 649         1465 $self->_build_params();
398             }
399              
400             sub _set_body_params {
401 8     8   22 my ($self, $params) = @_;
402 8         19 $self->{_body_params} = $params;
403 8         22 $self->_build_params();
404             }
405              
406             sub _set_query_params {
407 0     0   0 my ($self, $params) = @_;
408 0         0 $self->{_query_params} = $params;
409 0         0 $self->_build_params();
410             }
411              
412             sub _build_request_env {
413 611     611   1147 my ($self) = @_;
414              
415             # Don't refactor that, it's called whenever a request object is needed, that
416             # means at least once per request. If refactored in a loop, this will cost 4
417             # times more than the following static map.
418 611         1590 my $env = $self->env;
419 611         1331 $self->{user_agent} = $env->{HTTP_USER_AGENT};
420 611         2042 $self->{host} = $env->{HTTP_HOST};
421 611         1253 $self->{accept_language} = $env->{HTTP_ACCEPT_LANGUAGE};
422 611         1625 $self->{accept_charset} = $env->{HTTP_ACCEPT_CHARSET};
423 611         1120 $self->{accept_encoding} = $env->{HTTP_ACCEPT_ENCODING};
424 611         1312 $self->{keep_alive} = $env->{HTTP_KEEP_ALIVE};
425 611         1266 $self->{connection} = $env->{HTTP_CONNECTION};
426 611         1274 $self->{accept} = $env->{HTTP_ACCEPT};
427 611         1238 $self->{accept_type} = $env->{HTTP_ACCEPT_TYPE};
428 611         1105 $self->{referer} = $env->{HTTP_REFERER};
429 611         1369 $self->{x_requested_with} = $env->{HTTP_X_REQUESTED_WITH};
430             }
431              
432             sub _build_headers {
433 611     611   1140 my ($self) = @_;
434 611         2613 $self->{headers} = Dancer::SharedData->headers;
435             }
436              
437             sub _build_params {
438 2450     2450   4762 my ($self) = @_;
439              
440             # params may have been populated by before filters
441             # _before_ we get there, so we have to save it first
442 2450         4047 my $previous = $self->{params};
443              
444             # now parse environment params...
445 2450         6450 $self->_parse_get_params();
446 2450 100       5874 if ($self->is_forward) {
447 47   100     132 $self->{_body_params} ||= {};
448             } else {
449 2403         5459 $self->_parse_post_params();
450             }
451              
452             # and merge everything
453             $self->{params} = {
454 2450         4324 %$previous, %{$self->{_query_params}},
455 2450         8225 %{$self->{_route_params}}, %{$self->{_body_params}},
  2450         4072  
  2450         6893  
456             };
457              
458             }
459              
460             # Written from PSGI specs:
461             # http://search.cpan.org/dist/PSGI/PSGI.pod
462             sub _build_path {
463 611     611   1233 my ($self) = @_;
464 611         1291 my $path = "";
465              
466 611 100       1705 $path .= $self->script_name if defined $self->script_name;
467 611 100       1520 $path .= $self->env->{PATH_INFO} if defined $self->env->{PATH_INFO};
468              
469             # fallback to REQUEST_URI if nothing found
470             # we have to decode it, according to PSGI specs.
471 611 100       1633 if (defined $self->request_uri) {
472 526   33     1793 $path ||= $self->_url_decode($self->request_uri);
473             }
474              
475 611 50       1499 raise core_request => "Cannot resolve path" if not $path;
476 611         1717 $self->{path} = $path;
477             }
478              
479             sub _build_path_info {
480 611     611   1589 my ($self) = @_;
481 611         1808 my $info = $self->env->{PATH_INFO};
482 611 100       1808 if (defined $info) {
483              
484             # Empty path info will be interpreted as "root".
485 604   50     1679 $info ||= '/';
486             }
487             else {
488 7         19 $info = $self->path;
489             }
490 611         1496 $self->{path_info} = $info;
491             }
492              
493             sub _build_method {
494 611     611   1250 my ($self) = @_;
495             $self->{method} = $self->env->{REQUEST_METHOD}
496 611   33     2060 || $self->{request}->request_method();
497             }
498              
499             sub _url_decode {
500 80     80   161 my ($self, $encoded) = @_;
501 80         117 my $clean = $encoded;
502 80         121 $clean =~ tr/\+/ /;
503 80         154 $clean =~ s/%([a-fA-F0-9]{2})/pack "H2", $1/eg;
  4         21  
504 80         141 return $clean;
505             }
506              
507             sub _parse_post_params {
508 2403     2403   4506 my ($self) = @_;
509 2403 100       6068 return $self->{_body_params} if defined $self->{_body_params};
510              
511 595         1968 $self->_read_to_end();
512 595         2615 $self->{_body_params} = $self->{_http_body}->param;
513             }
514              
515             sub _parse_get_params {
516 2450     2450   4256 my ($self) = @_;
517 2450 100       7517 return $self->{_query_params} if defined $self->{_query_params};
518 611         1788 $self->{_query_params} = {};
519              
520 611   100     2120 my $source = $self->env->{QUERY_STRING} || '';
521 611         3047 foreach my $token (split /[&;]/, $source) {
522 40         114 my ($key, $val) = split(/=/, $token, 2);
523 40 50       91 next unless defined $key;
524 40 50       82 $val = (defined $val) ? $val : '';
525 40         77 $key = $self->_url_decode($key);
526 40         75 $val = $self->_url_decode($val);
527              
528             # looking for multi-value params
529 40 100       106 if (exists $self->{_query_params}{$key}) {
530 4         11 my $prev_val = $self->{_query_params}{$key};
531 4 50 33     16 if (ref($prev_val) && ref($prev_val) eq 'ARRAY') {
532 0         0 push @{$self->{_query_params}{$key}}, $val;
  0         0  
533             }
534             else {
535 4         13 $self->{_query_params}{$key} = [$prev_val, $val];
536             }
537             }
538              
539             # simple value param (first time we see it)
540             else {
541 36         92 $self->{_query_params}{$key} = $val;
542             }
543             }
544 611         1539 return $self->{_query_params};
545             }
546              
547             sub _read_to_end {
548 595     595   1393 my $self = shift;
549            
550 595 100       2114 return unless $self->_has_something_to_read;
551              
552 32 100       147 if ( $self->content_length > 0 ) {
553 20         47 my $body = '';
554              
555 20         81 my $store_raw_body = setting('raw_request_body_in_ram');
556 20 50       63 $store_raw_body = defined $store_raw_body ? $store_raw_body : 1;
557              
558 20         60 while ( my $buffer = $self->_read ) {
559 20         122 $self->{_http_body}->add($buffer);
560              
561             # Only keep a copy of the raw request body in RAM if the user has
562             # asked us to
563            
564 20 50       17828 if ($store_raw_body) {
565 20         91 $self->{body} .= $buffer;
566             }
567             }
568              
569             }
570              
571 32         61 return $self->{_http_body};
572             }
573              
574             sub _has_something_to_read {
575 595     595   1997 defined $_[0]->input_handle;
576             }
577              
578             # taken from Miyagawa's Plack::Request::BodyParser
579             sub _read {
580 40     40   95 my ($self,) = @_;
581 40         114 my $remaining = $self->content_length - $self->{_read_position};
582 40         81 my $maxlength = $self->{_chunk_size};
583              
584 40 100       140 return if ($remaining <= 0);
585              
586 20 50       51 my $readlen = ($remaining > $maxlength) ? $maxlength : $remaining;
587 20         33 my $buffer;
588             my $rc;
589              
590 20         50 $rc = $self->input_handle->read($buffer, $readlen);
591              
592 20 50       203 if (defined $rc) {
593 20         42 $self->{_read_position} += $rc;
594 20         75 return $buffer;
595             }
596             else {
597 0         0 raise core_request => "Unknown error reading input: $!";
598             }
599             }
600              
601             # Taken gently from Plack::Request, thanks to Plack authors.
602             sub _build_uploads {
603 611     611   1328 my ($self) = @_;
604              
605 611         2078 my $uploads = _decode($self->{_http_body}->upload);
606 611         1230 my %uploads;
607              
608 611         865 for my $name (keys %{$uploads}) {
  611         1572  
609 9         18 my $files = $uploads->{$name};
610 9 100       37 $files = ref $files eq 'ARRAY' ? $files : [$files];
611              
612 9         13 my @uploads;
613 9         17 for my $upload (@{$files}) {
  9         18  
614             push(
615             @uploads,
616             Dancer::Request::Upload->new(
617             headers => $upload->{headers},
618             tempname => $upload->{tempname},
619             size => $upload->{size},
620             filename => $upload->{filename},
621             )
622 11         63 );
623             }
624 9 100       30 $uploads{$name} = @uploads > 1 ? \@uploads : $uploads[0];
625              
626             # support access to the filename as a normal param
627 9         19 my @filenames = map { $_->{filename} } @uploads;
  11         33  
628 9 100       34 $self->{_body_params}{$name} =
629             @filenames > 1 ? \@filenames : $filenames[0];
630             }
631              
632 611         1710 $self->{uploads} = \%uploads;
633 611         1298 $self->_build_params();
634             }
635              
636             1;
637              
638             __END__