From 3526587637297dca72d4fdc9d8b2be2bc007ad6d Mon Sep 17 00:00:00 2001 From: Chris 'BinGOs' Williams Date: Sat, 22 Oct 2011 20:03:12 +0100 Subject: [PATCH] Update HTTP-Tiny to CPAN version 0.014 [DELTA] 0.014 2011-10-20 13:54:13 America/New_York [NEW FEATURES] - Adds additional shorthand methods for all common HTTP verbs (HEAD, PUT, POST, DELETE) [David Golden] - post_form() method for POST-ing x-www-form-urlencoded data [David Golden] - www_form_urlencode() utility method [David Golden] --- MANIFEST | 13 ++- Porting/Maintainers.pl | 2 +- cpan/HTTP-Tiny/lib/HTTP/Tiny.pm | 131 ++++++++++++++++++++++++++---- cpan/HTTP-Tiny/t/001_api.t | 6 +- cpan/HTTP-Tiny/t/101_head.t | 74 +++++++++++++++++ cpan/HTTP-Tiny/t/{120_put.t => 102_put.t} | 2 +- cpan/HTTP-Tiny/t/103_delete.t | 74 +++++++++++++++++ cpan/HTTP-Tiny/t/104_post.t | 74 +++++++++++++++++ cpan/HTTP-Tiny/t/150_post_form.t | 82 +++++++++++++++++++ cpan/HTTP-Tiny/t/cases/delete-01.txt | 15 ++++ cpan/HTTP-Tiny/t/cases/form-01.txt | 23 ++++++ cpan/HTTP-Tiny/t/cases/form-02.txt | 21 +++++ cpan/HTTP-Tiny/t/cases/form-03.txt | 21 +++++ cpan/HTTP-Tiny/t/cases/form-04.txt | 21 +++++ cpan/HTTP-Tiny/t/cases/head-01.txt | 16 ++++ cpan/HTTP-Tiny/t/cases/post-01.txt | 24 ++++++ pod/perldelta.pod | 6 +- 17 files changed, 582 insertions(+), 23 deletions(-) create mode 100644 cpan/HTTP-Tiny/t/101_head.t rename cpan/HTTP-Tiny/t/{120_put.t => 102_put.t} (97%) create mode 100644 cpan/HTTP-Tiny/t/103_delete.t create mode 100644 cpan/HTTP-Tiny/t/104_post.t create mode 100644 cpan/HTTP-Tiny/t/150_post_form.t create mode 100644 cpan/HTTP-Tiny/t/cases/delete-01.txt create mode 100644 cpan/HTTP-Tiny/t/cases/form-01.txt create mode 100644 cpan/HTTP-Tiny/t/cases/form-02.txt create mode 100644 cpan/HTTP-Tiny/t/cases/form-03.txt create mode 100644 cpan/HTTP-Tiny/t/cases/form-04.txt create mode 100644 cpan/HTTP-Tiny/t/cases/head-01.txt create mode 100644 cpan/HTTP-Tiny/t/cases/post-01.txt diff --git a/MANIFEST b/MANIFEST index 1309baa..7498fd7 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1161,10 +1161,19 @@ cpan/HTTP-Tiny/t/040_content.t cpan/HTTP-Tiny/t/050_chunked_body.t cpan/HTTP-Tiny/t/060_http_date.t cpan/HTTP-Tiny/t/100_get.t +cpan/HTTP-Tiny/t/101_head.t +cpan/HTTP-Tiny/t/102_put.t +cpan/HTTP-Tiny/t/103_delete.t +cpan/HTTP-Tiny/t/104_post.t cpan/HTTP-Tiny/t/110_mirror.t -cpan/HTTP-Tiny/t/120_put.t cpan/HTTP-Tiny/t/130_redirect.t cpan/HTTP-Tiny/t/140_proxy.t +cpan/HTTP-Tiny/t/150_post_form.t +cpan/HTTP-Tiny/t/cases/delete-01.txt +cpan/HTTP-Tiny/t/cases/form-01.txt +cpan/HTTP-Tiny/t/cases/form-02.txt +cpan/HTTP-Tiny/t/cases/form-03.txt +cpan/HTTP-Tiny/t/cases/form-04.txt cpan/HTTP-Tiny/t/cases/get-01.txt cpan/HTTP-Tiny/t/cases/get-02.txt cpan/HTTP-Tiny/t/cases/get-03.txt @@ -1186,11 +1195,13 @@ cpan/HTTP-Tiny/t/cases/get-18.txt cpan/HTTP-Tiny/t/cases/get-19.txt cpan/HTTP-Tiny/t/cases/get-20.txt cpan/HTTP-Tiny/t/cases/get-21.txt +cpan/HTTP-Tiny/t/cases/head-01.txt cpan/HTTP-Tiny/t/cases/mirror-01.txt cpan/HTTP-Tiny/t/cases/mirror-02.txt cpan/HTTP-Tiny/t/cases/mirror-03.txt cpan/HTTP-Tiny/t/cases/mirror-04.txt cpan/HTTP-Tiny/t/cases/mirror-05.txt +cpan/HTTP-Tiny/t/cases/post-01.txt cpan/HTTP-Tiny/t/cases/put-01.txt cpan/HTTP-Tiny/t/cases/put-02.txt cpan/HTTP-Tiny/t/cases/put-03.txt diff --git a/Porting/Maintainers.pl b/Porting/Maintainers.pl index f8d655a..7ae7bcf 100755 --- a/Porting/Maintainers.pl +++ b/Porting/Maintainers.pl @@ -978,7 +978,7 @@ use File::Glob qw(:case); 'HTTP::Tiny' => { 'MAINTAINER' => 'dagolden', - 'DISTRIBUTION' => 'DAGOLDEN/HTTP-Tiny-0.013.tar.gz', + 'DISTRIBUTION' => 'DAGOLDEN/HTTP-Tiny-0.014.tar.gz', 'FILES' => q[cpan/HTTP-Tiny], 'EXCLUDED' => [ 't/200_live.t', diff --git a/cpan/HTTP-Tiny/lib/HTTP/Tiny.pm b/cpan/HTTP-Tiny/lib/HTTP/Tiny.pm index 1355553..922532f 100644 --- a/cpan/HTTP-Tiny/lib/HTTP/Tiny.pm +++ b/cpan/HTTP-Tiny/lib/HTTP/Tiny.pm @@ -2,7 +2,8 @@ package HTTP::Tiny; use strict; use warnings; -our $VERSION = '0.013'; # VERSION +# ABSTRACT: A small, simple, correct HTTP/1.1 client +our $VERSION = '0.014'; # VERSION use Carp (); @@ -44,11 +45,40 @@ sub new { } -sub get { - my ($self, $url, $args) = @_; - @_ == 2 || (@_ == 3 && ref $args eq 'HASH') - or Carp::croak(q/Usage: $http->get(URL, [HASHREF])/ . "\n"); - return $self->request('GET', $url, $args || {}); +for my $sub_name ( qw/get head put post delete/ ) { + my $req_method = uc $sub_name; + no strict 'refs'; + eval <<"HERE"; + sub $sub_name { + my (\$self, \$url, \$args) = \@_; + \@_ == 2 || (\@_ == 3 && ref \$args eq 'HASH') + or Carp::croak(q/Usage: \$http->$sub_name(URL, [HASHREF])/ . "\n"); + return \$self->request('$req_method', \$url, \$args || {}); + } +HERE +} + + +sub post_form { + my ($self, $url, $data, $args) = @_; + (@_ == 3 || @_ == 4 && ref $args eq 'HASH') + or Carp::croak(q/Usage: $http->post_form(URL, DATAREF, [HASHREF])/ . "\n"); + + my $headers = {}; + while ( my ($key, $value) = each %{$args->{headers} || {}} ) { + $headers->{lc $key} = $value; + } + delete $args->{headers}; + + return $self->request('POST', $url, { + %$args, + content => $self->www_form_urlencode($data), + headers => { + %$headers, + 'content-type' => 'application/x-www-form-urlencoded' + }, + } + ); } @@ -112,6 +142,36 @@ sub request { return $response; } + +sub www_form_urlencode { + my ($self, $data) = @_; + (@_ == 2 && ref $data) + or Carp::croak(q/Usage: $http->www_form_urlencode(DATAREF)/ . "\n"); + (ref $data eq 'HASH' || ref $data eq 'ARRAY') + or Carp::croak("form data must be a hash or array reference"); + + my @params = ref $data eq 'HASH' ? %$data : @$data; + @params % 2 == 0 + or Carp::croak("form data reference must have an even number of terms\n"); + + my @terms; + while( @params ) { + my ($key, $value) = splice(@params, 0, 2); + if ( ref $value eq 'ARRAY' ) { + unshift @params, map { $key => $_ } @$value; + } + else { + push @terms, join("=", map { $self->_uri_escape($_) } $key, $value); + } + } + + return join("&", sort @terms); +} + +#--------------------------------------------------------------------------# +# private methods +#--------------------------------------------------------------------------# + my %DefaultPort = ( http => 80, https => 443, @@ -293,6 +353,19 @@ sub _parse_http_date { }; } +# URI escaping adapted from URI::Escape +# c.f. http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1 +my %escapes = map { chr($_) => sprintf("%%%02X", $_) } 0..255; +$escapes{' '}="+"; +my $unsafe_char = qr/[^A-Za-z0-9\-\._~]/; + +sub _uri_escape { + my ($self, $str) = @_; + utf8::encode($str); + $str =~ s/($unsafe_char)/$escapes{$1}/ge; + return $str; +} + package HTTP::Tiny::Handle; # hide from PAUSE/indexers use strict; @@ -748,8 +821,6 @@ sub can_write { 1; -# ABSTRACT: A small, simple, correct HTTP/1.1 client - __END__ @@ -761,7 +832,7 @@ HTTP::Tiny - A small, simple, correct HTTP/1.1 client =head1 VERSION -version 0.013 +version 0.014 =head1 SYNOPSIS @@ -783,7 +854,7 @@ version 0.013 =head1 DESCRIPTION -This is a very simple HTTP/1.1 client, designed primarily for doing simple GET +This is a very simple HTTP/1.1 client, designed for doing simple GET requests without the overhead of a large framework like L. It is more correct and more complete than L. It supports @@ -839,15 +910,29 @@ Request timeout in seconds (default is 60) =back -=head2 get +=head2 get|head|put|post|delete $response = $http->get($url); $response = $http->get($url, \%options); + $response = $http->head($url); + +These methods are shorthand for calling C for the given method. The +URL must have unsafe characters escaped and international domain names encoded. +See C for valid options and a description of the response. + +=head2 post_form + + $response = $http->post_form($url, $form_data); + $response = $http->post_form($url, $form_data, \%options); -Executes a C request for the given URL. The URL must have unsafe -characters escaped and international domain names encoded. Internally, it just -calls C with 'GET' as the method. See C for valid -options and a description of the response. +This method executes a C request and sends the key/value pairs from a +form data hash or array reference to the given URL with a C of +C. See documentation for the +C method for details on the encoding. + +The URL must have unsafe characters escaped and international domain names +encoded. See C for valid options and a description of the response. +Any C header or content in the options hashref will be ignored. =head2 mirror @@ -970,6 +1055,18 @@ it will otherwise be a scalar string containing the value On an exception during the execution of the request, the C field will contain 599, and the C field will contain the text of the exception. +=head2 www_form_urlencode + + $params = $http->www_form_urlencode( $data ); + $response = $http->get("http://example.com/query?$params"); + +This method converts the key/value pairs from a data hash or array reference +into a C string. The keys and values from the data +reference will be UTF-8 encoded and escaped per RFC 3986. If a value is an +array reference, the key will be repeated with each of the values of the array +reference. The key/value pairs in the resulting string will be sorted by key +and value. + =for Pod::Coverage agent default_headers max_redirect @@ -1072,9 +1169,9 @@ progress on the request by the system. This is open source software. The code repository is available for public review and contribution under the terms of the license. -L +L - git clone http://github.com/dagolden/p5-http-tiny + git clone https://github.com/dagolden/p5-http-tiny.git =head1 AUTHORS diff --git a/cpan/HTTP-Tiny/t/001_api.t b/cpan/HTTP-Tiny/t/001_api.t index 85dc937..8b31683 100644 --- a/cpan/HTTP-Tiny/t/001_api.t +++ b/cpan/HTTP-Tiny/t/001_api.t @@ -7,11 +7,13 @@ use Test::More tests => 2; use HTTP::Tiny; my @accessors = qw(agent default_headers max_redirect max_size proxy timeout); -my @methods = qw(new get request mirror); +my @methods = qw( + new get head put post delete post_form request mirror www_form_urlencode +); my %api; @api{@accessors} = (1) x @accessors; -@api{@methods} = (1) x @accessors; +@api{@methods} = (1) x @methods; can_ok('HTTP::Tiny', @methods, @accessors); diff --git a/cpan/HTTP-Tiny/t/101_head.t b/cpan/HTTP-Tiny/t/101_head.t new file mode 100644 index 0000000..ad95917 --- /dev/null +++ b/cpan/HTTP-Tiny/t/101_head.t @@ -0,0 +1,74 @@ +#!perl + +use strict; +use warnings; + +use File::Basename; +use Test::More 0.88; +use t::Util qw[tmpfile rewind slurp monkey_patch dir_list parse_case + set_socket_source sort_headers $CRLF $LF]; +use HTTP::Tiny; +BEGIN { monkey_patch() } + +for my $file ( dir_list("t/cases", qr/^head/ ) ) { + my $data = do { local (@ARGV,$/) = $file; <> }; + my ($params, $expect_req, $give_res) = split /--+\n/, $data; + # cleanup source data + my $version = HTTP::Tiny->VERSION || 0; + $expect_req =~ s{VERSION}{$version}; + s{\n}{$CRLF}g for ($expect_req, $give_res); + + # figure out what request to make + my $case = parse_case($params); + my $url = $case->{url}[0]; + my %options; + + my %headers; + for my $line ( @{ $case->{headers} } ) { + my ($k,$v) = ($line =~ m{^([^:]+): (.*)$}g); + $headers{$k} = $v; + } + $options{headers} = \%headers if %headers; + + if ( $case->{content} ) { + $options{content} = $case->{content}[0]; + } + elsif ( $case->{content_cb} ) { + $options{content} = eval join "\n", @{$case->{content_cb}}; + } + + if ( $case->{trailer_cb} ) { + $options{trailer_callback} = eval join "\n", @{$case->{trailer_cb}}; + } + + # setup mocking and test + my $res_fh = tmpfile($give_res); + my $req_fh = tmpfile(); + + my $http = HTTP::Tiny->new; + set_socket_source($req_fh, $res_fh); + + (my $url_basename = $url) =~ s{.*/}{}; + + my @call_args = %options ? ($url, \%options) : ($url); + my $response = $http->head(@call_args); + + my $got_req = slurp($req_fh); + + my $label = basename($file); + + is( sort_headers($got_req), sort_headers($expect_req), "$label request" ); + + my ($rc) = $give_res =~ m{\S+\s+(\d+)}g; + is( $response->{status}, $rc, "$label response code $rc" ) + or diag $response->{content}; + + if ( substr($rc,0,1) eq '2' ) { + ok( $response->{success}, "$label success flag true" ); + } + else { + ok( ! $response->{success}, "$label success flag false" ); + } +} + +done_testing; diff --git a/cpan/HTTP-Tiny/t/120_put.t b/cpan/HTTP-Tiny/t/102_put.t similarity index 97% rename from cpan/HTTP-Tiny/t/120_put.t rename to cpan/HTTP-Tiny/t/102_put.t index e0c98d7..2fc1169 100644 --- a/cpan/HTTP-Tiny/t/120_put.t +++ b/cpan/HTTP-Tiny/t/102_put.t @@ -51,7 +51,7 @@ for my $file ( dir_list("t/cases", qr/^put/ ) ) { (my $url_basename = $url) =~ s{.*/}{}; my @call_args = %options ? ($url, \%options) : ($url); - my $response = $http->request('PUT',@call_args); + my $response = $http->put(@call_args); my $got_req = slurp($req_fh); diff --git a/cpan/HTTP-Tiny/t/103_delete.t b/cpan/HTTP-Tiny/t/103_delete.t new file mode 100644 index 0000000..a565484 --- /dev/null +++ b/cpan/HTTP-Tiny/t/103_delete.t @@ -0,0 +1,74 @@ +#!perl + +use strict; +use warnings; + +use File::Basename; +use Test::More 0.88; +use t::Util qw[tmpfile rewind slurp monkey_patch dir_list parse_case + set_socket_source sort_headers $CRLF $LF]; +use HTTP::Tiny; +BEGIN { monkey_patch() } + +for my $file ( dir_list("t/cases", qr/^delete/ ) ) { + my $data = do { local (@ARGV,$/) = $file; <> }; + my ($params, $expect_req, $give_res) = split /--+\n/, $data; + # cleanup source data + my $version = HTTP::Tiny->VERSION || 0; + $expect_req =~ s{VERSION}{$version}; + s{\n}{$CRLF}g for ($expect_req, $give_res); + + # figure out what request to make + my $case = parse_case($params); + my $url = $case->{url}[0]; + my %options; + + my %headers; + for my $line ( @{ $case->{headers} } ) { + my ($k,$v) = ($line =~ m{^([^:]+): (.*)$}g); + $headers{$k} = $v; + } + $options{headers} = \%headers if %headers; + + if ( $case->{content} ) { + $options{content} = $case->{content}[0]; + } + elsif ( $case->{content_cb} ) { + $options{content} = eval join "\n", @{$case->{content_cb}}; + } + + if ( $case->{trailer_cb} ) { + $options{trailer_callback} = eval join "\n", @{$case->{trailer_cb}}; + } + + # setup mocking and test + my $res_fh = tmpfile($give_res); + my $req_fh = tmpfile(); + + my $http = HTTP::Tiny->new; + set_socket_source($req_fh, $res_fh); + + (my $url_basename = $url) =~ s{.*/}{}; + + my @call_args = %options ? ($url, \%options) : ($url); + my $response = $http->delete(@call_args); + + my $got_req = slurp($req_fh); + + my $label = basename($file); + + is( sort_headers($got_req), sort_headers($expect_req), "$label request" ); + + my ($rc) = $give_res =~ m{\S+\s+(\d+)}g; + is( $response->{status}, $rc, "$label response code $rc" ) + or diag $response->{content}; + + if ( substr($rc,0,1) eq '2' ) { + ok( $response->{success}, "$label success flag true" ); + } + else { + ok( ! $response->{success}, "$label success flag false" ); + } +} + +done_testing; diff --git a/cpan/HTTP-Tiny/t/104_post.t b/cpan/HTTP-Tiny/t/104_post.t new file mode 100644 index 0000000..181261a --- /dev/null +++ b/cpan/HTTP-Tiny/t/104_post.t @@ -0,0 +1,74 @@ +#!perl + +use strict; +use warnings; + +use File::Basename; +use Test::More 0.88; +use t::Util qw[tmpfile rewind slurp monkey_patch dir_list parse_case + set_socket_source sort_headers $CRLF $LF]; +use HTTP::Tiny; +BEGIN { monkey_patch() } + +for my $file ( dir_list("t/cases", qr/^post/ ) ) { + my $data = do { local (@ARGV,$/) = $file; <> }; + my ($params, $expect_req, $give_res) = split /--+\n/, $data; + # cleanup source data + my $version = HTTP::Tiny->VERSION || 0; + $expect_req =~ s{VERSION}{$version}; + s{\n}{$CRLF}g for ($expect_req, $give_res); + + # figure out what request to make + my $case = parse_case($params); + my $url = $case->{url}[0]; + my %options; + + my %headers; + for my $line ( @{ $case->{headers} } ) { + my ($k,$v) = ($line =~ m{^([^:]+): (.*)$}g); + $headers{$k} = $v; + } + $options{headers} = \%headers if %headers; + + if ( $case->{content} ) { + $options{content} = $case->{content}[0]; + } + elsif ( $case->{content_cb} ) { + $options{content} = eval join "\n", @{$case->{content_cb}}; + } + + if ( $case->{trailer_cb} ) { + $options{trailer_callback} = eval join "\n", @{$case->{trailer_cb}}; + } + + # setup mocking and test + my $res_fh = tmpfile($give_res); + my $req_fh = tmpfile(); + + my $http = HTTP::Tiny->new; + set_socket_source($req_fh, $res_fh); + + (my $url_basename = $url) =~ s{.*/}{}; + + my @call_args = %options ? ($url, \%options) : ($url); + my $response = $http->post(@call_args); + + my $got_req = slurp($req_fh); + + my $label = basename($file); + + is( sort_headers($got_req), sort_headers($expect_req), "$label request" ); + + my ($rc) = $give_res =~ m{\S+\s+(\d+)}g; + is( $response->{status}, $rc, "$label response code $rc" ) + or diag $response->{content}; + + if ( substr($rc,0,1) eq '2' ) { + ok( $response->{success}, "$label success flag true" ); + } + else { + ok( ! $response->{success}, "$label success flag false" ); + } +} + +done_testing; diff --git a/cpan/HTTP-Tiny/t/150_post_form.t b/cpan/HTTP-Tiny/t/150_post_form.t new file mode 100644 index 0000000..a0edcd4 --- /dev/null +++ b/cpan/HTTP-Tiny/t/150_post_form.t @@ -0,0 +1,82 @@ +#!perl + +use strict; +use warnings; + +use File::Basename; +use Test::More 0.88; +use t::Util qw[tmpfile rewind slurp monkey_patch dir_list parse_case + set_socket_source sort_headers $CRLF $LF]; +use HTTP::Tiny; +BEGIN { monkey_patch() } + +for my $file ( dir_list("t/cases", qr/^form/ ) ) { + my $data = do { local (@ARGV,$/) = $file; <> }; + my ($params, $expect_req, $give_res) = split /--+\n/, $data; + # cleanup source data + my $version = HTTP::Tiny->VERSION || 0; + $expect_req =~ s{VERSION}{$version}; + s{\n}{$CRLF}g for ($expect_req, $give_res); + + # figure out what request to make + my $case = parse_case($params); + my $url = $case->{url}[0]; + my %options; + + my %headers; + for my $line ( @{ $case->{headers} } ) { + my ($k,$v) = ($line =~ m{^([^:]+): (.*)$}g); + $headers{$k} = $v; + } + $options{headers} = \%headers if %headers; + + my @params = split "\\|", $case->{content}[0]; + my $formdata; + if ( $case->{datatype} eq 'HASH' ) { + while ( @params ) { + my ($key, $value) = splice( @params, 0, 2 ); + if ( ref $formdata->{$key} ) { + push @{$formdata->{$key}}, $value; + } + elsif ( exists $formdata->{$key} ) { + $formdata->{$key} = [ $formdata->{$key}, $value ]; + } + else { + $formdata->{$key} = $value; + } + } + } + else { + $formdata = [ @params ]; + } + + # setup mocking and test + my $res_fh = tmpfile($give_res); + my $req_fh = tmpfile(); + + my $http = HTTP::Tiny->new; + set_socket_source($req_fh, $res_fh); + + (my $url_basename = $url) =~ s{.*/}{}; + + my $response = $http->post_form( $url, $formdata, %options ? (\%options) : ()); + + my $got_req = slurp($req_fh); + + my $label = basename($file); + + is( sort_headers($got_req), sort_headers($expect_req), "$label request" ); + + my ($rc) = $give_res =~ m{\S+\s+(\d+)}g; + is( $response->{status}, $rc, "$label response code $rc" ) + or diag $response->{content}; + + if ( substr($rc,0,1) eq '2' ) { + ok( $response->{success}, "$label success flag true" ); + } + else { + ok( ! $response->{success}, "$label success flag false" ); + } +} + +done_testing; diff --git a/cpan/HTTP-Tiny/t/cases/delete-01.txt b/cpan/HTTP-Tiny/t/cases/delete-01.txt new file mode 100644 index 0000000..a83069e --- /dev/null +++ b/cpan/HTTP-Tiny/t/cases/delete-01.txt @@ -0,0 +1,15 @@ +url + http://example.com/index.html +expected + abcdefghijklmnopqrstuvwxyz1234567890abcdef +---------- +DELETE /index.html HTTP/1.1 +Host: example.com +Connection: close +User-Agent: HTTP-Tiny/VERSION + +---------- +HTTP/1.1 200 OK +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Length: 0 + diff --git a/cpan/HTTP-Tiny/t/cases/form-01.txt b/cpan/HTTP-Tiny/t/cases/form-01.txt new file mode 100644 index 0000000..876f1b6 --- /dev/null +++ b/cpan/HTTP-Tiny/t/cases/form-01.txt @@ -0,0 +1,23 @@ +url + http://example.com/new +headers + Content-Type: text/plain +content + key|value|name|John Doe|noise|!@#$%^&*() +datatype + ARRAY +---------- +POST /new HTTP/1.1 +Host: example.com +Connection: close +User-Agent: HTTP-Tiny/VERSION +Content-Type: application/x-www-form-urlencoded +Content-Length: 60 + +key=value&name=John+Doe&noise=%21%40%23%24%25%5E%26%2A%28%29 +---------- +HTTP/1.1 201 Created +Date: Thu, 03 Feb 1994 00:00:00 GMT +Location: http://example.com/new/01.txt +Content-Length: 0 + diff --git a/cpan/HTTP-Tiny/t/cases/form-02.txt b/cpan/HTTP-Tiny/t/cases/form-02.txt new file mode 100644 index 0000000..5ec2d91 --- /dev/null +++ b/cpan/HTTP-Tiny/t/cases/form-02.txt @@ -0,0 +1,21 @@ +url + http://example.com/new +content + key|value|name|John Doe|noise|!@#$%^&*() +datatype + HASH +---------- +POST /new HTTP/1.1 +Host: example.com +Connection: close +User-Agent: HTTP-Tiny/VERSION +Content-Type: application/x-www-form-urlencoded +Content-Length: 60 + +key=value&name=John+Doe&noise=%21%40%23%24%25%5E%26%2A%28%29 +---------- +HTTP/1.1 201 Created +Date: Thu, 03 Feb 1994 00:00:00 GMT +Location: http://example.com/new/01.txt +Content-Length: 0 + diff --git a/cpan/HTTP-Tiny/t/cases/form-03.txt b/cpan/HTTP-Tiny/t/cases/form-03.txt new file mode 100644 index 0000000..b6dcd47 --- /dev/null +++ b/cpan/HTTP-Tiny/t/cases/form-03.txt @@ -0,0 +1,21 @@ +url + http://example.com/new +content + bar|baz|ack|foo +datatype + ARRAY +---------- +POST /new HTTP/1.1 +Host: example.com +Connection: close +User-Agent: HTTP-Tiny/VERSION +Content-Type: application/x-www-form-urlencoded +Content-Length: 15 + +ack=foo&bar=baz +---------- +HTTP/1.1 201 Created +Date: Thu, 03 Feb 1994 00:00:00 GMT +Location: http://example.com/new/01.txt +Content-Length: 0 + diff --git a/cpan/HTTP-Tiny/t/cases/form-04.txt b/cpan/HTTP-Tiny/t/cases/form-04.txt new file mode 100644 index 0000000..3f762c0 --- /dev/null +++ b/cpan/HTTP-Tiny/t/cases/form-04.txt @@ -0,0 +1,21 @@ +url + http://example.com/new +content + utf8|☺ +datatype + ARRAY +---------- +POST /new HTTP/1.1 +Host: example.com +Connection: close +User-Agent: HTTP-Tiny/VERSION +Content-Type: application/x-www-form-urlencoded +Content-Length: 23 + +utf8=%C3%A2%C2%98%C2%BA +---------- +HTTP/1.1 201 Created +Date: Thu, 03 Feb 1994 00:00:00 GMT +Location: http://example.com/new/01.txt +Content-Length: 0 + diff --git a/cpan/HTTP-Tiny/t/cases/head-01.txt b/cpan/HTTP-Tiny/t/cases/head-01.txt new file mode 100644 index 0000000..1c6357a --- /dev/null +++ b/cpan/HTTP-Tiny/t/cases/head-01.txt @@ -0,0 +1,16 @@ +url + http://example.com/index.html +expected + abcdefghijklmnopqrstuvwxyz1234567890abcdef +---------- +HEAD /index.html HTTP/1.1 +Host: example.com +Connection: close +User-Agent: HTTP-Tiny/VERSION + +---------- +HTTP/1.1 200 OK +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/plain +Content-Length: 44 + diff --git a/cpan/HTTP-Tiny/t/cases/post-01.txt b/cpan/HTTP-Tiny/t/cases/post-01.txt new file mode 100644 index 0000000..644731b --- /dev/null +++ b/cpan/HTTP-Tiny/t/cases/post-01.txt @@ -0,0 +1,24 @@ +url + http://example.com/index.html +headers + Content-Type: text/plain + Content-Length: 42 +content + abcdefghijklmnopqrstuvwxyz1234567890abcdef +---------- +POST /index.html HTTP/1.1 +Host: example.com +Connection: close +User-Agent: HTTP-Tiny/VERSION +Content-Type: text/plain +Content-Length: 42 + +abcdefghijklmnopqrstuvwxyz1234567890abcdef + +---------- +HTTP/1.1 200 OK +Date: Thu, 03 Feb 1994 00:00:00 GMT +Content-Type: text/plain +Content-Length: 42 + +abcdefghijklmnopqrstuvwxyz1234567890abcdef diff --git a/pod/perldelta.pod b/pod/perldelta.pod index 1474e60..b99f7c6 100644 --- a/pod/perldelta.pod +++ b/pod/perldelta.pod @@ -96,7 +96,11 @@ XXX =item * -L has been upgraded from version 0.69 to version 0.70. +L has been upgraded from version 0.013 to version 0.014. + +Adds additional shorthand methods for all common HTTP verbs, +a C method for POST-ing x-www-form-urlencoded data and +a C utility method. =back -- 2.7.4