Fix to allow uri_for and uri_with to stringify non-array references
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Request.pm
1 package Catalyst::Request;
2
3 use strict;
4 use base 'Class::Accessor::Fast';
5
6 use IO::Socket qw[AF_INET inet_aton];
7 use Carp;
8 use utf8;
9 use URI::QueryParam;
10
11 __PACKAGE__->mk_accessors(
12     qw/action address arguments cookies headers match method
13       protocol query_parameters secure captures uri user/
14 );
15
16 *args         = \&arguments;
17 *body_params  = \&body_parameters;
18 *input        = \&body;
19 *params       = \&parameters;
20 *query_params = \&query_parameters;
21 *path_info    = \&path;
22 *snippets     = \&captures;
23
24 sub content_encoding { shift->headers->content_encoding(@_) }
25 sub content_length   { shift->headers->content_length(@_) }
26 sub content_type     { shift->headers->content_type(@_) }
27 sub header           { shift->headers->header(@_) }
28 sub referer          { shift->headers->referer(@_) }
29 sub user_agent       { shift->headers->user_agent(@_) }
30
31 =head1 NAME
32
33 Catalyst::Request - provides information about the current client request
34
35 =head1 SYNOPSIS
36
37     $req = $c->request;
38     $req->action;
39     $req->address;
40     $req->arguments;
41     $req->args;
42     $req->base;
43     $req->body;
44     $req->body_parameters;
45     $req->content_encoding;
46     $req->content_length;
47     $req->content_type;
48     $req->cookie;
49     $req->cookies;
50     $req->header;
51     $req->headers;
52     $req->hostname;
53     $req->input;
54     $req->match;
55     $req->method;
56     $req->param;
57     $req->parameters;
58     $req->params;
59     $req->path;
60     $req->protocol;
61     $req->query_parameters;
62     $req->read;
63     $req->referer;
64     $req->secure;
65     $req->captures; # previously knows as snippets
66     $req->upload;
67     $req->uploads;
68     $req->uri;
69     $req->user;
70     $req->user_agent;
71
72 See also L<Catalyst>, L<Catalyst::Request::Upload>.
73
74 =head1 DESCRIPTION
75
76 This is the Catalyst Request class, which provides an interface to data for the
77 current client request. The request object is prepared by L<Catalyst::Engine>,
78 thus hiding the details of the particular engine implementation.
79
80 =head1 METHODS
81
82 =head2 $req->action
83
84 Returns the requested action as a L<Catalyst::Action> object.
85
86 =head2 $req->address
87
88 Returns the IP address of the client.
89
90 =head2 $req->arguments
91
92 Returns a reference to an array containing the arguments.
93
94     print $c->request->arguments->[0];
95
96 For example, if your action was
97
98         package MyApp::C::Foo;
99         
100         sub moose : Local {
101                 ...
102         }
103
104 and the URI for the request was C<http://.../foo/moose/bah>, the string C<bah>
105 would be the first and only argument.
106
107 =head2 $req->args
108
109 Shortcut for arguments.
110
111 =head2 $req->base
112
113 Contains the URI base. This will always have a trailing slash.
114
115 If your application was queried with the URI
116 C<http://localhost:3000/some/path> then C<base> is C<http://localhost:3000/>.
117
118 =cut
119
120 sub base {
121     my ( $self, $base ) = @_;
122
123     return $self->{base} unless $base;
124
125     $self->{base} = $base;
126
127     # set the value in path for backwards-compat
128     if ( $self->uri ) {
129         $self->path;
130     }
131
132     return $self->{base};
133 }
134
135 =head2 $req->body
136
137 Returns the message body of the request, unless Content-Type is
138 C<application/x-www-form-urlencoded> or C<multipart/form-data>.
139
140 =cut
141
142 sub body {
143     my ( $self, $body ) = @_;
144     $self->{_context}->prepare_body;
145     return $self->{_body}->body;
146 }
147
148 =head2 $req->body_parameters
149
150 Returns a reference to a hash containing body (POST) parameters. Values can
151 be either a scalar or an arrayref containing scalars.
152
153     print $c->request->body_parameters->{field};
154     print $c->request->body_parameters->{field}->[0];
155
156 These are the parameters from the POST part of the request, if any.
157     
158 =head2 $req->body_params
159
160 Shortcut for body_parameters.
161
162 =cut
163
164 sub body_parameters {
165     my ( $self, $params ) = @_;
166     $self->{_context}->prepare_body;
167     $self->{body_parameters} = $params if $params;
168     return $self->{body_parameters};
169 }
170
171 =head2 $req->content_encoding
172
173 Shortcut for $req->headers->content_encoding.
174
175 =head2 $req->content_length
176
177 Shortcut for $req->headers->content_length.
178
179 =head2 $req->content_type
180
181 Shortcut for $req->headers->content_type.
182
183 =head2 $req->cookie
184
185 A convenient method to access $req->cookies.
186
187     $cookie  = $c->request->cookie('name');
188     @cookies = $c->request->cookie;
189
190 =cut
191
192 sub cookie {
193     my $self = shift;
194
195     if ( @_ == 0 ) {
196         return keys %{ $self->cookies };
197     }
198
199     if ( @_ == 1 ) {
200
201         my $name = shift;
202
203         unless ( exists $self->cookies->{$name} ) {
204             return undef;
205         }
206
207         return $self->cookies->{$name};
208     }
209 }
210
211 =head2 $req->cookies
212
213 Returns a reference to a hash containing the cookies.
214
215     print $c->request->cookies->{mycookie}->value;
216
217 The cookies in the hash are indexed by name, and the values are L<CGI::Cookie>
218 objects.
219
220 =head2 $req->header
221
222 Shortcut for $req->headers->header.
223
224 =head2 $req->headers
225
226 Returns an L<HTTP::Headers> object containing the headers for the current request.
227
228     print $c->request->headers->header('X-Catalyst');
229
230 =head2 $req->hostname
231
232 Returns the hostname of the client.
233     
234 =cut
235
236 sub hostname {
237     my $self = shift;
238
239     if ( @_ == 0 && not $self->{hostname} ) {
240         $self->{hostname} =
241           gethostbyaddr( inet_aton( $self->address ), AF_INET );
242     }
243
244     if ( @_ == 1 ) {
245         $self->{hostname} = shift;
246     }
247
248     return $self->{hostname};
249 }
250
251 =head2 $req->input
252
253 Alias for $req->body.
254
255 =head2 $req->match
256
257 This contains the matching part of a Regex action. Otherwise
258 it returns the same as 'action', except for default actions,
259 which return an empty string.
260
261 =head2 $req->method
262
263 Contains the request method (C<GET>, C<POST>, C<HEAD>, etc).
264
265 =head2 $req->param
266
267 Returns GET and POST parameters with a CGI.pm-compatible param method. This 
268 is an alternative method for accessing parameters in $c->req->parameters.
269
270     $value  = $c->request->param( 'foo' );
271     @values = $c->request->param( 'foo' );
272     @params = $c->request->param;
273
274 Like L<CGI>, and B<unlike> earlier versions of Catalyst, passing multiple
275 arguments to this method, like this:
276
277         $c->request->param( 'foo', 'bar', 'gorch', 'quxx' );
278
279 will set the parameter C<foo> to the multiple values C<bar>, C<gorch> and
280 C<quxx>. Previously this would have added C<bar> as another value to C<foo>
281 (creating it if it didn't exist before), and C<quxx> as another value for
282 C<gorch>.
283
284 =cut
285
286 sub param {
287     my $self = shift;
288
289     if ( @_ == 0 ) {
290         return keys %{ $self->parameters };
291     }
292
293     if ( @_ == 1 ) {
294
295         my $param = shift;
296
297         unless ( exists $self->parameters->{$param} ) {
298             return wantarray ? () : undef;
299         }
300
301         if ( ref $self->parameters->{$param} eq 'ARRAY' ) {
302             return (wantarray)
303               ? @{ $self->parameters->{$param} }
304               : $self->parameters->{$param}->[0];
305         }
306         else {
307             return (wantarray)
308               ? ( $self->parameters->{$param} )
309               : $self->parameters->{$param};
310         }
311     }
312     elsif ( @_ > 1 ) {
313         my $field = shift;
314         $self->parameters->{$field} = [@_];
315     }
316 }
317
318 =head2 $req->parameters
319
320 Returns a reference to a hash containing GET and POST parameters. Values can
321 be either a scalar or an arrayref containing scalars.
322
323     print $c->request->parameters->{field};
324     print $c->request->parameters->{field}->[0];
325
326 This is the combination of C<query_parameters> and C<body_parameters>.
327
328 =head2 $req->params
329
330 Shortcut for $req->parameters.
331
332 =cut
333
334 sub parameters {
335     my ( $self, $params ) = @_;
336     $self->{_context}->prepare_body;
337     if ( $params ) {
338         if ( ref $params ) {
339             $self->{parameters} = $params;
340         }
341         else {
342             $self->{_context}->log->warn( 
343                 "Attempt to retrieve '$params' with req->params(), " .
344                 "you probably meant to call req->param('$params')" );
345         }
346     }
347     return $self->{parameters};
348 }
349
350 =head2 $req->path
351
352 Returns the path, i.e. the part of the URI after $req->base, for the current request.
353
354 =head2 $req->path_info
355
356 Alias for path, added for compability with L<CGI>.
357
358 =cut
359
360 sub path {
361     my ( $self, $params ) = @_;
362
363     if ($params) {
364         $self->uri->path($params);
365     }
366     else {
367         return $self->{path} if $self->{path};
368     }
369
370     my $path     = $self->uri->path;
371     my $location = $self->base->path;
372     $path =~ s/^(\Q$location\E)?//;
373     $path =~ s/^\///;
374     $self->{path} = $path;
375
376     return $path;
377 }
378
379 =head2 $req->protocol
380
381 Returns the protocol (HTTP/1.0 or HTTP/1.1) used for the current request.
382
383 =head2 $req->query_parameters
384
385 Returns a reference to a hash containing query string (GET) parameters. Values can
386 be either a scalar or an arrayref containing scalars.
387
388     print $c->request->query_parameters->{field};
389     print $c->request->query_parameters->{field}->[0];
390     
391 =head2 $req->read( [$maxlength] )
392
393 Reads a chunk of data from the request body. This method is intended to be
394 used in a while loop, reading $maxlength bytes on every call. $maxlength
395 defaults to the size of the request if not specified.
396
397 You have to set MyApp->config->{parse_on_demand} to use this directly.
398
399 =cut
400
401 sub read { shift->{_context}->read(@_); }
402
403 =head2 $req->referer
404
405 Shortcut for $req->headers->referer. Returns the referring page.
406
407 =head2 $req->secure
408
409 Returns true or false, indicating whether the connection is secure (https).
410
411 =head2 $req->captures
412
413 Returns a reference to an array containing regex captures.
414
415     my @captures = @{ $c->request->captures };
416
417 =head2 $req->snippets
418
419 C<captures> used to be called snippets. This is still available for backwoards
420 compatibility, but is considered deprecated.
421
422 =head2 $req->upload
423
424 A convenient method to access $req->uploads.
425
426     $upload  = $c->request->upload('field');
427     @uploads = $c->request->upload('field');
428     @fields  = $c->request->upload;
429
430     for my $upload ( $c->request->upload('field') ) {
431         print $upload->filename;
432     }
433
434 =cut
435
436 sub upload {
437     my $self = shift;
438
439     if ( @_ == 0 ) {
440         return keys %{ $self->uploads };
441     }
442
443     if ( @_ == 1 ) {
444
445         my $upload = shift;
446
447         unless ( exists $self->uploads->{$upload} ) {
448             return wantarray ? () : undef;
449         }
450
451         if ( ref $self->uploads->{$upload} eq 'ARRAY' ) {
452             return (wantarray)
453               ? @{ $self->uploads->{$upload} }
454               : $self->uploads->{$upload}->[0];
455         }
456         else {
457             return (wantarray)
458               ? ( $self->uploads->{$upload} )
459               : $self->uploads->{$upload};
460         }
461     }
462
463     if ( @_ > 1 ) {
464
465         while ( my ( $field, $upload ) = splice( @_, 0, 2 ) ) {
466
467             if ( exists $self->uploads->{$field} ) {
468                 for ( $self->uploads->{$field} ) {
469                     $_ = [$_] unless ref($_) eq "ARRAY";
470                     push( @$_, $upload );
471                 }
472             }
473             else {
474                 $self->uploads->{$field} = $upload;
475             }
476         }
477     }
478 }
479
480 =head2 $req->uploads
481
482 Returns a reference to a hash containing uploads. Values can be either a
483 hashref or a arrayref containing L<Catalyst::Request::Upload> objects.
484
485     my $upload = $c->request->uploads->{field};
486     my $upload = $c->request->uploads->{field}->[0];
487
488 =cut
489
490 sub uploads {
491     my ( $self, $uploads ) = @_;
492     $self->{_context}->prepare_body;
493     $self->{uploads} = $uploads if $uploads;
494     return $self->{uploads};
495 }
496
497 =head2 $req->uri
498
499 Returns a URI object for the current request. Stringifies to the URI text.
500
501 =head2 $req->uri_with( { key => 'value' } );
502
503 Returns a rewritten URI object for the current request. Key/value pairs
504 passed in will override existing parameters. Unmodified pairs will be
505 preserved.
506
507 =cut
508
509 sub uri_with {
510     my( $self, $args ) = @_;
511     
512     carp( 'No arguments passed to uri_with()' ) unless $args;
513
514     for my $value ( values %$args ) {
515         for ( ref $value eq 'ARRAY' ? @$value : $value ) {
516             $_ = "$_";
517             utf8::encode( $_ );
518         }
519     };
520     
521     my $uri = $self->uri->clone;
522     
523     $uri->query_form( {
524         %{ $uri->query_form_hash },
525         %$args
526     } );
527     return $uri;
528 }
529
530 =head2 $req->user
531
532 Returns the currently logged in user. Deprecated. The method recommended for
533 newer plugins is $c->user.
534
535 =head2 $req->user_agent
536
537 Shortcut to $req->headers->user_agent. Returns the user agent (browser)
538 version string.
539
540 =head1 AUTHORS
541
542 Sebastian Riedel, C<sri@cpan.org>
543
544 Marcus Ramberg, C<mramberg@cpan.org>
545
546 =head1 COPYRIGHT
547
548 This program is free software, you can redistribute it and/or modify
549 it under the same terms as Perl itself.
550
551 =cut
552
553 1;