mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-25 17:25:08 +02:00
RequestServer: Don't create already-expired WebSockets in DNS callback
This prevents a race condition: 1. Try to connect a websocket 2. DNS lookup starts 3. JS causes the websocket to no longer be alive, and it is GCed 4. websocket_close() is called, but it doesn't find a websocket with that websocket_id, so nothing happens 5. DNS lookup completes, and opens the websocket 6. This websocket never gets closed By separately tracking which websockets we are trying to connect, we can record the fact we tried to close it, and then the DNS lookup callback can skip creating the now-unwanted websocket.
This commit is contained in:
Notes:
github-actions[bot]
2026-04-01 18:38:05 +00:00
Author: https://github.com/AtkinsSJ Commit: https://github.com/LadybirdBrowser/ladybird/commit/22d7138c8d5 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/8698 Reviewed-by: https://github.com/gmta
@@ -355,6 +355,7 @@ void ConnectionFromClient::remove_cache_entries_accessed_since(UnixDateTime sinc
|
||||
void ConnectionFromClient::websocket_connect(u64 websocket_id, URL::URL url, ByteString origin, Vector<ByteString> protocols, Vector<ByteString> extensions, Vector<HTTP::Header> additional_request_headers)
|
||||
{
|
||||
auto host = url.serialized_host().to_byte_string();
|
||||
m_pending_websockets.set(websocket_id);
|
||||
|
||||
m_resolver->dns.lookup(host, DNS::Messages::Class::IN, { DNS::Messages::ResourceType::A, DNS::Messages::ResourceType::AAAA })
|
||||
->when_rejected([this, websocket_id](auto const& error) {
|
||||
@@ -368,6 +369,10 @@ void ConnectionFromClient::websocket_connect(u64 websocket_id, URL::URL url, Byt
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't connect the websocket if we already requested to close it before the DNS lookup completed.
|
||||
if (!m_pending_websockets.remove(websocket_id))
|
||||
return;
|
||||
|
||||
WebSocket::ConnectionInfo connection_info(move(url));
|
||||
connection_info.set_origin(move(origin));
|
||||
connection_info.set_protocols(move(protocols));
|
||||
@@ -410,6 +415,7 @@ void ConnectionFromClient::websocket_send(u64 websocket_id, bool is_text, ByteBu
|
||||
|
||||
void ConnectionFromClient::websocket_close(u64 websocket_id, u16 code, ByteString reason)
|
||||
{
|
||||
m_pending_websockets.remove(websocket_id);
|
||||
if (auto* connection = m_websockets.get(websocket_id).value_or({}); connection && connection->ready_state() == WebSocket::ReadyState::Open)
|
||||
connection->close(code, reason);
|
||||
}
|
||||
|
||||
@@ -80,6 +80,7 @@ private:
|
||||
|
||||
HashMap<u64, NonnullOwnPtr<Request>> m_active_requests;
|
||||
HashMap<u64, NonnullOwnPtr<Request>> m_active_revalidation_requests;
|
||||
HashTable<u64> m_pending_websockets;
|
||||
HashMap<u64, RefPtr<WebSocket::WebSocket>> m_websockets;
|
||||
|
||||
RefPtr<Core::Timer> m_timer;
|
||||
|
||||
Reference in New Issue
Block a user