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