blob: e7b3a0314b47565999dc64207725caf4a948e01c [file] [log] [blame]
Sergey Kandaurov26b256c2014-09-16 14:22:27 +04001#!/usr/bin/perl
2
3# (C) Sergey Kandaurov
4# (C) Nginx, Inc.
5
6# Tests for http proxy module, proxy_next_upstream_tries
7# and proxy_next_upstream_timeout directives.
8
9###############################################################################
10
11use warnings;
12use strict;
13
14use Test::More;
15
16BEGIN { use FindBin; chdir($FindBin::Bin); }
17
18use lib 'lib';
19use Test::Nginx;
20
21###############################################################################
22
23select STDERR; $| = 1;
24select STDOUT; $| = 1;
25
Sergey Kandaurov66f73d22015-05-03 12:45:09 +030026my $t = Test::Nginx->new()->has(qw/http proxy rewrite/)->plan(8);
Sergey Kandaurov26b256c2014-09-16 14:22:27 +040027
28$t->write_file_expand('nginx.conf', <<'EOF');
29
30%%TEST_GLOBALS%%
31
32daemon off;
33
34events {
35}
36
37http {
38 %%TEST_GLOBALS_HTTP%%
39
40 upstream u {
Andrey Zelenkove59bf362016-07-12 17:39:03 +030041 server 127.0.0.1:8081;
42 server 127.0.0.1:8081;
43 server 127.0.0.1:8081;
Sergey Kandaurov26b256c2014-09-16 14:22:27 +040044 }
45
46 upstream u2 {
Andrey Zelenkove59bf362016-07-12 17:39:03 +030047 server 127.0.0.1:8081;
48 server 127.0.0.1:8081 backup;
49 server 127.0.0.1:8081 backup;
Sergey Kandaurov26b256c2014-09-16 14:22:27 +040050 }
51
Sergey Kandaurov26b256c2014-09-16 14:22:27 +040052 server {
Andrey Zelenkove59bf362016-07-12 17:39:03 +030053 listen 127.0.0.1:8080;
Sergey Kandaurov26b256c2014-09-16 14:22:27 +040054 server_name localhost;
55
56 proxy_next_upstream http_404;
57 proxy_intercept_errors on;
58 error_page 404 /404;
59
60 location /tries {
61 proxy_pass http://u;
62 proxy_next_upstream_tries 2;
63 }
64
65 location /tries/backup {
66 proxy_pass http://u2;
67 proxy_next_upstream_tries 2;
68 }
69
Sergey Kandaurov099d1252014-10-27 16:48:49 +030070 location /tries/resolver {
Andrey Zelenkov6503afd2017-09-13 19:04:25 +030071 resolver 127.0.0.1:%%PORT_8982_UDP%%;
Sergey Kandaurov099d1252014-10-27 16:48:49 +030072
Andrey Zelenkove59bf362016-07-12 17:39:03 +030073 proxy_pass http://$host:%%PORT_8081%%;
Sergey Kandaurov099d1252014-10-27 16:48:49 +030074 proxy_next_upstream_tries 2;
75 }
76
Sergey Kandaurov008bef72014-11-07 15:11:18 +030077 location /tries/zero {
78 proxy_pass http://u;
79 proxy_next_upstream_tries 0;
80 }
81
Sergey Kandaurov26b256c2014-09-16 14:22:27 +040082 location /timeout {
Sergey Kandaurovc4c6bd12015-06-16 20:39:22 +030083 proxy_pass http://u/w2;
84 proxy_next_upstream_timeout 3800ms;
Sergey Kandaurov26b256c2014-09-16 14:22:27 +040085 }
86
87 location /timeout/backup {
Sergey Kandaurovc4c6bd12015-06-16 20:39:22 +030088 proxy_pass http://u2/w2;
89 proxy_next_upstream_timeout 3800ms;
Sergey Kandaurov26b256c2014-09-16 14:22:27 +040090 }
91
Sergey Kandaurov099d1252014-10-27 16:48:49 +030092 location /timeout/resolver {
Andrey Zelenkov6503afd2017-09-13 19:04:25 +030093 resolver 127.0.0.1:%%PORT_8982_UDP%%;
Sergey Kandaurov099d1252014-10-27 16:48:49 +030094
Andrey Zelenkove59bf362016-07-12 17:39:03 +030095 proxy_pass http://$host:%%PORT_8081%%/w2;
Sergey Kandaurovc4c6bd12015-06-16 20:39:22 +030096 proxy_next_upstream_timeout 3800ms;
Sergey Kandaurov099d1252014-10-27 16:48:49 +030097 }
98
Sergey Kandaurov008bef72014-11-07 15:11:18 +030099 location /timeout/zero {
Sergey Kandaurovd04771f2014-11-07 15:20:02 +0300100 proxy_pass http://u/w;
Sergey Kandaurov008bef72014-11-07 15:11:18 +0300101 proxy_next_upstream_timeout 0;
102 }
103
Sergey Kandaurov26b256c2014-09-16 14:22:27 +0400104 location /404 {
105 return 200 x${upstream_status}x;
106 }
107 }
108}
109
110EOF
111
Andrey Zelenkove59bf362016-07-12 17:39:03 +0300112$t->run_daemon(\&http_daemon, port(8081));
Andrey Zelenkov6503afd2017-09-13 19:04:25 +0300113$t->run_daemon(\&dns_daemon, port(8982), $t);
Sergey Kandaurov66f73d22015-05-03 12:45:09 +0300114$t->run();
Sergey Kandaurov26b256c2014-09-16 14:22:27 +0400115
Andrey Zelenkove59bf362016-07-12 17:39:03 +0300116$t->waitforsocket('127.0.0.1:' . port(8081));
Andrey Zelenkov6503afd2017-09-13 19:04:25 +0300117$t->waitforfile($t->testdir . '/' . port(8982));
Sergey Kandaurov26b256c2014-09-16 14:22:27 +0400118
119###############################################################################
120
121like(http_get('/tries'), qr/x404, 404x/, 'tries');
122like(http_get('/tries/backup'), qr/x404, 404x/, 'tries backup');
Sergey Kandaurov099d1252014-10-27 16:48:49 +0300123like(http_get('/tries/resolver'), qr/x404, 404x/, 'tries resolved');
Sergey Kandaurov008bef72014-11-07 15:11:18 +0300124like(http_get('/tries/zero'), qr/x404, 404, 404x/, 'tries zero');
125
Sergey Kandaurov6964f122014-11-07 15:07:26 +0300126# two tries fit into 1.9s
Sergey Kandaurov26b256c2014-09-16 14:22:27 +0400127
Sergey Kandaurovc4c6bd12015-06-16 20:39:22 +0300128SKIP: {
129skip 'long tests', 4 unless $ENV{TEST_NGINX_UNSAFE};
130
Sergey Kandaurov26b256c2014-09-16 14:22:27 +0400131like(http_get('/timeout'), qr/x404, 404x/, 'timeout');
132like(http_get('/timeout/backup'), qr/x404, 404x/, 'timeout backup');
Sergey Kandaurov099d1252014-10-27 16:48:49 +0300133like(http_get('/timeout/resolver'), qr/x404, 404x/, 'timeout resolved');
Sergey Kandaurov008bef72014-11-07 15:11:18 +0300134like(http_get('/timeout/zero'), qr/x404, 404, 404x/, 'timeout zero');
135
Sergey Kandaurovc4c6bd12015-06-16 20:39:22 +0300136}
137
Sergey Kandaurov26b256c2014-09-16 14:22:27 +0400138###############################################################################
139
140sub http_daemon {
141 my ($port) = @_;
142
143 my $server = IO::Socket::INET->new(
144 Proto => 'tcp',
145 LocalHost => '127.0.0.1',
146 LocalPort => $port,
147 Listen => 5,
148 Reuse => 1
149 )
150 or die "Can't create listening socket: $!\n";
151
152 local $SIG{PIPE} = 'IGNORE';
153
154 while (my $client = $server->accept()) {
155 $client->autoflush(1);
156
157 my $headers = '';
Sergey Kandaurovd04771f2014-11-07 15:20:02 +0300158 my $uri = '';
Sergey Kandaurov26b256c2014-09-16 14:22:27 +0400159
160 while (<$client>) {
161 $headers .= $_;
162 last if (/^\x0d?\x0a?$/);
163 }
164
165 next if $headers eq '';
166
Sergey Kandaurovd04771f2014-11-07 15:20:02 +0300167 $uri = $1 if $headers =~ /^\S+\s+([^ ]+)\s+HTTP/i;
168
169 if ($uri eq '/w') {
Sergey Kandaurov26b256c2014-09-16 14:22:27 +0400170 Test::Nginx::log_core('||', "$port: sleep(1)");
171 select undef, undef, undef, 1;
172 }
173
Sergey Kandaurovc4c6bd12015-06-16 20:39:22 +0300174 if ($uri eq '/w2') {
175 Test::Nginx::log_core('||', "$port: sleep(2)");
176 select undef, undef, undef, 2;
177 }
178
Sergey Kandaurov26b256c2014-09-16 14:22:27 +0400179 Test::Nginx::log_core('||', "$port: response, 404");
180 print $client <<EOF;
181HTTP/1.1 404 Not Found
182Connection: close
183
184EOF
185
186 } continue {
187 close $client;
188 }
189}
190
Sergey Kandaurov099d1252014-10-27 16:48:49 +0300191sub reply_handler {
192 my ($recv_data) = @_;
193
194 my (@name, @rdata);
195
196 use constant NOERROR => 0;
197 use constant A => 1;
Andrey Zelenkov5ba1c972016-05-24 16:09:57 +0300198 use constant IN => 1;
Sergey Kandaurov099d1252014-10-27 16:48:49 +0300199
200 # default values
201
202 my ($hdr, $rcode, $ttl) = (0x8180, NOERROR, 3600);
203
204 # decode name
205
206 my ($len, $offset) = (undef, 12);
207 while (1) {
208 $len = unpack("\@$offset C", $recv_data);
209 last if $len == 0;
210 $offset++;
211 push @name, unpack("\@$offset A$len", $recv_data);
212 $offset += $len;
213 }
214
215 $offset -= 1;
216 my ($id, $type, $class) = unpack("n x$offset n2", $recv_data);
217
Sergey Kandaurov7b25f832014-10-28 19:29:17 +0300218 @rdata = map { rd_addr($ttl, '127.0.0.1') } (1 .. 3) if $type == A;
Sergey Kandaurov099d1252014-10-27 16:48:49 +0300219
220 $len = @name;
Sergey Kandaurov74cb5c62015-11-05 14:02:53 +0300221 pack("n6 (C/a*)$len x n2", $id, $hdr | $rcode, 1, scalar @rdata,
Sergey Kandaurov099d1252014-10-27 16:48:49 +0300222 0, 0, @name, $type, $class) . join('', @rdata);
223}
224
225sub rd_addr {
226 my ($ttl, $addr) = @_;
227
228 my $code = 'split(/\./, $addr)';
229
230 return pack 'n3N', 0xc00c, A, IN, $ttl if $addr eq '';
231
232 pack 'n3N nC4', 0xc00c, A, IN, $ttl, eval "scalar $code", eval($code);
233}
234
235sub dns_daemon {
236 my ($port, $t) = @_;
237
238 my ($data, $recv_data);
239 my $socket = IO::Socket::INET->new(
Andrey Zelenkov5ba1c972016-05-24 16:09:57 +0300240 LocalAddr => '127.0.0.1',
241 LocalPort => $port,
242 Proto => 'udp',
Sergey Kandaurov099d1252014-10-27 16:48:49 +0300243 )
244 or die "Can't create listening socket: $!\n";
245
246 # signal we are ready
247
248 open my $fh, '>', $t->testdir() . '/' . $port;
249 close $fh;
250
251 while (1) {
252 $socket->recv($recv_data, 65536);
253 $data = reply_handler($recv_data);
254 $socket->send($data);
255 }
256}
257
Sergey Kandaurov26b256c2014-09-16 14:22:27 +0400258###############################################################################