documentation and up version
[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
ac1cf8d4 672are known to cause demonstrated exploits. It is highly recommended that you
673avoid using this method, and migrate existing code away from it. Here's a
f384c848 674whitepaper of the exploit:
0810283f 675
676L<http://blog.gerv.net/2014/10/new-class-of-vulnerability-in-perl-web-applications/>
677
ac1cf8d4 678B<NOTE> Further discussion on IRC indicate that the L<Catalyst> core team from 'back then'
679were well aware of this hack and this is the main reason we added the new approach to
680getting parameters in the first place.
681
0810283f 682Basically this is an exploit that takes advantage of how L<\param> will do one thing
683in scalar context and another thing in list context. This is combined with how Perl
684chooses to deal with duplicate keys in a hash definition by overwriting the value of
685existing keys with a new value if the same key shows up again. Generally you will be
686vulnerale to this exploit if you are using this method in a direct assignment in a
687hash, such as with a L<DBIx::Class> create statement. For example, if you have
688parameters like:
689
690 user?user=123&foo=a&foo=user&foo=456
691
692You could end up with extra parameters injected into your method calls:
693
694 $c->model('User')->create({
695 user => $c->req->param('user'),
696 foo => $c->req->param('foo'),
697 });
698
699Which would look like:
700
701 $c->model('User')->create({
702 user => 123,
703 foo => qw(a user 456),
704 });
705
706(or to be absolutely clear if you are not seeing it):
707
708 $c->model('User')->create({
709 user => 456,
710 foo => 'a',
711 });
712
713Possible remediations include scrubbing your parameters with a form validator like
714L<HTML::FormHandler> or being careful to force scalar context using the scalar
715keyword:
716
717 $c->model('User')->create({
718 user => scalar($c->req->param('user')),
719 foo => scalar($c->req->param('foo')),
720 });
721
f384c848 722Upcoming versions of L<Catalyst> will disable this interface by default and require
723you to positively enable it should you require it for backwards compatibility reasons.
724
e7c0c583 725=cut
726
727sub param {
728 my $self = shift;
729
730 if ( @_ == 0 ) {
731 return keys %{ $self->parameters };
732 }
733
4f96d61c 734 # If anything in @_ is undef, carp about that, and remove it from
735 # the list;
736
737 my @params = grep { defined($_) ? 1 : do {carp "You called ->params with an undefined value"; 0} } @_;
738
739 if ( @params == 1 ) {
e7c0c583 740
4f96d61c 741 defined(my $param = shift @params) ||
742 carp "You called ->params with an undefined value 2";
6bd2b72c 743
bfde09a2 744 unless ( exists $self->parameters->{$param} ) {
745 return wantarray ? () : undef;
746 }
747
748 if ( ref $self->parameters->{$param} eq 'ARRAY' ) {
749 return (wantarray)
750 ? @{ $self->parameters->{$param} }
751 : $self->parameters->{$param}->[0];
752 }
753 else {
754 return (wantarray)
755 ? ( $self->parameters->{$param} )
756 : $self->parameters->{$param};
757 }
d7945f32 758 }
4f96d61c 759 elsif ( @params > 1 ) {
760 my $field = shift @params;
90d3ac10 761 $self->parameters->{$field} = [@params];
d7945f32 762 }
e7c0c583 763}
b5176d9e 764
b5ecfcf0 765=head2 $req->parameters
61b1e958 766
3e19f4f6 767Returns a reference to a hash containing GET and POST parameters. Values can
d08ced28 768be either a scalar or an arrayref containing scalars.
fc7ec1d9 769
e7c0c583 770 print $c->request->parameters->{field};
771 print $c->request->parameters->{field}->[0];
fc7ec1d9 772
c436c1e8 773This is the combination of C<query_parameters> and C<body_parameters>.
774
b5ecfcf0 775=head2 $req->params
3e19f4f6 776
777Shortcut for $req->parameters.
778
b5ecfcf0 779=head2 $req->path
fc7ec1d9 780
3e19f4f6 781Returns the path, i.e. the part of the URI after $req->base, for the current request.
fc7ec1d9 782
be6801fa 783 http://localhost/path/foo
784
785 $c->request->path will contain 'path/foo'
786
b5ecfcf0 787=head2 $req->path_info
fbcc39ad 788
10011c19 789Alias for path, added for compatibility with L<CGI>.
fbcc39ad 790
791=cut
792
793sub path {
02fb5d78 794 my ( $self, @params ) = @_;
4f5ebacd 795
02fb5d78 796 if (@params) {
797 $self->uri->path(@params);
02570318 798 $self->_clear_path;
fbcc39ad 799 }
02570318 800 elsif ( $self->_has_path ) {
801 return $self->_path;
e561386f 802 }
02fb5d78 803 else {
804 my $path = $self->uri->path;
805 my $location = $self->base->path;
806 $path =~ s/^(\Q$location\E)?//;
807 $path =~ s/^\///;
02570318 808 $self->_path($path);
fbcc39ad 809
02fb5d78 810 return $path;
811 }
fbcc39ad 812}
813
b5ecfcf0 814=head2 $req->protocol
bfde09a2 815
3e19f4f6 816Returns the protocol (HTTP/1.0 or HTTP/1.1) used for the current request.
bfde09a2 817
b5ecfcf0 818=head2 $req->query_parameters
fbcc39ad 819
def54ce2 820=head2 $req->query_params
821
3e19f4f6 822Returns a reference to a hash containing query string (GET) parameters. Values can
fbcc39ad 823be either a scalar or an arrayref containing scalars.
824
825 print $c->request->query_parameters->{field};
826 print $c->request->query_parameters->{field}->[0];
b0ad47c1 827
b5ecfcf0 828=head2 $req->read( [$maxlength] )
fbcc39ad 829
3e19f4f6 830Reads a chunk of data from the request body. This method is intended to be
831used in a while loop, reading $maxlength bytes on every call. $maxlength
fbcc39ad 832defaults to the size of the request if not specified.
833
87f50436 834=head2 $req->read_chunk(\$buff, $max)
835
d7f18923 836Reads a chunk.
87f50436 837
9779c885 838You have to set MyApp->config(parse_on_demand => 1) to use this directly.
fbcc39ad 839
b5ecfcf0 840=head2 $req->referer
fc7ec1d9 841
3e19f4f6 842Shortcut for $req->headers->referer. Returns the referring page.
fc7ec1d9 843
b5ecfcf0 844=head2 $req->secure
bfde09a2 845
328f225e 846Returns true or false, indicating whether the connection is secure
d7f18923 847(https). The reliability of $req->secure may depend on your server
848configuration; Catalyst relies on PSGI to determine whether or not a
849request is secure (Catalyst looks at psgi.url_scheme), and different
850PSGI servers may make this determination in different ways (as by
851directly passing along information from the server, interpreting any of
852several HTTP headers, or using heuristics of their own).
bfde09a2 853
2982e768 854=head2 $req->captures
855
5c6a56e0 856Returns a reference to an array containing captured args from chained
857actions or regex captures.
fc7ec1d9 858
2982e768 859 my @captures = @{ $c->request->captures };
860
b5ecfcf0 861=head2 $req->upload
e7c0c583 862
3e19f4f6 863A convenient method to access $req->uploads.
e7c0c583 864
865 $upload = $c->request->upload('field');
866 @uploads = $c->request->upload('field');
867 @fields = $c->request->upload;
bfde09a2 868
e7c0c583 869 for my $upload ( $c->request->upload('field') ) {
146554c5 870 print $upload->filename;
e7c0c583 871 }
872
873=cut
874
875sub upload {
876 my $self = shift;
877
878 if ( @_ == 0 ) {
879 return keys %{ $self->uploads };
880 }
881
bfde09a2 882 if ( @_ == 1 ) {
e7c0c583 883
bfde09a2 884 my $upload = shift;
885
886 unless ( exists $self->uploads->{$upload} ) {
887 return wantarray ? () : undef;
888 }
6bd2b72c 889
bfde09a2 890 if ( ref $self->uploads->{$upload} eq 'ARRAY' ) {
891 return (wantarray)
892 ? @{ $self->uploads->{$upload} }
893 : $self->uploads->{$upload}->[0];
894 }
895 else {
896 return (wantarray)
fbcc39ad 897 ? ( $self->uploads->{$upload} )
898 : $self->uploads->{$upload};
bfde09a2 899 }
d7945f32 900 }
bfde09a2 901
a4f5c51e 902 if ( @_ > 1 ) {
bfde09a2 903
904 while ( my ( $field, $upload ) = splice( @_, 0, 2 ) ) {
905
906 if ( exists $self->uploads->{$field} ) {
907 for ( $self->uploads->{$field} ) {
908 $_ = [$_] unless ref($_) eq "ARRAY";
909 push( @$_, $upload );
910 }
911 }
912 else {
913 $self->uploads->{$field} = $upload;
914 }
915 }
e7c0c583 916 }
917}
918
b5ecfcf0 919=head2 $req->uploads
fc7ec1d9 920
bfde09a2 921Returns a reference to a hash containing uploads. Values can be either a
b0ad47c1 922L<Catalyst::Request::Upload> object, or an arrayref of
84e7aa89 923L<Catalyst::Request::Upload> objects.
e7c0c583 924
925 my $upload = $c->request->uploads->{field};
926 my $upload = $c->request->uploads->{field}->[0];
927
b5ecfcf0 928=head2 $req->uri
fbcc39ad 929
d26ee0d0 930Returns a L<URI> object for the current request. Stringifies to the URI text.
fbcc39ad 931
a375a206 932=head2 $req->mangle_params( { key => 'value' }, $appendmode);
bd917b94 933
a375a206 934Returns a hashref of parameters stemming from the current request's params,
935plus the ones supplied. Keys for which no current param exists will be
936added, keys with undefined values will be removed and keys with existing
937params will be replaced. Note that you can supply a true value as the final
938argument to change behavior with regards to existing parameters, appending
939values rather than replacing them.
940
941A quick example:
942
943 # URI query params foo=1
944 my $hashref = $req->mangle_params({ foo => 2 });
945 # Result is query params of foo=2
946
947versus append mode:
948
949 # URI query params foo=1
950 my $hashref = $req->mangle_params({ foo => 2 }, 1);
951 # Result is query params of foo=1&foo=2
952
953This is the code behind C<uri_with>.
bd917b94 954
955=cut
956
a375a206 957sub mangle_params {
958 my ($self, $args, $append) = @_;
b0ad47c1 959
a375a206 960 carp('No arguments passed to mangle_params()') unless $args;
fbb513f7 961
2f381252 962 foreach my $value ( values %$args ) {
d0f0fcf6 963 next unless defined $value;
fbb513f7 964 for ( ref $value eq 'ARRAY' ? @$value : $value ) {
965 $_ = "$_";
5c779e98 966 # utf8::encode($_);
fc42a730 967 }
fc42a730 968 };
b0ad47c1 969
a375a206 970 my %params = %{ $self->uri->query_form_hash };
971 foreach my $key (keys %{ $args }) {
972 my $val = $args->{$key};
973 if(defined($val)) {
974
975 if($append && exists($params{$key})) {
976
977 # This little bit of heaven handles appending a new value onto
978 # an existing one regardless if the existing value is an array
979 # or not, and regardless if the new value is an array or not
980 $params{$key} = [
981 ref($params{$key}) eq 'ARRAY' ? @{ $params{$key} } : $params{$key},
982 ref($val) eq 'ARRAY' ? @{ $val } : $val
983 ];
984
985 } else {
986 $params{$key} = $val;
987 }
988 } else {
989
990 # If the param wasn't defined then we delete it.
991 delete($params{$key});
992 }
993 }
994
995
996 return \%params;
997}
998
999=head2 $req->uri_with( { key => 'value' } );
1000
1001Returns a rewritten URI object for the current request. Key/value pairs
1002passed in will override existing parameters. You can remove an existing
1003parameter by passing in an undef value. Unmodified pairs will be
1004preserved.
1005
1006You may also pass an optional second parameter that puts C<uri_with> into
1007append mode:
1008
1009 $req->uri_with( { key => 'value' }, { mode => 'append' } );
9779c885 1010
a375a206 1011See C<mangle_params> for an explanation of this behavior.
1012
1013=cut
1014
1015sub uri_with {
1016 my( $self, $args, $behavior) = @_;
1017
1018 carp( 'No arguments passed to uri_with()' ) unless $args;
1019
1020 my $append = 0;
1021 if((ref($behavior) eq 'HASH') && defined($behavior->{mode}) && ($behavior->{mode} eq 'append')) {
1022 $append = 1;
1023 }
1024
1025 my $params = $self->mangle_params($args, $append);
1026
1027 my $uri = $self->uri->clone;
1028 $uri->query_form($params);
2f381252 1029
bd917b94 1030 return $uri;
1031}
1032
8026359e 1033=head2 $req->remote_user
1034
1035Returns the value of the C<REMOTE_USER> environment variable.
7ce7ca2e 1036
b5ecfcf0 1037=head2 $req->user_agent
b5176d9e 1038
3e19f4f6 1039Shortcut to $req->headers->user_agent. Returns the user agent (browser)
1040version string.
b5176d9e 1041
eb1f4b49 1042=head2 $req->io_fh
1043
1044Returns a psgix.io bidirectional socket, if your server supports one. Used for
1045when you want to jailbreak out of PSGI and handle bidirectional client server
1046communication manually, such as when you are using cometd or websockets.
1047
47b9d68e 1048=head1 SETUP METHODS
1049
1050You should never need to call these yourself in application code,
1051however they are useful if extending Catalyst by applying a request role.
1052
1053=head2 $self->prepare_headers()
1054
1055Sets up the C<< $res->headers >> accessor.
1056
1057=head2 $self->prepare_body()
1058
1059Sets up the body using L<HTTP::Body>
1060
1061=head2 $self->prepare_body_chunk()
1062
1063Add a chunk to the request body.
1064
1065=head2 $self->prepare_body_parameters()
1066
1067Sets up parameters from body.
1068
8738b8fe 1069=head2 $self->prepare_cookies()
47b9d68e 1070
1071Parse cookies from header. Sets up a L<CGI::Simple::Cookie> object.
1072
8738b8fe 1073=head2 $self->prepare_connection()
1074
1075Sets up various fields in the request like the local and remote addresses,
f59eeb09 1076request method, hostname requested etc.
8738b8fe 1077
1078=head2 $self->prepare_parameters()
1079
1080Ensures that the body has been parsed, then builds the parameters, which are
1081combined from those in the request and those in the body.
1082
11e7af55 1083If parameters have already been set will clear the parameters and build them again.
1084
9d8d0ab9 1085=head2 $self->env
1086
1087Access to the raw PSGI env.
8738b8fe 1088
059c085b 1089=head2 meta
1090
1091Provided by Moose
1092
3e19f4f6 1093=head1 AUTHORS
fc7ec1d9 1094
2f381252 1095Catalyst Contributors, see Catalyst.pm
fc7ec1d9 1096
1097=head1 COPYRIGHT
1098
536bee89 1099This library is free software. You can redistribute it and/or modify
61b1e958 1100it under the same terms as Perl itself.
fc7ec1d9 1101
1102=cut
1103
e5ecd5bc 1104__PACKAGE__->meta->make_immutable;
1105
fc7ec1d9 11061;