summaryrefslogtreecommitdiff
path: root/cpan/HTTP-Tiny
diff options
context:
space:
mode:
authorChris 'BinGOs' Williams <chris@bingosnet.co.uk>2021-10-07 15:46:37 +0100
committerChris 'BinGOs' Williams <chris@bingosnet.co.uk>2021-10-07 15:46:37 +0100
commit2b0c7afada71b2d42dd50ec342a0e9878e4e2ef2 (patch)
tree8f7ea9195570bba05a7102745845226440665c8e /cpan/HTTP-Tiny
parent14956bc72e4dd8b178ec6986aa9857828f53e733 (diff)
downloadperl-2b0c7afada71b2d42dd50ec342a0e9878e4e2ef2.tar.gz
Update HTTP-Tiny to CPAN version 0.078
[DELTA] 0.078 2021-08-02 09:24:03-04:00 America/New_York - No changes from 0.077-TRIAL. 0.077 2021-07-22 13:07:14-04:00 America/New_York (TRIAL RELEASE) [ADDED] - Added a `patch` helper method for the HTTP `PATCH` verb. - If the REQUEST_METHOD environment variable is set, then CGI_HTTP_PROXY replaces HTTP_PROXY. [FIXED] - Unsupported scheme errors early without giving an uninitialized value warning first. - Sends Content-Length: 0 on empty body PUT/POST. This is not in the spec, but some servers require this. - Allows optional status line reason, as clarified in RFC 7230. - Ignore SIGPIPE on reads as well as writes, as IO::Socket::SSL says that SSL reads can also send writes as a side effect. - Check if a server has closed a connection before preserving it for reuse. [DOCS] - Clarified that exceptions/errors result in 599 status codes. [PREREQS] - Optional IO::Socket::IP prereq must be at least version 0.32 to be used. This ensures correct timeout support.
Diffstat (limited to 'cpan/HTTP-Tiny')
-rw-r--r--cpan/HTTP-Tiny/corpus/form-01.txt6
-rw-r--r--cpan/HTTP-Tiny/corpus/form-02.txt6
-rw-r--r--cpan/HTTP-Tiny/corpus/get-23.txt17
-rw-r--r--cpan/HTTP-Tiny/corpus/post-02.txt20
-rw-r--r--cpan/HTTP-Tiny/corpus/put-06.txt20
-rw-r--r--cpan/HTTP-Tiny/corpus/put-07.txt22
-rw-r--r--cpan/HTTP-Tiny/corpus/put-08.txt23
-rw-r--r--cpan/HTTP-Tiny/corpus/redirect-09.txt1
-rw-r--r--cpan/HTTP-Tiny/lib/HTTP/Tiny.pm174
-rw-r--r--cpan/HTTP-Tiny/t/001_api.t2
-rw-r--r--cpan/HTTP-Tiny/t/002_croakage.t19
-rw-r--r--cpan/HTTP-Tiny/t/003_agent.t4
-rw-r--r--cpan/HTTP-Tiny/t/030_response.t37
-rw-r--r--cpan/HTTP-Tiny/t/100_get.t4
-rw-r--r--cpan/HTTP-Tiny/t/101_head.t5
-rw-r--r--cpan/HTTP-Tiny/t/102_put.t8
-rw-r--r--cpan/HTTP-Tiny/t/103_delete.t5
-rw-r--r--cpan/HTTP-Tiny/t/104_post.t5
-rw-r--r--cpan/HTTP-Tiny/t/110_mirror.t5
-rw-r--r--cpan/HTTP-Tiny/t/140_proxy.t10
-rw-r--r--cpan/HTTP-Tiny/t/150_post_form.t10
-rw-r--r--cpan/HTTP-Tiny/t/Util.pm6
22 files changed, 327 insertions, 82 deletions
diff --git a/cpan/HTTP-Tiny/corpus/form-01.txt b/cpan/HTTP-Tiny/corpus/form-01.txt
index 876f1b67b5..f207bad44b 100644
--- a/cpan/HTTP-Tiny/corpus/form-01.txt
+++ b/cpan/HTTP-Tiny/corpus/form-01.txt
@@ -3,7 +3,7 @@ url
headers
Content-Type: text/plain
content
- key|value|name|John Doe|noise|!@#$%^&*()
+ key|value|name|John Doe|undef|<undef>|noise|!@#$%^&*()
datatype
ARRAY
----------
@@ -12,9 +12,9 @@ Host: example.com
Connection: close
User-Agent: HTTP-Tiny/VERSION
Content-Type: application/x-www-form-urlencoded
-Content-Length: 60
+Content-Length: 67
-key=value&name=John+Doe&noise=%21%40%23%24%25%5E%26%2A%28%29
+key=value&name=John+Doe&undef=&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
diff --git a/cpan/HTTP-Tiny/corpus/form-02.txt b/cpan/HTTP-Tiny/corpus/form-02.txt
index 5ec2d91f44..c825842df1 100644
--- a/cpan/HTTP-Tiny/corpus/form-02.txt
+++ b/cpan/HTTP-Tiny/corpus/form-02.txt
@@ -1,7 +1,7 @@
url
http://example.com/new
content
- key|value|name|John Doe|noise|!@#$%^&*()
+ key|value|name|John Doe|undef|<undef>|noise|!@#$%^&*()
datatype
HASH
----------
@@ -10,9 +10,9 @@ Host: example.com
Connection: close
User-Agent: HTTP-Tiny/VERSION
Content-Type: application/x-www-form-urlencoded
-Content-Length: 60
+Content-Length: 67
-key=value&name=John+Doe&noise=%21%40%23%24%25%5E%26%2A%28%29
+key=value&name=John+Doe&noise=%21%40%23%24%25%5E%26%2A%28%29&undef=
----------
HTTP/1.1 201 Created
Date: Thu, 03 Feb 1994 00:00:00 GMT
diff --git a/cpan/HTTP-Tiny/corpus/get-23.txt b/cpan/HTTP-Tiny/corpus/get-23.txt
new file mode 100644
index 0000000000..0f98696671
--- /dev/null
+++ b/cpan/HTTP-Tiny/corpus/get-23.txt
@@ -0,0 +1,17 @@
+url
+ http://example.com/index.html
+expected
+ abcdefghijklmnopqrstuvwxyz1234567890abcdef
+----------
+GET /index.html HTTP/1.1
+Host: example.com
+Connection: close
+User-Agent: HTTP-Tiny/VERSION
+
+----------
+HTTP/1.1 200
+Date: Thu, 03 Feb 1994 00:00:00 GMT
+Content-Type: text/plain
+Content-Length: 44
+
+abcdefghijklmnopqrstuvwxyz1234567890abcdef
diff --git a/cpan/HTTP-Tiny/corpus/post-02.txt b/cpan/HTTP-Tiny/corpus/post-02.txt
new file mode 100644
index 0000000000..e27365d224
--- /dev/null
+++ b/cpan/HTTP-Tiny/corpus/post-02.txt
@@ -0,0 +1,20 @@
+url
+ http://example.com/index.html
+headers
+ Content-Type: text/plain
+content
+
+----------
+POST /index.html HTTP/1.1
+Host: example.com
+Connection: close
+User-Agent: HTTP-Tiny/VERSION
+Content-Type: text/plain
+Content-Length: 0
+
+----------
+HTTP/1.1 200 OK
+Date: Thu, 03 Feb 1994 00:00:00 GMT
+Content-Type: text/plain
+Content-Length: 0
+
diff --git a/cpan/HTTP-Tiny/corpus/put-06.txt b/cpan/HTTP-Tiny/corpus/put-06.txt
new file mode 100644
index 0000000000..16306b46a9
--- /dev/null
+++ b/cpan/HTTP-Tiny/corpus/put-06.txt
@@ -0,0 +1,20 @@
+url
+ http://example.com/new.txt
+headers
+ Content-Type: text/plain
+content
+
+----------
+PUT /new.txt HTTP/1.1
+Host: example.com
+Connection: close
+User-Agent: HTTP-Tiny/VERSION
+Content-Type: text/plain
+Content-Length: 0
+
+----------
+HTTP/1.1 201 Created
+Date: Thu, 03 Feb 1994 00:00:00 GMT
+Location: http://example.com/new.txt
+Content-Length: 0
+
diff --git a/cpan/HTTP-Tiny/corpus/put-07.txt b/cpan/HTTP-Tiny/corpus/put-07.txt
new file mode 100644
index 0000000000..fd9920129c
--- /dev/null
+++ b/cpan/HTTP-Tiny/corpus/put-07.txt
@@ -0,0 +1,22 @@
+url
+ http://example.com/callback.txt
+headers
+ Content-Type: text/plain
+ Content-Length: 0
+content_cb
+ my @content = qq{};
+ sub { shift @content }
+----------
+PUT /callback.txt HTTP/1.1
+Host: example.com
+Connection: close
+User-Agent: HTTP-Tiny/VERSION
+Content-Type: text/plain
+Content-Length: 0
+
+----------
+HTTP/1.1 201 Created
+Date: Thu, 03 Feb 1994 00:00:00 GMT
+Location: http://example.com/callback.txt
+Content-Length: 0
+
diff --git a/cpan/HTTP-Tiny/corpus/put-08.txt b/cpan/HTTP-Tiny/corpus/put-08.txt
new file mode 100644
index 0000000000..263189376c
--- /dev/null
+++ b/cpan/HTTP-Tiny/corpus/put-08.txt
@@ -0,0 +1,23 @@
+url
+ http://example.com/callback.txt
+headers
+ Content-Type: text/plain
+content_cb
+ my @content = qq{};
+ sub { shift @content }
+----------
+PUT /callback.txt HTTP/1.1
+Host: example.com
+Connection: close
+User-Agent: HTTP-Tiny/VERSION
+Transfer-Encoding: chunked
+Content-Type: text/plain
+
+0
+
+----------
+HTTP/1.1 201 Created
+Date: Thu, 03 Feb 1994 00:00:00 GMT
+Location: http://example.com/callback.txt
+Content-Length: 0
+
diff --git a/cpan/HTTP-Tiny/corpus/redirect-09.txt b/cpan/HTTP-Tiny/corpus/redirect-09.txt
index afb0ec2f06..200c73a022 100644
--- a/cpan/HTTP-Tiny/corpus/redirect-09.txt
+++ b/cpan/HTTP-Tiny/corpus/redirect-09.txt
@@ -10,6 +10,7 @@ expected_url
POST /index.html HTTP/1.1
Host: example.com
Connection: close
+Content-Length: 0
User-Agent: HTTP-Tiny/VERSION
----------
diff --git a/cpan/HTTP-Tiny/lib/HTTP/Tiny.pm b/cpan/HTTP-Tiny/lib/HTTP/Tiny.pm
index 5803e4599f..7954b25094 100644
--- a/cpan/HTTP-Tiny/lib/HTTP/Tiny.pm
+++ b/cpan/HTTP-Tiny/lib/HTTP/Tiny.pm
@@ -4,7 +4,7 @@ use strict;
use warnings;
# ABSTRACT: A small, simple, correct HTTP/1.1 client
-our $VERSION = '0.076';
+our $VERSION = '0.078';
sub _croak { require Carp; Carp::croak(@_) }
@@ -26,8 +26,8 @@ sub _croak { require Carp; Carp::croak(@_) }
#pod scheme, host and port) (defaults to 1)
#pod * C<max_redirect> — Maximum number of redirects allowed (defaults to 5)
#pod * C<max_size> — Maximum response size in bytes (only when not using a data
-#pod callback). If defined, responses larger than this will return an
-#pod exception.
+#pod callback). If defined, requests with responses larger than this will return
+#pod a 599 status code.
#pod * C<http_proxy> — URL of a proxy server to use for HTTP connections
#pod (default is C<$ENV{http_proxy}> — if set)
#pod * C<https_proxy> — URL of a proxy server to use for HTTPS connections
@@ -38,23 +38,26 @@ sub _croak { require Carp; Carp::croak(@_) }
#pod be a comma-separated string or an array reference. (default is
#pod C<$ENV{no_proxy}> —)
#pod * C<timeout> — Request timeout in seconds (default is 60) If a socket open,
-#pod read or write takes longer than the timeout, an exception is thrown.
+#pod read or write takes longer than the timeout, the request response status code
+#pod will be 599.
#pod * C<verify_SSL> — A boolean that indicates whether to validate the SSL
#pod certificate of an C<https> — connection (default is false)
#pod * C<SSL_options> — A hashref of C<SSL_*> — options to pass through to
#pod L<IO::Socket::SSL>
#pod
+#pod An accessor/mutator method exists for each attribute.
+#pod
#pod Passing an explicit C<undef> for C<proxy>, C<http_proxy> or C<https_proxy> will
#pod prevent getting the corresponding proxies from the environment.
#pod
-#pod Exceptions from C<max_size>, C<timeout> or other errors will result in a
-#pod pseudo-HTTP status code of 599 and a reason of "Internal Exception". The
-#pod content field in the response will contain the text of the exception.
+#pod Errors during request execution will result in a pseudo-HTTP status code of 599
+#pod and a reason of "Internal Exception". The content field in the response will
+#pod contain the text of the error.
#pod
#pod The C<keep_alive> parameter enables a persistent connection, but only to a
-#pod single destination scheme, host and port. Also, if any connection-relevant
-#pod attributes are modified, or if the process ID or thread ID change, the
-#pod persistent connection will be dropped. If you want persistent connections
+#pod single destination scheme, host and port. If any connection-relevant
+#pod attributes are modified via accessor, or if the process ID or thread ID change,
+#pod the persistent connection will be dropped. If you want persistent connections
#pod across multiple destinations, use multiple HTTP::Tiny objects.
#pod
#pod See L</SSL SUPPORT> for more on the C<verify_SSL> and C<SSL_options> attributes.
@@ -152,7 +155,7 @@ sub _set_proxies {
# http proxy
if (! exists $self->{http_proxy} ) {
# under CGI, bypass HTTP_PROXY as request sets it from Proxy header
- local $ENV{HTTP_PROXY} if $ENV{REQUEST_METHOD};
+ local $ENV{HTTP_PROXY} = $ENV{CGI_HTTP_PROXY} if $ENV{REQUEST_METHOD};
$self->{http_proxy} = $ENV{http_proxy} || $ENV{HTTP_PROXY} || $self->{proxy};
}
@@ -186,7 +189,7 @@ sub _set_proxies {
return;
}
-#pod =method get|head|put|post|delete
+#pod =method get|head|put|post|patch|delete
#pod
#pod $response = $http->get($url);
#pod $response = $http->get($url, \%options);
@@ -200,7 +203,7 @@ sub _set_proxies {
#pod
#pod =cut
-for my $sub_name ( qw/get head put post delete/ ) {
+for my $sub_name ( qw/get head put post patch delete/ ) {
my $req_method = uc $sub_name;
no strict 'refs';
eval <<"HERE"; ## no critic
@@ -416,8 +419,8 @@ sub mirror {
#pod redirects in the same order that redirections occurred. If it does
#pod not exist, then no redirections occurred.
#pod
-#pod On an exception during the execution of the request, the C<status> field will
-#pod contain 599, and the C<content> field will contain the text of the exception.
+#pod On an error during the execution of the request, the C<status> field will
+#pod contain 599, and the C<content> field will contain the text of the error.
#pod
#pod =cut
@@ -434,7 +437,7 @@ sub request {
for ( 0 .. 1 ) {
$response = eval { $self->_request($method, $url, $args) };
last unless $@ && $idempotent{$method}
- && $@ =~ m{^(?:Socket closed|Unexpected end)};
+ && $@ =~ m{^(?:Socket closed|Unexpected end|SSL read error)};
}
if (my $e = $@) {
@@ -490,6 +493,8 @@ sub www_form_urlencode {
my @terms;
while( @params ) {
my ($key, $value) = splice(@params, 0, 2);
+ _croak("form data keys must not be undef")
+ if !defined($key);
if ( ref $value eq 'ARRAY' ) {
unshift @params, map { $key => $_ } @$value;
}
@@ -573,16 +578,8 @@ sub can_ssl {
sub connected {
my ($self) = @_;
- # If a socket exists...
- if ($self->{handle} && $self->{handle}{fh}) {
- my $socket = $self->{handle}{fh};
-
- # ...and is connected, return the peer host and port.
- if ($socket->connected) {
- return wantarray
- ? ($socket->peerhost, $socket->peerport)
- : join(':', $socket->peerhost, $socket->peerport);
- }
+ if ( $self->{handle} ) {
+ return $self->{handle}->connected;
}
return;
}
@@ -599,7 +596,9 @@ my %DefaultPort = (
sub _agent {
my $class = ref($_[0]) || $_[0];
(my $default_agent = $class) =~ s{::}{-}g;
- return $default_agent . "/" . $class->VERSION;
+ my $version = $class->VERSION;
+ $default_agent .= "/$version" if defined $version;
+ return $default_agent;
}
sub _request {
@@ -607,6 +606,10 @@ sub _request {
my ($scheme, $host, $port, $path_query, $auth) = $self->_split_url($url);
+ if ($scheme ne 'http' && $scheme ne 'https') {
+ die(qq/Unsupported URL scheme '$scheme'\n/);
+ }
+
my $request = {
method => $method,
scheme => $scheme,
@@ -659,6 +662,7 @@ sub _request {
}
if ( $self->{keep_alive}
+ && $handle->connected
&& $known_message_length
&& $response->{protocol} eq 'HTTP/1.1'
&& ($response->{headers}{connection} || '') ne 'close'
@@ -812,13 +816,25 @@ sub _prepare_headers_and_cb {
$request->{headers}{'connection'} = "close"
unless $self->{keep_alive};
+ # Some servers error on an empty-body PUT/POST without a content-length
+ if ( $request->{method} eq 'PUT' || $request->{method} eq 'POST' ) {
+ if (!defined($args->{content}) || !length($args->{content}) ) {
+ $request->{headers}{'content-length'} = 0;
+ }
+ }
+
if ( defined $args->{content} ) {
- if (ref $args->{content} eq 'CODE') {
- $request->{headers}{'content-type'} ||= "application/octet-stream";
- $request->{headers}{'transfer-encoding'} = 'chunked'
- unless $request->{headers}{'content-length'}
+ if ( ref $args->{content} eq 'CODE' ) {
+ if ( exists $request->{'content-length'} && $request->{'content-length'} == 0 ) {
+ $request->{cb} = sub { "" };
+ }
+ else {
+ $request->{headers}{'content-type'} ||= "application/octet-stream";
+ $request->{headers}{'transfer-encoding'} = 'chunked'
+ unless exists $request->{headers}{'content-length'}
|| $request->{headers}{'transfer-encoding'};
- $request->{cb} = $args->{content};
+ $request->{cb} = $args->{content};
+ }
}
elsif ( length $args->{content} ) {
my $content = $args->{content};
@@ -988,6 +1004,7 @@ my $unsafe_char = qr/[^A-Za-z0-9\-\._~]/;
sub _uri_escape {
my ($self, $str) = @_;
+ return "" if !defined $str;
if ( $] ge '5.008' ) {
utf8::encode($str);
}
@@ -1014,7 +1031,7 @@ use Socket qw[SOL_SOCKET SO_KEEPALIVE];
# not intended for general, per-client use and may be removed in the future
my $SOCKET_CLASS =
$ENV{PERL_HTTP_TINY_IPV4_ONLY} ? 'IO::Socket::INET' :
- eval { require IO::Socket::IP; IO::Socket::IP->VERSION(0.25) } ? 'IO::Socket::IP' :
+ eval { require IO::Socket::IP; IO::Socket::IP->VERSION(0.32) } ? 'IO::Socket::IP' :
'IO::Socket::INET';
sub BUFSIZE () { 32768 } ## no critic
@@ -1062,9 +1079,7 @@ sub connect {
if ( $scheme eq 'https' ) {
$self->_assert_ssl;
}
- elsif ( $scheme ne 'http' ) {
- die(qq/Unsupported URL scheme '$scheme'\n/);
- }
+
$self->{fh} = $SOCKET_CLASS->new(
PeerHost => $peer,
PeerPort => $port,
@@ -1097,6 +1112,16 @@ sub connect {
return $self;
}
+sub connected {
+ my ($self) = @_;
+ if ( $self->{fh} && $self->{fh}->connected ) {
+ return wantarray
+ ? ( $self->{fh}->peerhost, $self->{fh}->peerport )
+ : join( ':', $self->{fh}->peerhost, $self->{fh}->peerport );
+ }
+ return;
+}
+
sub start_ssl {
my ($self, $host) = @_;
@@ -1186,6 +1211,11 @@ sub read {
$len -= $take;
}
+ # Ignore SIGPIPE because SSL reads can result in writes that might error.
+ # See "Expecting exactly the same behavior as plain sockets" in
+ # https://metacpan.org/dist/IO-Socket-SSL/view/lib/IO/Socket/SSL.pod#Common-Usage-Errors
+ local $SIG{PIPE} = 'IGNORE';
+
while ($len > 0) {
$self->can_read
or die(q/Timed out while waiting for socket to become ready for reading/ . "\n");
@@ -1376,7 +1406,8 @@ sub read_body {
sub write_body {
@_ == 2 || die(q/Usage: $handle->write_body(request)/ . "\n");
my ($self, $request) = @_;
- if ($request->{headers}{'content-length'}) {
+ if (exists $request->{headers}{'content-length'}) {
+ return unless $request->{headers}{'content-length'};
return $self->write_content_body($request);
}
else {
@@ -1493,10 +1524,11 @@ sub read_response_header {
my $line = $self->readline;
- $line =~ /\A (HTTP\/(0*\d+\.0*\d+)) [\x09\x20]+ ([0-9]{3}) [\x09\x20]+ ([^\x0D\x0A]*) \x0D?\x0A/x
+ $line =~ /\A (HTTP\/(0*\d+\.0*\d+)) [\x09\x20]+ ([0-9]{3}) (?: [\x09\x20]+ ([^\x0D\x0A]*) )? \x0D?\x0A/x
or die(q/Malformed Status-Line: / . $Printable->($line). "\n");
my ($protocol, $version, $status, $reason) = ($1, $2, $3, $4);
+ $reason = "" unless defined $reason;
die (qq/Unsupported HTTP protocol: $protocol\n/)
unless $version =~ /0*1\.0*[01]/;
@@ -1672,7 +1704,7 @@ HTTP::Tiny - A small, simple, correct HTTP/1.1 client
=head1 VERSION
-version 0.076
+version 0.078
=head1 SYNOPSIS
@@ -1741,7 +1773,7 @@ C<max_redirect> — Maximum number of redirects allowed (defaults to 5)
=item *
-C<max_size> — Maximum response size in bytes (only when not using a data callback). If defined, responses larger than this will return an exception.
+C<max_size> — Maximum response size in bytes (only when not using a data callback). If defined, requests with responses larger than this will return a 599 status code.
=item *
@@ -1761,7 +1793,7 @@ C<no_proxy> — List of domain suffixes that should not be proxied. Must be a c
=item *
-C<timeout> — Request timeout in seconds (default is 60) If a socket open, read or write takes longer than the timeout, an exception is thrown.
+C<timeout> — Request timeout in seconds (default is 60) If a socket open, read or write takes longer than the timeout, the request response status code will be 599.
=item *
@@ -1773,22 +1805,24 @@ C<SSL_options> — A hashref of C<SSL_*> — options to pass through to L<IO::So
=back
+An accessor/mutator method exists for each attribute.
+
Passing an explicit C<undef> for C<proxy>, C<http_proxy> or C<https_proxy> will
prevent getting the corresponding proxies from the environment.
-Exceptions from C<max_size>, C<timeout> or other errors will result in a
-pseudo-HTTP status code of 599 and a reason of "Internal Exception". The
-content field in the response will contain the text of the exception.
+Errors during request execution will result in a pseudo-HTTP status code of 599
+and a reason of "Internal Exception". The content field in the response will
+contain the text of the error.
The C<keep_alive> parameter enables a persistent connection, but only to a
-single destination scheme, host and port. Also, if any connection-relevant
-attributes are modified, or if the process ID or thread ID change, the
-persistent connection will be dropped. If you want persistent connections
+single destination scheme, host and port. If any connection-relevant
+attributes are modified via accessor, or if the process ID or thread ID change,
+the persistent connection will be dropped. If you want persistent connections
across multiple destinations, use multiple HTTP::Tiny objects.
See L</SSL SUPPORT> for more on the C<verify_SSL> and C<SSL_options> attributes.
-=head2 get|head|put|post|delete
+=head2 get|head|put|post|patch|delete
$response = $http->get($url);
$response = $http->get($url, \%options);
@@ -1948,8 +1982,8 @@ C<redirects> If this field exists, it is an arrayref of response hash references
=back
-On an exception during the execution of the request, the C<status> field will
-contain 599, and the C<content> field will contain the text of the exception.
+On an error during the execution of the request, the C<status> field will
+contain 599, and the C<content> field will contain the text of the error.
=head2 www_form_urlencode
@@ -2012,8 +2046,8 @@ verify_SSL
=head1 SSL SUPPORT
Direct C<https> connections are supported only if L<IO::Socket::SSL> 1.56 or
-greater and L<Net::SSLeay> 1.49 or greater are installed. An exception will be
-thrown if new enough versions of these modules are not installed or if the SSL
+greater and L<Net::SSLeay> 1.49 or greater are installed. An error will occur
+if new enough versions of these modules are not installed or if the SSL
encryption fails. You can also use C<HTTP::Tiny::can_ssl()> utility function
that returns boolean to see if the required modules are installed.
@@ -2083,7 +2117,7 @@ system-specific default locations for a CA certificate file:
=back
-An exception will be raised if C<verify_SSL> is true and no CA certificate file
+An error will be occur if C<verify_SSL> is true and no CA certificate file
is available.
If you desire complete control over SSL connections, the C<SSL_options> attribute
@@ -2127,7 +2161,7 @@ all_proxy or ALL_PROXY
If the C<REQUEST_METHOD> environment variable is set, then this might be a CGI
process and C<HTTP_PROXY> would be set from the C<Proxy:> header, which is a
security risk. If C<REQUEST_METHOD> is set, C<HTTP_PROXY> (the upper case
-variant only) is ignored.
+variant only) is ignored, but C<CGI_HTTP_PROXY> is considered instead.
Tunnelling C<https> over an C<http> proxy using the CONNECT method is
supported. If your proxy uses C<https> itself, you can not tunnel C<https>
@@ -2178,7 +2212,7 @@ L<HTTP/1.1 specifications|http://www.w3.org/Protocols/>:
It attempts to meet all "MUST" requirements of the specification, but does not
implement all "SHOULD" requirements. (Note: it was developed against the
earlier RFC 2616 specification and may not yet meet the revised RFC 7230-7235
-spec.)
+spec.) Additionally, HTTP::Tiny supports the C<PATCH> method of RFC 5789.
Some particular limitations of note include:
@@ -2268,7 +2302,7 @@ L<Net::SSLeay> - Required for SSL support
=back
-=for :stopwords cpan testmatrix url annocpan anno bugtracker rt cpants kwalitee diff irc mailto metadata placeholders metacpan
+=for :stopwords cpan testmatrix url bugtracker rt cpants kwalitee diff irc mailto metadata placeholders metacpan
=head1 SUPPORT
@@ -2303,7 +2337,7 @@ David Golden <dagolden@cpan.org>
=head1 CONTRIBUTORS
-=for stopwords Alan Gardner Alessandro Ghedini A. Sinan Unur Brad Gilbert brian m. carlson Chris Nehren Weyl Claes Jakobsson Clinton Gormley Craig Berry David Golden Mitchell Dean Pearce Edward Zborowski Felipe Gasper James Raspass Jeremy Mates Jess Robinson Karen Etheridge Lukas Eklund Martin J. Evans Martin-Louis Bright Mike Doherty Nicolas Rochelemagne Olaf Alders Olivier Mengué Petr Písař Serguei Trouchelle Shoichi Kaji SkyMarshal Sören Kornetzki Steve Grazzini Syohei YOSHIDA Tatsuhiko Miyagawa Tom Hukins Tony Cook
+=for stopwords Alan Gardner Alessandro Ghedini A. Sinan Unur Brad Gilbert brian m. carlson Chris Nehren Weyl Claes Jakobsson Clinton Gormley Craig Berry David Golden Mitchell Dean Pearce Edward Zborowski Felipe Gasper Greg Kennedy James E Keenan Raspass Jeremy Mates Jess Robinson Karen Etheridge Lukas Eklund Martin J. Evans Martin-Louis Bright Matthew Horsfall Michael R. Davis Mike Doherty Nicolas Rochelemagne Olaf Alders Olivier Mengué Petr Písař sanjay-cpu Serguei Trouchelle Shoichi Kaji SkyMarshal Sören Kornetzki Steve Grazzini Syohei YOSHIDA Tatsuhiko Miyagawa Tom Hukins Tony Cook Xavier Guimard
=over 4
@@ -2373,6 +2407,14 @@ Felipe Gasper <felipe@felipegasper.com>
=item *
+Greg Kennedy <kennedy.greg@gmail.com>
+
+=item *
+
+James E Keenan <jkeenan@cpan.org>
+
+=item *
+
James Raspass <jraspass@gmail.com>
=item *
@@ -2401,6 +2443,14 @@ Martin-Louis Bright <mlbright@gmail.com>
=item *
+Matthew Horsfall <wolfsage@gmail.com>
+
+=item *
+
+Michael R. Davis <mrdvt92@users.noreply.github.com>
+
+=item *
+
Mike Doherty <doherty@cpan.org>
=item *
@@ -2421,6 +2471,10 @@ Petr Písař <ppisar@redhat.com>
=item *
+sanjay-cpu <snjkmr32@gmail.com>
+
+=item *
+
Serguei Trouchelle <stro@cpan.org>
=item *
@@ -2455,11 +2509,15 @@ Tom Hukins <tom@eborcom.com>
Tony Cook <tony@develop-help.com>
+=item *
+
+Xavier Guimard <yadd@debian.org>
+
=back
=head1 COPYRIGHT AND LICENSE
-This software is copyright (c) 2018 by Christian Hansen.
+This software is copyright (c) 2021 by Christian Hansen.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
diff --git a/cpan/HTTP-Tiny/t/001_api.t b/cpan/HTTP-Tiny/t/001_api.t
index 3e6864e5ce..48cc2f812c 100644
--- a/cpan/HTTP-Tiny/t/001_api.t
+++ b/cpan/HTTP-Tiny/t/001_api.t
@@ -11,7 +11,7 @@ my @accessors = qw(
max_redirect max_size proxy no_proxy timeout SSL_options verify_SSL cookie_jar
);
my @methods = qw(
- new get head put post delete post_form request mirror www_form_urlencode can_ssl
+ new get head put post patch delete post_form request mirror www_form_urlencode can_ssl
connected
);
diff --git a/cpan/HTTP-Tiny/t/002_croakage.t b/cpan/HTTP-Tiny/t/002_croakage.t
index ac3c8b93e4..331fda88a5 100644
--- a/cpan/HTTP-Tiny/t/002_croakage.t
+++ b/cpan/HTTP-Tiny/t/002_croakage.t
@@ -5,7 +5,7 @@ use warnings;
use Test::More;
use lib 't';
-use Util qw[tmpfile monkey_patch set_socket_source];
+use Util qw[tmpfile monkey_patch set_socket_source clear_socket_source];
use HTTP::Tiny;
@@ -35,6 +35,7 @@ my $res_fh = tmpfile();
my $req_fh = tmpfile();
my $http = HTTP::Tiny->new;
+clear_socket_source();
set_socket_source($req_fh, $res_fh);
for my $c ( @cases ) {
@@ -48,5 +49,21 @@ my $res = eval{ $http->get("http://www.example.com/", { headers => { host => "ww
is( $res->{status}, 599, "Providing a Host header errors with 599" );
like( $res->{content}, qr/'Host' header/, "Providing a Host header gives right error message" );
+$res = eval { $http->head("hxxp://www.example.com/") };
+is( $res->{status}, 599, "Error on unsupported scheme" );
+like(
+ $res->{content},
+ qr/Unsupported URL scheme 'hxxp'/,
+ "Error for unsupported scheme"
+);
+
+$res = eval { $http->post_form("http://www.example.com/", [undef, "123"]) };
+my $err = $@;
+like(
+ $err,
+ qr/form data keys must not be undef/,
+ "Error for undef key in form"
+);
+
done_testing;
diff --git a/cpan/HTTP-Tiny/t/003_agent.t b/cpan/HTTP-Tiny/t/003_agent.t
index 6962c66832..bc6188eef3 100644
--- a/cpan/HTTP-Tiny/t/003_agent.t
+++ b/cpan/HTTP-Tiny/t/003_agent.t
@@ -6,8 +6,8 @@ use warnings;
use Test::More tests => 8;
use HTTP::Tiny;
-# a couple tests to ensure that we get the default agent expected, the coorect
-# agent when specified, and the correct agent when specifified with a space at
+# a couple tests to ensure that we get the default agent expected, the correct
+# agent when specified, and the correct agent when specified with a space at
# the end of the string (as LWP::UserAgent does)
diff --git a/cpan/HTTP-Tiny/t/030_response.t b/cpan/HTTP-Tiny/t/030_response.t
index e519a62070..0694ad7495 100644
--- a/cpan/HTTP-Tiny/t/030_response.t
+++ b/cpan/HTTP-Tiny/t/030_response.t
@@ -34,3 +34,40 @@ sub _header {
is_deeply(_header($handle->read_response_header), $exp, "->read_response_header LF");
}
+{
+ # broken status-line
+ my $response = join $LF, "HTTP/08.15 66x Foo\nbar", 'Foo: Foo', 'Bar: Bar', '', '';
+ my $fh = tmpfile($response);
+ my $handle = HTTP::Tiny::Handle->new(fh => $fh);
+ my $res = eval{ $handle->read_response_header };
+ my $err = $@;
+ like $err, qr/Malformed Status-Line: /, '->read_response_header diagnoses malformed status line';
+}
+
+{
+ my $response = join $LF, "HTTP/2.0 200 Okish", 'Foo: Foo', 'Bar: Bar', '', '';
+ my $fh = tmpfile($response);
+ my $handle = HTTP::Tiny::Handle->new(fh => $fh);
+ my $res = eval{ $handle->read_response_header };
+ my $err = $@;
+ like $err, qr/Unsupported HTTP protocol: /, '->read_response_header unsupported HTTP protocol';
+}
+
+{
+ # strict RFC7230#3.1.2 compliance, require space after code
+ my $response = join $LF, 'HTTP/1.1 200 ', 'Foo: Foo', 'Bar: Bar', '', '';
+ my $fh = tmpfile($response);
+ my $handle = HTTP::Tiny::Handle->new(fh => $fh);
+ my $exp = [ 200, '', { foo => 'Foo', bar => 'Bar' }, 'HTTP/1.1' ];
+ is_deeply(_header($handle->read_response_header), $exp, "->read_response_header empty phrase preceded by SP");
+}
+
+{
+ # practical RFC7230#3.1.2 interpretation, require space after code
+ # only if there is a reason-phrase
+ my $response = join $LF, 'HTTP/1.1 200', 'Foo: Foo', 'Bar: Bar', '', '';
+ my $fh = tmpfile($response);
+ my $handle = HTTP::Tiny::Handle->new(fh => $fh);
+ my $exp = [ 200, '', { foo => 'Foo', bar => 'Bar' }, 'HTTP/1.1' ];
+ is_deeply(_header($handle->read_response_header), $exp, "->read_response_header empty phrase without preceding SP");
+}
diff --git a/cpan/HTTP-Tiny/t/100_get.t b/cpan/HTTP-Tiny/t/100_get.t
index 5dbf3e8a6c..17642af7a5 100644
--- a/cpan/HTTP-Tiny/t/100_get.t
+++ b/cpan/HTTP-Tiny/t/100_get.t
@@ -7,7 +7,8 @@ use File::Basename;
use Test::More 0.88;
use lib 't';
use Util qw[tmpfile rewind slurp monkey_patch dir_list parse_case
- hashify connect_args set_socket_source sort_headers $CRLF $LF];
+ hashify connect_args clear_socket_source set_socket_source sort_headers
+ $CRLF $LF];
use HTTP::Tiny;
BEGIN { monkey_patch() }
@@ -42,6 +43,7 @@ for my $file ( dir_list("corpus", qr/^get/ ) ) {
my $req_fh = tmpfile();
my $http = HTTP::Tiny->new(keep_alive => 0, %new_args);
+ clear_socket_source();
set_socket_source($req_fh, $res_fh);
(my $url_basename = $url) =~ s{.*/}{};
diff --git a/cpan/HTTP-Tiny/t/101_head.t b/cpan/HTTP-Tiny/t/101_head.t
index ace074566c..57062a5713 100644
--- a/cpan/HTTP-Tiny/t/101_head.t
+++ b/cpan/HTTP-Tiny/t/101_head.t
@@ -6,8 +6,8 @@ use warnings;
use File::Basename;
use Test::More 0.88;
use lib 't';
-use Util qw[tmpfile rewind slurp monkey_patch dir_list parse_case
- set_socket_source sort_headers $CRLF $LF];
+use Util qw[tmpfile rewind slurp monkey_patch dir_list parse_case
+ clear_socket_source set_socket_source sort_headers $CRLF $LF];
use HTTP::Tiny;
BEGIN { monkey_patch() }
@@ -47,6 +47,7 @@ for my $file ( dir_list("corpus", qr/^head/ ) ) {
my $req_fh = tmpfile();
my $http = HTTP::Tiny->new( keep_alive => 0 );
+ clear_socket_source();
set_socket_source($req_fh, $res_fh);
(my $url_basename = $url) =~ s{.*/}{};
diff --git a/cpan/HTTP-Tiny/t/102_put.t b/cpan/HTTP-Tiny/t/102_put.t
index 2fe3626dbc..57b2d97434 100644
--- a/cpan/HTTP-Tiny/t/102_put.t
+++ b/cpan/HTTP-Tiny/t/102_put.t
@@ -6,8 +6,8 @@ use warnings;
use File::Basename;
use Test::More 0.88;
use lib 't';
-use Util qw[tmpfile rewind slurp monkey_patch dir_list parse_case
- set_socket_source sort_headers $CRLF $LF];
+use Util qw[tmpfile rewind slurp monkey_patch dir_list parse_case
+ clear_socket_source set_socket_source sort_headers $CRLF $LF];
use HTTP::Tiny;
BEGIN { monkey_patch() }
@@ -34,6 +34,9 @@ for my $file ( dir_list("corpus", qr/^put/ ) ) {
if ( $case->{content} ) {
$options{content} = $case->{content}[0];
}
+ elsif ( exists $case->{content} ) {
+ $options{content} = "";
+ }
elsif ( $case->{content_cb} ) {
$options{content} = eval join "\n", @{$case->{content_cb}};
}
@@ -47,6 +50,7 @@ for my $file ( dir_list("corpus", qr/^put/ ) ) {
my $req_fh = tmpfile();
my $http = HTTP::Tiny->new( keep_alive => 0 );
+ clear_socket_source();
set_socket_source($req_fh, $res_fh);
(my $url_basename = $url) =~ s{.*/}{};
diff --git a/cpan/HTTP-Tiny/t/103_delete.t b/cpan/HTTP-Tiny/t/103_delete.t
index 66d345b698..39276ebafb 100644
--- a/cpan/HTTP-Tiny/t/103_delete.t
+++ b/cpan/HTTP-Tiny/t/103_delete.t
@@ -6,8 +6,8 @@ use warnings;
use File::Basename;
use Test::More 0.88;
use lib 't';
-use Util qw[tmpfile rewind slurp monkey_patch dir_list parse_case
- set_socket_source sort_headers $CRLF $LF];
+use Util qw[tmpfile rewind slurp monkey_patch dir_list parse_case
+ clear_socket_source set_socket_source sort_headers $CRLF $LF];
use HTTP::Tiny;
BEGIN { monkey_patch() }
@@ -47,6 +47,7 @@ for my $file ( dir_list("corpus", qr/^delete/ ) ) {
my $req_fh = tmpfile();
my $http = HTTP::Tiny->new( keep_alive => 0 );
+ clear_socket_source();
set_socket_source($req_fh, $res_fh);
(my $url_basename = $url) =~ s{.*/}{};
diff --git a/cpan/HTTP-Tiny/t/104_post.t b/cpan/HTTP-Tiny/t/104_post.t
index 9c765bd56b..ba49a0e37b 100644
--- a/cpan/HTTP-Tiny/t/104_post.t
+++ b/cpan/HTTP-Tiny/t/104_post.t
@@ -6,8 +6,8 @@ use warnings;
use File::Basename;
use Test::More 0.88;
use lib 't';
-use Util qw[tmpfile rewind slurp monkey_patch dir_list parse_case
- set_socket_source sort_headers $CRLF $LF];
+use Util qw[tmpfile rewind slurp monkey_patch dir_list parse_case
+ clear_socket_source set_socket_source sort_headers $CRLF $LF];
use HTTP::Tiny;
BEGIN { monkey_patch() }
@@ -47,6 +47,7 @@ for my $file ( dir_list("corpus", qr/^post/ ) ) {
my $req_fh = tmpfile();
my $http = HTTP::Tiny->new( keep_alive => 0 );
+ clear_socket_source();
set_socket_source($req_fh, $res_fh);
(my $url_basename = $url) =~ s{.*/}{};
diff --git a/cpan/HTTP-Tiny/t/110_mirror.t b/cpan/HTTP-Tiny/t/110_mirror.t
index de38fd128a..30a8b352e8 100644
--- a/cpan/HTTP-Tiny/t/110_mirror.t
+++ b/cpan/HTTP-Tiny/t/110_mirror.t
@@ -6,8 +6,8 @@ use warnings;
use File::Basename;
use Test::More 0.88;
use lib 't';
-use Util qw[tmpfile rewind slurp monkey_patch dir_list parse_case
- set_socket_source sort_headers $CRLF $LF];
+use Util qw[tmpfile rewind slurp monkey_patch dir_list parse_case
+ clear_socket_source set_socket_source sort_headers $CRLF $LF];
use HTTP::Tiny;
use File::Temp qw/tempdir/;
use File::Spec;
@@ -64,6 +64,7 @@ for my $file ( dir_list("corpus", qr/^mirror/ ) ) {
my $req_fh = tmpfile();
my $http = HTTP::Tiny->new( keep_alive => 0 );
+ clear_socket_source();
set_socket_source($req_fh, $res_fh);
my @call_args = %options ? ($url, $tempfile, \%options) : ($url, $tempfile);
diff --git a/cpan/HTTP-Tiny/t/140_proxy.t b/cpan/HTTP-Tiny/t/140_proxy.t
index dd38462824..bd558e6bce 100644
--- a/cpan/HTTP-Tiny/t/140_proxy.t
+++ b/cpan/HTTP-Tiny/t/140_proxy.t
@@ -80,4 +80,14 @@ for my $var ( qw/http_proxy https_proxy all_proxy/ ) {
}
+# allow CGI_HTTP_PROXY with REQUEST_METHOD
+{
+ local $ENV{HTTP_PROXY} = "http://localhost:8080";
+ local $ENV{CGI_HTTP_PROXY} = "http://localhost:9090";
+ local $ENV{REQUEST_METHOD} = 'GET';
+ my $c = HTTP::Tiny->new();
+ is($c->http_proxy, "http://localhost:9090",
+ "http_proxy set from CGI_HTTP_PROXY if REQUEST_METHOD set");
+}
+
done_testing();
diff --git a/cpan/HTTP-Tiny/t/150_post_form.t b/cpan/HTTP-Tiny/t/150_post_form.t
index 790cbc0481..0e76600c4b 100644
--- a/cpan/HTTP-Tiny/t/150_post_form.t
+++ b/cpan/HTTP-Tiny/t/150_post_form.t
@@ -7,8 +7,8 @@ use open IN => ':raw';
use File::Basename;
use Test::More 0.88;
use lib 't';
-use Util qw[tmpfile rewind slurp monkey_patch dir_list parse_case
- set_socket_source sort_headers $CRLF $LF];
+use Util qw[tmpfile rewind slurp monkey_patch dir_list parse_case
+ clear_socket_source set_socket_source sort_headers $CRLF $LF];
use HTTP::Tiny;
BEGIN { monkey_patch() }
@@ -38,6 +38,9 @@ for my $file ( dir_list("corpus", qr/^form/ ) ) {
if ( $case->{datatype}[0] eq 'HASH' ) {
while ( @params ) {
my ($key, $value) = splice( @params, 0, 2 );
+ if ($value eq "<undef>") {
+ $value = undef;
+ }
if ( ref $formdata->{$key} ) {
push @{$formdata->{$key}}, $value;
}
@@ -50,7 +53,7 @@ for my $file ( dir_list("corpus", qr/^form/ ) ) {
}
}
else {
- $formdata = [ @params ];
+ $formdata = [ map { $_ eq "<undef>" ? undef : $_ } @params ];
}
# setup mocking and test
@@ -58,6 +61,7 @@ for my $file ( dir_list("corpus", qr/^form/ ) ) {
my $req_fh = tmpfile();
my $http = HTTP::Tiny->new( keep_alive => 0 );
+ clear_socket_source();
set_socket_source($req_fh, $res_fh);
(my $url_basename = $url) =~ s{.*/}{};
diff --git a/cpan/HTTP-Tiny/t/Util.pm b/cpan/HTTP-Tiny/t/Util.pm
index 2e85b04823..6537b7e421 100644
--- a/cpan/HTTP-Tiny/t/Util.pm
+++ b/cpan/HTTP-Tiny/t/Util.pm
@@ -87,6 +87,7 @@ sub parse_case {
my ($case) = @_;
my %args;
my $key = '';
+ my %seen;
for my $line ( split "\n", $case ) {
chomp $line;
if ( substr($line,0,1) eq q{ } ) {
@@ -95,8 +96,12 @@ sub parse_case {
}
else {
$key = $line;
+ $seen{$key}++;
}
}
+ for my $k (keys %seen) {
+ $args{$k}=undef unless exists $args{$k};
+ }
return \%args;
}
@@ -168,6 +173,7 @@ sub sort_headers {
$self->{fh} = shift @res_fh;
};
*HTTP::Tiny::Handle::close = sub { 1 }; # don't close our temps
+ *HTTP::Tiny::Handle::connected = sub { 1 };
# don't try to proxy in mock-mode
delete $ENV{$_} for map { $_, uc($_) } qw/http_proxy https_proxy all_proxy/;