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