removed unneeded dependency that was causing test fails
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Request.pm
CommitLineData
fc7ec1d9 1package Catalyst::Request;
2
b4ca0ee8 3use IO::Socket qw[AF_INET inet_aton];
bd917b94 4use Carp;
fc42a730 5use utf8;
de19de2e 6use URI::http;
7use URI::https;
e669e88a 8use URI::QueryParam;
6680c772 9use HTTP::Headers;
191665f3 10use Stream::Buffered;
11use Hash::MultiValue;
12use Scalar::Util;
b9d96e27 13use HTTP::Body;
b94f8e72 14use Catalyst::Exception;
059c085b 15use Moose;
16
6802c884 17use namespace::clean -except => 'meta';
18
b99ff5d8 19with 'MooseX::Emulate::Class::Accessor::Fast';
20
f52cae56 21has env => (is => 'ro', writer => '_set_env', predicate => '_has_env');
47b9d68e 22# XXX Deprecated crap here - warn?
23has action => (is => 'rw');
24# XXX: Deprecated in docs ages ago (2006), deprecated with warning in 5.8000 due
25# to confusion between Engines and Plugin::Authentication. Remove in 5.8100?
26has user => (is => 'rw');
27sub snippets { shift->captures(@_) }
faa02805 28
47b9d68e 29has _read_position => (
26fc3c5f 30 # FIXME: work around Moose bug RT#75367
31 # init_arg => undef,
47b9d68e 32 is => 'ro',
33 writer => '_set_read_position',
34 default => 0,
35);
36has _read_length => (
26fc3c5f 37 # FIXME: work around Moose bug RT#75367
38 # init_arg => undef,
47b9d68e 39 is => 'ro',
faa02805 40 default => sub {
41 my $self = shift;
42 $self->header('Content-Length') || 0;
43 },
44 lazy => 1,
45);
46
5fb12dbb 47has address => (is => 'rw');
48has arguments => (is => 'rw', default => sub { [] });
d5f4b434 49has cookies => (is => 'ro', builder => 'prepare_cookies', lazy => 1);
50
d5f4b434 51sub prepare_cookies {
52 my ( $self ) = @_;
53
54 if ( my $header = $self->header('Cookie') ) {
55 return { CGI::Simple::Cookie->parse($header) };
56 }
57 {};
58}
59
5fb12dbb 60has query_keywords => (is => 'rw');
61has match => (is => 'rw');
62has method => (is => 'rw');
63has protocol => (is => 'rw');
f152ae23 64has query_parameters => (is => 'rw', lazy=>1, default => sub { shift->_use_hash_multivalue ? Hash::MultiValue->new : +{} });
5fb12dbb 65has secure => (is => 'rw', default => 0);
66has captures => (is => 'rw', default => sub { [] });
6cb9e383 67has uri => (is => 'rw', predicate => 'has_uri');
8026359e 68has remote_user => (is => 'rw');
5fb12dbb 69has headers => (
e5ecd5bc 70 is => 'rw',
059c085b 71 isa => 'HTTP::Headers',
72 handles => [qw(content_encoding content_length content_type header referer user_agent)],
d5f4b434 73 builder => 'prepare_headers',
6680c772 74 lazy => 1,
059c085b 75);
76
d5f4b434 77sub prepare_headers {
78 my ($self) = @_;
79
80 my $env = $self->env;
81 my $headers = HTTP::Headers->new();
82
83 for my $header (keys %{ $env }) {
84 next unless $header =~ /^(HTTP|CONTENT|COOKIE)/i;
85 (my $field = $header) =~ s/^HTTPS?_//;
86 $field =~ tr/_/-/;
87 $headers->header($field => $env->{$header});
88 }
89 return $headers;
90}
91
7c1c4dc6 92has _log => (
93 is => 'ro',
94 weak_ref => 1,
95 required => 1,
059c085b 96);
97
eb1f4b49 98has io_fh => (
b87d834e 99 is=>'ro',
c2fef52f 100 predicate=>'_has_io_fh',
b87d834e 101 lazy=>1,
102 builder=>'_build_io_fh');
eb1f4b49 103
ade3da0a 104sub _build_io_fh {
eb1f4b49 105 my $self = shift;
106 return $self->env->{'psgix.io'}
c368f69e 107 || (
108 $self->env->{'net.async.http.server.req'} &&
109 $self->env->{'net.async.http.server.req'}->stream) ## Until I can make ioasync cabal see the value of supportin psgix.io (jnap)
eb1f4b49 110 || die "Your Server does not support psgix.io";
ade3da0a 111};
eb1f4b49 112
b87d834e 113has data_handlers => ( is=>'ro', isa=>'HashRef', default=>sub { +{} } );
ade3da0a 114
b87d834e 115has body_data => (
116 is=>'ro',
117 lazy=>1,
118 builder=>'_build_body_data');
119
120sub _build_body_data {
121 my ($self) = @_;
b94f8e72 122
123 # Not sure if these returns should not be exceptions...
124 my $content_type = $self->content_type || return;
125 return unless ($self->method eq 'POST' || $self->method eq 'PUT');
126
b87d834e 127 my ($match) = grep { $content_type =~/$_/i }
128 keys(%{$self->data_handlers});
129
130 if($match) {
131 my $fh = $self->body;
132 local $_ = $fh;
133 return $self->data_handlers->{$match}->($fh, $self);
134 } else {
b94f8e72 135 Catalyst::Exception->throw("$content_type is does not have an available data handler");
b87d834e 136 }
137}
eb1f4b49 138
88ba7793 139has _use_hash_multivalue => (
140 is=>'ro',
141 required=>1,
142 default=> sub {0});
143
f083854e 144# Amount of data to read from input on each pass
145our $CHUNKSIZE = 64 * 1024;
146
147sub read {
148 my ($self, $maxlength) = @_;
149 my $remaining = $self->_read_length - $self->_read_position;
150 $maxlength ||= $CHUNKSIZE;
151
152 # Are we done reading?
153 if ( $remaining <= 0 ) {
154 return;
155 }
156
157 my $readlen = ( $remaining > $maxlength ) ? $maxlength : $remaining;
158 my $rc = $self->read_chunk( my $buffer, $readlen );
159 if ( defined $rc ) {
160 if (0 == $rc) { # Nothing more to read even though Content-Length
161 # said there should be.
162 return;
163 }
47b9d68e 164 $self->_set_read_position( $self->_read_position + $rc );
f083854e 165 return $buffer;
166 }
167 else {
168 Catalyst::Exception->throw(
169 message => "Unknown error reading input: $!" );
170 }
171}
172
87f50436 173sub read_chunk {
174 my $self = shift;
175 return $self->env->{'psgi.input'}->read(@_);
176}
177
059c085b 178has body_parameters => (
5fb12dbb 179 is => 'rw',
180 required => 1,
181 lazy => 1,
d003ff83 182 builder => 'prepare_body_parameters',
fc7ec1d9 183);
184
059c085b 185has uploads => (
5fb12dbb 186 is => 'rw',
187 required => 1,
5fb12dbb 188 default => sub { {} },
059c085b 189);
190
059c085b 191has parameters => (
1cbdfa9b 192 is => 'rw',
193 lazy => 1,
11e7af55 194 builder => '_build_parameters',
195 clearer => '_clear_parameters',
059c085b 196);
197
341620d5 198# TODO:
199# - Can we lose the before modifiers which just call prepare_body ?
200# they are wasteful, slow us down and feel cluttery.
201
202# Can we make _body an attribute, have the rest of
203# these lazy build from there and kill all the direct hash access
204# in Catalyst.pm and Engine.pm?
205
1cbdfa9b 206sub prepare_parameters {
207 my ( $self ) = @_;
11e7af55 208 $self->_clear_parameters;
209 return $self->parameters;
210}
211
11e7af55 212sub _build_parameters {
213 my ( $self ) = @_;
1cbdfa9b 214 my $parameters = {};
215 my $body_parameters = $self->body_parameters;
216 my $query_parameters = $self->query_parameters;
bd822b43 217
88ba7793 218 if($self->_use_hash_multivalue) {
f152ae23 219 return Hash::MultiValue->new($query_parameters->flatten, $body_parameters->flatten);
88ba7793 220 }
221
1cbdfa9b 222 # We copy, no references
223 foreach my $name (keys %$query_parameters) {
224 my $param = $query_parameters->{$name};
225 $parameters->{$name} = ref $param eq 'ARRAY' ? [ @$param ] : $param;
226 }
227
228 # Merge query and body parameters
229 foreach my $name (keys %$body_parameters) {
230 my $param = $body_parameters->{$name};
231 my @values = ref $param eq 'ARRAY' ? @$param : ($param);
232 if ( my $existing = $parameters->{$name} ) {
233 unshift(@values, (ref $existing eq 'ARRAY' ? @$existing : $existing));
234 }
235 $parameters->{$name} = @values > 1 ? \@values : $values[0];
236 }
237 $parameters;
238}
239
398f13db 240has _uploadtmp => (
241 is => 'ro',
242 predicate => '_has_uploadtmp',
243);
244
245sub prepare_body {
246 my ( $self ) = @_;
247
191665f3 248 # If previously applied middleware created the HTTP::Body object, then we
249 # just use that one.
952ff530 250
b111b5c1 251 if(my $plack_body = $self->_has_env ? $self->env->{'plack.request.http.body'} : undef) {
952ff530 252 $self->_body($plack_body);
191665f3 253 $self->_body->cleanup(1);
254 return;
952ff530 255 }
256
191665f3 257 # If there is nothing to read, set body to naught and return. This
258 # will cause all body code to be skipped
398f13db 259
191665f3 260 return $self->_body(0) unless my $length = $self->_read_length;
952ff530 261
191665f3 262 # Unless the body has already been set, create it. Not sure about this
263 # code, how else might it be set, but this was existing logic.
264
265 unless ($self->_body) {
266 my $type = $self->header('Content-Type');
267 $self->_body(HTTP::Body->new( $type, $length ));
268 $self->_body->cleanup(1);
952ff530 269
191665f3 270 # JNAP: I'm not sure this is doing what we expect, but it also doesn't
271 # seem to be hurting (seems ->_has_uploadtmp is true more than I would
272 # expect.
273
274 $self->_body->tmpdir( $self->_uploadtmp )
275 if $self->_has_uploadtmp;
952ff530 276 }
277
191665f3 278 # Ok if we get this far, we have to read psgi.input into the new body
279 # object. Lets play nice with any plack app or other downstream, so
280 # we create a buffer unless one exists.
281
282 my $stream_buffer;
283 if ($self->env->{'psgix.input.buffered'}) {
284 # Be paranoid about previous psgi middleware or apps that read the
285 # input but didn't return the buffer to the start.
286 $self->env->{'psgi.input'}->seek(0, 0);
287 } else {
288 $stream_buffer = Stream::Buffered->new($length);
289 }
952ff530 290
191665f3 291 # Check for definedness as you could read '0'
292 while ( defined ( my $chunk = $self->read() ) ) {
293 $self->prepare_body_chunk($chunk);
294 $stream_buffer->print($chunk) if $stream_buffer;
295 }
952ff530 296
191665f3 297 # Ok, we read the body. Lets play nice for any PSGI app down the pipe
298
299 if ($stream_buffer) {
300 $self->env->{'psgix.input.buffered'} = 1;
301 $self->env->{'psgi.input'} = $stream_buffer->rewind;
302 } else {
303 $self->env->{'psgi.input'}->seek(0, 0); # Reset the buffer for downstream middleware or apps
952ff530 304 }
191665f3 305
191665f3 306 # paranoia against wrong Content-Length header
307 my $remaining = $length - $self->_read_position;
308 if ( $remaining > 0 ) {
309 Catalyst::Exception->throw("Wrong Content-Length value: $length" );
952ff530 310 }
311}
312
398f13db 313sub prepare_body_chunk {
314 my ( $self, $chunk ) = @_;
315
316 $self->_body->add($chunk);
317}
318
398f13db 319sub prepare_body_parameters {
c0d561c1 320 my ( $self, $c ) = @_;
398f13db 321
d003ff83 322 $self->prepare_body if ! $self->_has_body;
f152ae23 323
324 unless($self->_body) {
325 return $self->_use_hash_multivalue ? Hash::MultiValue->new : {};
326 }
398f13db 327
c0d561c1 328 my $params = $self->_body->param;
329
330 # If we have an encoding configured (like UTF-8) in general we expect a client
331 # to POST with the encoding we fufilled the request in. Otherwise don't do any
332 # encoding (good change wide chars could be in HTML entity style llike the old
333 # days -JNAP
334
335 # so, now that HTTP::Body prepared the body params, we gotta 'walk' the structure
336 # and do any needed decoding.
337
338 # This only does something if the encoding is set via the encoding param. Remember
339 # this is assuming the client is not bad and responds with what you provided. In
340 # general you can just use utf8 and get away with it.
341 #
342 # I need to see if $c is here since this also doubles as a builder for the object :(
343
344 if($c and $c->encoding) {
345 $params = $c->_handle_unicode_decoding($params);
346 }
347
88ba7793 348 return $self->_use_hash_multivalue ?
c0d561c1 349 Hash::MultiValue->from_mixed($params) :
350 $params;
398f13db 351}
341620d5 352
2f498a7e 353sub prepare_connection {
354 my ($self) = @_;
355
356 my $env = $self->env;
357
358 $self->address( $env->{REMOTE_ADDR} );
359 $self->hostname( $env->{REMOTE_HOST} )
360 if exists $env->{REMOTE_HOST};
361 $self->protocol( $env->{SERVER_PROTOCOL} );
362 $self->remote_user( $env->{REMOTE_USER} );
363 $self->method( $env->{REQUEST_METHOD} );
364 $self->secure( $env->{'psgi.url_scheme'} eq 'https' ? 1 : 0 );
365}
366
367# XXX - FIXME - method is here now, move this crap...
e99ec2dc 368around parameters => sub {
369 my ($orig, $self, $params) = @_;
370 if ($params) {
371 if ( !ref $params ) {
7c1c4dc6 372 $self->_log->warn(
e99ec2dc 373 "Attempt to retrieve '$params' with req->params(), " .
374 "you probably meant to call req->param('$params')"
375 );
376 $params = undef;
377 }
378 return $self->$orig($params);
379 }
380 $self->$orig();
059c085b 381};
382
383has base => (
5fb12dbb 384 is => 'rw',
385 required => 1,
386 lazy => 1,
387 default => sub {
059c085b 388 my $self = shift;
6cb9e383 389 return $self->path if $self->has_uri;
059c085b 390 },
391);
392
069355da 393has _body => (
0f56bbcf 394 is => 'rw', clearer => '_clear_body', predicate => '_has_body',
059c085b 395);
610bc6ec 396# Eugh, ugly. Should just be able to rename accessor methods to 'body'
b0ad47c1 397# and provide a custom reader..
610bc6ec 398sub body {
399 my $self = shift;
952ff530 400 $self->prepare_body unless $self->_has_body;
14c057aa 401 croak 'body is a reader' if scalar @_;
610bc6ec 402 return blessed $self->_body ? $self->_body->body : $self->_body;
403}
059c085b 404
405has hostname => (
406 is => 'rw',
407 required => 1,
408 lazy => 1,
409 default => sub {
410 my ($self) = @_;
9fb936e5 411 gethostbyaddr( inet_aton( $self->address ), AF_INET ) || $self->address
059c085b 412 },
413);
414
02570318 415has _path => ( is => 'rw', predicate => '_has_path', clearer => '_clear_path' );
416
059c085b 417sub args { shift->arguments(@_) }
418sub body_params { shift->body_parameters(@_) }
419sub input { shift->body(@_) }
420sub params { shift->parameters(@_) }
421sub query_params { shift->query_parameters(@_) }
422sub path_info { shift->path(@_) }
f7e4e231 423
8738b8fe 424=for stopwords param params
965f3e35 425
fc7ec1d9 426=head1 NAME
427
3e19f4f6 428Catalyst::Request - provides information about the current client request
fc7ec1d9 429
430=head1 SYNOPSIS
431
b22c6668 432 $req = $c->request;
767480fd 433 $req->address eq "127.0.0.1";
b22c6668 434 $req->arguments;
3e19f4f6 435 $req->args;
b22c6668 436 $req->base;
06e1b616 437 $req->body;
974733c0 438 $req->body_data;
fbcc39ad 439 $req->body_parameters;
b5176d9e 440 $req->content_encoding;
441 $req->content_length;
442 $req->content_type;
b77e7869 443 $req->cookie;
b22c6668 444 $req->cookies;
b5176d9e 445 $req->header;
b22c6668 446 $req->headers;
447 $req->hostname;
61bacdcc 448 $req->input;
3b4d1251 449 $req->query_keywords;
b22c6668 450 $req->match;
451 $req->method;
e7c0c583 452 $req->param;
e7c0c583 453 $req->parameters;
3e19f4f6 454 $req->params;
b22c6668 455 $req->path;
bfde09a2 456 $req->protocol;
fbcc39ad 457 $req->query_parameters;
458 $req->read;
b5176d9e 459 $req->referer;
bfde09a2 460 $req->secure;
47b9d68e 461 $req->captures;
e7c0c583 462 $req->upload;
b22c6668 463 $req->uploads;
77d12cae 464 $req->uri;
7ce7ca2e 465 $req->user;
66294129 466 $req->user_agent;
9d8d0ab9 467 $req->env;
b22c6668 468
3e22baa5 469See also L<Catalyst>, L<Catalyst::Request::Upload>.
fc7ec1d9 470
471=head1 DESCRIPTION
472
3e19f4f6 473This is the Catalyst Request class, which provides an interface to data for the
474current client request. The request object is prepared by L<Catalyst::Engine>,
475thus hiding the details of the particular engine implementation.
b22c6668 476
477=head1 METHODS
fc7ec1d9 478
b5ecfcf0 479=head2 $req->address
0556eb49 480
3e19f4f6 481Returns the IP address of the client.
61b1e958 482
b5ecfcf0 483=head2 $req->arguments
61b1e958 484
b22c6668 485Returns a reference to an array containing the arguments.
fc7ec1d9 486
487 print $c->request->arguments->[0];
488
c436c1e8 489For example, if your action was
490
7d7519a4 491 package MyApp::Controller::Foo;
85d9fce6 492
493 sub moose : Local {
494 ...
495 }
c436c1e8 496
3e19f4f6 497and the URI for the request was C<http://.../foo/moose/bah>, the string C<bah>
c436c1e8 498would be the first and only argument.
499
6d920953 500Arguments get automatically URI-unescaped for you.
8f58057d 501
b5ecfcf0 502=head2 $req->args
3e19f4f6 503
01011731 504Shortcut for L</arguments>.
3e19f4f6 505
b5ecfcf0 506=head2 $req->base
fc7ec1d9 507
328f225e 508Contains the URI base. This will always have a trailing slash. Note that the
f4dda4a8 509URI scheme (e.g., http vs. https) must be determined through heuristics;
328f225e 510depending on your server configuration, it may be incorrect. See $req->secure
511for more info.
c436c1e8 512
3e19f4f6 513If your application was queried with the URI
514C<http://localhost:3000/some/path> then C<base> is C<http://localhost:3000/>.
fc7ec1d9 515
b5ecfcf0 516=head2 $req->body
06e1b616 517
843871cf 518Returns the message body of the request, as returned by L<HTTP::Body>: a string,
519unless Content-Type is C<application/x-www-form-urlencoded>, C<text/xml>, or
520C<multipart/form-data>, in which case a L<File::Temp> object is returned.
e060fe05 521
974733c0 522=head2 $req->body_data
523
524Returns a Perl representation of POST/PUT body data that is not classic HTML
525form data, such as JSON, XML, etc. By default, Catalyst will parse incoming
526data of the type 'application/json' and return access to that data via this
527method. You may define addition data_handlers via a global configuration
528setting. See L<Catalyst\DATA HANDLERS> for more information.
529
b94f8e72 530If the POST is malformed in some way (such as undefined or not content that
531matches the content-type) we raise a L<Catalyst::Exception> with the error
532text as the message.
533
534If the POSTed content type does not match an availabled data handler, this
535will also raise an exception.
536
b5ecfcf0 537=head2 $req->body_parameters
fbcc39ad 538
3e19f4f6 539Returns a reference to a hash containing body (POST) parameters. Values can
fbcc39ad 540be either a scalar or an arrayref containing scalars.
541
542 print $c->request->body_parameters->{field};
543 print $c->request->body_parameters->{field}->[0];
c436c1e8 544
d631b5f9 545These are the parameters from the POST part of the request, if any.
e5ecd5bc 546
b5ecfcf0 547=head2 $req->body_params
fbcc39ad 548
3e19f4f6 549Shortcut for body_parameters.
fbcc39ad 550
b5ecfcf0 551=head2 $req->content_encoding
b5176d9e 552
3e19f4f6 553Shortcut for $req->headers->content_encoding.
b5176d9e 554
b5ecfcf0 555=head2 $req->content_length
b5176d9e 556
3e19f4f6 557Shortcut for $req->headers->content_length.
b5176d9e 558
b5ecfcf0 559=head2 $req->content_type
b5176d9e 560
3e19f4f6 561Shortcut for $req->headers->content_type.
b5176d9e 562
b5ecfcf0 563=head2 $req->cookie
3ad654e0 564
3e19f4f6 565A convenient method to access $req->cookies.
3ad654e0 566
567 $cookie = $c->request->cookie('name');
568 @cookies = $c->request->cookie;
569
570=cut
571
572sub cookie {
573 my $self = shift;
574
575 if ( @_ == 0 ) {
b77e7869 576 return keys %{ $self->cookies };
3ad654e0 577 }
578
579 if ( @_ == 1 ) {
580
581 my $name = shift;
582
b77e7869 583 unless ( exists $self->cookies->{$name} ) {
3ad654e0 584 return undef;
585 }
fbcc39ad 586
b77e7869 587 return $self->cookies->{$name};
3ad654e0 588 }
589}
590
b5ecfcf0 591=head2 $req->cookies
fc7ec1d9 592
b22c6668 593Returns a reference to a hash containing the cookies.
fc7ec1d9 594
595 print $c->request->cookies->{mycookie}->value;
596
7e743798 597The cookies in the hash are indexed by name, and the values are L<CGI::Simple::Cookie>
c436c1e8 598objects.
599
b5ecfcf0 600=head2 $req->header
b5176d9e 601
3e19f4f6 602Shortcut for $req->headers->header.
b5176d9e 603
b5ecfcf0 604=head2 $req->headers
fc7ec1d9 605
3e19f4f6 606Returns an L<HTTP::Headers> object containing the headers for the current request.
fc7ec1d9 607
608 print $c->request->headers->header('X-Catalyst');
609
b5ecfcf0 610=head2 $req->hostname
0556eb49 611
178dca5f 612Returns the hostname of the client. Use C<< $req->uri->host >> to get the hostname of the server.
e5ecd5bc 613
b5ecfcf0 614=head2 $req->input
61bacdcc 615
3e19f4f6 616Alias for $req->body.
61bacdcc 617
3b4d1251 618=head2 $req->query_keywords
619
620Contains the keywords portion of a query string, when no '=' signs are
621present.
622
623 http://localhost/path?some+keywords
b0ad47c1 624
3b4d1251 625 $c->request->query_keywords will contain 'some keywords'
626
b5ecfcf0 627=head2 $req->match
fc7ec1d9 628
3e19f4f6 629This contains the matching part of a Regex action. Otherwise
2c83fd5a 630it returns the same as 'action', except for default actions,
631which return an empty string.
fc7ec1d9 632
b5ecfcf0 633=head2 $req->method
b5176d9e 634
635Contains the request method (C<GET>, C<POST>, C<HEAD>, etc).
636
b5ecfcf0 637=head2 $req->param
e7c0c583 638
b0ad47c1 639Returns GET and POST parameters with a CGI.pm-compatible param method. This
3e19f4f6 640is an alternative method for accessing parameters in $c->req->parameters.
e7c0c583 641
a82c2894 642 $value = $c->request->param( 'foo' );
643 @values = $c->request->param( 'foo' );
e7c0c583 644 @params = $c->request->param;
645
3e705254 646Like L<CGI>, and B<unlike> earlier versions of Catalyst, passing multiple
a82c2894 647arguments to this method, like this:
648
85d9fce6 649 $c->request->param( 'foo', 'bar', 'gorch', 'quxx' );
a82c2894 650
651will set the parameter C<foo> to the multiple values C<bar>, C<gorch> and
652C<quxx>. Previously this would have added C<bar> as another value to C<foo>
3e19f4f6 653(creating it if it didn't exist before), and C<quxx> as another value for
654C<gorch>.
a82c2894 655
83312afd 656B<NOTE> this is considered a legacy interface and care should be taken when
657using it. C<< scalar $c->req->param( 'foo' ) >> will return only the first
658C<foo> param even if multiple are present; C<< $c->req->param( 'foo' ) >> will
659return a list of as many are present, which can have unexpected consequences
660when writing code of the form:
661
662 $foo->bar(
663 a => 'b',
664 baz => $c->req->param( 'baz' ),
665 );
666
667If multiple C<baz> parameters are provided this code might corrupt data or
668cause a hash initialization error. For a more straightforward interface see
669C<< $c->req->parameters >>.
670
f384c848 671B<NOTE> Interfaces like this, which are based on L<CGI> and the C<param> method
672are now known to cause demonstrated exploits. It is highly recommended that you
673avoid using this method, and migrate existing code away from it. Here's the
674whitepaper of the exploit:
0810283f 675
676L<http://blog.gerv.net/2014/10/new-class-of-vulnerability-in-perl-web-applications/>
677
678Basically this is an exploit that takes advantage of how L<\param> will do one thing
679in scalar context and another thing in list context. This is combined with how Perl
680chooses to deal with duplicate keys in a hash definition by overwriting the value of
681existing keys with a new value if the same key shows up again. Generally you will be
682vulnerale to this exploit if you are using this method in a direct assignment in a
683hash, such as with a L<DBIx::Class> create statement. For example, if you have
684parameters like:
685
686 user?user=123&foo=a&foo=user&foo=456
687
688You could end up with extra parameters injected into your method calls:
689
690 $c->model('User')->create({
691 user => $c->req->param('user'),
692 foo => $c->req->param('foo'),
693 });
694
695Which would look like:
696
697 $c->model('User')->create({
698 user => 123,
699 foo => qw(a user 456),
700 });
701
702(or to be absolutely clear if you are not seeing it):
703
704 $c->model('User')->create({
705 user => 456,
706 foo => 'a',
707 });
708
709Possible remediations include scrubbing your parameters with a form validator like
710L<HTML::FormHandler> or being careful to force scalar context using the scalar
711keyword:
712
713 $c->model('User')->create({
714 user => scalar($c->req->param('user')),
715 foo => scalar($c->req->param('foo')),
716 });
717
f384c848 718Upcoming versions of L<Catalyst> will disable this interface by default and require
719you to positively enable it should you require it for backwards compatibility reasons.
720
e7c0c583 721=cut
722
723sub param {
724 my $self = shift;
725
726 if ( @_ == 0 ) {
727 return keys %{ $self->parameters };
728 }
729
4f96d61c 730 # If anything in @_ is undef, carp about that, and remove it from
731 # the list;
732
733 my @params = grep { defined($_) ? 1 : do {carp "You called ->params with an undefined value"; 0} } @_;
734
735 if ( @params == 1 ) {
e7c0c583 736
4f96d61c 737 defined(my $param = shift @params) ||
738 carp "You called ->params with an undefined value 2";
6bd2b72c 739
bfde09a2 740 unless ( exists $self->parameters->{$param} ) {
741 return wantarray ? () : undef;
742 }
743
744 if ( ref $self->parameters->{$param} eq 'ARRAY' ) {
745 return (wantarray)
746 ? @{ $self->parameters->{$param} }
747 : $self->parameters->{$param}->[0];
748 }
749 else {
750 return (wantarray)
751 ? ( $self->parameters->{$param} )
752 : $self->parameters->{$param};
753 }
d7945f32 754 }
4f96d61c 755 elsif ( @params > 1 ) {
756 my $field = shift @params;
90d3ac10 757 $self->parameters->{$field} = [@params];
d7945f32 758 }
e7c0c583 759}
b5176d9e 760
b5ecfcf0 761=head2 $req->parameters
61b1e958 762
3e19f4f6 763Returns a reference to a hash containing GET and POST parameters. Values can
d08ced28 764be either a scalar or an arrayref containing scalars.
fc7ec1d9 765
e7c0c583 766 print $c->request->parameters->{field};
767 print $c->request->parameters->{field}->[0];
fc7ec1d9 768
c436c1e8 769This is the combination of C<query_parameters> and C<body_parameters>.
770
b5ecfcf0 771=head2 $req->params
3e19f4f6 772
773Shortcut for $req->parameters.
774
b5ecfcf0 775=head2 $req->path
fc7ec1d9 776
3e19f4f6 777Returns the path, i.e. the part of the URI after $req->base, for the current request.
fc7ec1d9 778
be6801fa 779 http://localhost/path/foo
780
781 $c->request->path will contain 'path/foo'
782
b5ecfcf0 783=head2 $req->path_info
fbcc39ad 784
10011c19 785Alias for path, added for compatibility with L<CGI>.
fbcc39ad 786
787=cut
788
789sub path {
02fb5d78 790 my ( $self, @params ) = @_;
4f5ebacd 791
02fb5d78 792 if (@params) {
793 $self->uri->path(@params);
02570318 794 $self->_clear_path;
fbcc39ad 795 }
02570318 796 elsif ( $self->_has_path ) {
797 return $self->_path;
e561386f 798 }
02fb5d78 799 else {
800 my $path = $self->uri->path;
801 my $location = $self->base->path;
802 $path =~ s/^(\Q$location\E)?//;
803 $path =~ s/^\///;
02570318 804 $self->_path($path);
fbcc39ad 805
02fb5d78 806 return $path;
807 }
fbcc39ad 808}
809
b5ecfcf0 810=head2 $req->protocol
bfde09a2 811
3e19f4f6 812Returns the protocol (HTTP/1.0 or HTTP/1.1) used for the current request.
bfde09a2 813
b5ecfcf0 814=head2 $req->query_parameters
fbcc39ad 815
def54ce2 816=head2 $req->query_params
817
3e19f4f6 818Returns a reference to a hash containing query string (GET) parameters. Values can
fbcc39ad 819be either a scalar or an arrayref containing scalars.
820
821 print $c->request->query_parameters->{field};
822 print $c->request->query_parameters->{field}->[0];
b0ad47c1 823
b5ecfcf0 824=head2 $req->read( [$maxlength] )
fbcc39ad 825
3e19f4f6 826Reads a chunk of data from the request body. This method is intended to be
827used in a while loop, reading $maxlength bytes on every call. $maxlength
fbcc39ad 828defaults to the size of the request if not specified.
829
87f50436 830=head2 $req->read_chunk(\$buff, $max)
831
d7f18923 832Reads a chunk.
87f50436 833
9779c885 834You have to set MyApp->config(parse_on_demand => 1) to use this directly.
fbcc39ad 835
b5ecfcf0 836=head2 $req->referer
fc7ec1d9 837
3e19f4f6 838Shortcut for $req->headers->referer. Returns the referring page.
fc7ec1d9 839
b5ecfcf0 840=head2 $req->secure
bfde09a2 841
328f225e 842Returns true or false, indicating whether the connection is secure
d7f18923 843(https). The reliability of $req->secure may depend on your server
844configuration; Catalyst relies on PSGI to determine whether or not a
845request is secure (Catalyst looks at psgi.url_scheme), and different
846PSGI servers may make this determination in different ways (as by
847directly passing along information from the server, interpreting any of
848several HTTP headers, or using heuristics of their own).
bfde09a2 849
2982e768 850=head2 $req->captures
851
5c6a56e0 852Returns a reference to an array containing captured args from chained
853actions or regex captures.
fc7ec1d9 854
2982e768 855 my @captures = @{ $c->request->captures };
856
b5ecfcf0 857=head2 $req->upload
e7c0c583 858
3e19f4f6 859A convenient method to access $req->uploads.
e7c0c583 860
861 $upload = $c->request->upload('field');
862 @uploads = $c->request->upload('field');
863 @fields = $c->request->upload;
bfde09a2 864
e7c0c583 865 for my $upload ( $c->request->upload('field') ) {
146554c5 866 print $upload->filename;
e7c0c583 867 }
868
869=cut
870
871sub upload {
872 my $self = shift;
873
874 if ( @_ == 0 ) {
875 return keys %{ $self->uploads };
876 }
877
bfde09a2 878 if ( @_ == 1 ) {
e7c0c583 879
bfde09a2 880 my $upload = shift;
881
882 unless ( exists $self->uploads->{$upload} ) {
883 return wantarray ? () : undef;
884 }
6bd2b72c 885
bfde09a2 886 if ( ref $self->uploads->{$upload} eq 'ARRAY' ) {
887 return (wantarray)
888 ? @{ $self->uploads->{$upload} }
889 : $self->uploads->{$upload}->[0];
890 }
891 else {
892 return (wantarray)
fbcc39ad 893 ? ( $self->uploads->{$upload} )
894 : $self->uploads->{$upload};
bfde09a2 895 }
d7945f32 896 }
bfde09a2 897
a4f5c51e 898 if ( @_ > 1 ) {
bfde09a2 899
900 while ( my ( $field, $upload ) = splice( @_, 0, 2 ) ) {
901
902 if ( exists $self->uploads->{$field} ) {
903 for ( $self->uploads->{$field} ) {
904 $_ = [$_] unless ref($_) eq "ARRAY";
905 push( @$_, $upload );
906 }
907 }
908 else {
909 $self->uploads->{$field} = $upload;
910 }
911 }
e7c0c583 912 }
913}
914
b5ecfcf0 915=head2 $req->uploads
fc7ec1d9 916
bfde09a2 917Returns a reference to a hash containing uploads. Values can be either a
b0ad47c1 918L<Catalyst::Request::Upload> object, or an arrayref of
84e7aa89 919L<Catalyst::Request::Upload> objects.
e7c0c583 920
921 my $upload = $c->request->uploads->{field};
922 my $upload = $c->request->uploads->{field}->[0];
923
b5ecfcf0 924=head2 $req->uri
fbcc39ad 925
d26ee0d0 926Returns a L<URI> object for the current request. Stringifies to the URI text.
fbcc39ad 927
a375a206 928=head2 $req->mangle_params( { key => 'value' }, $appendmode);
bd917b94 929
a375a206 930Returns a hashref of parameters stemming from the current request's params,
931plus the ones supplied. Keys for which no current param exists will be
932added, keys with undefined values will be removed and keys with existing
933params will be replaced. Note that you can supply a true value as the final
934argument to change behavior with regards to existing parameters, appending
935values rather than replacing them.
936
937A quick example:
938
939 # URI query params foo=1
940 my $hashref = $req->mangle_params({ foo => 2 });
941 # Result is query params of foo=2
942
943versus append mode:
944
945 # URI query params foo=1
946 my $hashref = $req->mangle_params({ foo => 2 }, 1);
947 # Result is query params of foo=1&foo=2
948
949This is the code behind C<uri_with>.
bd917b94 950
951=cut
952
a375a206 953sub mangle_params {
954 my ($self, $args, $append) = @_;
b0ad47c1 955
a375a206 956 carp('No arguments passed to mangle_params()') unless $args;
fbb513f7 957
2f381252 958 foreach my $value ( values %$args ) {
d0f0fcf6 959 next unless defined $value;
fbb513f7 960 for ( ref $value eq 'ARRAY' ? @$value : $value ) {
961 $_ = "$_";
5c779e98 962 # utf8::encode($_);
fc42a730 963 }
fc42a730 964 };
b0ad47c1 965
a375a206 966 my %params = %{ $self->uri->query_form_hash };
967 foreach my $key (keys %{ $args }) {
968 my $val = $args->{$key};
969 if(defined($val)) {
970
971 if($append && exists($params{$key})) {
972
973 # This little bit of heaven handles appending a new value onto
974 # an existing one regardless if the existing value is an array
975 # or not, and regardless if the new value is an array or not
976 $params{$key} = [
977 ref($params{$key}) eq 'ARRAY' ? @{ $params{$key} } : $params{$key},
978 ref($val) eq 'ARRAY' ? @{ $val } : $val
979 ];
980
981 } else {
982 $params{$key} = $val;
983 }
984 } else {
985
986 # If the param wasn't defined then we delete it.
987 delete($params{$key});
988 }
989 }
990
991
992 return \%params;
993}
994
995=head2 $req->uri_with( { key => 'value' } );
996
997Returns a rewritten URI object for the current request. Key/value pairs
998passed in will override existing parameters. You can remove an existing
999parameter by passing in an undef value. Unmodified pairs will be
1000preserved.
1001
1002You may also pass an optional second parameter that puts C<uri_with> into
1003append mode:
1004
1005 $req->uri_with( { key => 'value' }, { mode => 'append' } );
9779c885 1006
a375a206 1007See C<mangle_params> for an explanation of this behavior.
1008
1009=cut
1010
1011sub uri_with {
1012 my( $self, $args, $behavior) = @_;
1013
1014 carp( 'No arguments passed to uri_with()' ) unless $args;
1015
1016 my $append = 0;
1017 if((ref($behavior) eq 'HASH') && defined($behavior->{mode}) && ($behavior->{mode} eq 'append')) {
1018 $append = 1;
1019 }
1020
1021 my $params = $self->mangle_params($args, $append);
1022
1023 my $uri = $self->uri->clone;
1024 $uri->query_form($params);
2f381252 1025
bd917b94 1026 return $uri;
1027}
1028
8026359e 1029=head2 $req->remote_user
1030
1031Returns the value of the C<REMOTE_USER> environment variable.
7ce7ca2e 1032
b5ecfcf0 1033=head2 $req->user_agent
b5176d9e 1034
3e19f4f6 1035Shortcut to $req->headers->user_agent. Returns the user agent (browser)
1036version string.
b5176d9e 1037
eb1f4b49 1038=head2 $req->io_fh
1039
1040Returns a psgix.io bidirectional socket, if your server supports one. Used for
1041when you want to jailbreak out of PSGI and handle bidirectional client server
1042communication manually, such as when you are using cometd or websockets.
1043
47b9d68e 1044=head1 SETUP METHODS
1045
1046You should never need to call these yourself in application code,
1047however they are useful if extending Catalyst by applying a request role.
1048
1049=head2 $self->prepare_headers()
1050
1051Sets up the C<< $res->headers >> accessor.
1052
1053=head2 $self->prepare_body()
1054
1055Sets up the body using L<HTTP::Body>
1056
1057=head2 $self->prepare_body_chunk()
1058
1059Add a chunk to the request body.
1060
1061=head2 $self->prepare_body_parameters()
1062
1063Sets up parameters from body.
1064
8738b8fe 1065=head2 $self->prepare_cookies()
47b9d68e 1066
1067Parse cookies from header. Sets up a L<CGI::Simple::Cookie> object.
1068
8738b8fe 1069=head2 $self->prepare_connection()
1070
1071Sets up various fields in the request like the local and remote addresses,
f59eeb09 1072request method, hostname requested etc.
8738b8fe 1073
1074=head2 $self->prepare_parameters()
1075
1076Ensures that the body has been parsed, then builds the parameters, which are
1077combined from those in the request and those in the body.
1078
11e7af55 1079If parameters have already been set will clear the parameters and build them again.
1080
9d8d0ab9 1081=head2 $self->env
1082
1083Access to the raw PSGI env.
8738b8fe 1084
059c085b 1085=head2 meta
1086
1087Provided by Moose
1088
3e19f4f6 1089=head1 AUTHORS
fc7ec1d9 1090
2f381252 1091Catalyst Contributors, see Catalyst.pm
fc7ec1d9 1092
1093=head1 COPYRIGHT
1094
536bee89 1095This library is free software. You can redistribute it and/or modify
61b1e958 1096it under the same terms as Perl itself.
fc7ec1d9 1097
1098=cut
1099
e5ecd5bc 1100__PACKAGE__->meta->make_immutable;
1101
fc7ec1d9 11021;