Mercurial > hg > nginx-tests
comparison h2_proxy_request_buffering_ssl.t @ 879:127a602f36c8
Tests: HTTP/2 tests for unbuffered request body.
author | Sergey Kandaurov <pluknet@nginx.com> |
---|---|
date | Wed, 23 Mar 2016 20:08:20 +0300 |
parents | |
children | 29aa547dd963 |
comparison
equal
deleted
inserted
replaced
878:327044615c87 | 879:127a602f36c8 |
---|---|
1 #!/usr/bin/perl | |
2 | |
3 # (C) Sergey Kandaurov | |
4 # (C) Nginx, Inc. | |
5 | |
6 # Tests for HTTP/2 protocol with unbuffered request body to ssl backend. | |
7 | |
8 ############################################################################### | |
9 | |
10 use warnings; | |
11 use strict; | |
12 | |
13 use Test::More; | |
14 | |
15 use Socket qw/ CRLF /; | |
16 | |
17 BEGIN { use FindBin; chdir($FindBin::Bin); } | |
18 | |
19 use lib 'lib'; | |
20 use Test::Nginx; | |
21 use Test::Nginx::HTTP2 qw/ :DEFAULT :frame :io /; | |
22 | |
23 ############################################################################### | |
24 | |
25 select STDERR; $| = 1; | |
26 select STDOUT; $| = 1; | |
27 | |
28 my $t = Test::Nginx->new()->has(qw/http http_ssl http_v2 proxy/) | |
29 ->has_daemon('openssl'); | |
30 | |
31 $t->write_file_expand('nginx.conf', <<'EOF'); | |
32 | |
33 %%TEST_GLOBALS%% | |
34 | |
35 daemon off; | |
36 | |
37 events { | |
38 } | |
39 | |
40 http { | |
41 %%TEST_GLOBALS_HTTP%% | |
42 | |
43 server { | |
44 listen 127.0.0.1:8080 http2; | |
45 server_name localhost; | |
46 | |
47 location / { | |
48 proxy_request_buffering off; | |
49 proxy_pass https://127.0.0.1:8082; | |
50 client_body_buffer_size 512; | |
51 } | |
52 location /chunked { | |
53 proxy_request_buffering off; | |
54 proxy_http_version 1.1; | |
55 proxy_pass https://127.0.0.1:8082; | |
56 client_body_buffer_size 512; | |
57 } | |
58 } | |
59 | |
60 server { | |
61 listen 127.0.0.1:8082 ssl; | |
62 server_name localhost; | |
63 | |
64 ssl_certificate_key localhost.key; | |
65 ssl_certificate localhost.crt; | |
66 | |
67 location / { | |
68 proxy_request_buffering off; | |
69 proxy_pass http://127.0.0.1:8081/; | |
70 client_body_buffer_size 1k; | |
71 } | |
72 location /chunked { | |
73 proxy_request_buffering off; | |
74 proxy_http_version 1.1; | |
75 proxy_pass http://127.0.0.1:8081/; | |
76 client_body_buffer_size 1k; | |
77 } | |
78 } | |
79 } | |
80 | |
81 EOF | |
82 | |
83 $t->write_file('openssl.conf', <<EOF); | |
84 [ req ] | |
85 default_bits = 2048 | |
86 encrypt_key = no | |
87 distinguished_name = req_distinguished_name | |
88 [ req_distinguished_name ] | |
89 EOF | |
90 | |
91 my $d = $t->testdir(); | |
92 | |
93 foreach my $name ('localhost') { | |
94 system('openssl req -x509 -new ' | |
95 . "-config '$d/openssl.conf' -subj '/CN=$name/' " | |
96 . "-out '$d/$name.crt' -keyout '$d/$name.key' " | |
97 . ">>$d/openssl.out 2>&1") == 0 | |
98 or die "Can't create certificate for $name: $!\n"; | |
99 } | |
100 | |
101 $t->run(); | |
102 | |
103 plan(skip_all => 'no unbuffered request body') unless get_body('/chunked'); | |
104 | |
105 $t->plan(40); | |
106 | |
107 ############################################################################### | |
108 | |
109 my ($f); | |
110 | |
111 # unbuffered request body | |
112 | |
113 $f = get_body('/', 'content-length' => 10); | |
114 ok($f->{headers}, 'request'); | |
115 is($f->{upload}('01234', body_more => 1), '01234', 'part'); | |
116 is($f->{upload}('56789'), '56789', 'part 2'); | |
117 is($f->{http_end}(), 200, 'response'); | |
118 | |
119 $f = get_body('/', 'content-length' => 1536); | |
120 ok($f->{headers}, 'buffer'); | |
121 is($f->{upload}('0123' x 128, body_more => 1), '0123' x 128, 'buffer - below'); | |
122 is($f->{upload}('4567' x 128, body_more => 1), '4567' x 128, 'buffer - equal'); | |
123 is($f->{upload}('89AB' x 128), '89AB' x 128, 'buffer - above'); | |
124 is($f->{http_end}(), 200, 'buffer - response'); | |
125 | |
126 $f = get_body('/', 'content-length' => 18); | |
127 ok($f->{headers}, 'many'); | |
128 is($f->{upload}('01234many', body_split => [ 5 ], body_more => 1), | |
129 '01234many', 'many - part'); | |
130 is($f->{upload}('56789many', body_split => [ 5 ]), | |
131 '56789many', 'many - part 2'); | |
132 is($f->{http_end}(), 200, 'many - response'); | |
133 | |
134 $f = get_body('/', 'content-length' => 0); | |
135 ok($f->{headers}, 'empty'); | |
136 is($f->{upload}('', body_more => 1), '', 'empty - part'); | |
137 is($f->{upload}(''), '', 'empty - part 2'); | |
138 is($f->{http_end}(), 200, 'empty - response'); | |
139 | |
140 $f = get_body('/', 'content-length' => 10); | |
141 ok($f->{headers}, 'split'); | |
142 is($f->{upload}('0123456789', split => [ 14 ]), '0123456789', 'split'); | |
143 is($f->{http_end}(), 200, 'split - response'); | |
144 | |
145 # unbuffered request body, chunked transfer-encoding | |
146 | |
147 $f = get_body('/chunked'); | |
148 ok($f->{headers}, 'chunk'); | |
149 is($f->{upload}('01234', body_more => 1), '5' . CRLF . '01234' . CRLF, | |
150 'chunked - part'); | |
151 is($f->{upload}('56789'), '5' . CRLF . '56789' . CRLF . '0' . CRLF . CRLF, | |
152 'chunked - part 2'); | |
153 is($f->{http_end}(), 200, 'chunked - response'); | |
154 | |
155 $f = get_body('/chunked'); | |
156 ok($f->{headers}, 'chunked buffer'); | |
157 is($f->{upload}('0123' x 64, body_more => 1), | |
158 '100' . CRLF . '0123' x 64 . CRLF, 'chunked buffer - below'); | |
159 is($f->{upload}('4567' x 64, body_more => 1), | |
160 '100' . CRLF . '4567' x 64 . CRLF, 'chunked buffer - equal'); | |
161 is($f->{upload}('89AB' x 64), | |
162 '100' . CRLF . '89AB' x 64 . CRLF . '0' . CRLF . CRLF, | |
163 'chunked buffer - above'); | |
164 is($f->{http_end}(), 200, 'chunked buffer - response'); | |
165 | |
166 $f = get_body('/chunked'); | |
167 ok($f->{headers}, 'chunked many'); | |
168 is($f->{upload}('01234many', body_split => [ 5 ], body_more => 1), | |
169 '9' . CRLF . '01234many' . CRLF, 'chunked many - part'); | |
170 is($f->{upload}('56789many', body_split => [ 5 ]), | |
171 '9' . CRLF . '56789many' . CRLF . '0' . CRLF . CRLF, | |
172 'chunked many - part 2'); | |
173 is($f->{http_end}(), 200, 'chunked many - response'); | |
174 | |
175 $f = get_body('/chunked'); | |
176 ok($f->{headers}, 'chunked empty'); | |
177 is($f->{upload}('', body_more => 1), '', 'chunked empty - part'); | |
178 is($f->{upload}(''), '0' . CRLF . CRLF, 'chunked empty - part 2'); | |
179 is($f->{http_end}(), 200, 'chunked empty - response'); | |
180 | |
181 $f = get_body('/chunked'); | |
182 ok($f->{headers}, 'chunked split'); | |
183 is($f->{upload}('0123456789', split => [ 14 ]), | |
184 '5' . CRLF . '01234' . CRLF . '5' . CRLF . '56789' . CRLF . | |
185 '0' . CRLF . CRLF, 'chunked split'); | |
186 is($f->{http_end}(), 200, 'chunked split - response'); | |
187 | |
188 ############################################################################### | |
189 | |
190 sub get_body { | |
191 my ($url, %extra) = @_; | |
192 my ($server, $client, $f); | |
193 | |
194 $server = IO::Socket::INET->new( | |
195 Proto => 'tcp', | |
196 LocalHost => '127.0.0.1', | |
197 LocalPort => 8081, | |
198 Listen => 5, | |
199 Timeout => 3, | |
200 Reuse => 1 | |
201 ) | |
202 or die "Can't create listening socket: $!\n"; | |
203 | |
204 my $sess = new_session(8080); | |
205 my $sid = exists $extra{'content-length'} | |
206 ? new_stream($sess, { headers => [ | |
207 { name => ':method', value => 'GET' }, | |
208 { name => ':scheme', value => 'http' }, | |
209 { name => ':path', value => $url, }, | |
210 { name => ':authority', value => 'localhost' }, | |
211 { name => 'content-length', | |
212 value => $extra{'content-length'} }], | |
213 body_more => 1 }) | |
214 : new_stream($sess, { path => $url, body_more => 1 }); | |
215 | |
216 $client = $server->accept() or return; | |
217 | |
218 log2c("(new connection $client)"); | |
219 | |
220 $f->{headers} = raw_read($client, '', 1, \&log2i); | |
221 | |
222 my $chunked = $f->{headers} =~ /chunked/; | |
223 | |
224 my $body_read = sub { | |
225 my ($s, $buf, $len) = @_; | |
226 | |
227 for (1 .. 10) { | |
228 $buf = raw_read($s, $buf, length($buf) + 1, \&log2i) | |
229 or return ''; | |
230 | |
231 my $got = 0; | |
232 $got += $chunked ? hex $_ : $_ for $chunked | |
233 ? $buf =~ /(\w+)\x0d\x0a?\w+\x0d\x0a?/g | |
234 : length($buf); | |
235 last if $got >= $len; | |
236 } | |
237 | |
238 return $buf; | |
239 }; | |
240 | |
241 $f->{upload} = sub { | |
242 my ($body, %extra) = @_; | |
243 | |
244 h2_body($sess, $body, { %extra }); | |
245 | |
246 return $body_read->($client, '', length($body)); | |
247 }; | |
248 $f->{http_end} = sub { | |
249 $client->write(<<EOF); | |
250 HTTP/1.1 200 OK | |
251 Connection: close | |
252 | |
253 EOF | |
254 | |
255 $client->close; | |
256 | |
257 my $frames = h2_read($sess, all => [{ sid => $sid, fin => 1 }]); | |
258 my ($frame) = grep { $_->{type} eq "HEADERS" } @$frames; | |
259 return $frame->{headers}->{':status'}; | |
260 }; | |
261 return $f; | |
262 } | |
263 | |
264 sub log2i { Test::Nginx::log_core('|| <<', @_); } | |
265 sub log2o { Test::Nginx::log_core('|| >>', @_); } | |
266 sub log2c { Test::Nginx::log_core('||', @_); } | |
267 | |
268 ############################################################################### |