File Coverage

blib/lib/Furl/HTTP.pm
Criterion Covered Total %
statement 324 499 64.9
branch 144 292 49.3
condition 47 97 48.4
subroutine 38 56 67.8
pod 9 18 50.0
total 562 962 58.4


line stmt bran cond sub pod time code
1             package Furl::HTTP;
2 47     47   914680 use strict;
  47         140  
  47         1740  
3 47     47   271 use warnings;
  47         84  
  47         2940  
4 47     47   271 use base qw/Exporter/;
  47         80  
  47         5029  
5 47     47   1030 use 5.008001;
  47         263  
6              
7             our $VERSION = '3.15';
8              
9 47     47   298 use Carp ();
  47         105  
  47         1145  
10 47     47   20956 use Furl::ConnectionCache;
  47         141  
  47         1702  
11              
12 47     47   329 use Scalar::Util ();
  47         75  
  47         1448  
13 47     47   21513 use Errno qw(EAGAIN ECONNRESET EINPROGRESS EINTR EWOULDBLOCK ECONNABORTED EISCONN);
  47         77277  
  47         7136  
14 47     47   345 use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK SEEK_SET SEEK_END);
  47         80  
  47         3510  
15 47         11247 use Socket qw(
16             PF_INET SOCK_STREAM
17             IPPROTO_TCP
18             TCP_NODELAY
19             pack_sockaddr_in
20 47     47   27521 );
  47         221898  
21 47     47   21782 use Time::HiRes qw(time);
  47         50600  
  47         495  
22              
23 47     47   6610 use constant WIN32 => $^O eq 'MSWin32';
  47         114  
  47         5615  
24 47     47   24388 use HTTP::Parser::XS qw/HEADERS_NONE HEADERS_AS_ARRAYREF HEADERS_AS_HASHREF/;
  47         50184  
  47         377410  
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 33     33 1 8177603 my $class = shift;
41 33 50       1163 my %args = @_ == 1 ? %{$_[0]} : @_;
  0         0  
