fix(http1): close a finished connection instead of holding it until reap
A connection's socket was owned by the registry entry and only released when the next accept() reaped it, so a peer we had finished with — after a 408, a 400, or a `connection: close` — never saw EOF and sat waiting for a server that was done talking. On a server that goes quiet it also held every descriptor from the last burst indefinitely. The connection thread now closes its own socket the moment Serve() returns, under the registry lock so Stop()'s shutdown() can never name a descriptor that has already been released, and Stop() waits on a condition variable for the last thread rather than assuming the vector it moved out is quiescent. Adopt() is also fully guarded: it runs on ListenerTCP's accept loop, which has no handler, so anything escaping it would abort the process. Found by ShouldSurviveAbuseHTTP1, added here: 24 concurrent keep-alive clients, peers that vanish mid-request or send garbage, and a peer that stalls forever — the server must keep serving and still stop promptly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
337ce32eca
commit
ea1310faec
3 changed files with 159 additions and 4 deletions
|
|
@ -131,6 +131,7 @@ extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> a
|
|||
cfg.AddTest("ShouldSendRecieveLargeHTTP").Dependencies({ &cfg });
|
||||
cfg.AddTest("ShouldSendRecieveQUICDatagram").Dependencies({ &cfg });
|
||||
cfg.AddTest("ShouldSendRecieveQUICStream").Dependencies({ &cfg });
|
||||
cfg.AddTest("ShouldSurviveAbuseHTTP1").Dependencies({ &cfg });
|
||||
}
|
||||
|
||||
return cfg;
|
||||
|
|
|
|||
Loading…
Reference in a new issue