File Coverage

blib/lib/HTTP/Tiny.pm
Criterion Covered Total %
statement 632 706 89.5
branch 344 490 70.2
condition 197 305 64.5
subroutine 81 85 95.2
pod 13 15 86.6
total 1267 1601 79.1


line stmt bran cond sub pod time code
1             # vim: ts=4 sts=4 sw=4 et:
2             package HTTP::Tiny;
3 31     31   3668199 use strict;
  31         56  
  31         1117  
4 31     31   178 use warnings;
  31         52  
  31         5622  
5             # ABSTRACT: A small, simple, correct HTTP/1.1 client
6              
7             our $VERSION = '0.094';
8              
9 15     15   85 sub _croak { require Carp; Carp::croak(@_) }
  15         1931  
10              
11             #pod =method new
12             #pod
13             #pod $http = HTTP::Tiny->new( %attributes );
14             #pod
15             #pod This constructor returns a new HTTP::Tiny object. Valid attributes include:
16             #pod
17             #pod =for :list
18             #pod * C — A user-agent string (defaults to 'HTTP-Tiny/$VERSION'). If
19             #pod C — ends in a space character, the default user-agent string is
20             #pod appended.
21             #pod * C — An instance of L — or equivalent class
22             #pod that supports the C and C methods
23             #pod * C — A hashref of default headers to apply to requests
24             #pod * C — The local IP address to bind to
25             #pod * C — Whether to reuse the last connection (if for the same
26             #pod scheme, host and port) (defaults to 1)
27             #pod * C — How many seconds to keep a connection available
28             #pod for after a request (defaults to 0, unlimited)
29             #pod * C — Maximum number of redirects allowed (defaults to 5)
30             #pod * C — Maximum response size in bytes (only when not using a data
31             #pod callback). If defined, requests with responses larger than this will return
32             #pod a 599 status code.
33             #pod * C — URL of a proxy server to use for HTTP connections
34             #pod (default is C<$ENV{http_proxy}> — if set)
35             #pod * C — URL of a proxy server to use for HTTPS connections
36             #pod (default is C<$ENV{https_proxy}> — if set)
37             #pod * C — URL of a generic proxy server for both HTTP and HTTPS
38             #pod connections (default is C<$ENV{all_proxy}> — if set)
39             #pod * C — List of domain suffixes that should not be proxied. Must
40             #pod be a comma-separated string or an array reference. (default is
41             #pod C<$ENV{no_proxy}> —)
42             #pod * C — Request timeout in seconds (default is 60) If a socket open,
43             #pod read or write takes longer than the timeout, the request response status code
44             #pod will be 599.
45             #pod * C — A boolean that indicates whether to validate the TLS/SSL
46             #pod certificate of an C — connection (default is true). Changed from false
47             #pod to true in version 0.083.
48             #pod * C — A hashref of C — options to pass through to
49             #pod L
50             #pod * C<$ENV{PERL_HTTP_TINY_SSL_INSECURE_BY_DEFAULT}> - Changes the default
51             #pod certificate verification behavior to not check server identity if set to 1.
52             #pod Only effective if C is not set. Added in version 0.083.
53             #pod
54             #pod
55             #pod An accessor/mutator method exists for each attribute.
56             #pod
57             #pod Passing an explicit C for C, C or C will
58             #pod prevent getting the corresponding proxies from the environment.
59             #pod
60             #pod Errors during request execution will result in a pseudo-HTTP status code of 599
61             #pod and a reason of "Internal Exception". The content field in the response will
62             #pod contain the text of the error.
63             #pod
64             #pod The C parameter enables a persistent connection, but only to a
65             #pod single destination scheme, host and port. If any connection-relevant
66             #pod attributes are modified via accessor, or if the process ID or thread ID change,
67             #pod the persistent connection will be dropped. If you want persistent connections
68             #pod across multiple destinations, use multiple HTTP::Tiny objects.
69             #pod
70             #pod The C parameter allows you to control how long a
71             #pod keep alive connection will be considered for reuse. By setting this lower
72             #pod than the server keep alive time, this allows you to avoid race conditions where
73             #pod the server closes the connection while preparing to write the request on
74             #pod a reused persistent connection.
75             #pod
76             #pod See L for more on the C and C
77             #pod attributes.
78             #pod
79             #pod =cut
80              
81             my @attributes;
82             BEGIN {
83 31     31   200 @attributes = qw(
84             cookie_jar default_headers http_proxy https_proxy keep_alive
85             local_address max_redirect max_size proxy no_proxy
86             SSL_options verify_SSL
87             );
88 31         81 my %persist_ok = map {; $_ => 1 } qw(
  124         322  
89             cookie_jar default_headers max_redirect max_size
90             );
91 31     31   194 no strict 'refs';
  31         164  
  31         1308  
92 31     31   172 no warnings 'uninitialized';
  31         68  
  31         5078  
93 31         105 for my $accessor ( @attributes ) {
94 372         26224 *{$accessor} = sub {
95             @_ > 1
96             ? do {
97 1 50 33     5 delete $_[0]->{handle} if !$persist_ok{$accessor} && $_[1] ne $_[0]->{$accessor};
98 1         2 $_[0]->{$accessor} = $_[1]
99             }
100 77 100   77   486 : $_[0]->{$accessor};
101 372         1147 };
102             }
103             }
104              
105             sub agent {
106 179     179 0 362 my($self, $agent) = @_;
107 179 100       479 if( @_ > 1 ){
108             $self->{agent} =
109 173 100 100     1136 (defined $agent && $agent =~ / $/) ? $agent . $self->_agent : $agent;
110             }
111 179         525 return $self->{agent};
112             }
113              
114             sub timeout {
115 8     8 0 40 my ($self, $timeout) = @_;
116 8 100       21 if ( @_ > 1 ) {
117 3         21 $self->{timeout} = $timeout;
118 3 100       11 if ($self->{handle}) {
119 2         5 $self->{handle}->timeout($timeout);
120             }
121             }
122 8         38 return $self->{timeout};
123             }
124              
125             sub new {
126 172     172 1 5585814 my($class, %args) = @_;
127              
128             # Support lower case verify_ssl argument, but only if verify_SSL is not
129             # true.
130 172 100       713 if ( exists $args{verify_ssl} ) {
131 7   100     22 $args{verify_SSL} ||= $args{verify_ssl};
132             }
133              
134             my $self = {
135             max_redirect => 5,
136             timeout => defined $args{timeout} ? $args{timeout} : 60,
137             keep_alive => 1,
138             keep_alive_timeout => 0,
139             verify_SSL => defined $args{verify_SSL} ? $args{verify_SSL} : _verify_SSL_default(),
140             no_proxy => $ENV{no_proxy},
141 172 100       1072 };
    100          
142              
143 172         390 bless $self, $class;
144              
145 172 100       472 $class->_validate_cookie_jar( $args{cookie_jar} ) if $args{cookie_jar};
146              
147 170         406 for my $key ( @attributes ) {
148 2040 100       3662 $self->{$key} = $args{$key} if exists $args{$key}
149             }
150              
151 170 100       686 $self->agent( exists $args{agent} ? $args{agent} : $class->_agent );
152              
153 170         1305 $self->_set_proxies;
154              
155 169         2321 return $self;
156             }
157              
158             sub _verify_SSL_default {
159 322     322   598 my ($self) = @_;
160             # Check if insecure default certificate verification behaviour has been
161             # changed by the user by setting PERL_HTTP_TINY_SSL_INSECURE_BY_DEFAULT=1
162 322 100 100     3777 return (($ENV{PERL_HTTP_TINY_SSL_INSECURE_BY_DEFAULT} || '') eq '1') ? 0 : 1;
163             }
164              
165             sub _set_proxies {
166 170     170   391 my ($self) = @_;
167              
168             # get proxies from %ENV only if not provided; explicit undef will disable
169             # getting proxies from the environment
170              
171             # generic proxy
172 170 100       454 if (! exists $self->{proxy} ) {
173 167   100     910 $self->{proxy} = $ENV{all_proxy} || $ENV{ALL_PROXY};
174             }
175              
176 170 100       385 if ( defined $self->{proxy} ) {
177 4         15 $self->_split_proxy( 'generic proxy' => $self->{proxy} ); # validate
178             }
179             else {
180 166         289 delete $self->{proxy};
181             }
182              
183             # http proxy
184 170 100       427 if (! exists $self->{http_proxy} ) {
185             # under CGI, bypass HTTP_PROXY as request sets it from Proxy header
186 169 100 100     394 local $ENV{HTTP_PROXY} = ($ENV{CGI_HTTP_PROXY} || "") if $ENV{REQUEST_METHOD};
187 169   100     945 $self->{http_proxy} = $ENV{http_proxy} || $ENV{HTTP_PROXY} || $self->{proxy};
188             }
189              
190 170 100       339 if ( defined $self->{http_proxy} ) {
191 10         27 $self->_split_proxy( http_proxy => $self->{http_proxy} ); # validate
192 9         40 $self->{_has_proxy}{http} = 1;
193             }
194             else {
195 160         249 delete $self->{http_proxy};
196             }
197              
198             # https proxy
199 169 100       382 if (! exists $self->{https_proxy} ) {
200 168   100     884 $self->{https_proxy} = $ENV{https_proxy} || $ENV{HTTPS_PROXY} || $self->{proxy};
201             }
202              
203 169 100       328 if ( $self->{https_proxy} ) {
204 6         19 $self->_split_proxy( https_proxy => $self->{https_proxy} ); # validate
205 6         14 $self->{_has_proxy}{https} = 1;
206             }
207             else {
208 163         234 delete $self->{https_proxy};
209             }
210              
211             # Split no_proxy to array reference if not provided as such
212 169 100       726 unless ( ref $self->{no_proxy} eq 'ARRAY' ) {
213             $self->{no_proxy} =
214 166 100       531 (defined $self->{no_proxy}) ? [ split /\s*,\s*/, $self->{no_proxy} ] : [];
215             }
216              
217 169         485 return;
218             }
219              
220             #pod =method get|head|put|post|patch|delete
221             #pod
222             #pod $response = $http->get($url);
223             #pod $response = $http->get($url, \%options);
224             #pod $response = $http->head($url);
225             #pod
226             #pod These methods are shorthand for calling C for the given method. The
227             #pod URL must have unsafe characters escaped and international domain names encoded.
228             #pod See C for valid options and a description of the response.
229             #pod
230             #pod The C field of the response will be true if the status code is 2XX.
231             #pod
232             #pod =cut
233              
234             for my $sub_name ( qw/get head put post patch delete/ ) {
235             my $req_method = uc $sub_name;
236 31     31   227 no strict 'refs';
  31         51  
  31         157007  
237 1 0 0 1 1 69 eval <<"HERE"; ## no critic
  1 100 33 76 1 6  
  1 0 50 2 1 11  
  76 0 100 0 1 23061  
  76 50 100 2 1 335  
  73 50 100 8 1 822  
  2   0     1239  
  2   33     8  
  2   50     17  
  0   0     0  
  0   0     0  
  0   0     0  
  2   33     84  
  2   33     12  
  2   50     8  
  8   33     442  
  8   33     49  
  8   50     35  
238             sub $sub_name {
239             my (\$self, \$url, \$args) = \@_;
240             \@_ == 2 || (\@_ == 3 && ref \$args eq 'HASH')
241             or _croak(q/Usage: \$http->$sub_name(URL, [HASHREF])/ . "\n");
242             return \$self->request('$req_method', \$url, \$args || {});
243             }
244             HERE
245             }
246              
247             #pod =method post_form
248             #pod
249             #pod $response = $http->post_form($url, $form_data);
250             #pod $response = $http->post_form($url, $form_data, \%options);
251             #pod
252             #pod This method executes a C request and sends the key/value pairs from a
253             #pod form data hash or array reference to the given URL with a C of
254             #pod C. If data is provided as an array
255             #pod reference, the order is preserved; if provided as a hash reference, the terms
256             #pod are sorted by key for consistency. See documentation for the
257             #pod C method for details on the encoding.
258             #pod
259             #pod The URL must have unsafe characters escaped and international domain names
260             #pod encoded. See C for valid options and a description of the response.
261             #pod Any C header or content in the options hashref will be ignored.
262             #pod
263             #pod The C field of the response will be true if the status code is 2XX.
264             #pod
265             #pod =cut
266              
267             sub post_form {
268 7     7 1 1202 my ($self, $url, $data, $args) = @_;
269 7 50 33     23 (@_ == 3 || @_ == 4 && ref $args eq 'HASH')
      66        
270             or _croak(q/Usage: $http->post_form(URL, DATAREF, [HASHREF])/ . "\n");
271              
272 7         7 my $headers = {};
273 7 100       8 while ( my ($key, $value) = each %{$args->{headers} || {}} ) {
  8         37  
274 1         4 $headers->{lc $key} = $value;
275             }
276              
277 7         22 return $self->request('POST', $url, {
278             # Any existing 'headers' key in $args will be overridden with a
279             # normalized version below.
280             %$args,
281             content => $self->www_form_urlencode($data),
282             headers => {
283             %$headers,
284             'content-type' => 'application/x-www-form-urlencoded'
285             },
286             }
287             );
288             }
289              
290             #pod =method mirror
291             #pod
292             #pod $response = $http->mirror($url, $file, \%options)
293             #pod if ( $response->{success} ) {
294             #pod print "$file is up to date\n";
295             #pod }
296             #pod
297             #pod Executes a C request for the URL and saves the response body to the file
298             #pod name provided. The URL must have unsafe characters escaped and international
299             #pod domain names encoded. If the file already exists, the request will include an
300             #pod C header with the modification timestamp of the file. You
301             #pod may specify a different C header yourself in the C<<
302             #pod $options->{headers} >> hash.
303             #pod
304             #pod The C field of the response will be true if the status code is 2XX
305             #pod or if the status code is 304 (unmodified).
306             #pod
307             #pod If the file was modified and the server response includes a properly
308             #pod formatted C header, the file modification time will
309             #pod be updated accordingly.
310             #pod
311             #pod =cut
312              
313             sub mirror {
314 9     9 1 2721 my ($self, $url, $file, $args) = @_;
315 9 100 100     43 @_ == 3 || (@_ == 4 && ref $args eq 'HASH')
      100        
316             or _croak(q/Usage: $http->mirror(URL, FILE, [HASHREF])/ . "\n");
317              
318 5 100       10 if ( exists $args->{headers} ) {
319 1         2 my $headers = {};
320 1 50       2 while ( my ($key, $value) = each %{$args->{headers} || {}} ) {
  2         8  
321 1         5 $headers->{lc $key} = $value;
322             }
323 1         2 $args->{headers} = $headers;
324             }
325              
326 5 100 66     86 if ( -e $file and my $mtime = (stat($file))[9] ) {
327 3   66     15 $args->{headers}{'if-modified-since'} ||= $self->_http_date($mtime);
328             }
329 5         20 my $tempfile = $file . int(rand(2**31));
330              
331 5         31 require Fcntl;
332 5 50       464 sysopen my $fh, $tempfile, Fcntl::O_CREAT()|Fcntl::O_EXCL()|Fcntl::O_WRONLY()
333             or _croak(qq/Error: Could not create temporary file $tempfile for downloading: $!\n/);
334 5         19 binmode $fh;
335 5     3   27 $args->{data_callback} = sub { print {$fh} $_[0] };
  3         3  
  3         9  
336 5         12 my $response = $self->request('GET', $url, $args);
337 5 50       154 close $fh
338             or _croak(qq/Error: Caught error closing temporary file $tempfile: $!\n/);
339              
340 5 100       15 if ( $response->{success} ) {
341 3 50       285 rename $tempfile, $file
342             or _croak(qq/Error replacing $file with $tempfile: $!\n/);
343 3         9 my $lm = $response->{headers}{'last-modified'};
344 3 50 33     14 if ( $lm and my $mtime = $self->_parse_http_date($lm) ) {
345 3         55 utime $mtime, $mtime, $file;
346             }
347             }
348 5   100     17 $response->{success} ||= $response->{status} eq '304';
349 5         178 unlink $tempfile;
350 5         46 return $response;
351             }
352              
353             #pod =method request
354             #pod
355             #pod $response = $http->request($method, $url);
356             #pod $response = $http->request($method, $url, \%options);
357             #pod
358             #pod Executes an HTTP request of the given method type ('GET', 'HEAD', 'POST',
359             #pod 'PUT', etc.) on the given URL. The URL must have unsafe characters escaped and
360             #pod international domain names encoded.
361             #pod
362             #pod B: Method names are B per the HTTP/1.1 specification.
363             #pod Don't use C when you really want C. See L for
364             #pod how this applies to redirection.
365             #pod
366             #pod If the URL includes a "user:password" stanza, they will be used for Basic-style
367             #pod authorization headers. (Authorization headers will not be included in a
368             #pod redirected request.) For example:
369             #pod
370             #pod $http->request('GET', 'http://Aladdin:open sesame@example.com/');
371             #pod
372             #pod If the "user:password" stanza contains reserved characters, they must
373             #pod be percent-escaped:
374             #pod
375             #pod $http->request('GET', 'http://john%40example.com:password@example.com/');
376             #pod
377             #pod A hashref of options may be appended to modify the request.
378             #pod
379             #pod Valid options are:
380             #pod
381             #pod =for :list
382             #pod * C
383             #pod A hashref containing headers to include with the request. If the value for
384             #pod a header is an array reference, the header will be output multiple times with
385             #pod each value in the array. These headers over-write any default headers.
386             #pod * C
387             #pod A scalar to include as the body of the request OR a code reference
388             #pod that will be called iteratively to produce the body of the request
389             #pod * C
390             #pod A code reference that will be called if it exists to provide a hashref
391             #pod of trailing headers (only used with chunked transfer-encoding)
392             #pod * C
393             #pod A code reference that will be called for each chunks of the response
394             #pod body received.
395             #pod * C
396             #pod Override host resolution and force all connections to go only to a
397             #pod specific peer address, regardless of the URL of the request. This will
398             #pod include any redirections! This options should be used with extreme
399             #pod caution (e.g. debugging or very special circumstances). It can be given as
400             #pod either a scalar or a code reference that will receive the hostname and
401             #pod whose response will be taken as the address.
402             #pod
403             #pod The C header is generated from the URL in accordance with RFC 2616. It
404             #pod is a fatal error to specify C in the C option. Other headers
405             #pod may be ignored or overwritten if necessary for transport compliance.
406             #pod
407             #pod If the C option is a code reference, it will be called iteratively
408             #pod to provide the content body of the request. It should return the empty
409             #pod string or undef when the iterator is exhausted.
410             #pod
411             #pod If the C option is the empty string, no C or
412             #pod C headers will be generated.
413             #pod
414             #pod If the C option is provided, it will be called iteratively until
415             #pod the entire response body is received. The first argument will be a string
416             #pod containing a chunk of the response body, the second argument will be the
417             #pod in-progress response hash reference, as described below. (This allows
418             #pod customizing the action of the callback based on the C or C
419             #pod received prior to the content body.)
420             #pod
421             #pod Content data in the request/response is handled as "raw bytes". Any
422             #pod encoding/decoding (with associated headers) are the responsibility of the
423             #pod caller.
424             #pod
425             #pod The C method returns a hashref containing the response. The hashref
426             #pod will have the following keys:
427             #pod
428             #pod =for :list
429             #pod * C
430             #pod Boolean indicating whether the operation returned a 2XX status code
431             #pod * C
432             #pod URL that provided the response. This is the URL of the request unless
433             #pod there were redirections, in which case it is the last URL queried
434             #pod in a redirection chain
435             #pod * C
436             #pod The HTTP status code of the response
437             #pod * C
438             #pod The response phrase returned by the server
439             #pod * C
440             #pod The body of the response. If the response does not have any content
441             #pod or if a data callback is provided to consume the response body,
442             #pod this will be the empty string
443             #pod * C
444             #pod A hashref of header fields. All header field names will be normalized
445             #pod to be lower case. If a header is repeated, the value will be an arrayref;
446             #pod it will otherwise be a scalar string containing the value
447             #pod * C -
448             #pod If this field exists, it is the protocol of the response
449             #pod such as HTTP/1.0 or HTTP/1.1
450             #pod * C
451             #pod If this field exists, it is an arrayref of response hash references from
452             #pod redirects in the same order that redirections occurred. If it does
453             #pod not exist, then no redirections occurred.
454             #pod
455             #pod On an error during the execution of the request, the C field will
456             #pod contain 599, and the C field will contain the text of the error.
457             #pod
458             #pod =cut
459              
460             my %idempotent = map { $_ => 1 } qw/GET HEAD PUT DELETE OPTIONS TRACE/;
461              
462             sub request {
463 149     149 1 15763 my ($self, $method, $url, $args) = @_;
464 149 100 100     863 @_ == 3 || (@_ == 4 && ref $args eq 'HASH')
      100        
465             or _croak(q/Usage: $http->request(METHOD, URL, [HASHREF])/ . "\n");
466 145   100     440 $args ||= {}; # we keep some state in this during _request
467              
468             # RFC 2616 Section 8.1.4 mandates a single retry on broken socket
469 145         196 my $response;
470 145         411 for ( 0 .. 1 ) {
471 145         227 $response = eval { $self->_request($method, $url, $args) };
  145         444  
472 145 50 66     5700 last unless $@ && $idempotent{$method}
      33        
473             && $@ =~ m{^(?:Socket closed|Unexpected end|SSL read error)};
474             }
475              
476 145 100       444 if (my $e = $@) {
477             # maybe we got a response hash thrown from somewhere deep
478 20 0 33     73 if ( ref $e eq 'HASH' && exists $e->{status} ) {
479 0 0       0 $e->{redirects} = delete $args->{_redirects} if @{ $args->{_redirects} || []};
  0 0       0  
480 0         0 return $e;
481             }
482              
483             # otherwise, stringify it
484 20         52 $e = "$e";
485             $response = {
486             url => $url,
487             success => q{},
488             status => 599,
489             reason => 'Internal Exception',
490             content => $e,
491             headers => {
492             'content-type' => 'text/plain',
493             'content-length' => length $e,
494             },
495 20 100       111 ( @{$args->{_redirects} || []} ? (redirects => delete $args->{_redirects}) : () ),
  20 50       279  
496             };
497             }
498 145         740 return $response;
499             }
500              
501             #pod =method www_form_urlencode
502             #pod
503             #pod $params = $http->www_form_urlencode( $data );
504             #pod $response = $http->get("http://example.com/query?$params");
505             #pod
506             #pod This method converts the key/value pairs from a data hash or array reference
507             #pod into a C string. The keys and values from the data
508             #pod reference will be UTF-8 encoded and escaped per RFC 3986. If a value is an
509             #pod array reference, the key will be repeated with each of the values of the array
510             #pod reference. If data is provided as a hash reference, the key/value pairs in the
511             #pod resulting string will be sorted by key and value for consistent ordering.
512             #pod
513             #pod =cut
514              
515             sub www_form_urlencode {
516 7     7 1 10 my ($self, $data) = @_;
517 7 50 33     21 (@_ == 2 && ref $data)
518             or _croak(q/Usage: $http->www_form_urlencode(DATAREF)/ . "\n");
519 7 50 66     21 (ref $data eq 'HASH' || ref $data eq 'ARRAY')
520             or _croak("form data must be a hash or array reference\n");
521              
522             my @params
523             = ref $data eq 'HASH'
524 7 100       29 ? map { ($_ => $data->{$_}) } sort keys %$data
  9         17  
525             : @$data;
526 7 50       16 @params % 2 == 0
527             or _croak("form data reference must have an even number of terms\n");
528              
529 7         17 my @terms;
530 7         14 while( @params ) {
531 21         37 my ($key, $value) = splice(@params, 0, 2);
532 21 100       27 _croak("form data keys must not be undef")
533             if !defined($key);
534 20 100       24 if ( ref $value eq 'ARRAY' ) {
535 2         3 unshift @params, map { $key => $_ } @$value;
  4         10  
536             }
537             else {
538 18         22 push @terms, join("=", map { $self->_uri_escape($_) } $key, $value);
  36         46  
539             }
540             }
541              
542 6         48 return join("&", @terms);
543             }
544              
545             #pod =method can_ssl
546             #pod
547             #pod $ok = HTTP::Tiny->can_ssl;
548             #pod ($ok, $why) = HTTP::Tiny->can_ssl;
549             #pod ($ok, $why) = $http->can_ssl;
550             #pod
551             #pod Indicates if SSL support is available. When called as a class object, it
552             #pod checks for the correct version of L and L.
553             #pod When called as an object methods, if C is true or if C
554             #pod is set in C, it checks that a CA file is available.
555             #pod
556             #pod In scalar context, returns a boolean indicating if SSL is available.
557             #pod In list context, returns the boolean and a (possibly multi-line) string of
558             #pod errors indicating why SSL isn't available.
559             #pod
560             #pod =cut
561              
562             sub can_ssl {
563 36     36 1 427461 my ($self) = @_;
564              
565 36         92 my($ok, $reason) = (1, '');
566              
567             # Need IO::Socket::SSL 1.968 for default_ca()
568 36         343 local @INC = @INC;
569 36 50       185 pop @INC if $INC[-1] eq '.';
570 36 50       75 unless (eval {require IO::Socket::SSL; IO::Socket::SSL->VERSION(1.968)}) {
  36         1940  
  36         117842  
571 0         0 $ok = 0;
572 0         0 $reason .= qq/IO::Socket::SSL 1.968 or later must be installed for https support\n/;
573             }
574              
575             # Need Net::SSLeay 1.49 for MODE_AUTO_RETRY
576 36 50       78 unless (eval {require Net::SSLeay; Net::SSLeay->VERSION(1.49)}) {
  36         162  
  36         482  
577 0         0 $ok = 0;
578 0         0 $reason .= qq/Net::SSLeay 1.49 or later must be installed for https support\n/;
579             }
580              
581             # If an object, check that SSL config lets us get a CA if necessary
582 36 50 33     125 if ( ref($self) && ( $self->{verify_SSL} || $self->{SSL_options}{SSL_verify_mode} ) ) {
      66        
583             my $handle = HTTP::Tiny::Handle->new(
584             SSL_options => $self->{SSL_options},
585             verify_SSL => $self->{verify_SSL},
586 3         22 );
587 3 100       8 unless ( eval { $handle->_find_CA; 1 } ) {
  3         12  
  2         9  
588 1         3 $ok = 0;
589 1         6 $reason .= "$@";
590             }
591             }
592              
593 36 100       206 wantarray ? ($ok, $reason) : $ok;
594             }
595              
596             #pod =method connected
597             #pod
598             #pod $host = $http->connected;
599             #pod ($host, $port) = $http->connected;
600             #pod
601             #pod Indicates if a connection to a peer is being kept alive, per the C
602             #pod option.
603             #pod
604             #pod In scalar context, returns the peer host and port, joined with a colon, or
605             #pod C (if no peer is connected).
606             #pod In list context, returns the peer host and port or an empty list (if no peer
607             #pod is connected).
608             #pod
609             #pod B: This method cannot reliably be used to discover whether the remote
610             #pod host has closed its end of the socket.
611             #pod
612             #pod =cut
613              
614             sub connected {
615 0     0 1 0 my ($self) = @_;
616              
617 0 0       0 if ( $self->{handle} ) {
618 0         0 return $self->{handle}->connected;
619             }
620 0         0 return;
621             }
622              
623             #--------------------------------------------------------------------------#
624             # private methods
625             #--------------------------------------------------------------------------#
626              
627             my %DefaultPort = (
628             http => 80,
629             https => 443,
630             );
631              
632             sub _agent {
633 172   66 172   740 my $class = ref($_[0]) || $_[0];
634 172         990 (my $default_agent = $class) =~ s{::}{-}g;
635 172         1743 my $version = $class->VERSION;
636 172 50       740 $default_agent .= "/$version" if defined $version;
637 172         641 return $default_agent;
638             }
639              
640             sub _request {
641 158     158   311 my ($self, $method, $url, $args) = @_;
642              
643 158         470 my ($scheme, $host, $port, $path_query, $auth) = $self->_split_url($url);
644              
645 158 100 100     525 if ($scheme ne 'http' && $scheme ne 'https') {
646 1         5 die(qq/Unsupported URL scheme '$scheme'\n/);
647             }
648              
649             my $request = {
650             method => $method,
651             scheme => $scheme,
652             host => $host,
653             port => $port,
654 157 100       1357 host_port => ($port == $DefaultPort{$scheme} ? $host : "$host:$port"),
655             uri => $path_query,
656             headers => {},
657             };
658              
659 157   33     630 my $peer = $args->{peer} || $host;
660              
661             # Allow 'peer' to be a coderef.
662 157 50       365 if ('CODE' eq ref $peer) {
663 0         0 $peer = $peer->($host);
664             }
665              
666             # We remove the cached handle so it is not reused in the case of redirect.
667             # If all is well, it will be recached at the end of _request. We only
668             # reuse for the same scheme, host and port
669 157         290 my $handle = delete $self->{handle};
670 157 100       314 if ( $handle ) {
671 16 100       34 unless ( $handle->can_reuse( $scheme, $host, $port, $peer ) ) {
672 11         66 $handle->close;
673 11         330 undef $handle;
674             }
675             }
676 157   100     694 $handle ||= $self->_open_handle( $request, $scheme, $host, $port, $peer );
677              
678 143         938 $self->_prepare_headers_and_cb($request, $args, $url, $auth);
679 142         450 $handle->write_request($request);
680              
681 141         2273 my $response;
682 143         386 do { $response = $handle->read_response_header }
683 141         183 until (substr($response->{status},0,1) ne '1');
684              
685 139 100       417 $self->_update_cookie_jar( $url, $response ) if $self->{cookie_jar};
686 139         414 my @redir_args = $self->_maybe_redirect($request, $response, $args);
687              
688 139         187 my $known_message_length;
689 139 100 100     574 if ($method eq 'HEAD' || $response->{status} =~ /^[23]04/) {
690             # response has no message body
691 2         4 $known_message_length = 1;
692             }
693             else {
694             # Ignore any data callbacks during redirection.
695 137 100       233 my $cb_args = @redir_args ? +{} : $args;
696 137         336 my $data_cb = $self->_prepare_data_cb($response, $cb_args);
697 137         328 $known_message_length = $handle->read_body($data_cb, $response);
698             }
699              
700 138 100 66     484 if ( $self->{keep_alive}
      100        
      100        
      100        
      100        
701             && $handle->connected
702             && $known_message_length
703             && $response->{protocol} eq 'HTTP/1.1'
704             && ($response->{headers}{connection} || '') ne 'close'
705             ) {
706 43         2170 $handle->_update_last_used();
707 43         1870 $self->{handle} = $handle;
708             }
709             else {
710 95         530 $handle->close;
711             }
712              
713 138         1626 $response->{success} = substr( $response->{status}, 0, 1 ) eq '2';
714 138         307 $response->{url} = $url;
715              
716             # Push the current response onto the stack of redirects if redirecting.
717 138 100       342 if (@redir_args) {
718 13         14 push @{$args->{_redirects}}, $response;
  13         25  
719 13         65 return $self->_request(@redir_args, $args);
720             }
721              
722             # Copy the stack of redirects into the response before returning.
723             $response->{redirects} = delete $args->{_redirects}
724 125 100       143 if @{$args->{_redirects}};
  125         332  
725 125         1402 return $response;
726             }
727              
728             sub _open_handle {
729 152     152   402 my ($self, $request, $scheme, $host, $port, $peer) = @_;
730              
731             my $handle = HTTP::Tiny::Handle->new(
732             timeout => $self->{timeout},
733             SSL_options => $self->{SSL_options},
734             verify_SSL => $self->{verify_SSL},
735             local_address => $self->{local_address},
736             keep_alive => $self->{keep_alive},
737             keep_alive_timeout => $self->{keep_alive_timeout}
738 152         1461 );
739              
740 152 50       570 require Time::HiRes if $self->{keep_alive_timeout} > 0;
741              
742 152 100 66     461 if ($self->{_has_proxy}{$scheme} && ! grep { $host =~ /\Q$_\E$/ } @{$self->{no_proxy}}) {
  0         0  
  2         9  
743 2         8 return $self->_proxy_connect( $request, $handle );
744             }
745             else {
746 150         901 return $handle->connect($scheme, $host, $port, $peer);
747             }
748             }
749              
750             sub _proxy_connect {
751 2     2   6 my ($self, $request, $handle) = @_;
752              
753 2         5 my @proxy_vars;
754 2 50       7 if ( $request->{scheme} eq 'https' ) {
755 0 0       0 _croak(qq{No https_proxy defined}) unless $self->{https_proxy};
756 0         0 @proxy_vars = $self->_split_proxy( https_proxy => $self->{https_proxy} );
757 0 0       0 if ( $proxy_vars[0] eq 'https' ) {
758 0         0 _croak(qq{Can't proxy https over https: $request->{uri} via $self->{https_proxy}});
759             }
760             }
761             else {
762 2 50       8 _croak(qq{No http_proxy defined}) unless $self->{http_proxy};
763 2         6 @proxy_vars = $self->_split_proxy( http_proxy => $self->{http_proxy} );
764             }
765              
766 2         6 my ($p_scheme, $p_host, $p_port, $p_auth) = @proxy_vars;
767              
768 2 100 66     33 if ( length $p_auth && ! defined $request->{headers}{'proxy-authorization'} ) {
769 1         3 $self->_add_basic_auth_header( $request, 'proxy-authorization' => $p_auth );
770             }
771              
772 2         18 $handle->connect($p_scheme, $p_host, $p_port, $p_host);
773              
774 2 50       13 if ($request->{scheme} eq 'https') {
775 0         0 $self->_create_proxy_tunnel( $request, $handle );
776             }
777             else {
778             # non-tunneled proxy requires absolute URI
779 2         10 $request->{uri} = "$request->{scheme}://$request->{host_port}$request->{uri}";
780             }
781              
782 2         12 return $handle;
783             }
784              
785             sub _split_proxy {
786 22     22   44 my ($self, $type, $proxy) = @_;
787              
788 22         31 my ($scheme, $host, $port, $path_query, $auth) = eval { $self->_split_url($proxy) };
  22         50  
789              
790 22 50 66     137 unless(
      66        
      33        
      33        
791             defined($scheme) && length($scheme) && length($host) && length($port)
792             && $path_query eq '/'
793             ) {
794 1         4 _croak(qq{$type URL must be in format http[s]://[auth@]:/\n});
795             }
796              
797 21         39 return ($scheme, $host, $port, $auth);
798             }
799              
800             sub _create_proxy_tunnel {
801 0     0   0 my ($self, $request, $handle) = @_;
802              
803 0         0 $handle->_assert_ssl;
804              
805             my $agent = exists($request->{headers}{'user-agent'})
806 0 0       0 ? $request->{headers}{'user-agent'} : $self->{agent};
807              
808 0         0 my $connect_request = {
809             method => 'CONNECT',
810             uri => "$request->{host}:$request->{port}",
811             headers => {
812             host => "$request->{host}:$request->{port}",
813             'user-agent' => $agent,
814             }
815             };
816              
817 0 0       0 if ( $request->{headers}{'proxy-authorization'} ) {
818             $connect_request->{headers}{'proxy-authorization'} =
819 0         0 delete $request->{headers}{'proxy-authorization'};
820             }
821              
822 0         0 $handle->write_request($connect_request);
823 0         0 my $response;
824 0         0 do { $response = $handle->read_response_header }
825 0         0 until (substr($response->{status},0,1) ne '1');
826              
827             # if CONNECT failed, throw the response so it will be
828             # returned from the original request() method;
829 0 0       0 unless (substr($response->{status},0,1) eq '2') {
830 0         0 die $response;
831             }
832              
833             # tunnel established, so start SSL handshake
834 0         0 $handle->start_ssl( $request->{host} );
835              
836 0         0 return;
837             }
838              
839             sub _prepare_headers_and_cb {
840 143     143   320 my ($self, $request, $args, $url, $auth) = @_;
841              
842 143         487 for ($self->{default_headers}, $args->{headers}) {
843 286 100       529 next unless defined;
844 25         107 while (my ($k, $v) = each %$_) {
845 32         94 $request->{headers}{lc $k} = $v;
846 32         157 $request->{header_case}{lc $k} = $k;
847             }
848             }
849              
850 143 100       339 if (exists $request->{headers}{'host'}) {
851 1         13 die(qq/The 'Host' header must not be provided as header option\n/);
852             }
853              
854 142         391 $request->{headers}{'host'} = $request->{host_port};
855 142   33     700 $request->{headers}{'user-agent'} ||= $self->{agent};
856             $request->{headers}{'connection'} = "close"
857 142 100       452 unless $self->{keep_alive};
858              
859             # Some servers error on an empty-body PUT/POST without a content-length
860 142 100 100     560 if ( $request->{method} eq 'PUT' || $request->{method} eq 'POST' ) {
861 49 100 100     140 if (!defined($args->{content}) || !length($args->{content}) ) {
862 19         56 $request->{headers}{'content-length'} = 0;
863             }
864             }
865              
866 142 100       308 if ( defined $args->{content} ) {
867 31 100       84 if ( ref $args->{content} eq 'CODE' ) {
    100          
868 5 50 33     15 if ( exists $request->{'content-length'} && $request->{'content-length'} == 0 ) {
869 0     0   0 $request->{cb} = sub { "" };
  0         0  
870             }
871             else {
872 5   50     12 $request->{headers}{'content-type'} ||= "application/octet-stream";
873             $request->{headers}{'transfer-encoding'} = 'chunked'
874             unless exists $request->{headers}{'content-length'}
875 5 50 66     22 || $request->{headers}{'transfer-encoding'};
876 5         13 $request->{cb} = $args->{content};
877             }
878             }
879             elsif ( length $args->{content} ) {
880 25         32 my $content = $args->{content};
881 25 50       117 if ( "$]" >= 5.008 ) {
882 25 50       61 utf8::downgrade($content, 1)
883             or die(qq/Wide character in request message body\n/);
884             }
885 25   100     66 $request->{headers}{'content-type'} ||= "application/octet-stream";
886             $request->{headers}{'content-length'} = length $content
887             unless $request->{headers}{'content-length'}
888 25 50 66     90 || $request->{headers}{'transfer-encoding'};
889 25     50   94 $request->{cb} = sub { substr $content, 0, length $content, '' };
  50         121  
890             }
891             $request->{trailer_cb} = $args->{trailer_callback}
892 31 100       68 if ref $args->{trailer_callback} eq 'CODE';
893             }
894              
895             ### If we have a cookie jar, then maybe add relevant cookies
896 142 100       392 if ( $self->{cookie_jar} ) {
897 17         42 my $cookies = $self->cookie_jar->cookie_header( $url );
898 17 100       176 $request->{headers}{cookie} = $cookies if length $cookies;
899             }
900              
901             # if we have Basic auth parameters, add them
902 142 100 100     354 if ( length $auth && ! defined $request->{headers}{authorization} ) {
903 4         10 $self->_add_basic_auth_header( $request, 'authorization' => $auth );
904             }
905              
906 142         244 return;
907             }
908              
909             sub _add_basic_auth_header {
910 5     5   26 my ($self, $request, $header, $auth) = @_;
911 5         1034 require MIME::Base64;
912 5         1668 $request->{headers}{$header} =
913             "Basic " . MIME::Base64::encode_base64($auth, "");
914 5         10 return;
915             }
916              
917             sub _prepare_data_cb {
918 137     137   232 my ($self, $response, $args) = @_;
919 137         216 my $data_cb = $args->{data_callback};
920 137         1865 $response->{content} = '';
921              
922 137 100 100     413 if (!$data_cb || $response->{status} !~ /^2/) {
923 133 100       257 if (defined $self->{max_size}) {
924             $data_cb = sub {
925 1     1   34 $_[1]->{content} .= $_[0];
926             die(qq/Size of response body exceeds the maximum allowed of $self->{max_size}\n/)
927 1 50       31 if length $_[1]->{content} > $self->{max_size};
928 1         10 };
929             }
930             else {
931 132     158   553 $data_cb = sub { $_[1]->{content} .= $_[0] };
  158         2822  
932             }
933             }
934 137         222 return $data_cb;
935             }
936              
937             sub _update_cookie_jar {
938 17     17   25 my ($self, $url, $response) = @_;
939              
940 17         28 my $cookies = $response->{headers}->{'set-cookie'};
941 17 100       24 return unless defined $cookies;
942              
943 15 100       29 my @cookies = ref $cookies ? @$cookies : $cookies;
944              
945 15         32 $self->cookie_jar->add( $url, $_ ) for @cookies;
946              
947 15         280 return;
948             }
949              
950             sub _validate_cookie_jar {
951 9     9   20 my ($class, $jar) = @_;
952              
953             # duck typing
954 9         19 for my $method ( qw/add cookie_header/ ) {
955 17 100 66     168 _croak(qq/Cookie jar must provide the '$method' method\n/)
956             unless ref($jar) && ref($jar)->can($method);
957             }
958              
959 7         13 return;
960             }
961              
962             sub _maybe_redirect {
963 139     139   286 my ($self, $request, $response, $args) = @_;
964 139         221 my $headers = $response->{headers};
965 139         330 my ($status, $method) = ($response->{status}, $request->{method});
966 139   100     614 $args->{_redirects} ||= [];
967              
968 139 100 100     660 if (($status eq '303' or ($status =~ /^30[1278]/ && $method =~ /^GET|HEAD$/))
      66        
      66        
969             and $headers->{location}
970 15         41 and @{$args->{_redirects}} < $self->{max_redirect}
971             ) {
972             my $location = ($headers->{location} =~ /^\//)
973             ? "$request->{scheme}://$request->{host_port}$headers->{location}"
974 13 100       62 : $headers->{location} ;
975 13 100       42 return (($status eq '303' ? 'GET' : $method), $location);
976             }
977 126         357 return;
978             }
979              
980             sub _split_url {
981 194     194   259116 my $url = pop;
982              
983             # URI regex adapted from the URI module
984 194 100       1575 my ($scheme, $host, $path_query) = $url =~ m<\A([^:/?#]+)://([^/?#]*)([^#]*)>
985             or die(qq/Cannot parse URL: '$url'\n/);
986              
987 193         459 $scheme = lc $scheme;
988 193 100       595 $path_query = "/$path_query" unless $path_query =~ m<\A/>;
989              
990 193         296 my $auth = '';
991 193 100       558 if ( (my $i = index $host, '@') != -1 ) {
992             # user:pass@host
993 12         26 $auth = substr $host, 0, $i, ''; # take up to the @ for auth
994 12         18 substr $host, 0, 1, ''; # knock the @ off the host
995              
996             # userinfo might be percent escaped, so recover real auth info
997 12         21 $auth =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
  1         6  
998             }
999 193 100 100     986 my $port = $host =~ s/:(\d*)\z// && length $1 ? $1
    100          
    100          
1000             : $scheme eq 'http' ? 80
1001             : $scheme eq 'https' ? 443
1002             : undef;
1003              
1004 193 100       1064 return ($scheme, (length $host ? lc $host : "localhost") , $port, $path_query, $auth);
1005             }
1006              
1007             # Date conversions adapted from HTTP::Date
1008             my $DoW = "Sun|Mon|Tue|Wed|Thu|Fri|Sat";
1009             my $MoY = "Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec";
1010             sub _http_date {
1011 3     3   309238 my ($sec, $min, $hour, $mday, $mon, $year, $wday) = gmtime($_[1]);
1012 3         40 return sprintf("%s, %02d %s %04d %02d:%02d:%02d GMT",
1013             substr($DoW,$wday*4,3),
1014             $mday, substr($MoY,$mon*4,3), $year+1900,
1015             $hour, $min, $sec
1016             );
1017             }
1018              
1019             sub _parse_http_date {
1020 9     9   4838 my ($self, $str) = @_;
1021 9         1392 require Time::Local;
1022 9         4013 my @tl_parts;
1023 9 100       670 if ($str =~ /^[SMTWF][a-z]+, +(\d{1,2}) ($MoY) +(\d\d\d\d) +(\d\d):(\d\d):(\d\d) +GMT$/) {
    100          
    50          
1024 5         48 @tl_parts = ($6, $5, $4, $1, (index($MoY,$2)/4), $3);
1025             }
1026             elsif ($str =~ /^[SMTWF][a-z]+, +(\d\d)-($MoY)-(\d{2,4}) +(\d\d):(\d\d):(\d\d) +GMT$/ ) {
1027 2         22 @tl_parts = ($6, $5, $4, $1, (index($MoY,$2)/4), $3);
1028             }
1029             elsif ($str =~ /^[SMTWF][a-z]+ +($MoY) +(\d{1,2}) +(\d\d):(\d\d):(\d\d) +(?:[^0-9]+ +)?(\d\d\d\d)$/ ) {
1030 2         22 @tl_parts = ($5, $4, $3, $2, (index($MoY,$1)/4), $6);
1031             }
1032 9         23 return eval {
1033 9 50       41 my $t = @tl_parts ? Time::Local::timegm(@tl_parts) : -1;
1034 9 50       437 $t < 0 ? undef : $t;
1035             };
1036             }
1037              
1038             # URI escaping adapted from URI::Escape
1039             # c.f. http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1
1040             # perl 5.6 ready UTF-8 encoding adapted from JSON::PP
1041             my %escapes = map { chr($_) => sprintf("%%%02X", $_) } 0..255;
1042             $escapes{' '}="+";
1043             my $unsafe_char = qr/[^A-Za-z0-9\-\._~]/;
1044              
1045             sub _uri_escape {
1046 36     36   40 my ($self, $str) = @_;
1047 36 100       44 return "" if !defined $str;
1048 34 50       71 if ( "$]" >= 5.008 ) {
1049 34         42 utf8::encode($str);
1050             }
1051             else {
1052             $str = pack("U*", unpack("C*", $str)) # UTF-8 encode a byte string
1053 31 0   31   16130 if ( length $str == do { use bytes; length $str } );
  31         13149  
  31         4666  
  0         0  
  0         0  
1054 0         0 $str = pack("C*", unpack("C*", $str)); # clear UTF-8 flag
1055             }
1056 34         181 $str =~ s/($unsafe_char)/$escapes{$1}/g;
1057 34         71 return $str;
1058             }
1059              
1060             package
1061             HTTP::Tiny::Handle; # hide from PAUSE/indexers
1062 31     31   4944 use strict;
  31         49  
  31         4700  
1063 31     31   1823 use warnings;
  31         47  
  31         1675  
1064              
1065 31     31   17908 use Errno qw[EINTR EPIPE];
  31         40030  
  31         4055  
1066 31     31   14847 use IO::Socket qw[SOCK_STREAM];
  31         436107  
  31         126  
1067 31     31   15679 use Socket qw[SOL_SOCKET SO_KEEPALIVE TCP_NODELAY IPPROTO_TCP];
  31         53  
  31         161724  
1068              
1069             # PERL_HTTP_TINY_IPV4_ONLY is a private environment variable to force old
1070             # behavior if someone is unable to boostrap CPAN from a new perl install; it is
1071             # not intended for general, per-client use and may be removed in the future
1072             my $SOCKET_CLASS =
1073             $ENV{PERL_HTTP_TINY_IPV4_ONLY} ? 'IO::Socket::INET' :
1074             eval { require IO::Socket::IP; IO::Socket::IP->VERSION(0.32) } ? 'IO::Socket::IP' :
1075             'IO::Socket::INET';
1076              
1077             sub BUFSIZE () { 32768 } ## no critic
1078              
1079             my $Printable = sub {
1080             local $_ = shift;
1081             s/\r/\\r/g;
1082             s/\n/\\n/g;
1083             s/\t/\\t/g;
1084             s/([^\x20-\x7E])/sprintf('\\x%.2X', ord($1))/ge;
1085             $_;
1086             };
1087              
1088             my $Token = qr/[\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7A\x7C\x7E]/;
1089             my $Field_Content = qr/[[:print:]]+ (?: [\x20\x09]+ [[:print:]]+ )*/x;
1090              
1091             sub new {
1092 177     177   1083549 my ($class, %args) = @_;
1093 177         543 return bless {
1094             rbuf => '',
1095             timeout => 60,
1096             max_line_size => 16384,
1097             max_header_lines => 64,
1098             verify_SSL => HTTP::Tiny::_verify_SSL_default(),
1099             SSL_options => {},
1100             %args
1101             }, $class;
1102             }
1103              
1104             sub timeout {
1105 2     2   28 my ($self, $timeout) = @_;
1106 2 50       5 if ( @_ > 1 ) {
1107 2         4 $self->{timeout} = $timeout;
1108 2 50 33     22 if ( $self->{fh} && $self->{fh}->can('timeout') ) {
1109 0         0 $self->{fh}->timeout($timeout);
1110             }
1111             }
1112 2         3 return $self->{timeout};
1113             }
1114              
1115             sub connect {
1116 32 50   32   78 @_ == 5 || die(q/Usage: $handle->connect(scheme, host, port, peer)/ . "\n");
1117 32         85 my ($self, $scheme, $host, $port, $peer) = @_;
1118              
1119 32 100       92 if ( $scheme eq 'https' ) {
1120 29         105 $self->_assert_ssl;
1121             }
1122              
1123             $self->{fh} = $SOCKET_CLASS->new(
1124             PeerHost => $peer,
1125             PeerPort => $port,
1126             $self->{local_address} ?
1127             ( LocalAddr => $self->{local_address} ) : (),
1128             Proto => 'tcp',
1129             Type => SOCK_STREAM,
1130             Timeout => $self->{timeout},
1131 32 100       414 ) or die(qq/Could not connect to '$host:$port': $@\n/);
    100          
1132              
1133 31         3533196 $self->{fh}->setsockopt(IPPROTO_TCP, TCP_NODELAY, 1);
1134              
1135             binmode($self->{fh})
1136 31 50       616 or die(qq/Could not binmode() socket: '$!'\n/);
1137              
1138 31 50       161 if ( $self->{keep_alive} ) {
1139 31 50       133 unless ( defined( $self->{fh}->setsockopt( SOL_SOCKET, SO_KEEPALIVE, 1 ) ) ) {
1140 0         0 CORE::close($self->{fh});
1141 0         0 die(qq/Could not set SO_KEEPALIVE on socket: '$!'\n/);
1142             }
1143             }
1144              
1145 31 100       613 $self->start_ssl($host) if $scheme eq 'https';
1146              
1147 18         89 $self->{scheme} = $scheme;
1148 18         62 $self->{host} = $host;
1149 18         59 $self->{peer} = $peer;
1150 18         82 $self->{port} = $port;
1151 18         147 $self->{pid} = $$;
1152 18         76 $self->{tid} = _get_tid();
1153              
1154 18         216 return $self;
1155             }
1156              
1157             sub connected {
1158 18     18   43 my ($self) = @_;
1159 18 50 33     197 if ( $self->{fh} && $self->{fh}->connected ) {
1160             return wantarray
1161             ? ( $self->{fh}->peerhost, $self->{fh}->peerport )
1162 18 50       785 : join( ':', $self->{fh}->peerhost, $self->{fh}->peerport );
1163             }
1164 0         0 return;
1165             }
1166              
1167             sub start_ssl {
1168 29     29   124 my ($self, $host) = @_;
1169              
1170             # As this might be used via CONNECT after an SSL session
1171             # to a proxy, we shut down any existing SSL before attempting
1172             # the handshake
1173 29 50       149 if ( ref($self->{fh}) eq 'IO::Socket::SSL' ) {
1174 0 0       0 unless ( $self->{fh}->stop_SSL ) {
1175 0         0 my $ssl_err = IO::Socket::SSL->errstr;
1176 0         0 die(qq/Error halting prior SSL connection: $ssl_err/);
1177             }
1178             }
1179              
1180 29         151 my $ssl_args = $self->_ssl_args($host);
1181             IO::Socket::SSL->start_SSL(
1182             $self->{fh},
1183             %$ssl_args,
1184             SSL_create_ctx_callback => sub {
1185 29     29   1695962 my $ctx = shift;
1186 29         2936 Net::SSLeay::CTX_set_mode($ctx, Net::SSLeay::MODE_AUTO_RETRY());
1187             },
1188 29         786 );
1189              
1190 29 100       3620881 unless ( ref($self->{fh}) eq 'IO::Socket::SSL' ) {
1191 13         90 my $ssl_err = IO::Socket::SSL->errstr;
1192 13         1903 die(qq/SSL connection failed for $host: $ssl_err\n/);
1193             }
1194             }
1195              
1196             sub close {
1197 2 50   2   17 @_ == 1 || die(q/Usage: $handle->close()/ . "\n");
1198 2         7 my ($self) = @_;
1199             CORE::close($self->{fh})
1200 2 50       11 or die(qq/Could not close socket: '$!'\n/);
1201             }
1202              
1203             sub write {
1204 361 50   361   670 @_ == 2 || die(q/Usage: $handle->write(buf)/ . "\n");
1205 361         567 my ($self, $buf) = @_;
1206              
1207 361 50       1394 if ( "$]" >= 5.008 ) {
1208 361 50       864 utf8::downgrade($buf, 1)
1209             or die(qq/Wide character in write()\n/);
1210             }
1211              
1212 361         441 my $len = length $buf;
1213 361         419 my $off = 0;
1214              
1215 361         3352 local $SIG{PIPE} = 'IGNORE';
1216              
1217 361         458 while () {
1218 361 50       831 $self->can_write
1219             or die(qq/Timed out while waiting for socket to become ready for writing\n/);
1220 361         8377 my $r = syswrite($self->{fh}, $buf, $len, $off);
1221 361 50       3445 if (defined $r) {
    0          
    0          
1222 361         435 $len -= $r;
1223 361         442 $off += $r;
1224 361 50       766 last unless $len > 0;
1225             }
1226             elsif ($! == EPIPE) {
1227 0         0 die(qq/Socket closed by remote server: $!\n/);
1228             }
1229             elsif ($! != EINTR) {
1230 0 0       0 if ($self->{fh}->can('errstr')){
1231 0         0 my $err = $self->{fh}->errstr();
1232 0         0 die (qq/Could not write to SSL socket: '$err'\n /);
1233             }
1234             else {
1235 0         0 die(qq/Could not write to socket: '$!'\n/);
1236             }
1237              
1238             }
1239             }
1240 361         2753 return $off;
1241             }
1242              
1243             sub read {
1244 323 50 66 323   777 @_ == 2 || @_ == 3 || die(q/Usage: $handle->read(len [, allow_partial])/ . "\n");
1245 323         470 my ($self, $len, $allow_partial) = @_;
1246              
1247 323         394 my $buf = '';
1248 323         432 my $got = length $self->{rbuf};
1249              
1250 323 100       519 if ($got) {
1251 269 100       405 my $take = ($got < $len) ? $got : $len;
1252 269         546 $buf = substr($self->{rbuf}, 0, $take, '');
1253 269         488 $len -= $take;
1254             }
1255              
1256             # Ignore SIGPIPE because SSL reads can result in writes that might error.
1257             # See "Expecting exactly the same behavior as plain sockets" in
1258             # https://metacpan.org/dist/IO-Socket-SSL/view/lib/IO/Socket/SSL.pod#Common-Usage-Errors
1259 323         2772 local $SIG{PIPE} = 'IGNORE';
1260              
1261 323         616 while ($len > 0) {
1262 911 50       1640 $self->can_read
1263             or die(q/Timed out while waiting for socket to become ready for reading/ . "\n");
1264 911         4119 my $r = sysread($self->{fh}, $buf, $len, length $buf);
1265 911 50       58459 if (defined $r) {
    0          
1266 911 100       1400 last unless $r;
1267 907         1714 $len -= $r;
1268             }
1269             elsif ($! != EINTR) {
1270 0 0       0 if ($self->{fh}->can('errstr')){
1271 0         0 my $err = $self->{fh}->errstr();
1272 0         0 die (qq/Could not read from SSL socket: '$err'\n /);
1273             }
1274             else {
1275 0         0 die(qq/Could not read from socket: '$!'\n/);
1276             }
1277             }
1278             }
1279 323 50 66     559 if ($len && !$allow_partial) {
1280 0         0 die(qq/Unexpected end of stream\n/);
1281             }
1282 323         2411 return $buf;
1283             }
1284              
1285             sub readline {
1286 1081 50   1081   2080 @_ == 1 || die(q/Usage: $handle->readline()/ . "\n");
1287 1081         1384 my ($self) = @_;
1288              
1289 1081         1094 while () {
1290 1287 100       5712 if ($self->{rbuf} =~ s/\A ([^\x0D\x0A]* \x0D?\x0A)//x) {
1291 1081         2582 return $1;
1292             }
1293 206 50       462 if (length $self->{rbuf} >= $self->{max_line_size}) {
1294 0         0 die(qq/Line size exceeds the maximum allowed size of $self->{max_line_size}\n/);
1295             }
1296             $self->can_read
1297 206 50       527 or die(qq/Timed out while waiting for socket to become ready for reading\n/);
1298 206         4427 my $r = sysread($self->{fh}, $self->{rbuf}, BUFSIZE, length $self->{rbuf});
1299 206 50       56504 if (defined $r) {
    0          
1300 206 50       475 last unless $r;
1301             }
1302             elsif ($! != EINTR) {
1303 0 0       0 if ($self->{fh}->can('errstr')){
1304 0         0 my $err = $self->{fh}->errstr();
1305 0         0 die (qq/Could not read from SSL socket: '$err'\n /);
1306             }
1307             else {
1308 0         0 die(qq/Could not read from socket: '$!'\n/);
1309             }
1310             }
1311             }
1312 0         0 die(qq/Unexpected end of stream while looking for line\n/);
1313             }
1314              
1315             sub read_header_lines {
1316 162 50 66 162   464 @_ == 1 || @_ == 2 || die(q/Usage: $handle->read_header_lines([headers])/ . "\n");
1317 162         335 my ($self, $headers) = @_;
1318 162   100     712 $headers ||= {};
1319 162         252 my $lines = 0;
1320 162         206 my $val;
1321              
1322 162         183 while () {
1323 818         1283 my $line = $self->readline;
1324              
1325 818 50       3122 if (++$lines >= $self->{max_header_lines}) {
    100          
    100          
    50          
1326 0         0 die(qq/Header lines exceeds maximum number allowed of $self->{max_header_lines}\n/);
1327             }
1328             elsif ($line =~ /\A ([^\x00-\x1F\x7F:]+) : [\x09\x20]* ([^\x0D\x0A]*)/x) {
1329 653         1270 my ($field_name) = lc $1;
1330 653 100       1051 if (exists $headers->{$field_name}) {
1331 14         33 for ($headers->{$field_name}) {
1332 14 100       51 $_ = [$_] unless ref $_ eq "ARRAY";
1333 14         57 push @$_, $2;
1334 14         36 $val = \$_->[-1];
1335             }
1336             }
1337             else {
1338 639         1892 $val = \($headers->{$field_name} = $2);
1339             }
1340             }
1341             elsif ($line =~ /\A [\x09\x20]+ ([^\x0D\x0A]*)/x) {
1342 3 50       8 $val
1343             or die(qq/Unexpected header continuation line\n/);
1344 3 100       6 next unless length $1;
1345 2 100       4 $$val .= ' ' if length $$val;
1346 2         4 $$val .= $1;
1347             }
1348             elsif ($line =~ /\A \x0D?\x0A \z/x) {
1349 162         256 last;
1350             }
1351             else {
1352 0         0 die(q/Malformed header line: / . $Printable->($line) . "\n");
1353             }
1354             }
1355 162         1265 return $headers;
1356             }
1357              
1358             sub write_request {
1359 18 50   18   68 @_ == 2 || die(q/Usage: $handle->write_request(request)/ . "\n");
1360 18         67 my($self, $request) = @_;
1361 18         42 $self->write_request_header(@{$request}{qw/method uri headers header_case/});
  18         159  
1362 18 50       73 $self->write_body($request) if $request->{cb};
1363 18         31 return;
1364             }
1365              
1366             # Standard request header names/case from HTTP/1.1 RFCs
1367             my @rfc_request_headers = qw(
1368             Accept Accept-Charset Accept-Encoding Accept-Language Authorization
1369             Cache-Control Connection Content-Length Expect From Host
1370             If-Match If-Modified-Since If-None-Match If-Range If-Unmodified-Since
1371             Max-Forwards Pragma Proxy-Authorization Range Referer TE Trailer
1372             Transfer-Encoding Upgrade User-Agent Via
1373             );
1374              
1375             my @other_request_headers = qw(
1376             Content-Encoding Content-MD5 Content-Type Cookie DNT Date Origin
1377             X-XSS-Protection
1378             );
1379              
1380             my %HeaderCase = map { lc($_) => $_ } @rfc_request_headers, @other_request_headers;
1381              
1382             # to avoid multiple small writes and hence nagle, you can pass the method line or anything else to
1383             # combine writes.
1384             sub write_header_lines {
1385 148 50 33 148   866 (@_ >= 2 && @_ <= 4 && ref $_[1] eq 'HASH') || die(q/Usage: $handle->write_header_lines(headers, [header_case, prefix])/ . "\n");
      33        
1386 148         288 my($self, $headers, $header_case, $prefix_data) = @_;
1387 148   100     451 $header_case ||= {};
1388              
1389 148 100       315 my $buf = (defined $prefix_data ? $prefix_data : '');
1390              
1391             # Per RFC, control fields should be listed first
1392 148         209 my %seen;
1393 148         355 for my $k ( qw/host cache-control expect max-forwards pragma range te/ ) {
1394 1035 100       1789 next unless exists $headers->{$k};
1395 143         311 $seen{$k}++;
1396 143         328 my $field_name = $HeaderCase{$k};
1397 143         259 my $v = $headers->{$k};
1398 143 50       332 for (ref $v eq 'ARRAY' ? @$v : $v) {
1399 143 100 66     3564 die(qq/Invalid HTTP header field value ($field_name): / . $Printable->($_). "\n")
1400             unless $_ eq '' || /\A $Field_Content \z/xo;
1401 142 50       341 $_ = '' unless defined $_;
1402 142         342 $buf .= "$field_name: $_\x0D\x0A";
1403             }
1404             }
1405              
1406             # Other headers sent in arbitrary order
1407 147         563 while (my ($k, $v) = each %$headers) {
1408 494         719 my $field_name = lc $k;
1409 494 100       1130 next if $seen{$field_name};
1410 352 100       612 if (exists $HeaderCase{$field_name}) {
1411 340         721 $field_name = $HeaderCase{$field_name};
1412             }
1413             else {
1414 12 100       48 if (exists $header_case->{$field_name}) {
1415 5         9 $field_name = $header_case->{$field_name};
1416             }
1417             else {
1418 7         80 $field_name =~ s/\b(\w)/\u$1/g;
1419             }
1420 12 100       287 $field_name =~ /\A $Token+ \z/xo
1421             or die(q/Invalid HTTP header field name: / . $Printable->($field_name) . "\n");
1422 11         37 $HeaderCase{lc $field_name} = $field_name;
1423             }
1424 351 100       635 for (ref $v eq 'ARRAY' ? @$v : $v) {
1425             # unwrap a field value if pre-wrapped by user
1426 354         497 s/\x0D?\x0A\s+/ /g;
1427 354 100 100     2997 die(qq/Invalid HTTP header field value ($field_name): / . $Printable->($_). "\n")
1428             unless $_ eq '' || /\A $Field_Content \z/xo;
1429 353 50       541 $_ = '' unless defined $_;
1430 353         1006 $buf .= "$field_name: $_\x0D\x0A";
1431             }
1432             }
1433 145         226 $buf .= "\x0D\x0A";
1434 145         448 return $self->write($buf);
1435             }
1436              
1437             # return value indicates whether message length was defined; this is generally
1438             # true unless there was no content-length header and we just read until EOF.
1439             # Other message length errors are thrown as exceptions
1440             sub read_body {
1441 137 50   137   249 @_ == 3 || die(q/Usage: $handle->read_body(callback, response)/ . "\n");
1442 137         219 my ($self, $cb, $response) = @_;
1443 137   100     417 my $te = $response->{headers}{'transfer-encoding'} || '';
1444 137 100       320 my $chunked = grep { /chunked/i } ( ref $te eq 'ARRAY' ? @$te : $te ) ;
  138         420  
1445 137 100       391 return $chunked
1446             ? $self->read_chunked_body($cb, $response)
1447             : $self->read_content_body($cb, $response);
1448             }
1449              
1450             sub write_body {
1451 30 50   30   76 @_ == 2 || die(q/Usage: $handle->write_body(request)/ . "\n");
1452 30         50 my ($self, $request) = @_;
1453 30 100       52 if (exists $request->{headers}{'content-length'}) {
1454 27 100       54 return unless $request->{headers}{'content-length'};
1455 26         59 return $self->write_content_body($request);
1456             }
1457             else {
1458 3         15 return $self->write_chunked_body($request);
1459             }
1460             }
1461              
1462             sub read_content_body {
1463 230 50 66 230   1701 @_ == 3 || @_ == 4 || die(q/Usage: $handle->read_content_body(callback, response, [read_length])/ . "\n");
1464 230         361 my ($self, $cb, $response, $content_length) = @_;
1465 230   100     587 $content_length ||= $response->{headers}{'content-length'};
1466              
1467 230 100       351 if ( defined $content_length ) {
1468 228         286 my $len = $content_length;
1469 228         494 while ($len > 0) {
1470 217 100       372 my $read = ($len > BUFSIZE) ? BUFSIZE : $len;
1471 217         446 $cb->($self->read($read, 0), $response);
1472 216         505 $len -= $read;
1473             }
1474 227         874 return length($self->{rbuf}) == 0;
1475             }
1476              
1477 2         4 my $chunk;
1478 2         6 $cb->($chunk, $response) while length( $chunk = $self->read(BUFSIZE, 1) );
1479              
1480 2         9 return;
1481             }
1482              
1483             sub write_content_body {
1484 27 50   27   58 @_ == 2 || die(q/Usage: $handle->write_content_body(request)/ . "\n");
1485 27         36 my ($self, $request) = @_;
1486              
1487 27         51 my ($len, $content_length) = (0, $request->{headers}{'content-length'});
1488 27         26 while () {
1489 181         372 my $data = $request->{cb}->();
1490              
1491 181 100 100     715 defined $data && length $data
1492             or last;
1493              
1494 154 50       514 if ( "$]" >= 5.008 ) {
1495 154 50       333 utf8::downgrade($data, 1)
1496             or die(qq/Wide character in write_content()\n/);
1497             }
1498              
1499 154         265 $len += $self->write($data);
1500             }
1501              
1502 27 50       49 $len == $content_length
1503             or die(qq/Content-Length mismatch (got: $len expected: $content_length)\n/);
1504              
1505 27         49 return $len;
1506             }
1507              
1508             sub read_chunked_body {
1509 12 50   12   122 @_ == 3 || die(q/Usage: $handle->read_chunked_body(callback, $response)/ . "\n");
1510 12         31 my ($self, $cb, $response) = @_;
1511              
1512 12         18 while () {
1513 114         232 my $head = $self->readline;
1514              
1515 114 50       381 $head =~ /\A ([A-Fa-f0-9]+)/x
1516             or die(q/Malformed chunk head: / . $Printable->($head) . "\n");
1517              
1518 114 100       270 my $len = hex($1)
1519             or last;
1520              
1521 102         220 $self->read_content_body($cb, $response, $len);
1522              
1523 102 50       182 $self->read(2) eq "\x0D\x0A"
1524             or die(qq/Malformed chunk: missing CRLF after chunk data\n/);
1525             }
1526 12         60 $self->read_header_lines($response->{headers});
1527 12         88 return 1;
1528             }
1529              
1530             sub write_chunked_body {
1531 5 50   5   72 @_ == 2 || die(q/Usage: $handle->write_chunked_body(request)/ . "\n");
1532 5         10 my ($self, $request) = @_;
1533              
1534 5         6 my $len = 0;
1535 5         8 while () {
1536 59         173 my $data = $request->{cb}->();
1537              
1538 59 100 100     198 defined $data && length $data
1539             or last;
1540              
1541 54 50       191 if ( "$]" >= 5.008 ) {
1542 54 50       82 utf8::downgrade($data, 1)
1543             or die(qq/Wide character in write_chunked_body()\n/);
1544             }
1545              
1546 54         52 $len += length $data;
1547              
1548 54         78 my $chunk = sprintf '%X', length $data;
1549 54         52 $chunk .= "\x0D\x0A";
1550 54         53 $chunk .= $data;
1551 54         62 $chunk .= "\x0D\x0A";
1552              
1553 54         67 $self->write($chunk);
1554             }
1555 5         15 $self->write("0\x0D\x0A");
1556 5 100       16 if ( ref $request->{trailer_cb} eq 'CODE' ) {
1557 2         15 $self->write_header_lines($request->{trailer_cb}->())
1558             }
1559             else {
1560 3         9 $self->write("\x0D\x0A");
1561             }
1562 5         23 return $len;
1563             }
1564              
1565             sub read_response_header {
1566 149 50   149   374 @_ == 1 || die(q/Usage: $handle->read_response_header()/ . "\n");
1567 149         278 my ($self) = @_;
1568              
1569 149         342 my $line = $self->readline;
1570              
1571 149 100       966 $line =~ /\A (HTTP\/(0*\d+\.0*\d+)) [\x09\x20]+ ([0-9]{3}) (?: [\x09\x20]+ ([^\x0D\x0A]*) )? \x0D?\x0A/x
1572             or die(q/Malformed Status-Line: / . $Printable->($line). "\n");
1573              
1574 147         847 my ($protocol, $version, $status, $reason) = ($1, $2, $3, $4);
1575 147 100       293 $reason = "" unless defined $reason;
1576              
1577 147 100       707 die (qq/Unsupported HTTP protocol: $protocol\n/)
1578             unless $version =~ /0*1\.0*[01]/;
1579              
1580             return {
1581 145         470 status => $status,
1582             reason => $reason,
1583             headers => $self->read_header_lines,
1584             protocol => $protocol,
1585             };
1586             }
1587              
1588             sub write_request_header {
1589 147 50   147   352 @_ == 5 || die(q/Usage: $handle->write_request_header(method, request_uri, headers, header_case)/ . "\n");
1590 147         327 my ($self, $method, $request_uri, $headers, $header_case) = @_;
1591              
1592 147 100       559 die (q/Invalid characters in Request-URI /. $Printable->($request_uri). "\n")
1593             if $request_uri =~ /[\x00-\x20\x7F]/;
1594              
1595 145 100       315 die (q/Invalid characters in Method /. $Printable->($method). "\n")
1596             if $method =~ /[\x00-\x20\x7F]/;
1597              
1598 142         522 return $self->write_header_lines($headers, $header_case, "$method $request_uri HTTP/1.1\x0D\x0A");
1599             }
1600              
1601             sub _do_timeout {
1602 940     940   1608 my ($self, $type, $timeout) = @_;
1603             $timeout = $self->{timeout}
1604 940 50 33     1878 unless defined $timeout && $timeout >= 0;
1605              
1606 940         2123 my $fd = fileno $self->{fh};
1607 940 50 33     8776 defined $fd && $fd >= 0
1608             or die(qq/select(2): 'Bad file descriptor'\n/);
1609              
1610 940         1081 my $initial = time;
1611 940         1042 my $pending = $timeout;
1612 940         969 my $nfound;
1613              
1614 940         2600 vec(my $fdset = '', $fd, 1) = 1;
1615              
1616 940         1271 while () {
1617 940 100       1156976 $nfound = ($type eq 'read')
1618             ? select($fdset, undef, undef, $pending)
1619             : select(undef, $fdset, undef, $pending) ;
1620 940 50       1720 if ($nfound == -1) {
1621 0 0       0 $! == EINTR
1622             or die(qq/select(2): '$!'\n/);
1623 0 0 0     0 redo if !$timeout || ($pending = $timeout - (time - $initial)) > 0;
1624 0         0 $nfound = 0;
1625             }
1626 940         1019 last;
1627             }
1628 940         1468 $! = 0;
1629 940         2165 return $nfound;
1630             }
1631              
1632             sub can_read {
1633 973 50 33 973   1689 @_ == 1 || @_ == 2 || die(q/Usage: $handle->can_read([timeout])/ . "\n");
1634 973         1069 my $self = shift;
1635 973 100       1949 if ( ref($self->{fh}) eq 'IO::Socket::SSL' ) {
1636 932 100       1830 return 1 if $self->{fh}->pending;
1637             }
1638 922         8713 return $self->_do_timeout('read', @_)
1639             }
1640              
1641             sub can_write {
1642 18 50 33 18   55 @_ == 1 || @_ == 2 || die(q/Usage: $handle->can_write([timeout])/ . "\n");
1643 18         29 my $self = shift;
1644 18         71 return $self->_do_timeout('write', @_)
1645             }
1646              
1647             sub _has_keep_alive_expired {
1648 13     13   16 my $self = shift;
1649 13 50       44 return unless $self->{keep_alive_timeout} > 0;
1650 0         0 my $now = Time::HiRes::time();
1651 0   0     0 return $now - ($self->{last_used} || $now) > $self->{keep_alive_timeout};
1652             }
1653              
1654             sub _update_last_used {
1655 43     43   63 my $self = shift;
1656 43 50       103 return unless $self->{keep_alive_timeout} > 0;
1657 0         0 $self->{last_used} = Time::HiRes::time();
1658             }
1659              
1660             sub _assert_ssl {
1661 29     29   110 my($ok, $reason) = HTTP::Tiny->can_ssl();
1662 29 50       116 die $reason unless $ok;
1663             }
1664              
1665             sub can_reuse {
1666 16     16   27 my ($self,$scheme,$host,$port,$peer) = @_;
1667             return 0 if
1668             $self->{pid} != $$
1669             || $self->{tid} != _get_tid()
1670             || length($self->{rbuf})
1671             || $scheme ne $self->{scheme}
1672             || $host ne $self->{host}
1673             || $port ne $self->{port}
1674             || $peer ne $self->{peer}
1675             || $self->_has_keep_alive_expired()
1676 16 100 33     117 || eval { $self->can_read(0) }
  13   33     27  
      66        
      100        
      100        
      66        
      66        
      66        
      66        
1677             || $@ ;
1678 5         36 return 1;
1679             }
1680              
1681             sub _find_CA {
1682 27     27   65 my $self = shift;
1683              
1684 27         90 my $ca_file = $self->{SSL_options}->{SSL_ca_file};
1685              
1686 27 100       96 if ( defined $ca_file ) {
1687 4 100       215 unless ( -r $ca_file ) {
1688 1         11 die qq/SSL_ca_file '$ca_file' not found or not readable\n/;
1689             }
1690 3         42 return ( SSL_ca_file => $ca_file );
1691             }
1692              
1693             # Return default_ca() parameters from IO::Socket::SSL. It looks for the
1694             # default bundle and directory from Net::SSLeay, handles $ENV{SSL_CERT_FILE}
1695             # and $ENV{SSL_CERT_DIR}, and finally fails over to Mozilla::CA
1696             #
1697 23         163 my %default_ca = IO::Socket::SSL::default_ca();
1698 23 50       3123 return %default_ca if %default_ca;
1699              
1700             # If IO::Socket::SSL::default_ca() was unable to find a CA bundle, look for
1701             # one in well known locations as a last resort. Cert list copied from golang
1702             # src/crypto/x509/root_unix.go
1703             #
1704 0         0 foreach my $ca_bundle (
1705             "/etc/ssl/certs/ca-certificates.crt", # Debian/Ubuntu/Gentoo etc.
1706             "/etc/pki/tls/certs/ca-bundle.crt", # Fedora/RHEL
1707             "/etc/ssl/ca-bundle.pem", # OpenSUSE
1708             "/etc/openssl/certs/ca-certificates.crt", # NetBSD
1709             "/etc/ssl/cert.pem", # OpenBSD
1710             "/usr/local/share/certs/ca-root-nss.crt", # FreeBSD/DragonFly
1711             "/etc/pki/tls/cacert.pem", # OpenELEC
1712             "/etc/certs/ca-certificates.crt", # Solaris 11.2+
1713             ) {
1714 0 0       0 return ( SSL_ca_file => $ca_bundle ) if -e $ca_bundle;
1715             }
1716              
1717 0         0 die qq/Couldn't find a CA bundle with which to verify the SSL certificate.\n/
1718             . qq/Try installing one from your OS vendor, or Mozilla::CA from CPAN\n/;
1719             }
1720              
1721             # not for internal use; backcompat shim only
1722             sub _find_CA_file {
1723 1     1   1298 my $self = shift;
1724 1         5 my %res = $self->_find_CA();
1725 1         7 return $res{SSL_ca_file};
1726             }
1727              
1728             # for thread safety, we need to know thread id if threads are loaded
1729             sub _get_tid {
1730 31     31   313 no warnings 'reserved'; # for 'threads'
  31         49  
  31         11141  
1731 154 50   154   3358 return threads->can("tid") ? threads->tid : 0;
1732             }
1733              
1734             sub _ssl_args {
1735 29     29   73 my ($self, $host) = @_;
1736              
1737 29         52 my %ssl_args;
1738              
1739             # This test reimplements IO::Socket::SSL::can_client_sni(), which wasn't
1740             # added until IO::Socket::SSL 1.84
1741 29 50       1901 if ( Net::SSLeay::OPENSSL_VERSION_NUMBER() >= 0x01000000 ) {
1742 29         265 $ssl_args{SSL_hostname} = $host, # Sane SNI support
1743             }
1744              
1745 29 100       183 if ($self->{verify_SSL}) {
1746 22         68 $ssl_args{SSL_verifycn_scheme} = 'http'; # enable CN validation
1747 22         74 $ssl_args{SSL_verifycn_name} = $host; # set validation hostname
1748 22         56 $ssl_args{SSL_verify_mode} = 0x01; # enable cert validation
1749              
1750 22         129 %ssl_args = ( %ssl_args, $self->_find_CA );
1751             }
1752             else {
1753 7         28 $ssl_args{SSL_verifycn_scheme} = 'none'; # disable CN validation
1754 7         24 $ssl_args{SSL_verify_mode} = 0x00; # disable cert validation
1755             }
1756              
1757             # user options override settings from verify_SSL
1758 29         90 for my $k ( keys %{$self->{SSL_options}} ) {
  29         174  
1759 9 50       44 $ssl_args{$k} = $self->{SSL_options}{$k} if $k =~ m/^SSL_/;
1760             }
1761              
1762 29         205 return \%ssl_args;
1763             }
1764              
1765             1;
1766              
1767             __END__