File Coverage

blib/lib/Net/HTTP/Knork/Request.pm
Criterion Covered Total %
statement 80 152 52.6
branch 14 44 31.8
condition 12 32 37.5
subroutine 18 31 58.0
pod 13 19 68.4
total 137 278 49.2


line stmt bran cond sub pod time code
1             package Net::HTTP::Knork::Request;
2              
3             # ABSTRACT: HTTP request object from SPORE env hash
4              
5 6     6   29 use Moo;
  6         9  
  6         42  
6 6     6   1730 use Carp;
  6         19  
  6         350  
7 6     6   79 use URI;
  6         11  
  6         121  
8 6     6   29 use HTTP::Headers;
  6         6  
  6         137  
9 6     6   22 use HTTP::Request;
  6         6  
  6         130  
10 6     6   76 use URI::Escape;
  6         6  
  6         332  
11 6     6   3000 use MIME::Base64;
  6         3488  
  6         339  
12 6     6   2224 use Net::HTTP::Knork::Response;
  6         19  
  6         10097  
13              
14             has env => (
15             is => 'rw',
16             required => 1,
17             default => sub { { } },
18             );
19              
20             sub get_from_env {
21 16     16 0 162 return $_[0]->env->{$_[1]};
22             }
23              
24             sub set_to_env {
25 0     0 0 0 $_[0]->env->{$_[1]} = $_[2];
26             }
27              
28             has path => (
29             is => 'rw',
30             lazy => 1,
31             default => sub { $_[0]->env->{PATH_INFO} }
32             );
33              
34             has headers => (
35             is => 'rw',
36             lazy => 1,
37             handles => {
38             header => 'header',
39             },
40             default => sub {
41             my $self = shift;
42             my $env = $self->env;
43             my $h = HTTP::Headers->new(
44             map {
45             ( my $field = $_ ) =~ s/^HTTPS?_//;
46             ( $field => $env->{$_} );
47             } grep { /^(?:HTTP|CONTENT)/i } keys %$env
48             );
49             return $h;
50             },
51             );
52              
53             sub BUILDARGS {
54 8     8 0 5024 my $class = shift;
55              
56 8 50 33     64 if (@_ == 1 && !exists $_[0]->{env}) {
57 8         154 return {env => $_[0]};
58             }
59 0         0 return @_;
60             }
61              
62             sub set_or_get_from_env {
63 16     16 0 26 my ( $self, $var, $value ) = @_;
64 16 50       44 if ($value) {
65 0         0 $self->set_to_env( $var, $value );
66 0         0 return;
67             }
68             else {
69 16         37 return $self->get_from_env($var);
70             }
71             }
72              
73             sub method {
74 8     8 1 16 my ( $self, $value ) = @_;
75 8         27 return $self->set_or_get_from_env( 'REQUEST_METHOD', $value );
76             }
77              
78             sub host {
79 0     0 0 0 my ( $self, $value ) = @_;
80 0         0 return $self->set_or_get_from_env( 'SERVER_NAME', $value );
81             }
82              
83             sub port {
84 0     0 1 0 my ( $self, $value ) = @_;
85 0         0 return $self->set_or_get_from_env( 'SERVER_PORT', $value );
86             }
87              
88             sub script_name {
89 0     0 1 0 my ( $self, $value ) = @_;
90 0         0 return $self->set_or_get_from_env( 'SCRIPT_NAME', $value );
91             }
92              
93             sub request_uri {
94 0     0 1 0 my ( $self, $value ) = @_;
95 0         0 return $self->set_or_get_from_env( 'REQUEST_URI', $value );
96             }
97              
98             sub scheme {
99 0     0 1 0 my ( $self, $value ) = @_;
100 0         0 return $self->set_or_get_from_env( 'spore.url_scheme', $value );
101             }
102              
103             sub logger {
104 0     0 0 0 my ( $self, $value ) = @_;
105 0         0 return $self->set_or_get_from_env( 'sporex.logger', $value );
106             }
107              
108             sub body {
109 8     8 1 13 my ( $self, $value ) = @_;
110 8         19 return $self->set_or_get_from_env( 'spore.payload', $value );
111             }
112              
113             sub base {
114 0     0 1 0 my $self = shift;
115 0         0 URI->new( $self->_uri_base )->canonical;
116             }
117              
118 0     0 1 0 sub input { (shift)->body(@_) }
119 8     8 1 30 sub content { (shift)->body(@_) }
120 0     0 1 0 sub secure { $_[0]->scheme eq 'https' }
121              
122             # TODO
123             # need to refactor this method, with path_info and query_string construction
124             sub uri {
125 8     8 1 17 my ($self, $path_info, $query_string) = @_;
126              
127 8 50 33     43 if ( !defined $path_info || !defined $query_string ) {
128 0         0 ($path_info,$query_string) = $self->_path;
129             }
130              
131 8         27 my $base = $self->_uri_base;
132              
133 8         15 my $path_escape_class = '^A-Za-z0-9\-\._~/';
134              
135 8   50     51 my $path = URI::Escape::uri_escape($path_info // '', $path_escape_class);
136              
137 8 50 33     994 if (defined $query_string && length($query_string) > 0) {
138 0         0 $path .= '?' . $query_string;
139             }
140              
141 8 50       54 $base =~ s!/$!! if $path =~ m!^/!;
142 8         46 return URI->new( $base . $path )->canonical;
143             }
144              
145             sub _path {
146 0     0   0 my $self = shift;
147              
148 0         0 my $query_string;
149 0         0 my $path = $self->env->{PATH_INFO};
150 0 0       0 my @params = @{ $self->env->{'spore.params'} || [] };
  0         0  
151              
152 0         0 my $j = 0;
153 0         0 for (my $i = 0; $i < scalar @params; $i++) {
154 0         0 my $key = $params[$i];
155 0         0 my $value = $params[++$i];
156 0 0       0 if (!$value) {
157 0         0 $query_string .= $key;
158 0         0 last;
159             }
160 0 0 0     0 unless ( $path && $path =~ s/\:$key/$value/ ) {
161 0         0 $query_string .= $key . '=' . $value;
162 0 0 0     0 $query_string .= '&' if $query_string && scalar @params;
163             }
164             }
165              
166 0 0       0 $query_string =~ s/&$// if $query_string;
167 0         0 return ( $path, $query_string );
168             }
169              
170             sub _uri_base {
171 8     8   12 my $self = shift;
172 8         18 my $env = $self->env;
173              
174 8 50 50     222 my $uri =
      33        
      50        
175             ( $env->{'spore.url_scheme'} || "http" ) . "://"
176             . (
177             defined $env->{'spore.userinfo'}
178             ? $env->{'spore.userinfo'} . '@'
179             : ''
180             )
181             . (
182             $env->{HTTP_HOST}
183             || (( $env->{SERVER_NAME} || "" ) . ":"
184             . ( $env->{SERVER_PORT} || 80 ) )
185             ) . ( $env->{SCRIPT_NAME} || '/' );
186              
187 8         20 return $uri;
188             }
189              
190             # stolen from HTTP::Request::Common
191             sub _boundary {
192 0     0   0 my ( $self, $size ) = @_;
193              
194 0 0       0 return "xYzZy" unless $size;
195              
196 0         0 my $b =
197             MIME::Base64::encode( join( "", map chr( rand(256) ), 1 .. $size * 3 ),
198             "" );
199 0         0 $b =~ s/[\W]/X/g;
200 0         0 return $b;
201             }
202              
203             sub _form_data {
204 0     0   0 my ( $self, $data ) = @_;
205              
206 0         0 my $form_data;
207 0         0 foreach my $k ( keys %$data ) {
208 0         0 push @$form_data,
209             'Content-Disposition: form-data; name="'
210             . $k
211             . '"'."\r\n\r\n"
212             . $data->{$k};
213             }
214              
215 0         0 my $b = $self->_boundary(10);
216 0         0 my $t = [];
217 0         0 foreach (@$form_data) {
218 0         0 push @$t, '--', $b, "\r\n", $_, "\r\n";
219             }
220 0         0 push @$t, '--', $b, , '--', "\r\n";
221 0         0 my $content = join("", @$t);
222 0         0 return ($content, $b);
223             }
224              
225             sub new_response {
226 8     8 1 310 my $self = shift;
227 8         203 my $res = Net::HTTP::Knork::Response->new(@_);
228 8         1028 $res->request($self);
229 8         21 $res;
230             }
231              
232             sub finalize {
233 8     8 1 140 my $self = shift;
234              
235 8         29 my $path_info = $self->env->{PATH_INFO};
236              
237 8         23 my $form_data = $self->env->{'spore.form_data'};
238 8         19 my $headers = $self->env->{'spore.headers'};
239 8   100     89 my $params = $self->env->{'spore.params'} || [];
240              
241 8         14 my $query = [];
242 8         15 my $form = {};
243              
244 8         32 for ( my $i = 0 ; $i < scalar @$params ; $i++ ) {
245 3         5 my $k = $params->[$i];
246 3   50     18 my $v = $params->[++$i] // '';
247 3         4 my $modified = 0;
248              
249 3 50 33     50 if ($path_info && $path_info =~ s/\:$k/$v/) {
250 3         4 $modified++;
251             }
252              
253 3         15 foreach my $f_k (keys %$form_data) {
254 0         0 my $f_v = $form_data->{$f_k};
255 0 0       0 if ($f_v =~ s/^\:$k/$v/) {
256 0         0 $form->{$f_k} = $f_v;
257 0         0 $modified++;
258             }
259             }
260              
261 3         10 foreach my $h_k (keys %$headers) {
262 0         0 my $h_v = $headers->{$h_k};
263 0 0       0 if ($h_v =~ s/^\:$k/$v/) {
264 0         0 $self->header($h_k => $h_v);
265 0         0 $modified++;
266             }
267             }
268              
269 3 50       17 if ($modified == 0) {
270 0 0       0 if (defined $v) {
271 0         0 push @$query, $k.'='.$v;
272             }else{
273 0         0 push @$query, $k;
274             }
275             }
276             }
277              
278             # clean remaining :name in url
279 8 50       29 $path_info =~ s/:\w+//g if $path_info;
280              
281 8         10 my $query_string;
282 8 50       21 if (scalar @$query) {
283 0         0 $query_string = join('&', @$query);
284             }
285              
286 8         27 $self->env->{PATH_INFO} = $path_info;
287 8         37 $self->env->{QUERY_STRING} = $query_string;
288              
289 8   50     51 my $uri = $self->uri($path_info, $query_string || '');
290              
291 8         1816 my $request = HTTP::Request->new(
292             $self->method => $uri, $self->headers
293             );
294              
295 8 50       1065 if ( keys %$form_data ) {
296 0         0 $self->env->{'spore.form_data'} = $form;
297 0         0 my ( $content, $b ) = $self->_form_data($form);
298 0         0 $request->content($content);
299 0         0 $request->header('Content-Length' => length($content));
300 0         0 $request->header(
301             'Content-Type' => 'multipart/form-data; boundary=' . $b );
302             }
303              
304 8 100       28 if ( my $payload = $self->content ) {
305 4         29 $request->content($payload);
306 4 50       109 $request->header(
307             'Content-Type' => 'application/x-www-form-urlencoded' )
308             unless $request->header('Content-Type');
309             }
310              
311 8         374 return $request;
312             }
313              
314             1;
315              
316             __END__