File Coverage

blib/lib/HTTP/Request/Common.pm
Criterion Covered Total %
statement 175 181 96.6
branch 74 88 84.0
condition 17 22 77.2
subroutine 18 18 100.0
pod 6 9 66.6
total 290 318 91.1


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