fixed spelling error
[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
952ff530 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');
059c085b 63has query_parameters => (is => 'rw', default => sub { {} });
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',
99 predicate=>'has_io_fh',
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
213 ## setup for downstream plack
214 $self->env->{'plack.request.merged'} ||= do {
215 my $query = $self->env->{'plack.request.query'} || Hash::MultiValue->new;
216 my $body = $self->env->{'plack.request.body'} || Hash::MultiValue->new;
217 Hash::MultiValue->new($query->flatten, $body->flatten);
218 };
219
88ba7793 220 if($self->_use_hash_multivalue) {
221 return $self->env->{'plack.request.merged'}->clone; # We want a copy, in case your App is evil
222 }
223
1cbdfa9b 224 # We copy, no references
225 foreach my $name (keys %$query_parameters) {
226 my $param = $query_parameters->{$name};
227 $parameters->{$name} = ref $param eq 'ARRAY' ? [ @$param ] : $param;
228 }
229
230 # Merge query and body parameters
231 foreach my $name (keys %$body_parameters) {
232 my $param = $body_parameters->{$name};
233 my @values = ref $param eq 'ARRAY' ? @$param : ($param);
234 if ( my $existing = $parameters->{$name} ) {
235 unshift(@values, (ref $existing eq 'ARRAY' ? @$existing : $existing));
236 }
237 $parameters->{$name} = @values > 1 ? \@values : $values[0];
238 }
239 $parameters;
240}
241
398f13db 242has _uploadtmp => (
243 is => 'ro',
244 predicate => '_has_uploadtmp',
245);
246
247sub prepare_body {
248 my ( $self ) = @_;
249
191665f3 250 # If previously applied middleware created the HTTP::Body object, then we
251 # just use that one.
952ff530 252
253 if(my $plack_body = $self->env->{'plack.request.http.body'}) {
952ff530 254 $self->_body($plack_body);
191665f3 255 $self->_body->cleanup(1);
256 return;
952ff530 257 }
258
191665f3 259 # Define PSGI ENV placeholders, or for empty should there be no content
260 # body (typical in HEAD or GET). Looks like from Plack::Request that
261 # middleware would probably expect to see this, even if empty
398f13db 262
191665f3 263 $self->env->{'plack.request.body'} = Hash::MultiValue->new;
264 $self->env->{'plack.request.upload'} = Hash::MultiValue->new;
398f13db 265
191665f3 266 # If there is nothing to read, set body to naught and return. This
267 # will cause all body code to be skipped
398f13db 268
191665f3 269 return $self->_body(0) unless my $length = $self->_read_length;
952ff530 270
191665f3 271 # Unless the body has already been set, create it. Not sure about this
272 # code, how else might it be set, but this was existing logic.
273
274 unless ($self->_body) {
275 my $type = $self->header('Content-Type');
276 $self->_body(HTTP::Body->new( $type, $length ));
277 $self->_body->cleanup(1);
952ff530 278
191665f3 279 # JNAP: I'm not sure this is doing what we expect, but it also doesn't
280 # seem to be hurting (seems ->_has_uploadtmp is true more than I would
281 # expect.
282
283 $self->_body->tmpdir( $self->_uploadtmp )
284 if $self->_has_uploadtmp;
952ff530 285 }
286
191665f3 287 # Ok if we get this far, we have to read psgi.input into the new body
288 # object. Lets play nice with any plack app or other downstream, so
289 # we create a buffer unless one exists.
290
291 my $stream_buffer;
292 if ($self->env->{'psgix.input.buffered'}) {
293 # Be paranoid about previous psgi middleware or apps that read the
294 # input but didn't return the buffer to the start.
295 $self->env->{'psgi.input'}->seek(0, 0);
296 } else {
297 $stream_buffer = Stream::Buffered->new($length);
298 }
952ff530 299
191665f3 300 # Check for definedness as you could read '0'
301 while ( defined ( my $chunk = $self->read() ) ) {
302 $self->prepare_body_chunk($chunk);
303 $stream_buffer->print($chunk) if $stream_buffer;
304 }
952ff530 305
191665f3 306 # Ok, we read the body. Lets play nice for any PSGI app down the pipe
307
308 if ($stream_buffer) {
309 $self->env->{'psgix.input.buffered'} = 1;
310 $self->env->{'psgi.input'} = $stream_buffer->rewind;
311 } else {
312 $self->env->{'psgi.input'}->seek(0, 0); # Reset the buffer for downstream middleware or apps
952ff530 313 }
191665f3 314
315 $self->env->{'plack.request.http.body'} = $self->_body;
316 $self->env->{'plack.request.body'} = Hash::MultiValue->from_mixed($self->_body->param);
317
318 # paranoia against wrong Content-Length header
319 my $remaining = $length - $self->_read_position;
320 if ( $remaining > 0 ) {
321 Catalyst::Exception->throw("Wrong Content-Length value: $length" );
952ff530 322 }
323}
324
398f13db 325sub prepare_body_chunk {
326 my ( $self, $chunk ) = @_;
327
328 $self->_body->add($chunk);
329}
330
398f13db 331sub prepare_body_parameters {
332 my ( $self ) = @_;
333
d003ff83 334 $self->prepare_body if ! $self->_has_body;
a7d2a530 335 return {} unless $self->_body;
398f13db 336
88ba7793 337 return $self->_use_hash_multivalue ?
338 $self->env->{'plack.request.body'}->clone :
339 $self->_body->param;
398f13db 340}
341620d5 341
2f498a7e 342sub prepare_connection {
343 my ($self) = @_;
344
345 my $env = $self->env;
346
347 $self->address( $env->{REMOTE_ADDR} );
348 $self->hostname( $env->{REMOTE_HOST} )
349 if exists $env->{REMOTE_HOST};
350 $self->protocol( $env->{SERVER_PROTOCOL} );
351 $self->remote_user( $env->{REMOTE_USER} );
352 $self->method( $env->{REQUEST_METHOD} );
353 $self->secure( $env->{'psgi.url_scheme'} eq 'https' ? 1 : 0 );
354}
355
356# XXX - FIXME - method is here now, move this crap...
e99ec2dc 357around parameters => sub {
358 my ($orig, $self, $params) = @_;
359 if ($params) {
360 if ( !ref $params ) {
7c1c4dc6 361 $self->_log->warn(
e99ec2dc 362 "Attempt to retrieve '$params' with req->params(), " .
363 "you probably meant to call req->param('$params')"
364 );
365 $params = undef;
366 }
367 return $self->$orig($params);
368 }
369 $self->$orig();
059c085b 370};
371
372has base => (
5fb12dbb 373 is => 'rw',
374 required => 1,
375 lazy => 1,
376 default => sub {
059c085b 377 my $self = shift;
6cb9e383 378 return $self->path if $self->has_uri;
059c085b 379 },
380);
381
069355da 382has _body => (
0f56bbcf 383 is => 'rw', clearer => '_clear_body', predicate => '_has_body',
059c085b 384);
610bc6ec 385# Eugh, ugly. Should just be able to rename accessor methods to 'body'
b0ad47c1 386# and provide a custom reader..
610bc6ec 387sub body {
388 my $self = shift;
952ff530 389 $self->prepare_body unless $self->_has_body;
14c057aa 390 croak 'body is a reader' if scalar @_;
610bc6ec 391 return blessed $self->_body ? $self->_body->body : $self->_body;
392}
059c085b 393
394has hostname => (
395 is => 'rw',
396 required => 1,
397 lazy => 1,
398 default => sub {
399 my ($self) = @_;
9fb936e5 400 gethostbyaddr( inet_aton( $self->address ), AF_INET ) || $self->address
059c085b 401 },
402);
403
02570318 404has _path => ( is => 'rw', predicate => '_has_path', clearer => '_clear_path' );
405
059c085b 406sub args { shift->arguments(@_) }
407sub body_params { shift->body_parameters(@_) }
408sub input { shift->body(@_) }
409sub params { shift->parameters(@_) }
410sub query_params { shift->query_parameters(@_) }
411sub path_info { shift->path(@_) }
f7e4e231 412
8738b8fe 413=for stopwords param params
965f3e35 414
fc7ec1d9 415=head1 NAME
416
3e19f4f6 417Catalyst::Request - provides information about the current client request
fc7ec1d9 418
419=head1 SYNOPSIS
420
b22c6668 421 $req = $c->request;
767480fd 422 $req->address eq "127.0.0.1";
b22c6668 423 $req->arguments;
3e19f4f6 424 $req->args;
b22c6668 425 $req->base;
06e1b616 426 $req->body;
974733c0 427 $req->body_data;
fbcc39ad 428 $req->body_parameters;
b5176d9e 429 $req->content_encoding;
430 $req->content_length;
431 $req->content_type;
b77e7869 432 $req->cookie;
b22c6668 433 $req->cookies;
b5176d9e 434 $req->header;
b22c6668 435 $req->headers;
436 $req->hostname;
61bacdcc 437 $req->input;
3b4d1251 438 $req->query_keywords;
b22c6668 439 $req->match;
440 $req->method;
e7c0c583 441 $req->param;
e7c0c583 442 $req->parameters;
3e19f4f6 443 $req->params;
b22c6668 444 $req->path;
bfde09a2 445 $req->protocol;
fbcc39ad 446 $req->query_parameters;
447 $req->read;
b5176d9e 448 $req->referer;
bfde09a2 449 $req->secure;
47b9d68e 450 $req->captures;
e7c0c583 451 $req->upload;
b22c6668 452 $req->uploads;
77d12cae 453 $req->uri;
7ce7ca2e 454 $req->user;
66294129 455 $req->user_agent;
b22c6668 456
3e22baa5 457See also L<Catalyst>, L<Catalyst::Request::Upload>.
fc7ec1d9 458
459=head1 DESCRIPTION
460
3e19f4f6 461This is the Catalyst Request class, which provides an interface to data for the
462current client request. The request object is prepared by L<Catalyst::Engine>,
463thus hiding the details of the particular engine implementation.
b22c6668 464
465=head1 METHODS
fc7ec1d9 466
b5ecfcf0 467=head2 $req->address
0556eb49 468
3e19f4f6 469Returns the IP address of the client.
61b1e958 470
b5ecfcf0 471=head2 $req->arguments
61b1e958 472
b22c6668 473Returns a reference to an array containing the arguments.
fc7ec1d9 474
475 print $c->request->arguments->[0];
476
c436c1e8 477For example, if your action was
478
7d7519a4 479 package MyApp::Controller::Foo;
85d9fce6 480
481 sub moose : Local {
482 ...
483 }
c436c1e8 484
3e19f4f6 485and the URI for the request was C<http://.../foo/moose/bah>, the string C<bah>
c436c1e8 486would be the first and only argument.
487
6d920953 488Arguments get automatically URI-unescaped for you.
8f58057d 489
b5ecfcf0 490=head2 $req->args
3e19f4f6 491
01011731 492Shortcut for L</arguments>.
3e19f4f6 493
b5ecfcf0 494=head2 $req->base
fc7ec1d9 495
328f225e 496Contains the URI base. This will always have a trailing slash. Note that the
f4dda4a8 497URI scheme (e.g., http vs. https) must be determined through heuristics;
328f225e 498depending on your server configuration, it may be incorrect. See $req->secure
499for more info.
c436c1e8 500
3e19f4f6 501If your application was queried with the URI
502C<http://localhost:3000/some/path> then C<base> is C<http://localhost:3000/>.
fc7ec1d9 503
b5ecfcf0 504=head2 $req->body
06e1b616 505
843871cf 506Returns the message body of the request, as returned by L<HTTP::Body>: a string,
507unless Content-Type is C<application/x-www-form-urlencoded>, C<text/xml>, or
508C<multipart/form-data>, in which case a L<File::Temp> object is returned.
e060fe05 509
974733c0 510=head2 $req->body_data
511
512Returns a Perl representation of POST/PUT body data that is not classic HTML
513form data, such as JSON, XML, etc. By default, Catalyst will parse incoming
514data of the type 'application/json' and return access to that data via this
515method. You may define addition data_handlers via a global configuration
516setting. See L<Catalyst\DATA HANDLERS> for more information.
517
b5ecfcf0 518=head2 $req->body_parameters
fbcc39ad 519
3e19f4f6 520Returns a reference to a hash containing body (POST) parameters. Values can
fbcc39ad 521be either a scalar or an arrayref containing scalars.
522
523 print $c->request->body_parameters->{field};
524 print $c->request->body_parameters->{field}->[0];
c436c1e8 525
d631b5f9 526These are the parameters from the POST part of the request, if any.
e5ecd5bc 527
b5ecfcf0 528=head2 $req->body_params
fbcc39ad 529
3e19f4f6 530Shortcut for body_parameters.
fbcc39ad 531
b5ecfcf0 532=head2 $req->content_encoding
b5176d9e 533
3e19f4f6 534Shortcut for $req->headers->content_encoding.
b5176d9e 535
b5ecfcf0 536=head2 $req->content_length
b5176d9e 537
3e19f4f6 538Shortcut for $req->headers->content_length.
b5176d9e 539
b5ecfcf0 540=head2 $req->content_type
b5176d9e 541
3e19f4f6 542Shortcut for $req->headers->content_type.
b5176d9e 543
b5ecfcf0 544=head2 $req->cookie
3ad654e0 545
3e19f4f6 546A convenient method to access $req->cookies.
3ad654e0 547
548 $cookie = $c->request->cookie('name');
549 @cookies = $c->request->cookie;
550
551=cut
552
553sub cookie {
554 my $self = shift;
555
556 if ( @_ == 0 ) {
b77e7869 557 return keys %{ $self->cookies };
3ad654e0 558 }
559
560 if ( @_ == 1 ) {
561
562 my $name = shift;
563
b77e7869 564 unless ( exists $self->cookies->{$name} ) {
3ad654e0 565 return undef;
566 }
fbcc39ad 567
b77e7869 568 return $self->cookies->{$name};
3ad654e0 569 }
570}
571
b5ecfcf0 572=head2 $req->cookies
fc7ec1d9 573
b22c6668 574Returns a reference to a hash containing the cookies.
fc7ec1d9 575
576 print $c->request->cookies->{mycookie}->value;
577
7e743798 578The cookies in the hash are indexed by name, and the values are L<CGI::Simple::Cookie>
c436c1e8 579objects.
580
b5ecfcf0 581=head2 $req->header
b5176d9e 582
3e19f4f6 583Shortcut for $req->headers->header.
b5176d9e 584
b5ecfcf0 585=head2 $req->headers
fc7ec1d9 586
3e19f4f6 587Returns an L<HTTP::Headers> object containing the headers for the current request.
fc7ec1d9 588
589 print $c->request->headers->header('X-Catalyst');
590
b5ecfcf0 591=head2 $req->hostname
0556eb49 592
178dca5f 593Returns the hostname of the client. Use C<< $req->uri->host >> to get the hostname of the server.
e5ecd5bc 594
b5ecfcf0 595=head2 $req->input
61bacdcc 596
3e19f4f6 597Alias for $req->body.
61bacdcc 598
3b4d1251 599=head2 $req->query_keywords
600
601Contains the keywords portion of a query string, when no '=' signs are
602present.
603
604 http://localhost/path?some+keywords
b0ad47c1 605
3b4d1251 606 $c->request->query_keywords will contain 'some keywords'
607
b5ecfcf0 608=head2 $req->match
fc7ec1d9 609
3e19f4f6 610This contains the matching part of a Regex action. Otherwise
2c83fd5a 611it returns the same as 'action', except for default actions,
612which return an empty string.
fc7ec1d9 613
b5ecfcf0 614=head2 $req->method
b5176d9e 615
616Contains the request method (C<GET>, C<POST>, C<HEAD>, etc).
617
b5ecfcf0 618=head2 $req->param
e7c0c583 619
b0ad47c1 620Returns GET and POST parameters with a CGI.pm-compatible param method. This
3e19f4f6 621is an alternative method for accessing parameters in $c->req->parameters.
e7c0c583 622
a82c2894 623 $value = $c->request->param( 'foo' );
624 @values = $c->request->param( 'foo' );
e7c0c583 625 @params = $c->request->param;
626
3e705254 627Like L<CGI>, and B<unlike> earlier versions of Catalyst, passing multiple
a82c2894 628arguments to this method, like this:
629
85d9fce6 630 $c->request->param( 'foo', 'bar', 'gorch', 'quxx' );
a82c2894 631
632will set the parameter C<foo> to the multiple values C<bar>, C<gorch> and
633C<quxx>. Previously this would have added C<bar> as another value to C<foo>
3e19f4f6 634(creating it if it didn't exist before), and C<quxx> as another value for
635C<gorch>.
a82c2894 636
83312afd 637B<NOTE> this is considered a legacy interface and care should be taken when
638using it. C<< scalar $c->req->param( 'foo' ) >> will return only the first
639C<foo> param even if multiple are present; C<< $c->req->param( 'foo' ) >> will
640return a list of as many are present, which can have unexpected consequences
641when writing code of the form:
642
643 $foo->bar(
644 a => 'b',
645 baz => $c->req->param( 'baz' ),
646 );
647
648If multiple C<baz> parameters are provided this code might corrupt data or
649cause a hash initialization error. For a more straightforward interface see
650C<< $c->req->parameters >>.
651
e7c0c583 652=cut
653
654sub param {
655 my $self = shift;
656
657 if ( @_ == 0 ) {
658 return keys %{ $self->parameters };
659 }
660
bfde09a2 661 if ( @_ == 1 ) {
e7c0c583 662
bfde09a2 663 my $param = shift;
6bd2b72c 664
bfde09a2 665 unless ( exists $self->parameters->{$param} ) {
666 return wantarray ? () : undef;
667 }
668
669 if ( ref $self->parameters->{$param} eq 'ARRAY' ) {
670 return (wantarray)
671 ? @{ $self->parameters->{$param} }
672 : $self->parameters->{$param}->[0];
673 }
674 else {
675 return (wantarray)
676 ? ( $self->parameters->{$param} )
677 : $self->parameters->{$param};
678 }
d7945f32 679 }
a82c2894 680 elsif ( @_ > 1 ) {
681 my $field = shift;
682 $self->parameters->{$field} = [@_];
d7945f32 683 }
e7c0c583 684}
b5176d9e 685
b5ecfcf0 686=head2 $req->parameters
61b1e958 687
3e19f4f6 688Returns a reference to a hash containing GET and POST parameters. Values can
d08ced28 689be either a scalar or an arrayref containing scalars.
fc7ec1d9 690
e7c0c583 691 print $c->request->parameters->{field};
692 print $c->request->parameters->{field}->[0];
fc7ec1d9 693
c436c1e8 694This is the combination of C<query_parameters> and C<body_parameters>.
695
b5ecfcf0 696=head2 $req->params
3e19f4f6 697
698Shortcut for $req->parameters.
699
b5ecfcf0 700=head2 $req->path
fc7ec1d9 701
3e19f4f6 702Returns the path, i.e. the part of the URI after $req->base, for the current request.
fc7ec1d9 703
be6801fa 704 http://localhost/path/foo
705
706 $c->request->path will contain 'path/foo'
707
b5ecfcf0 708=head2 $req->path_info
fbcc39ad 709
10011c19 710Alias for path, added for compatibility with L<CGI>.
fbcc39ad 711
712=cut
713
714sub path {
02fb5d78 715 my ( $self, @params ) = @_;
4f5ebacd 716
02fb5d78 717 if (@params) {
718 $self->uri->path(@params);
02570318 719 $self->_clear_path;
fbcc39ad 720 }
02570318 721 elsif ( $self->_has_path ) {
722 return $self->_path;
e561386f 723 }
02fb5d78 724 else {
725 my $path = $self->uri->path;
726 my $location = $self->base->path;
727 $path =~ s/^(\Q$location\E)?//;
728 $path =~ s/^\///;
02570318 729 $self->_path($path);
fbcc39ad 730
02fb5d78 731 return $path;
732 }
fbcc39ad 733}
734
b5ecfcf0 735=head2 $req->protocol
bfde09a2 736
3e19f4f6 737Returns the protocol (HTTP/1.0 or HTTP/1.1) used for the current request.
bfde09a2 738
b5ecfcf0 739=head2 $req->query_parameters
fbcc39ad 740
def54ce2 741=head2 $req->query_params
742
3e19f4f6 743Returns a reference to a hash containing query string (GET) parameters. Values can
fbcc39ad 744be either a scalar or an arrayref containing scalars.
745
746 print $c->request->query_parameters->{field};
747 print $c->request->query_parameters->{field}->[0];
b0ad47c1 748
b5ecfcf0 749=head2 $req->read( [$maxlength] )
fbcc39ad 750
3e19f4f6 751Reads a chunk of data from the request body. This method is intended to be
752used in a while loop, reading $maxlength bytes on every call. $maxlength
fbcc39ad 753defaults to the size of the request if not specified.
754
87f50436 755=head2 $req->read_chunk(\$buff, $max)
756
d7f18923 757Reads a chunk.
87f50436 758
9779c885 759You have to set MyApp->config(parse_on_demand => 1) to use this directly.
fbcc39ad 760
b5ecfcf0 761=head2 $req->referer
fc7ec1d9 762
3e19f4f6 763Shortcut for $req->headers->referer. Returns the referring page.
fc7ec1d9 764
b5ecfcf0 765=head2 $req->secure
bfde09a2 766
328f225e 767Returns true or false, indicating whether the connection is secure
d7f18923 768(https). The reliability of $req->secure may depend on your server
769configuration; Catalyst relies on PSGI to determine whether or not a
770request is secure (Catalyst looks at psgi.url_scheme), and different
771PSGI servers may make this determination in different ways (as by
772directly passing along information from the server, interpreting any of
773several HTTP headers, or using heuristics of their own).
bfde09a2 774
2982e768 775=head2 $req->captures
776
5c6a56e0 777Returns a reference to an array containing captured args from chained
778actions or regex captures.
fc7ec1d9 779
2982e768 780 my @captures = @{ $c->request->captures };
781
b5ecfcf0 782=head2 $req->upload
e7c0c583 783
3e19f4f6 784A convenient method to access $req->uploads.
e7c0c583 785
786 $upload = $c->request->upload('field');
787 @uploads = $c->request->upload('field');
788 @fields = $c->request->upload;
bfde09a2 789
e7c0c583 790 for my $upload ( $c->request->upload('field') ) {
146554c5 791 print $upload->filename;
e7c0c583 792 }
793
794=cut
795
796sub upload {
797 my $self = shift;
798
799 if ( @_ == 0 ) {
800 return keys %{ $self->uploads };
801 }
802
bfde09a2 803 if ( @_ == 1 ) {
e7c0c583 804
bfde09a2 805 my $upload = shift;
806
807 unless ( exists $self->uploads->{$upload} ) {
808 return wantarray ? () : undef;
809 }
6bd2b72c 810
bfde09a2 811 if ( ref $self->uploads->{$upload} eq 'ARRAY' ) {
812 return (wantarray)
813 ? @{ $self->uploads->{$upload} }
814 : $self->uploads->{$upload}->[0];
815 }
816 else {
817 return (wantarray)
fbcc39ad 818 ? ( $self->uploads->{$upload} )
819 : $self->uploads->{$upload};
bfde09a2 820 }
d7945f32 821 }
bfde09a2 822
a4f5c51e 823 if ( @_ > 1 ) {
bfde09a2 824
825 while ( my ( $field, $upload ) = splice( @_, 0, 2 ) ) {
826
827 if ( exists $self->uploads->{$field} ) {
828 for ( $self->uploads->{$field} ) {
829 $_ = [$_] unless ref($_) eq "ARRAY";
830 push( @$_, $upload );
831 }
832 }
833 else {
834 $self->uploads->{$field} = $upload;
835 }
836 }
e7c0c583 837 }
838}
839
b5ecfcf0 840=head2 $req->uploads
fc7ec1d9 841
bfde09a2 842Returns a reference to a hash containing uploads. Values can be either a
b0ad47c1 843L<Catalyst::Request::Upload> object, or an arrayref of
84e7aa89 844L<Catalyst::Request::Upload> objects.
e7c0c583 845
846 my $upload = $c->request->uploads->{field};
847 my $upload = $c->request->uploads->{field}->[0];
848
b5ecfcf0 849=head2 $req->uri
fbcc39ad 850
d26ee0d0 851Returns a L<URI> object for the current request. Stringifies to the URI text.
fbcc39ad 852
a375a206 853=head2 $req->mangle_params( { key => 'value' }, $appendmode);
bd917b94 854
a375a206 855Returns a hashref of parameters stemming from the current request's params,
856plus the ones supplied. Keys for which no current param exists will be
857added, keys with undefined values will be removed and keys with existing
858params will be replaced. Note that you can supply a true value as the final
859argument to change behavior with regards to existing parameters, appending
860values rather than replacing them.
861
862A quick example:
863
864 # URI query params foo=1
865 my $hashref = $req->mangle_params({ foo => 2 });
866 # Result is query params of foo=2
867
868versus append mode:
869
870 # URI query params foo=1
871 my $hashref = $req->mangle_params({ foo => 2 }, 1);
872 # Result is query params of foo=1&foo=2
873
874This is the code behind C<uri_with>.
bd917b94 875
876=cut
877
a375a206 878sub mangle_params {
879 my ($self, $args, $append) = @_;
b0ad47c1 880
a375a206 881 carp('No arguments passed to mangle_params()') unless $args;
fbb513f7 882
2f381252 883 foreach my $value ( values %$args ) {
d0f0fcf6 884 next unless defined $value;
fbb513f7 885 for ( ref $value eq 'ARRAY' ? @$value : $value ) {
886 $_ = "$_";
7066a4d5 887 utf8::encode( $_ ) if utf8::is_utf8($_);
fc42a730 888 }
fc42a730 889 };
b0ad47c1 890
a375a206 891 my %params = %{ $self->uri->query_form_hash };
892 foreach my $key (keys %{ $args }) {
893 my $val = $args->{$key};
894 if(defined($val)) {
895
896 if($append && exists($params{$key})) {
897
898 # This little bit of heaven handles appending a new value onto
899 # an existing one regardless if the existing value is an array
900 # or not, and regardless if the new value is an array or not
901 $params{$key} = [
902 ref($params{$key}) eq 'ARRAY' ? @{ $params{$key} } : $params{$key},
903 ref($val) eq 'ARRAY' ? @{ $val } : $val
904 ];
905
906 } else {
907 $params{$key} = $val;
908 }
909 } else {
910
911 # If the param wasn't defined then we delete it.
912 delete($params{$key});
913 }
914 }
915
916
917 return \%params;
918}
919
920=head2 $req->uri_with( { key => 'value' } );
921
922Returns a rewritten URI object for the current request. Key/value pairs
923passed in will override existing parameters. You can remove an existing
924parameter by passing in an undef value. Unmodified pairs will be
925preserved.
926
927You may also pass an optional second parameter that puts C<uri_with> into
928append mode:
929
930 $req->uri_with( { key => 'value' }, { mode => 'append' } );
9779c885 931
a375a206 932See C<mangle_params> for an explanation of this behavior.
933
934=cut
935
936sub uri_with {
937 my( $self, $args, $behavior) = @_;
938
939 carp( 'No arguments passed to uri_with()' ) unless $args;
940
941 my $append = 0;
942 if((ref($behavior) eq 'HASH') && defined($behavior->{mode}) && ($behavior->{mode} eq 'append')) {
943 $append = 1;
944 }
945
946 my $params = $self->mangle_params($args, $append);
947
948 my $uri = $self->uri->clone;
949 $uri->query_form($params);
2f381252 950
bd917b94 951 return $uri;
952}
953
8026359e 954=head2 $req->remote_user
955
956Returns the value of the C<REMOTE_USER> environment variable.
7ce7ca2e 957
b5ecfcf0 958=head2 $req->user_agent
b5176d9e 959
3e19f4f6 960Shortcut to $req->headers->user_agent. Returns the user agent (browser)
961version string.
b5176d9e 962
eb1f4b49 963=head2 $req->io_fh
964
965Returns a psgix.io bidirectional socket, if your server supports one. Used for
966when you want to jailbreak out of PSGI and handle bidirectional client server
967communication manually, such as when you are using cometd or websockets.
968
47b9d68e 969=head1 SETUP METHODS
970
971You should never need to call these yourself in application code,
972however they are useful if extending Catalyst by applying a request role.
973
974=head2 $self->prepare_headers()
975
976Sets up the C<< $res->headers >> accessor.
977
978=head2 $self->prepare_body()
979
980Sets up the body using L<HTTP::Body>
981
982=head2 $self->prepare_body_chunk()
983
984Add a chunk to the request body.
985
986=head2 $self->prepare_body_parameters()
987
988Sets up parameters from body.
989
8738b8fe 990=head2 $self->prepare_cookies()
47b9d68e 991
992Parse cookies from header. Sets up a L<CGI::Simple::Cookie> object.
993
8738b8fe 994=head2 $self->prepare_connection()
995
996Sets up various fields in the request like the local and remote addresses,
f59eeb09 997request method, hostname requested etc.
8738b8fe 998
999=head2 $self->prepare_parameters()
1000
1001Ensures that the body has been parsed, then builds the parameters, which are
1002combined from those in the request and those in the body.
1003
11e7af55 1004If parameters have already been set will clear the parameters and build them again.
1005
8738b8fe 1006
059c085b 1007=head2 meta
1008
1009Provided by Moose
1010
3e19f4f6 1011=head1 AUTHORS
fc7ec1d9 1012
2f381252 1013Catalyst Contributors, see Catalyst.pm
fc7ec1d9 1014
1015=head1 COPYRIGHT
1016
536bee89 1017This library is free software. You can redistribute it and/or modify
61b1e958 1018it under the same terms as Perl itself.
fc7ec1d9 1019
1020=cut
1021
e5ecd5bc 1022__PACKAGE__->meta->make_immutable;
1023
fc7ec1d9 10241;