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