From 7c4ecaf509bb851eb2750ead1dfeed66a39d9b99 Mon Sep 17 00:00:00 2001 From: Ali Mohammad Pur Date: Thu, 14 May 2026 14:39:07 +0200 Subject: [PATCH] LibRequests+RequestServer: Send oversized ws frames via shared memory --- Libraries/LibRequests/WebSocket.cpp | 13 +++++++++++++ Services/RequestServer/ConnectionFromClient.cpp | 13 +++++++++++++ Services/RequestServer/ConnectionFromClient.h | 1 + Services/RequestServer/RequestServer.ipc | 1 + 4 files changed, 28 insertions(+) diff --git a/Libraries/LibRequests/WebSocket.cpp b/Libraries/LibRequests/WebSocket.cpp index eb4a952aca..02bf929f0b 100644 --- a/Libraries/LibRequests/WebSocket.cpp +++ b/Libraries/LibRequests/WebSocket.cpp @@ -4,11 +4,14 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include namespace Requests { +static constexpr size_t WEBSOCKET_SHARED_MEMORY_THRESHOLD = 16 * MiB; + WebSocket::WebSocket(RequestClient& client, u64 websocket_id) : m_client(client) , m_websocket_id(websocket_id) @@ -39,6 +42,16 @@ void WebSocket::send(ReadonlyBytes binary_or_text_message, bool is_text) { if (!m_client) return; + if (binary_or_text_message.size() >= WEBSOCKET_SHARED_MEMORY_THRESHOLD) { + auto buffer_or_error = Core::AnonymousBuffer::create_with_size(binary_or_text_message.size()); + if (!buffer_or_error.is_error()) { + auto buffer = buffer_or_error.release_value(); + __builtin_memcpy(buffer.data(), binary_or_text_message.data(), binary_or_text_message.size()); + m_client->async_websocket_send_shared(m_websocket_id, is_text, move(buffer)); + return; + } + dbgln("WebSocket::send: failed to allocate shared buffer for {} bytes: {}", binary_or_text_message.size(), buffer_or_error.error()); + } m_client->async_websocket_send(m_websocket_id, is_text, binary_or_text_message); } diff --git a/Services/RequestServer/ConnectionFromClient.cpp b/Services/RequestServer/ConnectionFromClient.cpp index c81ee644b1..643eebb6bb 100644 --- a/Services/RequestServer/ConnectionFromClient.cpp +++ b/Services/RequestServer/ConnectionFromClient.cpp @@ -586,6 +586,19 @@ void ConnectionFromClient::websocket_send(u64 websocket_id, bool is_text, ByteBu connection->send(WebSocket::Message { move(data), is_text }); } +void ConnectionFromClient::websocket_send_shared(u64 websocket_id, bool is_text, Core::AnonymousBuffer data) +{ + auto* connection = m_websockets.get(websocket_id).value_or({}); + if (!connection || connection->ready_state() != WebSocket::ReadyState::Open) + return; + auto byte_buffer_or_error = ByteBuffer::copy(data.bytes()); + if (byte_buffer_or_error.is_error()) { + dbgln("websocket_send_shared: failed to copy {} bytes from shared buffer: {}", data.size(), byte_buffer_or_error.error()); + return; + } + connection->send(WebSocket::Message { byte_buffer_or_error.release_value(), is_text }); +} + void ConnectionFromClient::websocket_close(u64 websocket_id, u16 code, ByteString reason) { if (m_pending_websockets.remove(websocket_id)) { diff --git a/Services/RequestServer/ConnectionFromClient.h b/Services/RequestServer/ConnectionFromClient.h index 20f2682b1b..a4f7910d58 100644 --- a/Services/RequestServer/ConnectionFromClient.h +++ b/Services/RequestServer/ConnectionFromClient.h @@ -72,6 +72,7 @@ private: virtual void websocket_connect(u64 websocket_id, URL::URL, ByteString, Vector, Vector, Vector) override; virtual void websocket_send(u64 websocket_id, bool, ByteBuffer) override; + virtual void websocket_send_shared(u64 websocket_id, bool, Core::AnonymousBuffer) override; virtual void websocket_close(u64 websocket_id, u16, ByteString) override; virtual Messages::RequestServer::WebsocketSetCertificateResponse websocket_set_certificate(u64, ByteString, ByteString) override; diff --git a/Services/RequestServer/RequestServer.ipc b/Services/RequestServer/RequestServer.ipc index a127963f8a..1b465ae36a 100644 --- a/Services/RequestServer/RequestServer.ipc +++ b/Services/RequestServer/RequestServer.ipc @@ -42,6 +42,7 @@ endpoint RequestServer // Websocket Connection API websocket_connect(u64 websocket_id, URL::URL url, ByteString origin, Vector protocols, Vector extensions, Vector additional_request_headers) =| websocket_send(u64 websocket_id, bool is_text, ByteBuffer data) =| + websocket_send_shared(u64 websocket_id, bool is_text, Core::AnonymousBuffer data) =| websocket_close(u64 websocket_id, u16 code, ByteString reason) =| websocket_set_certificate(u64 request_id, ByteString certificate, ByteString key) => (bool success)