File Coverage

blib/lib/Furl/HTTP.pm
Criterion Covered Total %
statement 311 498 62.4
branch 138 292 47.2
condition 45 97 46.3
subroutine 37 56 66.0
pod 9 18 50.0
total 540 961 56.1


line stmt bran cond sub pod time code
1             package Furl::HTTP;
2 45     45   547152 use strict;
  45         321  
  45         1288  
3 45     45   220 use warnings;
  45         80  
  45         1243  
4 45     45   211 use base qw/Exporter/;
  45         81  
  45         3374  
5 45     45   1368 use 5.008001;
  45         150  
6              
7             our $VERSION = '3.14';
8              
9 45     45   295 use Carp ();
  45         80  
  45         998  
10 45     45   18297 use Furl::ConnectionCache;
  45         136  
  45         1476  
11              
12 45     45   287 use Scalar::Util ();
  45         82  
  45         938  
13 45     45   19883 use Errno qw(EAGAIN ECONNRESET EINPROGRESS EINTR EWOULDBLOCK ECONNABORTED EISCONN);
  45         62358  
  45         5752  
14 45     45   336 use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK SEEK_SET SEEK_END);
  45         90  
  45         3001  
15 45         8694 use Socket qw(
16             PF_INET SOCK_STREAM
17             IPPROTO_TCP
18             TCP_NODELAY
19             pack_sockaddr_in
20 45     45   26884 );
  45         232208  
21 45     45   25329 use Time::HiRes qw(time);
  45         53823  
  45         195  
22              
23 45     45   9650 use constant WIN32 => $^O eq 'MSWin32';
  45         99  
  45         4968  
24 45     45   22714 use HTTP::Parser::XS qw/HEADERS_NONE HEADERS_AS_ARRAYREF HEADERS_AS_HASHREF/;
  45         36586  
  45         285769  
