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