-# Copyright (C) 2016-2018 all contributors <meta@public-inbox.org>
+# Copyright (C) 2016-2019 all contributors <meta@public-inbox.org>
# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
# note: our HTTP server should be standalone and capable of running
-# generic Rack apps.
+# generic PSGI/Plack apps.
use strict;
use warnings;
use Test::More;
use IO::Socket;
use IO::Socket::UNIX;
use Fcntl qw(:seek);
-use Socket qw(IPPROTO_TCP TCP_NODELAY);
+use Socket qw(IPPROTO_TCP TCP_NODELAY SOL_SOCKET);
use POSIX qw(mkfifo);
require './t/common.perl';
my $tmpdir = tempdir('httpd-corner-XXXXXX', TMPDIR => 1, CLEANUP => 1);
Listen => 1024,
);
my $sock = IO::Socket::INET->new(%opts);
+
+# Make sure we don't clobber socket options set by systemd or similar
+# using socket activation:
+my ($defer_accept_val, $accf_arg);
+if ($^O eq 'linux') {
+ setsockopt($sock, IPPROTO_TCP, Socket::TCP_DEFER_ACCEPT(), 5) or die;
+ my $x = getsockopt($sock, IPPROTO_TCP, Socket::TCP_DEFER_ACCEPT());
+ defined $x or die "getsockopt: $!";
+ $defer_accept_val = unpack('i', $x);
+ if ($defer_accept_val <= 0) {
+ die "unexpected TCP_DEFER_ACCEPT value: $defer_accept_val";
+ }
+} elsif ($^O eq 'freebsd' && system('kldstat -m accf_data >/dev/null') == 0) {
+ require PublicInbox::Daemon;
+ my $var = PublicInbox::Daemon::SO_ACCEPTFILTER();
+ $accf_arg = pack('a16a240', 'dataready', '');
+ setsockopt($sock, SOL_SOCKET, $var, $accf_arg) or die "setsockopt: $!";
+}
+
my $upath = "$tmpdir/s";
my $unix = IO::Socket::UNIX->new(
Listen => 1024,
is(scalar(grep(/CLOSE FAIL/, @$after)), 1, 'body->close not called');
}
-{
+SKIP: {
my $conn = conn_for($sock, 'excessive header');
$SIG{PIPE} = 'IGNORE';
$conn->write("GET /callback HTTP/1.0\r\n");
like($head, qr/\b413\b/, 'got 413 response');
}
+{
+ my $conn = conn_for($sock, 'chunk with pipeline');
+ my $n = 10;
+ my $payload = 'b'x$n;
+ $conn->write("PUT /sha1 HTTP/1.1\r\nTransfer-Encoding: chunked\r\n");
+ $conn->write("\r\n".sprintf("%x\r\n", $n));
+ $conn->write($payload . "\r\n0\r\n\r\nGET /empty HTTP/1.0\r\n\r\n");
+ $conn->read(my $buf, 4096);
+ my $lim = 0;
+ $lim++ while ($conn->read($buf, 4096, bytes::length($buf)) && $lim < 9);
+ my $exp = sha1_hex($payload);
+ like($buf, qr!\r\n\r\n${exp}HTTP/1\.0 200 OK\r\n!s,
+ 'chunk parser can handled pipelined requests');
+}
+
# Unix domain sockets
{
my $u = IO::Socket::UNIX->new(Type => SOCK_STREAM, Peer => $upath);
is($body, sha1_hex(''), 'read expected body #2');
}
+SKIP: {
+ skip 'TCP_DEFER_ACCEPT is Linux-only', 1 if $^O ne 'linux';
+ my $var = Socket::TCP_DEFER_ACCEPT();
+ defined(my $x = getsockopt($sock, IPPROTO_TCP, $var)) or die;
+ is(unpack('i', $x), $defer_accept_val,
+ 'TCP_DEFER_ACCEPT unchanged if previously set');
+};
+SKIP: {
+ skip 'SO_ACCEPTFILTER is FreeBSD-only', 1 if $^O ne 'freebsd';
+ skip 'accf_data not loaded: kldload accf_data' if !defined $accf_arg;
+ my $var = PublicInbox::Daemon::SO_ACCEPTFILTER();
+ defined(my $x = getsockopt($sock, SOL_SOCKET, $var)) or die;
+ is($x, $accf_arg, 'SO_ACCEPTFILTER unchanged if previously set');
+};
+
done_testing();
sub capture {