user/dev discussion of public-inbox itself
 help / color / mirror / code / Atom feed
Search results ordered by [date|relevance]  view[summary|nested|Atom feed]
thread overview below | download mbox.gz: |
* [PATCH 4/4] t/httpd-corner.t: relax read-after-failed-write handling
  2020-04-11 10:53  6% [PATCH 0/4] FreeBSD and test fixes Eric Wong
@ 2020-04-11 10:53  7% ` Eric Wong
  0 siblings, 0 replies; 2+ results
From: Eric Wong @ 2020-04-11 10:53 UTC (permalink / raw)
  To: meta

I've observed FreeBSD 11.2 read(2) having one of three
behaviors after a failed write(2) on a socket:

1) returning number of bytes read
2) failing with ECONNRESET
3) returning with EOF

1) is the most common, and I've only seen 1) on Linux.  It may
be possible to use SO_LINGER or shutdown(2) to ensure 1) always
happens, but SO_LINGER behavior seems inconsistent across OSes,
especially with non-blocking sockets.

Since these tests are corner-cases where we're dealing with
broken/malicious clients, lets continue spending the least
amount of syscalls protecting ourselves in the daemon and
instead make the client-side test code tolerate more socket
implementations.
---
 t/httpd-corner.t | 39 +++++++++++++++++++++++----------------
 1 file changed, 23 insertions(+), 16 deletions(-)

diff --git a/t/httpd-corner.t b/t/httpd-corner.t
index 89f2866b..21b5c560 100644
--- a/t/httpd-corner.t
+++ b/t/httpd-corner.t
@@ -122,36 +122,48 @@ if ('test worker death') {
 	is(scalar(grep(/CLOSE FAIL/, @$after)), 1, 'body->close not called');
 }
 
-SKIP: {
+sub check_400 {
+	my ($conn) = @_;
+	my $r = $conn->read(my $buf, 8192);
+	# ECONNRESET and $r==0 are both observed on FreeBSD 11.2
+	if (!defined($r)) {
+		ok($!{ECONNRESET}, 'ECONNRESET on read (BSD sometimes)');
+	} elsif ($r > 0) {
+		like($buf, qr!\AHTTP/1\.\d 400 !, 'got 400 response');
+	} else {
+		is($r, 0, 'got EOF (BSD sometimes)');
+	}
+	close($conn); # ensure we don't get SIGPIPE later
+}
+
+{
+	local $SIG{PIPE} = 'IGNORE';
 	my $conn = conn_for($sock, 'excessive header');
-	$SIG{PIPE} = 'IGNORE';
 	$conn->write("GET /callback HTTP/1.0\r\n");
 	foreach my $i (1..500000) {
 		last unless $conn->write("X-xxxxxJunk-$i: omg\r\n");
 	}
 	ok(!$conn->write("\r\n"), 'broken request');
-	ok($conn->read(my $buf, 8192), 'read response');
-	my ($head, $body) = split(/\r\n\r\n/, $buf);
-	like($head, qr/\b400\b/, 'got 400 response');
+	check_400($conn);
 }
 
 {
 	my $conn = conn_for($sock, 'excessive body Content-Length');
-	$SIG{PIPE} = 'IGNORE';
 	my $n = (10 * 1024 * 1024) + 1;
 	$conn->write("PUT /sha1 HTTP/1.0\r\nContent-Length: $n\r\n\r\n");
-	ok($conn->read(my $buf, 8192), 'read response');
+	my $r = $conn->read(my $buf, 8192);
+	ok($r > 0, 'read response');
 	my ($head, $body) = split(/\r\n\r\n/, $buf);
 	like($head, qr/\b413\b/, 'got 413 response');
 }
 
 {
 	my $conn = conn_for($sock, 'excessive body chunked');
-	$SIG{PIPE} = 'IGNORE';
 	my $n = (10 * 1024 * 1024) + 1;
 	$conn->write("PUT /sha1 HTTP/1.1\r\nTransfer-Encoding: chunked\r\n");
 	$conn->write("\r\n".sprintf("%x\r\n", $n));
-	ok($conn->read(my $buf, 8192), 'read response');
+	my $r = $conn->read(my $buf, 8192);
+	ok($r > 0, 'read response');
 	my ($head, $body) = split(/\r\n\r\n/, $buf);
 	like($head, qr/\b413\b/, 'got 413 response');
 }
@@ -410,10 +422,7 @@ SKIP: {
 	ok($!, 'got error set in $!');
 	is($w, undef, 'write error happened');
 	ok($n > 0, 'was able to write');
-	my $r = $conn->read(my $buf, 66666);
-	ok($r > 0, 'got non-empty response');
-	like($buf, qr!HTTP/1\.\d 400 !, 'got 400 response');
-
+	check_400($conn);
 	$conn = conn_for($sock, '1.1 chunk trailer excessive');
 	$conn->write("PUT /sha1 HTTP/1.1\r\nTransfer-Encoding:chunked\r\n\r\n");
 	is($conn->syswrite("1\r\na"), 4, 'wrote first header + chunk');
@@ -424,9 +433,7 @@ SKIP: {
 	}
 	ok($!, 'got error set in $!');
 	ok($n > 0, 'wrote part of chunk end (\r)');
-	$r = $conn->read($buf, 66666);
-	ok($r > 0, 'got non-empty response');
-	like($buf, qr!HTTP/1\.\d 400 !, 'got 400 response');
+	check_400($conn);
 }
 
 {

^ permalink raw reply related	[relevance 7%]

* [PATCH 0/4] FreeBSD and test fixes
@ 2020-04-11 10:53  6% Eric Wong
  2020-04-11 10:53  7% ` [PATCH 4/4] t/httpd-corner.t: relax read-after-failed-write handling Eric Wong
  0 siblings, 1 reply; 2+ results
From: Eric Wong @ 2020-04-11 10:53 UTC (permalink / raw)
  To: meta

Looping the tests for hours on end with a FreeBSD 11.2 VM
revealed some problems (and a minor cleanup) I didn't
find on my Debian GNU/Linux systems.

Eric Wong (4):
  testcommon: DESTROY: wait for killed daemon
  dskqxs: ignore EV_SET errors on EVFILT_WRITE
  t/*.t: localize $SIG{__WARN__} changes
  t/httpd-corner.t: relax read-after-failed-write handling

 lib/PublicInbox/DSKQXS.pm     |  4 ++--
 lib/PublicInbox/TestCommon.pm |  6 +++---
 lib/PublicInbox/Xapcmd.pm     |  6 +++++-
 t/httpd-corner.t              | 39 +++++++++++++++++++++--------------
 t/mda_filter_rubylang.t       |  2 +-
 t/nntpd.t                     |  2 +-
 t/watch_filter_rubylang.t     |  2 +-
 7 files changed, 36 insertions(+), 25 deletions(-)

^ permalink raw reply	[relevance 6%]

Results 1-2 of 2 | reverse | sort options + mbox downloads above
-- links below jump to the message on this page --
2020-04-11 10:53  6% [PATCH 0/4] FreeBSD and test fixes Eric Wong
2020-04-11 10:53  7% ` [PATCH 4/4] t/httpd-corner.t: relax read-after-failed-write handling Eric Wong

Code repositories for project(s) associated with this public inbox

	https://80x24.org/public-inbox.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).