root/lang/perl/HTTP-Engine/branches/lazy_request/lib/HTTP/Engine/Request.pm @ 13398

Revision 13398, 9.5 kB (checked in by nothingmuch, 5 years ago)

lazify uri, use URI::WithBase?, path/base are handled by uri

Line 
1package HTTP::Engine::Request;
2use Moose;
3
4use Carp;
5use HTTP::Headers;
6use HTTP::Body;
7use HTTP::Engine::Types::Core qw( Uri Header );
8use HTTP::Request;
9
10sub BUILD {
11    my ( $self, $param ) = @_;
12
13    foreach my $field qw(base path) {
14        if ( my $val = $param->{$field} ) {
15            $self->$field($val);
16        }
17    }
18}
19
20has request_builder => (
21    isa => "HTTP::Engine::RequestBuilder",
22    is  => "rw",
23);
24
25# the IP address of the client
26has address => (
27    is  => 'rw',
28    isa => 'Str',
29);
30
31has context => (
32    is       => 'rw',
33    isa      => 'HTTP::Engine::Context',
34    weak_ref => 1,
35);
36
37has cookies => (
38    is      => 'rw',
39    isa     => 'HashRef',
40    lazy_build => 1,
41);
42
43sub _build_cookies {
44    my $self = shift;
45    $self->request_builder->_build_cookies($self);
46}
47
48has method => (
49    is  => 'rw',
50    # isa => 'Str',
51);
52
53has protocol => (
54    is  => 'rw',
55    # isa => 'Str',
56);
57
58has query_parameters => (
59    is      => 'rw',
60    isa     => 'HashRef',
61    lazy_build => 1,
62);
63
64sub _build_query_parameters {
65    my $self = shift;
66    $self->uri->query_form_hash;
67}
68
69# https or not?
70has secure => (
71    is      => 'rw',
72    isa     => 'Bool',
73    default => 0,
74);
75
76has uri => (
77    is     => 'rw',
78    isa    => Uri,
79    coerce => 1,
80    lazy_build => 1,
81    handles => [qw(base path)],
82);
83
84sub _build_uri {
85    my $self = shift;
86
87    if ( my $rb = $self->request_builder ) {
88        $rb->_build_uri($self);
89    } else {
90        URI::WithBase->new;
91    }
92}
93
94has user => ( is => 'rw', );
95
96has raw_body => (
97    is      => 'rw',
98    isa     => 'Str',
99    default => '',
100);
101
102has headers => (
103    is      => 'rw',
104    isa     => Header,
105    coerce  => 1,
106    lazy_build => 1,
107    handles => [ qw(content_encoding content_length content_type header referer user_agent) ],
108);
109
110sub _build_headers {
111    my $self = shift;
112
113    if ( my $rb = $self->request_builder ) {
114        return $rb->_build_headers($self);
115    } else {
116        return HTTP::Headers->new;
117    }
118}
119
120# Contains the URI base. This will always have a trailing slash.
121# If your application was queried with the URI C<http://localhost:3000/some/path> then C<base> is C<http://localhost:3000/>.
122
123has hostname => (
124    is      => 'rw',
125    isa     => 'Str',
126    lazy_build => 1,
127);
128
129sub _build_hostname {
130    my $self = shift;
131    $self->request_builder->_build_hostname;
132}
133
134has http_body => (
135    is      => 'rw',
136    isa     => 'HTTP::Body',
137    handles => {
138        body_parameters => 'param',
139        body            => 'body',
140    },
141);
142
143# contains body_params and query_params
144has parameters => (
145    is      => 'rw',
146    isa     => 'HashRef',
147    default => sub { +{} },
148);
149
150has uploads => (
151    is      => 'rw',
152    isa     => 'HashRef',
153    default => sub { +{} },
154);
155
156no Moose;
157
158# aliases
159*body_params  = \&body_parameters;
160*input        = \&body;
161*params       = \&parameters;
162*query_params = \&query_parameters;
163*path_info    = \&path;
164
165sub cookie {
166    my $self = shift;
167
168    return keys %{ $self->cookies } if @_ == 0;
169
170    if (@_ == 1) {
171        my $name = shift;
172        return undef unless exists $self->cookies->{$name}; ## no critic.
173        return $self->cookies->{$name};
174    }
175}
176
177sub param {
178    my $self = shift;
179
180    return keys %{ $self->parameters } if @_ == 0;
181
182    if (@_ == 1) {
183        my $param = shift;
184        return wantarray ? () : undef unless exists $self->parameters->{$param};
185
186        if ( ref $self->parameters->{$param} eq 'ARRAY' ) {
187            return (wantarray)
188              ? @{ $self->parameters->{$param} }
189                  : $self->parameters->{$param}->[0];
190        } else {
191            return (wantarray)
192              ? ( $self->parameters->{$param} )
193                  : $self->parameters->{$param};
194        }
195    } elsif (@_ > 1) {
196        my $field = shift;
197        $self->parameters->{$field} = [@_];
198    }
199}
200
201sub upload {
202    my $self = shift;
203
204    return keys %{ $self->uploads } if @_ == 0;
205
206    if (@_ == 1) {
207        my $upload = shift;
208        return wantarray ? () : undef unless exists $self->uploads->{$upload};
209
210        if (ref $self->uploads->{$upload} eq 'ARRAY') {
211            return (wantarray)
212              ? @{ $self->uploads->{$upload} }
213          : $self->uploads->{$upload}->[0];
214        } else {
215            return (wantarray)
216              ? ( $self->uploads->{$upload} )
217          : $self->uploads->{$upload};
218        }
219    }
220
221    if (@_ > 1) {
222        while ( my($field, $upload) = splice(@_, 0, 2) ) {
223            if ( exists $self->uploads->{$field} ) {
224                for ( $self->uploads->{$field} ) {
225                    $_ = [$_] unless ref($_) eq "ARRAY";
226                    push(@{ $_ }, $upload);
227                }
228            } else {
229                $self->uploads->{$field} = $upload;
230            }
231        }
232    }
233}
234
235sub uri_with {
236    my($self, $args) = @_;
237   
238    carp( 'No arguments passed to uri_with()' ) unless $args;
239
240    for my $value (values %{ $args }) {
241        next unless defined $value;
242        for ( ref $value eq 'ARRAY' ? @{ $value } : $value ) {
243            $_ = "$_";
244            utf8::encode( $_ );
245        }
246    };
247   
248    my $uri = $self->uri->clone;
249   
250    $uri->query_form( {
251        %{ $uri->query_form_hash },
252        %{ $args },
253    } );
254    return $uri;
255}
256
257sub as_http_request {
258    my $self = shift;
259    HTTP::Request->new( $self->method, $self->uri, $self->headers, $self->raw_body );
260}
261
262sub absolute_url {
263    my ($self, $location) = @_;
264
265    unless ($location =~ m!^https?://!) {
266        return URI->new( $location )->abs( $self->base );
267    } else {
268        return $location;
269    }
270}
271
272sub content {
273    my ( $self, @args ) = @_;
274
275    if ( @args ) {
276        croak "The HTTP::Request method 'content' is unsupported when used as a writer, use HTTP::Engine::RequestBuilder";
277    } else {
278        return $self->raw_body;
279    }
280}
281
282sub as_string {
283    my $self = shift;
284    $self->as_http_request->as_string; # FIXME not efficient
285}
286
287sub parse {
288    croak "The HTTP::Request method 'parse' is unsupported, use HTTP::Engine::RequestBuilder";
289}
290
291__PACKAGE__->meta->make_immutable;
292
2931;
294__END__
295
296=for stopwords Stringifies URI http https param CGI.pm-compatible referer uri IP hostname
297
298=head1 NAME
299
300HTTP::Engine::Request - http request object
301
302=head1 SYNOPSIS
303
304    $c->req
305
306=head1 ATTRIBUTES
307
308=over 4
309
310=item address
311
312Returns the IP address of the client.
313
314=item context
315
316Returns the HTTP::Context(internal use only)
317
318=item cookies
319
320Returns a reference to a hash containing the cookies
321
322=item method
323
324Contains the request method (C<GET>, C<POST>, C<HEAD>, etc).
325
326=item protocol
327
328Returns the protocol (HTTP/1.0 or HTTP/1.1) used for the current request.
329
330=item query_parameters
331
332Returns a reference to a hash containing query string (GET) parameters. Values can                                                   
333be either a scalar or an arrayref containing scalars.
334
335=item secure
336
337Returns true or false, indicating whether the connection is secure (https).
338
339=item uri
340
341Returns a URI object for the current request. Stringifies to the URI text.
342
343=item user
344
345Returns REMOTE_USER.
346
347=item raw_body
348
349Returns string containing body(POST).
350
351=item headers
352
353Returns an L<HTTP::Headers> object containing the headers for the current request.
354
355=item base
356
357Contains the URI base. This will always have a trailing slash.
358
359=item hostname
360
361Returns the hostname of the client.
362
363=item http_body
364
365Returns an L<HTTP::Body> object.
366
367=item parameters
368
369Returns a reference to a hash containing GET and POST parameters. Values can
370be either a scalar or an arrayref containing scalars.
371
372=item uploads
373
374Returns a reference to a hash containing uploads. Values can be either a
375L<HTTP::Engine::Request::Upload> object, or an arrayref of
376L<HTTP::Engine::Request::Upload> objects.
377
378=item content_encoding
379
380Shortcut to $req->headers->content_encoding.
381
382=item content_length
383
384Shortcut to $req->headers->content_length.
385
386=item content_type
387
388Shortcut to $req->headers->content_type.
389
390=item header
391
392Shortcut to $req->headers->header.
393
394=item referer
395
396Shortcut to $req->headers->referer.
397
398=item user_agent
399
400Shortcut to $req->headers->user_agent.
401
402=item cookie
403
404A convenient method to access $req->cookies.
405
406    $cookie  = $c->req->cookie('name');
407    @cookies = $c->req->cookie;
408
409=item param
410
411Returns GET and POST parameters with a CGI.pm-compatible param method. This
412is an alternative method for accessing parameters in $c->req->parameters.
413
414    $value  = $c->req->param( 'foo' );
415    @values = $c->req->param( 'foo' );
416    @params = $c->req->param;
417
418Like L<CGI>, and B<unlike> earlier versions of Catalyst, passing multiple
419arguments to this method, like this:
420
421    $c->req->param( 'foo', 'bar', 'gorch', 'quxx' );
422
423will set the parameter C<foo> to the multiple values C<bar>, C<gorch> and
424C<quxx>. Previously this would have added C<bar> as another value to C<foo>
425(creating it if it didn't exist before), and C<quxx> as another value for
426C<gorch>.
427
428=item path
429
430Returns the path, i.e. the part of the URI after $req->base, for the current request.
431
432=item upload
433
434A convenient method to access $req->uploads.
435
436    $upload  = $c->req->upload('field');
437    @uploads = $c->req->upload('field');
438    @fields  = $c->req->upload;
439
440    for my $upload ( $c->req->upload('field') ) {
441        print $upload->filename;
442    }
443
444
445=item uri_with
446
447Returns a rewritten URI object for the current request. Key/value pairs
448passed in will override existing parameters. Unmodified pairs will be
449preserved.
450
451=item as_http_request
452
453convert HTTP::Engine::Request to HTTP::Request.
454
455=item $req->absolute_url($location)
456
457convert $location to absolute uri.
458
459=back
460
461=head1 AUTHORS
462
463Kazuhiro Osawa and HTTP::Engine Authors.
464
465=head1 THANKS TO
466
467L<Catalyst::Request>
468
469=head1 SEE ALSO
470
471L<HTTP::Request>, L<Catalyst::Request>
472
Note: See TracBrowser for help on using the browser.