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