LibWebSocket: Time out stalled close handshakes

Start a single-shot timer when a websocket enters CLOSING and fail
the connection if the peer never answers with its close frame.

Without a bound here, a dropped or non-responsive peer can leave the
websocket stuck in the closing handshake forever, which is another
path to rare websocket timeouts during repeated test runs.
This commit is contained in:
Sam Atkins 2026-04-17 14:22:02 +01:00 committed by Shannon Booth
parent 94a98f5191
commit 7889a46724
2 changed files with 20 additions and 0 deletions

View file

@ -8,12 +8,15 @@
#include <AK/Base64.h>
#include <AK/Endian.h>
#include <AK/Random.h>
#include <LibCore/Timer.h>
#include <LibCrypto/Hash/HashManager.h>
#include <LibWebSocket/Impl/WebSocketImplSerenity.h>
#include <LibWebSocket/WebSocket.h>
namespace WebSocket {
static constexpr int s_closing_handshake_timeout_ms = 30'000;
// Note : The websocket protocol is defined by RFC 6455, found at https://tools.ietf.org/html/rfc6455
// In this file, section numbers will refer to the RFC 6455
@ -703,6 +706,21 @@ void WebSocket::set_state(InternalState state)
return;
auto old_ready_state = ready_state();
m_state = state;
if (state == InternalState::Closing) {
if (!m_closing_handshake_timer) {
m_closing_handshake_timer = Core::Timer::create_single_shot(s_closing_handshake_timeout_ms, [this] {
if (m_state != InternalState::Closing)
return;
fail_connection(to_underlying(CloseStatusCode::AbnormalClosure), WebSocket::Error::ServerClosedSocket, "Timed out waiting for the peer's close frame");
});
} else {
m_closing_handshake_timer->restart(s_closing_handshake_timeout_ms);
}
} else if (m_closing_handshake_timer) {
m_closing_handshake_timer->stop();
}
auto new_ready_state = ready_state();
if (old_ready_state != new_ready_state) {
if (on_ready_state_change)

View file

@ -9,6 +9,7 @@
#include <AK/Span.h>
#include <LibCore/EventReceiver.h>
#include <LibCore/Forward.h>
#include <LibWebSocket/ConnectionInfo.h>
#include <LibWebSocket/Impl/WebSocketImpl.h>
#include <LibWebSocket/Message.h>
@ -132,6 +133,7 @@ private:
ConnectionInfo m_connection;
RefPtr<WebSocketImpl> m_impl;
RefPtr<Core::Timer> m_closing_handshake_timer;
Vector<u8> m_buffered_data;
ByteBuffer m_fragmented_data_buffer;