1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 11:47:46 +00:00

Everywhere: Merge the WebSocket service into RequestServer

This keeps the APIs separate as they are wildly different, a future
improvement could be to somehow unify the APIs (if possible).

Closes #23080.
This commit is contained in:
Ali Mohammad Pur 2024-03-06 01:50:52 +01:00 committed by Jelle Raaijmakers
parent daf5484d6b
commit 6dfb2f9dc8
56 changed files with 231 additions and 845 deletions

View file

@ -2,14 +2,11 @@ set(SOURCES
Request.cpp
RequestClient.cpp
WebSocket.cpp
WebSocketClient.cpp
)
set(GENERATED_SOURCES
../../Services/RequestServer/RequestClientEndpoint.h
../../Services/RequestServer/RequestServerEndpoint.h
../../Services/WebSocket/WebSocketClientEndpoint.h
../../Services/WebSocket/WebSocketServerEndpoint.h
)
serenity_lib(LibProtocol protocol)

View file

@ -103,6 +103,54 @@ void RequestClient::certificate_requested(i32 request_id)
}
}
RefPtr<WebSocket> RequestClient::websocket_connect(const URL& url, ByteString const& origin, Vector<ByteString> const& protocols, Vector<ByteString> const& extensions, HashMap<ByteString, ByteString> const& request_headers)
{
auto headers_or_error = request_headers.clone();
if (headers_or_error.is_error())
return nullptr;
auto connection_id = IPCProxy::websocket_connect(url, origin, protocols, extensions, headers_or_error.release_value());
if (connection_id < 0)
return nullptr;
auto connection = WebSocket::create_from_id({}, *this, connection_id);
m_websockets.set(connection_id, connection);
return connection;
}
void RequestClient::websocket_connected(i32 connection_id)
{
auto maybe_connection = m_websockets.get(connection_id);
if (maybe_connection.has_value())
maybe_connection.value()->did_open({});
}
void RequestClient::websocket_received(i32 connection_id, bool is_text, ByteBuffer const& data)
{
auto maybe_connection = m_websockets.get(connection_id);
if (maybe_connection.has_value())
maybe_connection.value()->did_receive({}, data, is_text);
}
void RequestClient::websocket_errored(i32 connection_id, i32 message)
{
auto maybe_connection = m_websockets.get(connection_id);
if (maybe_connection.has_value())
maybe_connection.value()->did_error({}, message);
}
void RequestClient::websocket_closed(i32 connection_id, u16 code, ByteString const& reason, bool clean)
{
auto maybe_connection = m_websockets.get(connection_id);
if (maybe_connection.has_value())
maybe_connection.value()->did_close({}, code, reason, clean);
}
void RequestClient::websocket_certificate_requested(i32 connection_id)
{
auto maybe_connection = m_websockets.get(connection_id);
if (maybe_connection.has_value())
maybe_connection.value()->did_request_certificates({});
}
}
template RefPtr<Protocol::Request> Protocol::RequestClient::start_request(ByteString const& method, URL const&, HashMap<ByteString, ByteString> const& request_headers, ReadonlyBytes request_body, Core::ProxyData const&);

View file

