mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-09 21:03:18 +00:00
Wake a blocked WebSocket read when the pong timeout fires
When max_missed_pongs was exceeded, the heartbeat thread called close(), which returns without touching the socket while another thread is in read(). That read() then stayed blocked until its read timeout: forever by default on a client, 300 seconds on a server. A plain read loop never noticed the unresponsive peer the heartbeat had just detected. Shut down the read side of the socket after close() so the pending read() returns Fail. Only the read side: a TLS backend answers the EOF with an alert, and writing it to a socket closed for writing raises SIGPIPE in a process that has not ignored it. ClientDetectsNonResponsivePeer now waits in read() instead of polling is_open(), which covers both.
This commit is contained in:
@@ -179,18 +179,20 @@ protected:
|
||||
TEST_F(WebSocketPongTimeoutTest, ClientDetectsNonResponsivePeer) {
|
||||
ws::WebSocketClient client("ws://localhost:" + std::to_string(port_) + "/ws");
|
||||
client.set_websocket_max_missed_pongs(2);
|
||||
// A read timeout asked for at runtime is reported as Timeout, so it cannot
|
||||
// be mistaken for the Fail a pong timeout produces.
|
||||
client.set_read_timeout(10);
|
||||
ASSERT_TRUE(client.connect());
|
||||
ASSERT_TRUE(client.is_open());
|
||||
|
||||
// Client pings every 1s (compile-time default in this test file).
|
||||
// With max_missed_pongs = 2, the heartbeat thread should self-close within
|
||||
// roughly 3s. Poll is_open() up to 6s.
|
||||
// roughly 3s, and that has to end a read() already waiting on the peer.
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
while (client.is_open() &&
|
||||
std::chrono::steady_clock::now() - start < std::chrono::seconds(6)) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
}
|
||||
|
||||
std::string msg;
|
||||
EXPECT_EQ(client.read(msg), ws::Fail);
|
||||
EXPECT_TRUE(std::chrono::steady_clock::now() - start <
|
||||
std::chrono::seconds(6));
|
||||
EXPECT_FALSE(client.is_open());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user