| 1 | #!/usr/bin/perl
|
|---|
| 2 |
|
|---|
| 3 | # (C) Maxim Dounin
|
|---|
| 4 | # (C) Markus Linnala
|
|---|
| 5 |
|
|---|
| 6 | # Tests keepalive is kept regardless proxy type.
|
|---|
| 7 |
|
|---|
| 8 | ###############################################################################
|
|---|
| 9 |
|
|---|
| 10 | use warnings;
|
|---|
| 11 | use strict;
|
|---|
| 12 |
|
|---|
| 13 | use Test::More;
|
|---|
| 14 |
|
|---|
| 15 | use IO::Socket::INET;
|
|---|
| 16 | use Socket qw/ CRLF /;
|
|---|
| 17 |
|
|---|
| 18 | BEGIN { use FindBin; chdir($FindBin::Bin); }
|
|---|
| 19 |
|
|---|
| 20 | use lib 'lib';
|
|---|
| 21 | use Test::Nginx;
|
|---|
| 22 |
|
|---|
| 23 | ###############################################################################
|
|---|
| 24 |
|
|---|
| 25 | select STDERR; $| = 1;
|
|---|
| 26 | select STDOUT; $| = 1;
|
|---|
| 27 |
|
|---|
| 28 | plan(skip_all => 'win32') if $^O eq 'MSWin32';
|
|---|
| 29 |
|
|---|
| 30 | my $t = Test::Nginx->new()->has(qw/http proxy upstream_keepalive sub/)->plan(16)
|
|---|
| 31 | ->write_file_expand('nginx.conf', <<'EOF');
|
|---|
| 32 |
|
|---|
| 33 | %%TEST_GLOBALS%%
|
|---|
| 34 |
|
|---|
| 35 | daemon off;
|
|---|
| 36 |
|
|---|
| 37 | events {
|
|---|
| 38 | }
|
|---|
| 39 |
|
|---|
| 40 | http {
|
|---|
| 41 | %%TEST_GLOBALS_HTTP%%
|
|---|
| 42 |
|
|---|
| 43 | upstream backend {
|
|---|
| 44 | server 127.0.0.1:8081;
|
|---|
| 45 | keepalive 1;
|
|---|
| 46 | }
|
|---|
| 47 |
|
|---|
| 48 | server {
|
|---|
| 49 | listen 127.0.0.1:8080;
|
|---|
| 50 | server_name localhost;
|
|---|
| 51 |
|
|---|
| 52 | location /cl {
|
|---|
| 53 | proxy_pass http://backend;
|
|---|
| 54 | }
|
|---|
| 55 | location /ka {
|
|---|
| 56 | proxy_pass http://backend;
|
|---|
| 57 | proxy_read_timeout 2s;
|
|---|
| 58 | proxy_http_version 1.1;
|
|---|
| 59 | proxy_set_header Connection "";
|
|---|
| 60 | }
|
|---|
| 61 |
|
|---|
| 62 | location /cl-ch {
|
|---|
| 63 | sub_filter foo bar;
|
|---|
| 64 | sub_filter_types *;
|
|---|
| 65 | proxy_pass http://backend;
|
|---|
| 66 | }
|
|---|
| 67 | location /ka-ch {
|
|---|
| 68 | sub_filter foo bar;
|
|---|
| 69 | sub_filter_types *;
|
|---|
| 70 | proxy_pass http://backend;
|
|---|
| 71 | proxy_read_timeout 2s;
|
|---|
| 72 | proxy_http_version 1.1;
|
|---|
| 73 | proxy_set_header Connection "";
|
|---|
| 74 | }
|
|---|
| 75 | }
|
|---|
| 76 | }
|
|---|
| 77 |
|
|---|
| 78 | EOF
|
|---|
| 79 |
|
|---|
| 80 | $t->run_daemon(\&http_daemon);
|
|---|
| 81 | $t->run()->waitforsocket('127.0.0.1:8081')
|
|---|
| 82 | or die "Can't start test backend";
|
|---|
| 83 |
|
|---|
| 84 | ###############################################################################
|
|---|
| 85 |
|
|---|
| 86 | sub http_ka {
|
|---|
| 87 | my ($q, $p) = @_;
|
|---|
| 88 | my_http(<<EOF, 'sleep' => 0.1);
|
|---|
| 89 | GET $q HTTP/$p
|
|---|
| 90 | Host: localhost
|
|---|
| 91 | Connection: Keep-Alive
|
|---|
| 92 |
|
|---|
| 93 | EOF
|
|---|
| 94 | }
|
|---|
| 95 |
|
|---|
| 96 | sub http_cl {
|
|---|
| 97 | my ($q, $p) = @_;
|
|---|
| 98 | my_http(<<EOF, 'sleep' => 0.1);
|
|---|
| 99 | GET $q HTTP/$p
|
|---|
| 100 | Host: localhost
|
|---|
| 101 | Connection: close
|
|---|
| 102 |
|
|---|
| 103 | EOF
|
|---|
| 104 | }
|
|---|
| 105 |
|
|---|
| 106 | ###############################################################################
|
|---|
| 107 |
|
|---|
| 108 | like(http_ka('/ka','1.0'), qr/Connection: keep-alive/, 'ka-ka/1.0');
|
|---|
| 109 | like(http_cl('/ka','1.0'), qr/Connection: close/, 'ka-cl/1.0');
|
|---|
| 110 |
|
|---|
| 111 | like(http_ka('/ka','1.1'), qr/Connection: keep-alive/, 'ka-ka/1.1');
|
|---|
| 112 | like(http_cl('/ka','1.1'), qr/Connection: close/, 'ka-cl/1.1');
|
|---|
| 113 |
|
|---|
| 114 | like(http_ka('/cl','1.0'), qr/Connection: keep-alive/, 'cl-ka/1.0');
|
|---|
| 115 | like(http_cl('/cl','1.0'), qr/Connection: close/, 'cl-cl/1.0');
|
|---|
| 116 |
|
|---|
| 117 | like(http_ka('/cl','1.1'), qr/Connection: keep-alive/, 'cl-ka/1.1');
|
|---|
| 118 | like(http_cl('/cl','1.1'), qr/Connection: close/, 'cl-cl/1.1');
|
|---|
| 119 |
|
|---|
| 120 | like(http_ka('/ka-ch','1.0'), qr/Connection: keep-alive/, 'ka-ch-ka/1.0'); #
|
|---|
| 121 | like(http_cl('/ka-ch','1.0'), qr/Connection: close/, 'ka-ch-cl/1.0');
|
|---|
| 122 |
|
|---|
| 123 | like(http_ka('/ka-ch','1.1'), qr/Connection: keep-alive/, 'ka-ch-ka/1.1');
|
|---|
| 124 | like(http_cl('/ka-ch','1.1'), qr/Connection: close/, 'ka-ch-cl/1.1');
|
|---|
| 125 |
|
|---|
| 126 | like(http_ka('/cl-ch','1.0'), qr/Connection: keep-alive/, 'cl-ch-ka/1.0'); #
|
|---|
| 127 | like(http_cl('/cl-ch','1.0'), qr/Connection: close/, 'cl-ch-cl/1.0');
|
|---|
| 128 |
|
|---|
| 129 | like(http_ka('/cl-ch','1.1'), qr/Connection: keep-alive/, 'cl-ch-ka/1.1');
|
|---|
| 130 | like(http_cl('/cl-ch','1.1'), qr/Connection: close/, 'cl-ch-cl/1.1');
|
|---|
| 131 |
|
|---|
| 132 | ###############################################################################
|
|---|
| 133 |
|
|---|
| 134 | sub my_http {
|
|---|
| 135 | my ($request, %extra) = @_;
|
|---|
| 136 | my $reply;
|
|---|
| 137 |
|
|---|
| 138 | eval {
|
|---|
| 139 | local $SIG{ALRM} = sub { die "timeout\n" };
|
|---|
| 140 | local $SIG{PIPE} = sub { die "sigpipe\n" };
|
|---|
| 141 | alarm(5);
|
|---|
| 142 |
|
|---|
| 143 | my $s = $extra{socket} || IO::Socket::INET->new(
|
|---|
| 144 | Proto => 'tcp',
|
|---|
| 145 | PeerAddr => '127.0.0.1:8080',
|
|---|
| 146 | )
|
|---|
| 147 | or die "Can't connect to nginx: $!\n";
|
|---|
| 148 |
|
|---|
| 149 | log_out($request);
|
|---|
| 150 | $s->print($request);
|
|---|
| 151 |
|
|---|
| 152 | select undef, undef, undef, $extra{sleep} if $extra{sleep};
|
|---|
| 153 | return '' if $extra{aborted};
|
|---|
| 154 |
|
|---|
| 155 | if ($extra{body}) {
|
|---|
| 156 | log_out($extra{body});
|
|---|
| 157 | $s->print($extra{body});
|
|---|
| 158 | }
|
|---|
| 159 |
|
|---|
| 160 | # Done writing
|
|---|
| 161 | $s->shutdown(1);
|
|---|
| 162 |
|
|---|
| 163 | local $/;
|
|---|
| 164 | $reply = $s->getline();
|
|---|
| 165 |
|
|---|
| 166 | alarm(0);
|
|---|
| 167 | };
|
|---|
| 168 | alarm(0);
|
|---|
| 169 | if ($@) {
|
|---|
| 170 | log_in("died: $@");
|
|---|
| 171 | return undef;
|
|---|
| 172 | }
|
|---|
| 173 |
|
|---|
| 174 | log_in($reply);
|
|---|
| 175 | return $reply;
|
|---|
| 176 | }
|
|---|
| 177 |
|
|---|
| 178 | sub http_daemon {
|
|---|
| 179 | my $server = IO::Socket::INET->new(
|
|---|
| 180 | Proto => 'tcp',
|
|---|
| 181 | LocalHost => '127.0.0.1:8081',
|
|---|
| 182 | Listen => 5,
|
|---|
| 183 | Reuse => 1
|
|---|
| 184 | )
|
|---|
| 185 | or die "Can't create listening socket: $!\n";
|
|---|
| 186 |
|
|---|
| 187 | my $ccount = 0;
|
|---|
| 188 | my $rcount = 0;
|
|---|
| 189 |
|
|---|
| 190 | # dumb server which is able to keep connections alive
|
|---|
| 191 |
|
|---|
| 192 | while (my $client = $server->accept()) {
|
|---|
| 193 | $client->autoflush(1);
|
|---|
| 194 | $ccount++;
|
|---|
| 195 |
|
|---|
| 196 | while (1) {
|
|---|
| 197 | my $headers = '';
|
|---|
| 198 | my $uri = '';
|
|---|
| 199 |
|
|---|
| 200 | while (<$client>) {
|
|---|
| 201 | $headers .= $_;
|
|---|
| 202 | last if (/^\x0d?\x0a?$/);
|
|---|
| 203 | }
|
|---|
| 204 |
|
|---|
| 205 | last if $headers eq '';
|
|---|
| 206 | $rcount++;
|
|---|
| 207 |
|
|---|
| 208 | $uri = $1 if $headers =~ /^\S+\s+([^ ]+)\s+HTTP/i;
|
|---|
| 209 |
|
|---|
| 210 | if (1) {
|
|---|
| 211 | print { $client }
|
|---|
| 212 | "HTTP/1.1 200 OK" . CRLF .
|
|---|
| 213 | "X-Request: $rcount" . CRLF .
|
|---|
| 214 | "X-Connection: $ccount" . CRLF .
|
|---|
| 215 | "Content-Length: 10000" . CRLF . CRLF;
|
|---|
| 216 | print { $client } ('X' x 10000)
|
|---|
| 217 | unless $headers =~ /^HEAD/i;
|
|---|
| 218 |
|
|---|
| 219 | last;
|
|---|
| 220 | }
|
|---|
| 221 | }
|
|---|
| 222 |
|
|---|
| 223 | close $client;
|
|---|
| 224 | }
|
|---|
| 225 | }
|
|---|
| 226 |
|
|---|
| 227 | ###############################################################################
|
|---|