Subject: | Unhandled exception with bad chunked transfer encoding |
(I'm tagging this as 'wishlist' since I'm not sure how far you want to go in protecting against bad responses from an HTTP server)
If the server responds with something other than useful chunk data, this can cause a loop-level exception.
Subject: | nahttp-badchunks.t |
use strict;
use warnings;
use Test::More;
use Test::Fatal;
use Test::Warnings 0.005 ':all';
use IO::Async::Loop;
use IO::Socket::IP;
use Net::Async::HTTP;
my $loop = IO::Async::Loop->new;
my $s;
my ($listener) = $loop->listen(
addr => {
family => "inet",
socktype => "stream",
ip => '127.0.0.1',
port => 0,
},
on_accept => sub {
my ($sock) = @_;
my $remote = join(':', $sock->peerhost, $sock->peerport);
note "Accept from $remote";
use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);
my $flags = fcntl($sock, F_GETFL, 0) or die "Can't get flags for the socket: $!\n";
is($flags & O_NONBLOCK, O_NONBLOCK, 'nonblocking flag is set on accepted socket');
my $stream = IO::Async::Stream->new(
handle => $sock,
on_read => sub {
my ($stream, $buffref, $eof) = @_;
while($$buffref =~ s{^(.*)\x0D\x0A}{}) {
my $line = $1;
# note "HTTP request line: $line";
if(!length $line) {
$stream->write(
join "\x0D\x0A",
"HTTP/1.1 404 OK",
"Host: me",
"Transfer-Encoding: chunked",
"Connection: close",
"",
"0005",
# Partial chunk then CRLF
"hell",
"o",
""
)
}
}
0
}
);
$loop->add($stream);
}
)->get;
my $sock = $listener->read_handle;
my $hostport = join(':', $sock->sockhost, $sock->sockport);
note "Server listening on $hostport";
$loop->add(
my $ua = Net::Async::HTTP->new(
fail_on_error => 1,
max_connections_per_host => 0,
)
);
is(warnings {
is(exception {
$ua->GET(
'http://' . $hostport,
timeout => 2,
)->else(sub {
my ($failure) = @_;
like($failure, qr/chunk/i, "had some sort of error mentioning chunks");
# i.e. don't raise an exception
Future->wrap
})->get
}, undef, 'no exception');
}, 0, 'no warnings');
done_testing;