42              
43             my @headers = (
44 33   66     1321 'User-Agent' => (delete($args{agent}) || __PACKAGE__ . '/' . $Furl::HTTP::VERSION),
45             );
46 33         370 my $connection_header = 'keep-alive';
47 33 50       527 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 37     37   7841 inet_aton => sub { Socket::inet_aton($_[0]) },
70             ssl_opts => {},
71 33   100     1450 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 41 if ( @_ == 2 ) {
127 3         55 _header_set(shift->{headers}, 'User-Agent', shift);
128             } else {
129 2         10 return _header_get(shift->{headers}, 'User-Agent');
130             }
131             }
132              
133             sub _header_set {
134 3     3   30 my ($headers, $key, $value) = (shift, lc shift, shift);
135 3         26 for (my $i=0; $i<@$headers; $i+=2) {
136 3 50       36 if (lc($headers->[$i]) eq $key) {
137 3         7 $headers->[$i+1] = $value;
138 3         8 return;
139             }
140             }
141 0         0 push @$headers, $key, $value;
142             }
143              
144             sub _header_get {
145 23     23   62533 my ($headers, $key) = (shift, lc shift);
146 23         109 for (my $i=0; $i<@$headers; $i+=2) {
147 29 100       233 return $headers->[$i+1] if lc($headers->[$i]) eq $key;
148             }
149 3         13 return undef;
150             }
151              
152             sub _requires {
153 12     12   26 my($file, $feature, $library) = @_;
154 12 100       50 return if exists $INC{$file};
155 1 50       2 unless(eval { require $file }) {
  1         1000  
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   316423 my($self, $url) = @_;
176 35 100       887 $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         642 return( $1, $2, $3, $4, $5, $6 );
190             }
191              
192             sub make_x_www_form_urlencoded {
193 1     1 0 49 my($self, $content) = @_;
194 1         1 my @params;
195 0         0 my @p = ref($content) eq 'HASH' ? %{$content}
196 1 50       6 : ref($content) eq 'ARRAY' ? @{$content}
  1 50       2  
197             : Carp::croak("Cannot coerce $content to x-www-form-urlencoded");
198 1         7 while ( my ( $k, $v ) = splice @p, 0, 2 ) {
199 1         2 foreach my $s($k, $v) {
200 2         5 utf8::downgrade($s); # will die in wide characters
201             # escape unsafe chars (defined by RFC 3986)
202 2         4 $s =~ s/ ([^A-Za-z0-9\-\._~]) / sprintf '%%%02X', ord $1 /xmsge;
  0         0  
203             }
204 1         4 push @params, "$k=$v";
205             }
206 1         8 return join( "&", @params );
207             }
208              
209             sub env_proxy {
210 8     8 1 16 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       39 local $ENV{HTTP_PROXY} if $ENV{REQUEST_METHOD};
214 8   66     45 $self->{proxy} = $ENV{http_proxy} || $ENV{HTTP_PROXY} || $self->{proxy};
215 8   50     30 $self->{no_proxy} = $ENV{NO_PROXY} || '';
216 8         33 $self;
217             }
218              
219             sub request {
220 68     68 1 20131027 my $self = shift;
221 68         1152 my %args = @_;
222              
223 68         1028 my $timeout_at = time + $self->{timeout};
224              
225 68         300 my ($scheme, $username, $password, $host, $port, $path_query);
226 68 100       479 if (defined(my $url = $args{url})) {
227 23         242 ($scheme, $username, $password, $host, $port, $path_query) = $self->_parse_url($url);
228             }
229             else {
230 45         254 ($scheme, $host, $port, $path_query) = @args{qw/scheme host port path_query/};
231 45 50       376 if (not defined $host) {
232 0         0 Carp::croak("Missing host name in arguments");
233             }
234             }
235              
236 68 100 66     516 if (not defined $scheme) {
    100          
237 45         285 $scheme = 'http';
238             } elsif($scheme ne 'http' && $scheme ne 'https') {
239 6         899 Carp::croak("Unsupported scheme: $scheme");
240             }
241              
242 62 50       329 my $default_port = $scheme eq 'http'
243             ? 80
244             : 443;
245 62 100       332 if(not defined $port) {
246 1         2 $port = $default_port;
247             }
248 62 100       368 if(not defined $path_query) {
249 14         63 $path_query = '/';
250             }
251              
252 62 100       448 unless (substr($path_query, 0, 1) eq '/') {
253 3         33 $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 62 50       833 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 62         477 my $proxy = $self->{proxy};
264 62         296 my $no_proxy = $self->{no_proxy};
265 62 50 33     587 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 62         1631 local $SIG{PIPE} = 'IGNORE';
272 62         907 my $sock = $self->{connection_pool}->steal($host, $port);
273 62         180 my $in_keepalive;
274 62 100       251 if (defined $sock) {
275 26 100       128 if ($self->_do_select(0, $sock, 0)) {
276 2         158 close $sock;
277 2         14 undef $sock;
278             } else {
279 24         54 $in_keepalive = 1;
280             }
281             }
282 62 100       274 if(!$in_keepalive) {
283 38         216 my $err_reason;
284 38 50       216 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 38 50       214 if ($scheme eq 'http') {
309 38         411 ($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 38 100       137 return $self->_r500($err_reason)
317             unless $sock;
318             }
319              
320             # keep request dump
321 61         535 my ($req_headers, $req_content) = ("", "");
322              
323             # write request
324 61   100     663 my $method = $args{method} || 'GET';
325 61         173 my $connection_header = $self->{connection_header};
326 61         157 my $cookie_jar = $self->{cookie_jar};
327             {
328 61         102 my @headers = @{$self->{headers}};
  61         127  
  61         949  
329 61 100       4287 $connection_header = 'close'
330             if $method eq 'HEAD';
331 61 100       255 if (my $in_headers = $args{headers}) {
332 14         88 for (my $i = 0; $i < @$in_headers; $i += 2) {
333 18         34 my $name = $in_headers->[$i];
334 18 50       49 if (lc($name) eq 'connection') {
335 0         0 $connection_header = $in_headers->[$i + 1];
336             } else {
337 18         68 push @headers, $name, $in_headers->[$i + 1];
338             }
339             }
340             }
341 61         214 unshift @headers, 'Connection', $connection_header;
342 61 50       213 if (exists $self->{proxy_authorization}) {
343 0         0 push @headers, 'Proxy-Authorization', $self->{proxy_authorization};
344             }
345 61 100       170 if (defined $username) {
346 6         21 _requires('URI/Escape.pm', 'Basic auth');
347 6         59 my($unescape_username) = URI::Escape::uri_unescape($username);
348 6         131 my($unescape_password) = URI::Escape::uri_unescape($password);
349 6         61 _requires('MIME/Base64.pm', 'Basic auth');
350 6         1859 push @headers, 'Authorization', 'Basic ' . MIME::Base64::encode_base64("${unescape_username}:${unescape_password}","");
351             }
352              
353             # set Cookie header
354 61 50       176 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 61         193 my $content = $args{content};
372 61         116 my $content_is_fh = 0;
373 61 100       175 if(defined $content) {
374 3         16 $content_is_fh = Scalar::Util::openhandle($content);
375 3 50 33     42 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       27 if(!defined _header_get(\@headers, 'Content-Length')) {
383 3         5 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         6 $content_length = length($content);
399             }
400 3         43 push @headers, 'Content-Length' => $content_length;
401             }
402             }
403              
404             # finally, set Host header
405 61 100       506 my $request_target = ($port == $default_port) ? $host : "$host:$port";
406 61         390 push @headers, 'Host' => $request_target;
407              
408 61 50 33     417 my $request_uri = $proxy && $scheme eq 'http' ? "$scheme://$request_target$path_query" : $path_query;
409              
410 61         186 my $p = "$method $request_uri HTTP/1.1\015\012";
411 61         222 for (my $i = 0; $i < @headers; $i += 2) {
412 210         449 my $val = $headers[ $i + 1 ];
413             # the de facto standard way to handle [\015\012](by kazuho-san)
414 210         425 $val =~ tr/\015\012/ /;
415 210         570 $p .= "$headers[$i]: $val\015\012";
416             }
417 61         180 $p .= "\015\012";
418 61 50       317 $self->write_all($sock, $p, $timeout_at)
419             or return $self->_r500(
420             "Failed to send HTTP request: " . _strerror_or_timeout());
421              
422 61 100       261 if ($self->{capture_request}) {
423 1         4 $req_headers = $p;
424             }
425              
426 61 100       349 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       45 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 61         466 my $buf = '';
463 61         291 my $rest_header;
464             my $res_minor_version;
465 61         0 my $res_status;
466 61         0 my $res_msg;
467 61         0 my $res_headers;
468 61   50     601 my $special_headers = $args{special_headers} || +{};
469 61         279 $special_headers->{'connection'} = '';
470 61         255 $special_headers->{'content-length'} = undef;
471 61         257 $special_headers->{'location'} = '';
472 61         151 $special_headers->{'content-encoding'} = '';
473 61         179 $special_headers->{'transfer-encoding'} = '';
474 61         101 LOOP: while (1) {
475             my $n = $self->read_timeout($sock,
476 213         736 \$buf, $self->{bufsize}, length($buf), $timeout_at);
477 213 100       724 if(!$n) { # error or eof
478 3 50 33     76 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       22 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 210         390 my $ret;
491             ( $ret, $res_minor_version, $res_status, $res_msg, $res_headers )
492             = HTTP::Parser::XS::parse_http_response( $buf,
493 210         1442 $self->{header_format}, $special_headers );
494 210 50       783 if ( $ret == -1 ) {
    100          
495 0         0 return $self->_r500("Invalid HTTP response");
496             }
497             elsif ( $ret == -2 ) {
498             # partial response
499 147         303 next LOOP;
500             }
501             else {
502             # succeeded
503 63         235 $rest_header = substr( $buf, $ret );
504 63 100       362 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         7 $buf = $rest_header;
509 5         10 next LOOP;
510             }
511 58         154 last LOOP;
512             }
513             }
514             }
515              
516 58         103 my $max_redirects = 0;
517 58         114 my $do_redirect = undef;
518 58 50       284 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 58         284 my $res_content = '';
524 58 50       162 unless ($do_redirect) {
525 58 50       361 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 58 50       248 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 58         171 my $chunked = ($special_headers->{'transfer-encoding'} eq 'chunked');
541 58         120 my $content_length = $special_headers->{'content-length'};
542 58 100 100     1553 if (defined($content_length) && $content_length !~ /\A[0-9]+\z/) {
543 1         7 return $self->_r500("Bad Content-Length: ${content_length}");
544             }
545              
546 57 100 33     1025 unless ($method eq 'HEAD'
      66        
      66        
      100        
547             || ($res_status < 200 && $res_status >= 100)
548             || $res_status == 204
549             || $res_status == 304) {
550 50         85 my @err;
551 50 100       292 if ( $chunked ) {
552 7         51 @err = $self->_read_body_chunked($sock,
553             \$res_content, $rest_header, $timeout_at);
554             } else {
555 43         123 $res_content .= $rest_header;
556 43 100 66     315 if (ref $res_content || !defined($content_length)) {
557 2         16 @err = $self->_read_body_normal($sock,
558             \$res_content, length($rest_header),
559             $content_length, $timeout_at);
560             } else {
561 41         289 @err = $self->_read_body_normal_to_string_buffer($sock,
562             \$res_content, length($rest_header),
563             $content_length, $timeout_at);
564             }
565             }
566 50 100       165 if(@err) {
567 2         174 return @err;
568             }
569             }
570              
571             # manage connection cache (i.e. keep-alive)
572 55 100       216 if (lc($connection_header) eq 'keep-alive') {
573 54         187 my $connection = lc $special_headers->{'connection'};
574 54 100 66     471 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         335 $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         981 undef $sock;
584              
585             # process 'Set-Cookie' header.
586 55 50       217 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       177 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       193 if (ref $res_content) {
628 0         0 $res_content = $res_content->get_response_string;
629             }
630              
631             return (
632 55         4964 $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 38     38 0 467 my($self, $host, $port, $timeout_at) = @_;
640 38         90 my $sock;
641              
642 38         162 my $timeout = $timeout_at - time;
643 38 50       223 return (undef, "Failed to resolve host name: timeout")
644             if $timeout <= 0;
645 38         235 my ($sock_addr, $err_reason) = $self->_get_address($host, $port, $timeout);
646 38 100 33     5202 return (undef, "Cannot resolve host name: $host (port: $port), " . ($err_reason || $!))
647             unless $sock_addr;
648              
649 37 50       1922 RETRY:
650             socket($sock, Socket::sockaddr_family($sock_addr), SOCK_STREAM, 0)
651             or Carp::croak("Cannot create socket: $!");
652 37         747 _set_sockopts($sock);
653 37 50 50     5068 if (connect($sock, $sock_addr)) {
    50          
654             # connected
655             } elsif ($! == EINPROGRESS || (WIN32 && $! == EWOULDBLOCK)) {
656 37 50       592 $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 37         160 $sock;
667             }
668              
669             sub _get_address {
670 38     38   180 my ($self, $host, $port, $timeout) = @_;
671 38 100       221 if ($self->{get_address}) {
672 1         6 return $self->{get_address}->($host, $port, $timeout);
673             }
674             # default rule (TODO add support for IPv6)
675 37 100       205 my $iaddr = $self->{inet_aton}->($host, $timeout)
676             or return (undef, $!);
677 36         324 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   21 my ($self, $sock, $res_content, $rest_header, $timeout_at) = @_;
772              
773 7         14 my $buf = $rest_header;
774 7         13 READ_LOOP: while (1) {
775 2595 100       14779 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         3555 $buf = substr($buf, length($header)); # remove header from buf
793 2082         2747 $next_len = hex($next_len);
794 2082 100       3150 if ($next_len == 0) {
795 6         18 last READ_LOOP;
796             }
797              
798             # +2 means trailing CRLF
799 2076         3415 READ_CHUNK: while ( $next_len+2 > length($buf) ) {
800             my $n = $self->read_timeout( $sock,
801 1290         2783 \$buf, $self->{bufsize}, length($buf), $timeout_at );
802 1290 50       3291 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         3312 $$res_content .= substr($buf, 0, $next_len);
811 2076         3061 $buf = substr($buf, $next_len+2);
812 2076 50       3240 if (length($buf) > 0) {
813 2076         3293 next; # re-parse header
814             }
815             }
816              
817             my $n = $self->read_timeout( $sock,
818 513         1164 \$buf, $self->{bufsize}, length($buf), $timeout_at );
819 513 100       1080 if (!$n) {
820 1 50       6 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         25 return $self->_read_body_normal(
829             $sock, \$buf, length($buf), 2, $timeout_at);
830             }
831              
832             sub _read_body_normal {
833 8     8   24 my ($self, $sock, $res_content, $nread, $res_content_length, $timeout_at)
834             = @_;
835 8   66     52 while (!defined($res_content_length) || $res_content_length != $nread) {
836             my $n = $self->read_timeout( $sock,
837 2         11 \my $buf, $self->{bufsize}, 0, $timeout_at );
838 2 100       25 if (!defined($n)) {
    50          
839 1         4 return $self->_r500("Cannot read content body: " . _strerror_or_timeout());
840             } elsif (!$n) {
841 1 50       3 last if ! defined($res_content_length);
842 0         0 return $self->_r500("Unexpected EOF while reading content body");
843             }
844 0         0 $$res_content .= $buf;
845 0         0 $nread += $n;
846             }
847 7         24 return;
848             }
849              
850             # This function loads all content at once if it's possible. Since $res_content is just a plain scalar.
851             # Buffering is not needed.
852             sub _read_body_normal_to_string_buffer {
853 41     41   152 my ($self, $sock, $res_content, $nread, $res_content_length, $timeout_at)
854             = @_;
855 41         155 while ($res_content_length != $nread) {
856 29         100 my $n = $self->read_timeout( $sock,
857             $res_content, $res_content_length, $nread, $timeout_at );
858 29 50       107 if (!$n) {
859 0 0       0 return $self->_r500(
860             !defined($n)
861             ? "Cannot read content body: " . _strerror_or_timeout()
862             : "Unexpected EOF while reading content body"
863             );
864             }
865 29         114 $nread += $n;
866             }
867 41         121 return;
868             }
869              
870             # returns true if the socket is ready to read, false if timeout has occurred ($! will be cleared upon timeout)
871             sub do_select {
872 91     91 0 284 my($self, $is_write, $sock, $timeout_at) = @_;
873 91         377 my $now = time;
874 91         261 my $inactivity_timeout_at = $now + $self->{inactivity_timeout};
875 91 50       326 $timeout_at = $inactivity_timeout_at
876             if $timeout_at > $inactivity_timeout_at;
877             # wait for data
878 91         257 while (1) {
879 95         388 my $timeout = $timeout_at - $now;
880 95 100       322 if ($timeout <= 0) {
881 1         4 $! = 0;
882 1         6 return 0;
883             }
884 94         547 my $nfound = $self->_do_select($is_write, $sock, $timeout);
885 94 100       8176 return 1 if $nfound > 0;
886 7 100 66     143 return 0 if $nfound == -1 && $! == EINTR && $self->{stop_if}->();
      100        
887 4         43 $now = time;
888             }
889 0         0 die 'not reached';
890             }
891              
892             sub _do_select {
893 120     120   412 my($self, $is_write, $sock, $timeout) = @_;
894 120         236 my($rfd, $wfd);
895 120         407 my $efd = '';
896 120         825 vec($efd, fileno($sock), 1) = 1;
897 120 100       410 if ($is_write) {
898 37         85 $wfd = $efd;
899             } else {
900 83         164 $rfd = $efd;
901             }
902 120         19185101 my $nfound = select($rfd, $wfd, $efd, $timeout);
903 120         694 return $nfound;
904             }
905              
906             # returns (positive) number of bytes read, or undef if the socket is to be closed
907             sub read_timeout {
908 2047     2047 0 3593 my ($self, $sock, $buf, $len, $off, $timeout_at) = @_;
909 2047         2464 my $ret;
910              
911             # NOTE: select-read-select may get stuck in SSL,
912             # so we use read-select-read instead.
913 2047         2179 while(1) {
914             # try to do the IO
915 2097 100       18665 defined($ret = sysread($sock, $$buf, $len, $off))
916             and return $ret;
917 54 50 33     711 if ($! == EAGAIN || $! == EWOULDBLOCK || (WIN32 && $! == EISCONN)) {
    0 50        
918             # passthru
919             } elsif ($! == EINTR) {
920 0 0       0 return undef if $self->{stop_if}->();
921             # otherwise passthru
922             } else {
923 0         0 return undef;
924             }
925             # on EINTER/EAGAIN/EWOULDBLOCK
926 54 100       233 $self->do_select(0, $sock, $timeout_at) or return undef;
927             }
928             }
929              
930             # returns (positive) number of bytes written, or undef if the socket is to be closed
931             sub write_timeout {
932 61     61 0 181 my ($self, $sock, $buf, $len, $off, $timeout_at) = @_;
933 61         107 my $ret;
934 61         101 while(1) {
935             # try to do the IO
936 61 50       8631 defined($ret = syswrite($sock, $buf, $len, $off))
937             and return $ret;
938 0 0 0     0 if ($! == EAGAIN || $! == EWOULDBLOCK || (WIN32 && $! == EISCONN)) {
    0 0        
939             # passthru
940             } elsif ($! == EINTR) {
941 0 0       0 return undef if $self->{stop_if}->();
942             # otherwise passthru
943             } else {
944 0         0 return undef;
945             }
946 0 0       0 $self->do_select(1, $sock, $timeout_at) or return undef;
947             }
948             }
949              
950             # writes all data in buf and returns number of bytes written or undef if failed
951             sub write_all {
952 61     61 0 428 my ($self, $sock, $buf, $timeout_at) = @_;
953 61         170 my $off = 0;
954 61         265 while (my $len = length($buf) - $off) {
955 61 50       213 my $ret = $self->write_timeout($sock, $buf, $len, $off, $timeout_at)
956             or return undef;
957 61         303 $off += $ret;
958             }
959 61         233 return $off;
960             }
961              
962              
963             sub _r500 {
964 7     7   21 my($self, $message) = @_;
965 7         3994 $message = Carp::shortmess($message); # add lineno and filename
966 7         3679 return(0, 500, "Internal Response: $message",
967             [
968             'Content-Length' => length($message),
969             'X-Internal-Response' => 1,
970             # XXX ^^ EXPERIMENTAL header. Do not depend to this.
971             ], $message
972             );
973             }
974              
975             sub _strerror_or_timeout {
976 4 100   4   64 $! != 0 ? "$!" : 'timeout';
977             }
978              
979             sub _set_sockopts {
980 37     37   150 my $sock = shift;
981              
982 37 50       413 setsockopt( $sock, IPPROTO_TCP, TCP_NODELAY, 1 )
983             or Carp::croak("Failed to setsockopt(TCP_NODELAY): $!");
984 37         95 if (WIN32) {
985             if (ref($sock) ne 'IO::Socket::SSL') {
986             my $tmp = 1;
987             ioctl( $sock, 0x8004667E, \$tmp )
988             or Carp::croak("Cannot set flags for the socket: $!");
989             }
990             } else {
991 37 50       238 my $flags = fcntl( $sock, F_GETFL, 0 )
992             or Carp::croak("Cannot get flags for the socket: $!");
993 37 50       331 $flags = fcntl( $sock, F_SETFL, $flags | O_NONBLOCK )
994             or Carp::croak("Cannot set flags for the socket: $!");
995             }
996              
997             {
998             # no buffering
999 37         110 my $orig = select();
  37         220  
1000 37         180 select($sock); $|=1;
  37         140  
1001 37         147 select($orig);
1002             }
1003              
1004 37         131 binmode $sock;
1005             }
1006              
1007             # You can override this method if you want to use more powerful matcher.
1008             sub match_no_proxy {
1009 0     0 0   my ( $self, $no_proxy, $host ) = @_;
1010              
1011             # ref. curl.1.
1012             # list of host names that shouldn't go through any proxy.
1013             # If set to a asterisk '*' only, it matches all hosts.
1014 0 0         if ( $no_proxy eq '*' ) {
1015 0           return 1;
1016             }
1017             else {
1018 0           for my $pat ( split /\s*,\s*/, lc $no_proxy ) {
1019 0 0         if ( $host =~ /\Q$pat\E$/ ) { # suffix match(same behavior with LWP)
1020 0           return 1;
1021             }
1022             }
1023             }
1024 0           return 0;
1025             }
1026              
1027             # utility class
1028             {
1029             package # hide from pause
1030             Furl::FileStream;
1031 47     47   33852 use overload '.=' => 'append', fallback => 1;
  47         90817  
  47         339  
1032             sub new {
1033 0     0     my ($class, $fh) = @_;
1034 0           bless {fh => $fh}, $class;
1035             }
1036             sub append {
1037 0     0     my($self, $partial) = @_;
1038 0           print {$self->{fh}} $partial;
  0            
1039 0           return $self;
1040             }
1041 0     0     sub get_response_string { undef }
1042             }
1043              
1044             {
1045             package # hide from pause
1046             Furl::CallbackStream;
1047 47     47   10713 use overload '.=' => 'append', fallback => 1;
  47         124  
  47         230  
1048             sub new {
1049 0     0     my ($class, $cb) = @_;
1050 0           bless {cb => $cb}, $class;
1051             }
1052             sub append {
1053 0     0     my($self, $partial) = @_;
1054 0           $self->{cb}->($partial);
1055 0           return $self;
1056             }
1057 0     0     sub get_response_string { undef }
1058             }
1059              
1060             1;
1061             __END__