File Coverage

blib/lib/Net/HTTP/Knork/Request.pm
Criterion Covered Total %
statement 79 165 47.8
branch 15 62 24.1
condition 12 32 37.5
subroutine 17 30 56.6
pod 13 18 72.2
total 136 307 44.3


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