mirror of
https://github.com/h2o/h2o.git
synced 2025-04-20 02:44:45 +08:00
110 lines
3.6 KiB
Perl
110 lines
3.6 KiB
Perl
use strict;
|
|
use warnings;
|
|
use File::Temp qw(tempdir);
|
|
use Net::EmptyPort qw(wait_port);
|
|
use Test::More;
|
|
use Time::HiRes qw(time);
|
|
use t::Util;
|
|
use JSON;
|
|
|
|
plan skip_all => 'mruby support is off'
|
|
unless server_features()->{mruby};
|
|
|
|
my $client_prog = bindir() . "/h2o-httpclient";
|
|
plan skip_all => "$client_prog not found"
|
|
unless -e $client_prog;
|
|
|
|
plan skip_all => "macOS has issues https://twitter.com/kazuho/status/1298073110587949056"
|
|
if $^O eq 'darwin';
|
|
|
|
# This test utilizes two properties of BSD socket:
|
|
# * a port on a specific address can be bind(2)-ed after the same port on the ANY address in bound
|
|
# * any address within 127.0.0.0/24 is a local address that a server can accept packets
|
|
#
|
|
# Therefore, the test steps are:
|
|
# 1. create a client that connects to the server listening at 0.0.0.0 and sends a request slowly
|
|
# 2. create a new server listening at 127.0.0.1, that will forward the packets of the slow request to the original server (that
|
|
# can still receive packets at 127.0.0.2)
|
|
# 3. check that the slow request completes *after* the new server is up
|
|
|
|
my $quic_port = empty_port({ host => "0.0.0.0", proto => "udp" });
|
|
|
|
# start server1 at 0.0.0.0, check that it is up
|
|
my $server1 = spawn("*", 1);
|
|
is do {my $fh = fetch(""); local $/; join "", <$fh> }, "server=1", "server1 is up";
|
|
|
|
# initiate the slow request
|
|
my $slow_fh = fetch("-b 1200 -c 20 -i 100");
|
|
sleep 1;
|
|
|
|
# start server2 at 127.0.0.1, check that it isup
|
|
my $server2 = spawn("127.0.0.1", 2);
|
|
is do {my $fh = fetch(""); local $/; join "", <$fh> }, "server=2", "server2 is up";
|
|
|
|
# check that the slow request was served, going through $server2
|
|
my $elapsed = time;
|
|
is do {local $/; join "", <$slow_fh>}, "server=1", "slow request succeeded";
|
|
$elapsed = time - $elapsed;
|
|
cmp_ok $elapsed, '>=', 3, "slow request is so slow that the packets should have gone through server2";
|
|
|
|
# check that some packets were actually forwarded, and the event counter captured them
|
|
my $server1_port = ${server1}->{port};
|
|
my $server2_port = ${server2}->{port};
|
|
|
|
my $resp = `curl --silent -o /dev/stderr http://127.0.0.1:${server1_port}/server-status/json?show=events 2>&1 > /dev/null`;
|
|
my $jresp = decode_json("$resp");
|
|
my $num_forwarded_received = $jresp->{'http3.forwarded-packet-received'};
|
|
|
|
$resp = `curl --silent -o /dev/stderr http://127.0.0.1:${server2_port}/server-status/json?show=events 2>&1 > /dev/null`;
|
|
$jresp = decode_json("$resp");
|
|
my $num_forwarded = $jresp->{'http3.packet-forwarded'};
|
|
|
|
cmp_ok($num_forwarded, '>', 0, "some packets were forwarded");
|
|
is($num_forwarded, $num_forwarded_received, "packets forwarded == packets received");
|
|
|
|
done_testing;
|
|
|
|
sub spawn {
|
|
my ($listen_ip, $server_id) = @_;
|
|
my $host_directive = "";
|
|
if ($listen_ip ne "*") {
|
|
$host_directive = "\n host: $listen_ip";
|
|
}
|
|
my $conf = {opts => [qw(-m worker)], conf => <<"EOT"};
|
|
num-threads: 1
|
|
listen:
|
|
type: quic$host_directive
|
|
port: $quic_port
|
|
ssl:
|
|
key-file: examples/h2o/server.key
|
|
certificate-file: examples/h2o/server.crt
|
|
quic-nodes:
|
|
self: $server_id
|
|
mapping:
|
|
1: "[::1]:$quic_port" # server1 can be reached over ipv6 as well
|
|
2: "127.0.0.1:$quic_port"
|
|
ssl-session-resumption:
|
|
mode: ticket
|
|
ticket-store: file
|
|
ticket-file: t/40session-ticket/forever_ticket.yaml
|
|
hosts:
|
|
default:
|
|
paths:
|
|
"/":
|
|
mruby.handler: |
|
|
Proc.new do |env|
|
|
[200, {}, ["server=$server_id"]]
|
|
end
|
|
"/server-status":
|
|
status: ON
|
|
EOT
|
|
spawn_h2o($conf);
|
|
}
|
|
|
|
sub fetch {
|
|
my $opts = shift;
|
|
open my $fh, "-|", "$client_prog -3 100 $opts https://127.0.0.1:$quic_port/ 2> /dev/null"
|
|
or die "failed to spawn $client_prog:$!";
|
|
$fh;
|
|
}
|