Add tests to show that 5.80 broke ->req->parameters when you do on-demand parsing.
[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;
b4ca0ee8 10
059c085b 11use Moose;
12
6802c884 13use namespace::clean -except => 'meta';
14
b99ff5d8 15with 'MooseX::Emulate::Class::Accessor::Fast';
16
5fb12dbb 17has action => (is => 'rw');
18has address => (is => 'rw');
19has arguments => (is => 'rw', default => sub { [] });
20has cookies => (is => 'rw', default => sub { {} });
21has query_keywords => (is => 'rw');
22has match => (is => 'rw');
23has method => (is => 'rw');
24has protocol => (is => 'rw');
059c085b 25has query_parameters => (is => 'rw', default => sub { {} });
5fb12dbb 26has secure => (is => 'rw', default => 0);
27has captures => (is => 'rw', default => sub { [] });
6cb9e383 28has uri => (is => 'rw', predicate => 'has_uri');
f263fa9a 29has user => (is => 'rw');
5fb12dbb 30has headers => (
e5ecd5bc 31 is => 'rw',
059c085b 32 isa => 'HTTP::Headers',
33 handles => [qw(content_encoding content_length content_type header referer user_agent)],
6680c772 34 default => sub { HTTP::Headers->new() },
35 required => 1,
36 lazy => 1,
059c085b 37);
38
02570318 39# Moose TODO:
40# - Can we lose the before modifiers which just call prepare_body ?
41# they are wasteful, slow us down and feel cluttery.
0fc2d522 42# Can we call prepare_body at BUILD time?
02570318 43# Can we make _body an attribute, have the rest of
44# these lazy build from there and kill all the direct hash access
45# in Catalyst.pm and Engine.pm?
0fc2d522 46
059c085b 47has _context => (
48 is => 'rw',
49 weak_ref => 1,
0fc2d522 50 handles => ['read'],
02570318 51 clearer => '_clear_context',
059c085b 52);
53
54has body_parameters => (
5fb12dbb 55 is => 'rw',
56 required => 1,
57 lazy => 1,
58 default => sub { {} },
fc7ec1d9 59);
60
059c085b 61before body_parameters => sub {
62 my ($self) = @_;
63 $self->_context->prepare_body();
64};
65
66has uploads => (
5fb12dbb 67 is => 'rw',
68 required => 1,
5fb12dbb 69 default => sub { {} },
059c085b 70);
71
059c085b 72has parameters => (
73 is => 'rw',
74 required => 1,
75 lazy => 1,
76 default => sub { {} },
77);
78
e99ec2dc 79around parameters => sub {
80 my ($orig, $self, $params) = @_;
81 if ($params) {
82 if ( !ref $params ) {
83 $self->_context->log->warn(
84 "Attempt to retrieve '$params' with req->params(), " .
85 "you probably meant to call req->param('$params')"
86 );
87 $params = undef;
88 }
89 return $self->$orig($params);
90 }
91 $self->$orig();
059c085b 92};
93
94has base => (
5fb12dbb 95 is => 'rw',
96 required => 1,
97 lazy => 1,
98 default => sub {
059c085b 99 my $self = shift;
6cb9e383 100 return $self->path if $self->has_uri;
059c085b 101 },
102);
103
069355da 104has _body => (
0f56bbcf 105 is => 'rw', clearer => '_clear_body', predicate => '_has_body',
059c085b 106);
610bc6ec 107# Eugh, ugly. Should just be able to rename accessor methods to 'body'
108# and provide a custom reader..
109sub body {
110 my $self = shift;
059c085b 111 $self->_context->prepare_body();
610bc6ec 112 $self->_body(@_) if scalar @_;
113 return blessed $self->_body ? $self->_body->body : $self->_body;
114}
059c085b 115
116has hostname => (
117 is => 'rw',
118 required => 1,
119 lazy => 1,
120 default => sub {
121 my ($self) = @_;
8fc0d39e 122 gethostbyaddr( inet_aton( $self->address ), AF_INET ) || 'localhost'
059c085b 123 },
124);
125
02570318 126has _path => ( is => 'rw', predicate => '_has_path', clearer => '_clear_path' );
127
059c085b 128sub args { shift->arguments(@_) }
129sub body_params { shift->body_parameters(@_) }
130sub input { shift->body(@_) }
131sub params { shift->parameters(@_) }
132sub query_params { shift->query_parameters(@_) }
133sub path_info { shift->path(@_) }
134sub snippets { shift->captures(@_) }
f7e4e231 135
fc7ec1d9 136=head1 NAME
137
3e19f4f6 138Catalyst::Request - provides information about the current client request
fc7ec1d9 139
140=head1 SYNOPSIS
141
b22c6668 142 $req = $c->request;
143 $req->action;
144 $req->address;
b22c6668 145 $req->arguments;
3e19f4f6 146 $req->args;
b22c6668 147 $req->base;
06e1b616 148 $req->body;
fbcc39ad 149 $req->body_parameters;
b5176d9e 150 $req->content_encoding;
151 $req->content_length;
152 $req->content_type;
b77e7869 153 $req->cookie;
b22c6668 154 $req->cookies;
b5176d9e 155 $req->header;
b22c6668 156 $req->headers;
157 $req->hostname;
61bacdcc 158 $req->input;
3b4d1251 159 $req->query_keywords;
b22c6668 160 $req->match;
161 $req->method;
e7c0c583 162 $req->param;
e7c0c583 163 $req->parameters;
3e19f4f6 164 $req->params;
b22c6668 165 $req->path;
bfde09a2 166 $req->protocol;
fbcc39ad 167 $req->query_parameters;
168 $req->read;
b5176d9e 169 $req->referer;
bfde09a2 170 $req->secure;
2982e768 171 $req->captures; # previously knows as snippets
e7c0c583 172 $req->upload;
b22c6668 173 $req->uploads;
77d12cae 174 $req->uri;
7ce7ca2e 175 $req->user;
66294129 176 $req->user_agent;
b22c6668 177
3e22baa5 178See also L<Catalyst>, L<Catalyst::Request::Upload>.
fc7ec1d9 179
180=head1 DESCRIPTION
181
3e19f4f6 182This is the Catalyst Request class, which provides an interface to data for the
183current client request. The request object is prepared by L<Catalyst::Engine>,
184thus hiding the details of the particular engine implementation.
b22c6668 185
186=head1 METHODS
fc7ec1d9 187
b5ecfcf0 188=head2 $req->action
fc7ec1d9 189
aae8d418 190[DEPRECATED] Returns the name of the requested action.
191
192
193Use C<< $c->action >> instead (which returns a
194L<Catalyst::Action|Catalyst::Action> object).
fc7ec1d9 195
b5ecfcf0 196=head2 $req->address
0556eb49 197
3e19f4f6 198Returns the IP address of the client.
61b1e958 199
b5ecfcf0 200=head2 $req->arguments
61b1e958 201
b22c6668 202Returns a reference to an array containing the arguments.
fc7ec1d9 203
204 print $c->request->arguments->[0];
205
c436c1e8 206For example, if your action was
207
85d9fce6 208 package MyApp::C::Foo;
209
210 sub moose : Local {
211 ...
212 }
c436c1e8 213
3e19f4f6 214and the URI for the request was C<http://.../foo/moose/bah>, the string C<bah>
c436c1e8 215would be the first and only argument.
216
8f58057d 217Arguments just get passed through and B<don't> get unescaped automatically, so
218you should do that explicitly.
219
b5ecfcf0 220=head2 $req->args
3e19f4f6 221
222Shortcut for arguments.
223
b5ecfcf0 224=head2 $req->base
fc7ec1d9 225
328f225e 226Contains the URI base. This will always have a trailing slash. Note that the
227URI scheme (eg., http vs. https) must be determined through heuristics;
228depending on your server configuration, it may be incorrect. See $req->secure
229for more info.
c436c1e8 230
3e19f4f6 231If your application was queried with the URI
232C<http://localhost:3000/some/path> then C<base> is C<http://localhost:3000/>.
fc7ec1d9 233
b5ecfcf0 234=head2 $req->body
06e1b616 235
3e19f4f6 236Returns the message body of the request, unless Content-Type is
e060fe05 237C<application/x-www-form-urlencoded> or C<multipart/form-data>.
238
b5ecfcf0 239=head2 $req->body_parameters
fbcc39ad 240
3e19f4f6 241Returns a reference to a hash containing body (POST) parameters. Values can
fbcc39ad 242be either a scalar or an arrayref containing scalars.
243
244 print $c->request->body_parameters->{field};
245 print $c->request->body_parameters->{field}->[0];
c436c1e8 246
d631b5f9 247These are the parameters from the POST part of the request, if any.
e5ecd5bc 248
b5ecfcf0 249=head2 $req->body_params
fbcc39ad 250
3e19f4f6 251Shortcut for body_parameters.
fbcc39ad 252
b5ecfcf0 253=head2 $req->content_encoding
b5176d9e 254
3e19f4f6 255Shortcut for $req->headers->content_encoding.
b5176d9e 256
b5ecfcf0 257=head2 $req->content_length
b5176d9e 258
3e19f4f6 259Shortcut for $req->headers->content_length.
b5176d9e 260
b5ecfcf0 261=head2 $req->content_type
b5176d9e 262
3e19f4f6 263Shortcut for $req->headers->content_type.
b5176d9e 264
b5ecfcf0 265=head2 $req->cookie
3ad654e0 266
3e19f4f6 267A convenient method to access $req->cookies.
3ad654e0 268
269 $cookie = $c->request->cookie('name');
270 @cookies = $c->request->cookie;
271
272=cut
273
274sub cookie {
275 my $self = shift;
276
277 if ( @_ == 0 ) {
b77e7869 278 return keys %{ $self->cookies };
3ad654e0 279 }
280
281 if ( @_ == 1 ) {
282
283 my $name = shift;
284
b77e7869 285 unless ( exists $self->cookies->{$name} ) {
3ad654e0 286 return undef;
287 }
fbcc39ad 288
b77e7869 289 return $self->cookies->{$name};
3ad654e0 290 }
291}
292
b5ecfcf0 293=head2 $req->cookies
fc7ec1d9 294
b22c6668 295Returns a reference to a hash containing the cookies.
fc7ec1d9 296
297 print $c->request->cookies->{mycookie}->value;
298
3e19f4f6 299The cookies in the hash are indexed by name, and the values are L<CGI::Cookie>
c436c1e8 300objects.
301
b5ecfcf0 302=head2 $req->header
b5176d9e 303
3e19f4f6 304Shortcut for $req->headers->header.
b5176d9e 305
b5ecfcf0 306=head2 $req->headers
fc7ec1d9 307
3e19f4f6 308Returns an L<HTTP::Headers> object containing the headers for the current request.
fc7ec1d9 309
310 print $c->request->headers->header('X-Catalyst');
311
b5ecfcf0 312=head2 $req->hostname
0556eb49 313
3e19f4f6 314Returns the hostname of the client.
e5ecd5bc 315
b5ecfcf0 316=head2 $req->input
61bacdcc 317
3e19f4f6 318Alias for $req->body.
61bacdcc 319
3b4d1251 320=head2 $req->query_keywords
321
322Contains the keywords portion of a query string, when no '=' signs are
323present.
324
325 http://localhost/path?some+keywords
ac5c933b 326
3b4d1251 327 $c->request->query_keywords will contain 'some keywords'
328
b5ecfcf0 329=head2 $req->match
fc7ec1d9 330
3e19f4f6 331This contains the matching part of a Regex action. Otherwise
2c83fd5a 332it returns the same as 'action', except for default actions,
333which return an empty string.
fc7ec1d9 334
b5ecfcf0 335=head2 $req->method
b5176d9e 336
337Contains the request method (C<GET>, C<POST>, C<HEAD>, etc).
338
b5ecfcf0 339=head2 $req->param
e7c0c583 340
ac5c933b 341Returns GET and POST parameters with a CGI.pm-compatible param method. This
3e19f4f6 342is an alternative method for accessing parameters in $c->req->parameters.
e7c0c583 343
a82c2894 344 $value = $c->request->param( 'foo' );
345 @values = $c->request->param( 'foo' );
e7c0c583 346 @params = $c->request->param;
347
3e705254 348Like L<CGI>, and B<unlike> earlier versions of Catalyst, passing multiple
a82c2894 349arguments to this method, like this:
350
85d9fce6 351 $c->request->param( 'foo', 'bar', 'gorch', 'quxx' );
a82c2894 352
353will set the parameter C<foo> to the multiple values C<bar>, C<gorch> and
354C<quxx>. Previously this would have added C<bar> as another value to C<foo>
3e19f4f6 355(creating it if it didn't exist before), and C<quxx> as another value for
356C<gorch>.
a82c2894 357
e7c0c583 358=cut
359
360sub param {
361 my $self = shift;
362
363 if ( @_ == 0 ) {
364 return keys %{ $self->parameters };
365 }
366
bfde09a2 367 if ( @_ == 1 ) {
e7c0c583 368
bfde09a2 369 my $param = shift;
6bd2b72c 370
bfde09a2 371 unless ( exists $self->parameters->{$param} ) {
372 return wantarray ? () : undef;
373 }
374
375 if ( ref $self->parameters->{$param} eq 'ARRAY' ) {
376 return (wantarray)
377 ? @{ $self->parameters->{$param} }
378 : $self->parameters->{$param}->[0];
379 }
380 else {
381 return (wantarray)
382 ? ( $self->parameters->{$param} )
383 : $self->parameters->{$param};
384 }
d7945f32 385 }
a82c2894 386 elsif ( @_ > 1 ) {
387 my $field = shift;
388 $self->parameters->{$field} = [@_];
d7945f32 389 }
e7c0c583 390}
b5176d9e 391
b5ecfcf0 392=head2 $req->parameters
61b1e958 393
3e19f4f6 394Returns a reference to a hash containing GET and POST parameters. Values can
d08ced28 395be either a scalar or an arrayref containing scalars.
fc7ec1d9 396
e7c0c583 397 print $c->request->parameters->{field};
398 print $c->request->parameters->{field}->[0];
fc7ec1d9 399
c436c1e8 400This is the combination of C<query_parameters> and C<body_parameters>.
401
b5ecfcf0 402=head2 $req->params
3e19f4f6 403
404Shortcut for $req->parameters.
405
b5ecfcf0 406=head2 $req->path
fc7ec1d9 407
3e19f4f6 408Returns the path, i.e. the part of the URI after $req->base, for the current request.
fc7ec1d9 409
b5ecfcf0 410=head2 $req->path_info
fbcc39ad 411
10011c19 412Alias for path, added for compatibility with L<CGI>.
fbcc39ad 413
414=cut
415
416sub path {
02fb5d78 417 my ( $self, @params ) = @_;
4f5ebacd 418
02fb5d78 419 if (@params) {
420 $self->uri->path(@params);
02570318 421 $self->_clear_path;
fbcc39ad 422 }
02570318 423 elsif ( $self->_has_path ) {
424 return $self->_path;
e561386f 425 }
02fb5d78 426 else {
427 my $path = $self->uri->path;
428 my $location = $self->base->path;
429 $path =~ s/^(\Q$location\E)?//;
430 $path =~ s/^\///;
02570318 431 $self->_path($path);
fbcc39ad 432
02fb5d78 433 return $path;
434 }
fbcc39ad 435}
436
b5ecfcf0 437=head2 $req->protocol
bfde09a2 438
3e19f4f6 439Returns the protocol (HTTP/1.0 or HTTP/1.1) used for the current request.
bfde09a2 440
b5ecfcf0 441=head2 $req->query_parameters
fbcc39ad 442
def54ce2 443=head2 $req->query_params
444
3e19f4f6 445Returns a reference to a hash containing query string (GET) parameters. Values can
fbcc39ad 446be either a scalar or an arrayref containing scalars.
447
448 print $c->request->query_parameters->{field};
449 print $c->request->query_parameters->{field}->[0];
ac5c933b 450
b5ecfcf0 451=head2 $req->read( [$maxlength] )
fbcc39ad 452
3e19f4f6 453Reads a chunk of data from the request body. This method is intended to be
454used in a while loop, reading $maxlength bytes on every call. $maxlength
fbcc39ad 455defaults to the size of the request if not specified.
456
457You have to set MyApp->config->{parse_on_demand} to use this directly.
458
b5ecfcf0 459=head2 $req->referer
fc7ec1d9 460
3e19f4f6 461Shortcut for $req->headers->referer. Returns the referring page.
fc7ec1d9 462
b5ecfcf0 463=head2 $req->secure
bfde09a2 464
328f225e 465Returns true or false, indicating whether the connection is secure
466(https). Note that the URI scheme (eg., http vs. https) must be determined
467through heuristics, and therefore the reliablity of $req->secure will depend
468on your server configuration. If you are serving secure pages on the standard
469SSL port (443) and/or setting the HTTPS environment variable, $req->secure
470should be valid.
bfde09a2 471
2982e768 472=head2 $req->captures
473
5c6a56e0 474Returns a reference to an array containing captured args from chained
475actions or regex captures.
fc7ec1d9 476
2982e768 477 my @captures = @{ $c->request->captures };
478
479=head2 $req->snippets
fc7ec1d9 480
10011c19 481C<captures> used to be called snippets. This is still available for backwards
2982e768 482compatibility, but is considered deprecated.
fc7ec1d9 483
b5ecfcf0 484=head2 $req->upload
e7c0c583 485
3e19f4f6 486A convenient method to access $req->uploads.
e7c0c583 487
488 $upload = $c->request->upload('field');
489 @uploads = $c->request->upload('field');
490 @fields = $c->request->upload;
bfde09a2 491
e7c0c583 492 for my $upload ( $c->request->upload('field') ) {
146554c5 493 print $upload->filename;
e7c0c583 494 }
495
496=cut
497
498sub upload {
499 my $self = shift;
500
501 if ( @_ == 0 ) {
502 return keys %{ $self->uploads };
503 }
504
bfde09a2 505 if ( @_ == 1 ) {
e7c0c583 506
bfde09a2 507 my $upload = shift;
508
509 unless ( exists $self->uploads->{$upload} ) {
510 return wantarray ? () : undef;
511 }
6bd2b72c 512
bfde09a2 513 if ( ref $self->uploads->{$upload} eq 'ARRAY' ) {
514 return (wantarray)
515 ? @{ $self->uploads->{$upload} }
516 : $self->uploads->{$upload}->[0];
517 }
518 else {
519 return (wantarray)
fbcc39ad 520 ? ( $self->uploads->{$upload} )
521 : $self->uploads->{$upload};
bfde09a2 522 }
d7945f32 523 }
bfde09a2 524
a4f5c51e 525 if ( @_ > 1 ) {
bfde09a2 526
527 while ( my ( $field, $upload ) = splice( @_, 0, 2 ) ) {
528
529 if ( exists $self->uploads->{$field} ) {
530 for ( $self->uploads->{$field} ) {
531 $_ = [$_] unless ref($_) eq "ARRAY";
532 push( @$_, $upload );
533 }
534 }
535 else {
536 $self->uploads->{$field} = $upload;
537 }
538 }
e7c0c583 539 }
540}
541
b5ecfcf0 542=head2 $req->uploads
fc7ec1d9 543
bfde09a2 544Returns a reference to a hash containing uploads. Values can be either a
ac5c933b 545L<Catalyst::Request::Upload> object, or an arrayref of
84e7aa89 546L<Catalyst::Request::Upload> objects.
e7c0c583 547
548 my $upload = $c->request->uploads->{field};
549 my $upload = $c->request->uploads->{field}->[0];
550
b5ecfcf0 551=head2 $req->uri
fbcc39ad 552
3e19f4f6 553Returns a URI object for the current request. Stringifies to the URI text.
fbcc39ad 554
bd917b94 555=head2 $req->uri_with( { key => 'value' } );
556
3338e8ce 557Returns a rewritten URI object for the current request. Key/value pairs
2f381252 558passed in will override existing parameters. You can remove an existing
559parameter by passing in an undef value. Unmodified pairs will be
3338e8ce 560preserved.
bd917b94 561
562=cut
563
564sub uri_with {
565 my( $self, $args ) = @_;
ac5c933b 566
bd917b94 567 carp( 'No arguments passed to uri_with()' ) unless $args;
fbb513f7 568
2f381252 569 foreach my $value ( values %$args ) {
d0f0fcf6 570 next unless defined $value;
fbb513f7 571 for ( ref $value eq 'ARRAY' ? @$value : $value ) {
572 $_ = "$_";
7066a4d5 573 utf8::encode( $_ ) if utf8::is_utf8($_);
fc42a730 574 }
fc42a730 575 };
ac5c933b 576
2f381252 577 my $uri = $self->uri->clone;
578 my %query = ( %{ $uri->query_form_hash }, %$args );
579
bd917b94 580 $uri->query_form( {
2f381252 581 # remove undef values
582 map { defined $query{ $_ } ? ( $_ => $query{ $_ } ) : () } keys %query
bd917b94 583 } );
584 return $uri;
585}
586
b5ecfcf0 587=head2 $req->user
7ce7ca2e 588
3e19f4f6 589Returns the currently logged in user. Deprecated. The method recommended for
590newer plugins is $c->user.
7ce7ca2e 591
b5ecfcf0 592=head2 $req->user_agent
b5176d9e 593
3e19f4f6 594Shortcut to $req->headers->user_agent. Returns the user agent (browser)
595version string.
b5176d9e 596
059c085b 597=head2 meta
598
599Provided by Moose
600
3e19f4f6 601=head1 AUTHORS
fc7ec1d9 602
2f381252 603Catalyst Contributors, see Catalyst.pm
fc7ec1d9 604
605=head1 COPYRIGHT
606
e7c0c583 607This program is free software, you can redistribute it and/or modify
61b1e958 608it under the same terms as Perl itself.
fc7ec1d9 609
610=cut
611
e5ecd5bc 612__PACKAGE__->meta->make_immutable;
613
fc7ec1d9 6141;