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