diff --git a/src/connection.toit b/src/connection.toit index de635c6..d50110b 100644 --- a/src/connection.toit +++ b/src/connection.toit @@ -144,10 +144,11 @@ class Connection: // Set this before doing blocking operations on the socket, so that we // don't let another task start another request on the same connection. if has-body: current-writer_ = body-writer - socket_.no-delay = false headers-written := false + no-delay-restored := false try: + socket_.no-delay = false writer.write status headers.write-to writer if is-client-request and host_: @@ -157,13 +158,19 @@ class Connection: writer.write "\r\n" headers-written = true finally: - // If we failed to write the headers the connection is unusable: the - // peer may have received a partial header. Close it, which also - // resets $current-writer_ so that later attempts to respond don't - // fail with "Previous request not completed". - if not headers-written: close + // The TCP_NODELAY setter can throw if the peer has gone away. The nested + // finally ensures that we still close while its exception propagates. + try: + if headers-written: + socket_.no-delay = true + no-delay-restored = true + finally: + // A partial header or a failed TCP_NODELAY restoration makes the + // connection unusable. Closing also resets $current-writer_. + if not headers-written or + not no-delay-restored: + close - socket_.no-delay = true return body-writer // Gets the next request from the client. If the client closes the diff --git a/tests/server-peer-gone-test.toit b/tests/server-peer-gone-test.toit index cb67750..ebfed6d 100644 --- a/tests/server-peer-gone-test.toit +++ b/tests/server-peer-gone-test.toit @@ -4,9 +4,7 @@ // A client that connects, sends a request and closes before the server // writes the response must be treated as a normal disconnect: the server -// keeps serving and doesn't log any extraneous traces. The only acceptable -// trace is the one the server emits when the handler lets the socket error -// itself escape. +// keeps serving and doesn't log "Previous request not completed". import expect show * import http @@ -49,12 +47,9 @@ main: print "---------------------------------------" recorder.traces.clear test --max-tasks=max-tasks --scenario=scenario - traces-seen := recorder.traces.size - // The OS may report the disconnect during the response write or when - // the server next reads from the connection. - maximum := scenario == PROPAGATE ? 1 : 0 - if traces-seen > maximum: - failures.add "$scenario/max-tasks=$max-tasks ($traces-seen > $maximum)" + recorder.traces.do: | trace/ByteArray | + if trace.to-string.contains "Previous request not completed": + failures.add "$scenario/max-tasks=$max-tasks" finally: recorder.uninstall expect failures.is-empty --message="$failures"