From 05028146b5e69c566663fdab9f8b92c6145a791a Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 10 Sep 2023 19:52:03 +0000 Subject: [PATCH 11/11] tests: fold early shutdown() tests into t/integration.t This means fewer redundant tests and more chances to notice Ruby incompatibilities. --- t/integration.t | 22 +++++++++++++++-- test/unit/test_server.rb | 53 ---------------------------------------- 2 files changed, 20 insertions(+), 55 deletions(-) diff --git a/t/integration.t b/t/integration.t index ba17dd9e..7310ff29 100644 --- a/t/integration.t +++ b/t/integration.t @@ -7,7 +7,7 @@ use v5.14; BEGIN { require './t/lib.perl' }; use autodie; -use Socket qw(SOL_SOCKET SO_KEEPALIVE); +use Socket qw(SOL_SOCKET SO_KEEPALIVE SHUT_WR); our $srv = tcp_server(); our $host_port = tcp_host_port($srv); @@ -209,6 +209,7 @@ SKIP: { defined($opt{overwrite}) and print { $c } ('x' x $opt{overwrite}); $c->flush or die $!; + shutdown($c, SHUT_WR); ($status, $hdr) = slurp_hdr($c); is(readline($c), $blob_hash, "$sub $path"); }; @@ -225,6 +226,8 @@ SKIP: { # ensure small overwrites don't get checksummed $ck_hash->('identity', '/rack_input', -s => $blob_size, overwrite => 1); # one extra byte + unlike(slurp($err_log), qr/ClientShutdown/, + 'no overreads after client SHUT_WR'); # excessive overwrite truncated $c = tcp_start($srv); @@ -238,8 +241,23 @@ SKIP: { $! = 0; while (print $c $buf and time < $end) { ++$n } ok($!, 'overwrite truncated') or diag "n=$n err=$! ".time; + undef $c; + } + + # client shutdown early + $c = tcp_start($srv); + $c->autoflush(0); + print $c "PUT /rack_input HTTP/1.0\r\nContent-Length: 16384\r\n\r\n"; + if (1) { + local $SIG{PIPE} = 'IGNORE'; + print $c 'too short body'; + shutdown($c, SHUT_WR); + vec(my $rvec = '', fileno($c), 1) = 1; + select($rvec, undef, undef, 10) or BAIL_OUT "timed out"; + my $buf = <$c>; + is($buf, undef, 'server aborted after client SHUT_WR'); + undef $c; } - undef $c; $curl // skip 'no curl found in PATH', 1; diff --git a/test/unit/test_server.rb b/test/unit/test_server.rb index 2af12eac..7ffa48f0 100644 --- a/test/unit/test_server.rb +++ b/test/unit/test_server.rb @@ -132,59 +132,6 @@ def test_simple_server assert_equal 'hello!\n', results[0], "Handler didn't really run" end - def test_client_shutdown_writes - bs = 15609315 * rand - sock = tcp_socket('127.0.0.1', @port) - sock.syswrite("PUT /hello HTTP/1.1\r\n") - sock.syswrite("Host: example.com\r\n") - sock.syswrite("Transfer-Encoding: chunked\r\n") - sock.syswrite("Trailer: X-Foo\r\n") - sock.syswrite("\r\n") - sock.syswrite("%x\r\n" % [ bs ]) - sock.syswrite("F" * bs) - sock.syswrite("\r\n0\r\nX-") - "Foo: bar\r\n\r\n".each_byte do |x| - sock.syswrite x.chr - sleep 0.05 - end - # we wrote the entire request before shutting down, server should - # continue to process our request and never hit EOFError on our sock - sock.shutdown(Socket::SHUT_WR) - buf = sock.read - assert_match %r{\bhello!\\n\b}, buf.split(/\r\n\r\n/, 2).last - next_client = Net::HTTP.get(URI.parse("http://127.0.0.1:#@port/")) - assert_equal 'hello!\n', next_client - lines = File.readlines("test_stderr.#$$.log") - assert lines.grep(/^Unicorn::ClientShutdown: /).empty? - assert_nil sock.close - end - - def test_client_shutdown_write_truncates - bs = 15609315 * rand - sock = tcp_socket('127.0.0.1', @port) - sock.syswrite("PUT /hello HTTP/1.1\r\n") - sock.syswrite("Host: example.com\r\n") - sock.syswrite("Transfer-Encoding: chunked\r\n") - sock.syswrite("Trailer: X-Foo\r\n") - sock.syswrite("\r\n") - sock.syswrite("%x\r\n" % [ bs ]) - sock.syswrite("F" * (bs / 2.0)) - - # shutdown prematurely, this will force the server to abort - # processing on us even during app dispatch - sock.shutdown(Socket::SHUT_WR) - IO.select([sock], nil, nil, 60) or raise "Timed out" - buf = sock.read - assert_equal "", buf - next_client = Net::HTTP.get(URI.parse("http://127.0.0.1:#@port/")) - assert_equal 'hello!\n', next_client - lines = File.readlines("test_stderr.#$$.log") - lines = lines.grep(/^Unicorn::ClientShutdown: bytes_read=\d+/) - assert_equal 1, lines.size - assert_match %r{\AUnicorn::ClientShutdown: bytes_read=\d+ true$}, lines[0] - assert_nil sock.close - end - def test_client_malformed_body bs = 15653984 sock = tcp_socket('127.0.0.1', @port)