@ -8,6 +8,8 @@
#include <AK/HashMap.h>
#include <LibIPC/ConnectionToServer.h>
#include <LibProtocol/WebSocket.h>
#include <LibWebSocket/WebSocket.h>
#include <RequestServer/RequestClientEndpoint.h>
#include <RequestServer/RequestServerEndpoint.h>
@ -26,6 +28,8 @@ public:
template<typename RequestHashMapTraits = Traits<ByteString>>
RefPtr<Request> start_request(ByteString const& method, URL const&, HashMap<ByteString, ByteString, RequestHashMapTraits> const& request_headers = {}, ReadonlyBytes request_body = {}, Core::ProxyData const& = {});
RefPtr<WebSocket> websocket_connect(const URL&, ByteString const& origin = {}, Vector<ByteString> const& protocols = {}, Vector<ByteString> const& extensions = {}, HashMap<ByteString, ByteString> const& request_headers = {});
void ensure_connection(URL const&, ::RequestServer::CacheLevel);
bool stop_request(Badge<Request>, Request&);
@ -38,7 +42,14 @@ private:
virtual void certificate_requested(i32) override;
virtual void headers_became_available(i32, HashMap<ByteString, ByteString, CaseInsensitiveStringTraits> const&, Optional<u32> const&) override;
virtual void websocket_connected(i32) override;
virtual void websocket_received(i32, bool, ByteBuffer const&) override;
virtual void websocket_errored(i32, i32) override;
virtual void websocket_closed(i32, u16, ByteString const&, bool) override;
virtual void websocket_certificate_requested(i32) override;
HashMap<i32, RefPtr<Request>> m_requests;
HashMap<i32, NonnullRefPtr<WebSocket>> m_websockets;
};
}

View file

