Skip to content

Commit d752a65

Browse files
committed
Tests: add HTTP/2 proxy request buffering test support.
1 parent b3cbe01 commit d752a65

File tree

1 file changed

+205
-0
lines changed

1 file changed

+205
-0
lines changed

proxy_http2_request_buffering.t

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
#!/usr/bin/perl
2+
3+
# (C) Sergey Kandaurov
4+
# (C) Nginx, Inc.
5+
6+
# Tests for HTTP/2 proxy backend, request body buffered.
7+
8+
###############################################################################
9+
10+
use warnings;
11+
use strict;
12+
13+
use Test::More;
14+
15+
BEGIN { use FindBin; chdir($FindBin::Bin); }
16+
17+
use lib 'lib';
18+
use Test::Nginx;
19+
use Test::Nginx::HTTP2;
20+
21+
###############################################################################
22+
23+
select STDERR; $| = 1;
24+
select STDOUT; $| = 1;
25+
26+
my $t = Test::Nginx->new()->has(qw/http http_v2 proxy mirror/)->plan(12);
27+
28+
$t->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+
server {
41+
listen 127.0.0.1:8080 http2;
42+
listen 127.0.0.1:8082;
43+
server_name localhost;
44+
45+
location /mirror { }
46+
47+
location / {
48+
proxy_pass http://127.0.0.1:8081;
49+
proxy_http_version 2.0;
50+
proxy_request_buffering on;
51+
add_header X-Body $request_body;
52+
mirror /mirror;
53+
}
54+
55+
location /proxy {
56+
proxy_pass http://127.0.0.1:8082/mirror;
57+
proxy_intercept_errors on;
58+
error_page 404 = @fallback;
59+
}
60+
61+
location @fallback {
62+
proxy_pass http://127.0.0.1:8081;
63+
proxy_http_version 2.0;
64+
}
65+
}
66+
}
67+
68+
EOF
69+
70+
# suppress deprecation warning
71+
72+
open OLDERR, ">&", \*STDERR; close STDERR;
73+
$t->run();
74+
open STDERR, ">&", \*OLDERR;
75+
76+
###############################################################################
77+
78+
my $p = port(8081);
79+
my $f = proxy_http2();
80+
81+
my $frames = $f->{http_start}('/SayHello');
82+
my ($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
83+
is($frame->{flags}, 4, 'request - HEADERS flags');
84+
is($frame->{headers}{':method'}, 'POST', 'request - method');
85+
is($frame->{headers}{':scheme'}, 'http', 'request - scheme');
86+
is($frame->{headers}{':path'}, '/SayHello', 'request - path');
87+
is($frame->{headers}{':authority'}, "127.0.0.1:$p", 'request - authority');
88+
89+
($frame) = grep { $_->{type} eq "DATA" } @$frames;
90+
is($frame->{data}, 'Hello', 'request - DATA');
91+
is($frame->{length}, 5, 'request - DATA length');
92+
is($frame->{flags}, 1, 'request - DATA flags');
93+
94+
$frames = $f->{http_end}();
95+
($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
96+
is($frame->{headers}{'x-body'}, 'Hello', 'request body in memory');
97+
98+
# tcp_nopush usage on peer connections
99+
# reopen window for request body after initial window was exhausted
100+
101+
$frames = $f->{http_start}('/proxy');
102+
is(eval(join '+', map { $_->{length} } grep { $_->{type} eq "DATA" } @$frames),
103+
65535, 'preserve_output - first body bytes');
104+
105+
# expect body cleanup is disabled with preserve_output (ticket #1565).
106+
# after request body first bytes were proxied on behalf of initial window size,
107+
# send response header from upstream, this leads to body cleanup code path
108+
109+
$frames = $f->{http_end}();
110+
is(eval(join '+', map { $_->{length} } grep { $_->{type} eq "DATA" } @$frames),
111+
465, 'preserve_output - last body bytes');
112+
113+
like(`grep -F '[crit]' ${\($t->testdir())}/error.log`, qr/^$/s, 'no crits');
114+
115+
###############################################################################
116+
117+
sub proxy_http2 {
118+
my ($server, $client, $f, $s, $c, $sid, $uri);
119+
120+
$server = IO::Socket::INET->new(
121+
Proto => 'tcp',
122+
LocalHost => '127.0.0.1',
123+
LocalPort => $p,
124+
Listen => 5,
125+
Reuse => 1
126+
)
127+
or die "Can't create listening socket: $!\n";
128+
129+
$f->{http_start} = sub {
130+
($uri, my %extra) = @_;
131+
$s = Test::Nginx::HTTP2->new() if !defined $s;
132+
my ($body) = $uri eq '/proxy' ? 'Hello' x 13200 : 'Hello';
133+
$s->new_stream({ body => $body, headers => [
134+
{ name => ':method', value => 'POST', mode => 0 },
135+
{ name => ':scheme', value => 'http', mode => 0 },
136+
{ name => ':path', value => $uri },
137+
{ name => ':authority', value => 'localhost' },
138+
{ name => 'content-type', value => 'text/plain' },
139+
{ name => 'te', value => 'trailers', mode => 2 },
140+
{ name => 'content-length', value => length($body) }]});
141+
142+
if (!$extra{reuse}) {
143+
eval {
144+
local $SIG{ALRM} = sub { die "timeout\n" };
145+
alarm(5);
146+
147+
$client = $server->accept() or return;
148+
149+
alarm(0);
150+
};
151+
alarm(0);
152+
if ($@) {
153+
log_in("died: $@");
154+
return undef;
155+
}
156+
157+
log2c("(new connection $client)");
158+
159+
$client->sysread(my $buf, 24) == 24 or return; # preface
160+
161+
$c = Test::Nginx::HTTP2->new(1, socket => $client,
162+
pure => 1, preface => "") or return;
163+
}
164+
165+
my $frames = $uri eq '/proxy'
166+
? $c->read(all => [{ length => 65535 }])
167+
: $c->read(all => [{ fin => 1 }]);
168+
169+
if (!$extra{reuse}) {
170+
$c->h2_settings(0);
171+
$c->h2_settings(1);
172+
}
173+
174+
my ($frame) = grep { $_->{type} eq "HEADERS" } @$frames;
175+
$sid = $frame->{sid};
176+
return $frames;
177+
};
178+
$f->{http_end} = sub {
179+
$c->new_stream({ body_more => 1, headers => [
180+
{ name => ':status', value => '200', mode => 0 },
181+
{ name => 'content-type', value => 'text/plain' },
182+
]}, $sid);
183+
184+
# reopen window for request body after response HEADERS is sent
185+
186+
if ($uri eq '/proxy') {
187+
$c->h2_window(2**16, $sid);
188+
$c->h2_window(2**16);
189+
return $c->read(all => [{ sid => $sid, fin => 1 }]);
190+
}
191+
192+
$c->h2_body('Hello world', { body_more => 1 });
193+
$c->new_stream({ headers => [
194+
{ name => 'x-status', value => '0', mode => 2 },
195+
{ name => 'x-message', value => '', mode => 2 },
196+
]}, $sid);
197+
198+
return $s->read(all => [{ fin => 1 }]);
199+
};
200+
return $f;
201+
}
202+
203+
sub log2c { Test::Nginx::log_core('||', @_); }
204+
205+
###############################################################################

0 commit comments

Comments
 (0)