On Windows the malformed HTTP requests intermittently lose their error response. The server queues the reply and closes the connection right away and sometimes before it has finished reading everything the client sent. Windows reacts to that by resetting the TCP connection and the reset carries the queued response away with it so as the client never sees the 400
as we saw this in check_whitespace_in_headers instead of the expected HTTP 400 the client will occasionally get a bare ConnectionAbortedError.
so decided to change how the server closes connections after a parse error so as it gives the client a chance to read the response before it hangs up:
- Queue the 400 or 413 response with
Connection: close. - Wait for the response to actually leave the send buffer.
- Half-close the socket's write side with
shutdown(SD_SEND/SHUT_WR)so the client can still finish reading while we stop sending. - Keep draining whatever the client sends until it hits EOF or a permanent socket error.
- Only force-close after one secondand only as a fallback for a client that never finishes.
also added Sock::ShutdownSend() to wrap the platform-specific half-close call and made sure the linger state is consistent whether it's touched from the I/O thread or from a worker's send path.