File Coverage

blib/lib/Furl/HTTP.pm
Criterion Covered Total %
statement 313 498 62.8
branch 140 292 47.9
condition 46 100 46.0
subroutine 37 56 66.0
pod 9 18 50.0
total 545 964 56.5


line stmt bran cond sub pod time code
1             package Furl::HTTP;
2 45     45   416402 use strict;
  45         91  
  45         1160  
3 45     45   224 use warnings;
  45         87  
  45         1149  
4 45     45   200 use base qw/Exporter/;
  45         79  
  45         4162  
5 45     45   1105 use 5.008001;
  45         155  
6              
7             our $VERSION = '3.13';
8              
9 45     45   239 use Carp ();
  45         87  
  45         832  
10 45     45   10603 use Furl::ConnectionCache;
  45         132  
  45         1367  
11              
12 45     45   246 use Scalar::Util ();
  45         77  
  45         891  
13 45     45   10940 use Errno qw(EAGAIN ECONNRESET EINPROGRESS EINTR EWOULDBLOCK ECONNABORTED EISCONN);
  45         49999  
  45         4578  
14 45     45   284 use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK SEEK_SET SEEK_END);
  45         83  
  45         2290  
15 45         7877 use Socket qw(
16             PF_INET SOCK_STREAM
17             IPPROTO_TCP
18             TCP_NODELAY
19             pack_sockaddr_in
20 45     45   15278 );
  45         151659  
21 45     45   14632 use Time::HiRes qw(time);
  45         40844  
  45         177  
22              
23 45     45   7663 use constant WIN32 => $^O eq 'MSWin32';
  45         90  
  45         3629  
24 45     45   12187 use HTTP::Parser::XS qw/HEADERS_NONE HEADERS_AS_ARRAYREF HEADERS_AS_HASHREF/;
  45         28974  
  45         233006  
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 118554 my $class = shift;
41 32 50       331 my %args = @_ == 1 ? %{$_[0]} : @_;
  0         0  
