File Coverage

blib/lib/Dancer2/Core/Request.pm
Criterion Covered Total %
statement 307 327 93.8
branch 109 132 82.5
condition 43 59 72.8
subroutine 81 88 92.0
pod 47 54 87.0
total 587 660 88.9


line stmt bran cond sub pod time code
1             package Dancer2::Core::Request;
2             # ABSTRACT: Interface for accessing incoming requests
3             $Dancer2::Core::Request::VERSION = '2.0.1';
4 160     160   723264 use strict;
  160         399  
  160         6524  
5 160     160   799 use warnings;
  160         308  
  160         10021  
6 160     160   2581 use parent 'Plack::Request';
  160         1563  
  160         1520  
7              
8 160     160   14257099 use Carp;
  160         439  
  160         12129  
9 160     160   1074 use Encode;
  160         457  
  160         12757  
10 160     160   1046 use URI;
  160         367  
  160         4018  
11 160     160   839 use URI::Escape;
  160         807  
  160         8622  
12 160     160   7463 use Safe::Isa;
  160         8287  
  160         26091  
13 160     160   1218 use Hash::MultiValue;
  160         370  
  160         5994  
14 160     160   5911 use Ref::Util qw< is_ref is_arrayref is_hashref is_coderef >;
  160         16023  
  160         12196  
15              
16 160     160   6621 use Dancer2::Core::Types;
  160         444  
  160         3057  
17 160     160   2542860 use Dancer2::Core::Request::Upload;
  160         941  
  160         8671  
18 160     160   8328 use Dancer2::Core::Cookie;
  160         483  
  160         28841  
19              
20             # add an attribute for each HTTP_* variables
21             # (HOST is managed manually)
22             my @http_env_keys = (qw/
23             accept_charset
24             accept_encoding
25             accept_language
26             connection
27             keep_alive
28             x_requested_with
29             /);
30              
31             # apparently you can't eval core functions
32 1     1 1 3017 sub accept { $_[0]->env->{'HTTP_ACCEPT'} }
33              
34 1     1 1 721 eval << "_EVAL" or die $@ for @http_env_keys; ## no critic
  1     1 1 738  
  1     1 1 716  
  1     1 1 699  
  1     1 1 718  
  1     1 1 2395  
