Refreshing branch
[catagits/Catalyst-Runtime.git] / trunk / lib / Catalyst / Request.pm
CommitLineData
ceae39c5 1package Catalyst::Request;
2
3use IO::Socket qw[AF_INET inet_aton];
4use Carp;
5use utf8;
6use URI::http;
7use URI::https;
8use URI::QueryParam;
9use HTTP::Headers;
10
11use Moose;
12
13use namespace::clean -except => 'meta';
14
15with 'MooseX::Emulate::Class::Accessor::Fast';
16
17has action => (is => 'rw');
18has address => (is => 'rw');
19has arguments => (is => 'rw', default => sub { [] });
20has cookies => (is => 'rw', default => sub { {} });
21has query_keywords => (is => 'rw');
22has match => (is => 'rw');
23has method => (is => 'rw');
24has protocol => (is => 'rw');
25has query_parameters => (is => 'rw', default => sub { {} });
26has secure => (is => 'rw', default => 0);
27has captures => (is => 'rw', default => sub { [] });
28has uri => (is => 'rw', predicate => 'has_uri');
29has remote_user => (is => 'rw');
30has headers => (
31 is => 'rw',
32 isa => 'HTTP::Headers',
33 handles => [qw(content_encoding content_length content_type header referer user_agent)],
34 default => sub { HTTP::Headers->new() },
35 required => 1,
36 lazy => 1,
37);
38
39has _context => (
40 is => 'rw',
41 weak_ref => 1,
42 handles => ['read'],
43 clearer => '_clear_context',
44);
45
46has body_parameters => (
47 is => 'rw',
48 required => 1,
49 lazy => 1,
50 default => sub { {} },
51);
52
53has uploads => (
54 is => 'rw',
55 required => 1,
56 default => sub { {} },
57);
58
59has parameters => (
60 is => 'rw',
61 required => 1,
62 lazy => 1,
63 default => sub { {} },
64);
65
66# TODO:
67# - Can we lose the before modifiers which just call prepare_body ?
68# they are wasteful, slow us down and feel cluttery.
69
70# Can we make _body an attribute, have the rest of
71# these lazy build from there and kill all the direct hash access
72# in Catalyst.pm and Engine.pm?
73
74before $_ => sub {
75 my ($self) = @_;
76 my $context = $self->_context || return;
77 $context->prepare_body;
78} for qw/parameters body_parameters/;
79
80around parameters => sub {
81 my ($orig, $self, $params) = @_;
82 if ($params) {
83 if ( !ref $params ) {
84 $self->_context->log->warn(
85 "Attempt to retrieve '$params' with req->params(), " .
86 "you probably meant to call req->param('$params')"
87 );
88 $params = undef;
89 }
90 return $self->$orig($params);
91 }
92 $self->$orig();
93};
94
95has base => (
96 is => 'rw',
97 required => 1,
98 lazy => 1,
99 default => sub {
100 my $self = shift;
101 return $self->path if $self->has_uri;
102 },
103);
104
105has _body => (
106 is => 'rw', clearer => '_clear_body', predicate => '_has_body',
107);
108# Eugh, ugly. Should just be able to rename accessor methods to 'body'
109# and provide a custom reader..
110sub body {
111 my $self = shift;
112 $self->_context->prepare_body();
113 croak 'body is a reader' if scalar @_;
114 return blessed $self->_body ? $self->_body->body : $self->_body;
115}
116
117has hostname => (
118 is => 'rw',
119 required => 1,
120 lazy => 1,
121 default => sub {
122 my ($self) = @_;
123 gethostbyaddr( inet_aton( $self->address ), AF_INET ) || 'localhost'
124 },
125);
126
127has _path => ( is => 'rw', predicate => '_has_path', clearer => '_clear_path' );
128
129# XXX: Deprecated in docs ages ago (2006), deprecated with warning in 5.8000 due
130# to confusion between Engines and Plugin::Authentication. Remove in 5.8100?
131has user => (is => 'rw');
132
133sub args { shift->arguments(@_) }
134sub body_params { shift->body_parameters(@_) }
135sub input { shift->body(@_) }
136sub params { shift->parameters(@_) }
137sub query_params { shift->query_parameters(@_) }
138sub path_info { shift->path(@_) }
139sub snippets { shift->captures(@_) }
140
141=head1 NAME
142
143Catalyst::Request - provides information about the current client request
144
145=head1 SYNOPSIS
146
147 $req = $c->request;
148 $req->action;
149 $req->address;
150 $req->arguments;
151 $req->args;
152 $req->base;
153 $req->body;
154 $req->body_parameters;
155 $req->content_encoding;
156 $req->content_length;
157 $req->content_type;
158 $req->cookie;
159 $req->cookies;
160 $req->header;
161 $req->headers;
162 $req->hostname;
163 $req->input;
164 $req->query_keywords;
165 $req->match;
166 $req->method;
167 $req->param;
168 $req->parameters;
169 $req->params;
170 $req->path;
171 $req->protocol;
172 $req->query_parameters;
173 $req->read;
174 $req->referer;
175 $req->secure;
176 $req->captures; # previously knows as snippets
177 $req->upload;
178 $req->uploads;
179 $req->uri;
180 $req->user;
181 $req->user_agent;
182
183See also L<Catalyst>, L<Catalyst::Request::Upload>.
184
185=head1 DESCRIPTION
186
187This is the Catalyst Request class, which provides an interface to data for the
188current client request. The request object is prepared by L<Catalyst::Engine>,
189thus hiding the details of the particular engine implementation.
190
191=head1 METHODS
192
193=head2 $req->action
194
195[DEPRECATED] Returns the name of the requested action.
196
197
198Use C<< $c->action >> instead (which returns a
199L<Catalyst::Action|Catalyst::Action> object).
200
201=head2 $req->address
202
203Returns the IP address of the client.
204
205=head2 $req->arguments
206
207Returns a reference to an array containing the arguments.
208
209 print $c->request->arguments->[0];
210
211For example, if your action was
212
213 package MyApp::Controller::Foo;
214
215 sub moose : Local {
216 ...
217 }
218
219and the URI for the request was C<http://.../foo/moose/bah>, the string C<bah>
220would be the first and only argument.
221
222Arguments get automatically URI-unescaped for you.
223
224=head2 $req->args
225
226Shortcut for L</arguments>.
227
228=head2 $req->base
229
230Contains the URI base. This will always have a trailing slash. Note that the
231URI scheme (eg., http vs. https) must be determined through heuristics;
232depending on your server configuration, it may be incorrect. See $req->secure
233for more info.
234
235If your application was queried with the URI
236C<http://localhost:3000/some/path> then C<base> is C<http://localhost:3000/>.
237
238=head2 $req->body
239
240Returns the message body of the request, as returned by L<HTTP::Body>: a string,
241unless Content-Type is C<application/x-www-form-urlencoded>, C<text/xml>, or
242C<multipart/form-data>, in which case a L<File::Temp> object is returned.
243
244=head2 $req->body_parameters
245
246Returns a reference to a hash containing body (POST) parameters. Values can
247be either a scalar or an arrayref containing scalars.
248
249 print $c->request->body_parameters->{field};
250 print $c->request->body_parameters->{field}->[0];
251
252These are the parameters from the POST part of the request, if any.
253
254=head2 $req->body_params
255
256Shortcut for body_parameters.
257
258=head2 $req->content_encoding
259
260Shortcut for $req->headers->content_encoding.
261
262=head2 $req->content_length
263
264Shortcut for $req->headers->content_length.
265
266=head2 $req->content_type
267
268Shortcut for $req->headers->content_type.
269
270=head2 $req->cookie
271
272A convenient method to access $req->cookies.
273
274 $cookie = $c->request->cookie('name');
275 @cookies = $c->request->cookie;
276
277=cut
278
279sub cookie {
280 my $self = shift;
281
282 if ( @_ == 0 ) {
283 return keys %{ $self->cookies };
284 }
285
286 if ( @_ == 1 ) {
287
288 my $name = shift;
289
290 unless ( exists $self->cookies->{$name} ) {
291 return undef;
292 }
293
294 return $self->cookies->{$name};
295 }
296}
297
298=head2 $req->cookies
299
300Returns a reference to a hash containing the cookies.
301
302 print $c->request->cookies->{mycookie}->value;
303
304The cookies in the hash are indexed by name, and the values are L<CGI::Simple::Cookie>
305objects.
306
307=head2 $req->header
308
309Shortcut for $req->headers->header.
310
311=head2 $req->headers
312
313Returns an L<HTTP::Headers> object containing the headers for the current request.
314
315 print $c->request->headers->header('X-Catalyst');
316
317=head2 $req->hostname
318
319Returns the hostname of the client.
320
321=head2 $req->input
322
323Alias for $req->body.
324
325=head2 $req->query_keywords
326
327Contains the keywords portion of a query string, when no '=' signs are
328present.
329
330 http://localhost/path?some+keywords
331
332 $c->request->query_keywords will contain 'some keywords'
333
334=head2 $req->match
335
336This contains the matching part of a Regex action. Otherwise
337it returns the same as 'action', except for default actions,
338which return an empty string.
339
340=head2 $req->method
341
342Contains the request method (C<GET>, C<POST>, C<HEAD>, etc).
343
344=head2 $req->param
345
346Returns GET and POST parameters with a CGI.pm-compatible param method. This
347is an alternative method for accessing parameters in $c->req->parameters.
348
349 $value = $c->request->param( 'foo' );
350 @values = $c->request->param( 'foo' );
351 @params = $c->request->param;
352
353Like L<CGI>, and B<unlike> earlier versions of Catalyst, passing multiple
354arguments to this method, like this:
355
356 $c->request->param( 'foo', 'bar', 'gorch', 'quxx' );
357
358will set the parameter C<foo> to the multiple values C<bar>, C<gorch> and
359C<quxx>. Previously this would have added C<bar> as another value to C<foo>
360(creating it if it didn't exist before), and C<quxx> as another value for
361C<gorch>.
362
363B<NOTE> this is considered a legacy interface and care should be taken when
364using it. C<< scalar $c->req->param( 'foo' ) >> will return only the first
365C<foo> param even if multiple are present; C<< $c->req->param( 'foo' ) >> will
366return a list of as many are present, which can have unexpected consequences
367when writing code of the form:
368
369 $foo->bar(
370 a => 'b',
371 baz => $c->req->param( 'baz' ),
372 );
373
374If multiple C<baz> parameters are provided this code might corrupt data or
375cause a hash initialization error. For a more straightforward interface see
376C<< $c->req->parameters >>.
377
378=cut
379
380sub param {
381 my $self = shift;
382
383 if ( @_ == 0 ) {
384 return keys %{ $self->parameters };
385 }
386
387 if ( @_ == 1 ) {
388
389 my $param = shift;
390
391 unless ( exists $self->parameters->{$param} ) {
392 return wantarray ? () : undef;
393 }
394
395 if ( ref $self->parameters->{$param} eq 'ARRAY' ) {
396 return (wantarray)
397 ? @{ $self->parameters->{$param} }
398 : $self->parameters->{$param}->[0];
399 }
400 else {
401 return (wantarray)
402 ? ( $self->parameters->{$param} )
403 : $self->parameters->{$param};
404 }
405 }
406 elsif ( @_ > 1 ) {
407 my $field = shift;
408 $self->parameters->{$field} = [@_];
409 }
410}
411
412=head2 $req->parameters
413
414Returns a reference to a hash containing GET and POST parameters. Values can
415be either a scalar or an arrayref containing scalars.
416
417 print $c->request->parameters->{field};
418 print $c->request->parameters->{field}->[0];
419
420This is the combination of C<query_parameters> and C<body_parameters>.
421
422=head2 $req->params
423
424Shortcut for $req->parameters.
425
426=head2 $req->path
427
428Returns the path, i.e. the part of the URI after $req->base, for the current request.
429
430=head2 $req->path_info
431
432Alias for path, added for compatibility with L<CGI>.
433
434=cut
435
436sub path {
437 my ( $self, @params ) = @_;
438
439 if (@params) {
440 $self->uri->path(@params);
441 $self->_clear_path;
442 }
443 elsif ( $self->_has_path ) {
444 return $self->_path;
445 }
446 else {
447 my $path = $self->uri->path;
448 my $location = $self->base->path;
449 $path =~ s/^(\Q$location\E)?//;
450 $path =~ s/^\///;
451 $self->_path($path);
452
453 return $path;
454 }
455}
456
457=head2 $req->protocol
458
459Returns the protocol (HTTP/1.0 or HTTP/1.1) used for the current request.
460
461=head2 $req->query_parameters
462
463=head2 $req->query_params
464
465Returns a reference to a hash containing query string (GET) parameters. Values can
466be either a scalar or an arrayref containing scalars.
467
468 print $c->request->query_parameters->{field};
469 print $c->request->query_parameters->{field}->[0];
470
471=head2 $req->read( [$maxlength] )
472
473Reads a chunk of data from the request body. This method is intended to be
474used in a while loop, reading $maxlength bytes on every call. $maxlength
475defaults to the size of the request if not specified.
476
477You have to set MyApp->config(parse_on_demand => 1) to use this directly.
478
479=head2 $req->referer
480
481Shortcut for $req->headers->referer. Returns the referring page.
482
483=head2 $req->secure
484
485Returns true or false, indicating whether the connection is secure
486(https). Note that the URI scheme (eg., http vs. https) must be determined
487through heuristics, and therefore the reliablity of $req->secure will depend
488on your server configuration. If you are serving secure pages on the standard
489SSL port (443) and/or setting the HTTPS environment variable, $req->secure
490should be valid.
491
492=head2 $req->captures
493
494Returns a reference to an array containing captured args from chained
495actions or regex captures.
496
497 my @captures = @{ $c->request->captures };
498
499=head2 $req->snippets
500
501C<captures> used to be called snippets. This is still available for backwards
502compatibility, but is considered deprecated.
503
504=head2 $req->upload
505
506A convenient method to access $req->uploads.
507
508 $upload = $c->request->upload('field');
509 @uploads = $c->request->upload('field');
510 @fields = $c->request->upload;
511
512 for my $upload ( $c->request->upload('field') ) {
513 print $upload->filename;
514 }
515
516=cut
517
518sub upload {
519 my $self = shift;
520
521 if ( @_ == 0 ) {
522 return keys %{ $self->uploads };
523 }
524
525 if ( @_ == 1 ) {
526
527 my $upload = shift;
528
529 unless ( exists $self->uploads->{$upload} ) {
530 return wantarray ? () : undef;
531 }
532
533 if ( ref $self->uploads->{$upload} eq 'ARRAY' ) {
534 return (wantarray)
535 ? @{ $self->uploads->{$upload} }
536 : $self->uploads->{$upload}->[0];
537 }
538 else {
539 return (wantarray)
540 ? ( $self->uploads->{$upload} )
541 : $self->uploads->{$upload};
542 }
543 }
544
545 if ( @_ > 1 ) {
546
547 while ( my ( $field, $upload ) = splice( @_, 0, 2 ) ) {
548
549 if ( exists $self->uploads->{$field} ) {
550 for ( $self->uploads->{$field} ) {
551 $_ = [$_] unless ref($_) eq "ARRAY";
552 push( @$_, $upload );
553 }
554 }
555 else {
556 $self->uploads->{$field} = $upload;
557 }
558 }
559 }
560}
561
562=head2 $req->uploads
563
564Returns a reference to a hash containing uploads. Values can be either a
565L<Catalyst::Request::Upload> object, or an arrayref of
566L<Catalyst::Request::Upload> objects.
567
568 my $upload = $c->request->uploads->{field};
569 my $upload = $c->request->uploads->{field}->[0];
570
571=head2 $req->uri
572
573Returns a L<URI> object for the current request. Stringifies to the URI text.
574
575=head2 $req->mangle_params( { key => 'value' }, $appendmode);
576
577Returns a hashref of parameters stemming from the current request's params,
578plus the ones supplied. Keys for which no current param exists will be
579added, keys with undefined values will be removed and keys with existing
580params will be replaced. Note that you can supply a true value as the final
581argument to change behavior with regards to existing parameters, appending
582values rather than replacing them.
583
584A quick example:
585
586 # URI query params foo=1
587 my $hashref = $req->mangle_params({ foo => 2 });
588 # Result is query params of foo=2
589
590versus append mode:
591
592 # URI query params foo=1
593 my $hashref = $req->mangle_params({ foo => 2 }, 1);
594 # Result is query params of foo=1&foo=2
595
596This is the code behind C<uri_with>.
597
598=cut
599
600sub mangle_params {
601 my ($self, $args, $append) = @_;
602
603 carp('No arguments passed to mangle_params()') unless $args;
604
605 foreach my $value ( values %$args ) {
606 next unless defined $value;
607 for ( ref $value eq 'ARRAY' ? @$value : $value ) {
608 $_ = "$_";
609 utf8::encode( $_ ) if utf8::is_utf8($_);
610 }
611 };
612
613 my %params = %{ $self->uri->query_form_hash };
614 foreach my $key (keys %{ $args }) {
615 my $val = $args->{$key};
616 if(defined($val)) {
617
618 if($append && exists($params{$key})) {
619
620 # This little bit of heaven handles appending a new value onto
621 # an existing one regardless if the existing value is an array
622 # or not, and regardless if the new value is an array or not
623 $params{$key} = [
624 ref($params{$key}) eq 'ARRAY' ? @{ $params{$key} } : $params{$key},
625 ref($val) eq 'ARRAY' ? @{ $val } : $val
626 ];
627
628 } else {
629 $params{$key} = $val;
630 }
631 } else {
632
633 # If the param wasn't defined then we delete it.
634 delete($params{$key});
635 }
636 }
637
638
639 return \%params;
640}
641
642=head2 $req->uri_with( { key => 'value' } );
643
644Returns a rewritten URI object for the current request. Key/value pairs
645passed in will override existing parameters. You can remove an existing
646parameter by passing in an undef value. Unmodified pairs will be
647preserved.
648
649You may also pass an optional second parameter that puts C<uri_with> into
650append mode:
651
652 $req->uri_with( { key => 'value' }, { mode => 'append' } );
653
654See C<mangle_params> for an explanation of this behavior.
655
656=cut
657
658sub uri_with {
659 my( $self, $args, $behavior) = @_;
660
661 carp( 'No arguments passed to uri_with()' ) unless $args;
662
663 my $append = 0;
664 if((ref($behavior) eq 'HASH') && defined($behavior->{mode}) && ($behavior->{mode} eq 'append')) {
665 $append = 1;
666 }
667
668 my $params = $self->mangle_params($args, $append);
669
670 my $uri = $self->uri->clone;
671 $uri->query_form($params);
672
673 return $uri;
674}
675
676=head2 $req->user
677
678Returns the currently logged in user. B<Highly deprecated>, do not call,
679this will be removed in version 5.81. To retrieve the currently authenticated
680user, see C<< $c->user >> and C<< $c->user_exists >> in
681L<Catalyst::Plugin::Authentication>. For the C<REMOTE_USER> provided by the
682webserver, see C<< $req->remote_user >> below.
683
684=head2 $req->remote_user
685
686Returns the value of the C<REMOTE_USER> environment variable.
687
688=head2 $req->user_agent
689
690Shortcut to $req->headers->user_agent. Returns the user agent (browser)
691version string.
692
693=head2 meta
694
695Provided by Moose
696
697=head1 AUTHORS
698
699Catalyst Contributors, see Catalyst.pm
700
701=head1 COPYRIGHT
702
703This library is free software. You can redistribute it and/or modify
704it under the same terms as Perl itself.
705
706=cut
707
708__PACKAGE__->meta->make_immutable;
709
7101;