=== modified file 'lib/Net/Async/HTTP.pm'
--- lib/Net/Async/HTTP.pm 2014-10-14 10:17:32 +0000
+++ lib/Net/Async/HTTP.pm 2014-10-14 10:50:34 +0000
@@ -640,6 +640,18 @@
} );
}
+sub _should_redirect
+{
+ my ( $response ) = @_;
+
+ # Should only redirect if we actually have a Location header
+ return 0 unless $response->is_redirect and defined $response->header( "Location" );
+
+ my $req_method = $response->request->method;
+ # Should only redirect GET or HEAD requests
+ return $req_method eq "GET" || $req_method eq "HEAD";
+}
+
sub _do_request
{
my $self = shift;
@@ -725,7 +737,7 @@
while => sub {
my $f = shift;
return 0 if $f->failure or $f->is_cancelled;
- return $response->is_redirect && $redirects--;
+ return _should_redirect( $response ) && $redirects--;
} );
if( $self->{fail_on_error} ) {
=== modified file 't/05redir.t'
--- t/05redir.t 2013-09-10 00:28:12 +0000
+++ t/05redir.t 2014-10-14 10:50:34 +0000
@@ -186,4 +186,77 @@
is( $response->content, "Directory", 'Content of final response to local redirect' );
}
+# 304 Not Modified should not redirect (RT98093)
+{
+ my $peersock;
+ no warnings 'redefine';
+ local *IO::Async::Handle::connect = sub {
+ my $self = shift;
+ my %args = @_;
+
+ $args{host} eq "host2" or die "Expected $args{host} eq host2";
+
+ ( my $selfsock, $peersock ) = IO::Async::OS->socketpair() or die "Cannot create socket pair - $!";
+ $self->set_handle( $selfsock );
+
+ return Future->new->done( $self );
+ };
+
+ my $f = $http->do_request(
+ uri => URI->new( "
http://host2/unmod" ),
+
+ on_redirect => sub { die "Should not be redirected" },
+ );
+
+ my $request_stream = "";
+ wait_for_stream { $request_stream =~ m/$CRLF$CRLF/ } $peersock => $request_stream;
+
+ $peersock->syswrite( "HTTP/1.1 304 Not Modified$CRLF" .
+ $CRLF ); # 304 has no body
+
+ wait_for { $f->is_ready };
+
+ my $response = $f->get;
+ is( $response->code, 304, 'HTTP 304 response not redirected' );
+}
+
+# Methods other than GET and HEAD should not redirect
+{
+ my $peersock;
+ no warnings 'redefine';
+ local *IO::Async::Handle::connect = sub {
+ my $self = shift;
+ my %args = @_;
+
+ $args{host} eq "host3" or die "Expected $args{host} eq host3";
+
+ ( my $selfsock, $peersock ) = IO::Async::OS->socketpair() or die "Cannot create socket pair - $!";
+ $self->set_handle( $selfsock );
+
+ return Future->new->done( $self );
+ };
+
+ my $f = $http->do_request(
+ method => "PUT",
+ uri => URI->new( "
http://host3/somewhere" ),
+ content => "new content",
+ content_type => "text/plain",
+
+ on_redirect => sub { die "Should not be redirected" },
+ );
+
+ my $request_stream = "";
+ wait_for_stream { $request_stream =~ m/$CRLF$CRLF/ } $peersock => $request_stream;
+
+ $peersock->syswrite( "HTTP/1.1 301 Moved Permanently$CRLF" .
+ "Content-Length: 0$CRLF" .
+ "Location: /somewhere/else$CRLF" .
+ $CRLF );
+
+ wait_for { $f->is_ready };
+
+ my $response = $f->get;
+ is( $response->code, 301, 'POST request not redirected' );
+}
+
done_testing;