Skip Menu |

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

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

People
Owner: Nobody in particular
Requestors: leonerd-cpan [...] leonerd.org.uk
Cc:
AdminCc:

Bug Information
Severity: Wishlist
Broken in: (no value)
Fixed in: 0.45



Subject: Configuration option to use `Connection: close`
In general, adding config options to guide the module on choices like whether to force "Connection: close" would be useful. -- Paul Evans
Patch attached. -- Paul Evans
Subject: rt128952.patch
=== modified file 'lib/Net/Async/HTTP.pm' --- old/lib/Net/Async/HTTP.pm 2019-11-26 09:38:09 +0000 +++ new/lib/Net/Async/HTTP.pm 2019-11-26 10:19:19 +0000 @@ -218,6 +218,14 @@ Optional. If false, disables HTTP/1.1-style request pipelining. +=head2 close_after_request => BOOL + +I<Since version 0.45.> + +Optional. If true, will set the C<Connection: close> header on outgoing +requests and disable pipelining, thus making every request use a new +connection. + =head2 family => INT =head2 local_host => STRING @@ -305,8 +313,8 @@ foreach (qw( user_agent max_redirects max_in_flight max_connections_per_host timeout stall_timeout proxy_host proxy_port cookie_jar pipeline - family local_host local_port local_addrs local_addr fail_on_error - read_len write_len decode_content require_SSL )) + close_after_request family local_host local_port local_addrs local_addr + fail_on_error read_len write_len decode_content require_SSL )) { $self->{$_} = delete $params{$_} if exists $params{$_}; } @@ -436,7 +444,8 @@ notifier_name => "$host:$port,connecting", ready_queue => $ready_queue, ( map { $_ => $self->{$_} } - qw( max_in_flight pipeline read_len write_len decode_content ) ), + qw( max_in_flight read_len write_len decode_content ) ), + pipeline => ( $self->{pipeline} && !$self->{close_after_request} ), is_proxy => $args{is_proxy}, on_closed => sub { @@ -1055,7 +1064,12 @@ my ( $request ) = @_; $request->init_header( 'User-Agent' => $self->{user_agent} ) if length $self->{user_agent}; - $request->init_header( "Connection" => "keep-alive" ); + if( $self->{close_after_request} ) { + $request->header( "Connection" => "close" ); + } + else { + $request->init_header( "Connection" => "keep-alive" ); + } $self->{cookie_jar}->add_cookie_header( $request ) if $self->{cookie_jar}; } === modified file 't/12conn-persistence.t' --- old/t/12conn-persistence.t 2019-11-26 09:49:57 +0000 +++ new/t/12conn-persistence.t 2019-11-26 10:19:19 +0000 @@ -191,4 +191,44 @@ wait_for { scalar $http->children == 0 }; } +# Check that close_after_request sets close header +{ + my $peersock; + + no warnings 'redefine'; + local *IO::Async::Handle::connect = sub { + my $self = shift; + my %args = @_; + + ( my $selfsock, $peersock ) = IO::Async::OS->socketpair() or die "Cannot create socket pair - $!"; + $self->set_handle( $selfsock ); + + return Future->done( $self ); + }; + + $http->configure( close_after_request => 1 ); + + my $future = $http->do_request( + uri => URI->new( "http://host/closed" ), + ); + + wait_for { $peersock }; + + my $request_stream = ""; + wait_for_stream { $request_stream =~ m/$CRLF$CRLF/ } $peersock => $request_stream; + + like( $request_stream, qr/^Connection: close$CRLF/m, 'Request has Connection: close header' ); + + $peersock->syswrite( "HTTP/1.1 200 OK$CRLF" . + "Content-Type: text/plain$CRLF" . + "Connection: close$CRLF" . + "$CRLF" . + "Bye" ); + $peersock->close; + + my $response = wait_for_future( $future )->get; + + is( $response->content, "Bye", 'Content of response' ); +} + done_testing;