25              
26             our @EXPORT_OK = qw/HEADERS_NONE HEADERS_AS_ARRAYREF HEADERS_AS_HASHREF/;
27              
28              
29             # ref. RFC 2616, 3.5 Content Codings:
30             # For compatibility with previous implementations of HTTP,
31             # applications SHOULD consider "x-gzip" and "x-compress" to be
32             # equivalent to "gzip" and "compress" respectively.
33             # ("compress" is not supported, though)
34             my %COMPRESSED = map { $_ => undef } qw(gzip x-gzip deflate);
35              
36             my $HTTP_TOKEN = '[^\x00-\x31\x7F]+';
37             my $HTTP_QUOTED_STRING = q{"([^"]+|\\.)*"};
38              
39             sub new {
40 32     32 1 154690 my $class = shift;
41 32 50       936 my %args = @_ == 1 ? %{$_[0]} : @_;
  0         0  
42              
43             my @headers = (
44 32   66     1142 'User-Agent' => (delete($args{agent}) || __PACKAGE__ . '/' . $Furl::HTTP::VERSION),
45             );
46 32         269 my $connection_header = 'keep-alive';
47 32 50       329 if(defined $args{headers}) {
48 0         0 my $in_headers = delete $args{headers};
49 0         0 for (my $i = 0; $i < @$in_headers; $i += 2) {
50 0         0 my $name = $in_headers->[$i];
51 0 0       0 if (lc($name) eq 'connection') {
52 0         0 $connection_header = $in_headers->[$i + 1];
53             } else {
54 0         0 push @headers, $name, $in_headers->[$i + 1];
55             }
56             }
57             }
58             bless {
59             timeout => 10,
60             max_redirects => 7,
61             bufsize => 10*1024, # no mmap
62             headers => \@headers,
63             connection_header => $connection_header,
64             proxy => '',
65             no_proxy => '',
66             connection_pool => Furl::ConnectionCache->new(),
67             header_format => HEADERS_AS_ARRAYREF,
68       0     stop_if => sub {},
69 36     36   32186 inet_aton => sub { Socket::inet_aton($_[0]) },
70             ssl_opts => {},
71 32   100     1003 capture_request => $args{capture_request} || 0,
72             inactivity_timeout => 600,
73             %args
74             }, $class;
75             }
76              
77             sub get {
78 0     0 1 0 my ( $self, $url, $headers ) = @_;
79 0         0 $self->request(
80             method => 'GET',
81             url => $url,
82             headers => $headers
83             );
84             }
85              
86             sub head {
87 0     0 1 0 my ( $self, $url, $headers ) = @_;
88 0         0 $self->request(
89             method => 'HEAD',
90             url => $url,
91             headers => $headers
92             );
93             }
94              
95             sub post {
96 0     0 1 0 my ( $self, $url, $headers, $content ) = @_;
97 0         0 $self->request(
98             method => 'POST',
99             url => $url,
100             headers => $headers,
101             content => $content
102             );
103             }
104              
105             sub put {
106 0     0 1 0 my ( $self, $url, $headers, $content ) = @_;
107 0         0 $self->request(
108             method => 'PUT',
109             url => $url,
110             headers => $headers,
111             content => $content
112             );
113             }
114              
115             sub delete {
116 0     0 1 0 my ( $self, $url, $headers, $content ) = @_;
117 0         0 $self->request(
118             method => 'DELETE',
119             url => $url,
120             headers => $headers,
121             content => $content
122             );
123             }
124              
125             sub agent {
126 5 100   5 1 37 if ( @_ == 2 ) {
127 3         22 _header_set(shift->{headers}, 'User-Agent', shift);
128             } else {
129 2         11 return _header_get(shift->{headers}, 'User-Agent');
130             }
131             }
132              
133             sub _header_set {
134 3     3   37 my ($headers, $key, $value) = (shift, lc shift, shift);
135 3         18 for (my $i=0; $i<@$headers; $i+=2) {
136 3 50       21 if (lc($headers->[$i]) eq $key) {
137 3         11 $headers->[$i+1] = $value;
138 3         21 return;
139             }
140             }
141 0         0 push @$headers, $key, $value;
142             }
143              
144             sub _header_get {
145 23     23   35258 my ($headers, $key) = (shift, lc shift);
146 23         145 for (my $i=0; $i<@$headers; $i+=2) {
147 29 100       194 return $headers->[$i+1] if lc($headers->[$i]) eq $key;
148             }
149 3         8 return undef;
150             }
151              
152             sub _requires {
153 12     12   28 my($file, $feature, $library) = @_;
154 12 100       53 return if exists $INC{$file};
155 1 50       7 unless(eval { require $file }) {
  1         1009  
156 0 0       0 if ($@ =~ /^Can't locate/) {
157 0   0     0 $library ||= do {
158 0         0 local $_ = $file;
159 0         0 s/ \.pm \z//xms;
160 0         0 s{/}{::}g;
161 0         0 $_;
162             };
163 0         0 Carp::croak(
164             "$feature requires $library, but it is not available."
165             . " Please install $library using your prefer CPAN client"
166             );
167             } else {
168 0         0 die $@;
169             }
170             }
171             }
172              
173             # returns $scheme, $host, $port, $path_query
174             sub _parse_url {
175 35     35   5692 my($self, $url) = @_;
176 35 100       623 $url =~ m{\A
177             ([a-z]+) # scheme
178             ://
179             (?:
180             ([^/:@?]+) # user
181             :
182             ([^/:@?]+) # password
183             @
184             )?
185             ([^/:?]+) # host
186             (?: : (\d+) )? # port
187             (?: ( /? \? .* | / .*) )? # path_query
188             \z}xms or Carp::croak("Passed malformed URL: $url");
189 34         437 return( $1, $2, $3, $4, $5, $6 );
190             }
191              
192             sub make_x_www_form_urlencoded {
193 0     0 0 0 my($self, $content) = @_;
194 0         0 my @params;
195 0         0 my @p = ref($content) eq 'HASH' ? %{$content}
196 0 0       0 : ref($content) eq 'ARRAY' ? @{$content}
  0 0       0  
197             : Carp::croak("Cannot coerce $content to x-www-form-urlencoded");
198 0         0 while ( my ( $k, $v ) = splice @p, 0, 2 ) {
199 0         0 foreach my $s($k, $v) {
200 0         0 utf8::downgrade($s); # will die in wide characters
201             # escape unsafe chars (defined by RFC 3986)
202 0         0 $s =~ s/ ([^A-Za-z0-9\-\._~]) / sprintf '%%%02X', ord $1 /xmsge;
  0         0  
203             }
204 0         0 push @params, "$k=$v";
205             }
206 0         0 return join( "&", @params );
207             }
208              
209             sub env_proxy {
210 8     8 1 13 my $self = shift;
211             # Under CGI, bypass HTTP_PROXY as request sets it from Proxy header
212             # Note: This doesn't work on windows correctly.
213 8 100       21 local $ENV{HTTP_PROXY} if $ENV{REQUEST_METHOD};
214 8   66     31 $self->{proxy} = $ENV{http_proxy} || $ENV{HTTP_PROXY} || $self->{proxy};
215 8   50     21 $self->{no_proxy} = $ENV{NO_PROXY} || '';
216 8         19 $self;
217             }
218              
219             sub request {
220 67     67 1 20069708 my $self = shift;
221 67         688 my %args = @_;
222              
223 67         722 my $timeout_at = time + $self->{timeout};
224              
225 67         242 my ($scheme, $username, $password, $host, $port, $path_query);
226 67 100       317 if (defined(my $url = $args{url})) {
227 23         121 ($scheme, $username, $password, $host, $port, $path_query) = $self->_parse_url($url);
228             }
229             else {
230 44         260 ($scheme, $host, $port, $path_query) = @args{qw/scheme host port path_query/};
231 44 50       262 if (not defined $host) {
232 0         0 Carp::croak("Missing host name in arguments");
233             }
234             }
235              
236 67 100 66     377 if (not defined $scheme) {
    100          
237 44         227 $scheme = 'http';
238             } elsif($scheme ne 'http' && $scheme ne 'https') {
239 6         511 Carp::croak("Unsupported scheme: $scheme");
240             }
241              
242 61 50       301 my $default_port = $scheme eq 'http'
243             ? 80
244             : 443;
245 61 100       280 if(not defined $port) {
246 1         2 $port = $default_port;
247             }
248 61 100       219 if(not defined $path_query) {
249 13         42 $path_query = '/';
250             }
251              
252 61 100       524 unless (substr($path_query, 0, 1) eq '/') {
253 3         30 $path_query = "/$path_query"; # Compensate for slash (?foo=bar => /?foo=bar)
254             }
255              
256             # Note. '_' is a invalid character for URI, but some servers using fucking underscore for domain name. Then, I accept the '_' character for domain name.
257 61 50       533 if ($host =~ /[^A-Za-z0-9._-]/) {
258 0         0 _requires('Net/IDN/Encode.pm',
259             'Internationalized Domain Name (IDN)');
260 0         0 $host = Net::IDN::Encode::domain_to_ascii($host);
261             }
262              
263 61         280 my $proxy = $self->{proxy};
264 61         181 my $no_proxy = $self->{no_proxy};
265 61 50 33     321 if ($proxy && $no_proxy) {
266 0 0       0 if ($self->match_no_proxy($no_proxy, $host)) {
267 0         0 undef $proxy;
268             }
269             }
270              
271 61         1497 local $SIG{PIPE} = 'IGNORE';
272 61         599 my $sock = $self->{connection_pool}->steal($host, $port);
273 61         149 my $in_keepalive;
274 61 100       199 if (defined $sock) {
275 26 100       118 if ($self->_do_select(0, $sock, 0)) {
276 2         117 close $sock;
277 2         13 undef $sock;
278             } else {
279 24         53 $in_keepalive = 1;
280             }
281             }
282 61 100       255 if(!$in_keepalive) {
283 37         70 my $err_reason;
284 37 50       152 if ($proxy) {
285 0         0 my (undef, $proxy_user, $proxy_pass, $proxy_host, $proxy_port, undef)
286             = $self->_parse_url($proxy);
287 0         0 my $proxy_authorization;
288 0 0       0 if (defined $proxy_user) {
289 0         0 _requires('URI/Escape.pm',
290             'Basic auth');
291 0         0 my($unescape_proxy_user) = URI::Escape::uri_unescape($proxy_user);
292 0         0 my($unescape_proxy_pass) = URI::Escape::uri_unescape($proxy_pass);
293 0         0 _requires('MIME/Base64.pm',
294             'Basic auth');
295 0         0 $proxy_authorization = 'Basic ' . MIME::Base64::encode_base64("$unescape_proxy_user:$unescape_proxy_pass","");
296             }
297 0 0       0 if ($scheme eq 'http') {
298 0         0 ($sock, $err_reason)
299             = $self->connect($proxy_host, $proxy_port, $timeout_at);
300 0 0       0 if (defined $proxy_authorization) {
301 0         0 $self->{proxy_authorization} = $proxy_authorization;
302             }
303             } else {
304 0         0 ($sock, $err_reason) = $self->connect_ssl_over_proxy(
305             $proxy_host, $proxy_port, $host, $port, $timeout_at, $proxy_authorization);
306             }
307             } else {
308 37 50       124 if ($scheme eq 'http') {
309 37         456 ($sock, $err_reason)
310             = $self->connect($host, $port, $timeout_at);
311             } else {
312 0         0 ($sock, $err_reason)
313             = $self->connect_ssl($host, $port, $timeout_at);
314             }
315             }
316 37 100       149 return $self->_r500($err_reason)
317             unless $sock;
318             }
319              
320             # keep request dump
321 60         427 my ($req_headers, $req_content) = ("", "");
322              
323             # write request
324 60   100     465 my $method = $args{method} || 'GET';
325 60         154 my $connection_header = $self->{connection_header};
326 60         145 my $cookie_jar = $self->{cookie_jar};
327             {
328 60         98 my @headers = @{$self->{headers}};
  60         101  
  60         231  
329 60 100       235 $connection_header = 'close'
330             if $method eq 'HEAD';
331 60 100       253 if (my $in_headers = $args{headers}) {
332 14         48 for (my $i = 0; $i < @$in_headers; $i += 2) {
333 18         38 my $name = $in_headers->[$i];
334 18 50       48 if (lc($name) eq 'connection') {
335 0         0 $connection_header = $in_headers->[$i + 1];
336             } else {
337 18         81 push @headers, $name, $in_headers->[$i + 1];
338             }
339             }
340             }
341 60         234 unshift @headers, 'Connection', $connection_header;
342 60 50       244 if (exists $self->{proxy_authorization}) {
343 0         0 push @headers, 'Proxy-Authorization', $self->{proxy_authorization};
344             }
345 60 100       211 if (defined $username) {
346 6         23 _requires('URI/Escape.pm', 'Basic auth');
347 6         45 my($unescape_username) = URI::Escape::uri_unescape($username);
348 6         145 my($unescape_password) = URI::Escape::uri_unescape($password);
349 6         149 _requires('MIME/Base64.pm', 'Basic auth');
350 6         1235 push @headers, 'Authorization', 'Basic ' . MIME::Base64::encode_base64("${unescape_username}:${unescape_password}","");
351             }
352              
353             # set Cookie header
354 60 50       209 if (defined $cookie_jar) {
355 0         0 my $url;
356 0 0       0 if ($args{url}) {
357 0         0 $url = $args{url};
358             } else {
359             $url = join(
360             '',
361             $args{scheme},
362             '://',
363             $args{host},
364             (exists($args{port}) ? ":$args{port}" : ()),
365 0 0       0 exists($args{path_query}) ? $args{path_query} : '/',
    0          
366             );
367             }
368 0         0 push @headers, 'Cookie' => $cookie_jar->cookie_header($url);
369             }
370              
371 60         299 my $content = $args{content};
372 60         223 my $content_is_fh = 0;
373 60 100       204 if(defined $content) {
374 3         13 $content_is_fh = Scalar::Util::openhandle($content);
375 3 50 33     38 if(!$content_is_fh && ref $content) {
376 0         0 $content = $self->make_x_www_form_urlencoded($content);
377 0 0       0 if(!defined _header_get(\@headers, 'Content-Type')) {
378 0         0 push @headers, 'Content-Type'
379             => 'application/x-www-form-urlencoded';
380             }
381             }
382 3 50       106 if(!defined _header_get(\@headers, 'Content-Length')) {
383 3         6 my $content_length;
384 3 50       8 if($content_is_fh) {
385             my $assert = sub {
386 0 0   0   0 $_[0] or Carp::croak(
387             "Failed to $_[1] for Content-Length: $!",
388             );
389 0         0 };
390 0         0 $assert->(defined(my $cur_pos = tell($content)), 'tell');
391 0         0 $assert->(seek($content, 0, SEEK_END), 'seek');
392 0         0 $assert->(defined(my $end_pos = tell($content)), 'tell');
393 0         0 $assert->(seek($content, $cur_pos, SEEK_SET), 'seek');
394              
395 0         0 $content_length = $end_pos - $cur_pos;
396             }
397             else {
398 3         7 $content_length = length($content);
399             }
400 3         18 push @headers, 'Content-Length' => $content_length;
401             }
402             }
403              
404             # finally, set Host header
405 60 100       375 my $request_target = ($port == $default_port) ? $host : "$host:$port";
406 60         448 push @headers, 'Host' => $request_target;
407              
408 60 50 33     484 my $request_uri = $proxy && $scheme eq 'http' ? "$scheme://$request_target$path_query" : $path_query;
409              
410 60         308 my $p = "$method $request_uri HTTP/1.1\015\012";
411 60         394 for (my $i = 0; $i < @headers; $i += 2) {
412 207         410 my $val = $headers[ $i + 1 ];
413             # the de facto standard way to handle [\015\012](by kazuho-san)
414 207         386 $val =~ tr/\015\012/ /;
415 207         599 $p .= "$headers[$i]: $val\015\012";
416             }
417 60         154 $p .= "\015\012";
418 60 50       215 $self->write_all($sock, $p, $timeout_at)
419             or return $self->_r500(
420             "Failed to send HTTP request: " . _strerror_or_timeout());
421              
422 60 100       244 if ($self->{capture_request}) {
423 1         2 $req_headers = $p;
424             }
425              
426 60 100       301 if (defined $content) {
427 3 50       8 if ($content_is_fh) {
428 0         0 my $ret;
429             my $buf;
430 0         0 SENDFILE: while (1) {
431 0         0 $ret = read($content, $buf, $self->{bufsize});
432 0 0       0 if (not defined $ret) {
    0          
433 0         0 Carp::croak("Failed to read request content: $!");
434             } elsif ($ret == 0) { # EOF
435 0         0 last SENDFILE;
436             }
437 0 0       0 $self->write_all($sock, $buf, $timeout_at)
438             or return $self->_r500(
439             "Failed to send content: " . _strerror_or_timeout()
440             );
441              
442 0 0       0 if ($self->{capture_request}) {
443 0         0 $req_content .= $buf;
444             }
445             }
446             } else { # simple string
447 3 50       16 if (length($content) > 0) {
448 0 0       0 $self->write_all($sock, $content, $timeout_at)
449             or return $self->_r500(
450             "Failed to send content: " . _strerror_or_timeout()
451             );
452              
453 0 0       0 if ($self->{capture_request}) {
454 0         0 $req_content = $content;
455             }
456             }
457             }
458             }
459             }
460              
461             # read response
462 60         276 my $buf = '';
463 60         300 my $rest_header;
464             my $res_minor_version;
465 60         0 my $res_status;
466 60         0 my $res_msg;
467 60         0 my $res_headers;
468 60   50     481 my $special_headers = $args{special_headers} || +{};
469 60         264 $special_headers->{'connection'} = '';
470 60         140 $special_headers->{'content-length'} = undef;
471 60         166 $special_headers->{'location'} = '';
472 60         177 $special_headers->{'content-encoding'} = '';
473 60         135 $special_headers->{'transfer-encoding'} = '';
474 60         91 LOOP: while (1) {
475             my $n = $self->read_timeout($sock,
476 212         746 \$buf, $self->{bufsize}, length($buf), $timeout_at);
477 212 100       798 if(!$n) { # error or eof
478 3 50 33     69 if ($in_keepalive && length($buf) == 0
      50        
      33        
479             && (defined($n) || $!==ECONNRESET || (WIN32 && $! == ECONNABORTED))) {
480             # the server closes the connection (maybe because of keep-alive timeout)
481 0         0 return $self->request(%args);
482             }
483 3 50       25 return $self->_r500(
484             !defined($n)
485             ? "Cannot read response header: " . _strerror_or_timeout()
486             : "Unexpected EOF while reading response header"
487             );
488             }
489             else {
490 209         278 my $ret;
491             ( $ret, $res_minor_version, $res_status, $res_msg, $res_headers )
492             = HTTP::Parser::XS::parse_http_response( $buf,
493 209         1786 $self->{header_format}, $special_headers );
494 209 50       681 if ( $ret == -1 ) {
    100          
495 0         0 return $self->_r500("Invalid HTTP response");
496             }
497             elsif ( $ret == -2 ) {
498             # partial response
499 147         332 next LOOP;
500             }
501             else {
502             # succeeded
503 62         189 $rest_header = substr( $buf, $ret );
504 62 100       355 if ((int $res_status / 100) eq 1) { # Continue
505             # The origin server must not wait for the request body
506             # before sending the 100 (Continue) response.
507             # see http://greenbytes.de/tech/webdav/rfc2616.html#status.100
508 5         10 $buf = $rest_header;
509 5         9 next LOOP;
510             }
511 57         142 last LOOP;
512             }
513             }
514             }
515              
516 57         99 my $max_redirects = 0;
517 57         120 my $do_redirect = undef;
518 57 50       197 if ($special_headers->{location}) {
519 0 0       0 $max_redirects = defined($args{max_redirects}) ? $args{max_redirects} : $self->{max_redirects};
520 0   0     0 $do_redirect = $max_redirects && $res_status =~ /^30[12378]$/;
521             }
522              
523 57         145 my $res_content = '';
524 57 50       184 unless ($do_redirect) {
525 57 50       328 if (my $fh = $args{write_file}) {
    50          
526 0         0 $res_content = Furl::FileStream->new( $fh );
527             } elsif (my $coderef = $args{write_code}) {
528             $res_content = Furl::CallbackStream->new(
529 0     0   0 sub { $coderef->($res_status, $res_msg, $res_headers, @_) }
530 0         0 );
531             }
532             }
533              
534 57 50       224 if (exists $COMPRESSED{ $special_headers->{'content-encoding'} }) {
535 0         0 _requires('Furl/ZlibStream.pm', 'Content-Encoding', 'Compress::Raw::Zlib');
536              
537 0         0 $res_content = Furl::ZlibStream->new($res_content);
538             }
539              
540 57         153 my $chunked = ($special_headers->{'transfer-encoding'} eq 'chunked');
541 57         118 my $content_length = $special_headers->{'content-length'};
542 57 100 100     944 if (defined($content_length) && $content_length !~ /\A[0-9]+\z/) {
543 1         5 return $self->_r500("Bad Content-Length: ${content_length}");
544             }
545              
546 56 100 33     1010 unless ($method eq 'HEAD'
      66        
      66        
      100        
547             || ($res_status < 200 && $res_status >= 100)
548             || $res_status == 204
549             || $res_status == 304) {
550 49         116 my @err;
551 49 100       139 if ( $chunked ) {
552 7         45 @err = $self->_read_body_chunked($sock,
553             \$res_content, $rest_header, $timeout_at);
554             } else {
555 42         112 $res_content .= $rest_header;
556 42 100 66     217 if (ref $res_content || !defined($content_length)) {
557 1         19 @err = $self->_read_body_normal($sock,
558             \$res_content, length($rest_header),
559             $content_length, $timeout_at);
560             } else {
561 41         247 @err = $self->_read_body_normal_to_string_buffer($sock,
562             \$res_content, length($rest_header),
563             $content_length, $timeout_at);
564             }
565             }
566 49 100       165 if(@err) {
567 1         86 return @err;
568             }
569             }
570              
571             # manage connection cache (i.e. keep-alive)
572 55 100       215 if (lc($connection_header) eq 'keep-alive') {
573 54         144 my $connection = lc $special_headers->{'connection'};
574 54 100 66     456 if (($res_minor_version == 0
    50 100        
575             ? $connection eq 'keep-alive' # HTTP/1.0 needs explicit keep-alive
576             : $connection ne 'close') # HTTP/1.1 can keep alive by default
577             && ( defined $content_length or $chunked)) {
578 44         351 $self->{connection_pool}->push($host, $port, $sock);
579             }
580             }
581             # explicitly close here, just after returning the socket to the pool,
582             # since it might be reused in the upcoming recursive call
583 55         882 undef $sock;
584              
585             # process 'Set-Cookie' header.
586 55 50       184 if (defined $cookie_jar) {
587 0 0 0     0 my $req_url = join(
588             '',
589             $scheme,
590             '://',
591             (defined($username) && defined($password) ? "${username}:${password}@" : ()),
592             "$host:${port}${path_query}",
593             );
594 0         0 my $cookies = $res_headers->{'set-cookie'};
595 0 0       0 $cookies = [$cookies] if !ref$cookies;
596 0         0 for my $cookie (@$cookies) {
597 0         0 $cookie_jar->add($req_url, $cookie);
598             }
599             }
600              
601 55 50       157 if ($do_redirect) {
602 0         0 my $location = $special_headers->{location};
603 0 0       0 unless ($location =~ m{^[a-z0-9]+://}) {
604             # RFC 2616 14.30 says Location header is absolute URI.
605             # But, a lot of servers return relative URI.
606 0         0 _requires("URI.pm", "redirect with relative url");
607 0         0 $location = URI->new_abs($location, "$scheme://$host:$port$path_query")->as_string;
608             }
609             # Note: RFC 1945 and RFC 2068 specify that the client is not allowed
610             # to change the method on the redirected request. However, most
611             # existing user agent implementations treat 302 as if it were a 303
612             # response, performing a GET on the Location field-value regardless
613             # of the original request method. The status codes 303 and 307 have
614             # been added for servers that wish to make unambiguously clear which
615             # kind of reaction is expected of the client. Also, 308 was introduced
616             # to avoid the ambiguity of 301.
617 0 0       0 return $self->request(
618             @_,
619             method => $res_status =~ /^30[178]$/ ? $method : 'GET',
620             url => $location,
621             max_redirects => $max_redirects - 1,
622             );
623             }
624              
625             # return response.
626              
627 55 50       156 if (ref $res_content) {
628 0         0 $res_content = $res_content->get_response_string;
629             }
630              
631             return (
632 55         1796 $res_minor_version, $res_status, $res_msg, $res_headers, $res_content,
633             $req_headers, $req_content, undef, undef, [$scheme, $username, $password, $host, $port, $path_query],
634             );
635             }
636              
637             # connects to $host:$port and returns $socket
638             sub connect :method {
639 37     37 0 187 my($self, $host, $port, $timeout_at) = @_;
640 37         81 my $sock;
641              
642 37         187 my $timeout = $timeout_at - time;
643 37 50       147 return (undef, "Failed to resolve host name: timeout")
644             if $timeout <= 0;
645 37         192 my ($sock_addr, $err_reason) = $self->_get_address($host, $port, $timeout);
646 37 100 33     2884 return (undef, "Cannot resolve host name: $host (port: $port), " . ($err_reason || $!))
647             unless $sock_addr;
648              
649 36 50       1658 RETRY:
650             socket($sock, Socket::sockaddr_family($sock_addr), SOCK_STREAM, 0)
651             or Carp::croak("Cannot create socket: $!");
652 36         438 _set_sockopts($sock);
653 36 50 50     3832 if (connect($sock, $sock_addr)) {
    50          
654             # connected
655             } elsif ($! == EINPROGRESS || (WIN32 && $! == EWOULDBLOCK)) {
656 36 50       438 $self->do_select(1, $sock, $timeout_at)
657             or return (undef, "Cannot connect to ${host}:${port}: timeout");
658             # connected
659             } else {
660 0 0 0     0 if ($! == EINTR && ! $self->{stop_if}->()) {
661 0         0 close $sock;
662 0         0 goto RETRY;
663             }
664 0         0 return (undef, "Cannot connect to ${host}:${port}: $!");
665             }
666 36         207 $sock;
667             }
668              
669             sub _get_address {
670 37     37   131 my ($self, $host, $port, $timeout) = @_;
671 37 100       173 if ($self->{get_address}) {
672 1         3 return $self->{get_address}->($host, $port, $timeout);
673             }
674             # default rule (TODO add support for IPv6)
675 36 100       107 my $iaddr = $self->{inet_aton}->($host, $timeout)
676             or return (undef, $!);
677 35         261 pack_sockaddr_in($port, $iaddr);
678             }
679              
680             sub _ssl_opts {
681 0     0   0 my $self = shift;
682 0         0 my $ssl_opts = $self->{ssl_opts};
683 0 0       0 unless (exists $ssl_opts->{SSL_verify_mode}) {
684             # set SSL_VERIFY_PEER as default.
685 0         0 $ssl_opts->{SSL_verify_mode} = IO::Socket::SSL::SSL_VERIFY_PEER();
686 0 0       0 unless (exists $ssl_opts->{SSL_verifycn_scheme}) {
687 0         0 $ssl_opts->{SSL_verifycn_scheme} = 'www'
688             }
689             }
690 0 0       0 if ($ssl_opts->{SSL_verify_mode}) {
691 0 0 0     0 unless (exists $ssl_opts->{SSL_ca_file} || exists $ssl_opts->{SSL_ca_path}) {
692 0         0 require Mozilla::CA;
693 0         0 $ssl_opts->{SSL_ca_file} = Mozilla::CA::SSL_ca_file();
694             }
695             }
696 0         0 $ssl_opts;
697             }
698              
699             # connect SSL socket.
700             # You can override this method in your child class, if you want to use Crypt::SSLeay or some other library.
701             # @return file handle like object
702             sub connect_ssl {
703 0     0 0 0 my ($self, $host, $port, $timeout_at) = @_;
704 0         0 _requires('IO/Socket/SSL.pm', 'SSL');
705              
706 0         0 my ($sock, $err_reason) = $self->connect($host, $port, $timeout_at);
707 0 0       0 return (undef, $err_reason)
708             unless $sock;
709              
710 0         0 my $timeout = $timeout_at - time;
711 0 0       0 return (undef, "Cannot create SSL connection: timeout")
712             if $timeout <= 0;
713              
714 0         0 my $ssl_opts = $self->_ssl_opts;
715 0 0       0 IO::Socket::SSL->start_SSL(
716             $sock,
717             PeerHost => $host,
718             PeerPort => $port,
719             Timeout => $timeout,
720             %$ssl_opts,
721             ) or return (undef, "Cannot create SSL connection: " . IO::Socket::SSL::errstr());
722 0         0 _set_sockopts($sock);
723 0         0 $sock;
724             }
725              
726             sub connect_ssl_over_proxy {
727 0     0 0 0 my ($self, $proxy_host, $proxy_port, $host, $port, $timeout_at, $proxy_authorization) = @_;
728 0         0 _requires('IO/Socket/SSL.pm', 'SSL');
729              
730 0         0 my $sock = $self->connect($proxy_host, $proxy_port, $timeout_at);
731              
732 0         0 my $p = "CONNECT $host:$port HTTP/1.0\015\012Server: $host\015\012";
733 0 0       0 if (defined $proxy_authorization) {
734 0         0 $p .= "Proxy-Authorization: $proxy_authorization\015\012";
735             }
736 0         0 $p .= "\015\012";
737 0 0       0 $self->write_all($sock, $p, $timeout_at)
738             or return $self->_r500(
739             "Failed to send HTTP request to proxy: " . _strerror_or_timeout());
740 0         0 my $buf = '';
741             my $read = $self->read_timeout($sock,
742 0         0 \$buf, $self->{bufsize}, length($buf), $timeout_at);
743 0 0       0 if (not defined $read) {
    0          
    0          
744 0         0 return (undef, "Cannot read proxy response: " . _strerror_or_timeout());
745             } elsif ( $read == 0 ) { # eof
746 0         0 return (undef, "Unexpected EOF while reading proxy response");
747             } elsif ( $buf !~ /^HTTP\/1\.[0-9] 200 .+\015\012/ ) {
748 0         0 return (undef, "Invalid HTTP Response via proxy");
749             }
750              
751 0         0 my $timeout = $timeout_at - time;
752 0 0       0 return (undef, "Cannot start SSL connection: timeout")
753             if $timeout_at <= 0;
754              
755 0         0 my $ssl_opts = $self->_ssl_opts;
756 0 0       0 unless (exists $ssl_opts->{SSL_verifycn_name}) {
757 0         0 $ssl_opts->{SSL_verifycn_name} = $host;
758             }
759             IO::Socket::SSL->start_SSL(
760 0 0       0 $sock,
761             PeerHost => $host,
762             PeerPort => $port,
763             Timeout => $timeout,
764             %$ssl_opts
765             ) or return (undef, "Cannot start SSL connection: " . IO::Socket::SSL::errstr());
766 0         0 _set_sockopts($sock); # just in case (20101118 kazuho)
767 0         0 $sock;
768             }
769              
770             sub _read_body_chunked {
771 7     7   24 my ($self, $sock, $res_content, $rest_header, $timeout_at) = @_;
772              
773 7         11 my $buf = $rest_header;
774 7         11 READ_LOOP: while (1) {
775 2595 100       15227 if (
776             my ( $header, $next_len ) = (
777             $buf =~
778             m{\A ( # header
779             ( [0-9a-fA-F]+ ) # next_len (hex number)
780             (?:;
781             $HTTP_TOKEN
782             =
783             (?: $HTTP_TOKEN | $HTTP_QUOTED_STRING )
784             )* # optional chunk-extensions
785             [ ]* # www.yahoo.com adds spaces here.
786             # Is this valid?
787             \015\012 # CR+LF
788             ) }xmso
789             )
790             )
791             {
792 2082         3819 $buf = substr($buf, length($header)); # remove header from buf
793 2082         2880 $next_len = hex($next_len);
794 2082 100       3340 if ($next_len == 0) {
795 6         18 last READ_LOOP;
796             }
797              
798             # +2 means trailing CRLF
799 2076         3500 READ_CHUNK: while ( $next_len+2 > length($buf) ) {
800             my $n = $self->read_timeout( $sock,
801 1290         3339 \$buf, $self->{bufsize}, length($buf), $timeout_at );
802 1290 50       4515 if (!$n) {
803 0 0       0 return $self->_r500(
804             !defined($n)
805             ? "Cannot read chunk: " . _strerror_or_timeout()
806             : "Unexpected EOF while reading packets"
807             );
808             }
809             }
810 2076         3848 $$res_content .= substr($buf, 0, $next_len);
811 2076         3358 $buf = substr($buf, $next_len+2);
812 2076 50       3265 if (length($buf) > 0) {
813 2076         3690 next; # re-parse header
814             }
815             }
816              
817             my $n = $self->read_timeout( $sock,
818 513         1340 \$buf, $self->{bufsize}, length($buf), $timeout_at );
819 513 100       1448 if (!$n) {
820 1 50       5 return $self->_r500(
821             !defined($n)
822             ? "Cannot read chunk: " . _strerror_or_timeout()
823             : "Unexpected EOF while reading packets"
824             );
825             }
826             }
827             # read last CRLF
828 6         31 return $self->_read_body_normal(
829             $sock, \$buf, length($buf), 2, $timeout_at);
830             }
831              
832             sub _read_body_normal {
833 7     7   20 my ($self, $sock, $res_content, $nread, $res_content_length, $timeout_at)
834             = @_;
835 7   66     57 while (!defined($res_content_length) || $res_content_length != $nread) {
836             my $n = $self->read_timeout( $sock,
837 1         4 \my $buf, $self->{bufsize}, 0, $timeout_at );
838 1 50       5 if (!$n) {
839 1 50       5 last if ! defined($res_content_length);
840 0 0       0 return $self->_r500(
841             !defined($n)
842             ? "Cannot read content body: " . _strerror_or_timeout()
843             : "Unexpected EOF while reading content body"
844             );
845             }
846 0         0 $$res_content .= $buf;
847 0         0 $nread += $n;
848             }
849 7         21 return;
850             }
851              
852             # This function loads all content at once if it's possible. Since $res_content is just a plain scalar.
853             # Buffering is not needed.
854             sub _read_body_normal_to_string_buffer {
855 41     41   134 my ($self, $sock, $res_content, $nread, $res_content_length, $timeout_at)
856             = @_;
857 41         174 while ($res_content_length != $nread) {
858 26         83 my $n = $self->read_timeout( $sock,
859             $res_content, $res_content_length, $nread, $timeout_at );
860 26 50       126 if (!$n) {
861 0 0       0 return $self->_r500(
862             !defined($n)
863             ? "Cannot read content body: " . _strerror_or_timeout()
864             : "Unexpected EOF while reading content body"
865             );
866             }
867 26         80 $nread += $n;
868             }
869 41         120 return;
870             }
871              
872             # returns true if the socket is ready to read, false if timeout has occurred ($! will be cleared upon timeout)
873             sub do_select {
874 94     94 0 319 my($self, $is_write, $sock, $timeout_at) = @_;
875 94         282 my $now = time;
876 94         299 my $inactivity_timeout_at = $now + $self->{inactivity_timeout};
877 94 50       287 $timeout_at = $inactivity_timeout_at
878             if $timeout_at > $inactivity_timeout_at;
879             # wait for data
880 94         191 while (1) {
881 97         169 my $timeout = $timeout_at - $now;
882 97 50       313 if ($timeout <= 0) {
883 0         0 $! = 0;
884 0         0 return 0;
885             }
886 97         345 my $nfound = $self->_do_select($is_write, $sock, $timeout);
887 97 100       5608 return 1 if $nfound > 0;
888 6 100 33     104 return 0 if $nfound == -1 && $! == EINTR && $self->{stop_if}->();
      66        
889 3         32 $now = time;
890             }
891 0         0 die 'not reached';
892             }
893              
894             sub _do_select {
895 123     123   300 my($self, $is_write, $sock, $timeout) = @_;
896 123         207 my($rfd, $wfd);
897 123         328 my $efd = '';
898 123         672 vec($efd, fileno($sock), 1) = 1;
899 123 100       408 if ($is_write) {
900 36         89 $wfd = $efd;
901             } else {
902 87         156 $rfd = $efd;
903             }
904 123         18073403 my $nfound = select($rfd, $wfd, $efd, $timeout);
905 123         1419 return $nfound;
906             }
907              
908             # returns (positive) number of bytes read, or undef if the socket is to be closed
909             sub read_timeout {
910 2042     2042 0 3435 my ($self, $sock, $buf, $len, $off, $timeout_at) = @_;
911 2042         2364 my $ret;
912              
913             # NOTE: select-read-select may get stuck in SSL,
914             # so we use read-select-read instead.
915 2042         2551 while(1) {
916             # try to do the IO
917 2097 100       22607 defined($ret = sysread($sock, $$buf, $len, $off))
918             and return $ret;
919 58 50 33     697 if ($! == EAGAIN || $! == EWOULDBLOCK || (WIN32 && $! == EISCONN)) {
    0 50        
920             # passthru
921             } elsif ($! == EINTR) {
922 0 0       0 return undef if $self->{stop_if}->();
923             # otherwise passthru
924             } else {
925 0         0 return undef;
926             }
927             # on EINTER/EAGAIN/EWOULDBLOCK
928 58 100       280 $self->do_select(0, $sock, $timeout_at) or return undef;
929             }
930             }
931              
932             # returns (positive) number of bytes written, or undef if the socket is to be closed
933             sub write_timeout {
934 60     60 0 154 my ($self, $sock, $buf, $len, $off, $timeout_at) = @_;
935 60         84 my $ret;
936 60         92 while(1) {
937             # try to do the IO
938 60 50       4116 defined($ret = syswrite($sock, $buf, $len, $off))
939             and return $ret;
940 0 0 0     0 if ($! == EAGAIN || $! == EWOULDBLOCK || (WIN32 && $! == EISCONN)) {
    0 0        
941             # passthru
942             } elsif ($! == EINTR) {
943 0 0       0 return undef if $self->{stop_if}->();
944             # otherwise passthru
945             } else {
946 0         0 return undef;
947             }
948 0 0       0 $self->do_select(1, $sock, $timeout_at) or return undef;
949             }
950             }
951              
952             # writes all data in buf and returns number of bytes written or undef if failed
953             sub write_all {
954 60     60 0 181 my ($self, $sock, $buf, $timeout_at) = @_;
955 60         120 my $off = 0;
956 60         204 while (my $len = length($buf) - $off) {
957 60 50       215 my $ret = $self->write_timeout($sock, $buf, $len, $off, $timeout_at)
958             or return undef;
959 60         314 $off += $ret;
960             }
961 60         197 return $off;
962             }
963              
964              
965             sub _r500 {
966 6     6   20 my($self, $message) = @_;
967 6         2135 $message = Carp::shortmess($message); # add lineno and filename
968 6         1048 return(0, 500, "Internal Response: $message",
969             [
970             'Content-Length' => length($message),
971             'X-Internal-Response' => 1,
972             # XXX ^^ EXPERIMENTAL header. Do not depend to this.
973             ], $message
974             );
975             }
976              
977             sub _strerror_or_timeout {
978 3 50   3   33 $! != 0 ? "$!" : 'timeout';
979             }
980              
981             sub _set_sockopts {
982 36     36   99 my $sock = shift;
983              
984 36 50       359 setsockopt( $sock, IPPROTO_TCP, TCP_NODELAY, 1 )
985             or Carp::croak("Failed to setsockopt(TCP_NODELAY): $!");
986 36         100 if (WIN32) {
987             if (ref($sock) ne 'IO::Socket::SSL') {
988             my $tmp = 1;
989             ioctl( $sock, 0x8004667E, \$tmp )
990             or Carp::croak("Cannot set flags for the socket: $!");
991             }
992             } else {
993 36 50       309 my $flags = fcntl( $sock, F_GETFL, 0 )
994             or Carp::croak("Cannot get flags for the socket: $!");
995 36 50       344 $flags = fcntl( $sock, F_SETFL, $flags | O_NONBLOCK )
996             or Carp::croak("Cannot set flags for the socket: $!");
997             }
998              
999             {
1000             # no buffering
1001 36         105 my $orig = select();
  36         183  
1002 36         121 select($sock); $|=1;
  36         151  
1003 36         129 select($orig);
1004             }
1005              
1006 36         169 binmode $sock;
1007             }
1008              
1009             # You can override this method if you want to use more powerful matcher.
1010             sub match_no_proxy {
1011 0     0 0   my ( $self, $no_proxy, $host ) = @_;
1012              
1013             # ref. curl.1.
1014             # list of host names that shouldn't go through any proxy.
1015             # If set to a asterisk '*' only, it matches all hosts.
1016 0 0         if ( $no_proxy eq '*' ) {
1017 0           return 1;
1018             }
1019             else {
1020 0           for my $pat ( split /\s*,\s*/, lc $no_proxy ) {
1021 0 0         if ( $host =~ /\Q$pat\E$/ ) { # suffix match(same behavior with LWP)
1022 0           return 1;
1023             }
1024             }
1025             }
1026 0           return 0;
1027             }
1028              
1029             # utility class
1030             {
1031             package # hide from pause
1032             Furl::FileStream;
1033 45     45   56472 use overload '.=' => 'append', fallback => 1;
  45         42444  
  45         294  
1034             sub new {
1035 0     0     my ($class, $fh) = @_;
1036 0           bless {fh => $fh}, $class;
1037             }
1038             sub append {
1039 0     0     my($self, $partial) = @_;
1040 0           print {$self->{fh}} $partial;
  0            
1041 0           return $self;
1042             }
1043 0     0     sub get_response_string { undef }
1044             }
1045              
1046             {
1047             package # hide from pause
1048             Furl::CallbackStream;
1049 45     45   8936 use overload '.=' => 'append', fallback => 1;
  45         105  
  45         377  
1050             sub new {
1051 0     0     my ($class, $cb) = @_;
1052 0           bless {cb => $cb}, $class;
1053             }
1054             sub append {
1055 0     0     my($self, $partial) = @_;
1056 0           $self->{cb}->($partial);
1057 0           return $self;
1058             }
1059 0     0     sub get_response_string { undef }
1060             }
1061              
1062             1;
1063             __END__