File Coverage

blib/lib/HTTP/Request/Common.pm
Criterion Covered Total %
statement 174 180 96.6
branch 72 86 83.7
condition 17 22 77.2
subroutine 18 18 100.0
pod 6 9 66.6
total 287 315 91.1


line stmt bran cond sub pod time code
1             package HTTP::Request::Common;
2              
3 3     3   243286 use strict;
  3         6  
  3         110  
4 3     3   14 use warnings;
  3         10  
  3         369  
5              
6             our $VERSION = '7.01';
7              
8             our $DYNAMIC_FILE_UPLOAD ||= 0; # make it defined (don't know why)
9             our $READ_BUFFER_SIZE = 8192;
10              
11 3     3   20 use Exporter 5.57 'import';
  3         57  
  3         201  
12              
13             our @EXPORT =qw(GET HEAD PUT PATCH POST OPTIONS);
14             our @EXPORT_OK = qw($DYNAMIC_FILE_UPLOAD DELETE);
15              
16             require HTTP::Request;
17 3     3   15 use Carp();
  3         16  
  3         69  
18 3     3   14 use File::Spec;
  3         6  
  3         3107  
19              
20             my $CRLF = "\015\012"; # "\r\n" is not portable
21              
22 1     1 1 556031 sub GET { _simple_req('GET', @_); }
23 3     3 1 13 sub HEAD { _simple_req('HEAD', @_); }
24 1     1   6 sub DELETE { _simple_req('DELETE', @_); }
25 2     2 1 60 sub PATCH { request_type_with_data('PATCH', @_); }
26 14     14 1 16104 sub POST { request_type_with_data('POST', @_); }
27 3     3 1 14 sub PUT { request_type_with_data('PUT', @_); }
28 2     2 1 37 sub OPTIONS { request_type_with_data('OPTIONS', @_); }
29              
30             sub request_type_with_data
31             {
32 22     22 0 507486 my $type = shift;
33 22         39 my $url = shift;
34 22         129 my $req = HTTP::Request->new($type => $url);
35 22         44 my $content;
36 22 100 100     113 $content = shift if @_ and ref $_[0];
37 22         46 my($k, $v);
38 22         88 while (($k,$v) = splice(@_, 0, 2)) {
39 26 100       63 if (lc($k) eq 'content') {
40 11         34 $content = $v;
41             }
42             else {
43 15         78 $req->push_header($k, $v);
44             }
45             }
46 22         77 my $ct = $req->header('Content-Type');
47 22 100 100     65 unless ($ct) {
48 11         19 $ct = 'application/x-www-form-urlencoded';
49             }
50             elsif ($ct eq 'form-data') {
51             $ct = 'multipart/form-data';
52             }
53              
54 22 100       43 if (ref $content) {
55 14 100       68 if ($ct =~ m,^multipart/form-data\s*(;|$),i) {
56 7         1893 require HTTP::Headers::Util;
57 7         28 my @v = HTTP::Headers::Util::split_header_words($ct);
58 7 50       19 Carp::carp("Multiple Content-Type headers") if @v > 1;
59 7         11 @v = @{$v[0]};
  7         13  
60              
61 7         14 my $boundary;
62             my $boundary_index;
63 7         19 for (my @tmp = @v; @tmp;) {
64 8         18 my($k, $v) = splice(@tmp, 0, 2);
65 8 100       27 if ($k eq "boundary") {
66 1         1 $boundary = $v;
67 1         2 $boundary_index = @v - @tmp - 1;
68 1         1 last;
69             }
70             }
71              
72 7         23 ($content, $boundary) = form_data($content, $boundary, $req);
73              
74 7 100       33 if ($boundary_index) {
75 1         3 $v[$boundary_index] = $boundary;
76             }
77             else {
78 6         13 push(@v, boundary => $boundary);
79             }
80              
81 7         25 $ct = HTTP::Headers::Util::join_header_words(@v);
82             }
83             else {
84             # We use a temporary URI object to format
85             # the application/x-www-form-urlencoded content.
86 7         51 require URI;
87 7         28 my $url = URI->new('http:');
88 7 100       412 $url->query_form(ref($content) eq "HASH" ? %$content : @$content);
89 7         570 $content = $url->query;
90             }
91             }
92              
93 22         121 $req->header('Content-Type' => $ct); # might be redundant
94 22 100       41 if (defined($content)) {
95 17 100       74 $req->header('Content-Length' =>
96             length($content)) unless ref($content);
97 17         57 $req->content($content);
98             }
99             else {
100 5         10 $req->header('Content-Length' => 0);
101             }
102 22         177 $req;
103             }
104              
105              
106             sub _simple_req
107             {
108 5     5   25 my($method, $url) = splice(@_, 0, 2);
109 5         37 my $req = HTTP::Request->new($method => $url);
110 5         17 my($k, $v);
111 5         0 my $content;
112 5         29 while (($k,$v) = splice(@_, 0, 2)) {
113 5 100       19 if (lc($k) eq 'content') {
114 2         15 $req->add_content($v);
115 2         10 $content++;
116             }
117             else {
118 3         27 $req->push_header($k, $v);
119             }
120             }
121 5 100 100     24 if ($content && !defined($req->header("Content-Length"))) {
122 1         3 $req->header("Content-Length", length(${$req->content_ref}));
  1         8  
123             }
124 5         53 $req;
125             }
126              
127              
128             sub form_data # RFC1867
129             {
130 7     7 0 20 my($data, $boundary, $req) = @_;
131 7 50       29 my @data = ref($data) eq "HASH" ? %$data : @$data; # copy
132 7         16 my $fhparts;
133             my @parts;
134 7         22 while (my ($k,$v) = splice(@data, 0, 2)) {
135 16 100       46 if (!ref($v)) {
136 12         20 $k =~ s/([\\\"])/\\$1/g; # escape quotes and backslashes
137 3     3   25 no warnings 'uninitialized';
  3         7  
  3         4355  
138 12         43 push(@parts,
139             qq(Content-Disposition: form-data; name="$k"$CRLF$CRLF$v));
140             }
141             else {
142 4         10 my($file, $usename, @headers) = @$v;
143 4 100       11 unless (defined $usename) {
144 3         3 $usename = $file;
145 3 100       28 $usename = (File::Spec->splitpath($usename))[-1] if defined($usename);
146             }
147 4         10 $k =~ s/([\\\"])/\\$1/g;
148 4         8 my $disp = qq(form-data; name="$k");
149 4 100 66     14 if (defined($usename) and length($usename)) {
150 3         15 $usename =~ s/([\\\"])/\\$1/g;
151 3         6 $disp .= qq(; filename="$usename");
152             }
153 4         7 my $content = "";
154 4         37 my $h = HTTP::Headers->new(@headers);
155 4 100       8 if ($file) {
156 2 50       76 open(my $fh, "<", $file) or Carp::croak("Can't open file $file: $!");
157 2         5 binmode($fh);
158 2 100       5 if ($DYNAMIC_FILE_UPLOAD) {
159             # will read file later, close it now in order to
160             # not accumulate to many open file handles
161 1         7 close($fh);
162 1         3 $content = \$file;
163             }
164             else {
165 1         6 local($/) = undef; # slurp files
166 1         42 $content = <$fh>;
167 1         10 close($fh);
168             }
169 2 50       8 unless ($h->header("Content-Type")) {
170 2         473 require LWP::MediaTypes;
171 2         18611 LWP::MediaTypes::guess_media_type($file, $h);
172             }
173             }
174 4 50       37 if ($h->header("Content-Disposition")) {
175             # just to get it sorted first
176 0         0 $disp = $h->header("Content-Disposition");
177 0         0 $h->remove_header("Content-Disposition");
178             }
179 4 100       7 if ($h->header("Content")) {
180 2         5 $content = $h->header("Content");
181 2         5 $h->remove_header("Content");
182             }
183 4         19 my $head = join($CRLF, "Content-Disposition: $disp",
184             $h->as_string($CRLF),
185             "");
186 4 100       10 if (ref $content) {
187 1         5 push(@parts, [$head, $$content]);
188 1         97 $fhparts++;
189             }
190             else {
191 3         25 push(@parts, $head . $content);
192             }
193             }
194             }
195 7 100       21 return ("", "none") unless @parts;
196              
197 6         7 my $content;
198 6 100       15 if ($fhparts) {
199 1 50       7 $boundary = boundary(10) # hopefully enough randomness
200             unless $boundary;
201              
202             # add the boundaries to the @parts array
203 1         4 for (1..@parts-1) {
204 4         9 splice(@parts, $_*2-1, 0, "$CRLF--$boundary$CRLF");
205             }
206 1         3 unshift(@parts, "--$boundary$CRLF");
207 1         3 push(@parts, "$CRLF--$boundary--$CRLF");
208              
209             # See if we can generate Content-Length header
210 1         1 my $length = 0;
211 1         3 for (@parts) {
212 11 100       12 if (ref $_) {
213 1         3 my ($head, $f) = @$_;
214 1         2 my $file_size;
215 1 50 33     21 unless ( -f $f && ($file_size = -s _) ) {
216             # The file is either a dynamic file like /dev/audio
217             # or perhaps a file in the /proc file system where
218             # stat may return a 0 size even though reading it
219             # will produce data. So we cannot make
220             # a Content-Length header.
221 0         0 undef $length;
222 0         0 last;
223             }
224 1         3 $length += $file_size + length $head;
225             }
226             else {
227 10         11 $length += length;
228             }
229             }
230 1 50       6 $length && $req->header('Content-Length' => $length);
231              
232             # set up a closure that will return content piecemeal
233             $content = sub {
234 7     7   25 for (;;) {
235 8 100       13 unless (@parts) {
236 1 50 33     5 defined $length && $length != 0 &&
237             Carp::croak "length of data sent did not match calculated Content-Length header. Probably because uploaded file changed in size during transfer.";
238 1         2 return;
239             }
240 7         11 my $p = shift @parts;
241 7 100       14 unless (ref $p) {
242 2   100     18 $p .= shift @parts while @parts && !ref($parts[0]);
243 2 50       5 defined $length && ($length -= length $p);
244 2         5 return $p;
245             }
246 5         8 my($buf, $fh) = @$p;
247 5 100       10 unless (ref($fh)) {
248 1         1 my $file = $fh;
249 1         2 undef($fh);
250 1 50       38 open($fh, "<", $file) || Carp::croak("Can't open file $file: $!");
251 1         3 binmode($fh);
252             }
253 5         5 my $buflength = length $buf;
254 5         85 my $n = read($fh, $buf, $READ_BUFFER_SIZE, $buflength);
255 5 100       12 if ($n) {
256 4         6 $buflength += $n;
257 4         9 unshift(@parts, ["", $fh]);
258             }
259             else {
260 1         12 close($fh);
261             }
262 5 100       14 if ($buflength) {
263 4 50       8 defined $length && ($length -= $buflength);
264 4         13 return $buf
265             }
266             }
267 1         8 };
268              
269             }
270             else {
271 5 100       16 $boundary = boundary() unless $boundary;
272              
273 5         8 my $bno = 0;
274             CHECK_BOUNDARY:
275             {
276 5         8 for (@parts) {
  5         11  
277 11 50       27 if (index($_, $boundary) >= 0) {
278             # must have a better boundary
279 0         0 $boundary = boundary(++$bno);
280 0         0 redo CHECK_BOUNDARY;
281             }
282             }
283 5         9 last;
284             }
285 5         27 $content = "--$boundary$CRLF" .
286             join("$CRLF--$boundary$CRLF", @parts) .
287             "$CRLF--$boundary--$CRLF";
288             }
289              
290 6 50       30 wantarray ? ($content, $boundary) : $content;
291             }
292              
293              
294             sub boundary
295             {
296 5   100 5 0 41 my $size = shift || return "xYzZY";
297 1         512 require MIME::Base64;
298 1         813 my $b = MIME::Base64::encode(join("", map chr(rand(256)), 1..$size*3), "");
299 1         5 $b =~ s/[\W]/X/g; # ensure alnum only
300 1         3 $b;
301             }
302              
303             1;
304              
305             =pod
306              
307             =encoding UTF-8
308              
309             =head1 NAME
310              
311             HTTP::Request::Common - Construct common HTTP::Request objects
312              
313             =head1 VERSION
314              
315             version 7.01
316              
317             =head1 SYNOPSIS
318              
319             use HTTP::Request::Common;
320             $ua = LWP::UserAgent->new;
321             $ua->request(GET 'http://www.sn.no/');
322             $ua->request(POST 'http://somewhere/foo', foo => bar, bar => foo);
323             $ua->request(PATCH 'http://somewhere/foo', foo => bar, bar => foo);
324             $ua->request(PUT 'http://somewhere/foo', foo => bar, bar => foo);
325             $ua->request(OPTIONS 'http://somewhere/foo', foo => bar, bar => foo);
326              
327             =head1 DESCRIPTION
328              
329             This module provides functions that return newly created C
330             objects. These functions are usually more convenient to use than the
331             standard C constructor for the most common requests.
332              
333             Note that L has several convenience methods, including
334             C, C, C, C and C.
335              
336             The following functions are provided:
337              
338             =over 4
339              
340             =item GET $url
341              
342             =item GET $url, Header => Value,...
343              
344             The C function returns an L object initialized with
345             the "GET" method and the specified URL. It is roughly equivalent to the
346             following call
347              
348             HTTP::Request->new(
349             GET => $url,
350             HTTP::Headers->new(Header => Value,...),
351             )
352              
353             but is less cluttered. What is different is that a header named
354             C will initialize the content part of the request instead of
355             setting a header field. Note that GET requests should normally not
356             have a content, so this hack makes more sense for the C, C
357             and C functions described below.
358              
359             The C method of L exists as a shortcut for
360             C<< $ua->request(GET ...) >>.
361              
362             =item HEAD $url
363              
364             =item HEAD $url, Header => Value,...
365              
366             Like GET() but the method in the request is "HEAD".
367              
368             The C method of L exists as a shortcut for
369             C<< $ua->request(HEAD ...) >>.
370              
371             =item DELETE $url
372              
373             =item DELETE $url, Header => Value,...
374              
375             Like C but the method in the request is C. This function
376             is not exported by default.
377              
378             =item PATCH $url
379              
380             =item PATCH $url, Header => Value,...
381              
382             =item PATCH $url, $form_ref, Header => Value,...
383              
384             =item PATCH $url, Header => Value,..., Content => $form_ref
385              
386             =item PATCH $url, Header => Value,..., Content => $content
387              
388             The same as C below, but the method in the request is C.
389              
390             =item PUT $url
391              
392             =item PUT $url, Header => Value,...
393              
394             =item PUT $url, $form_ref, Header => Value,...
395              
396             =item PUT $url, Header => Value,..., Content => $form_ref
397              
398             =item PUT $url, Header => Value,..., Content => $content
399              
400             The same as C below, but the method in the request is C
401              
402             =item OPTIONS $url
403              
404             =item OPTIONS $url, Header => Value,...
405              
406             =item OPTIONS $url, $form_ref, Header => Value,...
407              
408             =item OPTIONS $url, Header => Value,..., Content => $form_ref
409              
410             =item OPTIONS $url, Header => Value,..., Content => $content
411              
412             The same as C below, but the method in the request is C
413              
414             This was added in version 6.21, so you should require that in your code:
415              
416             use HTTP::Request::Common 6.21;
417              
418             =item POST $url
419              
420             =item POST $url, Header => Value,...
421              
422             =item POST $url, $form_ref, Header => Value,...
423              
424             =item POST $url, Header => Value,..., Content => $form_ref
425              
426             =item POST $url, Header => Value,..., Content => $content
427              
428             C, C and C all work with the same parameters.
429              
430             %data = ( title => 'something', body => something else' );
431             $ua = LWP::UserAgent->new();
432             $request = HTTP::Request::Common::POST( $url, [ %data ] );
433             $response = $ua->request($request);
434              
435             They take a second optional array or hash reference
436             parameter C<$form_ref>. The content can also be specified
437             directly using the C pseudo-header, and you may also provide
438             the C<$form_ref> this way.
439              
440             The C pseudo-header steals a bit of the header field namespace as
441             there is no way to directly specify a header that is actually called
442             "Content". If you really need this you must update the request
443             returned in a separate statement.
444              
445             The C<$form_ref> argument can be used to pass key/value pairs for the
446             form content. By default we will initialize a request using the
447             C content type. This means that
448             you can emulate an HTML Eform> POSTing like this:
449              
450             POST 'http://www.perl.org/survey.cgi',
451             [ name => 'Gisle Aas',
452             email => 'gisle@aas.no',
453             gender => 'M',
454             born => '1964',
455             perc => '3%',
456             ];
457              
458             This will create an L object that looks like this:
459              
460             POST http://www.perl.org/survey.cgi
461             Content-Length: 66
462             Content-Type: application/x-www-form-urlencoded
463              
464             name=Gisle%20Aas&email=gisle%40aas.no&gender=M&born=1964&perc=3%25
465              
466             Multivalued form fields can be specified by either repeating the field
467             name or by passing the value as an array reference.
468              
469             The POST method also supports the C content used
470             for I as specified in RFC 1867. You trigger
471             this content format by specifying a content type of C<'form-data'> as
472             one of the request headers. If one of the values in the C<$form_ref> is
473             an array reference, then it is treated as a file part specification
474             with the following interpretation:
475              
476             [ $file, $filename, Header => Value... ]
477             [ undef, $filename, Header => Value,..., Content => $content ]
478              
479             The first value in the array ($file) is the name of a file to open.
480             This file will be read and its content placed in the request. The
481             routine will croak if the file can't be opened. Use an C as
482             $file value if you want to specify the content directly with a
483             C header. The $filename is the filename to report in the
484             request. If this value is undefined, then the basename of the $file
485             will be used. You can specify an empty string as $filename if you
486             want to suppress sending the filename when you provide a $file value.
487              
488             If a $file is provided by no C header, then C
489             and C will be filled in automatically with the values
490             returned by C
491              
492             Sending my F<~/.profile> to the survey used as example above can be
493             achieved by this:
494              
495             POST 'http://www.perl.org/survey.cgi',
496             Content_Type => 'form-data',
497             Content => [ name => 'Gisle Aas',
498             email => 'gisle@aas.no',
499             gender => 'M',
500             born => '1964',
501             init => ["$ENV{HOME}/.profile"],
502             ]
503              
504             This will create an L object that almost looks this (the
505             boundary and the content of your F<~/.profile> is likely to be
506             different):
507              
508             POST http://www.perl.org/survey.cgi
509             Content-Length: 388
510             Content-Type: multipart/form-data; boundary="6G+f"
511              
512             --6G+f
513             Content-Disposition: form-data; name="name"
514              
515             Gisle Aas
516             --6G+f
517             Content-Disposition: form-data; name="email"
518              
519             gisle@aas.no
520             --6G+f
521             Content-Disposition: form-data; name="gender"
522              
523             M
524             --6G+f
525             Content-Disposition: form-data; name="born"
526              
527             1964
528             --6G+f
529             Content-Disposition: form-data; name="init"; filename=".profile"
530             Content-Type: text/plain
531              
532             PATH=/local/perl/bin:$PATH
533             export PATH
534              
535             --6G+f--
536              
537             If you set the C<$DYNAMIC_FILE_UPLOAD> variable (exportable) to some TRUE
538             value, then you get back a request object with a subroutine closure as
539             the content attribute. This subroutine will read the content of any
540             files on demand and return it in suitable chunks. This allow you to
541             upload arbitrary big files without using lots of memory. You can even
542             upload infinite files like F if you wish; however, if
543             the file is not a plain file, there will be no C header
544             defined for the request. Not all servers (or server
545             applications) like this. Also, if the file(s) change in size between
546             the time the C is calculated and the time that the last
547             chunk is delivered, the subroutine will C.
548              
549             The C method of L exists as a shortcut for
550             C<< $ua->request(POST ...) >>.
551              
552             =back
553              
554             =head1 SEE ALSO
555              
556             L, L
557              
558             Also, there are some examples in L that you might
559             find useful. For example, batch requests are explained there.
560              
561             =head1 AUTHOR
562              
563             Gisle Aas
564              
565             =head1 COPYRIGHT AND LICENSE
566              
567             This software is copyright (c) 1994 by Gisle Aas.
568              
569             This is free software; you can redistribute it and/or modify it under
570             the same terms as the Perl 5 programming language system itself.
571              
572             =cut
573              
574             __END__