# HG changeset patch # User Sergey Kandaurov # Date 1634813744 -10800 # Node ID f7e667a4898d5cf6e3d45ef6cd2c499c36f723aa # Parent f2fe58b4b59f74d69765c112983f581b3de4fc82 Tests: added HTTP/2 test for ALPN fallback to HTTP/1.1. While here, deorbit NPN negotiation going to be dropped in 1.21.4. Note that generic NPN tests are still present in h2_ssl_variables.t. diff --git a/h2_ssl.t b/h2_ssl.t --- a/h2_ssl.t +++ b/h2_ssl.t @@ -23,9 +23,6 @@ use Test::Nginx::HTTP2; select STDERR; $| = 1; select STDOUT; $| = 1; -eval { require IO::Socket::SSL; }; -plan(skip_all => 'IO::Socket::SSL not installed') if $@; - my $t = Test::Nginx->new()->has(qw/http http_ssl http_v2/) ->has_daemon('openssl'); @@ -56,6 +53,15 @@ http { EOF +eval { require IO::Socket::SSL; die if $IO::Socket::SSL::VERSION < 1.56; }; +plan(skip_all => 'IO::Socket::SSL version >= 1.56 required') if $@; + +eval { IO::Socket::SSL->can_alpn() or die; }; +plan(skip_all => 'IO::Socket::SSL with OpenSSL ALPN support required') if $@; + +eval { exists &Net::SSLeay::P_alpn_selected or die; }; +plan(skip_all => 'Net::SSLeay with OpenSSL ALPN support required') if $@; + $t->write_file('openssl.conf', <write_file('index.html', ''); $t->write_file('tbig.html', join('', map { sprintf "XX%06dXX", $_ } (1 .. 500000))); @@ -81,19 +88,25 @@ open OLDERR, ">&", \*STDERR; close STDER $t->run(); open STDERR, ">&", \*OLDERR; -plan(skip_all => 'no ALPN/NPN negotiation') unless defined getconn(port(8080)); -$t->plan(1); +plan(skip_all => 'no ALPN negotiation') unless defined getconn(); +$t->plan(2); ############################################################################### -# client cancels 2nd stream after HEADERS has been created +like(http_get('/', socket => get_ssl_socket(['http/1.1'])), + qr/200 OK/, 'alpn to HTTP/1.1 fallback'); + +my $s = getconn(['http/1.1', 'h2']); +my $sid = $s->new_stream(); +my $frames = $s->read(all => [{ sid => $sid, fin => 1 }]); +my ($frame) = grep { $_->{type} eq "HEADERS" } @$frames; +is($frame->{headers}->{':status'}, 200, 'alpn to HTTP/2'); + +# client cancels last stream after HEADERS has been created, # while some unsent data was left in the SSL buffer # HEADERS frame may stuck in SSL buffer and won't be sent producing alert -my $s = getconn(port(8080)); -ok($s, 'ssl connection'); - -my $sid = $s->new_stream({ path => '/tbig.html' }); +$sid = $s->new_stream({ path => '/tbig.html' }); select undef, undef, undef, 0.2; $s->h2_rst($sid, 8); @@ -108,24 +121,38 @@ select undef, undef, undef, 0.2; ############################################################################### sub getconn { - my ($port) = @_; + my ($alpn) = @_; + $alpn = ['h2'] if !defined $alpn; + + my $sock = get_ssl_socket($alpn); + my $s = Test::Nginx::HTTP2->new(undef, socket => $sock) + if $sock->alpn_selected(); +} + +sub get_ssl_socket { + my ($alpn) = @_; my $s; eval { - my $sock = Test::Nginx::HTTP2::new_socket($port, SSL => 1, - alpn => 'h2'); - $s = Test::Nginx::HTTP2->new($port, socket => $sock) - if $sock->alpn_selected(); + local $SIG{ALRM} = sub { die "timeout\n" }; + local $SIG{PIPE} = sub { die "sigpipe\n" }; + alarm(8); + $s = IO::Socket::SSL->new( + Proto => 'tcp', + PeerAddr => '127.0.0.1', + PeerPort => port(8080), + SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE(), + SSL_alpn_protocols => $alpn, + SSL_error_trap => sub { die $_[1] } + ); + alarm(0); }; + alarm(0); - return $s if defined $s; - - eval { - my $sock = Test::Nginx::HTTP2::new_socket($port, SSL => 1, - npn => 'h2'); - $s = Test::Nginx::HTTP2->new($port, socket => $sock) - if $sock->next_proto_negotiated(); - }; + if ($@) { + log_in("died: $@"); + return undef; + } return $s; }