35             sub $_ { \$_[0]->env->{ 'HTTP_' . ( uc "$_" ) } }
36             1;
37             _EVAL
38              
39             eval {
40             require Unicode::UTF8;
41 160     160   8390 no warnings qw;
  160         357  
  160         23198  
42 21580     21580   56538 *__decode = sub { Unicode::UTF8::decode_utf8($_[0]) };
43             1;
44             } or do {
45 160     160   1286 no warnings qw;
  160         420  
  160         853366  
46             *__decode = sub { decode( 'UTF-8', $_[0] ) };
47             };
48              
49             # check presence of XS module to speedup request
50             our $XS_URL_DECODE = eval { require URL::Encode::XS; 1; };
51             our $XS_PARSE_QUERY_STRING = eval { require CGI::Deurl::XS; 1; };
52             our $XS_HTTP_COOKIES = eval { require HTTP::XSCookies; 1; };
53              
54             our $_id = 0;
55              
56             # self->new( env => {}, serializer => $s, is_behind_proxy => 0|1 )
57             sub new {
58 779     779 1 2034120 my ( $class, @args ) = @_;
59              
60             # even sized list
61 779 50       3633 @args % 2 == 0
62             or croak 'Must provide even sized list';
63              
64 779         4047 my %opts = @args;
65 779         2116 my $env = $opts{'env'};
66              
67 779         6344 my $self = $class->SUPER::new($env);
68              
69 779 100       12542 if ( my $s = $opts{'serializer'} ) {
70 85 100       527 $s->$_does('Dancer2::Core::Role::Serializer')
71             or croak 'Serializer provided not a Serializer object';
72              
73 84         7690 $self->{'serializer'} = $s;
74             }
75              
76             # additionally supported attributes
77 778         3098 $self->{'id'} = ++$_id;
78 778         2447 $self->{'vars'} = {};
79 778         2514 $self->{'is_behind_proxy'} = !!$opts{'is_behind_proxy'};
80 778         2108 $self->{'uri_for_route'} = $opts{'uri_for_route'};
81              
82             $opts{'body_params'}
83 778 100       2838 and $self->{'_body_params'} = $opts{'body_params'};
84              
85             # Deserialize/parse body for HMV
86 778         3905 $self->data;
87 775         4338 $self->_build_uploads();
88              
89 774         4279 return $self;
90             }
91              
92             # a buffer for per-request variables
93 100     100 1 367 sub vars { $_[0]->{'vars'} }
94              
95             sub var {
96 12     12 1 1171 my $self = shift;
97             @_ == 2
98             ? $self->vars->{ $_[0] } = $_[1]
99 12 100       75 : $self->vars->{ $_[0] };
100             }
101              
102             # I don't like this. I know send_file uses this and I wonder
103             # if we can remove it.
104             # -- Sawyer
105 0     0 0 0 sub set_path_info { $_[0]->env->{'PATH_INFO'} = $_[1] }
106              
107             # XXX: incompatible with Plack::Request
108 32     32 1 359 sub body { $_[0]->raw_body }
109              
110 17     17 1 4730 sub id { $_id }
111              
112             # Private 'read-only' attributes for request params. See the params()
113             # method for the public interface.
114             #
115             # _body_params, _query_params and _route_params have setter methods that
116             # decode byte string to characters before setting; If you know you have
117             # decoded (character) params, such as output from a deserializer, you can
118             # set these directly in the request object hash to avoid the decode op.
119 297   66 297   1953 sub _params { $_[0]->{'_params'} ||= $_[0]->_build_params }
120              
121 612     612   2975 sub _has_params { defined $_[0]->{'_params'} }
122              
123 1398   66 1398   7814 sub _body_params { $_[0]->{'_body_params'} ||= $_[0]->body_parameters->as_hashref_mixed }
124              
125 79     79   313 sub _query_params { $_[0]->{'_query_params'} }
126              
127             sub _set_query_params {
128 31     31   80 my ( $self, $params ) = @_;
129 31         97 $self->{_query_params} = _decode( $params );
130             }
131              
132 613   100 613   3537 sub _route_params { $_[0]->{'_route_params'} ||= {} }
133              
134             sub _set_route_params {
135 585     585   1792 my ( $self, $params ) = @_;
136 585         2241 $self->{_route_params} = _decode( $params );
137 585         2656 $self->_build_params();
138             }
139              
140             # XXX: incompatible with Plack::Request
141 5     5 1 33 sub uploads { $_[0]->{'uploads'} }
142              
143 333 100   333 0 2149 sub is_behind_proxy { $_[0]->{'is_behind_proxy'} || 0 }
144              
145             sub host {
146 160     160 1 2941 my ($self) = @_;
147              
148 160 100 100     551 if ( $self->is_behind_proxy and exists $self->env->{'HTTP_X_FORWARDED_HOST'} ) {
149 3         29 my @hosts = split /\s*,\s*/, $self->env->{'HTTP_X_FORWARDED_HOST'}, 2;
150 3         36 return $hosts[0];
151             } else {
152 157         621 return $self->env->{'HTTP_HOST'};
153             }
154             }
155              
156             # aliases, kept for backward compat
157 12     12 1 3460 sub agent { shift->user_agent }
158 4     4 1 8848 sub remote_address { shift->address }
159 3     3 1 8260 sub forwarded_for_address { shift->env->{'HTTP_X_FORWARDED_FOR'} }
160 0     0 1 0 sub forwarded_host { shift->env->{'HTTP_X_FORWARDED_HOST'} }
161              
162             # there are two options
163             sub forwarded_protocol {
164             $_[0]->env->{'HTTP_X_FORWARDED_PROTO'} ||
165             $_[0]->env->{'HTTP_X_FORWARDED_PROTOCOL'} ||
166 14 100 100 14 1 48 $_[0]->env->{'HTTP_FORWARDED_PROTO'}
167             }
168              
169             sub scheme {
170 172     172 1 19016 my ($self) = @_;
171 172 100       468 my $scheme = $self->is_behind_proxy
172             ? $self->forwarded_protocol
173             : '';
174              
175 172   66     989 return $scheme || $self->env->{'psgi.url_scheme'};
176             }
177              
178 835     835 1 7214 sub serializer { $_[0]->{'serializer'} }
179              
180 828   100 828 1 6310 sub data { $_[0]->{'data'} ||= $_[0]->deserialize() }
181              
182             sub deserialize {
183 778     778 0 1907 my $self = shift;
184              
185             # don't attempt to deserialize if the form is 'multipart/form-data'
186 778 100 100     3933 if (
187             $self->content_type
188             && $self->content_type =~ /^multipart\/form-data/i
189             ) {
190 7         207 return;
191             }
192              
193              
194 771 100       10317 my $serializer = $self->serializer
195             or return;
196              
197             # The latest draft of the RFC does not forbid DELETE to have content,
198             # rather the behaviour is undefined. Take the most lenient route and
199             # deserialize any content on delete as well.
200             return
201 83 100       243 unless grep { $self->method eq $_ } qw/ PUT POST PATCH DELETE /;
  332         1832  
202              
203             # try to deserialize
204 31         296 my $body = $self->body;
205              
206 31 100 66     14282 $body && length $body > 0
207             or return;
208              
209             # Catch serializer fails - which is tricky as Role::Serializer
210             # wraps the deserializaion in an eval and returns undef.
211             # We want to generate a 500 error on serialization fail (Ref #794)
212             # to achieve that, override the log callback so we can catch a signal
213             # that it failed. This is messy (messes with serializer internals), but
214             # "works".
215 30         72 my $serializer_fail;
216 30         151 my $serializer_log_cb = $serializer->log_cb;
217             local $serializer->{log_cb} = sub {
218 3     3   10 $serializer_fail = $_[1];
219 3         16 $serializer_log_cb->(@_);
220 30         233 };
221             # work-around to resolve a chicken-and-egg issue when instantiating a
222             # request object; the serializer needs that request object to deserialize
223             # the body params.
224 30         85 Scalar::Util::weaken( my $request = $self );
225 30 100       91 $self->serializer->has_request || $self->serializer->set_request($request);
226 30         1927 my $data = $serializer->deserialize($body);
227 30 100       168 die $serializer_fail if $serializer_fail;
228              
229             # Set _body_params directly rather than using the setter. Deserializiation
230             # returns characters and skipping the decode op in the setter ensures
231             # that numerical data "stays" numerical; decoding an SV that is an IV
232             # converts that to a PVIV. Some serializers are picky (JSON)..
233 27         118 $self->{_body_params} = $data;
234              
235             # Set body parameters (decoded HMV)
236 27 100       270 $self->{'body_parameters'} =
237             Hash::MultiValue->from_mixed( is_hashref($data) ? %$data : () );
238              
239 27         1679 return $data;
240             }
241              
242 3     3 1 17629 sub uri { $_[0]->request_uri }
243              
244 4     4 1 1372 sub is_head { $_[0]->method eq 'HEAD' }
245 7     7 1 8641 sub is_post { $_[0]->method eq 'POST' }
246 7     7 1 21820 sub is_get { $_[0]->method eq 'GET' }
247 4     4 1 1140 sub is_put { $_[0]->method eq 'PUT' }
248 4     4 1 1068 sub is_delete { $_[0]->method eq 'DELETE' }
249 4     4 0 2250 sub is_patch { $_[0]->method eq 'PATCH' }
250 0     0 1 0 sub is_options { $_[0]->method eq 'OPTIONS' }
251              
252             # public interface compat with CGI.pm objects
253 3     3 1 3563 sub request_method { $_[0]->method }
254 0     0 1 0 sub input_handle { $_[0]->env->{'psgi.input'} }
255              
256             sub to_string {
257 7     7 1 27243 my ($self) = @_;
258 7         37 return "[#" . $self->id . "] " . $self->method . " " . $self->path;
259             }
260              
261             sub base {
262 37     37 1 14979 my $self = shift;
263 37         107 my $uri = $self->_common_uri;
264              
265 37         125 return $uri->canonical;
266             }
267              
268             sub _common_uri {
269 154     154   329 my $self = shift;
270              
271 154         730 my $path = $self->env->{SCRIPT_NAME};
272 154         968 my $port = $self->env->{SERVER_PORT};
273 154         725 my $server = $self->env->{SERVER_NAME};
274 154         1946 my $host = $self->host;
275 154         1192 my $scheme = $self->scheme;
276              
277 154         1743 my $uri = URI->new;
278 154         39222 $uri->scheme($scheme);
279 154   66     24420 $uri->authority( $host || "$server:$port" );
280 154   100     12238 $uri->path( $path || '/' );
281              
282 154         6894 return $uri;
283             }
284              
285             sub uri_base {
286 117     117 1 14979 my $self = shift;
287 117         476 my $uri = $self->_common_uri;
288 117         602 my $canon = $uri->canonical;
289              
290 117 100       15565 if ( $uri->path eq '/' ) {
291 110         1783 $canon =~ s{/$}{};
292             }
293              
294 117         2462 return $canon;
295             }
296              
297             sub dispatch_path {
298 0     0 1 0 Carp::croak q{DEPRECATED: request->dispatch_path. Please use request->path instead};
299             }
300              
301             sub uri_for {
302 28     28 1 17933 my ( $self, $part, $params, $dont_escape ) = @_;
303              
304 28   50     75 $part ||= '';
305 28         116 my $uri = $self->base;
306              
307             # Make sure there's exactly one slash between the base and the new part
308 28         2615 my $base = $uri->path;
309 28         252 $base =~ s|/$||;
310 28         81 $part =~ s|^/||;
311 28         116 $uri->path("$base/$part");
312              
313 28 100       938 $uri->query_form($params) if $params;
314              
315             return $dont_escape
316 3         8 ? uri_unescape( ${ $uri->canonical } )
317 28 100       1443 : ${ $uri->canonical };
  25         61  
318             }
319              
320             sub uri_for_route {
321 0     0 1 0 my ( $self, @args ) = @_;
322              
323 0 0       0 is_coderef( $self->{'uri_for_route'} )
324             or die 'uri_for_route called on a request instance without it';
325              
326 0         0 return $self->{'uri_for_route'}->(@_);
327             }
328              
329             sub params {
330 265     265 1 47130 my ( $self, $source ) = @_;
331              
332 265 100 66     1349 return %{ $self->_params } if wantarray && @_ == 1;
  31         132  
333 234 100       1368 return $self->_params if @_ == 1;
334              
335 16 100       79 if ( $source eq 'query' ) {
    100          
336 5 0       18 return %{ $self->_query_params || {} } if wantarray;
  0 50       0  
337 5         19 return $self->_query_params;
338             }
339             elsif ( $source eq 'body' ) {
340 10 0       27 return %{ $self->_body_params || {} } if wantarray;
  0 50       0  
341 10         35 return $self->_body_params;
342             }
343 1 50       3 if ( $source eq 'route' ) {
344 1 50       18 return %{ $self->_route_params } if wantarray;
  0         0  
345 1         4 return $self->_route_params;
346             }
347             else {
348 0         0 croak "Unknown source params \"$source\".";
349             }
350             }
351              
352             sub query_parameters {
353 59     59 1 123 my $self = shift;
354 59   66     301 $self->{'query_parameters'} ||= do {
355 47 100       174 if ($XS_PARSE_QUERY_STRING) {
356             my $query = _decode(CGI::Deurl::XS::parse_query_string(
357 43         177 $self->env->{'QUERY_STRING'}
358             ));
359              
360             Hash::MultiValue->new(
361             map {;
362 10         20 my $key = $_;
363             is_arrayref( $query->{$key} )
364 2         33 ? ( map +( $key => $_ ), @{ $query->{$key} } )
365 10 100       67 : ( $key => $query->{$key} )
366 43         119 } keys %{$query}
  43         269  
367             );
368             } else {
369             # defer to Plack::Request
370 4         23 _decode($self->SUPER::query_parameters);
371             }
372             };
373             }
374              
375             # this will be filled once the route is matched
376 17   33 17 0 114 sub route_parameters { $_[0]->{'route_parameters'} ||= Hash::MultiValue->new }
377              
378             sub _set_route_parameters {
379 585     585   1594 my ( $self, $params ) = @_;
380             # remove reserved splat parameter name
381             # you should access splat parameters using splat() keyword
382 585         1310 delete @{$params}{qw};
  585         1786  
383 585         1216 $self->{'route_parameters'} = Hash::MultiValue->from_mixed( %{_decode($params)} );
  585         1649  
384             }
385              
386             sub body_parameters {
387 756     756 1 1603 my $self = shift;
388             # defer to (the overridden) Plack::Request->body_parameters
389 756   66     5903 $self->{'body_parameters'} ||= _decode($self->SUPER::body_parameters());
390             }
391              
392             sub parameters {
393 3     3 1 10 my ( $self, $type ) = @_;
394              
395             # handle a specific case
396 3 50       10 if ($type) {
397 0         0 my $attr = "${type}_parameters";
398 0         0 return $self->$attr;
399             }
400              
401             # merge together the *decoded* parameters
402 3   33     15 $self->{'merged_parameters'} ||= do {
403 3         11 my $query = $self->query_parameters;
404 3         9 my $body = $self->body_parameters;
405 3         10 my $route = $self->route_parameters; # not in Plack::Request
406 3         16 Hash::MultiValue->new( map $_->flatten, $query, $body, $route );
407             };
408             }
409              
410 2 100   2 0 9 sub captures { shift->params->{captures} || {} }
411              
412 31 100   31 0 69 sub splat { @{ shift->params->{splat} || [] } }
  31         169  
