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