--- AnyEvent-HTTP/HTTP.pm 2009/07/05 23:50:59 1.41 +++ AnyEvent-HTTP/HTTP.pm 2009/08/05 16:09:10 1.48 @@ -43,14 +43,14 @@ use Errno (); -use AnyEvent 4.452 (); +use AnyEvent 4.8 (); use AnyEvent::Util (); use AnyEvent::Socket (); use AnyEvent::Handle (); use base Exporter::; -our $VERSION = '1.12'; +our $VERSION = '1.42'; our @EXPORT = qw(http_get http_post http_head http_request); @@ -61,7 +61,7 @@ our $TIMEOUT = 300; # changing these is evil -our $MAX_PERSISTENT_PER_HOST = 2; +our $MAX_PERSISTENT_PER_HOST = 0; our $MAX_PER_HOST = 4; our $PROXY; @@ -96,9 +96,9 @@ object at least alive until the callback get called. If the object gets destroyed before the callbakc is called, the request will be cancelled. -The callback will be called with the response data as first argument -(or C if it wasn't available due to errors), and a hash-ref with -response headers as second argument. +The callback will be called with the response body data as first argument +(or C if an error occured), and a hash-ref with response headers as +second argument. All the headers in that hash are lowercased. In addition to the response headers, the "pseudo-headers" C, C and C @@ -140,7 +140,9 @@ The request headers to use. Currently, C may provide its own C, C, C and C headers -and will provide defaults for C and C. +and will provide defaults for C and C (this can be +suppressed by using C for these headers in which case they won't be +send at all). =item timeout => $seconds @@ -152,7 +154,7 @@ Use the given http proxy for all requests. If not specified, then the default proxy (as specified by C<$ENV{http_proxy}>) is used. -C<$scheme> must be either missing or C for HTTP, or C for +C<$scheme> must be either missing, C for HTTP or C for HTTPS. =item body => $string @@ -188,7 +190,7 @@ The default for this option is C, which could be interpreted as "give me the page, no matter what". -=item on_header => $callback->($hdr) +=item on_header => $callback->($headers) When specified, this callback will be called with the header hash as soon as headers have been successfully received from the remote server (not on @@ -202,21 +204,31 @@ content, which, if it is supposed to be rare, can be faster than first doing a C request. -=item on_body => $callback->($data, $hdr) +Example: cancel the request unless the content-type is "text/html". -When specified, all body data will be "filtered" through this callback. + on_header => sub { + $_[0]{"content-type"} =~ /^text\/html\s*(?:;|$)/ + }, -The callback will incrementally receive body data, and is supposed to -return it or a modified version of it (empty strings are valid returns). +=item on_body => $callback->($partial_body, $headers) -If the callback returns C, then the request will be cancelled. +When specified, all body data will be passed to this callback instead of +to the completion callback. The completion callback will get the empty +string instead of the body data. -This callback is useful when you want to do some processing on the data, -or the data is too large to be held in memory (so the callback writes it -to a file and returns the empty string) and so on. +It has to return either true (in which case AnyEvent::HTTP will continue), +or false, in which case AnyEvent::HTTP will cancel the download (and call +the completion callback with an error code of C<598>). + +This callback is useful when the data is too large to be held in memory +(so the callback writes it to a file) or when only some information should +be extracted, or when the body should be processed incrementally. It is usually preferred over doing your own body handling via -C. +C, but in case of streaming APIs, where HTTP is +only used to create a connection, C is the better +alternative, as it allows you to install your own event handler, reducing +resource usage. =item want_body_handle => $enable @@ -238,7 +250,7 @@ push-style twitter API which starts a JSON/XML stream). If you think you need this, first have a look at C, to see if -that doesn'T solve your problem in a better way. +that doesn't solve your problem in a better way. =back @@ -304,8 +316,8 @@ _slot_schedule $_[0]; } -our $qr_nl = qr<\015?\012>; -our $qr_nlnl = qr<\015?\012\015?\012>; +our $qr_nl = qr{\015?\012}; +our $qr_nlnl = qr{(? 1, sslv2 => 1 }; our $TLS_CTX_HIGH = { cache => 1, verify => 1, verify_peername => "https" }; @@ -350,6 +362,8 @@ my $uhost = $1; $uport = $2 if defined $2; + $hdr{host} = defined $2 ? "$uhost:$2" : "$uhost"; + $uhost =~ s/^\[(.*)\]$/$1/; $upath .= "?$query" if length $query; @@ -391,6 +405,8 @@ if ($proxy) { ($rpath, $rhost, $rport, $rscheme) = ($url, @$proxy); + $rscheme = "http" unless defined $rscheme; + # don't support https requests over https-proxy transport, # can't be done with tls as spec'ed, unless you double-encrypt. $rscheme = "http" if $uscheme eq "https" && $rscheme eq "https"; @@ -398,10 +414,10 @@ ($rhost, $rport, $rscheme, $rpath) = ($uhost, $uport, $uscheme, $upath); } - $hdr{"user-agent"} ||= $USERAGENT; - $hdr{referer} ||= "$uscheme://$uauthority$upath"; # leave out fragment and query string, just a heuristic + # leave out fragment and query string, just a heuristic + $hdr{referer} ||= "$uscheme://$uauthority$upath" unless exists $hdr{referer}; + $hdr{"user-agent"} ||= $USERAGENT unless exists $hdr{"user-agent"}; - $hdr{host} = "$uhost:$uport"; $hdr{"content-length"} = length $arg{body}; my %state = (connect_guard => 1); @@ -413,7 +429,12 @@ $state{connect_guard} = AnyEvent::Socket::tcp_connect $rhost, $rport, sub { $state{fh} = shift - or return (%state = (), $cb->(undef, { Status => 599, Reason => "$!", URL => $url })); + or do { + my $err = "$!"; + %state = (); + return $cb->(undef, { Status => 599, Reason => $err, URL => $url }); + }; + pop; # free memory, save a tree return unless delete $state{connect_guard}; @@ -456,7 +477,7 @@ # send request $state{handle}->push_write ( "$method $rpath HTTP/1.0\015\012" - . (join "", map "\u$_: $hdr{$_}\015\012", keys %hdr) + . (join "", map "\u$_: $hdr{$_}\015\012", grep defined $hdr{$_}, keys %hdr) . "\015\012" . (delete $arg{body}) ); @@ -477,7 +498,7 @@ # headers, could be optimized a bit $state{handle}->unshift_read (line => $qr_nlnl, sub { - for ("$_[1]\012") { + for ("$_[1]") { y/\015//d; # weed out any \015, as they show up in the weirdest of places. # things seen, not parsed: @@ -485,7 +506,7 @@ $hdr{lc $1} .= ",$2" while /\G - ([^:\000-\037]+): + ([^:\000-\037]*): [\011\040]* ((?: [^\012]+ | \012[\011\040] )*) \012 @@ -584,7 +605,7 @@ } } - if ($redirect) { + if ($redirect && exists $hdr{location}) { # we ignore any errors, as it is very common to receive # Content-Length != 0 but no actual body # we also access %hdr, as $_[1] might be an erro @@ -599,7 +620,7 @@ if (!$redirect && $arg{on_header} && !$arg{on_header}(\%hdr)) { $finish->(undef, { Status => 598, Reason => "Request cancelled by on_header", URL => $url }); } elsif ( - $hdr{Status} =~ /^(?:1..|204|304)$/ + $hdr{Status} =~ /^(?:1..|[23]04)$/ or $method eq "HEAD" or (defined $len && !$len) ) { @@ -649,7 +670,7 @@ }); } else { $_[0]->on_error (sub { - $! == Errno::EPIPE + $! == Errno::EPIPE || !$! ? $finish->(delete $_[0]{rbuf}, \%hdr) : $finish->(undef, { Status => 599, Reason => $_[2], URL => $url }); }); @@ -727,17 +748,14 @@ The default value for the C header (the default is C). -=item $AnyEvent::HTTP::MAX_PERSISTENT - -The maximum number of persistent connections to keep open (default: 8). - -Not implemented currently. - -=item $AnyEvent::HTTP::PERSISTENT_TIMEOUT +=item $AnyEvent::HTTP::MAX_PER_HOST -The maximum time to cache a persistent connection, in seconds (default: 2). +The maximum number of concurrent connections to the same host (identified +by the hostname). If the limit is exceeded, then the additional requests +are queued until previous connections are closed. -Not implemented currently. +The default value for this is C<4>, and it is highly advisable to not +increase it. =item $AnyEvent::HTTP::ACTIVE