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