413              
414             # XXX: incompatible with Plack::Request
415 10     10 1 2051 sub param { shift->params->{ $_[0] } }
416              
417             sub _decode {
418 24309     24309   321713 my ($h) = @_;
419 24309 100       46944 return if not defined $h;
420              
421 24266 100 66     79986 if ( !is_ref($h) && !utf8::is_utf8($h) ) {
    100          
    100          
    50          
422 21580         35131 return __decode($h);
423             }
424             elsif ( ref($h) eq 'Hash::MultiValue' ) {
425 698         3493 return Hash::MultiValue->from_mixed(_decode($h->as_hashref_mixed));
426             }
427             elsif ( is_hashref($h) ) {
428 1908         13279 return { map {my $t = _decode($_); $t} (%$h) };
  21518         33478  
  21518         61350  
429             }
430             elsif ( is_arrayref($h) ) {
431 80         305 return [ map _decode($_), @$h ];
432             }
433              
434 0         0 return $h;
435             }
436              
437             sub is_ajax {
438 0     0 1 0 my $self = shift;
439              
440 0 0       0 return 0 unless defined $self->headers;
441 0 0       0 return 0 unless defined $self->header('X-Requested-With');
442 0 0       0 return 0 if $self->header('X-Requested-With') ne 'XMLHttpRequest';
443 0         0 return 1;
444             }
445              
446             # XXX incompatible with Plack::Request
447             # context-aware accessor for uploads
448             sub upload {
449 21     21 1 7648 my ( $self, $name ) = @_;
450 21         70 my $res = $self->{uploads}{$name};
451              
452 21 100       90 return $res unless wantarray;
453 9 100       36 return () unless defined $res;
454 6 100       36 return ( is_arrayref($res) ) ? @$res : $res;
455             }
456              
457             sub _build_params {
458 612     612   1579 my ($self) = @_;
459              
460             # params may have been populated by before filters
461             # _before_ we get there, so we have to save it first
462 612 100       2477 my $previous = $self->_has_params ? $self->_params : {};
463              
464             # now parse environment params...
465 612         2515 my $get_params = $self->_parse_get_params();
466              
467             # and merge everything
468             $self->{_params} = {
469 612 100       2118 map +( is_hashref($_) ? %{$_} : () ),
  1908         7750  
470             $previous,
471             $get_params,
472             $self->_body_params,
473             $self->_route_params,
474             };
475              
476             }
477              
478             sub _url_decode {
479 64     64   166 my ( $self, $encoded ) = @_;
480 64 100       193 return URL::Encode::XS::url_decode($encoded) if $XS_URL_DECODE;
481 32         68 my $clean = $encoded;
482 32         60 $clean =~ tr/\+/ /;
483 32         158 $clean =~ s/%([a-fA-F0-9]{2})/pack "H2", $1/eg;
  7         40  
484 32         111 return $clean;
485             }
486              
487             sub _parse_get_params {
488 612     612   1675 my ($self) = @_;
489 612 100       2333 return $self->_query_params if defined $self->{_query_params};
490              
491 569         1303 my $query_params = {};
492              
493 569         2605 my $source = $self->env->{QUERY_STRING};
494 569 100 100     6440 return if !defined $source || $source eq '';
495              
496 31 100       127 if ($XS_PARSE_QUERY_STRING) {
497 21   50     329 $self->_set_query_params(
498             CGI::Deurl::XS::parse_query_string($source) || {}
499             );
500 21         193 return $self->_query_params;
501             }
502              
503 10         109 foreach my $token ( split /[&;]/, $source ) {
504 32         140 my ( $key, $val ) = split( /=/, $token );
505 32 50       93 next unless defined $key;
506 32 50       89 $val = ( defined $val ) ? $val : '';
507 32         79 $key = $self->_url_decode($key);
508 32         74 $val = $self->_url_decode($val);
509              
510             # looking for multi-value params
511 32 100       92 if ( exists $query_params->{$key} ) {
512 6         16 my $prev_val = $query_params->{$key};
513 6 100       55 if ( is_arrayref($prev_val) ) {
514 2         7 push @{ $query_params->{$key} }, $val;
  2         12  
515             }
516             else {
517 4         22 $query_params->{$key} = [ $prev_val, $val ];
518             }
519             }
520              
521             # simple value param (first time we see it)
522             else {
523 26         116 $query_params->{$key} = $val;
524             }
525             }
526 10         54 $self->_set_query_params( $query_params );
527 10         47 return $self->_query_params;
528             }
529              
530             sub _build_uploads {
531 775     775   2033 my ($self) = @_;
532              
533             # parse body and build body params
534 775         3005 my $body_params = $self->_body_params;
535              
536 774         44009 my $uploads = $self->SUPER::uploads;
537 774         9740 my %uploads;
538              
539 774         2767 for my $name ( keys %$uploads ) {
540             my @uploads = map Dancer2::Core::Request::Upload->new(
541             # For back-compatibility, we use a HashRef of headers
542 21         7631 headers => {@{$_->{headers}->psgi_flatten_without_sort}},
543             tempname => $_->{tempname},
544             size => $_->{size},
545 15         68 filename => _decode( $_->{filename} ),
546             ), $uploads->get_all($name);
547              
548 15 100       9984 $uploads{$name} = @uploads > 1 ? \@uploads : $uploads[0];
549              
550             # support access to the filename as a normal param
551 15         66 my @filenames = map $_->{'filename'}, @uploads;
552 15 100       84 $self->{_body_params}{$name} =
553             @filenames > 1 ? \@filenames : $filenames[0];
554             }
555              
556 774         3106 $self->{uploads} = \%uploads;
557             }
558              
559             # XXX: incompatible with Plack::Request
560 611   66 611 1 4825 sub cookies { $_[0]->{'cookies'} ||= $_[0]->_build_cookies }
561              
562             sub _build_cookies {
563 517     517   1117 my $self = shift;
564 517         1241 my $cookies = {};
565              
566 517         3405 my $http_cookie = $self->header('Cookie');
567 517 100       108028 return $cookies unless defined $http_cookie; # nothing to do
568              
569 64 100       249 if ( $XS_HTTP_COOKIES ) {
570 63         724 $cookies = HTTP::XSCookies::crush_cookie($http_cookie);
571             }
572             else {
573             # handle via Plack::Request
574 1         12 $cookies = $self->SUPER::cookies();
575             }
576              
577             # convert to objects
578 64         229 while (my ($name, $value) = each %{$cookies}) {
  131         2814  
579 67 100       2592 $cookies->{$name} = Dancer2::Core::Cookie->new(
580             name => $name,
581             # HTTP::XSCookies v0.17+ will do the split and return an arrayref
582             value => is_arrayref($value) ? $value : [split '&', $value ]
583             );
584             }
585 64         648 return $cookies;
586             }
587              
588             # poor man's clone
589             sub _shallow_clone {
590 53     53   199 my ($self, $params, $options) = @_;
591              
592             # shallow clone $env; we don't want to alter the existing one
593             # in $self, then merge any overridden values
594 53 50       150 my $env = { %{ $self->env }, %{ $options || {} } };
  53         296  
  53         1622  
595              
596 53         617 my $new_request = __PACKAGE__->new(
597             env => $env,
598             body_params => {},
599             );
600              
601             # Clone and merge query params
602 53         290 my $new_params = $self->params;
603 53 100       141 $new_request->{_query_params} = { %{ $self->{_query_params} || {} } };
  53         527  
604 53         275 $new_request->{query_parameters} = $self->query_parameters->clone;
605 53 100       6343 for my $key ( keys %{ $params || {} } ) {
  53         320  
606 9         29 my $value = $params->{$key};
607 9         30 $new_params->{$key} = $value;
608 9         30 $new_request->{_query_params}->{$key} = $value;
609 9         42 $new_request->{query_parameters}->add( $key => $value );
610             }
611              
612             # Copy params (these are already decoded)
613 53         590 $new_request->{_params} = $new_params;
614 53         178 $new_request->{_body_params} = $self->{_body_params};
615 53         190 $new_request->{_route_params} = $self->{_route_params};
616 53         330 $new_request->{headers} = $self->headers;
617              
618             # Copy remaining settings
619 53         7022 $new_request->{is_behind_proxy} = $self->{is_behind_proxy};
620 53         153 $new_request->{vars} = $self->{vars};
621              
622             # Clone any existing decoded & cached body params. (GH#1116 GH#1269)
623 53         226 $new_request->{'body_parameters'} = $self->body_parameters->clone;
624              
625             # Delete merged HMV parameters, allowing them to be reconstructed on first use.
626 53         2750 delete $new_request->{'merged_parameters'};
627              
628 53         210 return $new_request;
629             }
630              
631              
632             sub _set_route {
633 585     585   1646 my ( $self, $route ) = @_;
634 585         2027 $self->{'route'} = $route;
635             }
636              
637 6     6 1 66 sub route { $_[0]->{'route'} }
638              
639             sub body_data {
640 2     2 1 4 my $self = shift;
641 2 100       9 return $self->data if $self->serializer;
642 1         5 $self->_body_params;
643 1 50       2 return $self->{_body_params} if keys %{ $self->{_body_params} };
  1         7  
644 1         4 return $self->body;
645             }
646              
647             1;
648              
649             __END__