home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / share / perl5 / HTTP / Request / Common.pm
Encoding:
Perl POD Document  |  2004-11-15  |  12.7 KB  |  479 lines

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