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 ###############################################################################