comparison proxy_request_buffering_chunked.t @ 542:e7e3ced702f5

Tests: unbuffered request body.
author Sergey Kandaurov <pluknet@nginx.com>
date Mon, 06 Apr 2015 18:02:30 +0300
parents
children dbf8fb0f3d30
comparison
equal deleted inserted replaced
541:53d0d963eb40 542:e7e3ced702f5
1 #!/usr/bin/perl
2
3 # (C) Maxim Dounin
4 # (C) Sergey Kandaurov
5 # (C) Nginx, Inc.
6
7 # Tests for unbuffered request body, chunked transfer-encoding.
8
9 ###############################################################################
10
11 use warnings;
12 use strict;
13
14 use Test::More;
15 use Socket qw/ CRLF /;
16
17 BEGIN { use FindBin; chdir($FindBin::Bin); }
18
19 use lib 'lib';
20 use Test::Nginx;
21
22 ###############################################################################
23
24 select STDERR; $| = 1;
25 select STDOUT; $| = 1;
26
27 my $t = Test::Nginx->new()->has(qw/http proxy rewrite/);
28
29 $t->write_file_expand('nginx.conf', <<'EOF');
30
31 %%TEST_GLOBALS%%
32
33 daemon off;
34
35 events {
36 }
37
38 http {
39 %%TEST_GLOBALS_HTTP%%
40
41 server {
42 listen 127.0.0.1:8080;
43 server_name localhost;
44
45 client_header_buffer_size 1k;
46 proxy_request_buffering off;
47 proxy_http_version 1.1;
48
49 location / {
50 client_body_buffer_size 2k;
51 add_header X-Body "$request_body";
52 proxy_pass http://127.0.0.1:8081;
53 }
54 location /small {
55 client_body_in_file_only on;
56 proxy_pass http://127.0.0.1:8080/;
57 }
58 location /single {
59 client_body_in_single_buffer on;
60 add_header X-Body "$request_body";
61 proxy_pass http://127.0.0.1:8081;
62 }
63 location /discard {
64 return 200 "TEST\n";
65 }
66 location /preread {
67 proxy_pass http://127.0.0.1:8082/;
68 }
69 location /error_page {
70 proxy_pass http://127.0.0.1:8081/404;
71 error_page 404 /404;
72 proxy_intercept_errors on;
73 }
74 location /404 {
75 return 200 "$request_body\n";
76 }
77 }
78
79 server {
80 listen 127.0.0.1:8081;
81 server_name localhost;
82
83 location / {
84 return 204;
85 }
86 location /404 { }
87 }
88 }
89
90 EOF
91
92 $t->try_run('no proxy_request_buffering')->plan(22);
93
94 ###############################################################################
95
96 unlike(http_get('/'), qr/X-Body:/ms, 'no body');
97
98 like(http_get_body('/', '0123456789'),
99 qr/X-Body: 0123456789\x0d?$/ms, 'body');
100
101 like(http_get_body('/', '0123456789' x 128),
102 qr/X-Body: (0123456789){128}\x0d?$/ms, 'body in two buffers');
103
104 like(http_get_body('/single', '0123456789' x 128),
105 qr/X-Body: (0123456789){128}\x0d?$/ms, 'body in single buffer');
106
107 like(http_get_body('/error_page', '0123456789'),
108 qr/^0123456789$/m, 'body in error page');
109
110 # pipelined requests
111
112 like(http_get_body('/', '0123456789', '0123456789' x 128, '0123456789' x 512,
113 'foobar'), qr/X-Body: foobar\x0d?$/ms, 'body pipelined');
114 like(http_get_body('/', '0123456789' x 128, '0123456789' x 512, '0123456789',
115 'foobar'), qr/X-Body: foobar\x0d?$/ms, 'body pipelined 2');
116
117 like(http_get_body('/discard', '0123456789', '0123456789' x 128,
118 '0123456789' x 512, 'foobar'), qr/(TEST.*){4}/ms,
119 'body discard');
120 like(http_get_body('/discard', '0123456789' x 128, '0123456789' x 512,
121 '0123456789', 'foobar'), qr/(TEST.*){4}/ms,
122 'body discard 2');
123
124 # proxy with file only is disabled in unbuffered mode
125
126 like(http_get_body('/small', '0123456789'),
127 qr/X-Body: 0123456789\x0d?$/ms, 'small body in file only');
128
129 # interactive tests
130
131 my $s = get_body('/preread', 8082);
132 ok($s, 'no preread');
133
134 SKIP: {
135 skip 'no preread failed', 3 unless $s;
136
137 is($s->{upload}('01234'), '5' . CRLF . '01234' . CRLF,
138 'no preread - body part');
139 is($s->{upload}('56789', last => 1),
140 '5' . CRLF . '56789' . CRLF . '0' . CRLF . CRLF,
141 'no preread - body part 2');
142
143 like($s->{http_end}(), qr/200 OK/, 'no preread - response');
144
145 }
146
147 $s = get_body('/preread', 8082, '01234');
148 ok($s, 'preread');
149
150 SKIP: {
151 skip 'preread failed', 3 unless $s;
152
153 TODO: {
154 local $TODO = 'not yet' unless $t->has_version('1.7.12');
155
156 is($s->{preread}, '5' . CRLF . '01234' . CRLF, 'preread - preread');
157
158 }
159
160 is($s->{upload}('56789', last => 1),
161 '5' . CRLF . '56789' . CRLF . '0' . CRLF . CRLF, 'preread - body');
162
163 like($s->{http_end}(), qr/200 OK/, 'preread - response');
164
165 }
166
167 $s = get_body('/preread', 8082, '01234', many => 1);
168 ok($s, 'chunks');
169
170 SKIP: {
171 skip 'chunks failed', 3 unless $s;
172
173 TODO: {
174 local $TODO = 'not yet' unless $t->has_version('1.7.12');
175
176 is($s->{preread}, '9' . CRLF . '01234many' . CRLF, 'chunks - preread');
177
178 }
179
180 is($s->{upload}('56789', many => 1, last => 1),
181 '9' . CRLF . '56789many' . CRLF . '0' . CRLF . CRLF, 'chunks - body');
182
183 like($s->{http_end}(), qr/200 OK/, 'chunks - response');
184
185 }
186
187 ###############################################################################
188
189 sub http_get_body {
190 my $uri = shift;
191 my $last = pop;
192 return http( join '', (map {
193 my $body = $_;
194 "GET $uri HTTP/1.1" . CRLF
195 . "Host: localhost" . CRLF
196 . "Content-Length: " . (length $body) . CRLF . CRLF
197 . $body
198 } @_),
199 "GET $uri HTTP/1.1" . CRLF
200 . "Host: localhost" . CRLF
201 . "Connection: close" . CRLF
202 . "Content-Length: " . (length $last) . CRLF . CRLF
203 . $last
204 );
205 }
206
207 sub get_body {
208 my ($url, $port, $body, %extra) = @_;
209 my ($server, $client, $s);
210 my ($last, $many) = (0, 0);
211
212 $last = $extra{last} if defined $extra{last};
213 $many = $extra{many} if defined $extra{many};
214
215 $server = IO::Socket::INET->new(
216 Proto => 'tcp',
217 LocalHost => '127.0.0.1',
218 LocalPort => $port,
219 Listen => 5,
220 Reuse => 1
221 )
222 or die "Can't create listening socket: $!\n";
223
224 my $r = <<EOF;
225 GET $url HTTP/1.1
226 Host: localhost
227 Connection: close
228 Transfer-Encoding: chunked
229
230 EOF
231
232 if (defined $body) {
233 $r .= sprintf("%x", length $body) . CRLF;
234 $r .= $body . CRLF;
235 }
236 if (defined $body && $many) {
237 $r .= sprintf("%x", length 'many') . CRLF;
238 $r .= 'many' . CRLF;
239 }
240 if ($last) {
241 $r .= "0" . CRLF . CRLF;
242 }
243
244 $s = http($r, start => 1);
245
246 eval {
247 local $SIG{ALRM} = sub { die "timeout\n" };
248 local $SIG{PIPE} = sub { die "sigpipe\n" };
249 alarm(5);
250
251 $client = $server->accept();
252
253 alarm(0);
254 };
255 alarm(0);
256 if ($@) {
257 log_in("died: $@");
258 return undef;
259 }
260
261 $client->sysread(my $buf, 1024);
262 $buf =~ s/.*?\x0d\x0a?\x0d\x0a?(.*)/$1/ms;
263
264 my $f = { preread => $buf };
265 $f->{upload} = sub {
266 my ($body, %extra) = @_;
267 my ($last, $many) = (0, 0);
268
269 $last = $extra{last} if defined $extra{last};
270 $many = $extra{many} if defined $extra{many};
271
272 my $buf = sprintf("%x", length $body) . CRLF;
273 $buf .= $body . CRLF;
274 if ($many) {
275 $buf .= sprintf("%x", length 'many') . CRLF;
276 $buf .= 'many' . CRLF;
277 }
278 if ($last) {
279 $buf .= "0" . CRLF . CRLF;
280 }
281
282 eval {
283 local $SIG{ALRM} = sub { die "timeout\n" };
284 local $SIG{PIPE} = sub { die "sigpipe\n" };
285 alarm(5);
286
287 $s->write($buf);
288 $client->sysread($buf, 1024);
289
290 alarm(0);
291 };
292 alarm(0);
293 if ($@) {
294 log_in("died: $@");
295 return undef;
296 }
297
298 return $buf;
299 };
300 $f->{http_end} = sub {
301 my $buf = '';
302
303 $client->write(<<EOF);
304 HTTP/1.1 200 OK
305 Connection: close
306 X-Port: $port
307
308 OK
309 EOF
310
311 $client->close;
312
313 eval {
314 local $SIG{ALRM} = sub { die "timeout\n" };
315 local $SIG{PIPE} = sub { die "sigpipe\n" };
316 alarm(5);
317
318 $s->sysread($buf, 1024);
319 $s->close();
320
321 alarm(0);
322 };
323 alarm(0);
324 if ($@) {
325 log_in("died: $@");
326 return undef;
327 }
328
329 return $buf;
330 };
331 return $f;
332 }
333
334 ###############################################################################