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.3514_04'; # TRIAL
5             $Dancer::Request::VERSION = '1.351404';
6 183     183   765377 use strict;
  183         409  
  183         4354  
7 183     183   775 use warnings;
  183         309  
  183         3703  
8 183     183   754 use Carp;
  183         304  
  183         8789  
9              
10 183     183   1132 use base 'Dancer::Object';
  183         417  
  183         22123  
11              
12 183     183   7658 use Dancer::Config 'setting';
  183         368  
  183         7582  
13 183     183   67716 use Dancer::Request::Upload;
  183         417  
  183         3792  
14 183     183   61142 use Dancer::SharedData;
  183         473  
  183         4921  
15 183     183   68391 use Dancer::Session;
  183         439  
  183         5455  
16 183     183   1047 use Dancer::Exception qw(:all);
  183         381  
  183         20157  
17 183     183   1066 use Encode;
  183         349  
  183         11533  
18 183     183   74832 use HTTP::Body;
  183         2879367  
  183         5302  
19 183     183   1307 use URI;
  183         375  
  183         4297  
20 183     183   877 use URI::Escape;
  183         365  
  183         262025  
21              
22             my @http_env_keys = (
23             'user_agent', 'accept_language', 'accept_charset',
24             'accept_encoding', 'keep_alive', 'connection', 'accept',
25             'accept_type', 'referer', #'host', managed manually
26             );
27             my $count = 0;
28              
29             __PACKAGE__->attributes(
30              
31             # query
32             'env', 'path', 'method',
33             'content_type', 'content_length',
34             'id',
35             'uploads', 'headers', 'path_info',
36             'ajax', 'is_forward',
37             @http_env_keys,
38             );
39              
40             sub new {
41 614     614 1 65980 my ($self, @args) = @_;
42 614 50       1818 if (@args == 1) {
43 0         0 @args = ('env' => $args[0]);
44 0         0 Dancer::Deprecation->deprecated(
45             fatal => 1,
46             feature => 'Calling Dancer::Request->new($env)',
47             version => 1.3059,
48             reason => 'Please use Dancer::Request->new( env => $env ) instead',
49             );
50             }
51 614         2838 $self->SUPER::new(@args);
52             }
53              
54             # aliases
55 1     1 1 4 sub agent { $_[0]->user_agent }
56 19     19 1 40 sub remote_address { $_[0]->address }
57 1 50   1 1 4 sub forwarded_for_address { $_[0]->env->{'X_FORWARDED_FOR'} || $_[0]->env->{'HTTP_X_FORWARDED_FOR'} }
58             sub address {
59             setting('behind_proxy')
60             ? $_[0]->forwarded_for_address()
61             : $_[0]->env->{REMOTE_ADDR}
62 19 50   19 1 46 }
63             sub host {
64 34 50   34 1 83 if (@_==2) {
65 0         0 $_[0]->{host} = $_[1];
66             } else {
67 34         43 my $host;
68 34 100 33     88 $host = ($_[0]->env->{X_FORWARDED_HOST} || $_[0]->env->{HTTP_X_FORWARDED_HOST}) if setting('behind_proxy');
69 34 100 100     180 $host || $_[0]->{host} || $_[0]->env->{HTTP_HOST};
70             }
71             }
72 0     0 1 0 sub remote_host { $_[0]->env->{REMOTE_HOST} }
73 1     1 1 5 sub protocol { $_[0]->env->{SERVER_PROTOCOL} }
74 1     1 1 5 sub port { $_[0]->env->{SERVER_PORT} }
75 620     620 1 1713 sub request_uri { $_[0]->env->{REQUEST_URI} }
76 1     1 1 3 sub user { $_[0]->env->{REMOTE_USER} }
77 625     625 1 1378 sub script_name { $_[0]->env->{SCRIPT_NAME} }
78 1 50   1 1 4 sub request_base { $_[0]->env->{REQUEST_BASE} || $_[0]->env->{HTTP_REQUEST_BASE} }
79             sub scheme {
80 33     33 1 41 my $scheme;
81 33 100       64 if (setting('behind_proxy')) {
82             # PSGI specs say that X_FORWARDED_PROTO will
83             # be converted into HTTP_X_FORWARDED_PROTO
84             # but Dancer::Test doesn't use PSGI (for now)
85             $scheme = $_[0]->env->{'HTTP_X_FORWARDED_PROTO'}
86             || $_[0]->env->{'X_FORWARDED_PROTOCOL'}
87             || $_[0]->env->{'HTTP_X_FORWARDED_PROTOCOL'}
88             || $_[0]->env->{'HTTP_FORWARDED_PROTO'}
89 5   100     10 || $_[0]->env->{'X_FORWARDED_PROTO'}
90             || ""
91             }
92             return $scheme
93             || $_[0]->env->{'psgi.url_scheme'}
94 33   50     113 || $_[0]->env->{'PSGI.URL_SCHEME'}
95             || "";
96             }
97 1     1 1 5 sub secure { $_[0]->scheme eq 'https' }
98 3     3 1 9 sub uri { $_[0]->request_uri }
99              
100 18     18 1 58 sub is_head { $_[0]->{method} eq 'HEAD' }
101 10     10 1 70 sub is_post { $_[0]->{method} eq 'POST' }
102 2     2 1 8 sub is_get { $_[0]->{method} eq 'GET' }
103 15     15 1 76 sub is_put { $_[0]->{method} eq 'PUT' }
104 2     2 1 10 sub is_delete { $_[0]->{method} eq 'DELETE' }
105 1     1 1 6 sub is_patch { $_[0]->{method} eq 'PATCH' }
106 7     7 1 30 sub header { $_[0]->{headers}->header($_[1]) }
107              
108             # We used to store the whole raw unparsed body; this was a big problem for large
109             # file uploads (Issue 1129).
110             # The original fix was to stop doing so, and replace the accessor with one that
111             # would read it out of the temp file returned by HTTP::Body->body - but that
112             # doesn't work for e.g. parsed form submissions, only certain types.
113             # So, back to the older way - we may have a request body squirreled away
114             # in memory if the config included the raw_request_body_in_ram boolean
115 17     17 1 82 sub body { $_[0]->{body} }
116              
117             # public interface compat with CGI.pm objects
118 1     1 1 6 sub request_method { method(@_) }
119 2     2 1 5 sub Vars { params(@_) }
120 618 100   618 1 1391 sub input_handle { $_[0]->env->{'psgi.input'} || $_[0]->env->{'PSGI.INPUT'} }
121              
122             sub init {
123 614     614 1 1707 my ($self) = @_;
124              
125 614   50     2207 $self->{env} ||= {};
126 614         1459 $self->{path} = undef;
127 614         1652 $self->{method} = undef;
128 614         1716 $self->{params} = {};
129 614   100     3665 $self->{is_forward} ||= 0;
130 614   100     2015 $self->{content_length} = $self->env->{CONTENT_LENGTH} || 0;
131 614   100     1987 $self->{content_type} = $self->env->{CONTENT_TYPE} || '';
132 614         2217 $self->{id} = ++$count;
133 614         1553 $self->{_chunk_size} = 4096;
134 614         1754 $self->{_read_position} = 0;
135 614         1576 $self->{_body_params} = undef;
136 614         1642 $self->{_query_params} = undef;
137 614         1613 $self->{_route_params} = {};
138              
139 614         1918 $self->_build_headers();
140 614         2019 $self->_build_request_env();
141 614 50       1584 $self->_build_path() unless $self->path;
142 614 50       1490 $self->_build_path_info() unless $self->path_info;
143 614 50       1489 $self->_build_method() unless $self->method;
144              
145             $self->{_http_body}
146 614         1586 = HTTP::Body->new($self->content_type, $self->content_length);
147 614         41433 $self->{_http_body}->cleanup(1);
148 614         3794 $self->{body} = ''; # default, because we might not store it now.
149 614         1568 $self->_build_params();
150 614 50       1864 $self->_build_uploads unless $self->uploads;
151 614         1668 $self->{ajax} = $self->is_ajax;
152              
153 614         1256 return $self;
154             }
155              
156             sub to_string {
157 1     1 1 4 my ($self) = @_;
158 1         3 return "[#" . $self->id . "] " . $self->method . " " . $self->path;
159             }
160              
161             # helper for building a request object by hand
162             # with the given method, path, params, body and headers.
163             sub new_for_request {
164 574     574 1 3298 my ($class, $method, $uri, $params, $body, $headers, $extra_env) = @_;
165 574   100     2705 $params ||= {};
166 574   100     1695 $extra_env ||= {};
167 574         1256 $method = uc($method);
168              
169 574         3281 my ( $path, $query_string ) = ( $uri =~ /([^?]*)(?:\?(.*))?/s ); #from HTTP::Server::Simple
170              
171             my $env = {
172             %ENV,
173 574         15331 %{$extra_env},
174             PATH_INFO => $path,
175 574   100     4812 QUERY_STRING => $query_string || $ENV{QUERY_STRING} || '',
176             REQUEST_METHOD => $method
177             };
178 574 100       3447 $env->{CONTENT_LENGTH} = defined($body) ? length($body) : 0 if !exists $env->{CONTENT_LENGTH};
    100          
179 574         2397 my $req = $class->new(env => $env);
180 574         828 $req->{params} = {%{$req->{params}}, %{$params}};
  574         1087  
  574         1116  
181 574         1420 $req->_build_params();
182 574         1023 $req->{_query_params} = $req->{params};
183 574         1718 my $store_raw_body = setting('raw_request_body_in_ram');
184 574 50       1233 $store_raw_body = defined $store_raw_body ? $store_raw_body : 1;
185 574 50       1163 if ($store_raw_body) {
186 574         913 $req->{body} = $body;
187             }
188 574   66     1535 $req->{headers} = $headers || HTTP::Headers->new;
189              
190 574         2226 return $req;
191             }
192              
193             #Create a new request which is a clone of the current one, apart
194             #from the path location, which points instead to the new location
195             sub forward {
196 16     16 1 28 my ($class, $request, $to_data) = @_;
197              
198 16         35 my $env = $request->env;
199 16         29 $env->{PATH_INFO} = $to_data->{to_url};
200              
201 16         33 my $new_request = $class->new(env => $env, is_forward => 1);
202             my $new_params = _merge_params(scalar($request->params),
203 16   100     31 $to_data->{params} || {});
204              
205 16 100       34 if (exists($to_data->{options}{method})) {
206 2 50       4 die unless _valid_method($to_data->{options}{method});
207 2         4 $new_request->{method} = uc $to_data->{options}{method};
208             }
209              
210 16         21 $new_request->{params} = $new_params;
211 16         24 $new_request->{_body_params} = $request->{_body_params};
212 16         20 $new_request->{_query_params} = $request->{_query_params};
213 16         20 $new_request->{_route_params} = $request->{_route_params};
214 16         19 $new_request->{_params_are_decoded} = 1;
215 16         35 $new_request->{headers} = $request->headers;
216              
217 16 100 66     53 if( my $session = Dancer::Session->engine
218             && Dancer::Session->get_current_session ) {
219 15         25 my $name = $session->session_name;
220              
221             # make sure that COOKIE is populated
222 15   33     56 $new_request->{env}{COOKIE} ||= $new_request->{env}{HTTP_COOKIE};
223              
224 183     183   1481 no warnings; # COOKIE can be undef
  183         456  
  183         426402  
225 15 50       74 unless ( $new_request->{env}{COOKIE} =~ /$name\s*=/ ) {
226             $new_request->{env}{COOKIE} = join ';',
227 30         58 grep { $_ }
228             $new_request->{env}{COOKIE},
229 15         36 join '=', $name, Dancer::Session->get_current_session->id;
230             }
231             }
232              
233 16         34 $new_request->{uploads} = $request->uploads;
234              
235 16         45 return $new_request;
236             }
237              
238             sub _valid_method {
239 2     2   3 my $method = shift;
240 2         12 return $method =~ /^(?:head|post|get|put|delete)$/i;
241             }
242              
243             sub _merge_params {
244 16     16   26 my ($params, $to_add) = @_;
245              
246 16 50       29 die unless ref $to_add eq "HASH";
247 16         32 for my $key (keys %$to_add) {
248 4         7 $params->{$key} = $to_add->{$key};
249             }
250 16         21 return $params;
251             }
252              
253             sub base {
254 29     29 1 1334 my $self = shift;
255 29         55 my $uri = $self->_common_uri;
256              
257 29         95 return $uri->canonical;
258             }
259              
260             sub _common_uri {
261 32     32   43 my $self = shift;
262              
263 32   100     66 my $path = $self->env->{SCRIPT_NAME} || '';
264 32         59 my $port = $self->env->{SERVER_PORT};
265 32         67 my $server = $self->env->{SERVER_NAME};
266 32         91 my $host = $self->host;
267 32         72 my $scheme = $self->scheme;
268              
269 32         120 my $uri = URI->new;
270 32         33345 $uri->scheme($scheme);
271 32   66     28357 $uri->authority($host || "$server:$port");
272 32 100       1278 if (setting('behind_proxy')) {
273 5   100     12 my $request_base = $self->env->{REQUEST_BASE} || $self->env->{HTTP_REQUEST_BASE} || '';
274 5   100     26 $uri->path($request_base . $path || '/');
275             }
276             else {
277 27   100     135 $uri->path($path || '/');
278             }
279              
280 32         1002 return $uri;
281             }
282              
283             sub uri_base {
284 3     3 1 22 my $self = shift;
285 3         7 my $uri = $self->_common_uri;
286 3         8 my $canon = $uri->canonical;
287              
288 3 100       320 if ( $uri->path eq '/' ) {
289 2         23 $canon =~ s{/$}{};
290             }
291              
292 3         76 return $canon;
293             }
294              
295             sub uri_for {
296 26     26 1 5817 my ($self, $part, $params, $dont_escape) = @_;
297 26         58 my $uri = $self->base;
298              
299             # Make sure there's exactly one slash between the base and the new part
300 26         2296 my $base = $uri->path;
301 26         240 $base =~ s|/$||;
302 26         65 $part =~ s|^/||;
303 26         96 $uri->path("$base/$part");
304              
305 26 100       722 $uri->query_form($params) if $params;
306              
307 26 100       868 return $dont_escape ? uri_unescape($uri->canonical) : $uri->canonical;
308             }
309              
310             sub params {
311 436     436 1 1443 my ($self, $source) = @_;
312              
313 436         1375 my @caller = caller;
314              
315 436 100       1129 if (not $self->{_params_are_decoded}) {
316 289         667 $self->{params} = _decode($self->{params});
317 289         624 $self->{_body_params} = _decode($self->{_body_params});
318 289         609 $self->{_query_params} = _decode($self->{_query_params});
319 289         566 $self->{_route_params} = _decode($self->{_route_params});
320 289         1217 $self->{_params_are_decoded} = 1;
321             }
322              
323 436 100 100     1108 return %{$self->{params}} if wantarray && @_ == 1;
  15         79  
324 421 100       1928 return $self->{params} if @_ == 1;
325              
326 19 100       113 if ($source eq 'query') {
    50          
327 4 100       11 return %{$self->{_query_params}} if wantarray;
  2         14  
328 2         8 return $self->{_query_params};
329             }
330             elsif ($source eq 'body') {
331 15 50       58 return %{$self->{_body_params}} if wantarray;
  0         0  
332 15         57 return $self->{_body_params};
333             }
334 0 0       0 if ($source eq 'route') {
335 0 0       0 return %{$self->{_route_params}} if wantarray;
  0         0  
336 0         0 return $self->{_route_params};
337             }
338             else {
339 0         0 raise core_request => "Unknown source params \"$source\".";
340             }
341             }
342              
343             sub _decode {
344 2541     2541   6540 my ($h) = @_;
345 2541 100       4002 return if not defined $h;
346              
347 2529 100 100     5340 if (!ref($h) && !utf8::is_utf8($h)) {
348 622         2424 return decode('UTF-8', $h);
349             }
350              
351 1907 100       3415 if (ref($h) eq 'HASH') {
352 1796         4448 while (my ($k, $v) = each(%$h)) {
353 631         7413 $h->{$k} = _decode($v);
354             }
355 1796         18955 return $h;
356             }
357              
358 111 100       205 if (ref($h) eq 'ARRAY') {
359 83         136 return [ map { _decode($_) } @$h ];
  140         2317  
360             }
361              
362 28         84 return $h;
363             }
364              
365             sub is_ajax {
366 617     617 1 1013 my $self = shift;
367              
368             # when using Plack::Builder headers are not set
369             # so we're checking if it's actually there with PSGI plain headers
370 617 50       1511 if ( defined $self->{x_requested_with} ) {
371 0 0       0 if ( $self->{x_requested_with} eq "XMLHttpRequest" ) {
372 0         0 return 1;
373             }
374             }
375              
376 617 100       1423 return 0 unless defined $self->headers;
377 4 100       11 return 0 unless defined $self->header('X-Requested-With');
378 1 50       33 return 0 if $self->header('X-Requested-With') ne 'XMLHttpRequest';
379 1         29 return 1;
380             }
381              
382             # context-aware accessor for uploads
383             sub upload {
384 8     8 1 1308 my ($self, $name) = @_;
385 8         24 my $res = $self->{uploads}{$name};
386              
387 8 100       36 return $res unless wantarray;
388 3 100       12 return () unless defined $res;
389 2 100       297 return (ref($res) eq 'ARRAY') ? @$res : $res;
390             }
391              
392             # Some Dancer's core components sometimes need to alter
393             # the parsed request params, these protected accessors are provided
394             # for this purpose
395             sub _set_route_params {
396 652     652   1160 my ($self, $params) = @_;
397 652         1227 $self->{_route_params} = $params;
398 652         1273 $self->_build_params();
399             }
400              
401             sub _set_body_params {
402 8     8   21 my ($self, $params) = @_;
403 8         16 $self->{_body_params} = $params;
404 8         19 $self->_build_params();
405             }
406              
407             sub _set_query_params {
408 0     0   0 my ($self, $params) = @_;
409 0         0 $self->{_query_params} = $params;
410 0         0 $self->_build_params();
411             }
412              
413             sub _build_request_env {
414 614     614   1157 my ($self) = @_;
415              
416             # Don't refactor that, it's called whenever a request object is needed, that
417             # means at least once per request. If refactored in a loop, this will cost 4
418             # times more than the following static map.
419 614         1443 my $env = $self->env;
420 614         1534 $self->{user_agent} = $env->{HTTP_USER_AGENT};
421 614         1695 $self->{host} = $env->{HTTP_HOST};
422 614         1545 $self->{accept_language} = $env->{HTTP_ACCEPT_LANGUAGE};
423 614         1107 $self->{accept_charset} = $env->{HTTP_ACCEPT_CHARSET};
424 614         1132 $self->{accept_encoding} = $env->{HTTP_ACCEPT_ENCODING};
425 614         964 $self->{keep_alive} = $env->{HTTP_KEEP_ALIVE};
426 614         1547 $self->{connection} = $env->{HTTP_CONNECTION};
427 614         1046 $self->{accept} = $env->{HTTP_ACCEPT};
428 614         1100 $self->{accept_type} = $env->{HTTP_ACCEPT_TYPE};
429 614         1106 $self->{referer} = $env->{HTTP_REFERER};
430 614         1483 $self->{x_requested_with} = $env->{HTTP_X_REQUESTED_WITH};
431             }
432              
433             sub _build_headers {
434 614     614   1602 my ($self) = @_;
435 614         2600 $self->{headers} = Dancer::SharedData->headers;
436             }
437              
438             sub _build_params {
439 2462     2462   3429 my ($self) = @_;
440              
441             # params may have been populated by before filters
442             # _before_ we get there, so we have to save it first
443 2462         3109 my $previous = $self->{params};
444              
445             # now parse environment params...
446 2462         4881 $self->_parse_get_params();
447 2462 100       4389 if ($self->is_forward) {
448 47   100     118 $self->{_body_params} ||= {};
449             } else {
450 2415         3829 $self->_parse_post_params();
451             }
452              
453             # and merge everything
454             $self->{params} = {
455 2462         3509 %$previous, %{$self->{_query_params}},
456 2462         6755 %{$self->{_route_params}}, %{$self->{_body_params}},
  2462         3567  
  2462         5565  
457             };
458              
459             }
460              
461             # Written from PSGI specs:
462             # http://search.cpan.org/dist/PSGI/PSGI.pod
463             sub _build_path {
464 614     614   1124 my ($self) = @_;
465 614         1085 my $path = "";
466              
467 614 100       1870 $path .= $self->script_name if defined $self->script_name;
468 614 100       1499 $path .= $self->env->{PATH_INFO} if defined $self->env->{PATH_INFO};
469              
470             # fallback to REQUEST_URI if nothing found
471             # we have to decode it, according to PSGI specs.
472 614 100       1510 if (defined $self->request_uri) {
473 529   33     1108 $path ||= $self->_url_decode($self->request_uri);
474             }
475              
476 614 50       1256 raise core_request => "Cannot resolve path" if not $path;
477 614         1278 $self->{path} = $path;
478             }
479              
480             sub _build_path_info {
481 614     614   984 my ($self) = @_;
482 614         1195 my $info = $self->env->{PATH_INFO};
483 614 100       1287 if (defined $info) {
484              
485             # Empty path info will be interpreted as "root".
486 607   50     1272 $info ||= '/';
487             }
488             else {
489 7         16 $info = $self->path;
490             }
491 614         1195 $self->{path_info} = $info;
492             }
493              
494             sub _build_method {
495 614     614   1013 my ($self) = @_;
496             $self->{method} = $self->env->{REQUEST_METHOD}
497 614   33     1153 || $self->{request}->request_method();
498             }
499              
500             sub _url_decode {
501 80     80   114 my ($self, $encoded) = @_;
502 80         94 my $clean = $encoded;
503 80         100 $clean =~ tr/\+/ /;
504 80         133 $clean =~ s/%([a-fA-F0-9]{2})/pack "H2", $1/eg;
  4         18  
505 80         113 return $clean;
506             }
507              
508             sub _parse_post_params {
509 2415     2415   3167 my ($self) = @_;
510 2415 100       4583 return $self->{_body_params} if defined $self->{_body_params};
511              
512 598         1460 $self->_read_to_end();
513 598         2110 $self->{_body_params} = $self->{_http_body}->param;
514             }
515              
516             sub _parse_get_params {
517 2462     2462   3184 my ($self) = @_;
518 2462 100       5104 return $self->{_query_params} if defined $self->{_query_params};
519 614         1066 $self->{_query_params} = {};
520              
521 614   100     1395 my $source = $self->env->{QUERY_STRING} || '';
522 614         1921 foreach my $token (split /[&;]/, $source) {
523 40         97 my ($key, $val) = split(/=/, $token, 2);
524 40 50       80 next unless defined $key;
525 40 50       66 $val = (defined $val) ? $val : '';
526 40         70 $key = $self->_url_decode($key);
527 40         66 $val = $self->_url_decode($val);
528              
529             # looking for multi-value params
530 40 100       80 if (exists $self->{_query_params}{$key}) {
531 4         7 my $prev_val = $self->{_query_params}{$key};
532 4 50 33     16 if (ref($prev_val) && ref($prev_val) eq 'ARRAY') {
533 0         0 push @{$self->{_query_params}{$key}}, $val;
  0         0  
534             }
535             else {
536 4         13 $self->{_query_params}{$key} = [$prev_val, $val];
537             }
538             }
539              
540             # simple value param (first time we see it)
541             else {
542 36         75 $self->{_query_params}{$key} = $val;
543             }
544             }
545 614         998 return $self->{_query_params};
546             }
547              
548             sub _read_to_end {
549 598     598   921 my $self = shift;
550            
551 598 100       1235 return unless $self->_has_something_to_read;
552              
553 32 100       102 if ( $self->content_length > 0 ) {
554 20         42 my $body = '';
555              
556 20         88 my $store_raw_body = setting('raw_request_body_in_ram');
557 20 50       78 $store_raw_body = defined $store_raw_body ? $store_raw_body : 1;
558              
559 20         61 while ( my $buffer = $self->_read ) {
560 20         123 $self->{_http_body}->add($buffer);
561              
562             # Only keep a copy of the raw request body in RAM if the user has
563             # asked us to
564            
565 20 50       16168 if ($store_raw_body) {
566 20         100 $self->{body} .= $buffer;
567             }
568             }
569              
570             }
571              
572 32         66 return $self->{_http_body};
573             }
574              
575             sub _has_something_to_read {
576 598     598   1639 defined $_[0]->input_handle;
577             }
578              
579             # taken from Miyagawa's Plack::Request::BodyParser
580             sub _read {
581 40     40   83 my ($self,) = @_;
582 40         108 my $remaining = $self->content_length - $self->{_read_position};
583 40         69 my $maxlength = $self->{_chunk_size};
584              
585 40 100       146 return if ($remaining <= 0);
586              
587 20 50       53 my $readlen = ($remaining > $maxlength) ? $maxlength : $remaining;
588 20         37 my $buffer;
589             my $rc;
590              
591 20         46 $rc = $self->input_handle->read($buffer, $readlen);
592              
593 20 50       236 if (defined $rc) {
594 20         42 $self->{_read_position} += $rc;
595 20         97 return $buffer;
596             }
597             else {
598 0         0 raise core_request => "Unknown error reading input: $!";
599             }
600             }
601              
602             # Taken gently from Plack::Request, thanks to Plack authors.
603             sub _build_uploads {
604 614     614   1090 my ($self) = @_;
605              
606 614         1948 my $uploads = _decode($self->{_http_body}->upload);
607 614         1472 my %uploads;
608              
609 614         920 for my $name (keys %{$uploads}) {
  614         1293  
610 9         17 my $files = $uploads->{$name};
611 9 100       39 $files = ref $files eq 'ARRAY' ? $files : [$files];
612              
613 9         13 my @uploads;
614 9         13 for my $upload (@{$files}) {
  9         18  
615             push(
616             @uploads,
617             Dancer::Request::Upload->new(
618             headers => $upload->{headers},
619             tempname => $upload->{tempname},
620             size => $upload->{size},
621             filename => $upload->{filename},
622             )
623 11         150 );
624             }
625 9 100       31 $uploads{$name} = @uploads > 1 ? \@uploads : $uploads[0];
626              
627             # support access to the filename as a normal param
628 9         21 my @filenames = map { $_->{filename} } @uploads;
  11         36  
629 9 100       38 $self->{_body_params}{$name} =
630             @filenames > 1 ? \@filenames : $filenames[0];
631             }
632              
633 614         1276 $self->{uploads} = \%uploads;
634 614         1175 $self->_build_params();
635             }
636              
637             1;
638              
639             __END__