@ -4,12 +4,12 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibProtocol/RequestClient.h>
#include <LibProtocol/WebSocket.h>
#include <LibProtocol/WebSocketClient.h>
namespace Protocol {
WebSocket::WebSocket(WebSocketClient& client, i32 connection_id)
WebSocket::WebSocket(RequestClient& client, i32 connection_id)
: m_client(client)
, m_connection_id(connection_id)
{
@ -17,17 +17,17 @@ WebSocket::WebSocket(WebSocketClient& client, i32 connection_id)
WebSocket::ReadyState WebSocket::ready_state()
{
return (WebSocket::ReadyState)m_client->ready_state({}, *this);
return static_cast<WebSocket::ReadyState>(m_client->websocket_ready_state(m_connection_id));
}
ByteString WebSocket::subprotocol_in_use()
{
return m_client->subprotocol_in_use({}, *this);
return m_client->websocket_subprotocol_in_use(m_connection_id);
}
void WebSocket::send(ByteBuffer binary_or_text_message, bool is_text)
{
m_client->send({}, *this, move(binary_or_text_message), is_text);
m_client->async_websocket_send(m_connection_id, is_text, move(binary_or_text_message));
}
void WebSocket::send(StringView text_message)
@ -37,38 +37,38 @@ void WebSocket::send(StringView text_message)
void WebSocket::close(u16 code, ByteString reason)
{
m_client->close({}, *this, code, move(reason));
m_client->async_websocket_close(m_connection_id, code, move(reason));
}
void WebSocket::did_open(Badge<WebSocketClient>)
void WebSocket::did_open(Badge<RequestClient>)
{
if (on_open)
on_open();
}
void WebSocket::did_receive(Badge<WebSocketClient>, ByteBuffer data, bool is_text)
void WebSocket::did_receive(Badge<RequestClient>, ByteBuffer data, bool is_text)
{
if (on_message)
on_message(WebSocket::Message { move(data), is_text });
}
void WebSocket::did_error(Badge<WebSocketClient>, i32 error_code)
void WebSocket::did_error(Badge<RequestClient>, i32 error_code)
{
if (on_error)
on_error((WebSocket::Error)error_code);
}
void WebSocket::did_close(Badge<WebSocketClient>, u16 code, ByteString reason, bool was_clean)
void WebSocket::did_close(Badge<RequestClient>, u16 code, ByteString reason, bool was_clean)
{
if (on_close)
on_close(code, move(reason), was_clean);
}
void WebSocket::did_request_certificates(Badge<WebSocketClient>)
void WebSocket::did_request_certificates(Badge<RequestClient>)
{
if (on_certificate_requested) {
auto result = on_certificate_requested();
if (!m_client->set_certificate({}, *this, result.certificate, result.key))
if (!m_client->websocket_set_certificate(m_connection_id, result.certificate, result.key))
dbgln("WebSocket: set_certificate failed");
}
}

View file

@ -17,7 +17,7 @@
namespace Protocol {
class WebSocketClient;
class RequestClient;
class WebSocket : public RefCounted<WebSocket> {
public:
@ -44,7 +44,7 @@ public:
Closed = 3,
};
static NonnullRefPtr<WebSocket> create_from_id(Badge<WebSocketClient>, WebSocketClient& client, i32 connection_id)
static NonnullRefPtr<WebSocket> create_from_id(Badge<RequestClient>, RequestClient& client, i32 connection_id)
{
return adopt_ref(*new WebSocket(client, connection_id));
}
@ -65,15 +65,15 @@ public:
Function<void(u16 code, ByteString reason, bool was_clean)> on_close;
Function<CertificateAndKey()> on_certificate_requested;
void did_open(Badge<WebSocketClient>);
void did_receive(Badge<WebSocketClient>, ByteBuffer, bool);
void did_error(Badge<WebSocketClient>, i32);
void did_close(Badge<WebSocketClient>, u16, ByteString, bool);
void did_request_certificates(Badge<WebSocketClient>);
void did_open(Badge<RequestClient>);
void did_receive(Badge<RequestClient>, ByteBuffer, bool);
void did_error(Badge<RequestClient>, i32);
void did_close(Badge<RequestClient>, u16, ByteString, bool);
void did_request_certificates(Badge<RequestClient>);
private:
explicit WebSocket(WebSocketClient&, i32 connection_id);
WeakPtr<WebSocketClient> m_client;
explicit WebSocket(RequestClient&, i32 connection_id);
WeakPtr<RequestClient> m_client;
int m_connection_id { -1 };
};

View file

@ -1,100 +0,0 @@
/*
* Copyright (c) 2021, Dex <dexes.ttp@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibProtocol/WebSocket.h>
#include <LibProtocol/WebSocketClient.h>
namespace Protocol {
WebSocketClient::WebSocketClient(NonnullOwnPtr<Core::LocalSocket> socket)
: IPC::ConnectionToServer<WebSocketClientEndpoint, WebSocketServerEndpoint>(*this, move(socket))
{
}
RefPtr<WebSocket> WebSocketClient::connect(const URL& url, ByteString const& origin, Vector<ByteString> const& protocols, Vector<ByteString> const& extensions, HashMap<ByteString, ByteString> const& request_headers)
{
auto headers_or_error = request_headers.clone();
if (headers_or_error.is_error())
return nullptr;
auto connection_id = IPCProxy::connect(url, origin, protocols, extensions, headers_or_error.release_value());
if (connection_id < 0)
return nullptr;
auto connection = WebSocket::create_from_id({}, *this, connection_id);
m_connections.set(connection_id, connection);
return connection;
}
u32 WebSocketClient::ready_state(Badge<WebSocket>, WebSocket& connection)
{
if (!m_connections.contains(connection.id()))
return (u32)WebSocket::ReadyState::Closed;
return IPCProxy::ready_state(connection.id());
}
ByteString WebSocketClient::subprotocol_in_use(Badge<WebSocket>, WebSocket& connection)
{
if (!m_connections.contains(connection.id()))
return ByteString::empty();
return IPCProxy::subprotocol_in_use(connection.id());
}
void WebSocketClient::send(Badge<WebSocket>, WebSocket& connection, ByteBuffer data, bool is_text)
{
if (!m_connections.contains(connection.id()))
return;
async_send(connection.id(), is_text, move(data));
}
void WebSocketClient::close(Badge<WebSocket>, WebSocket& connection, u16 code, ByteString message)
{
if (!m_connections.contains(connection.id()))
return;
async_close(connection.id(), code, move(message));
}
bool WebSocketClient::set_certificate(Badge<WebSocket>, WebSocket& connection, ByteString certificate, ByteString key)
{
if (!m_connections.contains(connection.id()))
return false;
return IPCProxy::set_certificate(connection.id(), move(certificate), move(key));
}
void WebSocketClient::connected(i32 connection_id)
{
auto maybe_connection = m_connections.get(connection_id);
if (maybe_connection.has_value())
maybe_connection.value()->did_open({});
}
void WebSocketClient::received(i32 connection_id, bool is_text, ByteBuffer const& data)
{
auto maybe_connection = m_connections.get(connection_id);
if (maybe_connection.has_value())
maybe_connection.value()->did_receive({}, data, is_text);
}
void WebSocketClient::errored(i32 connection_id, i32 message)
{
auto maybe_connection = m_connections.get(connection_id);
if (maybe_connection.has_value())
maybe_connection.value()->did_error({}, message);
}
void WebSocketClient::closed(i32 connection_id, u16 code, ByteString const& reason, bool clean)
{
auto maybe_connection = m_connections.get(connection_id);
if (maybe_connection.has_value())
maybe_connection.value()->did_close({}, code, reason, clean);
}
void WebSocketClient::certificate_requested(i32 connection_id)
{
auto maybe_connection = m_connections.get(connection_id);
if (maybe_connection.has_value())
maybe_connection.value()->did_request_certificates({});
}
}

View file

@ -1,44 +0,0 @@
/*
* Copyright (c) 2021, Dex <dexes.ttp@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/HashMap.h>
#include <LibIPC/ConnectionToServer.h>
#include <WebSocket/WebSocketClientEndpoint.h>
#include <WebSocket/WebSocketServerEndpoint.h>
namespace Protocol {
class WebSocket;
class WebSocketClient final
: public IPC::ConnectionToServer<WebSocketClientEndpoint, WebSocketServerEndpoint>
, public WebSocketClientEndpoint {
IPC_CLIENT_CONNECTION(WebSocketClient, "/tmp/session/%sid/portal/websocket"sv)
public:
explicit WebSocketClient(NonnullOwnPtr<Core::LocalSocket>);
RefPtr<WebSocket> connect(const URL&, ByteString const& origin = {}, Vector<ByteString> const& protocols = {}, Vector<ByteString> const& extensions = {}, HashMap<ByteString, ByteString> const& request_headers = {});
u32 ready_state(Badge<WebSocket>, WebSocket&);
ByteString subprotocol_in_use(Badge<WebSocket>, WebSocket&);
void send(Badge<WebSocket>, WebSocket&, ByteBuffer, bool is_text);
void close(Badge<WebSocket>, WebSocket&, u16 code, ByteString reason);
bool set_certificate(Badge<WebSocket>, WebSocket&, ByteString, ByteString);
private:
virtual void connected(i32) override;
virtual void received(i32, bool, ByteBuffer const&) override;
virtual void errored(i32, i32) override;
virtual void closed(i32, u16, ByteString const&, bool) override;
virtual void certificate_requested(i32) override;
HashMap<i32, NonnullRefPtr<WebSocket>> m_connections;
};
}

View file

@ -66,6 +66,10 @@ namespace Web {
constexpr auto default_user_agent = "Mozilla/5.0 (" OS_STRING "; " CPU_STRING ") " BROWSER_NAME "/" BROWSER_VERSION ""sv;
constexpr auto default_platform = OS_STRING " " CPU_STRING ""sv;
namespace WebSockets {
class WebSocketClientSocket;
}
class ResourceLoaderConnectorRequest : public RefCounted<ResourceLoaderConnectorRequest> {
public:
virtual ~ResourceLoaderConnectorRequest();
@ -97,6 +101,7 @@ public:
virtual void preconnect(URL const&) = 0;
virtual RefPtr<ResourceLoaderConnectorRequest> start_request(ByteString const& method, URL const&, HashMap<ByteString, ByteString> const& request_headers = {}, ReadonlyBytes request_body = {}, Core::ProxyData const& = {}) = 0;
virtual RefPtr<Web::WebSockets::WebSocketClientSocket> websocket_connect(const URL&, ByteString const& origin, Vector<ByteString> const& protocols) = 0;
protected:
explicit ResourceLoaderConnector();

View file

@ -19,6 +19,7 @@
#include <LibWeb/HTML/MessageEvent.h>
#include <LibWeb/HTML/Origin.h>
#include <LibWeb/HTML/Window.h>
#include <LibWeb/Loader/ResourceLoader.h>
#include <LibWeb/WebIDL/AbstractOperations.h>
#include <LibWeb/WebIDL/Buffers.h>
#include <LibWeb/WebIDL/DOMException.h>
@ -29,28 +30,8 @@ namespace Web::WebSockets {
JS_DEFINE_ALLOCATOR(WebSocket);
static RefPtr<WebSocketClientManager> s_websocket_client_manager;
void WebSocketClientManager::initialize(RefPtr<WebSocketClientManager> websocket_client_manager)
{
s_websocket_client_manager = websocket_client_manager;
}
WebSocketClientManager& WebSocketClientManager::the()
{
if (!s_websocket_client_manager) [[unlikely]] {
dbgln("Web::WebSockets::WebSocketClientManager was not initialized!");
VERIFY_NOT_REACHED();
}
return *s_websocket_client_manager;
}
WebSocketClientSocket::WebSocketClientSocket() = default;
WebSocketClientSocket::~WebSocketClientSocket() = default;
WebSocketClientManager::WebSocketClientManager() = default;
// https://websockets.spec.whatwg.org/#dom-websocket-websocket
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebSocket>> WebSocket::construct_impl(JS::Realm& realm, String const& url, Optional<Variant<String, Vector<String>>> const& protocols)
{
@ -148,7 +129,7 @@ ErrorOr<void> WebSocket::establish_web_socket_connection(URL& url_record, Vector
for (auto const& protocol : protocols)
TRY(protcol_byte_strings.try_append(protocol.to_byte_string()));
m_websocket = WebSocketClientManager::the().connect(url_record, origin_string, protcol_byte_strings);
m_websocket = ResourceLoader::the().connector().websocket_connect(url_record, origin_string, protcol_byte_strings);
m_websocket->on_open = [weak_this = make_weak_ptr<WebSocket>()] {
if (!weak_this)
return;

View file

@ -114,19 +114,7 @@ public:
Function<CertificateAndKey()> on_certificate_requested;
protected:
explicit WebSocketClientSocket();
};
class WebSocketClientManager : public Core::EventReceiver {
C_OBJECT_ABSTRACT(WebSocketClientManager)
public:
static void initialize(RefPtr<WebSocketClientManager>);
static WebSocketClientManager& the();
virtual RefPtr<WebSocketClientSocket> connect(URL const&, ByteString const& origin, Vector<ByteString> const& protocols) = 0;
protected:
explicit WebSocketClientManager();
explicit WebSocketClientSocket() = default;
};
}

View file

@ -40,8 +40,6 @@ set(GENERATED_SOURCES
../../Services/WebContent/WebContentServerEndpoint.h
../../Services/WebContent/WebDriverClientEndpoint.h
../../Services/WebContent/WebDriverServerEndpoint.h
../../Services/WebSocket/WebSocketClientEndpoint.h
../../Services/WebSocket/WebSocketServerEndpoint.h
NativeStyleSheetSource.cpp
)

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "WebSocketClientAdapter.h"
#include <LibProtocol/Request.h>
#include <LibProtocol/RequestClient.h>
#include <LibWebView/RequestServerAdapter.h>
@ -94,6 +95,14 @@ RefPtr<Web::ResourceLoaderConnectorRequest> RequestServerAdapter::start_request(
return RequestServerRequestAdapter::try_create(protocol_request.release_nonnull()).release_value_but_fixme_should_propagate_errors();
}
RefPtr<Web::WebSockets::WebSocketClientSocket> RequestServerAdapter::websocket_connect(AK::URL const& url, AK::ByteString const& origin, Vector<AK::ByteString> const& protocols)
{
auto underlying_websocket = m_protocol_client->websocket_connect(url, origin, protocols);
if (!underlying_websocket)
return {};
return WebSocketClientSocketAdapter::create(underlying_websocket.release_nonnull());
}
void RequestServerAdapter::prefetch_dns(URL const& url)
{
m_protocol_client->ensure_connection(url, RequestServer::CacheLevel::ResolveOnly);

View file

@ -9,6 +9,7 @@
#include <AK/Function.h>
#include <AK/URL.h>
#include <LibWeb/Loader/ResourceLoader.h>
#include <LibWeb/WebSockets/WebSocket.h>
namespace Protocol {
class Request;
@ -46,6 +47,7 @@ public:
virtual void preconnect(URL const& url) override;
virtual RefPtr<Web::ResourceLoaderConnectorRequest> start_request(ByteString const& method, URL const&, HashMap<ByteString, ByteString> const& request_headers = {}, ReadonlyBytes request_body = {}, Core::ProxyData const& = {}) override;
virtual RefPtr<Web::WebSockets::WebSocketClientSocket> websocket_connect(const URL&, ByteString const& origin, Vector<ByteString> const& protocols) override;
private:
RefPtr<Protocol::RequestClient> m_protocol_client;

View file

@ -4,8 +4,8 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibProtocol/RequestClient.h>
#include <LibProtocol/WebSocket.h>
#include <LibProtocol/WebSocketClient.h>
#include <LibWebView/WebSocketClientAdapter.h>
namespace WebView {
@ -107,30 +107,4 @@ void WebSocketClientSocketAdapter::close(u16 code, ByteString reason)
m_websocket->close(code, reason);
}
ErrorOr<NonnullRefPtr<WebSocketClientManagerAdapter>> WebSocketClientManagerAdapter::try_create(NonnullRefPtr<Protocol::WebSocketClient> websocket_client)
{
return adopt_nonnull_ref_or_enomem(new (nothrow) WebSocketClientManagerAdapter(move(websocket_client)));
}
ErrorOr<NonnullRefPtr<WebSocketClientManagerAdapter>> WebSocketClientManagerAdapter::try_create()
{
auto websocket_client = TRY(Protocol::WebSocketClient::try_create());
return adopt_nonnull_ref_or_enomem(new (nothrow) WebSocketClientManagerAdapter(move(websocket_client)));
}
WebSocketClientManagerAdapter::WebSocketClientManagerAdapter(NonnullRefPtr<Protocol::WebSocketClient> websocket_client)
: m_websocket_client(move(websocket_client))
{
}
WebSocketClientManagerAdapter::~WebSocketClientManagerAdapter() = default;
RefPtr<Web::WebSockets::WebSocketClientSocket> WebSocketClientManagerAdapter::connect(const URL& url, ByteString const& origin, Vector<ByteString> const& protocols)
{
auto underlying_websocket = m_websocket_client->connect(url, origin, protocols);
if (!underlying_websocket)
return {};
return WebSocketClientSocketAdapter::create(underlying_websocket.release_nonnull());
}
}

View file

@ -13,7 +13,7 @@
namespace Protocol {
class WebSocket;
class WebSocketClient;
class RequestClient;
};
namespace WebView {
@ -38,19 +38,4 @@ private:
NonnullRefPtr<Protocol::WebSocket> m_websocket;
};
class WebSocketClientManagerAdapter : public Web::WebSockets::WebSocketClientManager {
public:
static ErrorOr<NonnullRefPtr<WebSocketClientManagerAdapter>> try_create(NonnullRefPtr<Protocol::WebSocketClient>);
static ErrorOr<NonnullRefPtr<WebSocketClientManagerAdapter>> try_create();
virtual ~WebSocketClientManagerAdapter() override;
virtual RefPtr<Web::WebSockets::WebSocketClientSocket> connect(const URL&, ByteString const& origin, Vector<ByteString> const& protocols) override;
private:
WebSocketClientManagerAdapter(NonnullRefPtr<Protocol::WebSocketClient>);
NonnullRefPtr<Protocol::WebSocketClient> m_websocket_client;
};
}