comparison h2_proxy_request_buffering.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.
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_v2 proxy/);
29
30 $t->write_file_expand('nginx.conf', <<'EOF');
31
32 %%TEST_GLOBALS%%
33
34 daemon off;
35
36 events {
37 }
38
39 http {
40 %%TEST_GLOBALS_HTTP%%
41
42 server {
43 listen 127.0.0.1:8080 http2;
44 server_name localhost;
45
46 location / {
47 proxy_request_buffering off;
48 proxy_pass http://127.0.0.1:8081/;
49 client_body_buffer_size 1k;
50 }
51 location /chunked {
52 proxy_request_buffering off;
53 proxy_http_version 1.1;
54 proxy_pass http://127.0.0.1:8081/;
55 client_body_buffer_size 1k;
56 }
57 }
58 }
59
60 EOF
61
62 $t->run();
63
64 plan(skip_all => 'no unbuffered request body') unless get_body('/chunked');
65
66 $t->plan(48);
67
68 ###############################################################################
69
70 my ($f);
71
72 # unbuffered request body
73
74 $f = get_body('/', 'content-length' => 10);
75 ok($f->{headers}, 'request');
76 is($f->{upload}('01234', body_more => 1), '01234', 'part');
77 is($f->{upload}('56789'), '56789', 'part 2');
78 is($f->{http_end}(), 200, 'response');
79
80 $f = get_body('/', 'content-length' => 10);
81 ok($f->{headers}, 'much');
82 is($f->{upload}('0123456789', body_more => 1), '0123456789', 'much - part');
83 is($f->{upload}('many'), '', 'much - part 2');
84 is($f->{http_end}(), 400, 'much - response');
85
86 $f = get_body('/', 'content-length' => 10);
87 ok($f->{headers}, 'less');
88 is($f->{upload}('0123', body_more => 1), '0123', 'less - part');
89 is($f->{upload}('56789'), '', 'less - part 2');
90 is($f->{http_end}(), 400, 'less - response');
91
92 $f = get_body('/', 'content-length' => 18);
93 ok($f->{headers}, 'many');
94 is($f->{upload}('01234many', body_split => [ 5 ], body_more => 1),
95 '01234many', 'many - part');
96 is($f->{upload}('56789many', body_split => [ 5 ]),
97 '56789many', 'many - part 2');
98 is($f->{http_end}(), 200, 'many - response');
99
100 $f = get_body('/', 'content-length' => 0);
101 ok($f->{headers}, 'empty');
102 is($f->{upload}('', body_more => 1), '', 'empty - part');
103 is($f->{upload}(''), '', 'empty - part 2');
104 is($f->{http_end}(), 200, 'empty - response');
105
106 $f = get_body('/', 'content-length' => 1536);
107 ok($f->{headers}, 'buffer');
108 is($f->{upload}('0123' x 128, body_more => 1), '0123' x 128,
109 'buffer - below');
110 is($f->{upload}('4567' x 128, body_more => 1), '4567' x 128,
111 'buffer - equal');
112 is($f->{upload}('89AB' x 128), '89AB' x 128, 'buffer - above');
113 is($f->{http_end}(), 200, 'buffer - response');
114
115 $f = get_body('/', 'content-length' => 10);
116 ok($f->{headers}, 'split');
117 is($f->{upload}('0123456789', split => [ 14 ]), '0123456789', 'split');
118 is($f->{http_end}(), 200, 'split - response');
119
120 # unbuffered request body, chunked transfer-encoding
121
122 $f = get_body('/chunked');
123 ok($f->{headers}, 'chunked');
124 is($f->{upload}('01234', body_more => 1), '5' . CRLF . '01234' . CRLF,
125 'chunked - part');
126 is($f->{upload}('56789'), '5' . CRLF . '56789' . CRLF . '0' . CRLF . CRLF,
127 'chunked - part 2');
128 is($f->{http_end}(), 200, 'chunked - response');
129
130 $f = get_body('/chunked');
131 ok($f->{headers}, 'chunked buffer');
132 is($f->{upload}('0123' x 128, body_more => 1),
133 '200' . CRLF . '0123' x 128 . CRLF, 'chunked buffer - below');
134 is($f->{upload}('4567' x 128, body_more => 1),
135 '200' . CRLF . '4567' x 128 . CRLF, 'chunked buffer - equal');
136 is($f->{upload}('89AB' x 128),
137 '200' . CRLF . '89AB' x 128 . CRLF . '0' . CRLF . CRLF,
138 'chunked buffer - above');
139 is($f->{http_end}(), 200, 'chunked buffer - response');
140
141 $f = get_body('/chunked');
142 ok($f->{headers}, 'chunked many');
143 is($f->{upload}('01234many', body_split => [ 5 ], body_more => 1),
144 '9' . CRLF . '01234many' . CRLF, 'chunked many - part');
145 is($f->{upload}('56789many', body_split => [ 5 ]),
146 '9' . CRLF . '56789many' . CRLF . '0' . CRLF . CRLF,
147 'chunked many - part 2');
148 is($f->{http_end}(), 200, 'chunked many - response');
149
150 $f = get_body('/chunked');
151 ok($f->{headers}, 'chunked empty');
152 is($f->{upload}('', body_more => 1), '', 'chunked empty - part');
153 is($f->{upload}(''), '0' . CRLF . CRLF, 'chunked empty - part 2');
154 is($f->{http_end}(), 200, 'chunked empty - response');
155
156 $f = get_body('/chunked');
157 ok($f->{headers}, 'chunked split');
158 is($f->{upload}('0123456789', split => [ 14 ]),
159 '5' . CRLF . '01234' . CRLF . '5' . CRLF . '56789' . CRLF .
160 '0' . CRLF . CRLF, 'chunked split');
161 is($f->{http_end}(), 200, 'chunked split - response');
162
163 ###############################################################################
164
165 sub get_body {
166 my ($url, %extra) = @_;
167 my ($server, $client, $f);
168
169 $server = IO::Socket::INET->new(
170 Proto => 'tcp',
171 LocalHost => '127.0.0.1',
172 LocalPort => 8081,
173 Listen => 5,
174 Timeout => 3,
175 Reuse => 1
176 )
177 or die "Can't create listening socket: $!\n";
178
179 my $sess = new_session(8080);
180 my $sid = exists $extra{'content-length'}
181 ? new_stream($sess, { headers => [
182 { name => ':method', value => 'GET' },
183 { name => ':scheme', value => 'http' },
184 { name => ':path', value => $url, },
185 { name => ':authority', value => 'localhost' },
186 { name => 'content-length',
187 value => $extra{'content-length'} }],
188 body_more => 1 })
189 : new_stream($sess, { path => $url, body_more => 1 });
190
191 $client = $server->accept() or return;
192
193 log2c("(new connection $client)");
194
195 $f->{headers} = raw_read($client, '', 1, \&log2i);
196
197 my $chunked = $f->{headers} =~ /chunked/;
198
199 my $body_read = sub {
200 my ($s, $buf, $len) = @_;
201
202 for (1 .. 10) {
203 $buf = raw_read($s, $buf, length($buf) + 1, \&log2i)
204 or return '';
205
206 my $got = 0;
207 $got += $chunked ? hex $_ : $_ for $chunked
208 ? $buf =~ /(\w+)\x0d\x0a?\w+\x0d\x0a?/g
209 : length($buf);
210 last if $got >= $len;
211 }
212
213 return $buf;
214 };
215
216 $f->{upload} = sub {
217 my ($body, %extra) = @_;
218
219 h2_body($sess, $body, { %extra });
220
221 return $body_read->($client, '', length($body));
222 };
223 $f->{http_end} = sub {
224 $client->write(<<EOF);
225 HTTP/1.1 200 OK
226 Connection: close
227
228 EOF
229
230 $client->close;
231
232 my $frames = h2_read($sess, all => [{ sid => $sid, fin => 1 }]);
233 my ($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
234 return $frame->{headers}->{':status'};
235 };
236 return $f;
237 }
238
239 sub log2i { Test::Nginx::log_core('|| <<', @_); }
240 sub log2o { Test::Nginx::log_core('|| >>', @_); }
241 sub log2c { Test::Nginx::log_core('||', @_); }
242
243 ###############################################################################