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.3521';
5 182     182   905672 use strict;
  182         501  
  182         5516  
6 182     182   948 use warnings;
  182         389  
  182         4180  
7 182     182   929 use Carp;
  182         1606  
  182         9693  
8              
9 182     182   1192 use base 'Dancer::Object';
  182         390  
  182         26334  
10              
11 182     182   9460 use Dancer::Config 'setting';
  182         427  
  182         8795  
12 182     182   81732 use Dancer::Request::Upload;
  182         522  
  182         4612  
13 182     182   72361 use Dancer::SharedData;
  182         691  
  182         5947  
14 182     182   81518 use Dancer::Session;
  182         539  
  182         6667  
15 182     182   1272 use Dancer::Exception qw(:all);
  182         478  
  182         22679  
16 182     182   1339 use Encode;
  182         637  
  182         15016  
17 182     182   86824 use HTTP::Body;
  182         3527353  
  182         6115  
18 182     182   1425 use URI;
  182         640  
  182         4956  
19 182     182   1133 use URI::Escape;
  182         492  
  182         316902  
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 84201 my ($self, @args) = @_;
41 611 50       1774 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         2869 $self->SUPER::new(@args);
51             }
52              
53             # aliases
54 1     1 1 4 sub agent { $_[0]->user_agent }
55 19     19 1 56 sub remote_address { $_[0]->address }
56 1 50   1 1 22 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 109 if (@_==2) {
64 0         0 $_[0]->{host} = $_[1];
65             } else {
66 34         54 my $host;
67 34 100 33     112 $host = ($_[0]->env->{X_FORWARDED_HOST} || $_[0]->env->{HTTP_X_FORWARDED_HOST}) if setting('behind_proxy');
68 34 100 100     320 $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 7 sub protocol { $_[0]->env->{SERVER_PROTOCOL} }
73 1     1 1 5 sub port { $_[0]->env->{SERVER_PORT} }
74 617     617 1 2387 sub request_uri { $_[0]->env->{REQUEST_URI} }
75 1     1 1 26 sub user { $_[0]->env->{REMOTE_USER} }
76 622     622 1 1696 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 50 my $scheme;
80 33 100       84 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     12 || $_[0]->env->{'X_FORWARDED_PROTO'}
89             || ""
90             }
91             return $scheme
92             || $_[0]->env->{'psgi.url_scheme'}
93 33   50     356 || $_[0]->env->{'PSGI.URL_SCHEME'}
94             || "";
95             }
96 1     1 1 5 sub secure { $_[0]->scheme eq 'https' }
97 3     3 1 12 sub uri { $_[0]->request_uri }
98              
99 18     18 1 78 sub is_head { $_[0]->{method} eq 'HEAD' }
100 10     10 1 77 sub is_post { $_[0]->{method} eq 'POST' }
101 2     2 1 13 sub is_get { $_[0]->{method} eq 'GET' }
102 15     15 1 89 sub is_put { $_[0]->{method} eq 'PUT' }
103 2     2 1 28 sub is_delete { $_[0]->{method} eq 'DELETE' }
104 1     1 1 18 sub is_patch { $_[0]->{method} eq 'PATCH' }
105 7     7 1 28 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 106 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 8 sub Vars { params(@_) }
119 615 100   615 1 1918 sub input_handle { $_[0]->env->{'psgi.input'} || $_[0]->env->{'PSGI.INPUT'} }
120              
121             sub init {
122 611     611 1 1272 my ($self) = @_;
123              
124 611   50     2125 $self->{env} ||= {};
125 611         1679 $self->{path} = undef;
126 611         1122 $self->{method} = undef;
127 611         1504 $self->{params} = {};
128 611   100     3438 $self->{is_forward} ||= 0;
129 611   100     1989 $self->{content_length} = $self->env->{CONTENT_LENGTH} || 0;
130 611   100     1565 $self->{content_type} = $self->env->{CONTENT_TYPE} || '';
131 611         1963 $self->{id} = ++$count;
132 611         1436 $self->{_chunk_size} = 4096;
133 611         1084 $self->{_read_position} = 0;
134 611         1212 $self->{_body_params} = undef;
135 611         1423 $self->{_query_params} = undef;
136 611         1490 $self->{_route_params} = {};
137              
138 611         1908 $self->_build_headers();
139 611         1808 $self->_build_request_env();
140 611 50       1831 $self->_build_path() unless $self->path;
141 611 50       1877 $self->_build_path_info() unless $self->path_info;
142 611 50       1995 $self->_build_method() unless $self->method;
143              
144             $self->{_http_body}
145 611         2015 = HTTP::Body->new($self->content_type, $self->content_length);
146 611         46567 $self->{_http_body}->cleanup(1);
147 611         4189 $self->{body} = ''; # default, because we might not store it now.
148 611         2580 $self->_build_params();
149 611 50       2183 $self->_build_uploads unless $self->uploads;
150 611         1887 $self->{ajax} = $self->is_ajax;
151              
152 611         1529 return $self;
153             }
154              
155             sub to_string {
156 1     1 1 4 my ($self) = @_;
157 1         4 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 3062 my ($class, $method, $uri, $params, $body, $headers, $extra_env) = @_;
164 571   100     2541 $params ||= {};
165 571   100     1763 $extra_env ||= {};
166 571         1272 $method = uc($method);
167              
168 571         3613 my ( $path, $query_string ) = ( $uri =~ /([^?]*)(?:\?(.*))?/s ); #from HTTP::Server::Simple
169              
170             my $env = {
171             %ENV,
172 571         14534 %{$extra_env},
173             PATH_INFO => $path,
174 571   100     4734 QUERY_STRING => $query_string || $ENV{QUERY_STRING} || '',
175             REQUEST_METHOD => $method
176             };
177 571 100       3414 $env->{CONTENT_LENGTH} = defined($body) ? length($body) : 0 if !exists $env->{CONTENT_LENGTH};
    100          
178 571         1913 my $req = $class->new(env => $env);
179 571         899 $req->{params} = {%{$req->{params}}, %{$params}};
  571         1254  
  571         1256  
180 571         1645 $req->_build_params();
181 571         1287 $req->{_query_params} = $req->{params};
182 571         1912 my $store_raw_body = setting('raw_request_body_in_ram');
183 571 50       1418 $store_raw_body = defined $store_raw_body ? $store_raw_body : 1;
184 571 50       1277 if ($store_raw_body) {
185 571         1006 $req->{body} = $body;
186             }
187 571   66     1729 $req->{headers} = $headers || HTTP::Headers->new;
188              
189 571         2685 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 38 my ($class, $request, $to_data) = @_;
196              
197 16         39 my $env = $request->env;
198 16         45 $env->{PATH_INFO} = $to_data->{to_url};
199              
200 16         40 my $new_request = $class->new(env => $env, is_forward => 1);
201             my $new_params = _merge_params(scalar($request->params),
202 16   100     41 $to_data->{params} || {});
203              
204 16 100       47 if (exists($to_data->{options}{method})) {
205 2 50       13 die unless _valid_method($to_data->{options}{method});
206 2         6 $new_request->{method} = uc $to_data->{options}{method};
207             }
208              
209 16         33 $new_request->{params} = $new_params;
210 16         31 $new_request->{_body_params} = $request->{_body_params};
211 16         28 $new_request->{_query_params} = $request->{_query_params};
212 16         26 $new_request->{_route_params} = $request->{_route_params};
213 16         26 $new_request->{_params_are_decoded} = 1;
214 16         37 $new_request->{headers} = $request->headers;
215              
216 16 100 66     78 if( my $session = Dancer::Session->engine
217             && Dancer::Session->get_current_session ) {
218 15         40 my $name = $session->session_name;
219              
220             # make sure that COOKIE is populated
221 15   33     79 $new_request->{env}{COOKIE} ||= $new_request->{env}{HTTP_COOKIE};
222              
223 182     182   1740 no warnings; # COOKIE can be undef
  182         771  
  182         519855  
224 15 50       120 unless ( $new_request->{env}{COOKIE} =~ /$name\s*=/ ) {
225             $new_request->{env}{COOKIE} = join ';',
226 30         91 grep { $_ }
227             $new_request->{env}{COOKIE},
228 15         45 join '=', $name, Dancer::Session->get_current_session->id;
229             }
230             }
231              
232 16         67 $new_request->{uploads} = $request->uploads;
233              
234 16         56 return $new_request;
235             }
236              
237             sub _valid_method {
238 2     2   5 my $method = shift;
239 2         16 return $method =~ /^(?:head|post|get|put|delete)$/i;
240             }
241              
242             sub _merge_params {
243 16     16   35 my ($params, $to_add) = @_;
244              
245 16 50       39 die unless ref $to_add eq "HASH";
246 16         52 for my $key (keys %$to_add) {
247 4         11 $params->{$key} = $to_add->{$key};
248             }
249 16         30 return $params;
250             }
251              
252             sub base {
253 29     29 1 1545 my $self = shift;
254 29         79 my $uri = $self->_common_uri;
255              
256 29         103 return $uri->canonical;
257             }
258              
259             sub _common_uri {
260 32     32   53 my $self = shift;
261              
262 32   100     107 my $path = $self->env->{SCRIPT_NAME} || '';
263 32         104 my $port = $self->env->{SERVER_PORT};
264 32         105 my $server = $self->env->{SERVER_NAME};
265 32         96 my $host = $self->host;
266 32         94 my $scheme = $self->scheme;
267              
268 32         151 my $uri = URI->new;
269 32         41735 $uri->scheme($scheme);
270 32   66     35309 $uri->authority($host || "$server:$port");
271 32 100       1612 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     331 $uri->path($path || '/');
277             }
278              
279 32         1245 return $uri;
280             }
281              
282             sub uri_base {
283 3     3 1 35 my $self = shift;
284 3         11 my $uri = $self->_common_uri;
285 3         13 my $canon = $uri->canonical;
286              
287 3 100       448 if ( $uri->path eq '/' ) {
288 2         40 $canon =~ s{/$}{};
289             }
290              
291 3         54 return $canon;
292             }
293              
294             sub uri_for {
295 26     26 1 6451 my ($self, $part, $params, $dont_escape) = @_;
296 26         68 my $uri = $self->base;
297              
298             # Make sure there's exactly one slash between the base and the new part
299 26         2773 my $base = $uri->path;
300 26         299 $base =~ s|/$||;
301 26         84 $part =~ s|^/||;
302 26         106 $uri->path("$base/$part");
303              
304 26 100       944 $uri->query_form($params) if $params;
305              
306 26 100       1137 return $dont_escape ? uri_unescape($uri->canonical) : $uri->canonical;
307             }
308              
309             sub params {
310 436     436 1 1636 my ($self, $source) = @_;
311              
312 436         1406 my @caller = caller;
313              
314 436 100       1371 if (not $self->{_params_are_decoded}) {
315 289         924 $self->{params} = _decode($self->{params});
316 289         706 $self->{_body_params} = _decode($self->{_body_params});
317 289         693 $self->{_query_params} = _decode($self->{_query_params});
318 289         833 $self->{_route_params} = _decode($self->{_route_params});
319 289         1414 $self->{_params_are_decoded} = 1;
320             }
321              
322 436 100 100     1256 return %{$self->{params}} if wantarray && @_ == 1;
  15         110  
323 421 100       2172 return $self->{params} if @_ == 1;
324              
325 19 100       99 if ($source eq 'query') {
    50          
326 4 100       25 return %{$self->{_query_params}} if wantarray;
  2         16  
327 2         11 return $self->{_query_params};
328             }
329             elsif ($source eq 'body') {
330 15 50       87 return %{$self->{_body_params}} if wantarray;
  0         0  
331 15         69 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   7907 my ($h) = @_;
344 2538 100       4848 return if not defined $h;
345              
346 2526 100 100     6279 if (!ref($h) && !utf8::is_utf8($h)) {
347 622         2597 return decode('UTF-8', $h);
348             }
349              
350 1904 100       4070 if (ref($h) eq 'HASH') {
351 1793         5398 while (my ($k, $v) = each(%$h)) {
352 631         8027 $h->{$k} = _decode($v);
353             }
354 1793         22704 return $h;
355             }
356              
357 111 100       249 if (ref($h) eq 'ARRAY') {
358 83         162 return [ map { _decode($_) } @$h ];
  140         2498  
359             }
360              
361 28         94 return $h;
362             }
363              
364             sub is_ajax {
365 614     614 1 997 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       1488 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       1481 return 0 unless defined $self->headers;
376 4 100       17 return 0 unless defined $self->header('X-Requested-With');
377 1 50       40 return 0 if $self->header('X-Requested-With') ne 'XMLHttpRequest';
378 1         46 return 1;
379             }
380              
381             # context-aware accessor for uploads
382             sub upload {
383 8     8 1 755 my ($self, $name) = @_;
384 8         17 my $res = $self->{uploads}{$name};
385              
386 8 100       34 return $res unless wantarray;
387 3 100       9 return () unless defined $res;
388 2 100       11 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   1254 my ($self, $params) = @_;
396 649         1432 $self->{_route_params} = $params;
397 649         1421 $self->_build_params();
398             }
399              
400             sub _set_body_params {
401 8     8   22 my ($self, $params) = @_;
402 8         21 $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   1168 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         1544 my $env = $self->env;
419 611         1357 $self->{user_agent} = $env->{HTTP_USER_AGENT};
420 611         2152 $self->{host} = $env->{HTTP_HOST};
421 611         1207 $self->{accept_language} = $env->{HTTP_ACCEPT_LANGUAGE};
422 611         1777 $self->{accept_charset} = $env->{HTTP_ACCEPT_CHARSET};
423 611         1133 $self->{accept_encoding} = $env->{HTTP_ACCEPT_ENCODING};
424 611         1250 $self->{keep_alive} = $env->{HTTP_KEEP_ALIVE};
425 611         1308 $self->{connection} = $env->{HTTP_CONNECTION};
426 611         1264 $self->{accept} = $env->{HTTP_ACCEPT};
427 611         1244 $self->{accept_type} = $env->{HTTP_ACCEPT_TYPE};
428 611         1158 $self->{referer} = $env->{HTTP_REFERER};
429 611         1365 $self->{x_requested_with} = $env->{HTTP_X_REQUESTED_WITH};
430             }
431              
432             sub _build_headers {
433 611     611   1205 my ($self) = @_;
434 611         2548 $self->{headers} = Dancer::SharedData->headers;
435             }
436              
437             sub _build_params {
438 2450     2450   4760 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         4205 my $previous = $self->{params};
443              
444             # now parse environment params...
445 2450         6385 $self->_parse_get_params();
446 2450 100       5847 if ($self->is_forward) {
447 47   100     120 $self->{_body_params} ||= {};
448             } else {
449 2403         5313 $self->_parse_post_params();
450             }
451              
452             # and merge everything
453             $self->{params} = {
454 2450         4433 %$previous, %{$self->{_query_params}},
455 2450         8391 %{$self->{_route_params}}, %{$self->{_body_params}},
  2450         3936  
  2450         6798  
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   1230 my ($self) = @_;
464 611         1217 my $path = "";
465              
466 611 100       1740 $path .= $self->script_name if defined $self->script_name;
467 611 100       1591 $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       1744 if (defined $self->request_uri) {
472 526   33     1819 $path ||= $self->_url_decode($self->request_uri);
473             }
474              
475 611 50       1466 raise core_request => "Cannot resolve path" if not $path;
476 611         1310 $self->{path} = $path;
477             }
478              
479             sub _build_path_info {
480 611     611   1516 my ($self) = @_;
481 611         1757 my $info = $self->env->{PATH_INFO};
482 611 100       1873 if (defined $info) {
483              
484             # Empty path info will be interpreted as "root".
485 604   50     1690 $info ||= '/';
486             }
487             else {
488 7         22 $info = $self->path;
489             }
490 611         1504 $self->{path_info} = $info;
491             }
492              
493             sub _build_method {
494 611     611   1277 my ($self) = @_;
495             $self->{method} = $self->env->{REQUEST_METHOD}
496 611   33     1932 || $self->{request}->request_method();
497             }
498              
499             sub _url_decode {
500 80     80   132 my ($self, $encoded) = @_;
501 80         115 my $clean = $encoded;
502 80         116 $clean =~ tr/\+/ /;
503 80         146 $clean =~ s/%([a-fA-F0-9]{2})/pack "H2", $1/eg;
  4         21  
504 80         153 return $clean;
505             }
506              
507             sub _parse_post_params {
508 2403     2403   4505 my ($self) = @_;
509 2403 100       5912 return $self->{_body_params} if defined $self->{_body_params};
510              
511 595         1949 $self->_read_to_end();
512 595         2496 $self->{_body_params} = $self->{_http_body}->param;
513             }
514              
515             sub _parse_get_params {
516 2450     2450   4197 my ($self) = @_;
517 2450 100       7252 return $self->{_query_params} if defined $self->{_query_params};
518 611         1708 $self->{_query_params} = {};
519              
520 611   100     2180 my $source = $self->env->{QUERY_STRING} || '';
521 611         2962 foreach my $token (split /[&;]/, $source) {
522 40         115 my ($key, $val) = split(/=/, $token, 2);
523 40 50       95 next unless defined $key;
524 40 50       114 $val = (defined $val) ? $val : '';
525 40         91 $key = $self->_url_decode($key);
526 40         75 $val = $self->_url_decode($val);
527              
528             # looking for multi-value params
529 40 100       103 if (exists $self->{_query_params}{$key}) {
530 4         9 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         16 $self->{_query_params}{$key} = [$prev_val, $val];
536             }
537             }
538              
539             # simple value param (first time we see it)
540             else {
541 36         99 $self->{_query_params}{$key} = $val;
542             }
543             }
544 611         1478 return $self->{_query_params};
545             }
546              
547             sub _read_to_end {
548 595     595   1324 my $self = shift;
549            
550 595 100       1604 return unless $self->_has_something_to_read;
551              
552 32 100       108 if ( $self->content_length > 0 ) {
553 20         43 my $body = '';
554              
555 20         70 my $store_raw_body = setting('raw_request_body_in_ram');
556 20 50       93 $store_raw_body = defined $store_raw_body ? $store_raw_body : 1;
557              
558 20         72 while ( my $buffer = $self->_read ) {
559 20         107 $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       17075 if ($store_raw_body) {
565 20         83 $self->{body} .= $buffer;
566             }
567             }
568              
569             }
570              
571 32         71 return $self->{_http_body};
572             }
573              
574             sub _has_something_to_read {
575 595     595   1865 defined $_[0]->input_handle;
576             }
577              
578             # taken from Miyagawa's Plack::Request::BodyParser
579             sub _read {
580 40     40   86 my ($self,) = @_;
581 40         101 my $remaining = $self->content_length - $self->{_read_position};
582 40         73 my $maxlength = $self->{_chunk_size};
583              
584 40 100       125 return if ($remaining <= 0);
585              
586 20 50       50 my $readlen = ($remaining > $maxlength) ? $maxlength : $remaining;
587 20         35 my $buffer;
588             my $rc;
589              
590 20         47 $rc = $self->input_handle->read($buffer, $readlen);
591              
592 20 50       204 if (defined $rc) {
593 20         40 $self->{_read_position} += $rc;
594 20         74 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   1372 my ($self) = @_;
604              
605 611         1960 my $uploads = _decode($self->{_http_body}->upload);
606 611         1234 my %uploads;
607              
608 611         900 for my $name (keys %{$uploads}) {
  611         1579  
609 9         17 my $files = $uploads->{$name};
610 9 100       40 $files = ref $files eq 'ARRAY' ? $files : [$files];
611              
612 9         19 my @uploads;
613 9         13 for my $upload (@{$files}) {
  9         21  
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         64 );
623             }
624 9 100       28 $uploads{$name} = @uploads > 1 ? \@uploads : $uploads[0];
625              
626             # support access to the filename as a normal param
627 9         20 my @filenames = map { $_->{filename} } @uploads;
  11         55  
628 9 100       37 $self->{_body_params}{$name} =
629             @filenames > 1 ? \@filenames : $filenames[0];
630             }
631              
632 611         1701 $self->{uploads} = \%uploads;
633 611         1266 $self->_build_params();
634             }
635              
636             1;
637              
638             __END__