|
Packit |
a09cf7 |
package HTTP::Request::Common;
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
use strict;
|
|
Packit |
a09cf7 |
use warnings;
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
our $VERSION = '6.18';
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
our $DYNAMIC_FILE_UPLOAD ||= 0; # make it defined (don't know why)
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
use Exporter 5.57 'import';
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
our @EXPORT =qw(GET HEAD PUT PATCH POST);
|
|
Packit |
a09cf7 |
our @EXPORT_OK = qw($DYNAMIC_FILE_UPLOAD DELETE);
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
require HTTP::Request;
|
|
Packit |
a09cf7 |
use Carp();
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
my $CRLF = "\015\012"; # "\r\n" is not portable
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
sub GET { _simple_req('GET', @_); }
|
|
Packit |
a09cf7 |
sub HEAD { _simple_req('HEAD', @_); }
|
|
Packit |
a09cf7 |
sub DELETE { _simple_req('DELETE', @_); }
|
|
Packit |
a09cf7 |
sub PATCH { request_type_with_data('PATCH', @_); }
|
|
Packit |
a09cf7 |
sub POST { request_type_with_data('POST', @_); }
|
|
Packit |
a09cf7 |
sub PUT { request_type_with_data('PUT', @_); }
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
sub request_type_with_data
|
|
Packit |
a09cf7 |
{
|
|
Packit |
a09cf7 |
my $type = shift;
|
|
Packit |
a09cf7 |
my $url = shift;
|
|
Packit |
a09cf7 |
my $req = HTTP::Request->new($type => $url);
|
|
Packit |
a09cf7 |
my $content;
|
|
Packit |
a09cf7 |
$content = shift if @_ and ref $_[0];
|
|
Packit |
a09cf7 |
my($k, $v);
|
|
Packit |
a09cf7 |
while (($k,$v) = splice(@_, 0, 2)) {
|
|
Packit |
a09cf7 |
if (lc($k) eq 'content') {
|
|
Packit |
a09cf7 |
$content = $v;
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
else {
|
|
Packit |
a09cf7 |
$req->push_header($k, $v);
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
my $ct = $req->header('Content-Type');
|
|
Packit |
a09cf7 |
unless ($ct) {
|
|
Packit |
a09cf7 |
$ct = 'application/x-www-form-urlencoded';
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
elsif ($ct eq 'form-data') {
|
|
Packit |
a09cf7 |
$ct = 'multipart/form-data';
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
if (ref $content) {
|
|
Packit |
a09cf7 |
if ($ct =~ m,^multipart/form-data\s*(;|$),i) {
|
|
Packit |
a09cf7 |
require HTTP::Headers::Util;
|
|
Packit |
a09cf7 |
my @v = HTTP::Headers::Util::split_header_words($ct);
|
|
Packit |
a09cf7 |
Carp::carp("Multiple Content-Type headers") if @v > 1;
|
|
Packit |
a09cf7 |
@v = @{$v[0]};
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
my $boundary;
|
|
Packit |
a09cf7 |
my $boundary_index;
|
|
Packit |
a09cf7 |
for (my @tmp = @v; @tmp;) {
|
|
Packit |
a09cf7 |
my($k, $v) = splice(@tmp, 0, 2);
|
|
Packit |
a09cf7 |
if ($k eq "boundary") {
|
|
Packit |
a09cf7 |
$boundary = $v;
|
|
Packit |
a09cf7 |
$boundary_index = @v - @tmp - 1;
|
|
Packit |
a09cf7 |
last;
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
($content, $boundary) = form_data($content, $boundary, $req);
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
if ($boundary_index) {
|
|
Packit |
a09cf7 |
$v[$boundary_index] = $boundary;
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
else {
|
|
Packit |
a09cf7 |
push(@v, boundary => $boundary);
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
$ct = HTTP::Headers::Util::join_header_words(@v);
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
else {
|
|
Packit |
a09cf7 |
# We use a temporary URI object to format
|
|
Packit |
a09cf7 |
# the application/x-www-form-urlencoded content.
|
|
Packit |
a09cf7 |
require URI;
|
|
Packit |
a09cf7 |
my $url = URI->new('http:');
|
|
Packit |
a09cf7 |
$url->query_form(ref($content) eq "HASH" ? %$content : @$content);
|
|
Packit |
a09cf7 |
$content = $url->query;
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
# HTML/4.01 says that line breaks are represented as "CR LF" pairs (i.e., `%0D%0A')
|
|
Packit |
a09cf7 |
$content =~ s/(?
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
$req->header('Content-Type' => $ct); # might be redundant
|
|
Packit |
a09cf7 |
if (defined($content)) {
|
|
Packit |
a09cf7 |
$req->header('Content-Length' =>
|
|
Packit |
a09cf7 |
length($content)) unless ref($content);
|
|
Packit |
a09cf7 |
$req->content($content);
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
else {
|
|
Packit |
a09cf7 |
$req->header('Content-Length' => 0);
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
$req;
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
sub _simple_req
|
|
Packit |
a09cf7 |
{
|
|
Packit |
a09cf7 |
my($method, $url) = splice(@_, 0, 2);
|
|
Packit |
a09cf7 |
my $req = HTTP::Request->new($method => $url);
|
|
Packit |
a09cf7 |
my($k, $v);
|
|
Packit |
a09cf7 |
my $content;
|
|
Packit |
a09cf7 |
while (($k,$v) = splice(@_, 0, 2)) {
|
|
Packit |
a09cf7 |
if (lc($k) eq 'content') {
|
|
Packit |
a09cf7 |
$req->add_content($v);
|
|
Packit |
a09cf7 |
$content++;
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
else {
|
|
Packit |
a09cf7 |
$req->push_header($k, $v);
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
if ($content && !defined($req->header("Content-Length"))) {
|
|
Packit |
a09cf7 |
$req->header("Content-Length", length(${$req->content_ref}));
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
$req;
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
sub form_data # RFC1867
|
|
Packit |
a09cf7 |
{
|
|
Packit |
a09cf7 |
my($data, $boundary, $req) = @_;
|
|
Packit |
a09cf7 |
my @data = ref($data) eq "HASH" ? %$data : @$data; # copy
|
|
Packit |
a09cf7 |
my $fhparts;
|
|
Packit |
a09cf7 |
my @parts;
|
|
Packit |
a09cf7 |
while (my ($k,$v) = splice(@data, 0, 2)) {
|
|
Packit |
a09cf7 |
if (!ref($v)) {
|
|
Packit |
a09cf7 |
$k =~ s/([\\\"])/\\$1/g; # escape quotes and backslashes
|
|
Packit |
a09cf7 |
no warnings 'uninitialized';
|
|
Packit |
a09cf7 |
push(@parts,
|
|
Packit |
a09cf7 |
qq(Content-Disposition: form-data; name="$k"$CRLF$CRLF$v));
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
else {
|
|
Packit |
a09cf7 |
my($file, $usename, @headers) = @$v;
|
|
Packit |
a09cf7 |
unless (defined $usename) {
|
|
Packit |
a09cf7 |
$usename = $file;
|
|
Packit |
a09cf7 |
$usename =~ s,.*/,, if defined($usename);
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
$k =~ s/([\\\"])/\\$1/g;
|
|
Packit |
a09cf7 |
my $disp = qq(form-data; name="$k");
|
|
Packit |
a09cf7 |
if (defined($usename) and length($usename)) {
|
|
Packit |
a09cf7 |
$usename =~ s/([\\\"])/\\$1/g;
|
|
Packit |
a09cf7 |
$disp .= qq(; filename="$usename");
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
my $content = "";
|
|
Packit |
a09cf7 |
my $h = HTTP::Headers->new(@headers);
|
|
Packit |
a09cf7 |
if ($file) {
|
|
Packit |
a09cf7 |
open(my $fh, "<", $file) or Carp::croak("Can't open file $file: $!");
|
|
Packit |
a09cf7 |
binmode($fh);
|
|
Packit |
a09cf7 |
if ($DYNAMIC_FILE_UPLOAD) {
|
|
Packit |
a09cf7 |
# will read file later, close it now in order to
|
|
Packit |
a09cf7 |
# not accumulate to many open file handles
|
|
Packit |
a09cf7 |
close($fh);
|
|
Packit |
a09cf7 |
$content = \$file;
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
else {
|
|
Packit |
a09cf7 |
local($/) = undef; # slurp files
|
|
Packit |
a09cf7 |
$content = <$fh>;
|
|
Packit |
a09cf7 |
close($fh);
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
unless ($h->header("Content-Type")) {
|
|
Packit |
a09cf7 |
require LWP::MediaTypes;
|
|
Packit |
a09cf7 |
LWP::MediaTypes::guess_media_type($file, $h);
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
if ($h->header("Content-Disposition")) {
|
|
Packit |
a09cf7 |
# just to get it sorted first
|
|
Packit |
a09cf7 |
$disp = $h->header("Content-Disposition");
|
|
Packit |
a09cf7 |
$h->remove_header("Content-Disposition");
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
if ($h->header("Content")) {
|
|
Packit |
a09cf7 |
$content = $h->header("Content");
|
|
Packit |
a09cf7 |
$h->remove_header("Content");
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
my $head = join($CRLF, "Content-Disposition: $disp",
|
|
Packit |
a09cf7 |
$h->as_string($CRLF),
|
|
Packit |
a09cf7 |
"");
|
|
Packit |
a09cf7 |
if (ref $content) {
|
|
Packit |
a09cf7 |
push(@parts, [$head, $$content]);
|
|
Packit |
a09cf7 |
$fhparts++;
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
else {
|
|
Packit |
a09cf7 |
push(@parts, $head . $content);
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
return ("", "none") unless @parts;
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
my $content;
|
|
Packit |
a09cf7 |
if ($fhparts) {
|
|
Packit |
a09cf7 |
$boundary = boundary(10) # hopefully enough randomness
|
|
Packit |
a09cf7 |
unless $boundary;
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
# add the boundaries to the @parts array
|
|
Packit |
a09cf7 |
for (1..@parts-1) {
|
|
Packit |
a09cf7 |
splice(@parts, $_*2-1, 0, "$CRLF--$boundary$CRLF");
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
unshift(@parts, "--$boundary$CRLF");
|
|
Packit |
a09cf7 |
push(@parts, "$CRLF--$boundary--$CRLF");
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
# See if we can generate Content-Length header
|
|
Packit |
a09cf7 |
my $length = 0;
|
|
Packit |
a09cf7 |
for (@parts) {
|
|
Packit |
a09cf7 |
if (ref $_) {
|
|
Packit |
a09cf7 |
my ($head, $f) = @$_;
|
|
Packit |
a09cf7 |
my $file_size;
|
|
Packit |
a09cf7 |
unless ( -f $f && ($file_size = -s _) ) {
|
|
Packit |
a09cf7 |
# The file is either a dynamic file like /dev/audio
|
|
Packit |
a09cf7 |
# or perhaps a file in the /proc file system where
|
|
Packit |
a09cf7 |
# stat may return a 0 size even though reading it
|
|
Packit |
a09cf7 |
# will produce data. So we cannot make
|
|
Packit |
a09cf7 |
# a Content-Length header.
|
|
Packit |
a09cf7 |
undef $length;
|
|
Packit |
a09cf7 |
last;
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
$length += $file_size + length $head;
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
else {
|
|
Packit |
a09cf7 |
$length += length;
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
$length && $req->header('Content-Length' => $length);
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
# set up a closure that will return content piecemeal
|
|
Packit |
a09cf7 |
$content = sub {
|
|
Packit |
a09cf7 |
for (;;) {
|
|
Packit |
a09cf7 |
unless (@parts) {
|
|
Packit |
a09cf7 |
defined $length && $length != 0 &&
|
|
Packit |
a09cf7 |
Carp::croak "length of data sent did not match calculated Content-Length header. Probably because uploaded file changed in size during transfer.";
|
|
Packit |
a09cf7 |
return;
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
my $p = shift @parts;
|
|
Packit |
a09cf7 |
unless (ref $p) {
|
|
Packit |
a09cf7 |
$p .= shift @parts while @parts && !ref($parts[0]);
|
|
Packit |
a09cf7 |
defined $length && ($length -= length $p);
|
|
Packit |
a09cf7 |
return $p;
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
my($buf, $fh) = @$p;
|
|
Packit |
a09cf7 |
unless (ref($fh)) {
|
|
Packit |
a09cf7 |
my $file = $fh;
|
|
Packit |
a09cf7 |
undef($fh);
|
|
Packit |
a09cf7 |
open($fh, "<", $file) || Carp::croak("Can't open file $file: $!");
|
|
Packit |
a09cf7 |
binmode($fh);
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
my $buflength = length $buf;
|
|
Packit |
a09cf7 |
my $n = read($fh, $buf, 2048, $buflength);
|
|
Packit |
a09cf7 |
if ($n) {
|
|
Packit |
a09cf7 |
$buflength += $n;
|
|
Packit |
a09cf7 |
unshift(@parts, ["", $fh]);
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
else {
|
|
Packit |
a09cf7 |
close($fh);
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
if ($buflength) {
|
|
Packit |
a09cf7 |
defined $length && ($length -= $buflength);
|
|
Packit |
a09cf7 |
return $buf
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
};
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
else {
|
|
Packit |
a09cf7 |
$boundary = boundary() unless $boundary;
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
my $bno = 0;
|
|
Packit |
a09cf7 |
CHECK_BOUNDARY:
|
|
Packit |
a09cf7 |
{
|
|
Packit |
a09cf7 |
for (@parts) {
|
|
Packit |
a09cf7 |
if (index($_, $boundary) >= 0) {
|
|
Packit |
a09cf7 |
# must have a better boundary
|
|
Packit |
a09cf7 |
$boundary = boundary(++$bno);
|
|
Packit |
a09cf7 |
redo CHECK_BOUNDARY;
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
last;
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
$content = "--$boundary$CRLF" .
|
|
Packit |
a09cf7 |
join("$CRLF--$boundary$CRLF", @parts) .
|
|
Packit |
a09cf7 |
"$CRLF--$boundary--$CRLF";
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
wantarray ? ($content, $boundary) : $content;
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
sub boundary
|
|
Packit |
a09cf7 |
{
|
|
Packit |
a09cf7 |
my $size = shift || return "xYzZY";
|
|
Packit |
a09cf7 |
require MIME::Base64;
|
|
Packit |
a09cf7 |
my $b = MIME::Base64::encode(join("", map chr(rand(256)), 1..$size*3), "");
|
|
Packit |
a09cf7 |
$b =~ s/[\W]/X/g; # ensure alnum only
|
|
Packit |
a09cf7 |
$b;
|
|
Packit |
a09cf7 |
}
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
1;
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=pod
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=encoding UTF-8
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=head1 NAME
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
HTTP::Request::Common - Construct common HTTP::Request objects
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=head1 VERSION
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
version 6.18
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=head1 SYNOPSIS
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
use HTTP::Request::Common;
|
|
Packit |
a09cf7 |
$ua = LWP::UserAgent->new;
|
|
Packit |
a09cf7 |
$ua->request(GET 'http://www.sn.no/');
|
|
Packit |
a09cf7 |
$ua->request(POST 'http://somewhere/foo', [foo => bar, bar => foo]);
|
|
Packit |
a09cf7 |
$ua->request(PATCH 'http://somewhere/foo', [foo => bar, bar => foo]);
|
|
Packit |
a09cf7 |
$ua->request(PUT 'http://somewhere/foo', [foo => bar, bar => foo]);
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=head1 DESCRIPTION
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
This module provides functions that return newly created C<HTTP::Request>
|
|
Packit |
a09cf7 |
objects. These functions are usually more convenient to use than the
|
|
Packit |
a09cf7 |
standard C<HTTP::Request> constructor for the most common requests.
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
Note that L<LWP::UserAgent> has several convenience methods, including
|
|
Packit |
a09cf7 |
C<get>, C<head>, C<delete>, C<post> and C<put>.
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
The following functions are provided:
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=over 4
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=item GET $url
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=item GET $url, Header => Value,...
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
The C<GET> function returns an L<HTTP::Request> object initialized with
|
|
Packit |
a09cf7 |
the "GET" method and the specified URL. It is roughly equivalent to the
|
|
Packit |
a09cf7 |
following call
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
HTTP::Request->new(
|
|
Packit |
a09cf7 |
GET => $url,
|
|
Packit |
a09cf7 |
HTTP::Headers->new(Header => Value,...),
|
|
Packit |
a09cf7 |
)
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
but is less cluttered. What is different is that a header named
|
|
Packit |
a09cf7 |
C<Content> will initialize the content part of the request instead of
|
|
Packit |
a09cf7 |
setting a header field. Note that GET requests should normally not
|
|
Packit |
a09cf7 |
have a content, so this hack makes more sense for the C<PUT>, C<PATCH>
|
|
Packit |
a09cf7 |
and C<POST> functions described below.
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
The C<get(...)> method of L<LWP::UserAgent> exists as a shortcut for
|
|
Packit |
a09cf7 |
C<< $ua->request(GET ...) >>.
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=item HEAD $url
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=item HEAD $url, Header => Value,...
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
Like GET() but the method in the request is "HEAD".
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
The C<head(...)> method of L<LWP::UserAgent> exists as a shortcut for
|
|
Packit |
a09cf7 |
C<< $ua->request(HEAD ...) >>.
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=item DELETE $url
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=item DELETE $url, Header => Value,...
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
Like C<GET> but the method in the request is C<DELETE>. This function
|
|
Packit |
a09cf7 |
is not exported by default.
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=item PATCH $url
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=item PATCH $url, Header => Value,...
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=item PATCH $url, $form_ref, Header => Value,...
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=item PATCH $url, Header => Value,..., Content => $form_ref
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=item PATCH $url, Header => Value,..., Content => $content
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
The same as C<POST> below, but the method in the request is C<PATCH>.
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=item PUT $url
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=item PUT $url, Header => Value,...
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=item PUT $url, $form_ref, Header => Value,...
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=item PUT $url, Header => Value,..., Content => $form_ref
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=item PUT $url, Header => Value,..., Content => $content
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
The same as C<POST> below, but the method in the request is C<PUT>
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=item POST $url
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=item POST $url, Header => Value,...
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=item POST $url, $form_ref, Header => Value,...
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=item POST $url, Header => Value,..., Content => $form_ref
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=item POST $url, Header => Value,..., Content => $content
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
C<POST>, C<PATCH> and C<PUT> all work with the same parameters.
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
%data = ( title => 'something', body => something else' );
|
|
Packit |
a09cf7 |
$ua = LWP::UserAgent->new();
|
|
Packit |
a09cf7 |
$request = HTTP::Request::Common::POST( $url, [ %data ] );
|
|
Packit |
a09cf7 |
$response = $ua->request($request);
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
They take a second optional array or hash reference
|
|
Packit |
a09cf7 |
parameter C<$form_ref>. The content can also be specified
|
|
Packit |
a09cf7 |
directly using the C<Content> pseudo-header, and you may also provide
|
|
Packit |
a09cf7 |
the C<$form_ref> this way.
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
The C<Content> pseudo-header steals a bit of the header field namespace as
|
|
Packit |
a09cf7 |
there is no way to directly specify a header that is actually called
|
|
Packit |
a09cf7 |
"Content". If you really need this you must update the request
|
|
Packit |
a09cf7 |
returned in a separate statement.
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
The C<$form_ref> argument can be used to pass key/value pairs for the
|
|
Packit |
a09cf7 |
form content. By default we will initialize a request using the
|
|
Packit |
a09cf7 |
C<application/x-www-form-urlencoded> content type. This means that
|
|
Packit |
a09cf7 |
you can emulate an HTML E<lt>form> POSTing like this:
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
POST 'http://www.perl.org/survey.cgi',
|
|
Packit |
a09cf7 |
[ name => 'Gisle Aas',
|
|
Packit |
a09cf7 |
email => 'gisle@aas.no',
|
|
Packit |
a09cf7 |
gender => 'M',
|
|
Packit |
a09cf7 |
born => '1964',
|
|
Packit |
a09cf7 |
perc => '3%',
|
|
Packit |
a09cf7 |
];
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
This will create an L<HTTP::Request> object that looks like this:
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
POST http://www.perl.org/survey.cgi
|
|
Packit |
a09cf7 |
Content-Length: 66
|
|
Packit |
a09cf7 |
Content-Type: application/x-www-form-urlencoded
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
name=Gisle%20Aas&email=gisle%40aas.no&gender=M&born=1964&perc=3%25
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
Multivalued form fields can be specified by either repeating the field
|
|
Packit |
a09cf7 |
name or by passing the value as an array reference.
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
The POST method also supports the C<multipart/form-data> content used
|
|
Packit |
a09cf7 |
for I<Form-based File Upload> as specified in RFC 1867. You trigger
|
|
Packit |
a09cf7 |
this content format by specifying a content type of C<'form-data'> as
|
|
Packit |
a09cf7 |
one of the request headers. If one of the values in the C<$form_ref> is
|
|
Packit |
a09cf7 |
an array reference, then it is treated as a file part specification
|
|
Packit |
a09cf7 |
with the following interpretation:
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
[ $file, $filename, Header => Value... ]
|
|
Packit |
a09cf7 |
[ undef, $filename, Header => Value,..., Content => $content ]
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
The first value in the array ($file) is the name of a file to open.
|
|
Packit |
a09cf7 |
This file will be read and its content placed in the request. The
|
|
Packit |
a09cf7 |
routine will croak if the file can't be opened. Use an C<undef> as
|
|
Packit |
a09cf7 |
$file value if you want to specify the content directly with a
|
|
Packit |
a09cf7 |
C<Content> header. The $filename is the filename to report in the
|
|
Packit |
a09cf7 |
request. If this value is undefined, then the basename of the $file
|
|
Packit |
a09cf7 |
will be used. You can specify an empty string as $filename if you
|
|
Packit |
a09cf7 |
want to suppress sending the filename when you provide a $file value.
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
If a $file is provided by no C<Content-Type> header, then C<Content-Type>
|
|
Packit |
a09cf7 |
and C<Content-Encoding> will be filled in automatically with the values
|
|
Packit |
a09cf7 |
returned by C<LWP::MediaTypes::guess_media_type()>
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
Sending my F<~/.profile> to the survey used as example above can be
|
|
Packit |
a09cf7 |
achieved by this:
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
POST 'http://www.perl.org/survey.cgi',
|
|
Packit |
a09cf7 |
Content_Type => 'form-data',
|
|
Packit |
a09cf7 |
Content => [ name => 'Gisle Aas',
|
|
Packit |
a09cf7 |
email => 'gisle@aas.no',
|
|
Packit |
a09cf7 |
gender => 'M',
|
|
Packit |
a09cf7 |
born => '1964',
|
|
Packit |
a09cf7 |
init => ["$ENV{HOME}/.profile"],
|
|
Packit |
a09cf7 |
]
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
This will create an L<HTTP::Request> object that almost looks this (the
|
|
Packit |
a09cf7 |
boundary and the content of your F<~/.profile> is likely to be
|
|
Packit |
a09cf7 |
different):
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
POST http://www.perl.org/survey.cgi
|
|
Packit |
a09cf7 |
Content-Length: 388
|
|
Packit |
a09cf7 |
Content-Type: multipart/form-data; boundary="6G+f"
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
--6G+f
|
|
Packit |
a09cf7 |
Content-Disposition: form-data; name="name"
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
Gisle Aas
|
|
Packit |
a09cf7 |
--6G+f
|
|
Packit |
a09cf7 |
Content-Disposition: form-data; name="email"
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
gisle@aas.no
|
|
Packit |
a09cf7 |
--6G+f
|
|
Packit |
a09cf7 |
Content-Disposition: form-data; name="gender"
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
M
|
|
Packit |
a09cf7 |
--6G+f
|
|
Packit |
a09cf7 |
Content-Disposition: form-data; name="born"
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
1964
|
|
Packit |
a09cf7 |
--6G+f
|
|
Packit |
a09cf7 |
Content-Disposition: form-data; name="init"; filename=".profile"
|
|
Packit |
a09cf7 |
Content-Type: text/plain
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
PATH=/local/perl/bin:$PATH
|
|
Packit |
a09cf7 |
export PATH
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
--6G+f--
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
If you set the C<$DYNAMIC_FILE_UPLOAD> variable (exportable) to some TRUE
|
|
Packit |
a09cf7 |
value, then you get back a request object with a subroutine closure as
|
|
Packit |
a09cf7 |
the content attribute. This subroutine will read the content of any
|
|
Packit |
a09cf7 |
files on demand and return it in suitable chunks. This allow you to
|
|
Packit |
a09cf7 |
upload arbitrary big files without using lots of memory. You can even
|
|
Packit |
a09cf7 |
upload infinite files like F</dev/audio> if you wish; however, if
|
|
Packit |
a09cf7 |
the file is not a plain file, there will be no C<Content-Length> header
|
|
Packit |
a09cf7 |
defined for the request. Not all servers (or server
|
|
Packit |
a09cf7 |
applications) like this. Also, if the file(s) change in size between
|
|
Packit |
a09cf7 |
the time the C<Content-Length> is calculated and the time that the last
|
|
Packit |
a09cf7 |
chunk is delivered, the subroutine will C<Croak>.
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
The C<post(...)> method of L<LWP::UserAgent> exists as a shortcut for
|
|
Packit |
a09cf7 |
C<< $ua->request(POST ...) >>.
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=back
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=head1 SEE ALSO
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
L<HTTP::Request>, L<LWP::UserAgent>
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
Also, there are some examples in L<HTTP::Request/"EXAMPLES"> that you might
|
|
Packit |
a09cf7 |
find useful. For example, batch requests are explained there.
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=head1 AUTHOR
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
Gisle Aas <gisle@activestate.com>
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=head1 COPYRIGHT AND LICENSE
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
This software is copyright (c) 1994-2017 by Gisle Aas.
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
This is free software; you can redistribute it and/or modify it under
|
|
Packit |
a09cf7 |
the same terms as the Perl 5 programming language system itself.
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
=cut
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
__END__
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
|
|
Packit |
a09cf7 |
#ABSTRACT: Construct common HTTP::Request objects
|