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