Skip Menu |

This queue is for tickets about the Net-Async-HTTP CPAN distribution.

Report information
The Basics
Id: 66189
Status: resolved
Priority: 0/
Queue: Net-Async-HTTP

People
Owner: Nobody in particular
Requestors: G.Ansari [...] gmail.com
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: 0.11
Fixed in: 0.12



Subject: Fetching fails with multiple requests to the same host.
When an instance of Net-Async-HTTP is being used to issue several requests to the same host, it fails. I'm using v5.8.8 built for x86_64- linux-thread-multi on Linux 2.6.18-164.2.1.el5.028stab066.10 (CentOS 5.4). Please consider the following sample code (a simple FastCGI script that is supposed to fetch content from an uri and modify it in some way): #!/usr/bin/perl use strict; use warnings; use Data::Dumper; use Net::Async::FastCGI; use IO::Async::Loop; use Net::Async::HTTP; use URI; use Carp; $SIG{ __DIE__ } = sub { Carp::confess( @_ ) }; my $loop = IO::Async::Loop->new(); my $http = Net::Async::HTTP->new(); my $fcgi = Net::Async::FastCGI->new( on_request => sub { my ( $fcgi, $r ) = @_; $http->do_request( uri => URI->new("http://test.com/test"), on_response => sub { my ($response) = @_; $r->print_stdout("Status: 200 OK\r\n" . "Content-type: text/html\r\n" . "\r\n"); $r->print_stdout("<pre>". Dumper $response); $r->finish(); }, on_error => sub { my ($message) = @_; $r->print_stdout("Error: $message"); $r->finish(); } ) } ); $loop->add($fcgi); $loop->add($http); $fcgi->listen( service => 8888, on_resolve_error => sub { print STDERR "Cannot resolve - $_[0]\n"; }, on_listen_error => sub { print STDERR "Cannot listen $_[0]\n"; }, ); $loop->loop_forever; The above code works happily when called once. As soon as concurrent requests are issues (i.e. ab -n 10 -c 2 uri), I'm getting the message Can't call method "write" on an undefined value at /usr/lib/perl5/site_perl/5.8.8/IO/Async/Protocol/Stream.pm line 200. The backtrace follows: Can't call method "write" on an undefined value at /usr/lib/perl5/site_perl/5.8.8/IO/Async/Protocol/Stream.pm line 200. at ./test.pl line 11 main::__ANON__('Can\'t call method "write" on an undefined value at /usr/lib/...') called at /usr/lib/perl5/site_perl/5.8.8/IO/Async/Protocol/Stream.pm line 200 IO::Async::Protocol::Stream::write('Net::Async::HTTP::Protocol=H ASH(0x1e455650)', 'GET /test HTTP/1.1\x{d}\x{a}Host: safein.us\x{d}\x{a}User-Agent: Perl + Net::...') called at /usr/lib/perl5/site_perl/5.8.8/Net/Async/HTTP/Protocol.pm line 184 Net::Async::HTTP::Protocol::request('Net::Async::HTTP::Protocol= HASH(0x1e455650)', 'request', 'HTTP::Request=HASH(0x1e4c9a10)', 'request_body', 'undef', 'on_header', 'CODE(0x1e4c96f0)', 'on_error', 'CODE(0x1e4c9600)', ...) called at /usr/lib/perl5/site_perl/5.8.8/Net/Async/HTTP.pm line 503 Net::Async::HTTP::__ANON__('Net::Async::HTTP::Protocol=HASH(0x1e 455650)') called at /usr/lib/perl5/site_perl/5.8.8/Net/Async/HTTP.pm line 166 Net::Async::HTTP::get_connection('Net::Async::HTTP=HASH(0x1e28ff b0)', 'host', 'safein.us', 'port', 80, 'SSL', '', 'on_error', 'CODE(0x1e4c9600)', ...) called at /usr/lib/perl5/site_perl/5.8.8/Net/Async/HTTP.pm line 510 Net::Async::HTTP::do_request('Net::Async::HTTP=HASH(0x1e28ffb0)' , 'uri', 'URI::http=SCALAR(0x1e4551f0)', 'on_response', 'CODE(0x1e4c9520)', 'on_error', 'CODE(0x1e4c9600)') called at ./test.pl line 40 main::__ANON__('Net::Async::FastCGI=HASH(0x1e290380)', 'Net::Async::FastCGI::Request=HASH(0x1e4bfd80)') called at /usr/lib/perl5/site_perl/5.8.8/Net/Async/FastCGI.pm line 188 Net::Async::FastCGI::_request_ready('Net::Async::FastCGI=HASH(0x 1e290380)', 'Net::Async::FastCGI::Request=HASH(0x1e4bfd80)') called at /usr/lib/perl5/site_perl/5.8.8/Net/Async/FastCGI/Request.pm line 146 Net::Async::FastCGI::Request::_ready_check('Net::Async::FastCGI: :Request=HASH(0x1e4bfd80)') called at /usr/lib/perl5/site_perl/5.8.8/Net/Async/FastCGI/Request.pm line 187 Net::Async::FastCGI::Request::incomingrecord_stdin('Net::Async:: FastCGI::Request=HASH(0x1e4bfd80)', 'HASH(0x1e2970a0)') called at /usr/lib/perl5/site_perl/5.8.8/Net/Async/FastCGI/Request.pm line 131 Net::Async::FastCGI::Request::incomingrecord('Net::Async::FastCG I::Request=HASH(0x1e4bfd80)', 'HASH(0x1e2970a0)') called at /usr/lib/perl5/site_perl/5.8.8/Net/Async/FastCGI/ServerProtocol.pm line 84 Net::Async::FastCGI::ServerProtocol::on_record('Net::Async::Fast CGI::ServerProtocol=HASH(0x1e461410)', 1, 'HASH(0x1e2970a0)') called at /usr/lib/perl5/site_perl/5.8.8/Net/Async/FastCGI/Protocol.pm line 65 Net::Async::FastCGI::Protocol::on_read('Net::Async::FastCGI::Ser verProtocol=HASH(0x1e461410)', 'SCALAR(0x1e455d20)', '') called at /usr/lib/perl5/site_perl/5.8.8/IO/Async/Notifier.pm line 634 IO::Async::Notifier::invoke_event('Net::Async::FastCGI::ServerPr otocol=HASH(0x1e461410)', 'on_read', 'SCALAR(0x1e455d20)', '') called at /usr/lib/perl5/site_perl/5.8.8/IO/Async/Protocol/Stream.pm line 159 IO::Async::Protocol::Stream::__ANON__('undef', 'IO::Async::Stream=HASH(0x1e460fc0)', 'SCALAR(0x1e455d20)', '') called at /usr/lib/perl5/site_perl/5.8.8/IO/Async/Notifier.pm line 634 IO::Async::Notifier::invoke_event('IO::Async::Stream=HASH(0x1e46 0fc0)', 'on_read', 'SCALAR(0x1e455d20)', '') called at /usr/lib/perl5/site_perl/5.8.8/IO/Async/Stream.pm line 553 IO::Async::Stream::on_read_ready('undef') called at /usr/lib/perl5/site_perl/5.8.8/IO/Async/Loop/Poll.pm line 146 IO::Async::Loop::Poll::post_poll('IO::Async::Loop::Poll=HASH(0x1 e28fe40)') called at /usr/lib/perl5/site_perl/5.8.8/IO/Async/Loop/Poll.pm line 214 IO::Async::Loop::Poll::loop_once('IO::Async::Loop::Poll=HASH(0x1 e28fe40)', 'undef') called at /usr/lib/perl5/site_perl/5.8.8/IO/Async/Loop.pm line 432 IO::Async::Loop::loop_forever('IO::Async::Loop::Poll=HASH(0x1e28 fe40)') called at ./test.pl I'm looking into this myself, trying to reproduce with more recent perl version, and will provide the patch if I'll be able to solve the issue, but any help from the author or anyone else will be highly appreciated. Thank you, Greg.
Ah, curious. I expect that'll be an interraction between the connection cache sharing, and an HTTP/1.0 server closing the connection after the first response. I'll take a look into it. -- Paul Evans
Hi there, Sorry it's taken quite so long to fix this one; it managed to get buried in amongst some other things, and I recently re-remembered about it when someone else ran into the same bug. Find attached a patch that should fix it. This will be in the next release; 0.12 -- Paul Evans
Subject: rt66189.patch
=== modified file 'lib/Net/Async/HTTP.pm' --- lib/Net/Async/HTTP.pm 2011-02-09 12:48:01 +0000 +++ lib/Net/Async/HTTP.pm 2011-09-29 22:16:00 +0000 @@ -94,7 +94,7 @@ { my $self = shift; - $self->{connections} = {}; # { "$host:$port" } -> [ $conn, @pending_onread ] + $self->{connections} = {}; # { "$host:$port" } -> $conn } =head1 PARAMETERS @@ -160,16 +160,13 @@ my $host = delete $args{host}; my $port = delete $args{port}; - if( my $cr = $self->{connections}->{"$host:$port"} ) { - my ( $conn ) = @$cr; - - $on_ready->( $conn ); - + my $connections = $self->{connections}; + + if( my $conn = $connections->{"$host:$port"} ) { + $conn->run_when_ready( $on_ready ); return; } - my $connections = $self->{connections}; - my $conn = Net::Async::HTTP::Protocol->new( on_closed => sub { delete $connections->{"$host:$port"}; @@ -177,7 +174,7 @@ ); $self->add_child( $conn ); - $connections->{"$host:$port"} = [ $conn ]; + $connections->{"$host:$port"} = $conn; if( $args{SSL} ) { require IO::Async::SSL; @@ -202,13 +199,10 @@ $on_error->( "$host:$port not contactable" ); }, - on_connected => sub { - - $on_ready->( $conn ); - }, - %args, ); + + $conn->run_when_ready( $on_ready ); } =head2 $http->do_request( %args ) === modified file 'lib/Net/Async/HTTP/Protocol.pm' --- lib/Net/Async/HTTP/Protocol.pm 2011-02-09 12:48:01 +0000 +++ lib/Net/Async/HTTP/Protocol.pm 2011-09-29 22:16:00 +0000 @@ -29,6 +29,35 @@ =cut +sub connect +{ + my $self = shift; + $self->SUPER::connect( + @_, + + on_connected => sub { + my $self = shift; + + if( my $queue = delete $self->{on_ready_queue} ) { + $_->( $self ) for @$queue; + } + }, + ); +} + +sub run_when_ready +{ + my $self = shift; + my ( $on_ready ) = @_; + + if( $self->transport ) { + $on_ready->( $self ); + } + else { + push @{ $self->{on_ready_queue} }, $on_ready; + } +} + sub on_read { my $self = shift;
Fixed in 0.12, now released to CPAN -- Paul Evans