comparison proxy_keepalive.t @ 250:0c9f15938545

Tests: upstream keepalive tests imported.
author Maxim Dounin <mdounin@mdounin.ru>
date Thu, 24 Jan 2013 02:00:03 +0400
parents
children 957fe2a76aa7
comparison
equal deleted inserted replaced
249:6a0d934950bc 250:0c9f15938545
1 #!/usr/bin/perl
2
3 # (C) Maxim Dounin
4
5 # Tests for proxy with keepalive.
6
7 ###############################################################################
8
9 use warnings;
10 use strict;
11
12 use Test::More;
13
14 use IO::Socket::INET;
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 ssi rewrite/)
28 ->write_file_expand('nginx.conf', <<'EOF');
29
30 %%TEST_GLOBALS%%
31
32 daemon off;
33
34 events {
35 }
36
37 http {
38 %%TEST_GLOBALS_HTTP%%
39
40 upstream backend {
41 server 127.0.0.1:8081;
42 keepalive 1;
43 }
44
45 server {
46 listen 127.0.0.1:8080;
47 server_name localhost;
48
49 proxy_read_timeout 2s;
50 proxy_http_version 1.1;
51 proxy_set_header Connection "";
52
53 location / {
54 proxy_pass http://backend;
55 }
56
57 location /unbuffered/ {
58 proxy_pass http://backend;
59 proxy_buffering off;
60 }
61
62 location /inmemory/ {
63 ssi on;
64 rewrite ^ /ssi.html break;
65 }
66 }
67 }
68
69 EOF
70
71 $t->write_file('ssi.html',
72 '<!--#include virtual="/include$request_uri" set="x" -->' .
73 'set: <!--#echo var="x" -->');
74
75 $t->run_daemon(\&http_daemon);
76
77 eval {
78 open OLDERR, ">&", \*STDERR; close STDERR;
79 $t->run();
80 open STDERR, ">&", \*OLDERR;
81 };
82 plan(skip_all => 'no keepalive patches') if $@;
83
84 $t->plan(50);
85
86 ###############################################################################
87
88 # There are 3 mostly independend modes of upstream operation:
89 #
90 # 1. Buffered, i.e. normal mode with "proxy_buffering on;"
91 # 2. Unbuffered, i.e. "proxy_buffering off;".
92 # 3. In memory, i.e. ssi <!--#include ... set -->
93 #
94 # These all should be tested.
95
96 my ($r, $n);
97
98 # buffered
99
100 like($r = http_get('/buffered/length1'), qr/SEE-THIS/, 'buffered');
101 $r =~ m/X-Connection: (\d+)/; $n = $1;
102 like(http_get('/buffered/length2'), qr/X-Connection: $n.*SEE/ms, 'buffered 2');
103
104 like($r = http_get('/buffered/chunked1'), qr/SEE-THIS/, 'buffered chunked');
105 $r =~ m/X-Connection: (\d+)/; $n = $1;
106 like(http_get('/buffered/chunked2'), qr/X-Connection: $n/,
107 'buffered chunked 2');
108
109 like($r = http_get('/buffered/complex1'), qr/(0123456789){100}/,
110 'buffered complex chunked');
111 $r =~ m/X-Connection: (\d+)/; $n = $1;
112 like(http_get('/buffered/complex2'), qr/X-Connection: $n/,
113 'buffered complex chunked 2');
114
115 like($r = http_get('/buffered/chunk01'), qr/200 OK/, 'buffered 0 chunk');
116 $r =~ m/X-Connection: (\d+)/; $n = $1;
117 like(http_get('/buffered/chunk02'), qr/X-Connection: $n/, 'buffered 0 chunk 2');
118
119 like($r = http_head('/buffered/length/head1'), qr/(?!SEE-THIS)/,
120 'buffered head');
121 $r =~ m/X-Connection: (\d+)/; $n = $1;
122 like(http_head('/buffered/length/head2'), qr/X-Connection: $n/,
123 'buffered head 2');
124
125 like($r = http_get('/buffered/empty1'), qr/200 OK/, 'buffered empty');
126 $r =~ m/X-Connection: (\d+)/; $n = $1;
127 like(http_get('/buffered/empty2'), qr/X-Connection: $n/, 'buffered empty 2');
128
129 like($r = http_get('/buffered/304nolen1'), qr/304 Not/, 'buffered 304');
130 $r =~ m/X-Connection: (\d+)/; $n = $1;
131 like(http_get('/buffered/304nolen2'), qr/X-Connection: $n/, 'buffered 304 2');
132
133 like($r = http_get('/buffered/304len1'), qr/304 Not/,
134 'buffered 304 with length');
135 $r =~ m/X-Connection: (\d+)/; $n = $1;
136 like(http_get('/buffered/304len2'), qr/X-Connection: $n/,
137 'buffered 304 with length 2');
138
139 # unbuffered
140
141 like($r = http_get('/unbuffered/length1'), qr/SEE-THIS/, 'unbuffered');
142 $r =~ m/X-Connection: (\d+)/; $n = $1;
143 like(http_get('/unbuffered/length2'), qr/X-Connection: $n/, 'unbuffered 2');
144
145 like($r = http_get('/unbuffered/chunked1'), qr/SEE-THIS/, 'unbuffered chunked');
146 $r =~ m/X-Connection: (\d+)/; $n = $1;
147 like(http_get('/unbuffered/chunked2'), qr/X-Connection: $n/,
148 'unbuffered chunked 2');
149
150 like($r = http_get('/unbuffered/complex1'), qr/(0123456789){100}/,
151 'unbuffered complex chunked');
152 $r =~ m/X-Connection: (\d+)/; $n = $1;
153 like(http_get('/unbuffered/complex2'), qr/X-Connection: $n/,
154 'unbuffered complex chunked 2');
155
156 like($r = http_get('/unbuffered/chunk01'), qr/200 OK/, 'unbuffered 0 chunk');
157 $r =~ m/X-Connection: (\d+)/; $n = $1;
158 like(http_get('/unbuffered/chunk02'), qr/X-Connection: $n/,
159 'unbuffered 0 chunk 2');
160
161 like($r = http_get('/unbuffered/empty1'), qr/200 OK/, 'unbuffered empty');
162 $r =~ m/X-Connection: (\d+)/; $n = $1;
163 like(http_get('/unbuffered/empty2'), qr/X-Connection: $n/,
164 'unbuffered empty 2');
165
166 like($r = http_head('/unbuffered/length/head1'), qr/(?!SEE-THIS)/,
167 'unbuffered head');
168 $r =~ m/X-Connection: (\d+)/; $n = $1;
169 like(http_head('/unbuffered/length/head2'), qr/X-Connection: $n/,
170 'unbuffered head 2');
171
172 like($r = http_get('/unbuffered/304nolen1'), qr/304 Not/, 'unbuffered 304');
173 $r =~ m/X-Connection: (\d+)/; $n = $1;
174 like(http_get('/unbuffered/304nolen2'), qr/X-Connection: $n/,
175 'unbuffered 304 2');
176
177 like($r = http_get('/unbuffered/304len1'), qr/304 Not/,
178 'unbuffered 304 with length');
179 $r =~ m/X-Connection: (\d+)/; $n = $1;
180 like(http_get('/unbuffered/304len2'), qr/X-Connection: $n/,
181 'unbuffered 304 with length 2');
182
183 # in memory
184
185 like($r = http_get('/inmemory/length1'), qr/SEE-THIS/, 'inmemory');
186 $r =~ m/SEE-THIS(\d+)/; $n = $1;
187 like(http_get('/inmemory/length2'), qr/SEE-THIS$n/, 'inmemory 2');
188
189 like($r = http_get('/inmemory/empty1'), qr/200 OK/, 'inmemory empty');
190 $r =~ m/SEE-THIS(\d+)/; $n = $1;
191 like(http_get('/inmemory/empty2'), qr/200 OK/, 'inmemory empty 2');
192
193 like($r = http_get('/inmemory/chunked1'), qr/SEE-THIS/, 'inmemory chunked');
194 $r =~ m/SEE-THIS(\d+)/; $n = $1;
195 like(http_get('/inmemory/chunked2'), qr/SEE-THIS$n/, 'inmemory chunked 2');
196
197 like($r = http_get('/inmemory/complex1'), qr/(0123456789){100}/,
198 'inmemory complex chunked');
199 $r =~ m/SEE-THIS(\d+)/; $n = $1;
200 like(http_get('/inmemory/complex2'), qr/SEE-THIS$n/,
201 'inmemory complex chunked 2');
202
203 like(http_get('/inmemory/chunk01'), qr/set: $/, 'inmemory 0 chunk');
204 like(http_get('/inmemory/chunk02'), qr/set: $/, 'inmemory 0 chunk 2');
205
206 # closed connection tests
207
208 like(http_get('/buffered/closed1'), qr/200 OK/, 'buffered closed 1');
209 like(http_get('/buffered/closed2'), qr/200 OK/, 'buffered closed 2');
210 like(http_get('/unbuffered/closed1'), qr/200 OK/, 'unbuffered closed 1');
211 like(http_get('/unbuffered/closed2'), qr/200 OK/, 'unbuffered closed 2');
212 like(http_get('/inmemory/closed1'), qr/200 OK/, 'inmemory closed 1');
213 like(http_get('/inmemory/closed2'), qr/200 OK/, 'inmemory closed 2');
214
215 # check for errors, shouldn't be any
216
217 like(`grep -F '[alert]' ${\($t->testdir())}/error.log`, qr/^$/s, 'no alerts');
218 like(`grep -F '[error]' ${\($t->testdir())}/error.log`, qr/^$/s, 'no errors');
219
220 ###############################################################################
221
222 sub http_daemon {
223 my $server = IO::Socket::INET->new(
224 Proto => 'tcp',
225 LocalHost => '127.0.0.1:8081',
226 Listen => 5,
227 Reuse => 1
228 )
229 or die "Can't create listening socket: $!\n";
230
231 my $ccount = 0;
232 my $rcount = 0;
233
234 # dumb server which is able to keep connections alive
235
236 while (my $client = $server->accept()) {
237 Test::Nginx::log_core('||',
238 "connection from " . $client->peerhost());
239 $client->autoflush(1);
240 $ccount++;
241
242 while (1) {
243 my $headers = '';
244 my $uri = '';
245
246 while (<$client>) {
247 Test::Nginx::log_core('||', $_);
248 $headers .= $_;
249 last if (/^\x0d?\x0a?$/);
250 }
251
252 last if $headers eq '';
253 $rcount++;
254
255 $uri = $1 if $headers =~ /^\S+\s+([^ ]+)\s+HTTP/i;
256
257 if ($uri =~ m/length/) {
258 print $client
259 "HTTP/1.1 200 OK" . CRLF .
260 "X-Request: $rcount" . CRLF .
261 "X-Connection: $ccount" . CRLF .
262 "Content-Length: 26" . CRLF . CRLF;
263 print $client "TEST-OK-IF-YOU-SEE-THIS" .
264 sprintf("%03d", $ccount)
265 unless $headers =~ /^HEAD/i;
266
267 } elsif ($uri =~ m/empty/) {
268 print $client
269 "HTTP/1.1 200 OK" . CRLF .
270 "X-Request: $rcount" . CRLF .
271 "X-Connection: $ccount" . CRLF .
272 "Content-Length: 0" . CRLF . CRLF;
273
274 } elsif ($uri =~ m/304nolen/) {
275 print $client
276 "HTTP/1.1 304 Not Modified" . CRLF .
277 "X-Request: $rcount" . CRLF .
278 "X-Connection: $ccount" . CRLF . CRLF;
279
280 } elsif ($uri =~ m/304len/) {
281 print $client
282 "HTTP/1.1 304 Not Modified" . CRLF .
283 "X-Request: $rcount" . CRLF .
284 "X-Connection: $ccount" . CRLF .
285 "Content-Length: 100" . CRLF . CRLF;
286
287 } elsif ($uri =~ m/chunked/) {
288 print $client
289 "HTTP/1.1 200 OK" . CRLF .
290 "X-Request: $rcount" . CRLF .
291 "X-Connection: $ccount" . CRLF .
292 "Transfer-Encoding: chunked" . CRLF .
293 CRLF;
294 print $client
295 "1a" . CRLF .
296 "TEST-OK-IF-YOU-SEE-THIS" .
297 sprintf("%03d", $ccount) . CRLF .
298 "0" . CRLF . CRLF
299 unless $headers =~ /^HEAD/i;
300
301 } elsif ($uri =~ m/complex/) {
302 print $client
303 "HTTP/1.1 200 OK" . CRLF .
304 "X-Request: $rcount" . CRLF .
305 "X-Connection: $ccount" . CRLF .
306 "Transfer-Encoding: chunked" . CRLF .
307 CRLF;
308
309 if ($headers !~ /^HEAD/i) {
310 for my $n (1..100) {
311 print $client
312 "a" . CRLF .
313 "0123456789" . CRLF;
314 select undef, undef, undef, 0.01
315 if $n % 50 == 0;
316 }
317 print $client
318 "1a" . CRLF .
319 "TEST-OK-IF-YOU-SEE-THIS" .
320 sprintf("%03d", $ccount) .
321 CRLF .
322 "0" . CRLF;
323 select undef, undef, undef, 0.05;
324 print $client CRLF;
325 }
326
327 } elsif ($uri =~ m/chunk0/) {
328 print $client
329 "HTTP/1.1 200 OK" . CRLF .
330 "X-Request: $rcount" . CRLF .
331 "X-Connection: $ccount" . CRLF .
332 "Transfer-Encoding: chunked" . CRLF .
333 CRLF;
334 print $client
335 "0" . CRLF . CRLF
336 unless $headers =~ /^HEAD/i;
337
338 } elsif ($uri =~ m/closed/) {
339 print $client
340 "HTTP/1.1 200 OK" . CRLF .
341 "X-Request: $rcount" . CRLF .
342 "X-Connection: $ccount" . CRLF .
343 "Connection: close" . CRLF .
344 "Content-Length: 12" . CRLF . CRLF .
345 "0123456789" . CRLF;
346 last;
347
348 } else {
349 print $client
350 "HTTP/1.1 404 Not Found" . CRLF .
351 "X-Request: $rcount" . CRLF .
352 "X-Connection: $ccount" . CRLF .
353 "Connection: close" . CRLF . CRLF .
354 "Oops, '$uri' not found" . CRLF;
355 last;
356 }
357 }
358
359 close $client;
360 }
361 }
362
363 ###############################################################################