comparison h3_server_name.t @ 1882:3619dcc8ba6d

Tests: HTTP/3 tests with server_name captures.
author Sergey Kandaurov <pluknet@nginx.com>
date Fri, 13 Jan 2023 17:12:20 +0400
parents
children cd66d6f50ec1
comparison
equal deleted inserted replaced
1881:33432a6877f7 1882:3619dcc8ba6d
1 #!/usr/bin/perl
2
3 # (C) Sergey Kandaurov
4 # (C) Nginx, Inc.
5
6 # Tests for HTTP/3 protocol, SNI TLS extension and regex in server_name.
7
8 ###############################################################################
9
10 use warnings;
11 use strict;
12
13 use Test::More;
14
15 BEGIN { use FindBin; chdir($FindBin::Bin); }
16
17 use lib 'lib';
18 use Test::Nginx;
19 use Test::Nginx::HTTP2;
20 use Test::Nginx::HTTP3;
21
22 ###############################################################################
23
24 select STDERR; $| = 1;
25 select STDOUT; $| = 1;
26
27 eval { require IO::Socket::SSL; die if $IO::Socket::SSL::VERSION < 1.56; };
28 plan(skip_all => 'IO::Socket::SSL version >= 1.56 required') if $@;
29
30 eval { IO::Socket::SSL->can_client_sni() or die; };
31 plan(skip_all => 'IO::Socket::SSL with OpenSSL SNI support required') if $@;
32
33 eval { IO::Socket::SSL->can_alpn() or die; };
34 plan(skip_all => 'IO::Socket::SSL with OpenSSL ALPN support required') if $@;
35
36 eval { require Crypt::Misc; die if $Crypt::Misc::VERSION < 0.067; };
37 plan(skip_all => 'CryptX version >= 0.067 required') if $@;
38
39 my $t = Test::Nginx->new()->has(qw/http http_ssl http_v2 http_v3 rewrite/)
40 ->has_daemon('openssl')->plan(6);
41
42 $t->write_file_expand('nginx.conf', <<'EOF');
43
44 %%TEST_GLOBALS%%
45
46 daemon off;
47
48 events {
49 }
50
51 http {
52 %%TEST_GLOBALS_HTTP%%
53
54 ssl_certificate_key localhost.key;
55 ssl_certificate localhost.crt;
56
57 server {
58 listen 127.0.0.1:8080 ssl http2;
59 listen 127.0.0.1:%%PORT_8980_UDP%% quic;
60 server_name ~^(?P<name>.+)\.example\.com$;
61
62 location / {
63 return 200 $name;
64 }
65 }
66 }
67
68 EOF
69
70 $t->write_file('openssl.conf', <<EOF);
71 [ req ]
72 default_bits = 2048
73 encrypt_key = no
74 distinguished_name = req_distinguished_name
75 [ req_distinguished_name ]
76 EOF
77
78 my $d = $t->testdir();
79
80 foreach my $name ('localhost') {
81 system('openssl req -x509 -new '
82 . "-config $d/openssl.conf -subj /CN=$name/ "
83 . "-out $d/$name.crt -keyout $d/$name.key "
84 . ">>$d/openssl.out 2>&1") == 0
85 or die "Can't create certificate for $name: $!\n";
86 }
87
88 $t->run();
89
90 ###############################################################################
91
92 # ssl_servername_regex wasn't inherited from QUIC connection,
93 # other protocols are provided for convenience
94
95 is(get1('test.example.com'), 'test', 'http1 - sni match');
96 is(get1('test.example.com', 'localhost'), 'test', 'http1 - sni not found');
97
98 is(get2('test.example.com'), 'test', 'http2 - sni match');
99 is(get2('test.example.com', 'localhost'), 'test', 'http2 - sni not found');
100
101 is(get3('test.example.com'), 'test', 'http3 - sni match');
102 is(get3('test.example.com', 'localhost'), 'test', 'http3 - sni not found');
103
104 ###############################################################################
105
106 sub get1 {
107 my ($host, $sni) = @_;
108 my $s = get_ssl_socket(sni => $sni || $host, alpn => ['http/1.1']);
109 http(<<EOF, socket => $s) =~ /.*?\x0d\x0a?\x0d\x0a?(.*)/ms;
110 GET / HTTP/1.1
111 Host: $host
112 Connection: close
113
114 EOF
115 return $1;
116 }
117
118 sub get2 {
119 my ($host, $sni) = @_;
120 my $sock = get_ssl_socket(sni => $sni || $host, alpn => ['h2']);
121 my $s = Test::Nginx::HTTP2->new(undef, socket => $sock);
122 my $sid = $s->new_stream({ host => $host });
123 my $frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
124
125 my ($frame) = grep { $_->{type} eq "DATA" } @$frames;
126 return $frame->{data};
127 }
128
129 sub get3 {
130 my ($host, $sni) = @_;
131 my $s = Test::Nginx::HTTP3->new(8980, sni => $sni || $host);
132 my $sid = $s->new_stream({ host => $host });
133 my $frames = $s->read(all => [{ sid => $sid, fin => 1 }]);
134
135 my ($frame) = grep { $_->{type} eq "DATA" } @$frames;
136 return $frame->{data};
137 }
138
139 sub get_ssl_socket {
140 my (%extra) = @_;
141 my $s;
142
143 eval {
144 local $SIG{ALRM} = sub { die "timeout\n" };
145 local $SIG{PIPE} = sub { die "sigpipe\n" };
146 alarm(8);
147 $s = IO::Socket::SSL->new(
148 Proto => 'tcp',
149 PeerAddr => '127.0.0.1',
150 PeerPort => port(8080),
151 SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE(),
152 SSL_hostname => $extra{sni},
153 SSL_alpn_protocols => $extra{alpn},
154 SSL_error_trap => sub { die $_[1] }
155 );
156 alarm(0);
157 };
158 alarm(0);
159
160 if ($@) {
161 log_in("died: $@");
162 return undef;
163 }
164
165 return $s;
166 }
167
168 ###############################################################################