xref: /openbsd-src/gnu/usr.bin/perl/cpan/HTTP-Tiny/lib/HTTP/Tiny.pm (revision 0b7734b3d77bb9b21afec6f4621cae6c805dbd45)
1# vim: ts=4 sts=4 sw=4 et:
2package HTTP::Tiny;
3use strict;
4use warnings;
5# ABSTRACT: A small, simple, correct HTTP/1.1 client
6our $VERSION = '0.043_01'; # VERSION
7
8use Carp ();
9
10# =method new
11#
12#     $http = HTTP::Tiny->new( %attributes );
13#
14# This constructor returns a new HTTP::Tiny object.  Valid attributes include:
15#
16# =for :list
17# * C<agent>
18# A user-agent string (defaults to 'HTTP-Tiny/$VERSION'). If C<agent> ends in a space character, the default user-agent string is appended.
19# * C<cookie_jar>
20# An instance of L<HTTP::CookieJar> or equivalent class that supports the C<add> and C<cookie_header> methods
21# * C<default_headers>
22# A hashref of default headers to apply to requests
23# * C<local_address>
24# The local IP address to bind to
25# * C<keep_alive>
26# Whether to reuse the last connection (if for the same scheme, host and port) (defaults to 1)
27# * C<max_redirect>
28# Maximum number of redirects allowed (defaults to 5)
29# * C<max_size>
30# Maximum response size (only when not using a data callback).  If defined, responses larger than this will return an exception.
31# * C<http_proxy>
32# URL of a proxy server to use for HTTP connections (default is C<$ENV{http_proxy}> if set)
33# * C<https_proxy>
34# URL of a proxy server to use for HTTPS connections (default is C<$ENV{https_proxy}> if set)
35# * C<proxy>
36# URL of a generic proxy server for both HTTP and HTTPS connections (default is C<$ENV{all_proxy}> if set)
37# * C<no_proxy>
38# List of domain suffixes that should not be proxied.  Must be a comma-separated string or an array reference. (default is C<$ENV{no_proxy}>)
39# * C<timeout>
40# Request timeout in seconds (default is 60)
41# * C<verify_SSL>
42# A boolean that indicates whether to validate the SSL certificate of an C<https>
43# connection (default is false)
44# * C<SSL_options>
45# A hashref of C<SSL_*> options to pass through to L<IO::Socket::SSL>
46#
47# Exceptions from C<max_size>, C<timeout> or other errors will result in a
48# pseudo-HTTP status code of 599 and a reason of "Internal Exception". The
49# content field in the response will contain the text of the exception.
50#
51# The C<keep_alive> parameter enables a persistent connection, but only to a
52# single destination scheme, host and port.  Also, if any connection-relevant
53# attributes are modified, a persistent connection will be dropped.  If you want
54# persistent connections across multiple destinations, use multiple HTTP::Tiny
55# objects.
56#
57# See L</SSL SUPPORT> for more on the C<verify_SSL> and C<SSL_options> attributes.
58#
59# =cut
60
61my @attributes;
62BEGIN {
63    @attributes = qw(
64        cookie_jar default_headers http_proxy https_proxy keep_alive
65        local_address max_redirect max_size proxy no_proxy timeout
66        SSL_options verify_SSL
67    );
68    my %persist_ok = map {; $_ => 1 } qw(
69        cookie_jar default_headers max_redirect max_size
70    );
71    no strict 'refs';
72    no warnings 'uninitialized';
73    for my $accessor ( @attributes ) {
74        *{$accessor} = sub {
75            @_ > 1
76                ? do {
77                    delete $_[0]->{handle} if !$persist_ok{$accessor} && $_[1] ne $_[0]->{$accessor};
78                    $_[0]->{$accessor} = $_[1]
79                }
80                : $_[0]->{$accessor};
81        };
82    }
83}
84
85sub agent {
86    my($self, $agent) = @_;
87    if( @_ > 1 ){
88        $self->{agent} =
89            (defined $agent && $agent =~ / $/) ? $agent . $self->_agent : $agent;
90    }
91    return $self->{agent};
92}
93
94sub new {
95    my($class, %args) = @_;
96
97    my $self = {
98        max_redirect => 5,
99        timeout      => 60,
100        keep_alive   => 1,
101        verify_SSL   => $args{verify_SSL} || $args{verify_ssl} || 0, # no verification by default
102        no_proxy     => $ENV{no_proxy},
103    };
104
105    bless $self, $class;
106
107    $class->_validate_cookie_jar( $args{cookie_jar} ) if $args{cookie_jar};
108
109    for my $key ( @attributes ) {
110        $self->{$key} = $args{$key} if exists $args{$key}
111    }
112
113    $self->agent( exists $args{agent} ? $args{agent} : $class->_agent );
114
115    $self->_set_proxies;
116
117    return $self;
118}
119
120sub _set_proxies {
121    my ($self) = @_;
122
123    if (! $self->{proxy} ) {
124        $self->{proxy} = $ENV{all_proxy} || $ENV{ALL_PROXY};
125        if ( defined $self->{proxy} ) {
126            $self->_split_proxy( 'generic proxy' => $self->{proxy} ); # validate
127        }
128        else {
129            delete $self->{proxy};
130        }
131    }
132
133    if (! $self->{http_proxy} ) {
134        $self->{http_proxy} = $ENV{http_proxy} || $self->{proxy};
135        if ( defined $self->{http_proxy} ) {
136            $self->_split_proxy( http_proxy => $self->{http_proxy} ); # validate
137            $self->{_has_proxy}{http} = 1;
138        }
139        else {
140            delete $self->{http_proxy};
141        }
142    }
143
144    if (! $self->{https_proxy} ) {
145        $self->{https_proxy} = $ENV{https_proxy} || $ENV{HTTPS_PROXY} || $self->{proxy};
146        if ( $self->{https_proxy} ) {
147            $self->_split_proxy( https_proxy => $self->{https_proxy} ); # validate
148            $self->{_has_proxy}{https} = 1;
149        }
150        else {
151            delete $self->{https_proxy};
152        }
153    }
154
155    # Split no_proxy to array reference if not provided as such
156    unless ( ref $self->{no_proxy} eq 'ARRAY' ) {
157        $self->{no_proxy} =
158            (defined $self->{no_proxy}) ? [ split /\s*,\s*/, $self->{no_proxy} ] : [];
159    }
160
161    return;
162}
163
164# =method get|head|put|post|delete
165#
166#     $response = $http->get($url);
167#     $response = $http->get($url, \%options);
168#     $response = $http->head($url);
169#
170# These methods are shorthand for calling C<request()> for the given method.  The
171# URL must have unsafe characters escaped and international domain names encoded.
172# See C<request()> for valid options and a description of the response.
173#
174# The C<success> field of the response will be true if the status code is 2XX.
175#
176# =cut
177
178for my $sub_name ( qw/get head put post delete/ ) {
179    my $req_method = uc $sub_name;
180    no strict 'refs';
181    eval <<"HERE"; ## no critic
182    sub $sub_name {
183        my (\$self, \$url, \$args) = \@_;
184        \@_ == 2 || (\@_ == 3 && ref \$args eq 'HASH')
185        or Carp::croak(q/Usage: \$http->$sub_name(URL, [HASHREF])/ . "\n");
186        return \$self->request('$req_method', \$url, \$args || {});
187    }
188HERE
189}
190
191# =method post_form
192#
193#     $response = $http->post_form($url, $form_data);
194#     $response = $http->post_form($url, $form_data, \%options);
195#
196# This method executes a C<POST> request and sends the key/value pairs from a
197# form data hash or array reference to the given URL with a C<content-type> of
198# C<application/x-www-form-urlencoded>.  If data is provided as an array
199# reference, the order is preserved; if provided as a hash reference, the terms
200# are sorted on key and value for consistency.  See documentation for the
201# C<www_form_urlencode> method for details on the encoding.
202#
203# The URL must have unsafe characters escaped and international domain names
204# encoded.  See C<request()> for valid options and a description of the response.
205# Any C<content-type> header or content in the options hashref will be ignored.
206#
207# The C<success> field of the response will be true if the status code is 2XX.
208#
209# =cut
210
211sub post_form {
212    my ($self, $url, $data, $args) = @_;
213    (@_ == 3 || @_ == 4 && ref $args eq 'HASH')
214        or Carp::croak(q/Usage: $http->post_form(URL, DATAREF, [HASHREF])/ . "\n");
215
216    my $headers = {};
217    while ( my ($key, $value) = each %{$args->{headers} || {}} ) {
218        $headers->{lc $key} = $value;
219    }
220    delete $args->{headers};
221
222    return $self->request('POST', $url, {
223            %$args,
224            content => $self->www_form_urlencode($data),
225            headers => {
226                %$headers,
227                'content-type' => 'application/x-www-form-urlencoded'
228            },
229        }
230    );
231}
232
233# =method mirror
234#
235#     $response = $http->mirror($url, $file, \%options)
236#     if ( $response->{success} ) {
237#         print "$file is up to date\n";
238#     }
239#
240# Executes a C<GET> request for the URL and saves the response body to the file
241# name provided.  The URL must have unsafe characters escaped and international
242# domain names encoded.  If the file already exists, the request will include an
243# C<If-Modified-Since> header with the modification timestamp of the file.  You
244# may specify a different C<If-Modified-Since> header yourself in the C<<
245# $options->{headers} >> hash.
246#
247# The C<success> field of the response will be true if the status code is 2XX
248# or if the status code is 304 (unmodified).
249#
250# If the file was modified and the server response includes a properly
251# formatted C<Last-Modified> header, the file modification time will
252# be updated accordingly.
253#
254# =cut
255
256sub mirror {
257    my ($self, $url, $file, $args) = @_;
258    @_ == 3 || (@_ == 4 && ref $args eq 'HASH')
259      or Carp::croak(q/Usage: $http->mirror(URL, FILE, [HASHREF])/ . "\n");
260    if ( -e $file and my $mtime = (stat($file))[9] ) {
261        $args->{headers}{'if-modified-since'} ||= $self->_http_date($mtime);
262    }
263    my $tempfile = $file . int(rand(2**31));
264
265    require Fcntl;
266    sysopen my $fh, $tempfile, Fcntl::O_CREAT()|Fcntl::O_EXCL()|Fcntl::O_WRONLY()
267       or Carp::croak(qq/Error: Could not create temporary file $tempfile for downloading: $!\n/);
268    binmode $fh;
269    $args->{data_callback} = sub { print {$fh} $_[0] };
270    my $response = $self->request('GET', $url, $args);
271    close $fh
272        or Carp::croak(qq/Error: Caught error closing temporary file $tempfile: $!\n/);
273
274    if ( $response->{success} ) {
275        rename $tempfile, $file
276            or Carp::croak(qq/Error replacing $file with $tempfile: $!\n/);
277        my $lm = $response->{headers}{'last-modified'};
278        if ( $lm and my $mtime = $self->_parse_http_date($lm) ) {
279            utime $mtime, $mtime, $file;
280        }
281    }
282    $response->{success} ||= $response->{status} eq '304';
283    unlink $tempfile;
284    return $response;
285}
286
287# =method request
288#
289#     $response = $http->request($method, $url);
290#     $response = $http->request($method, $url, \%options);
291#
292# Executes an HTTP request of the given method type ('GET', 'HEAD', 'POST',
293# 'PUT', etc.) on the given URL.  The URL must have unsafe characters escaped and
294# international domain names encoded.
295#
296# If the URL includes a "user:password" stanza, they will be used for Basic-style
297# authorization headers.  (Authorization headers will not be included in a
298# redirected request.) For example:
299#
300#     $http->request('GET', 'http://Aladdin:open sesame@example.com/');
301#
302# If the "user:password" stanza contains reserved characters, they must
303# be percent-escaped:
304#
305#     $http->request('GET', 'http://john%40example.com:password@example.com/');
306#
307# A hashref of options may be appended to modify the request.
308#
309# Valid options are:
310#
311# =for :list
312# * C<headers>
313# A hashref containing headers to include with the request.  If the value for
314# a header is an array reference, the header will be output multiple times with
315# each value in the array.  These headers over-write any default headers.
316# * C<content>
317# A scalar to include as the body of the request OR a code reference
318# that will be called iteratively to produce the body of the request
319# * C<trailer_callback>
320# A code reference that will be called if it exists to provide a hashref
321# of trailing headers (only used with chunked transfer-encoding)
322# * C<data_callback>
323# A code reference that will be called for each chunks of the response
324# body received.
325#
326# If the C<content> option is a code reference, it will be called iteratively
327# to provide the content body of the request.  It should return the empty
328# string or undef when the iterator is exhausted.
329#
330# If the C<content> option is the empty string, no C<content-type> or
331# C<content-length> headers will be generated.
332#
333# If the C<data_callback> option is provided, it will be called iteratively until
334# the entire response body is received.  The first argument will be a string
335# containing a chunk of the response body, the second argument will be the
336# in-progress response hash reference, as described below.  (This allows
337# customizing the action of the callback based on the C<status> or C<headers>
338# received prior to the content body.)
339#
340# The C<request> method returns a hashref containing the response.  The hashref
341# will have the following keys:
342#
343# =for :list
344# * C<success>
345# Boolean indicating whether the operation returned a 2XX status code
346# * C<url>
347# URL that provided the response. This is the URL of the request unless
348# there were redirections, in which case it is the last URL queried
349# in a redirection chain
350# * C<status>
351# The HTTP status code of the response
352# * C<reason>
353# The response phrase returned by the server
354# * C<content>
355# The body of the response.  If the response does not have any content
356# or if a data callback is provided to consume the response body,
357# this will be the empty string
358# * C<headers>
359# A hashref of header fields.  All header field names will be normalized
360# to be lower case. If a header is repeated, the value will be an arrayref;
361# it will otherwise be a scalar string containing the value
362#
363# On an exception during the execution of the request, the C<status> field will
364# contain 599, and the C<content> field will contain the text of the exception.
365#
366# =cut
367
368my %idempotent = map { $_ => 1 } qw/GET HEAD PUT DELETE OPTIONS TRACE/;
369
370sub request {
371    my ($self, $method, $url, $args) = @_;
372    @_ == 3 || (@_ == 4 && ref $args eq 'HASH')
373      or Carp::croak(q/Usage: $http->request(METHOD, URL, [HASHREF])/ . "\n");
374    $args ||= {}; # we keep some state in this during _request
375
376    # RFC 2616 Section 8.1.4 mandates a single retry on broken socket
377    my $response;
378    for ( 0 .. 1 ) {
379        $response = eval { $self->_request($method, $url, $args) };
380        last unless $@ && $idempotent{$method}
381            && $@ =~ m{^(?:Socket closed|Unexpected end)};
382    }
383
384    if (my $e = $@) {
385        # maybe we got a response hash thrown from somewhere deep
386        if ( ref $e eq 'HASH' && exists $e->{status} ) {
387            return $e;
388        }
389
390        # otherwise, stringify it
391        $e = "$e";
392        $response = {
393            url     => $url,
394            success => q{},
395            status  => 599,
396            reason  => 'Internal Exception',
397            content => $e,
398            headers => {
399                'content-type'   => 'text/plain',
400                'content-length' => length $e,
401            }
402        };
403    }
404    return $response;
405}
406
407# =method www_form_urlencode
408#
409#     $params = $http->www_form_urlencode( $data );
410#     $response = $http->get("http://example.com/query?$params");
411#
412# This method converts the key/value pairs from a data hash or array reference
413# into a C<x-www-form-urlencoded> string.  The keys and values from the data
414# reference will be UTF-8 encoded and escaped per RFC 3986.  If a value is an
415# array reference, the key will be repeated with each of the values of the array
416# reference.  If data is provided as a hash reference, the key/value pairs in the
417# resulting string will be sorted by key and value for consistent ordering.
418#
419# =cut
420
421sub www_form_urlencode {
422    my ($self, $data) = @_;
423    (@_ == 2 && ref $data)
424        or Carp::croak(q/Usage: $http->www_form_urlencode(DATAREF)/ . "\n");
425    (ref $data eq 'HASH' || ref $data eq 'ARRAY')
426        or Carp::croak("form data must be a hash or array reference\n");
427
428    my @params = ref $data eq 'HASH' ? %$data : @$data;
429    @params % 2 == 0
430        or Carp::croak("form data reference must have an even number of terms\n");
431
432    my @terms;
433    while( @params ) {
434        my ($key, $value) = splice(@params, 0, 2);
435        if ( ref $value eq 'ARRAY' ) {
436            unshift @params, map { $key => $_ } @$value;
437        }
438        else {
439            push @terms, join("=", map { $self->_uri_escape($_) } $key, $value);
440        }
441    }
442
443    return join("&", (ref $data eq 'ARRAY') ? (@terms) : (sort @terms) );
444}
445
446#--------------------------------------------------------------------------#
447# private methods
448#--------------------------------------------------------------------------#
449
450my %DefaultPort = (
451    http => 80,
452    https => 443,
453);
454
455sub _agent {
456    my $class = ref($_[0]) || $_[0];
457    (my $default_agent = $class) =~ s{::}{-}g;
458    return $default_agent . "/" . ($class->VERSION || 0);
459}
460
461sub _request {
462    my ($self, $method, $url, $args) = @_;
463
464    my ($scheme, $host, $port, $path_query, $auth) = $self->_split_url($url);
465
466    my $request = {
467        method    => $method,
468        scheme    => $scheme,
469        host      => $host,
470        host_port => ($port == $DefaultPort{$scheme} ? $host : "$host:$port"),
471        uri       => $path_query,
472        headers   => {},
473    };
474
475    # We remove the cached handle so it is not reused in the case of redirect.
476    # If all is well, it will be recached at the end of _request.  We only
477    # reuse for the same scheme, host and port
478    my $handle = delete $self->{handle};
479    if ( $handle ) {
480        unless ( $handle->can_reuse( $scheme, $host, $port ) ) {
481            $handle->close;
482            undef $handle;
483        }
484    }
485    $handle ||= $self->_open_handle( $request, $scheme, $host, $port );
486
487    $self->_prepare_headers_and_cb($request, $args, $url, $auth);
488    $handle->write_request($request);
489
490    my $response;
491    do { $response = $handle->read_response_header }
492        until (substr($response->{status},0,1) ne '1');
493
494    $self->_update_cookie_jar( $url, $response ) if $self->{cookie_jar};
495
496    if ( my @redir_args = $self->_maybe_redirect($request, $response, $args) ) {
497        $handle->close;
498        return $self->_request(@redir_args, $args);
499    }
500
501    my $known_message_length;
502    if ($method eq 'HEAD' || $response->{status} =~ /^[23]04/) {
503        # response has no message body
504        $known_message_length = 1;
505    }
506    else {
507        my $data_cb = $self->_prepare_data_cb($response, $args);
508        $known_message_length = $handle->read_body($data_cb, $response);
509    }
510
511    if ( $self->{keep_alive}
512        && $known_message_length
513        && $response->{protocol} eq 'HTTP/1.1'
514        && ($response->{headers}{connection} || '') ne 'close'
515    ) {
516        $self->{handle} = $handle;
517    }
518    else {
519        $handle->close;
520    }
521
522    $response->{success} = substr( $response->{status}, 0, 1 ) eq '2';
523    $response->{url} = $url;
524    return $response;
525}
526
527sub _open_handle {
528    my ($self, $request, $scheme, $host, $port) = @_;
529
530    my $handle  = HTTP::Tiny::Handle->new(
531        timeout         => $self->{timeout},
532        SSL_options     => $self->{SSL_options},
533        verify_SSL      => $self->{verify_SSL},
534        local_address   => $self->{local_address},
535        keep_alive      => $self->{keep_alive}
536    );
537
538    if ($self->{_has_proxy}{$scheme} && ! grep { $host =~ /\Q$_\E$/ } @{$self->{no_proxy}}) {
539        return $self->_proxy_connect( $request, $handle );
540    }
541    else {
542        return $handle->connect($scheme, $host, $port);
543    }
544}
545
546sub _proxy_connect {
547    my ($self, $request, $handle) = @_;
548
549    my @proxy_vars;
550    if ( $request->{scheme} eq 'https' ) {
551        Carp::croak(qq{No https_proxy defined}) unless $self->{https_proxy};
552        @proxy_vars = $self->_split_proxy( https_proxy => $self->{https_proxy} );
553        if ( $proxy_vars[0] eq 'https' ) {
554            Carp::croak(qq{Can't proxy https over https: $request->{uri} via $self->{https_proxy}});
555        }
556    }
557    else {
558        Carp::croak(qq{No http_proxy defined}) unless $self->{http_proxy};
559        @proxy_vars = $self->_split_proxy( http_proxy => $self->{http_proxy} );
560    }
561
562    my ($p_scheme, $p_host, $p_port, $p_auth) = @proxy_vars;
563
564    if ( length $p_auth && ! defined $request->{headers}{'proxy-authorization'} ) {
565        $self->_add_basic_auth_header( $request, 'proxy-authorization' => $p_auth );
566    }
567
568    $handle->connect($p_scheme, $p_host, $p_port);
569
570    if ($request->{scheme} eq 'https') {
571        $self->_create_proxy_tunnel( $request, $handle );
572    }
573    else {
574        # non-tunneled proxy requires absolute URI
575        $request->{uri} = "$request->{scheme}://$request->{host_port}$request->{uri}";
576    }
577
578    return $handle;
579}
580
581sub _split_proxy {
582    my ($self, $type, $proxy) = @_;
583
584    my ($scheme, $host, $port, $path_query, $auth) = eval { $self->_split_url($proxy) };
585
586    unless(
587        defined($scheme) && length($scheme) && length($host) && length($port)
588        && $path_query eq '/'
589    ) {
590        Carp::croak(qq{$type URL must be in format http[s]://[auth@]<host>:<port>/\n});
591    }
592
593    return ($scheme, $host, $port, $auth);
594}
595
596sub _create_proxy_tunnel {
597    my ($self, $request, $handle) = @_;
598
599    $handle->_assert_ssl;
600
601    my $agent = exists($request->{headers}{'user-agent'})
602        ? $request->{headers}{'user-agent'} : $self->{agent};
603
604    my $connect_request = {
605        method    => 'CONNECT',
606        uri       => $request->{host_port},
607        headers   => {
608            host => $request->{host_port},
609            'user-agent' => $agent,
610        }
611    };
612
613    if ( $request->{headers}{'proxy-authorization'} ) {
614        $connect_request->{headers}{'proxy-authorization'} =
615            delete $request->{headers}{'proxy-authorization'};
616    }
617
618    $handle->write_request($connect_request);
619    my $response;
620    do { $response = $handle->read_response_header }
621        until (substr($response->{status},0,1) ne '1');
622
623    # if CONNECT failed, throw the response so it will be
624    # returned from the original request() method;
625    unless (substr($response->{status},0,1) eq '2') {
626        die $response;
627    }
628
629    # tunnel established, so start SSL handshake
630    $handle->start_ssl( $request->{host} );
631
632    return;
633}
634
635sub _prepare_headers_and_cb {
636    my ($self, $request, $args, $url, $auth) = @_;
637
638    for ($self->{default_headers}, $args->{headers}) {
639        next unless defined;
640        while (my ($k, $v) = each %$_) {
641            $request->{headers}{lc $k} = $v;
642        }
643    }
644    $request->{headers}{'host'}         = $request->{host_port};
645    $request->{headers}{'user-agent'} ||= $self->{agent};
646    $request->{headers}{'connection'}   = "close"
647        unless $self->{keep_alive};
648
649    if ( defined $args->{content} ) {
650        if (ref $args->{content} eq 'CODE') {
651            $request->{headers}{'content-type'} ||= "application/octet-stream";
652            $request->{headers}{'transfer-encoding'} = 'chunked'
653              unless $request->{headers}{'content-length'}
654                  || $request->{headers}{'transfer-encoding'};
655            $request->{cb} = $args->{content};
656        }
657        elsif ( length $args->{content} ) {
658            my $content = $args->{content};
659            if ( $] ge '5.008' ) {
660                utf8::downgrade($content, 1)
661                    or die(qq/Wide character in request message body\n/);
662            }
663            $request->{headers}{'content-type'} ||= "application/octet-stream";
664            $request->{headers}{'content-length'} = length $content
665              unless $request->{headers}{'content-length'}
666                  || $request->{headers}{'transfer-encoding'};
667            $request->{cb} = sub { substr $content, 0, length $content, '' };
668        }
669        $request->{trailer_cb} = $args->{trailer_callback}
670            if ref $args->{trailer_callback} eq 'CODE';
671    }
672
673    ### If we have a cookie jar, then maybe add relevant cookies
674    if ( $self->{cookie_jar} ) {
675        my $cookies = $self->cookie_jar->cookie_header( $url );
676        $request->{headers}{cookie} = $cookies if length $cookies;
677    }
678
679    # if we have Basic auth parameters, add them
680    if ( length $auth && ! defined $request->{headers}{authorization} ) {
681        $self->_add_basic_auth_header( $request, 'authorization' => $auth );
682    }
683
684    return;
685}
686
687sub _add_basic_auth_header {
688    my ($self, $request, $header, $auth) = @_;
689    require MIME::Base64;
690    $request->{headers}{$header} =
691        "Basic " . MIME::Base64::encode_base64($auth, "");
692    return;
693}
694
695sub _prepare_data_cb {
696    my ($self, $response, $args) = @_;
697    my $data_cb = $args->{data_callback};
698    $response->{content} = '';
699
700    if (!$data_cb || $response->{status} !~ /^2/) {
701        if (defined $self->{max_size}) {
702            $data_cb = sub {
703                $_[1]->{content} .= $_[0];
704                die(qq/Size of response body exceeds the maximum allowed of $self->{max_size}\n/)
705                  if length $_[1]->{content} > $self->{max_size};
706            };
707        }
708        else {
709            $data_cb = sub { $_[1]->{content} .= $_[0] };
710        }
711    }
712    return $data_cb;
713}
714
715sub _update_cookie_jar {
716    my ($self, $url, $response) = @_;
717
718    my $cookies = $response->{headers}->{'set-cookie'};
719    return unless defined $cookies;
720
721    my @cookies = ref $cookies ? @$cookies : $cookies;
722
723    $self->cookie_jar->add( $url, $_ ) for @cookies;
724
725    return;
726}
727
728sub _validate_cookie_jar {
729    my ($class, $jar) = @_;
730
731    # duck typing
732    for my $method ( qw/add cookie_header/ ) {
733        Carp::croak(qq/Cookie jar must provide the '$method' method\n/)
734            unless ref($jar) && ref($jar)->can($method);
735    }
736
737    return;
738}
739
740sub _maybe_redirect {
741    my ($self, $request, $response, $args) = @_;
742    my $headers = $response->{headers};
743    my ($status, $method) = ($response->{status}, $request->{method});
744    if (($status eq '303' or ($status =~ /^30[127]/ && $method =~ /^GET|HEAD$/))
745        and $headers->{location}
746        and ++$args->{redirects} <= $self->{max_redirect}
747    ) {
748        my $location = ($headers->{location} =~ /^\//)
749            ? "$request->{scheme}://$request->{host_port}$headers->{location}"
750            : $headers->{location} ;
751        return (($status eq '303' ? 'GET' : $method), $location);
752    }
753    return;
754}
755
756sub _split_url {
757    my $url = pop;
758
759    # URI regex adapted from the URI module
760    my ($scheme, $authority, $path_query) = $url =~ m<\A([^:/?#]+)://([^/?#]*)([^#]*)>
761      or die(qq/Cannot parse URL: '$url'\n/);
762
763    $scheme     = lc $scheme;
764    $path_query = "/$path_query" unless $path_query =~ m<\A/>;
765
766    my ($auth,$host);
767    $authority = (length($authority)) ? $authority : 'localhost';
768    if ( $authority =~ /@/ ) {
769        ($auth,$host) = $authority =~ m/\A([^@]*)@(.*)\z/;   # user:pass@host
770        # userinfo might be percent escaped, so recover real auth info
771        $auth =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
772    }
773    else {
774        $host = $authority;
775        $auth = '';
776    }
777    $host = lc $host;
778    my $port = do {
779       $host =~ s/:([0-9]*)\z// && length $1
780         ? $1
781         : ($scheme eq 'http' ? 80 : $scheme eq 'https' ? 443 : undef);
782    };
783
784    return ($scheme, $host, $port, $path_query, $auth);
785}
786
787# Date conversions adapted from HTTP::Date
788my $DoW = "Sun|Mon|Tue|Wed|Thu|Fri|Sat";
789my $MoY = "Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec";
790sub _http_date {
791    my ($sec, $min, $hour, $mday, $mon, $year, $wday) = gmtime($_[1]);
792    return sprintf("%s, %02d %s %04d %02d:%02d:%02d GMT",
793        substr($DoW,$wday*4,3),
794        $mday, substr($MoY,$mon*4,3), $year+1900,
795        $hour, $min, $sec
796    );
797}
798
799sub _parse_http_date {
800    my ($self, $str) = @_;
801    require Time::Local;
802    my @tl_parts;
803    if ($str =~ /^[SMTWF][a-z]+, +(\d{1,2}) ($MoY) +(\d\d\d\d) +(\d\d):(\d\d):(\d\d) +GMT$/) {
804        @tl_parts = ($6, $5, $4, $1, (index($MoY,$2)/4), $3);
805    }
806    elsif ($str =~ /^[SMTWF][a-z]+, +(\d\d)-($MoY)-(\d{2,4}) +(\d\d):(\d\d):(\d\d) +GMT$/ ) {
807        @tl_parts = ($6, $5, $4, $1, (index($MoY,$2)/4), $3);
808    }
809    elsif ($str =~ /^[SMTWF][a-z]+ +($MoY) +(\d{1,2}) +(\d\d):(\d\d):(\d\d) +(?:[^0-9]+ +)?(\d\d\d\d)$/ ) {
810        @tl_parts = ($5, $4, $3, $2, (index($MoY,$1)/4), $6);
811    }
812    return eval {
813        my $t = @tl_parts ? Time::Local::timegm(@tl_parts) : -1;
814        $t < 0 ? undef : $t;
815    };
816}
817
818# URI escaping adapted from URI::Escape
819# c.f. http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1
820# perl 5.6 ready UTF-8 encoding adapted from JSON::PP
821my %escapes = map { chr($_) => sprintf("%%%02X", $_) } 0..255;
822$escapes{' '}="+";
823my $unsafe_char = qr/[^A-Za-z0-9\-\._~]/;
824
825sub _uri_escape {
826    my ($self, $str) = @_;
827    if ( $] ge '5.008' ) {
828        utf8::encode($str);
829    }
830    else {
831        $str = pack("U*", unpack("C*", $str)) # UTF-8 encode a byte string
832            if ( length $str == do { use bytes; length $str } );
833        $str = pack("C*", unpack("C*", $str)); # clear UTF-8 flag
834    }
835    $str =~ s/($unsafe_char)/$escapes{$1}/ge;
836    return $str;
837}
838
839package
840    HTTP::Tiny::Handle; # hide from PAUSE/indexers
841use strict;
842use warnings;
843
844use Errno      qw[EINTR EPIPE];
845use IO::Socket qw[SOCK_STREAM];
846
847# PERL_HTTP_TINY_IPV4_ONLY is a private environment variable to force old
848# behavior if someone is unable to boostrap CPAN from a new perl install; it is
849# not intended for general, per-client use and may be removed in the future
850my $SOCKET_CLASS =
851    $ENV{PERL_HTTP_TINY_IPV4_ONLY} ? 'IO::Socket::INET' :
852    eval { require IO::Socket::IP; IO::Socket::IP->VERSION(0.25) } ? 'IO::Socket::IP' :
853    'IO::Socket::INET';
854
855sub BUFSIZE () { 32768 } ## no critic
856
857my $Printable = sub {
858    local $_ = shift;
859    s/\r/\\r/g;
860    s/\n/\\n/g;
861    s/\t/\\t/g;
862    s/([^\x20-\x7E])/sprintf('\\x%.2X', ord($1))/ge;
863    $_;
864};
865
866my $Token = qr/[\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7A\x7C\x7E]/;
867
868sub new {
869    my ($class, %args) = @_;
870    return bless {
871        rbuf             => '',
872        timeout          => 60,
873        max_line_size    => 16384,
874        max_header_lines => 64,
875        verify_SSL       => 0,
876        SSL_options      => {},
877        %args
878    }, $class;
879}
880
881sub connect {
882    @_ == 4 || die(q/Usage: $handle->connect(scheme, host, port)/ . "\n");
883    my ($self, $scheme, $host, $port) = @_;
884
885    if ( $scheme eq 'https' ) {
886        $self->_assert_ssl;
887    }
888    elsif ( $scheme ne 'http' ) {
889      die(qq/Unsupported URL scheme '$scheme'\n/);
890    }
891    $self->{fh} = $SOCKET_CLASS->new(
892        PeerHost  => $host,
893        PeerPort  => $port,
894        $self->{local_address} ?
895            ( LocalAddr => $self->{local_address} ) : (),
896        Proto     => 'tcp',
897        Type      => SOCK_STREAM,
898        Timeout   => $self->{timeout},
899        KeepAlive => !!$self->{keep_alive}
900    ) or die(qq/Could not connect to '$host:$port': $@\n/);
901
902    binmode($self->{fh})
903      or die(qq/Could not binmode() socket: '$!'\n/);
904
905    $self->start_ssl($host) if $scheme eq 'https';
906
907    $self->{scheme} = $scheme;
908    $self->{host} = $host;
909    $self->{port} = $port;
910
911    return $self;
912}
913
914sub start_ssl {
915    my ($self, $host) = @_;
916
917    # As this might be used via CONNECT after an SSL session
918    # to a proxy, we shut down any existing SSL before attempting
919    # the handshake
920    if ( ref($self->{fh}) eq 'IO::Socket::SSL' ) {
921        unless ( $self->{fh}->stop_SSL ) {
922            my $ssl_err = IO::Socket::SSL->errstr;
923            die(qq/Error halting prior SSL connection: $ssl_err/);
924        }
925    }
926
927    my $ssl_args = $self->_ssl_args($host);
928    IO::Socket::SSL->start_SSL(
929        $self->{fh},
930        %$ssl_args,
931        SSL_create_ctx_callback => sub {
932            my $ctx = shift;
933            Net::SSLeay::CTX_set_mode($ctx, Net::SSLeay::MODE_AUTO_RETRY());
934        },
935    );
936
937    unless ( ref($self->{fh}) eq 'IO::Socket::SSL' ) {
938        my $ssl_err = IO::Socket::SSL->errstr;
939        die(qq/SSL connection failed for $host: $ssl_err\n/);
940    }
941}
942
943sub close {
944    @_ == 1 || die(q/Usage: $handle->close()/ . "\n");
945    my ($self) = @_;
946    CORE::close($self->{fh})
947      or die(qq/Could not close socket: '$!'\n/);
948}
949
950sub write {
951    @_ == 2 || die(q/Usage: $handle->write(buf)/ . "\n");
952    my ($self, $buf) = @_;
953
954    if ( $] ge '5.008' ) {
955        utf8::downgrade($buf, 1)
956            or die(qq/Wide character in write()\n/);
957    }
958
959    my $len = length $buf;
960    my $off = 0;
961
962    local $SIG{PIPE} = 'IGNORE';
963
964    while () {
965        $self->can_write
966          or die(qq/Timed out while waiting for socket to become ready for writing\n/);
967        my $r = syswrite($self->{fh}, $buf, $len, $off);
968        if (defined $r) {
969            $len -= $r;
970            $off += $r;
971            last unless $len > 0;
972        }
973        elsif ($! == EPIPE) {
974            die(qq/Socket closed by remote server: $!\n/);
975        }
976        elsif ($! != EINTR) {
977            if ($self->{fh}->can('errstr')){
978                my $err = $self->{fh}->errstr();
979                die (qq/Could not write to SSL socket: '$err'\n /);
980            }
981            else {
982                die(qq/Could not write to socket: '$!'\n/);
983            }
984
985        }
986    }
987    return $off;
988}
989
990sub read {
991    @_ == 2 || @_ == 3 || die(q/Usage: $handle->read(len [, allow_partial])/ . "\n");
992    my ($self, $len, $allow_partial) = @_;
993
994    my $buf  = '';
995    my $got = length $self->{rbuf};
996
997    if ($got) {
998        my $take = ($got < $len) ? $got : $len;
999        $buf  = substr($self->{rbuf}, 0, $take, '');
1000        $len -= $take;
1001    }
1002
1003    while ($len > 0) {
1004        $self->can_read
1005          or die(q/Timed out while waiting for socket to become ready for reading/ . "\n");
1006        my $r = sysread($self->{fh}, $buf, $len, length $buf);
1007        if (defined $r) {
1008            last unless $r;
1009            $len -= $r;
1010        }
1011        elsif ($! != EINTR) {
1012            if ($self->{fh}->can('errstr')){
1013                my $err = $self->{fh}->errstr();
1014                die (qq/Could not read from SSL socket: '$err'\n /);
1015            }
1016            else {
1017                die(qq/Could not read from socket: '$!'\n/);
1018            }
1019        }
1020    }
1021    if ($len && !$allow_partial) {
1022        die(qq/Unexpected end of stream\n/);
1023    }
1024    return $buf;
1025}
1026
1027sub readline {
1028    @_ == 1 || die(q/Usage: $handle->readline()/ . "\n");
1029    my ($self) = @_;
1030
1031    while () {
1032        if ($self->{rbuf} =~ s/\A ([^\x0D\x0A]* \x0D?\x0A)//x) {
1033            return $1;
1034        }
1035        if (length $self->{rbuf} >= $self->{max_line_size}) {
1036            die(qq/Line size exceeds the maximum allowed size of $self->{max_line_size}\n/);
1037        }
1038        $self->can_read
1039          or die(qq/Timed out while waiting for socket to become ready for reading\n/);
1040        my $r = sysread($self->{fh}, $self->{rbuf}, BUFSIZE, length $self->{rbuf});
1041        if (defined $r) {
1042            last unless $r;
1043        }
1044        elsif ($! != EINTR) {
1045            if ($self->{fh}->can('errstr')){
1046                my $err = $self->{fh}->errstr();
1047                die (qq/Could not read from SSL socket: '$err'\n /);
1048            }
1049            else {
1050                die(qq/Could not read from socket: '$!'\n/);
1051            }
1052        }
1053    }
1054    die(qq/Unexpected end of stream while looking for line\n/);
1055}
1056
1057sub read_header_lines {
1058    @_ == 1 || @_ == 2 || die(q/Usage: $handle->read_header_lines([headers])/ . "\n");
1059    my ($self, $headers) = @_;
1060    $headers ||= {};
1061    my $lines   = 0;
1062    my $val;
1063
1064    while () {
1065         my $line = $self->readline;
1066
1067         if (++$lines >= $self->{max_header_lines}) {
1068             die(qq/Header lines exceeds maximum number allowed of $self->{max_header_lines}\n/);
1069         }
1070         elsif ($line =~ /\A ([^\x00-\x1F\x7F:]+) : [\x09\x20]* ([^\x0D\x0A]*)/x) {
1071             my ($field_name) = lc $1;
1072             if (exists $headers->{$field_name}) {
1073                 for ($headers->{$field_name}) {
1074                     $_ = [$_] unless ref $_ eq "ARRAY";
1075                     push @$_, $2;
1076                     $val = \$_->[-1];
1077                 }
1078             }
1079             else {
1080                 $val = \($headers->{$field_name} = $2);
1081             }
1082         }
1083         elsif ($line =~ /\A [\x09\x20]+ ([^\x0D\x0A]*)/x) {
1084             $val
1085               or die(qq/Unexpected header continuation line\n/);
1086             next unless length $1;
1087             $$val .= ' ' if length $$val;
1088             $$val .= $1;
1089         }
1090         elsif ($line =~ /\A \x0D?\x0A \z/x) {
1091            last;
1092         }
1093         else {
1094            die(q/Malformed header line: / . $Printable->($line) . "\n");
1095         }
1096    }
1097    return $headers;
1098}
1099
1100sub write_request {
1101    @_ == 2 || die(q/Usage: $handle->write_request(request)/ . "\n");
1102    my($self, $request) = @_;
1103    $self->write_request_header(@{$request}{qw/method uri headers/});
1104    $self->write_body($request) if $request->{cb};
1105    return;
1106}
1107
1108my %HeaderCase = (
1109    'content-md5'      => 'Content-MD5',
1110    'etag'             => 'ETag',
1111    'te'               => 'TE',
1112    'www-authenticate' => 'WWW-Authenticate',
1113    'x-xss-protection' => 'X-XSS-Protection',
1114);
1115
1116# to avoid multiple small writes and hence nagle, you can pass the method line or anything else to
1117# combine writes.
1118sub write_header_lines {
1119    (@_ == 2 || @_ == 3 && ref $_[1] eq 'HASH') || die(q/Usage: $handle->write_header_lines(headers[,prefix])/ . "\n");
1120    my($self, $headers, $prefix_data) = @_;
1121
1122    my $buf = (defined $prefix_data ? $prefix_data : '');
1123    while (my ($k, $v) = each %$headers) {
1124        my $field_name = lc $k;
1125        if (exists $HeaderCase{$field_name}) {
1126            $field_name = $HeaderCase{$field_name};
1127        }
1128        else {
1129            $field_name =~ /\A $Token+ \z/xo
1130              or die(q/Invalid HTTP header field name: / . $Printable->($field_name) . "\n");
1131            $field_name =~ s/\b(\w)/\u$1/g;
1132            $HeaderCase{lc $field_name} = $field_name;
1133        }
1134        for (ref $v eq 'ARRAY' ? @$v : $v) {
1135            /[^\x0D\x0A]/
1136              or die(qq/Invalid HTTP header field value ($field_name): / . $Printable->($_). "\n");
1137            $buf .= "$field_name: $_\x0D\x0A";
1138        }
1139    }
1140    $buf .= "\x0D\x0A";
1141    return $self->write($buf);
1142}
1143
1144# return value indicates whether message length was defined; this is generally
1145# true unless there was no content-length header and we just read until EOF.
1146# Other message length errors are thrown as exceptions
1147sub read_body {
1148    @_ == 3 || die(q/Usage: $handle->read_body(callback, response)/ . "\n");
1149    my ($self, $cb, $response) = @_;
1150    my $te = $response->{headers}{'transfer-encoding'} || '';
1151    my $chunked = grep { /chunked/i } ( ref $te eq 'ARRAY' ? @$te : $te ) ;
1152    return $chunked
1153        ? $self->read_chunked_body($cb, $response)
1154        : $self->read_content_body($cb, $response);
1155}
1156
1157sub write_body {
1158    @_ == 2 || die(q/Usage: $handle->write_body(request)/ . "\n");
1159    my ($self, $request) = @_;
1160    if ($request->{headers}{'content-length'}) {
1161        return $self->write_content_body($request);
1162    }
1163    else {
1164        return $self->write_chunked_body($request);
1165    }
1166}
1167
1168sub read_content_body {
1169    @_ == 3 || @_ == 4 || die(q/Usage: $handle->read_content_body(callback, response, [read_length])/ . "\n");
1170    my ($self, $cb, $response, $content_length) = @_;
1171    $content_length ||= $response->{headers}{'content-length'};
1172
1173    if ( defined $content_length ) {
1174        my $len = $content_length;
1175        while ($len > 0) {
1176            my $read = ($len > BUFSIZE) ? BUFSIZE : $len;
1177            $cb->($self->read($read, 0), $response);
1178            $len -= $read;
1179        }
1180        return length($self->{rbuf}) == 0;
1181    }
1182
1183    my $chunk;
1184    $cb->($chunk, $response) while length( $chunk = $self->read(BUFSIZE, 1) );
1185
1186    return;
1187}
1188
1189sub write_content_body {
1190    @_ == 2 || die(q/Usage: $handle->write_content_body(request)/ . "\n");
1191    my ($self, $request) = @_;
1192
1193    my ($len, $content_length) = (0, $request->{headers}{'content-length'});
1194    while () {
1195        my $data = $request->{cb}->();
1196
1197        defined $data && length $data
1198          or last;
1199
1200        if ( $] ge '5.008' ) {
1201            utf8::downgrade($data, 1)
1202                or die(qq/Wide character in write_content()\n/);
1203        }
1204
1205        $len += $self->write($data);
1206    }
1207
1208    $len == $content_length
1209      or die(qq/Content-Length missmatch (got: $len expected: $content_length)\n/);
1210
1211    return $len;
1212}
1213
1214sub read_chunked_body {
1215    @_ == 3 || die(q/Usage: $handle->read_chunked_body(callback, $response)/ . "\n");
1216    my ($self, $cb, $response) = @_;
1217
1218    while () {
1219        my $head = $self->readline;
1220
1221        $head =~ /\A ([A-Fa-f0-9]+)/x
1222          or die(q/Malformed chunk head: / . $Printable->($head) . "\n");
1223
1224        my $len = hex($1)
1225          or last;
1226
1227        $self->read_content_body($cb, $response, $len);
1228
1229        $self->read(2) eq "\x0D\x0A"
1230          or die(qq/Malformed chunk: missing CRLF after chunk data\n/);
1231    }
1232    $self->read_header_lines($response->{headers});
1233    return 1;
1234}
1235
1236sub write_chunked_body {
1237    @_ == 2 || die(q/Usage: $handle->write_chunked_body(request)/ . "\n");
1238    my ($self, $request) = @_;
1239
1240    my $len = 0;
1241    while () {
1242        my $data = $request->{cb}->();
1243
1244        defined $data && length $data
1245          or last;
1246
1247        if ( $] ge '5.008' ) {
1248            utf8::downgrade($data, 1)
1249                or die(qq/Wide character in write_chunked_body()\n/);
1250        }
1251
1252        $len += length $data;
1253
1254        my $chunk  = sprintf '%X', length $data;
1255           $chunk .= "\x0D\x0A";
1256           $chunk .= $data;
1257           $chunk .= "\x0D\x0A";
1258
1259        $self->write($chunk);
1260    }
1261    $self->write("0\x0D\x0A");
1262    $self->write_header_lines($request->{trailer_cb}->())
1263        if ref $request->{trailer_cb} eq 'CODE';
1264    return $len;
1265}
1266
1267sub read_response_header {
1268    @_ == 1 || die(q/Usage: $handle->read_response_header()/ . "\n");
1269    my ($self) = @_;
1270
1271    my $line = $self->readline;
1272
1273    $line =~ /\A (HTTP\/(0*\d+\.0*\d+)) [\x09\x20]+ ([0-9]{3}) [\x09\x20]+ ([^\x0D\x0A]*) \x0D?\x0A/x
1274      or die(q/Malformed Status-Line: / . $Printable->($line). "\n");
1275
1276    my ($protocol, $version, $status, $reason) = ($1, $2, $3, $4);
1277
1278    die (qq/Unsupported HTTP protocol: $protocol\n/)
1279        unless $version =~ /0*1\.0*[01]/;
1280
1281    return {
1282        status       => $status,
1283        reason       => $reason,
1284        headers      => $self->read_header_lines,
1285        protocol     => $protocol,
1286    };
1287}
1288
1289sub write_request_header {
1290    @_ == 4 || die(q/Usage: $handle->write_request_header(method, request_uri, headers)/ . "\n");
1291    my ($self, $method, $request_uri, $headers) = @_;
1292
1293    return $self->write_header_lines($headers, "$method $request_uri HTTP/1.1\x0D\x0A");
1294}
1295
1296sub _do_timeout {
1297    my ($self, $type, $timeout) = @_;
1298    $timeout = $self->{timeout}
1299        unless defined $timeout && $timeout >= 0;
1300
1301    my $fd = fileno $self->{fh};
1302    defined $fd && $fd >= 0
1303      or die(qq/select(2): 'Bad file descriptor'\n/);
1304
1305    my $initial = time;
1306    my $pending = $timeout;
1307    my $nfound;
1308
1309    vec(my $fdset = '', $fd, 1) = 1;
1310
1311    while () {
1312        $nfound = ($type eq 'read')
1313            ? select($fdset, undef, undef, $pending)
1314            : select(undef, $fdset, undef, $pending) ;
1315        if ($nfound == -1) {
1316            $! == EINTR
1317              or die(qq/select(2): '$!'\n/);
1318            redo if !$timeout || ($pending = $timeout - (time - $initial)) > 0;
1319            $nfound = 0;
1320        }
1321        last;
1322    }
1323    $! = 0;
1324    return $nfound;
1325}
1326
1327sub can_read {
1328    @_ == 1 || @_ == 2 || die(q/Usage: $handle->can_read([timeout])/ . "\n");
1329    my $self = shift;
1330    if ( ref($self->{fh}) eq 'IO::Socket::SSL' ) {
1331        return 1 if $self->{fh}->pending;
1332    }
1333    return $self->_do_timeout('read', @_)
1334}
1335
1336sub can_write {
1337    @_ == 1 || @_ == 2 || die(q/Usage: $handle->can_write([timeout])/ . "\n");
1338    my $self = shift;
1339    return $self->_do_timeout('write', @_)
1340}
1341
1342sub _assert_ssl {
1343    # Need IO::Socket::SSL 1.42 for SSL_create_ctx_callback
1344    die(qq/IO::Socket::SSL 1.42 must be installed for https support\n/)
1345        unless eval {require IO::Socket::SSL; IO::Socket::SSL->VERSION(1.42)};
1346    # Need Net::SSLeay 1.49 for MODE_AUTO_RETRY
1347    die(qq/Net::SSLeay 1.49 must be installed for https support\n/)
1348        unless eval {require Net::SSLeay; Net::SSLeay->VERSION(1.49)};
1349}
1350
1351sub can_reuse {
1352    my ($self,$scheme,$host,$port) = @_;
1353    return 0 if
1354         length($self->{rbuf})
1355        || $scheme ne $self->{scheme}
1356        || $host ne $self->{host}
1357        || $port ne $self->{port}
1358        || eval { $self->can_read(0) }
1359        || $@ ;
1360        return 1;
1361}
1362
1363# Try to find a CA bundle to validate the SSL cert,
1364# prefer Mozilla::CA or fallback to a system file
1365sub _find_CA_file {
1366    my $self = shift();
1367
1368    return $self->{SSL_options}->{SSL_ca_file}
1369        if $self->{SSL_options}->{SSL_ca_file} and -e $self->{SSL_options}->{SSL_ca_file};
1370
1371    local @INC = @INC;
1372    pop @INC if $INC[-1] eq '.';
1373    return Mozilla::CA::SSL_ca_file()
1374        if eval { require Mozilla::CA };
1375
1376    foreach my $ca_bundle (qw{
1377        /etc/ssl/certs/ca-certificates.crt
1378        /etc/pki/tls/certs/ca-bundle.crt
1379        /etc/ssl/ca-bundle.pem
1380        }
1381    ) {
1382        return $ca_bundle if -e $ca_bundle;
1383    }
1384
1385    die qq/Couldn't find a CA bundle with which to verify the SSL certificate.\n/
1386      . qq/Try installing Mozilla::CA from CPAN\n/;
1387}
1388
1389sub _ssl_args {
1390    my ($self, $host) = @_;
1391
1392    my %ssl_args;
1393
1394    # This test reimplements IO::Socket::SSL::can_client_sni(), which wasn't
1395    # added until IO::Socket::SSL 1.84
1396    if ( Net::SSLeay::OPENSSL_VERSION_NUMBER() >= 0x01000000 ) {
1397        $ssl_args{SSL_hostname} = $host,          # Sane SNI support
1398    }
1399
1400    if ($self->{verify_SSL}) {
1401        $ssl_args{SSL_verifycn_scheme}  = 'http'; # enable CN validation
1402        $ssl_args{SSL_verifycn_name}    = $host;  # set validation hostname
1403        $ssl_args{SSL_verify_mode}      = 0x01;   # enable cert validation
1404        $ssl_args{SSL_ca_file}          = $self->_find_CA_file;
1405    }
1406    else {
1407        $ssl_args{SSL_verifycn_scheme}  = 'none'; # disable CN validation
1408        $ssl_args{SSL_verify_mode}      = 0x00;   # disable cert validation
1409    }
1410
1411    # user options override settings from verify_SSL
1412    for my $k ( keys %{$self->{SSL_options}} ) {
1413        $ssl_args{$k} = $self->{SSL_options}{$k} if $k =~ m/^SSL_/;
1414    }
1415
1416    return \%ssl_args;
1417}
1418
14191;
1420
1421__END__
1422
1423=pod
1424
1425=encoding UTF-8
1426
1427=head1 NAME
1428
1429HTTP::Tiny - A small, simple, correct HTTP/1.1 client
1430
1431=head1 VERSION
1432
1433version 0.043
1434
1435=head1 SYNOPSIS
1436
1437    use HTTP::Tiny;
1438
1439    my $response = HTTP::Tiny->new->get('http://example.com/');
1440
1441    die "Failed!\n" unless $response->{success};
1442
1443    print "$response->{status} $response->{reason}\n";
1444
1445    while (my ($k, $v) = each %{$response->{headers}}) {
1446        for (ref $v eq 'ARRAY' ? @$v : $v) {
1447            print "$k: $_\n";
1448        }
1449    }
1450
1451    print $response->{content} if length $response->{content};
1452
1453=head1 DESCRIPTION
1454
1455This is a very simple HTTP/1.1 client, designed for doing simple
1456requests without the overhead of a large framework like L<LWP::UserAgent>.
1457
1458It is more correct and more complete than L<HTTP::Lite>.  It supports
1459proxies and redirection.  It also correctly resumes after EINTR.
1460
1461If L<IO::Socket::IP> 0.25 or later is installed, HTTP::Tiny will use it instead
1462of L<IO::Socket::INET> for transparent support for both IPv4 and IPv6.
1463
1464Cookie support requires L<HTTP::CookieJar> or an equivalent class.
1465
1466=head1 METHODS
1467
1468=head2 new
1469
1470    $http = HTTP::Tiny->new( %attributes );
1471
1472This constructor returns a new HTTP::Tiny object.  Valid attributes include:
1473
1474=over 4
1475
1476=item *
1477
1478C<agent>
1479
1480A user-agent string (defaults to 'HTTP-Tiny/$VERSION'). If C<agent> ends in a space character, the default user-agent string is appended.
1481
1482=item *
1483
1484C<cookie_jar>
1485
1486An instance of L<HTTP::CookieJar> or equivalent class that supports the C<add> and C<cookie_header> methods
1487
1488=item *
1489
1490C<default_headers>
1491
1492A hashref of default headers to apply to requests
1493
1494=item *
1495
1496C<local_address>
1497
1498The local IP address to bind to
1499
1500=item *
1501
1502C<keep_alive>
1503
1504Whether to reuse the last connection (if for the same scheme, host and port) (defaults to 1)
1505
1506=item *
1507
1508C<max_redirect>
1509
1510Maximum number of redirects allowed (defaults to 5)
1511
1512=item *
1513
1514C<max_size>
1515
1516Maximum response size (only when not using a data callback).  If defined, responses larger than this will return an exception.
1517
1518=item *
1519
1520C<http_proxy>
1521
1522URL of a proxy server to use for HTTP connections (default is C<$ENV{http_proxy}> if set)
1523
1524=item *
1525
1526C<https_proxy>
1527
1528URL of a proxy server to use for HTTPS connections (default is C<$ENV{https_proxy}> if set)
1529
1530=item *
1531
1532C<proxy>
1533
1534URL of a generic proxy server for both HTTP and HTTPS connections (default is C<$ENV{all_proxy}> if set)
1535
1536=item *
1537
1538C<no_proxy>
1539
1540List of domain suffixes that should not be proxied.  Must be a comma-separated string or an array reference. (default is C<$ENV{no_proxy}>)
1541
1542=item *
1543
1544C<timeout>
1545
1546Request timeout in seconds (default is 60)
1547
1548=item *
1549
1550C<verify_SSL>
1551
1552A boolean that indicates whether to validate the SSL certificate of an C<https>
1553connection (default is false)
1554
1555=item *
1556
1557C<SSL_options>
1558
1559A hashref of C<SSL_*> options to pass through to L<IO::Socket::SSL>
1560
1561=back
1562
1563Exceptions from C<max_size>, C<timeout> or other errors will result in a
1564pseudo-HTTP status code of 599 and a reason of "Internal Exception". The
1565content field in the response will contain the text of the exception.
1566
1567The C<keep_alive> parameter enables a persistent connection, but only to a
1568single destination scheme, host and port.  Also, if any connection-relevant
1569attributes are modified, a persistent connection will be dropped.  If you want
1570persistent connections across multiple destinations, use multiple HTTP::Tiny
1571objects.
1572
1573See L</SSL SUPPORT> for more on the C<verify_SSL> and C<SSL_options> attributes.
1574
1575=head2 get|head|put|post|delete
1576
1577    $response = $http->get($url);
1578    $response = $http->get($url, \%options);
1579    $response = $http->head($url);
1580
1581These methods are shorthand for calling C<request()> for the given method.  The
1582URL must have unsafe characters escaped and international domain names encoded.
1583See C<request()> for valid options and a description of the response.
1584
1585The C<success> field of the response will be true if the status code is 2XX.
1586
1587=head2 post_form
1588
1589    $response = $http->post_form($url, $form_data);
1590    $response = $http->post_form($url, $form_data, \%options);
1591
1592This method executes a C<POST> request and sends the key/value pairs from a
1593form data hash or array reference to the given URL with a C<content-type> of
1594C<application/x-www-form-urlencoded>.  If data is provided as an array
1595reference, the order is preserved; if provided as a hash reference, the terms
1596are sorted on key and value for consistency.  See documentation for the
1597C<www_form_urlencode> method for details on the encoding.
1598
1599The URL must have unsafe characters escaped and international domain names
1600encoded.  See C<request()> for valid options and a description of the response.
1601Any C<content-type> header or content in the options hashref will be ignored.
1602
1603The C<success> field of the response will be true if the status code is 2XX.
1604
1605=head2 mirror
1606
1607    $response = $http->mirror($url, $file, \%options)
1608    if ( $response->{success} ) {
1609        print "$file is up to date\n";
1610    }
1611
1612Executes a C<GET> request for the URL and saves the response body to the file
1613name provided.  The URL must have unsafe characters escaped and international
1614domain names encoded.  If the file already exists, the request will include an
1615C<If-Modified-Since> header with the modification timestamp of the file.  You
1616may specify a different C<If-Modified-Since> header yourself in the C<<
1617$options->{headers} >> hash.
1618
1619The C<success> field of the response will be true if the status code is 2XX
1620or if the status code is 304 (unmodified).
1621
1622If the file was modified and the server response includes a properly
1623formatted C<Last-Modified> header, the file modification time will
1624be updated accordingly.
1625
1626=head2 request
1627
1628    $response = $http->request($method, $url);
1629    $response = $http->request($method, $url, \%options);
1630
1631Executes an HTTP request of the given method type ('GET', 'HEAD', 'POST',
1632'PUT', etc.) on the given URL.  The URL must have unsafe characters escaped and
1633international domain names encoded.
1634
1635If the URL includes a "user:password" stanza, they will be used for Basic-style
1636authorization headers.  (Authorization headers will not be included in a
1637redirected request.) For example:
1638
1639    $http->request('GET', 'http://Aladdin:open sesame@example.com/');
1640
1641If the "user:password" stanza contains reserved characters, they must
1642be percent-escaped:
1643
1644    $http->request('GET', 'http://john%40example.com:password@example.com/');
1645
1646A hashref of options may be appended to modify the request.
1647
1648Valid options are:
1649
1650=over 4
1651
1652=item *
1653
1654C<headers>
1655
1656A hashref containing headers to include with the request.  If the value for
1657a header is an array reference, the header will be output multiple times with
1658each value in the array.  These headers over-write any default headers.
1659
1660=item *
1661
1662C<content>
1663
1664A scalar to include as the body of the request OR a code reference
1665that will be called iteratively to produce the body of the request
1666
1667=item *
1668
1669C<trailer_callback>
1670
1671A code reference that will be called if it exists to provide a hashref
1672of trailing headers (only used with chunked transfer-encoding)
1673
1674=item *
1675
1676C<data_callback>
1677
1678A code reference that will be called for each chunks of the response
1679body received.
1680
1681=back
1682
1683If the C<content> option is a code reference, it will be called iteratively
1684to provide the content body of the request.  It should return the empty
1685string or undef when the iterator is exhausted.
1686
1687If the C<content> option is the empty string, no C<content-type> or
1688C<content-length> headers will be generated.
1689
1690If the C<data_callback> option is provided, it will be called iteratively until
1691the entire response body is received.  The first argument will be a string
1692containing a chunk of the response body, the second argument will be the
1693in-progress response hash reference, as described below.  (This allows
1694customizing the action of the callback based on the C<status> or C<headers>
1695received prior to the content body.)
1696
1697The C<request> method returns a hashref containing the response.  The hashref
1698will have the following keys:
1699
1700=over 4
1701
1702=item *
1703
1704C<success>
1705
1706Boolean indicating whether the operation returned a 2XX status code
1707
1708=item *
1709
1710C<url>
1711
1712URL that provided the response. This is the URL of the request unless
1713there were redirections, in which case it is the last URL queried
1714in a redirection chain
1715
1716=item *
1717
1718C<status>
1719
1720The HTTP status code of the response
1721
1722=item *
1723
1724C<reason>
1725
1726The response phrase returned by the server
1727
1728=item *
1729
1730C<content>
1731
1732The body of the response.  If the response does not have any content
1733or if a data callback is provided to consume the response body,
1734this will be the empty string
1735
1736=item *
1737
1738C<headers>
1739
1740A hashref of header fields.  All header field names will be normalized
1741to be lower case. If a header is repeated, the value will be an arrayref;
1742it will otherwise be a scalar string containing the value
1743
1744=back
1745
1746On an exception during the execution of the request, the C<status> field will
1747contain 599, and the C<content> field will contain the text of the exception.
1748
1749=head2 www_form_urlencode
1750
1751    $params = $http->www_form_urlencode( $data );
1752    $response = $http->get("http://example.com/query?$params");
1753
1754This method converts the key/value pairs from a data hash or array reference
1755into a C<x-www-form-urlencoded> string.  The keys and values from the data
1756reference will be UTF-8 encoded and escaped per RFC 3986.  If a value is an
1757array reference, the key will be repeated with each of the values of the array
1758reference.  If data is provided as a hash reference, the key/value pairs in the
1759resulting string will be sorted by key and value for consistent ordering.
1760
1761=for Pod::Coverage SSL_options
1762agent
1763cookie_jar
1764default_headers
1765http_proxy
1766https_proxy
1767keep_alive
1768local_address
1769max_redirect
1770max_size
1771no_proxy
1772proxy
1773timeout
1774verify_SSL
1775
1776=head1 SSL SUPPORT
1777
1778Direct C<https> connections are supported only if L<IO::Socket::SSL> 1.56 or
1779greater and L<Net::SSLeay> 1.49 or greater are installed. An exception will be
1780thrown if a new enough versions of these modules not installed or if the SSL
1781encryption fails. An C<https> connection may be made via an C<http> proxy that
1782supports the CONNECT command (i.e. RFC 2817).  You may not proxy C<https> via
1783a proxy that itself requires C<https> to communicate.
1784
1785SSL provides two distinct capabilities:
1786
1787=over 4
1788
1789=item *
1790
1791Encrypted communication channel
1792
1793=item *
1794
1795Verification of server identity
1796
1797=back
1798
1799B<By default, HTTP::Tiny does not verify server identity>.
1800
1801Server identity verification is controversial and potentially tricky because it
1802depends on a (usually paid) third-party Certificate Authority (CA) trust model
1803to validate a certificate as legitimate.  This discriminates against servers
1804with self-signed certificates or certificates signed by free, community-driven
1805CA's such as L<CAcert.org|http://cacert.org>.
1806
1807By default, HTTP::Tiny does not make any assumptions about your trust model,
1808threat level or risk tolerance.  It just aims to give you an encrypted channel
1809when you need one.
1810
1811Setting the C<verify_SSL> attribute to a true value will make HTTP::Tiny verify
1812that an SSL connection has a valid SSL certificate corresponding to the host
1813name of the connection and that the SSL certificate has been verified by a CA.
1814Assuming you trust the CA, this will protect against a L<man-in-the-middle
1815attack|http://en.wikipedia.org/wiki/Man-in-the-middle_attack>.  If you are
1816concerned about security, you should enable this option.
1817
1818Certificate verification requires a file containing trusted CA certificates.
1819If the L<Mozilla::CA> module is installed, HTTP::Tiny will use the CA file
1820included with it as a source of trusted CA's.  (This means you trust Mozilla,
1821the author of Mozilla::CA, the CPAN mirror where you got Mozilla::CA, the
1822toolchain used to install it, and your operating system security, right?)
1823
1824If that module is not available, then HTTP::Tiny will search several
1825system-specific default locations for a CA certificate file:
1826
1827=over 4
1828
1829=item *
1830
1831/etc/ssl/certs/ca-certificates.crt
1832
1833=item *
1834
1835/etc/pki/tls/certs/ca-bundle.crt
1836
1837=item *
1838
1839/etc/ssl/ca-bundle.pem
1840
1841=back
1842
1843An exception will be raised if C<verify_SSL> is true and no CA certificate file
1844is available.
1845
1846If you desire complete control over SSL connections, the C<SSL_options> attribute
1847lets you provide a hash reference that will be passed through to
1848C<IO::Socket::SSL::start_SSL()>, overriding any options set by HTTP::Tiny. For
1849example, to provide your own trusted CA file:
1850
1851    SSL_options => {
1852        SSL_ca_file => $file_path,
1853    }
1854
1855The C<SSL_options> attribute could also be used for such things as providing a
1856client certificate for authentication to a server or controlling the choice of
1857cipher used for the SSL connection. See L<IO::Socket::SSL> documentation for
1858details.
1859
1860=head1 PROXY SUPPORT
1861
1862HTTP::Tiny can proxy both C<http> and C<https> requests.  Only Basic proxy
1863authorization is supported and it must be provided as part of the proxy URL:
1864C<http://user:pass@proxy.example.com/>.
1865
1866HTTP::Tiny supports the following proxy environment variables:
1867
1868=over 4
1869
1870=item *
1871
1872http_proxy
1873
1874=item *
1875
1876https_proxy or HTTPS_PROXY
1877
1878=item *
1879
1880all_proxy or ALL_PROXY
1881
1882=back
1883
1884Tunnelling C<https> over an C<http> proxy using the CONNECT method is
1885supported.  If your proxy uses C<https> itself, you can not tunnel C<https>
1886over it.
1887
1888Be warned that proxying an C<https> connection opens you to the risk of a
1889man-in-the-middle attack by the proxy server.
1890
1891The C<no_proxy> environment variable is supported in the format of a
1892comma-separated list of domain extensions proxy should not be used for.
1893
1894Proxy arguments passed to C<new> will override their corresponding
1895environment variables.
1896
1897=head1 LIMITATIONS
1898
1899HTTP::Tiny is I<conditionally compliant> with the
1900L<HTTP/1.1 specification|http://www.w3.org/Protocols/rfc2616/rfc2616.html>.
1901It attempts to meet all "MUST" requirements of the specification, but does not
1902implement all "SHOULD" requirements.
1903
1904Some particular limitations of note include:
1905
1906=over
1907
1908=item *
1909
1910HTTP::Tiny focuses on correct transport.  Users are responsible for ensuring
1911that user-defined headers and content are compliant with the HTTP/1.1
1912specification.
1913
1914=item *
1915
1916Users must ensure that URLs are properly escaped for unsafe characters and that
1917international domain names are properly encoded to ASCII. See L<URI::Escape>,
1918L<URI::_punycode> and L<Net::IDN::Encode>.
1919
1920=item *
1921
1922Redirection is very strict against the specification.  Redirection is only
1923automatic for response codes 301, 302 and 307 if the request method is 'GET' or
1924'HEAD'.  Response code 303 is always converted into a 'GET' redirection, as
1925mandated by the specification.  There is no automatic support for status 305
1926("Use proxy") redirections.
1927
1928=item *
1929
1930There is no provision for delaying a request body using an C<Expect> header.
1931Unexpected C<1XX> responses are silently ignored as per the specification.
1932
1933=item *
1934
1935Only 'chunked' C<Transfer-Encoding> is supported.
1936
1937=item *
1938
1939There is no support for a Request-URI of '*' for the 'OPTIONS' request.
1940
1941=back
1942
1943Despite the limitations listed above, HTTP::Tiny is considered
1944feature-complete.  New feature requests should be directed to
1945L<HTTP::Tiny::UA>.
1946
1947=head1 SEE ALSO
1948
1949=over 4
1950
1951=item *
1952
1953L<HTTP::Tiny::UA> - Higher level UA features for HTTP::Tiny
1954
1955=item *
1956
1957L<HTTP::Thin> - HTTP::Tiny wrapper with L<HTTP::Request>/L<HTTP::Response> compatibility
1958
1959=item *
1960
1961L<HTTP::Tiny::Mech> - Wrap L<WWW::Mechanize> instance in HTTP::Tiny compatible interface
1962
1963=item *
1964
1965L<IO::Socket::IP> - Required for IPv6 support
1966
1967=item *
1968
1969L<IO::Socket::SSL> - Required for SSL support
1970
1971=item *
1972
1973L<LWP::UserAgent> - If HTTP::Tiny isn't enough for you, this is the "standard" way to do things
1974
1975=item *
1976
1977L<Mozilla::CA> - Required if you want to validate SSL certificates
1978
1979=item *
1980
1981L<Net::SSLeay> - Required for SSL support
1982
1983=back
1984
1985=for :stopwords cpan testmatrix url annocpan anno bugtracker rt cpants kwalitee diff irc mailto metadata placeholders metacpan
1986
1987=head1 SUPPORT
1988
1989=head2 Bugs / Feature Requests
1990
1991Please report any bugs or feature requests through the issue tracker
1992at L<https://github.com/chansen/p5-http-tiny/issues>.
1993You will be notified automatically of any progress on your issue.
1994
1995=head2 Source Code
1996
1997This is open source software.  The code repository is available for
1998public review and contribution under the terms of the license.
1999
2000L<https://github.com/chansen/p5-http-tiny>
2001
2002  git clone https://github.com/chansen/p5-http-tiny.git
2003
2004=head1 AUTHORS
2005
2006=over 4
2007
2008=item *
2009
2010Christian Hansen <chansen@cpan.org>
2011
2012=item *
2013
2014David Golden <dagolden@cpan.org>
2015
2016=back
2017
2018=head1 CONTRIBUTORS
2019
2020=over 4
2021
2022=item *
2023
2024Alan Gardner <gardner@pythian.com>
2025
2026=item *
2027
2028Alessandro Ghedini <al3xbio@gmail.com>
2029
2030=item *
2031
2032Brad Gilbert <bgills@cpan.org>
2033
2034=item *
2035
2036Chris Nehren <apeiron@cpan.org>
2037
2038=item *
2039
2040Chris Weyl <cweyl@alumni.drew.edu>
2041
2042=item *
2043
2044Claes Jakobsson <claes@surfar.nu>
2045
2046=item *
2047
2048Clinton Gormley <clint@traveljury.com>
2049
2050=item *
2051
2052Craig Berry <cberry@cpan.org>
2053
2054=item *
2055
2056David Mitchell <davem@iabyn.com>
2057
2058=item *
2059
2060Edward Zborowski <ed@rubensteintech.com>
2061
2062=item *
2063
2064Jess Robinson <castaway@desert-island.me.uk>
2065
2066=item *
2067
2068Lukas Eklund <leklund@gmail.com>
2069
2070=item *
2071
2072Martin J. Evans <mjegh@ntlworld.com>
2073
2074=item *
2075
2076Martin-Louis Bright <mlbright@gmail.com>
2077
2078=item *
2079
2080Mike Doherty <doherty@cpan.org>
2081
2082=item *
2083
2084Petr Písař <ppisar@redhat.com>
2085
2086=item *
2087
2088Serguei Trouchelle <stro@cpan.org>
2089
2090=item *
2091
2092Syohei YOSHIDA <syohex@gmail.com>
2093
2094=item *
2095
2096Tony Cook <tony@develop-help.com>
2097
2098=back
2099
2100=head1 COPYRIGHT AND LICENSE
2101
2102This software is copyright (c) 2014 by Christian Hansen.
2103
2104This is free software; you can redistribute it and/or modify it under
2105the same terms as the Perl 5 programming language system itself.
2106
2107=cut
2108