Doc fixes / additions in Catalyst::Component
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Request.pm
CommitLineData
fc7ec1d9 1package Catalyst::Request;
2
b4ca0ee8 3use IO::Socket qw[AF_INET inet_aton];
bd917b94 4use Carp;
fc42a730 5use utf8;
de19de2e 6use URI::http;
7use URI::https;
e669e88a 8use URI::QueryParam;
6680c772 9use HTTP::Headers;
b4ca0ee8 10
059c085b 11use Moose;
12
6802c884 13use namespace::clean -except => 'meta';
14
b99ff5d8 15with 'MooseX::Emulate::Class::Accessor::Fast';
16
faa02805 17has env => (is => 'ro', writer => '_set_env');
47b9d68e 18# XXX Deprecated crap here - warn?
19has action => (is => 'rw');
20# XXX: Deprecated in docs ages ago (2006), deprecated with warning in 5.8000 due
21# to confusion between Engines and Plugin::Authentication. Remove in 5.8100?
22has user => (is => 'rw');
23sub snippets { shift->captures(@_) }
faa02805 24
47b9d68e 25has _read_position => (
26 init_arg => undef,
27 is => 'ro',
28 writer => '_set_read_position',
29 default => 0,
30);
31has _read_length => (
32 init_arg => undef,
33 is => 'ro',
faa02805 34 default => sub {
35 my $self = shift;
36 $self->header('Content-Length') || 0;
37 },
38 lazy => 1,
39);
40
5fb12dbb 41has address => (is => 'rw');
42has arguments => (is => 'rw', default => sub { [] });
d5f4b434 43has cookies => (is => 'ro', builder => 'prepare_cookies', lazy => 1);
44
d5f4b434 45sub prepare_cookies {
46 my ( $self ) = @_;
47
48 if ( my $header = $self->header('Cookie') ) {
49 return { CGI::Simple::Cookie->parse($header) };
50 }
51 {};
52}
53
5fb12dbb 54has query_keywords => (is => 'rw');
55has match => (is => 'rw');
56has method => (is => 'rw');
57has protocol => (is => 'rw');
059c085b 58has query_parameters => (is => 'rw', default => sub { {} });
5fb12dbb 59has secure => (is => 'rw', default => 0);
60has captures => (is => 'rw', default => sub { [] });
6cb9e383 61has uri => (is => 'rw', predicate => 'has_uri');
8026359e 62has remote_user => (is => 'rw');
5fb12dbb 63has headers => (
e5ecd5bc 64 is => 'rw',
059c085b 65 isa => 'HTTP::Headers',
66 handles => [qw(content_encoding content_length content_type header referer user_agent)],
d5f4b434 67 builder => 'prepare_headers',
6680c772 68 lazy => 1,
059c085b 69);
70
d5f4b434 71sub prepare_headers {
72 my ($self) = @_;
73
74 my $env = $self->env;
75 my $headers = HTTP::Headers->new();
76
77 for my $header (keys %{ $env }) {
78 next unless $header =~ /^(HTTP|CONTENT|COOKIE)/i;
79 (my $field = $header) =~ s/^HTTPS?_//;
80 $field =~ tr/_/-/;
81 $headers->header($field => $env->{$header});
82 }
83 return $headers;
84}
85
7c1c4dc6 86has _log => (
87 is => 'ro',
88 weak_ref => 1,
89 required => 1,
059c085b 90);
91
f083854e 92# Amount of data to read from input on each pass
93our $CHUNKSIZE = 64 * 1024;
94
95sub read {
96 my ($self, $maxlength) = @_;
97 my $remaining = $self->_read_length - $self->_read_position;
98 $maxlength ||= $CHUNKSIZE;
99
100 # Are we done reading?
101 if ( $remaining <= 0 ) {
102 return;
103 }
104
105 my $readlen = ( $remaining > $maxlength ) ? $maxlength : $remaining;
106 my $rc = $self->read_chunk( my $buffer, $readlen );
107 if ( defined $rc ) {
108 if (0 == $rc) { # Nothing more to read even though Content-Length
109 # said there should be.
110 return;
111 }
47b9d68e 112 $self->_set_read_position( $self->_read_position + $rc );
f083854e 113 return $buffer;
114 }
115 else {
116 Catalyst::Exception->throw(
117 message => "Unknown error reading input: $!" );
118 }
119}
120
87f50436 121sub read_chunk {
122 my $self = shift;
123 return $self->env->{'psgi.input'}->read(@_);
124}
125
059c085b 126has body_parameters => (
5fb12dbb 127 is => 'rw',
128 required => 1,
129 lazy => 1,
130 default => sub { {} },
fc7ec1d9 131);
132
059c085b 133has uploads => (
5fb12dbb 134 is => 'rw',
135 required => 1,
5fb12dbb 136 default => sub { {} },
059c085b 137);
138
059c085b 139has parameters => (
1cbdfa9b 140 is => 'rw',
141 lazy => 1,
142 builder => 'prepare_parameters',
059c085b 143);
144
341620d5 145# TODO:
146# - Can we lose the before modifiers which just call prepare_body ?
147# they are wasteful, slow us down and feel cluttery.
148
149# Can we make _body an attribute, have the rest of
150# these lazy build from there and kill all the direct hash access
151# in Catalyst.pm and Engine.pm?
152
1cbdfa9b 153sub prepare_parameters {
154 my ( $self ) = @_;
155
398f13db 156 $self->prepare_body;
1cbdfa9b 157 my $parameters = {};
158 my $body_parameters = $self->body_parameters;
159 my $query_parameters = $self->query_parameters;
160 # We copy, no references
161 foreach my $name (keys %$query_parameters) {
162 my $param = $query_parameters->{$name};
163 $parameters->{$name} = ref $param eq 'ARRAY' ? [ @$param ] : $param;
164 }
165
166 # Merge query and body parameters
167 foreach my $name (keys %$body_parameters) {
168 my $param = $body_parameters->{$name};
169 my @values = ref $param eq 'ARRAY' ? @$param : ($param);
170 if ( my $existing = $parameters->{$name} ) {
171 unshift(@values, (ref $existing eq 'ARRAY' ? @$existing : $existing));
172 }
173 $parameters->{$name} = @values > 1 ? \@values : $values[0];
174 }
175 $parameters;
176}
177
398f13db 178before body_parameters => sub {
179 my ($self) = @_;
180 $self->prepare_body;
181 $self->prepare_body_parameters;
182};
183
398f13db 184has _uploadtmp => (
185 is => 'ro',
186 predicate => '_has_uploadtmp',
187);
188
189sub prepare_body {
190 my ( $self ) = @_;
191
192 if ( my $length = $self->_read_length ) {
193 unless ( $self->_body ) {
194 my $type = $self->header('Content-Type');
195 $self->_body(HTTP::Body->new( $type, $length ));
196 $self->_body->cleanup(1); # Make extra sure!
197 $self->_body->tmpdir( $self->_uploadtmp )
198 if $self->_has_uploadtmp;
199 }
200
201 # Check for definedness as you could read '0'
202 while ( defined ( my $buffer = $self->read() ) ) {
203 $self->prepare_body_chunk($buffer);
204 }
205
206 # paranoia against wrong Content-Length header
207 my $remaining = $length - $self->_read_position;
208 if ( $remaining > 0 ) {
209 Catalyst::Exception->throw(
210 "Wrong Content-Length value: $length" );
211 }
212 }
213 else {
214 # Defined but will cause all body code to be skipped
215 $self->_body(0);
216 }
217}
218
398f13db 219sub prepare_body_chunk {
220 my ( $self, $chunk ) = @_;
221
222 $self->_body->add($chunk);
223}
224
398f13db 225sub prepare_body_parameters {
226 my ( $self ) = @_;
227
228 return unless $self->_body;
229
230 $self->{body_parameters} = $self->_body->param; # FIXME!! Recursion here.
231}
341620d5 232
2f498a7e 233sub prepare_connection {
234 my ($self) = @_;
235
236 my $env = $self->env;
237
238 $self->address( $env->{REMOTE_ADDR} );
239 $self->hostname( $env->{REMOTE_HOST} )
240 if exists $env->{REMOTE_HOST};
241 $self->protocol( $env->{SERVER_PROTOCOL} );
242 $self->remote_user( $env->{REMOTE_USER} );
243 $self->method( $env->{REQUEST_METHOD} );
244 $self->secure( $env->{'psgi.url_scheme'} eq 'https' ? 1 : 0 );
245}
246
247# XXX - FIXME - method is here now, move this crap...
e99ec2dc 248around parameters => sub {
249 my ($orig, $self, $params) = @_;
250 if ($params) {
251 if ( !ref $params ) {
7c1c4dc6 252 $self->_log->warn(
e99ec2dc 253 "Attempt to retrieve '$params' with req->params(), " .
254 "you probably meant to call req->param('$params')"
255 );
256 $params = undef;
257 }
258 return $self->$orig($params);
259 }
260 $self->$orig();
059c085b 261};
262
263has base => (
5fb12dbb 264 is => 'rw',
265 required => 1,
266 lazy => 1,
267 default => sub {
059c085b 268 my $self = shift;
6cb9e383 269 return $self->path if $self->has_uri;
059c085b 270 },
271);
272
069355da 273has _body => (
0f56bbcf 274 is => 'rw', clearer => '_clear_body', predicate => '_has_body',
059c085b 275);
610bc6ec 276# Eugh, ugly. Should just be able to rename accessor methods to 'body'
b0ad47c1 277# and provide a custom reader..
610bc6ec 278sub body {
279 my $self = shift;
398f13db 280 $self->prepare_body();
14c057aa 281 croak 'body is a reader' if scalar @_;
610bc6ec 282 return blessed $self->_body ? $self->_body->body : $self->_body;
283}
059c085b 284
285has hostname => (
286 is => 'rw',
287 required => 1,
288 lazy => 1,
289 default => sub {
290 my ($self) = @_;
9fb936e5 291 gethostbyaddr( inet_aton( $self->address ), AF_INET ) || $self->address
059c085b 292 },
293);
294
02570318 295has _path => ( is => 'rw', predicate => '_has_path', clearer => '_clear_path' );
296
059c085b 297sub args { shift->arguments(@_) }
298sub body_params { shift->body_parameters(@_) }
299sub input { shift->body(@_) }
300sub params { shift->parameters(@_) }
301sub query_params { shift->query_parameters(@_) }
302sub path_info { shift->path(@_) }
f7e4e231 303
8738b8fe 304=for stopwords param params
965f3e35 305
fc7ec1d9 306=head1 NAME
307
3e19f4f6 308Catalyst::Request - provides information about the current client request
fc7ec1d9 309
310=head1 SYNOPSIS
311
b22c6668 312 $req = $c->request;
767480fd 313 $req->address eq "127.0.0.1";
b22c6668 314 $req->arguments;
3e19f4f6 315 $req->args;
b22c6668 316 $req->base;
06e1b616 317 $req->body;
fbcc39ad 318 $req->body_parameters;
b5176d9e 319 $req->content_encoding;
320 $req->content_length;
321 $req->content_type;
b77e7869 322 $req->cookie;
b22c6668 323 $req->cookies;
b5176d9e 324 $req->header;
b22c6668 325 $req->headers;
326 $req->hostname;
61bacdcc 327 $req->input;
3b4d1251 328 $req->query_keywords;
b22c6668 329 $req->match;
330 $req->method;
e7c0c583 331 $req->param;
e7c0c583 332 $req->parameters;
3e19f4f6 333 $req->params;
b22c6668 334 $req->path;
bfde09a2 335 $req->protocol;
fbcc39ad 336 $req->query_parameters;
337 $req->read;
b5176d9e 338 $req->referer;
bfde09a2 339 $req->secure;
47b9d68e 340 $req->captures;
e7c0c583 341 $req->upload;
b22c6668 342 $req->uploads;
77d12cae 343 $req->uri;
7ce7ca2e 344 $req->user;
66294129 345 $req->user_agent;
b22c6668 346
3e22baa5 347See also L<Catalyst>, L<Catalyst::Request::Upload>.
fc7ec1d9 348
349=head1 DESCRIPTION
350
3e19f4f6 351This is the Catalyst Request class, which provides an interface to data for the
352current client request. The request object is prepared by L<Catalyst::Engine>,
353thus hiding the details of the particular engine implementation.
b22c6668 354
355=head1 METHODS
fc7ec1d9 356
b5ecfcf0 357=head2 $req->address
0556eb49 358
3e19f4f6 359Returns the IP address of the client.
61b1e958 360
b5ecfcf0 361=head2 $req->arguments
61b1e958 362
b22c6668 363Returns a reference to an array containing the arguments.
fc7ec1d9 364
365 print $c->request->arguments->[0];
366
c436c1e8 367For example, if your action was
368
7d7519a4 369 package MyApp::Controller::Foo;
85d9fce6 370
371 sub moose : Local {
372 ...
373 }
c436c1e8 374
3e19f4f6 375and the URI for the request was C<http://.../foo/moose/bah>, the string C<bah>
c436c1e8 376would be the first and only argument.
377
6d920953 378Arguments get automatically URI-unescaped for you.
8f58057d 379
b5ecfcf0 380=head2 $req->args
3e19f4f6 381
01011731 382Shortcut for L</arguments>.
3e19f4f6 383
b5ecfcf0 384=head2 $req->base
fc7ec1d9 385
328f225e 386Contains the URI base. This will always have a trailing slash. Note that the
f4dda4a8 387URI scheme (e.g., http vs. https) must be determined through heuristics;
328f225e 388depending on your server configuration, it may be incorrect. See $req->secure
389for more info.
c436c1e8 390
3e19f4f6 391If your application was queried with the URI
392C<http://localhost:3000/some/path> then C<base> is C<http://localhost:3000/>.
fc7ec1d9 393
b5ecfcf0 394=head2 $req->body
06e1b616 395
843871cf 396Returns the message body of the request, as returned by L<HTTP::Body>: a string,
397unless Content-Type is C<application/x-www-form-urlencoded>, C<text/xml>, or
398C<multipart/form-data>, in which case a L<File::Temp> object is returned.
e060fe05 399
b5ecfcf0 400=head2 $req->body_parameters
fbcc39ad 401
3e19f4f6 402Returns a reference to a hash containing body (POST) parameters. Values can
fbcc39ad 403be either a scalar or an arrayref containing scalars.
404
405 print $c->request->body_parameters->{field};
406 print $c->request->body_parameters->{field}->[0];
c436c1e8 407
d631b5f9 408These are the parameters from the POST part of the request, if any.
e5ecd5bc 409
b5ecfcf0 410=head2 $req->body_params
fbcc39ad 411
3e19f4f6 412Shortcut for body_parameters.
fbcc39ad 413
b5ecfcf0 414=head2 $req->content_encoding
b5176d9e 415
3e19f4f6 416Shortcut for $req->headers->content_encoding.
b5176d9e 417
b5ecfcf0 418=head2 $req->content_length
b5176d9e 419
3e19f4f6 420Shortcut for $req->headers->content_length.
b5176d9e 421
b5ecfcf0 422=head2 $req->content_type
b5176d9e 423
3e19f4f6 424Shortcut for $req->headers->content_type.
b5176d9e 425
b5ecfcf0 426=head2 $req->cookie
3ad654e0 427
3e19f4f6 428A convenient method to access $req->cookies.
3ad654e0 429
430 $cookie = $c->request->cookie('name');
431 @cookies = $c->request->cookie;
432
433=cut
434
435sub cookie {
436 my $self = shift;
437
438 if ( @_ == 0 ) {
b77e7869 439 return keys %{ $self->cookies };
3ad654e0 440 }
441
442 if ( @_ == 1 ) {
443
444 my $name = shift;
445
b77e7869 446 unless ( exists $self->cookies->{$name} ) {
3ad654e0 447 return undef;
448 }
fbcc39ad 449
b77e7869 450 return $self->cookies->{$name};
3ad654e0 451 }
452}
453
b5ecfcf0 454=head2 $req->cookies
fc7ec1d9 455
b22c6668 456Returns a reference to a hash containing the cookies.
fc7ec1d9 457
458 print $c->request->cookies->{mycookie}->value;
459
7e743798 460The cookies in the hash are indexed by name, and the values are L<CGI::Simple::Cookie>
c436c1e8 461objects.
462
b5ecfcf0 463=head2 $req->header
b5176d9e 464
3e19f4f6 465Shortcut for $req->headers->header.
b5176d9e 466
b5ecfcf0 467=head2 $req->headers
fc7ec1d9 468
3e19f4f6 469Returns an L<HTTP::Headers> object containing the headers for the current request.
fc7ec1d9 470
471 print $c->request->headers->header('X-Catalyst');
472
b5ecfcf0 473=head2 $req->hostname
0556eb49 474
178dca5f 475Returns the hostname of the client. Use C<< $req->uri->host >> to get the hostname of the server.
e5ecd5bc 476
b5ecfcf0 477=head2 $req->input
61bacdcc 478
3e19f4f6 479Alias for $req->body.
61bacdcc 480
3b4d1251 481=head2 $req->query_keywords
482
483Contains the keywords portion of a query string, when no '=' signs are
484present.
485
486 http://localhost/path?some+keywords
b0ad47c1 487
3b4d1251 488 $c->request->query_keywords will contain 'some keywords'
489
b5ecfcf0 490=head2 $req->match
fc7ec1d9 491
3e19f4f6 492This contains the matching part of a Regex action. Otherwise
2c83fd5a 493it returns the same as 'action', except for default actions,
494which return an empty string.
fc7ec1d9 495
b5ecfcf0 496=head2 $req->method
b5176d9e 497
498Contains the request method (C<GET>, C<POST>, C<HEAD>, etc).
499
b5ecfcf0 500=head2 $req->param
e7c0c583 501
b0ad47c1 502Returns GET and POST parameters with a CGI.pm-compatible param method. This
3e19f4f6 503is an alternative method for accessing parameters in $c->req->parameters.
e7c0c583 504
a82c2894 505 $value = $c->request->param( 'foo' );
506 @values = $c->request->param( 'foo' );
e7c0c583 507 @params = $c->request->param;
508
3e705254 509Like L<CGI>, and B<unlike> earlier versions of Catalyst, passing multiple
a82c2894 510arguments to this method, like this:
511
85d9fce6 512 $c->request->param( 'foo', 'bar', 'gorch', 'quxx' );
a82c2894 513
514will set the parameter C<foo> to the multiple values C<bar>, C<gorch> and
515C<quxx>. Previously this would have added C<bar> as another value to C<foo>
3e19f4f6 516(creating it if it didn't exist before), and C<quxx> as another value for
517C<gorch>.
a82c2894 518
83312afd 519B<NOTE> this is considered a legacy interface and care should be taken when
520using it. C<< scalar $c->req->param( 'foo' ) >> will return only the first
521C<foo> param even if multiple are present; C<< $c->req->param( 'foo' ) >> will
522return a list of as many are present, which can have unexpected consequences
523when writing code of the form:
524
525 $foo->bar(
526 a => 'b',
527 baz => $c->req->param( 'baz' ),
528 );
529
530If multiple C<baz> parameters are provided this code might corrupt data or
531cause a hash initialization error. For a more straightforward interface see
532C<< $c->req->parameters >>.
533
e7c0c583 534=cut
535
536sub param {
537 my $self = shift;
538
539 if ( @_ == 0 ) {
540 return keys %{ $self->parameters };
541 }
542
bfde09a2 543 if ( @_ == 1 ) {
e7c0c583 544
bfde09a2 545 my $param = shift;
6bd2b72c 546
bfde09a2 547 unless ( exists $self->parameters->{$param} ) {
548 return wantarray ? () : undef;
549 }
550
551 if ( ref $self->parameters->{$param} eq 'ARRAY' ) {
552 return (wantarray)
553 ? @{ $self->parameters->{$param} }
554 : $self->parameters->{$param}->[0];
555 }
556 else {
557 return (wantarray)
558 ? ( $self->parameters->{$param} )
559 : $self->parameters->{$param};
560 }
d7945f32 561 }
a82c2894 562 elsif ( @_ > 1 ) {
563 my $field = shift;
564 $self->parameters->{$field} = [@_];
d7945f32 565 }
e7c0c583 566}
b5176d9e 567
b5ecfcf0 568=head2 $req->parameters
61b1e958 569
3e19f4f6 570Returns a reference to a hash containing GET and POST parameters. Values can
d08ced28 571be either a scalar or an arrayref containing scalars.
fc7ec1d9 572
e7c0c583 573 print $c->request->parameters->{field};
574 print $c->request->parameters->{field}->[0];
fc7ec1d9 575
c436c1e8 576This is the combination of C<query_parameters> and C<body_parameters>.
577
b5ecfcf0 578=head2 $req->params
3e19f4f6 579
580Shortcut for $req->parameters.
581
b5ecfcf0 582=head2 $req->path
fc7ec1d9 583
3e19f4f6 584Returns the path, i.e. the part of the URI after $req->base, for the current request.
fc7ec1d9 585
be6801fa 586 http://localhost/path/foo
587
588 $c->request->path will contain 'path/foo'
589
b5ecfcf0 590=head2 $req->path_info
fbcc39ad 591
10011c19 592Alias for path, added for compatibility with L<CGI>.
fbcc39ad 593
594=cut
595
596sub path {
02fb5d78 597 my ( $self, @params ) = @_;
4f5ebacd 598
02fb5d78 599 if (@params) {
600 $self->uri->path(@params);
02570318 601 $self->_clear_path;
fbcc39ad 602 }
02570318 603 elsif ( $self->_has_path ) {
604 return $self->_path;
e561386f 605 }
02fb5d78 606 else {
607 my $path = $self->uri->path;
608 my $location = $self->base->path;
609 $path =~ s/^(\Q$location\E)?//;
610 $path =~ s/^\///;
02570318 611 $self->_path($path);
fbcc39ad 612
02fb5d78 613 return $path;
614 }
fbcc39ad 615}
616
b5ecfcf0 617=head2 $req->protocol
bfde09a2 618
3e19f4f6 619Returns the protocol (HTTP/1.0 or HTTP/1.1) used for the current request.
bfde09a2 620
b5ecfcf0 621=head2 $req->query_parameters
fbcc39ad 622
def54ce2 623=head2 $req->query_params
624
3e19f4f6 625Returns a reference to a hash containing query string (GET) parameters. Values can
fbcc39ad 626be either a scalar or an arrayref containing scalars.
627
628 print $c->request->query_parameters->{field};
629 print $c->request->query_parameters->{field}->[0];
b0ad47c1 630
b5ecfcf0 631=head2 $req->read( [$maxlength] )
fbcc39ad 632
3e19f4f6 633Reads a chunk of data from the request body. This method is intended to be
634used in a while loop, reading $maxlength bytes on every call. $maxlength
fbcc39ad 635defaults to the size of the request if not specified.
636
87f50436 637=head2 $req->read_chunk(\$buff, $max)
638
639Reads a chunk..
640
9779c885 641You have to set MyApp->config(parse_on_demand => 1) to use this directly.
fbcc39ad 642
b5ecfcf0 643=head2 $req->referer
fc7ec1d9 644
3e19f4f6 645Shortcut for $req->headers->referer. Returns the referring page.
fc7ec1d9 646
b5ecfcf0 647=head2 $req->secure
bfde09a2 648
328f225e 649Returns true or false, indicating whether the connection is secure
f4dda4a8 650(https). Note that the URI scheme (e.g., http vs. https) must be determined
ae7da8f5 651through heuristics, and therefore the reliability of $req->secure will depend
328f225e 652on your server configuration. If you are serving secure pages on the standard
653SSL port (443) and/or setting the HTTPS environment variable, $req->secure
654should be valid.
bfde09a2 655
2982e768 656=head2 $req->captures
657
5c6a56e0 658Returns a reference to an array containing captured args from chained
659actions or regex captures.
fc7ec1d9 660
2982e768 661 my @captures = @{ $c->request->captures };
662
b5ecfcf0 663=head2 $req->upload
e7c0c583 664
3e19f4f6 665A convenient method to access $req->uploads.
e7c0c583 666
667 $upload = $c->request->upload('field');
668 @uploads = $c->request->upload('field');
669 @fields = $c->request->upload;
bfde09a2 670
e7c0c583 671 for my $upload ( $c->request->upload('field') ) {
146554c5 672 print $upload->filename;
e7c0c583 673 }
674
675=cut
676
677sub upload {
678 my $self = shift;
679
680 if ( @_ == 0 ) {
681 return keys %{ $self->uploads };
682 }
683
bfde09a2 684 if ( @_ == 1 ) {
e7c0c583 685
bfde09a2 686 my $upload = shift;
687
688 unless ( exists $self->uploads->{$upload} ) {
689 return wantarray ? () : undef;
690 }
6bd2b72c 691
bfde09a2 692 if ( ref $self->uploads->{$upload} eq 'ARRAY' ) {
693 return (wantarray)
694 ? @{ $self->uploads->{$upload} }
695 : $self->uploads->{$upload}->[0];
696 }
697 else {
698 return (wantarray)
fbcc39ad 699 ? ( $self->uploads->{$upload} )
700 : $self->uploads->{$upload};
bfde09a2 701 }
d7945f32 702 }
bfde09a2 703
a4f5c51e 704 if ( @_ > 1 ) {
bfde09a2 705
706 while ( my ( $field, $upload ) = splice( @_, 0, 2 ) ) {
707
708 if ( exists $self->uploads->{$field} ) {
709 for ( $self->uploads->{$field} ) {
710 $_ = [$_] unless ref($_) eq "ARRAY";
711 push( @$_, $upload );
712 }
713 }
714 else {
715 $self->uploads->{$field} = $upload;
716 }
717 }
e7c0c583 718 }
719}
720
b5ecfcf0 721=head2 $req->uploads
fc7ec1d9 722
bfde09a2 723Returns a reference to a hash containing uploads. Values can be either a
b0ad47c1 724L<Catalyst::Request::Upload> object, or an arrayref of
84e7aa89 725L<Catalyst::Request::Upload> objects.
e7c0c583 726
727 my $upload = $c->request->uploads->{field};
728 my $upload = $c->request->uploads->{field}->[0];
729
b5ecfcf0 730=head2 $req->uri
fbcc39ad 731
d26ee0d0 732Returns a L<URI> object for the current request. Stringifies to the URI text.
fbcc39ad 733
a375a206 734=head2 $req->mangle_params( { key => 'value' }, $appendmode);
bd917b94 735
a375a206 736Returns a hashref of parameters stemming from the current request's params,
737plus the ones supplied. Keys for which no current param exists will be
738added, keys with undefined values will be removed and keys with existing
739params will be replaced. Note that you can supply a true value as the final
740argument to change behavior with regards to existing parameters, appending
741values rather than replacing them.
742
743A quick example:
744
745 # URI query params foo=1
746 my $hashref = $req->mangle_params({ foo => 2 });
747 # Result is query params of foo=2
748
749versus append mode:
750
751 # URI query params foo=1
752 my $hashref = $req->mangle_params({ foo => 2 }, 1);
753 # Result is query params of foo=1&foo=2
754
755This is the code behind C<uri_with>.
bd917b94 756
757=cut
758
a375a206 759sub mangle_params {
760 my ($self, $args, $append) = @_;
b0ad47c1 761
a375a206 762 carp('No arguments passed to mangle_params()') unless $args;
fbb513f7 763
2f381252 764 foreach my $value ( values %$args ) {
d0f0fcf6 765 next unless defined $value;
fbb513f7 766 for ( ref $value eq 'ARRAY' ? @$value : $value ) {
767 $_ = "$_";
7066a4d5 768 utf8::encode( $_ ) if utf8::is_utf8($_);
fc42a730 769 }
fc42a730 770 };
b0ad47c1 771
a375a206 772 my %params = %{ $self->uri->query_form_hash };
773 foreach my $key (keys %{ $args }) {
774 my $val = $args->{$key};
775 if(defined($val)) {
776
777 if($append && exists($params{$key})) {
778
779 # This little bit of heaven handles appending a new value onto
780 # an existing one regardless if the existing value is an array
781 # or not, and regardless if the new value is an array or not
782 $params{$key} = [
783 ref($params{$key}) eq 'ARRAY' ? @{ $params{$key} } : $params{$key},
784 ref($val) eq 'ARRAY' ? @{ $val } : $val
785 ];
786
787 } else {
788 $params{$key} = $val;
789 }
790 } else {
791
792 # If the param wasn't defined then we delete it.
793 delete($params{$key});
794 }
795 }
796
797
798 return \%params;
799}
800
801=head2 $req->uri_with( { key => 'value' } );
802
803Returns a rewritten URI object for the current request. Key/value pairs
804passed in will override existing parameters. You can remove an existing
805parameter by passing in an undef value. Unmodified pairs will be
806preserved.
807
808You may also pass an optional second parameter that puts C<uri_with> into
809append mode:
810
811 $req->uri_with( { key => 'value' }, { mode => 'append' } );
9779c885 812
a375a206 813See C<mangle_params> for an explanation of this behavior.
814
815=cut
816
817sub uri_with {
818 my( $self, $args, $behavior) = @_;
819
820 carp( 'No arguments passed to uri_with()' ) unless $args;
821
822 my $append = 0;
823 if((ref($behavior) eq 'HASH') && defined($behavior->{mode}) && ($behavior->{mode} eq 'append')) {
824 $append = 1;
825 }
826
827 my $params = $self->mangle_params($args, $append);
828
829 my $uri = $self->uri->clone;
830 $uri->query_form($params);
2f381252 831
bd917b94 832 return $uri;
833}
834
8026359e 835=head2 $req->remote_user
836
837Returns the value of the C<REMOTE_USER> environment variable.
7ce7ca2e 838
b5ecfcf0 839=head2 $req->user_agent
b5176d9e 840
3e19f4f6 841Shortcut to $req->headers->user_agent. Returns the user agent (browser)
842version string.
b5176d9e 843
47b9d68e 844=head1 SETUP METHODS
845
846You should never need to call these yourself in application code,
847however they are useful if extending Catalyst by applying a request role.
848
849=head2 $self->prepare_headers()
850
851Sets up the C<< $res->headers >> accessor.
852
853=head2 $self->prepare_body()
854
855Sets up the body using L<HTTP::Body>
856
857=head2 $self->prepare_body_chunk()
858
859Add a chunk to the request body.
860
861=head2 $self->prepare_body_parameters()
862
863Sets up parameters from body.
864
8738b8fe 865=head2 $self->prepare_cookies()
47b9d68e 866
867Parse cookies from header. Sets up a L<CGI::Simple::Cookie> object.
868
8738b8fe 869=head2 $self->prepare_connection()
870
871Sets up various fields in the request like the local and remote addresses,
f59eeb09 872request method, hostname requested etc.
8738b8fe 873
874=head2 $self->prepare_parameters()
875
876Ensures that the body has been parsed, then builds the parameters, which are
877combined from those in the request and those in the body.
878
879This method is the builder for the 'parameters' attribute.
880
059c085b 881=head2 meta
882
883Provided by Moose
884
3e19f4f6 885=head1 AUTHORS
fc7ec1d9 886
2f381252 887Catalyst Contributors, see Catalyst.pm
fc7ec1d9 888
889=head1 COPYRIGHT
890
536bee89 891This library is free software. You can redistribute it and/or modify
61b1e958 892it under the same terms as Perl itself.
fc7ec1d9 893
894=cut
895
e5ecd5bc 896__PACKAGE__->meta->make_immutable;
897
fc7ec1d9 8981;