File Coverage

blib/lib/HTTP/Tiny.pm
Criterion Covered Total %
statement 612 689 88.8
branch 331 478 69.2
condition 191 293 65.1
subroutine 76 81 93.8
pod 13 15 86.6
total 1223 1556 78.6


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