comparison h2_ssl.t @ 1740:f7e667a4898d

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.
author Sergey Kandaurov <pluknet@nginx.com>
date Thu, 21 Oct 2021 13:55:44 +0300
parents 341506267e16
children 3408029c09f5
comparison
equal deleted inserted replaced
1739:f2fe58b4b59f 1740:f7e667a4898d
20 20
21 ############################################################################### 21 ###############################################################################
22 22
23 select STDERR; $| = 1; 23 select STDERR; $| = 1;
24 select STDOUT; $| = 1; 24 select STDOUT; $| = 1;
25
26 eval { require IO::Socket::SSL; };
27 plan(skip_all => 'IO::Socket::SSL not installed') if $@;
28 25
29 my $t = Test::Nginx->new()->has(qw/http http_ssl http_v2/) 26 my $t = Test::Nginx->new()->has(qw/http http_ssl http_v2/)
30 ->has_daemon('openssl'); 27 ->has_daemon('openssl');
31 28
32 $t->write_file_expand('nginx.conf', <<'EOF'); 29 $t->write_file_expand('nginx.conf', <<'EOF');
54 } 51 }
55 } 52 }
56 53
57 EOF 54 EOF
58 55
56 eval { require IO::Socket::SSL; die if $IO::Socket::SSL::VERSION < 1.56; };
57 plan(skip_all => 'IO::Socket::SSL version >= 1.56 required') if $@;
58
59 eval { IO::Socket::SSL->can_alpn() or die; };
60 plan(skip_all => 'IO::Socket::SSL with OpenSSL ALPN support required') if $@;
61
62 eval { exists &Net::SSLeay::P_alpn_selected or die; };
63 plan(skip_all => 'Net::SSLeay with OpenSSL ALPN support required') if $@;
64
59 $t->write_file('openssl.conf', <<EOF); 65 $t->write_file('openssl.conf', <<EOF);
60 [ req ] 66 [ req ]
61 default_bits = 2048 67 default_bits = 2048
62 encrypt_key = no 68 encrypt_key = no
63 distinguished_name = req_distinguished_name 69 distinguished_name = req_distinguished_name
72 . "-out $d/$name.crt -keyout $d/$name.key " 78 . "-out $d/$name.crt -keyout $d/$name.key "
73 . ">>$d/openssl.out 2>&1") == 0 79 . ">>$d/openssl.out 2>&1") == 0
74 or die "Can't create certificate for $name: $!\n"; 80 or die "Can't create certificate for $name: $!\n";
75 } 81 }
76 82
83 $t->write_file('index.html', '');
77 $t->write_file('tbig.html', 84 $t->write_file('tbig.html',
78 join('', map { sprintf "XX%06dXX", $_ } (1 .. 500000))); 85 join('', map { sprintf "XX%06dXX", $_ } (1 .. 500000)));
79 86
80 open OLDERR, ">&", \*STDERR; close STDERR; 87 open OLDERR, ">&", \*STDERR; close STDERR;
81 $t->run(); 88 $t->run();
82 open STDERR, ">&", \*OLDERR; 89 open STDERR, ">&", \*OLDERR;
83 90
84 plan(skip_all => 'no ALPN/NPN negotiation') unless defined getconn(port(8080)); 91 plan(skip_all => 'no ALPN negotiation') unless defined getconn();
85 $t->plan(1); 92 $t->plan(2);
86 93
87 ############################################################################### 94 ###############################################################################
88 95
89 # client cancels 2nd stream after HEADERS has been created 96 like(http_get('/', socket => get_ssl_socket(['http/1.1'])),
97 qr/200 OK/, 'alpn to HTTP/1.1 fallback');
98
99 my $s = getconn(['http/1.1', 'h2']);
100 my $sid = $s->new_stream();
101 my $frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
102 my ($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
103 is($frame->{headers}->{':status'}, 200, 'alpn to HTTP/2');
104
105 # client cancels last stream after HEADERS has been created,
90 # while some unsent data was left in the SSL buffer 106 # while some unsent data was left in the SSL buffer
91 # HEADERS frame may stuck in SSL buffer and won't be sent producing alert 107 # HEADERS frame may stuck in SSL buffer and won't be sent producing alert
92 108
93 my $s = getconn(port(8080)); 109 $sid = $s->new_stream({ path => '/tbig.html' });
94 ok($s, 'ssl connection');
95
96 my $sid = $s->new_stream({ path => '/tbig.html' });
97 110
98 select undef, undef, undef, 0.2; 111 select undef, undef, undef, 0.2;
99 $s->h2_rst($sid, 8); 112 $s->h2_rst($sid, 8);
100 113
101 $sid = $s->new_stream({ path => '/tbig.html' }); 114 $sid = $s->new_stream({ path => '/tbig.html' });
106 $t->stop(); 119 $t->stop();
107 120
108 ############################################################################### 121 ###############################################################################
109 122
110 sub getconn { 123 sub getconn {
111 my ($port) = @_; 124 my ($alpn) = @_;
125 $alpn = ['h2'] if !defined $alpn;
126
127 my $sock = get_ssl_socket($alpn);
128 my $s = Test::Nginx::HTTP2->new(undef, socket => $sock)
129 if $sock->alpn_selected();
130 }
131
132 sub get_ssl_socket {
133 my ($alpn) = @_;
112 my $s; 134 my $s;
113 135
114 eval { 136 eval {
115 my $sock = Test::Nginx::HTTP2::new_socket($port, SSL => 1, 137 local $SIG{ALRM} = sub { die "timeout\n" };
116 alpn => 'h2'); 138 local $SIG{PIPE} = sub { die "sigpipe\n" };
117 $s = Test::Nginx::HTTP2->new($port, socket => $sock) 139 alarm(8);
118 if $sock->alpn_selected(); 140 $s = IO::Socket::SSL->new(
141 Proto => 'tcp',
142 PeerAddr => '127.0.0.1',
143 PeerPort => port(8080),
144 SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE(),
145 SSL_alpn_protocols => $alpn,
146 SSL_error_trap => sub { die $_[1] }
147 );
148 alarm(0);
119 }; 149 };
150 alarm(0);
120 151
121 return $s if defined $s; 152 if ($@) {
122 153 log_in("died: $@");
123 eval { 154 return undef;
124 my $sock = Test::Nginx::HTTP2::new_socket($port, SSL => 1, 155 }
125 npn => 'h2');
126 $s = Test::Nginx::HTTP2->new($port, socket => $sock)
127 if $sock->next_proto_negotiated();
128 };
129 156
130 return $s; 157 return $s;
131 } 158 }
132 159
133 ############################################################################### 160 ###############################################################################