--- AnyEvent-HTTP/HTTP.pm 2008/10/27 11:09:54 1.33 +++ AnyEvent-HTTP/HTTP.pm 2009/06/11 12:46:01 1.39 @@ -50,7 +50,7 @@ use base Exporter::; -our $VERSION = '1.05'; +our $VERSION = '1.12'; our @EXPORT = qw(http_get http_post http_head http_request); @@ -239,6 +239,9 @@ _slot_schedule $_[0]; } +our $qr_nl = qr<\015?\012>; +our $qr_nlnl = qr<\015?\012\015?\012>; + sub http_request($$@) { my $cb = pop; my ($method, $url, %arg) = @_; @@ -319,10 +322,10 @@ my ($rhost, $rport, $rscheme, $rpath); # request host, port, path if ($proxy) { - ($rhost, $rport, $rscheme, $rpath) = (@$proxy, $url); + ($rpath, $rhost, $rport, $rscheme) = ($url, @$proxy); # don't support https requests over https-proxy transport, - # can't be done with tls as spec'ed. + # can't be done with tls as spec'ed, unless you double-encrypt. $rscheme = "http" if $uscheme eq "https" && $rscheme eq "https"; } else { ($rhost, $rport, $rscheme, $rpath) = ($uhost, $uport, $uscheme, $upath); @@ -341,25 +344,28 @@ $state{connect_guard} = AnyEvent::Socket::tcp_connect $rhost, $rport, sub { $state{fh} = shift or return $cb->(undef, { Status => 599, Reason => "$!", URL => $url }); + pop; # free memory, save a tree - delete $state{connect_guard}; # reduce memory usage, save a tree + return unless delete $state{connect_guard}; # get handle $state{handle} = new AnyEvent::Handle - fh => $state{fh}; + fh => $state{fh}, + timeout => $timeout; # limit the number of persistent connections + # keepalive not yet supported if ($KA_COUNT{$_[1]} < $MAX_PERSISTENT_PER_HOST) { ++$KA_COUNT{$_[1]}; - $state{handle}{ka_count_guard} = AnyEvent::Util::guard { --$KA_COUNT{$_[1]} }; + $state{handle}{ka_count_guard} = AnyEvent::Util::guard { + --$KA_COUNT{$_[1]} + }; $hdr{connection} = "keep-alive"; - delete $hdr{connection}; # keep-alive not yet supported } else { delete $hdr{connection}; } # (re-)configure handle - $state{handle}->timeout ($timeout); $state{handle}->on_error (sub { my $errno = "$!"; %state = (); @@ -374,7 +380,7 @@ # handle actual, non-tunneled, request my $handle_actual_request = sub { - $state{handle}->starttls ("connect") if $uscheme eq "https"; + $state{handle}->starttls ("connect") if $uscheme eq "https" && !exists $state{handle}{tls}; # send request $state{handle}->push_write ( @@ -387,7 +393,7 @@ %hdr = (); # reduce memory usage, save a kitten # status line - $state{handle}->push_read (line => qr/\015?\012/, sub { + $state{handle}->push_read (line => $qr_nl, sub { $_[1] =~ /^HTTP\/([0-9\.]+) \s+ ([0-9]{3}) (?: \s+ ([^\015\012]*) )?/ix or return (%state = (), $cb->(undef, { Status => 599, Reason => "invalid server response ($_[1])", URL => $url })); @@ -399,7 +405,7 @@ ); # headers, could be optimized a bit - $state{handle}->unshift_read (line => qr/\015?\012\015?\012/, sub { + $state{handle}->unshift_read (line => $qr_nlnl, sub { for ("$_[1]\012") { y/\015//d; # weed out any \015, as they show up in the weirdest of places. @@ -422,10 +428,7 @@ for values %hdr; my $finish = sub { - # TODO: use destroy method, when/if available - #$state{handle}->destroy; - $state{handle}->on_eof (undef); - $state{handle}->on_error (undef); + $state{handle}->destroy; %state = (); # set-cookie processing @@ -524,7 +527,9 @@ # too bad, need to read until we get an error or EOF, # no way to detect winged data. $_[0]->on_error (sub { - $finish->($_[0]{rbuf}, \%hdr); + # delete ought to be more efficient, as we would have to make + # a copy otherwise as $_[0] gets destroyed. + $finish->(delete $_[0]{rbuf}, \%hdr); }); $_[0]->on_eof (undef); $_[0]->on_read (sub { }); @@ -540,7 +545,7 @@ # maybe re-use $uauthority with patched port? $state{handle}->push_write ("CONNECT $uhost:$uport HTTP/1.0\015\012Host: $uhost\015\012\015\012"); - $state{handle}->push_read (line => qr/\015?\012\015?\012/, sub { + $state{handle}->push_read (line => $qr_nlnl, sub { $_[1] =~ /^HTTP\/([0-9\.]+) \s+ ([0-9]{3}) (?: \s+ ([^\015\012]*) )?/ix or return (%state = (), $cb->(undef, { Status => 599, Reason => "invalid proxy connect response ($_[1])", URL => $url })); @@ -638,6 +643,9 @@ Marc Lehmann http://home.schmorp.de/ +With many thanks to Дмитрий Шалашов, who provided countless +testcases and bugreports. + =cut 1