42              
43             my @headers = (
44 32   66     534 'User-Agent' => (delete($args{agent}) || __PACKAGE__ . '/' . $Furl::HTTP::VERSION),
45             );
46 32         138 my $connection_header = 'keep-alive';
47 32 50       157 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   113772 inet_aton => sub { Socket::inet_aton($_[0]) },
70             ssl_opts => {},
71 32   100     558 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 22 if ( @_ == 2 ) {
127 3         17 _header_set(shift->{headers}, 'User-Agent', shift);
128             } else {
129 2         9 return _header_get(shift->{headers}, 'User-Agent');
130             }
131             }
132              
133             sub _header_set {
134 3     3   11 my ($headers, $key, $value) = (shift, lc shift, shift);
135 3         11 for (my $i=0; $i<@$headers; $i+=2) {
136 3 50       15 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   26359 my ($headers, $key) = (shift, lc shift);
146 23         113 for (my $i=0; $i<@$headers; $i+=2) {
147 29 100       183 return $headers->[$i+1] if lc($headers->[$i]) eq $key;
148             }
149 3         14 return undef;
150             }
151              
152             sub _requires {
153 12     12   77 my($file, $feature, $library) = @_;
154 12 100       40 return if exists $INC{$file};
155 1 50       2 unless(eval { require $file }) {
  1         436  
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   5221 my($self, $url) = @_;
176 35 100       584 $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         315 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 12 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       25 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     20 $self->{no_proxy} = $ENV{NO_PROXY} || '';
216 8         22 $self;
217             }
218              
219             sub request {
220 67     67 1 20054977 my $self = shift;
221 67         533 my %args = @_;
222              
223 67         570 my $timeout_at = time + $self->{timeout};
224              
225 67         178 my ($scheme, $username, $password, $host, $port, $path_query);
226 67 100       269 if (defined(my $url = $args{url})) {
227 23         148 ($scheme, $username, $password, $host, $port, $path_query) = $self->_parse_url($url);
228             }
229             else {
230 44         177 ($scheme, $host, $port, $path_query) = @args{qw/scheme host port path_query/};
231 44 50       183 if (not defined $host) {
232 0         0 Carp::croak("Missing host name in arguments");
233             }
234             }
235              
236 67 100 66     346 if (not defined $scheme) {
    100          
237 44         154 $scheme = 'http';
238             } elsif($scheme ne 'http' && $scheme ne 'https') {
239 6         550 Carp::croak("Unsupported scheme: $scheme");
240             }
241              
242 61 50       221 my $default_port = $scheme eq 'http'
243             ? 80
244             : 443;
245 61 100       310 if(not defined $port) {
246 1         2 $port = $default_port;
247             }
248 61 100       184 if(not defined $path_query) {
249 13         30 $path_query = '/';
250             }
251              
252 61 100       243 unless (substr($path_query, 0, 1) eq '/') {
253 3         19 $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       384 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         178 my $proxy = $self->{proxy};
264 61         205 my $no_proxy = $self->{no_proxy};
265 61 50 33     216 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         1046 local $SIG{PIPE} = 'IGNORE';
272 61         408 my $sock = $self->{connection_pool}->steal($host, $port);
273 61         127 my $in_keepalive;
274 61 100       163 if (defined $sock) {
275 26 100       84 if ($self->_do_select(0, $sock, 0)) {
276 2         121 close $sock;
277 2         12 undef $sock;
278             } else {
279 24         53 $in_keepalive = 1;
280             }
281             }
282 61 100       159 if(!$in_keepalive) {
283 37         71 my $err_reason;
284 37 50       103 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       104 if ($scheme eq 'http') {
309 37         368 ($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       153 return $self->_r500($err_reason)
317             unless $sock;
318             }
319              
320             # keep request dump
321 60         263 my ($req_headers, $req_content) = ("", "");
322              
323             # write request
324 60   100     344 my $method = $args{method} || 'GET';
325 60         131 my $connection_header = $self->{connection_header};
326 60         108 my $cookie_jar = $self->{cookie_jar};
327             {
328 60         89 my @headers = @{$self->{headers}};
  60         97  
  60         214  
329 60 100       184 $connection_header = 'close'
330             if $method eq 'HEAD';
331 60 100       195 if (my $in_headers = $args{headers}) {
332 14         46 for (my $i = 0; $i < @$in_headers; $i += 2) {
333 18         38 my $name = $in_headers->[$i];
334 18 50       78 if (lc($name) eq 'connection') {
335 0         0 $connection_header = $in_headers->[$i + 1];
336             } else {
337 18         66 push @headers, $name, $in_headers->[$i + 1];
338             }
339             }
340             }
341 60         209 unshift @headers, 'Connection', $connection_header;
342 60 50       180 if (exists $self->{proxy_authorization}) {
343 0         0 push @headers, 'Proxy-Authorization', $self->{proxy_authorization};
344             }
345 60 100       283 if (defined $username) {
346 6         18 _requires('URI/Escape.pm', 'Basic auth');
347 6         41 my($unescape_username) = URI::Escape::uri_unescape($username);
348 6         103 my($unescape_password) = URI::Escape::uri_unescape($password);
349 6         53 _requires('MIME/Base64.pm', 'Basic auth');
350 6         733 push @headers, 'Authorization', 'Basic ' . MIME::Base64::encode_base64("${unescape_username}:${unescape_password}","");
351             }
352              
353             # set Cookie header
354 60 50       161 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         139 my $content = $args{content};
372 60         130 my $content_is_fh = 0;
373 60 100       148 if(defined $content) {
374 3         14 $content_is_fh = Scalar::Util::openhandle($content);
375 3 50 33     28 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         7 my $content_length;
384 3 50       11 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         8 $content_length = length($content);
399             }
400 3         16 push @headers, 'Content-Length' => $content_length;
401             }
402             }
403              
404             # finally, set Host header
405 60 100       305 my $request_target = ($port == $default_port) ? $host : "$host:$port";
406 60         221 push @headers, 'Host' => $request_target;
407              
408 60 50 33     249 my $request_uri = $proxy && $scheme eq 'http' ? "$scheme://$request_target$path_query" : $path_query;
409              
410 60         171 my $p = "$method $request_uri HTTP/1.1\015\012";
411 60         217 for (my $i = 0; $i < @headers; $i += 2) {
412 207         390 my $val = $headers[ $i + 1 ];
413             # the de facto standard way to handle [\015\012](by kazuho-san)
414 207         352 $val =~ tr/\015\012/ /;
415 207         607 $p .= "$headers[$i]: $val\015\012";
416             }
417 60         121 $p .= "\015\012";
418 60 50       224 $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       229 if ($self->{capture_request}) {
423 1         2 $req_headers = $p;
424             }
425              
426 60 100       297 if (defined $content) {
427 3 50       11 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       18 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         234 my $buf = '';
463 60         389 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     430 my $special_headers = $args{special_headers} || +{};
469 60         265 $special_headers->{'connection'} = '';
470 60         135 $special_headers->{'content-length'} = undef;
471 60         133 $special_headers->{'location'} = '';
472 60         146 $special_headers->{'content-encoding'} = '';
473 60         178 $special_headers->{'transfer-encoding'} = '';
474 60         82 LOOP: while (1) {
475             my $n = $self->read_timeout($sock,
476 212         669 \$buf, $self->{bufsize}, length($buf), $timeout_at);
477 212 100       559 if(!$n) { # error or eof
478 3 50 33     49 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       14 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         311 my $ret;
491             ( $ret, $res_minor_version, $res_status, $res_msg, $res_headers )
492             = HTTP::Parser::XS::parse_http_response( $buf,
493 209         1465 $self->{header_format}, $special_headers );
494 209 50       687 if ( $ret == -1 ) {
    100          
495 0         0 return $self->_r500("Invalid HTTP response");
496             }
497             elsif ( $ret == -2 ) {
498             # partial response
499 147         264 next LOOP;
500             }
501             else {
502             # succeeded
503 62         189 $rest_header = substr( $buf, $ret );
504 62 100       284 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         11 $buf = $rest_header;
509 5         10 next LOOP;
510             }
511 57         142 last LOOP;
512             }
513             }
514             }
515              
516 57         97 my $max_redirects = 0;
517 57         97 my $do_redirect = undef;
518 57 50       144 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[1237]$/;
521             }
522              
523 57         145 my $res_content = '';
524 57 50       156 unless ($do_redirect) {
525 57 50       252 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       203 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         135 my $chunked = ($special_headers->{'transfer-encoding'} eq 'chunked');
541 57         117 my $content_length = $special_headers->{'content-length'};
542 57 100 100     644 if (defined($content_length) && $content_length !~ /\A[0-9]+\z/) {
543 1         6 return $self->_r500("Bad Content-Length: ${content_length}");
544             }
545              
546 56 100 33     670 unless ($method eq 'HEAD'
      66        
      66        
      100        
547             || ($res_status < 200 && $res_status >= 100)
548             || $res_status == 204
549             || $res_status == 304) {
550 49         103 my @err;
551 49 100       116 if ( $chunked ) {
552 7         41 @err = $self->_read_body_chunked($sock,
553             \$res_content, $rest_header, $timeout_at);
554             } else {
555 42         88 $res_content .= $rest_header;
556 42 100 66     185 if (ref $res_content || !defined($content_length)) {
557 1         4 @err = $self->_read_body_normal($sock,
558             \$res_content, length($rest_header),
559             $content_length, $timeout_at);
560             } else {
561 41         196 @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       161 if(@err) {
567 1         149 return @err;
568             }
569             }
570              
571             # manage connection cache (i.e. keep-alive)
572 55 100       187 if (lc($connection_header) eq 'keep-alive') {
573 54         126 my $connection = lc $special_headers->{'connection'};
574 54 100 66     370 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         297 $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         594 undef $sock;
584              
585             # process 'Set-Cookie' header.
586 55 50       163 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       122 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.
616 0 0 0     0 return $self->request(
617             @_,
618             method => ($res_status eq '301' or $res_status eq '307') ? $method : 'GET',
619             url => $location,
620             max_redirects => $max_redirects - 1,
621             );
622             }
623              
624             # return response.
625              
626 55 50       140 if (ref $res_content) {
627 0         0 $res_content = $res_content->get_response_string;
628             }
629              
630             return (
631 55         1119 $res_minor_version, $res_status, $res_msg, $res_headers, $res_content,
632             $req_headers, $req_content, undef, undef, [$scheme, $username, $password, $host, $port, $path_query],
633             );
634             }
635              
636             # connects to $host:$port and returns $socket
637             sub connect :method {
638 37     37 0 127 my($self, $host, $port, $timeout_at) = @_;
639 37         55 my $sock;
640              
641 37         131 my $timeout = $timeout_at - time;
642 37 50       166 return (undef, "Failed to resolve host name: timeout")
643             if $timeout <= 0;
644 37         135 my ($sock_addr, $err_reason) = $self->_get_address($host, $port, $timeout);
645 37 100 33     2787 return (undef, "Cannot resolve host name: $host (port: $port), " . ($err_reason || $!))
646             unless $sock_addr;
647              
648 36 50       1060 RETRY:
649             socket($sock, Socket::sockaddr_family($sock_addr), SOCK_STREAM, 0)
650             or Carp::croak("Cannot create socket: $!");
651 36         281 _set_sockopts($sock);
652 36 50 50     3084 if (connect($sock, $sock_addr)) {
    50          
653             # connected
654             } elsif ($! == EINPROGRESS || (WIN32 && $! == EWOULDBLOCK)) {
655 36 50       291 $self->do_select(1, $sock, $timeout_at)
656             or return (undef, "Cannot connect to ${host}:${port}: timeout");
657             # connected
658             } else {
659 0 0 0     0 if ($! == EINTR && ! $self->{stop_if}->()) {
660 0         0 close $sock;
661 0         0 goto RETRY;
662             }
663 0         0 return (undef, "Cannot connect to ${host}:${port}: $!");
664             }
665 36         122 $sock;
666             }
667              
668             sub _get_address {
669 37     37   109 my ($self, $host, $port, $timeout) = @_;
670 37 100       107 if ($self->{get_address}) {
671 1         3 return $self->{get_address}->($host, $port, $timeout);
672             }
673             # default rule (TODO add support for IPv6)
674 36 100       106 my $iaddr = $self->{inet_aton}->($host, $timeout)
675             or return (undef, $!);
676 35         275 pack_sockaddr_in($port, $iaddr);
677             }
678              
679             sub _ssl_opts {
680 0     0   0 my $self = shift;
681 0         0 my $ssl_opts = $self->{ssl_opts};
682 0 0       0 unless (exists $ssl_opts->{SSL_verify_mode}) {
683             # set SSL_VERIFY_PEER as default.
684 0         0 $ssl_opts->{SSL_verify_mode} = IO::Socket::SSL::SSL_VERIFY_PEER();
685 0 0       0 unless (exists $ssl_opts->{SSL_verifycn_scheme}) {
686 0         0 $ssl_opts->{SSL_verifycn_scheme} = 'www'
687             }
688             }
689 0 0       0 if ($ssl_opts->{SSL_verify_mode}) {
690 0 0 0     0 unless (exists $ssl_opts->{SSL_ca_file} || exists $ssl_opts->{SSL_ca_path}) {
691 0         0 require Mozilla::CA;
692 0         0 $ssl_opts->{SSL_ca_file} = Mozilla::CA::SSL_ca_file();
693             }
694             }
695 0         0 $ssl_opts;
696             }
697              
698             # connect SSL socket.
699             # You can override this method in your child class, if you want to use Crypt::SSLeay or some other library.
700             # @return file handle like object
701             sub connect_ssl {
702 0     0 0 0 my ($self, $host, $port, $timeout_at) = @_;
703 0         0 _requires('IO/Socket/SSL.pm', 'SSL');
704              
705 0         0 my ($sock, $err_reason) = $self->connect($host, $port, $timeout_at);
706 0 0       0 return (undef, $err_reason)
707             unless $sock;
708              
709 0         0 my $timeout = $timeout_at - time;
710 0 0       0 return (undef, "Cannot create SSL connection: timeout")
711             if $timeout <= 0;
712              
713 0         0 my $ssl_opts = $self->_ssl_opts;
714 0 0       0 IO::Socket::SSL->start_SSL(
715             $sock,
716             PeerHost => $host,
717             PeerPort => $port,
718             Timeout => $timeout,
719             %$ssl_opts,
720             ) or return (undef, "Cannot create SSL connection: " . IO::Socket::SSL::errstr());
721 0         0 _set_sockopts($sock);
722 0         0 $sock;
723             }
724              
725             sub connect_ssl_over_proxy {
726 0     0 0 0 my ($self, $proxy_host, $proxy_port, $host, $port, $timeout_at, $proxy_authorization) = @_;
727 0         0 _requires('IO/Socket/SSL.pm', 'SSL');
728              
729 0         0 my $sock = $self->connect($proxy_host, $proxy_port, $timeout_at);
730              
731 0         0 my $p = "CONNECT $host:$port HTTP/1.0\015\012Server: $host\015\012";
732 0 0       0 if (defined $proxy_authorization) {
733 0         0 $p .= "Proxy-Authorization: $proxy_authorization\015\012";
734             }
735 0         0 $p .= "\015\012";
736 0 0       0 $self->write_all($sock, $p, $timeout_at)
737             or return $self->_r500(
738             "Failed to send HTTP request to proxy: " . _strerror_or_timeout());
739 0         0 my $buf = '';
740             my $read = $self->read_timeout($sock,
741 0         0 \$buf, $self->{bufsize}, length($buf), $timeout_at);
742 0 0       0 if (not defined $read) {
    0          
    0          
743 0         0 return (undef, "Cannot read proxy response: " . _strerror_or_timeout());
744             } elsif ( $read == 0 ) { # eof
745 0         0 return (undef, "Unexpected EOF while reading proxy response");
746             } elsif ( $buf !~ /^HTTP\/1\.[0-9] 200 .+\015\012/ ) {
747 0         0 return (undef, "Invalid HTTP Response via proxy");
748             }
749              
750 0         0 my $timeout = $timeout_at - time;
751 0 0       0 return (undef, "Cannot start SSL connection: timeout")
752             if $timeout_at <= 0;
753              
754 0         0 my $ssl_opts = $self->_ssl_opts;
755 0 0       0 unless (exists $ssl_opts->{SSL_verifycn_name}) {
756 0         0 $ssl_opts->{SSL_verifycn_name} = $host;
757             }
758             IO::Socket::SSL->start_SSL(
759 0 0       0 $sock,
760             PeerHost => $host,
761             PeerPort => $port,
762             Timeout => $timeout,
763             %$ssl_opts
764             ) or return (undef, "Cannot start SSL connection: " . IO::Socket::SSL::errstr());
765 0         0 _set_sockopts($sock); # just in case (20101118 kazuho)
766 0         0 $sock;
767             }
768              
769             sub _read_body_chunked {
770 7     7   25 my ($self, $sock, $res_content, $rest_header, $timeout_at) = @_;
771              
772 7         13 my $buf = $rest_header;
773 7         11 READ_LOOP: while (1) {
774 2605 100       13124 if (
775             my ( $header, $next_len ) = (
776             $buf =~
777             m{\A ( # header
778             ( [0-9a-fA-F]+ ) # next_len (hex number)
779             (?:;
780             $HTTP_TOKEN
781             =
782             (?: $HTTP_TOKEN | $HTTP_QUOTED_STRING )
783             )* # optional chunk-extensions
784             [ ]* # www.yahoo.com adds spaces here.
785             # Is this valid?
786             \015\012 # CR+LF
787             ) }xmso
788             )
789             )
790             {
791 2082         3957 $buf = substr($buf, length($header)); # remove header from buf
792 2082         2776 $next_len = hex($next_len);
793 2082 100       3250 if ($next_len == 0) {
794 6         18 last READ_LOOP;
795             }
796              
797             # +2 means trailing CRLF
798 2076         3458 READ_CHUNK: while ( $next_len+2 > length($buf) ) {
799             my $n = $self->read_timeout( $sock,
800 1026         2350 \$buf, $self->{bufsize}, length($buf), $timeout_at );
801 1026 50       2642 if (!$n) {
802 0 0       0 return $self->_r500(
803             !defined($n)
804             ? "Cannot read chunk: " . _strerror_or_timeout()
805             : "Unexpected EOF while reading packets"
806             );
807             }
808             }
809 2076         3671 $$res_content .= substr($buf, 0, $next_len);
810 2076         3142 $buf = substr($buf, $next_len+2);
811 2076 100       3564 if (length($buf) > 0) {
812 1820         3016 next; # re-parse header
813             }
814             }
815              
816             my $n = $self->read_timeout( $sock,
817 779         1954 \$buf, $self->{bufsize}, length($buf), $timeout_at );
818 779 100       1670 if (!$n) {
819 1 50       7 return $self->_r500(
820             !defined($n)
821             ? "Cannot read chunk: " . _strerror_or_timeout()
822             : "Unexpected EOF while reading packets"
823             );
824             }
825             }
826             # read last CRLF
827 6         31 return $self->_read_body_normal(
828             $sock, \$buf, length($buf), 2, $timeout_at);
829             }
830              
831             sub _read_body_normal {
832 7     7   19 my ($self, $sock, $res_content, $nread, $res_content_length, $timeout_at)
833             = @_;
834 7   100     49 while (!defined($res_content_length) || $res_content_length != $nread) {
835             my $n = $self->read_timeout( $sock,
836 2         11 \my $buf, $self->{bufsize}, 0, $timeout_at );
837 2 100       10 if (!$n) {
838 1 50       3 last if ! defined($res_content_length);
839 0 0       0 return $self->_r500(
840             !defined($n)
841             ? "Cannot read content body: " . _strerror_or_timeout()
842             : "Unexpected EOF while reading content body"
843             );
844             }
845 1         3 $$res_content .= $buf;
846 1         6 $nread += $n;
847             }
848 7         24 return;
849             }
850              
851             # This function loads all content at once if it's possible. Since $res_content is just a plain scalar.
852             # Buffering is not needed.
853             sub _read_body_normal_to_string_buffer {
854 41     41   170 my ($self, $sock, $res_content, $nread, $res_content_length, $timeout_at)
855             = @_;
856 41         134 while ($res_content_length != $nread) {
857 31         77 my $n = $self->read_timeout( $sock,
858             $res_content, $res_content_length, $nread, $timeout_at );
859 31 50       133 if (!$n) {
860 0 0       0 return $self->_r500(
861             !defined($n)
862             ? "Cannot read content body: " . _strerror_or_timeout()
863             : "Unexpected EOF while reading content body"
864             );
865             }
866 31         78 $nread += $n;
867             }
868 41         100 return;
869             }
870              
871             # returns true if the socket is ready to read, false if timeout has occurred ($! will be cleared upon timeout)
872             sub do_select {
873 95     95 0 250 my($self, $is_write, $sock, $timeout_at) = @_;
874 95         284 my $now = time;
875 95         218 my $inactivity_timeout_at = $now + $self->{inactivity_timeout};
876 95 50       252 $timeout_at = $inactivity_timeout_at
877             if $timeout_at > $inactivity_timeout_at;
878             # wait for data
879 95         143 while (1) {
880 98         177 my $timeout = $timeout_at - $now;
881 98 50       226 if ($timeout <= 0) {
882 0         0 $! = 0;
883 0         0 return 0;
884             }
885 98         252 my $nfound = $self->_do_select($is_write, $sock, $timeout);
886 98 100       4455 return 1 if $nfound > 0;
887 6 100 33     97 return 0 if $nfound == -1 && $! == EINTR && $self->{stop_if}->();
      66        
888 3         33 $now = time;
889             }
890 0         0 die 'not reached';
891             }
892              
893             sub _do_select {
894 124     124   266 my($self, $is_write, $sock, $timeout) = @_;
895 124         176 my($rfd, $wfd);
896 124         240 my $efd = '';
897 124         527 vec($efd, fileno($sock), 1) = 1;
898 124 100       342 if ($is_write) {
899 36         78 $wfd = $efd;
900             } else {
901 88         147 $rfd = $efd;
902             }
903 124         18047464 my $nfound = select($rfd, $wfd, $efd, $timeout);
904 124         745 return $nfound;
905             }
906              
907             # returns (positive) number of bytes read, or undef if the socket is to be closed
908             sub read_timeout {
909 2050     2050 0 3497 my ($self, $sock, $buf, $len, $off, $timeout_at) = @_;
910 2050         2550 my $ret;
911              
912             # NOTE: select-read-select may get stuck in SSL,
913             # so we use read-select-read instead.
914 2050         2352 while(1) {
915             # try to do the IO
916 2106 100       11397 defined($ret = sysread($sock, $$buf, $len, $off))
917             and return $ret;
918 59 50 33     547 if ($! == EAGAIN || $! == EWOULDBLOCK || (WIN32 && $! == EISCONN)) {
    0 50        
919             # passthru
920             } elsif ($! == EINTR) {
921 0 0       0 return undef if $self->{stop_if}->();
922             # otherwise passthru
923             } else {
924 0         0 return undef;
925             }
926             # on EINTER/EAGAIN/EWOULDBLOCK
927 59 100       189 $self->do_select(0, $sock, $timeout_at) or return undef;
928             }
929             }
930              
931             # returns (positive) number of bytes written, or undef if the socket is to be closed
932             sub write_timeout {
933 60     60 0 166 my ($self, $sock, $buf, $len, $off, $timeout_at) = @_;
934 60         112 my $ret;
935 60         153 while(1) {
936             # try to do the IO
937 60 50       3184 defined($ret = syswrite($sock, $buf, $len, $off))
938             and return $ret;
939 0 0 0     0 if ($! == EAGAIN || $! == EWOULDBLOCK || (WIN32 && $! == EISCONN)) {
    0 0        
940             # passthru
941             } elsif ($! == EINTR) {
942 0 0       0 return undef if $self->{stop_if}->();
943             # otherwise passthru
944             } else {
945 0         0 return undef;
946             }
947 0 0       0 $self->do_select(1, $sock, $timeout_at) or return undef;
948             }
949             }
950              
951             # writes all data in buf and returns number of bytes written or undef if failed
952             sub write_all {
953 60     60 0 177 my ($self, $sock, $buf, $timeout_at) = @_;
954 60         101 my $off = 0;
955 60         182 while (my $len = length($buf) - $off) {
956 60 50       181 my $ret = $self->write_timeout($sock, $buf, $len, $off, $timeout_at)
957             or return undef;
958 60         301 $off += $ret;
959             }
960 60         221 return $off;
961             }
962              
963              
964             sub _r500 {
965 6     6   20 my($self, $message) = @_;
966 6         1581 $message = Carp::shortmess($message); # add lineno and filename
967 6         837 return(0, 500, "Internal Response: $message",
968             [
969             'Content-Length' => length($message),
970             'X-Internal-Response' => 1,
971             # XXX ^^ EXPERIMENTAL header. Do not depend to this.
972             ], $message
973             );
974             }
975              
976             sub _strerror_or_timeout {
977 3 50   3   25 $! != 0 ? "$!" : 'timeout';
978             }
979              
980             sub _set_sockopts {
981 36     36   71 my $sock = shift;
982              
983 36 50       210 setsockopt( $sock, IPPROTO_TCP, TCP_NODELAY, 1 )
984             or Carp::croak("Failed to setsockopt(TCP_NODELAY): $!");
985 36         67 if (WIN32) {
986             if (ref($sock) ne 'IO::Socket::SSL') {
987             my $tmp = 1;
988             ioctl( $sock, 0x8004667E, \$tmp )
989             or Carp::croak("Cannot set flags for the socket: $!");
990             }
991             } else {
992 36 50       148 my $flags = fcntl( $sock, F_GETFL, 0 )
993             or Carp::croak("Cannot get flags for the socket: $!");
994 36 50       183 $flags = fcntl( $sock, F_SETFL, $flags | O_NONBLOCK )
995             or Carp::croak("Cannot set flags for the socket: $!");
996             }
997              
998             {
999             # no buffering
1000 36         69 my $orig = select();
  36         121  
1001 36         88 select($sock); $|=1;
  36         99  
1002 36         115 select($orig);
1003             }
1004              
1005 36         116 binmode $sock;
1006             }
1007              
1008             # You can override this method if you want to use more powerful matcher.
1009             sub match_no_proxy {
1010 0     0 0   my ( $self, $no_proxy, $host ) = @_;
1011              
1012             # ref. curl.1.
1013             # list of host names that shouldn't go through any proxy.
1014             # If set to a asterisk '*' only, it matches all hosts.
1015 0 0         if ( $no_proxy eq '*' ) {
1016 0           return 1;
1017             }
1018             else {
1019 0           for my $pat ( split /\s*,\s*/, lc $no_proxy ) {
1020 0 0         if ( $host =~ /\Q$pat\E$/ ) { # suffix match(same behavior with LWP)
1021 0           return 1;
1022             }
1023             }
1024             }
1025 0           return 0;
1026             }
1027              
1028             # utility class
1029             {
1030             package # hide from pause
1031             Furl::FileStream;
1032 45     45   38608 use overload '.=' => 'append', fallback => 1;
  45         35168  
  45         268  
1033             sub new {
1034 0     0     my ($class, $fh) = @_;
1035 0           bless {fh => $fh}, $class;
1036             }
1037             sub append {
1038 0     0     my($self, $partial) = @_;
1039 0           print {$self->{fh}} $partial;
  0            
1040 0           return $self;
1041             }
1042 0     0     sub get_response_string { undef }
1043             }
1044              
1045             {
1046             package # hide from pause
1047             Furl::CallbackStream;
1048 45     45   7484 use overload '.=' => 'append', fallback => 1;
  45         94  
  45         156  
1049             sub new {
1050 0     0     my ($class, $cb) = @_;
1051 0           bless {cb => $cb}, $class;
1052             }
1053             sub append {
1054 0     0     my($self, $partial) = @_;
1055 0           $self->{cb}->($partial);
1056 0           return $self;
1057             }
1058 0     0     sub get_response_string { undef }
1059             }
1060              
1061             1;
1062             __END__