File Coverage

blib/lib/Net/HTTP/Spore/Request.pm
Criterion Covered Total %
statement 146 163 89.5
branch 45 62 72.5
condition 23 30 76.6
subroutine 24 28 85.7
pod 14 16 87.5
total 252 299 84.2


line stmt bran cond sub pod time code
1             package Net::HTTP::Spore::Request;
2             $Net::HTTP::Spore::Request::VERSION = '0.07';
3             # ABSTRACT: Net::HTTP::Spore::Request - Portable HTTP request object from SPORE env hash
4              
5 27     27   316335 use Moose;
  27         2627253  
  27         178  
6 27     27   163125 use Carp ();
  27         62  
  27         476  
7 27     27   3337 use URI;
  27         26098  
  27         659  
8 27     27   2350 use HTTP::Headers;
  27         39738  
  27         607  
9 27     27   1774 use HTTP::Request;
  27         35693  
  27         687  
10 27     27   139 use URI::Escape;
  27         52  
  27         1584  
11 27     27   7703 use MIME::Base64;
  27         13556  
  27         1273  
12 27     27   2344 use Net::HTTP::Spore::Response;
  27         61  
  27         40497  
13              
14             has env => (
15             is => 'rw',
16             isa => 'HashRef',
17             required => 1,
18             traits => ['Hash'],
19             handles => {
20             set_to_env => 'set',
21             get_from_env => 'get',
22             }
23             );
24              
25             has path => (
26             is => 'rw',
27             isa => 'Str',
28             lazy => 1,
29             default => sub { $_[0]->env->{PATH_INFO} }
30             );
31              
32             has headers => (
33             is => 'rw',
34             isa => 'HTTP::Headers',
35             lazy => 1,
36             handles => {
37             header => 'header',
38             },
39             default => sub {
40             my $self = shift;
41             my $env = $self->env;
42             my $h = HTTP::Headers->new(
43             map {
44             ( my $field = $_ ) =~ s/^HTTPS?_//;
45             ( $field => $env->{$_} );
46             } grep { /^(?:HTTP|CONTENT)/i } keys %$env
47             );
48             return $h;
49             },
50             );
51              
52             sub BUILDARGS {
53 49     49 1 21410 my $class = shift;
54              
55 49 50 33     310 if (@_ == 1 && !exists $_[0]->{env}) {
56 49         182 return {env => $_[0]};
57             }
58 0         0 return @_;
59             }
60              
61             sub method {
62 46     46 1 1434 my ( $self, $value ) = @_;
63 46 50       132 if ($value) {
64 0         0 $self->set_to_env( 'REQUEST_METHOD', $value );
65             }
66             else {
67 46         1606 return $self->get_from_env('REQUEST_METHOD');
68             }
69             }
70              
71             sub host {
72 0     0 0 0 my ($self, $value) = @_;
73 0 0       0 if ($value) {
74 0         0 $self->set_to_env('SERVER_NAME', $value);
75             }else{
76 0         0 return $self->get_from_env('SERVER_NAME');
77             }
78             }
79              
80             sub port {
81 4     4 1 5963 my ( $self, $value ) = @_;
82 4 50       12 if ($value) {
83 0         0 $self->set_to_env( 'SERVER_PORT', $value );
84             }
85             else {
86 4         120 return $self->get_from_env('SERVER_PORT');
87             }
88             }
89              
90             sub script_name {
91 2     2 1 1168 my ( $self, $value ) = @_;
92 2 50       6 if ($value) {
93 0         0 $self->set_to_env( 'SCRIPT_NAME', $value );
94             }
95             else {
96 2         70 return $self->get_from_env('SCRIPT_NAME');
97             }
98             }
99              
100             sub request_uri {
101 2     2 1 1480 my ($self, $value) = @_;
102 2 50       8 if ($value) {
103 0         0 $self->set_to_env( 'REQUEST_URI', $value );
104             }
105             else {
106 2         90 return $self->get_from_env('REQUEST_URI');
107             }
108             }
109              
110             sub scheme {
111 4     4 1 12 my ($self, $value) = @_;
112 4 50       10 if ($value) {
113 0         0 $self->set_to_env( 'spore.url_scheme', $value );
114             }
115             else {
116 4         125 return $self->get_from_env('spore.url_scheme');
117             }
118             }
119              
120             sub logger {
121 0     0 0 0 my ($self, $value) = @_;
122 0 0       0 if ($value) {
123 0         0 $self->set_to_env( 'sporex.logger', $value );
124             }
125             else {
126 0         0 return $self->get_from_env('sporex.logger');
127             }
128             }
129              
130             sub body {
131 44     44 1 711 my ($self, $value) = @_;
132 44 50       110 if ($value) {
133 0         0 $self->set_to_env( 'spore.payload', $value );
134             }
135             else {
136 44         1510 return $self->get_from_env('spore.payload');
137             }
138             }
139              
140             sub base {
141 9     9 1 5925 my $self = shift;
142 9         22 URI->new( $self->_uri_base )->canonical;
143             }
144              
145 0     0 1 0 sub input { (shift)->body(@_) }
146 40     40 1 134 sub content { (shift)->body(@_) }
147 0     0 1 0 sub secure { $_[0]->scheme eq 'https' }
148              
149             # TODO
150             # need to refactor this method, with path_info and query_string construction
151             sub uri {
152 41     41 1 117 my ($self, $path_info, $query_string) = @_;
153              
154 41 100 66     215 if ( !defined $path_info || !defined $query_string ) {
155 9         20 my @path_info = $self->_path;
156 9 50       20 $path_info = $path_info[0] if !$path_info;
157 9 100       20 $query_string = $path_info[1] if !$query_string;
158             }
159              
160 41         132 my $base = $self->_uri_base;
161              
162 41         89 my $path_escape_class = '^A-Za-z0-9\-\._~/';
163              
164 41   100     199 my $path = URI::Escape::uri_escape($path_info || '', $path_escape_class);
165              
166 41 100 100     3906 if (defined $query_string && length($query_string) > 0) {
167 9         25 $path .= '?' . $query_string;
168             }
169              
170 41 100       236 $base =~ s!/$!! if $path =~ m!^/!;
171 41         214 return URI->new( $base . $path )->canonical;
172             }
173              
174             sub _path {
175 9     9   11 my $self = shift;
176              
177 9         9 my $query_string;
178 9         204 my $path = $self->env->{PATH_INFO};
179 9 100       12 my @params = @{ $self->env->{'spore.params'} || [] };
  9         202  
180              
181 9         16 my $j = 0;
182 9         22 for (my $i = 0; $i < scalar @params; $i++) {
183 3         4 my $key = $params[$i];
184 3         4 my $value = $params[++$i];
185 3 100       7 if (!$value) {
186 1         2 $query_string .= $key;
187 1         2 last;
188             }
189 2 50 33     6 unless ( $path && $path =~ s/\:$key/$value/ ) {
190 2         4 $query_string .= $key . '=' . $value;
191 2 50 50     10 $query_string .= '&' if $query_string && scalar @params;
192             }
193             }
194              
195 9 100       24 $query_string =~ s/&$// if $query_string;
196 9         20 return ( $path, $query_string );
197             }
198              
199             sub _uri_base {
200 50     50   90 my $self = shift;
201 50         1210 my $env = $self->env;
202              
203             my $uri =
204             ( $env->{'spore.url_scheme'} || "http" ) . "://"
205             . (
206             defined $env->{'spore.userinfo'}
207             ? $env->{'spore.userinfo'} . '@'
208             : ''
209             )
210             . (
211             $env->{HTTP_HOST}
212             || (( $env->{SERVER_NAME} || "" ) . ":"
213             . ( $env->{SERVER_PORT} || 80 ) )
214 50 50 100     633 ) . ( $env->{SCRIPT_NAME} || '/' );
      66        
      100        
215              
216 50         140 return $uri;
217             }
218              
219             # stolen from HTTP::Request::Common
220             sub _boundary {
221 2     2   4 my ( $self, $size ) = @_;
222              
223 2 50       4 return "xYzZy" unless $size;
224              
225 2         60 my $b =
226             MIME::Base64::encode( join( "", map chr( rand(256) ), 1 .. $size * 3 ),
227             "" );
228 2         25 $b =~ s/[\W]/X/g;
229 2         4 return $b;
230             }
231              
232             sub _form_data {
233 2     2   4 my ( $self, $data ) = @_;
234              
235 2         3 my $form_data;
236 2         5 foreach my $k ( keys %$data ) {
237             push @$form_data,
238             'Content-Disposition: form-data; name="'
239             . $k
240             . '"'."\r\n\r\n"
241 1         5 . $data->{$k};
242             }
243              
244 2         5 my $b = $self->_boundary(10);
245 2         4 my $t = [];
246 2         5 foreach (@$form_data) {
247 1         4 push @$t, '--', $b, "\r\n", $_, "\r\n";
248             }
249 2         5 push @$t, '--', $b, , '--', "\r\n";
250 2         5 my $content = join("", @$t);
251 2         6 return ($content, $b);
252             }
253              
254             sub new_response {
255 22     22 1 15213 my $self = shift;
256 22         214 my $res = Net::HTTP::Spore::Response->new(@_);
257 22         95 $res->request($self);
258 22         94 $res;
259             }
260              
261             sub finalize {
262 40     40 1 8410 my $self = shift;
263              
264 40         1101 my $path_info = $self->env->{PATH_INFO};
265              
266 40         934 my $form_data = $self->env->{'spore.form_data'};
267 40         906 my $headers = $self->env->{'spore.headers'};
268 40   100     906 my $params = $self->env->{'spore.params'} || [];
269              
270 40         88 my $query = [];
271 40         75 my $form = {};
272              
273 40         150 for ( my $i = 0 ; $i < scalar @$params ; $i++ ) {
274 16         26 my $k = $params->[$i];
275 16         29 my $v = $params->[++$i];
276 16         21 my $modified = 0;
277              
278 16 100 100     202 if ($path_info && $path_info =~ s/\:$k/$v/) {
279 3         6 $modified++;
280             }
281              
282 16         47 foreach my $f_k (keys %$form_data) {
283 2         4 my $f_v = $form_data->{$f_k};
284 2 100       19 if ($f_v =~ s/^\:$k/$v/) {
285 1         4 $form->{$f_k} = $f_v;
286 1         3 $modified++;
287             }
288             }
289              
290 16         34 foreach my $h_k (keys %$headers) {
291 4         6 my $h_v = $headers->{$h_k};
292 4 100       37 if ($h_v =~ s/^\:$k/$v/) {
293 2         9 $self->header($h_k => $h_v);
294 2         91 $modified++;
295             }
296             }
297              
298 16 100       44 if ($modified == 0) {
299 10 100       25 if (defined $v) {
300 9         32 push @$query, $k.'='.$v;
301             }else{
302 1         3 push @$query, $k;
303             }
304             }
305             }
306              
307             # clean remaining :name in url
308 40 100       128 $path_info =~ s/:\w+//g if $path_info;
309              
310 40         64 my $query_string;
311 40 100       114 if (scalar @$query) {
312 9         20 $query_string = join('&', @$query);
313             }
314              
315 40         983 $self->env->{PATH_INFO} = $path_info;
316 40         960 $self->env->{QUERY_STRING} = $query_string;
317              
318 40   100     229 my $uri = $self->uri($path_info, $query_string || '');
319              
320 40         19491 my $request = HTTP::Request->new(
321             $self->method => $uri, $self->headers
322             );
323              
324 40 100       5467 if ( keys %$form_data ) {
325 2         55 $self->env->{'spore.form_data'} = $form;
326 2         6 my ( $content, $b ) = $self->_form_data($form);
327 2         11 $request->content($content);
328 2         50 $request->header('Content-Length' => length($content));
329 2         119 $request->header(
330             'Content-Type' => 'multipart/form-data; boundary=' . $b );
331             }
332              
333 40 100       202 if ( my $payload = $self->content ) {
334 1         7 $request->content($payload);
335 1 50       30 $request->header(
336             'Content-Type' => 'application/x-www-form-urlencoded' )
337             unless $request->header('Content-Type');
338             }
339              
340 40         295 return $request;
341             }
342              
343             1;
344              
345             __END__
346              
347             =pod
348              
349             =encoding UTF-8
350              
351             =head1 NAME
352              
353             Net::HTTP::Spore::Request - Net::HTTP::Spore::Request - Portable HTTP request object from SPORE env hash
354              
355             =head1 VERSION
356              
357             version 0.07
358              
359             =head1 SYNOPSIS
360              
361             use Net::HTTP::Spore::Request;
362              
363             my $request = Net::HTTP::Spore::Request->new($env);
364              
365             =head1 DESCRIPTION
366              
367             Net::HTTP::Spore::Request create a HTTP request
368              
369             =head1 METHODS
370              
371             =over 4
372              
373             =item new
374              
375             my $req = Net::HTTP::Spore::Request->new();
376              
377             Creates a new Net::HTTP::Spore::Request object.
378              
379             =item env
380              
381             my $env = $request->env;
382              
383             Get the environment for the given request
384              
385             =item method
386              
387             my $method = $request->method;
388              
389             Get the HTTP method for the given request
390              
391             =item port
392              
393             my $port = $request->port;
394              
395             Get the HTTP port from the URL
396              
397             =item script_name
398              
399             my $script_name = $request->script_name;
400              
401             Get the script name part from the URL
402              
403             =item path
404              
405             =item path_info
406              
407             my $path = $request->path_info;
408              
409             Get the path info part from the URL
410              
411             =item request_uri
412              
413             my $request_uri = $request->request_uri;
414              
415             Get the request uri from the URL
416              
417             =item scheme
418              
419             my $scheme = $request->scheme;
420              
421             Get the scheme from the URL
422              
423             =item secure
424              
425             my $secure = $request->secure;
426              
427             Return true if the URL is HTTPS
428              
429             =item content
430              
431             =item body
432              
433             =item input
434              
435             my $input = $request->input;
436              
437             Get the content that will be posted
438              
439             =item query_string
440              
441             =item headers
442              
443             =item header
444              
445             =item uri
446              
447             =item query_parameters
448              
449             =item base
450              
451             =item new_response
452              
453             =item finalize
454              
455             =back
456              
457             =head1 AUTHORS
458              
459             =over 4
460              
461             =item *
462              
463             Franck Cuny <franck.cuny@gmail.com>
464              
465             =item *
466              
467             Ash Berlin <ash@cpan.org>
468              
469             =item *
470              
471             Ahmad Fatoum <athreef@cpan.org>
472              
473             =back
474              
475             =head1 COPYRIGHT AND LICENSE
476              
477             This software is copyright (c) 2012 by Linkfluence.
478              
479             This is free software; you can redistribute it and/or modify it under
480             the same terms as the Perl 5 programming language system itself.
481              
482             =cut