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