diff options
author | DexesTTP <dexes.ttp@gmail.com> | 2022-04-30 11:26:21 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-05-15 12:17:36 +0200 |
commit | 2a359695c6d2b96080c64bdbcf8cd553bcab71d5 (patch) | |
tree | 6a227686ce4673e4c1165241edf5a0b1bb7159fe /Userland | |
parent | 2198091bbcd8ccd9445f12b6628e4b2d1268451b (diff) | |
download | serenity-2a359695c6d2b96080c64bdbcf8cd553bcab71d5.zip |
LibWeb: Abstract the LibProtocol WebSockets connection
Much like the ImageDecoder change, this moves the underlying connection
of the Web::WebSockets class from LibWeb to LibWebView, removing the
need for LibProtocol in LibWeb for this specific use-case.
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Libraries/LibWeb/WebSockets/WebSocket.cpp | 49 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/WebSockets/WebSocket.h | 72 | ||||
-rw-r--r-- | Userland/Libraries/LibWebView/CMakeLists.txt | 3 | ||||
-rw-r--r-- | Userland/Libraries/LibWebView/WebSocketClientAdapter.cpp | 126 | ||||
-rw-r--r-- | Userland/Libraries/LibWebView/WebSocketClientAdapter.h | 54 | ||||
-rw-r--r-- | Userland/Services/WebContent/main.cpp | 3 |
6 files changed, 254 insertions, 53 deletions
diff --git a/Userland/Libraries/LibWeb/WebSockets/WebSocket.cpp b/Userland/Libraries/LibWeb/WebSockets/WebSocket.cpp index c351b95501..4c32160716 100644 --- a/Userland/Libraries/LibWeb/WebSockets/WebSocket.cpp +++ b/Userland/Libraries/LibWeb/WebSockets/WebSocket.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Dex♪ <dexes.ttp@gmail.com> + * Copyright (c) 2021-2022, Dex♪ <dexes.ttp@gmail.com> * * SPDX-License-Identifier: BSD-2-Clause */ @@ -8,8 +8,6 @@ #include <LibJS/Parser.h> #include <LibJS/Runtime/ArrayBuffer.h> #include <LibJS/Runtime/FunctionObject.h> -#include <LibProtocol/WebSocket.h> -#include <LibProtocol/WebSocketClient.h> #include <LibWeb/Bindings/EventWrapper.h> #include <LibWeb/Bindings/WebSocketWrapper.h> #include <LibWeb/DOM/DOMException.h> @@ -28,29 +26,27 @@ namespace Web::WebSockets { -WebSocketClientManager& WebSocketClientManager::the() -{ - static RefPtr<WebSocketClientManager> s_the; - if (!s_the) - s_the = WebSocketClientManager::try_create().release_value_but_fixme_should_propagate_errors(); - return *s_the; -} +static RefPtr<WebSocketClientManager> s_websocket_client_manager; -ErrorOr<NonnullRefPtr<WebSocketClientManager>> WebSocketClientManager::try_create() +void WebSocketClientManager::initialize(RefPtr<WebSocketClientManager> websocket_client_manager) { - auto websocket_client = TRY(Protocol::WebSocketClient::try_create()); - return adopt_nonnull_ref_or_enomem(new (nothrow) WebSocketClientManager(move(websocket_client))); + s_websocket_client_manager = websocket_client_manager; } -WebSocketClientManager::WebSocketClientManager(NonnullRefPtr<Protocol::WebSocketClient> websocket_client) - : m_websocket_client(move(websocket_client)) +WebSocketClientManager& WebSocketClientManager::the() { + if (!s_websocket_client_manager) [[unlikely]] { + dbgln("Web::WebSockets::WebSocketClientManager was not initialized!"); + VERIFY_NOT_REACHED(); + } + return *s_websocket_client_manager; } -RefPtr<Protocol::WebSocket> WebSocketClientManager::connect(const AK::URL& url, String const& origin) -{ - return m_websocket_client->connect(url, origin); -} +WebSocketClientSocket::WebSocketClientSocket() = default; + +WebSocketClientSocket::~WebSocketClientSocket() = default; + +WebSocketClientManager::WebSocketClientManager() = default; // https://websockets.spec.whatwg.org/#dom-websocket-websocket DOM::ExceptionOr<NonnullRefPtr<WebSocket>> WebSocket::create_with_global_object(Bindings::WindowObject& window, String const& url) @@ -107,18 +103,7 @@ WebSocket::ReadyState WebSocket::ready_state() const { if (!m_websocket) return WebSocket::ReadyState::Closed; - auto ready_state = const_cast<Protocol::WebSocket&>(*m_websocket).ready_state(); - switch (ready_state) { - case Protocol::WebSocket::ReadyState::Connecting: - return WebSocket::ReadyState::Connecting; - case Protocol::WebSocket::ReadyState::Open: - return WebSocket::ReadyState::Open; - case Protocol::WebSocket::ReadyState::Closing: - return WebSocket::ReadyState::Closing; - case Protocol::WebSocket::ReadyState::Closed: - return WebSocket::ReadyState::Closed; - } - return WebSocket::ReadyState::Closed; + return const_cast<WebSocketClientSocket&>(*m_websocket).ready_state(); } // https://websockets.spec.whatwg.org/#dom-websocket-extensions @@ -212,7 +197,7 @@ void WebSocket::on_close(u16 code, String reason, bool was_clean) // https://websockets.spec.whatwg.org/#feedback-from-the-protocol void WebSocket::on_message(ByteBuffer message, bool is_text) { - if (m_websocket->ready_state() != Protocol::WebSocket::ReadyState::Open) + if (m_websocket->ready_state() != WebSocket::ReadyState::Open) return; if (is_text) { auto text_message = String(ReadonlyBytes(message)); diff --git a/Userland/Libraries/LibWeb/WebSockets/WebSocket.h b/Userland/Libraries/LibWeb/WebSockets/WebSocket.h index 7d2b292592..2bc3b42838 100644 --- a/Userland/Libraries/LibWeb/WebSockets/WebSocket.h +++ b/Userland/Libraries/LibWeb/WebSockets/WebSocket.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Dex♪ <dexes.ttp@gmail.com> + * Copyright (c) 2021-2022, Dex♪ <dexes.ttp@gmail.com> * * SPDX-License-Identifier: BSD-2-Clause */ @@ -23,26 +23,10 @@ E(onopen, HTML::EventNames::open) \ E(onmessage, HTML::EventNames::message) -namespace Protocol { -class WebSocketClient; -class WebSocket; -} - namespace Web::WebSockets { -class WebSocketClientManager : public Core::Object { - C_OBJECT_ABSTRACT(WebSocketClientManager) -public: - static WebSocketClientManager& the(); - - RefPtr<Protocol::WebSocket> connect(const AK::URL&, String const& origin); - -private: - static ErrorOr<NonnullRefPtr<WebSocketClientManager>> try_create(); - WebSocketClientManager(NonnullRefPtr<Protocol::WebSocketClient>); - - RefPtr<Protocol::WebSocketClient> m_websocket_client; -}; +class WebSocketClientSocket; +class WebSocketClientManager; class WebSocket final : public RefCounted<WebSocket> @@ -106,7 +90,55 @@ private: AK::URL m_url; String m_binary_type { "blob" }; - RefPtr<Protocol::WebSocket> m_websocket; + RefPtr<WebSocketClientSocket> m_websocket; +}; + +class WebSocketClientSocket : public RefCounted<WebSocketClientSocket> { +public: + virtual ~WebSocketClientSocket(); + + struct CertificateAndKey { + String certificate; + String key; + }; + + struct Message { + ByteBuffer data; + bool is_text { false }; + }; + + enum class Error { + CouldNotEstablishConnection, + ConnectionUpgradeFailed, + ServerClosedSocket, + }; + + virtual Web::WebSockets::WebSocket::ReadyState ready_state() = 0; + + virtual void send(ByteBuffer binary_or_text_message, bool is_text) = 0; + virtual void send(StringView text_message) = 0; + virtual void close(u16 code = 1005, String reason = {}) = 0; + + Function<void()> on_open; + Function<void(Message)> on_message; + Function<void(Error)> on_error; + Function<void(u16 code, String reason, bool was_clean)> on_close; + Function<CertificateAndKey()> on_certificate_requested; + +protected: + explicit WebSocketClientSocket(); +}; + +class WebSocketClientManager : public Core::Object { + C_OBJECT_ABSTRACT(WebSocketClientManager) +public: + static void initialize(RefPtr<WebSocketClientManager>); + static WebSocketClientManager& the(); + + virtual RefPtr<WebSocketClientSocket> connect(AK::URL const&, String const& origin) = 0; + +protected: + explicit WebSocketClientManager(); }; } diff --git a/Userland/Libraries/LibWebView/CMakeLists.txt b/Userland/Libraries/LibWebView/CMakeLists.txt index d0da3aef1e..4fa461b816 100644 --- a/Userland/Libraries/LibWebView/CMakeLists.txt +++ b/Userland/Libraries/LibWebView/CMakeLists.txt @@ -4,6 +4,7 @@ set(SOURCES OutOfProcessWebView.cpp StylePropertiesModel.cpp WebContentClient.cpp + WebSocketClientAdapter.cpp ) set(GENERATED_SOURCES @@ -14,6 +15,6 @@ set(GENERATED_SOURCES ) serenity_lib(LibWebView webview) -target_link_libraries(LibWebView LibGfx LibGUI LibImageDecoderClient LibIPC LibWeb) +target_link_libraries(LibWebView LibGfx LibGUI LibImageDecoderClient LibIPC LibProtocol LibWeb) add_subdirectory(DumpLayoutTree) diff --git a/Userland/Libraries/LibWebView/WebSocketClientAdapter.cpp b/Userland/Libraries/LibWebView/WebSocketClientAdapter.cpp new file mode 100644 index 0000000000..7c1f0982e8 --- /dev/null +++ b/Userland/Libraries/LibWebView/WebSocketClientAdapter.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2022, Dex♪ <dexes.ttp@gmail.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <LibProtocol/WebSocket.h> +#include <LibProtocol/WebSocketClient.h> +#include <LibWebView/WebSocketClientAdapter.h> + +namespace WebView { + +RefPtr<WebSocketClientSocketAdapter> WebSocketClientSocketAdapter::create(NonnullRefPtr<Protocol::WebSocket> websocket) +{ + return adopt_ref(*new WebSocketClientSocketAdapter(move(websocket))); +} + +WebSocketClientSocketAdapter::WebSocketClientSocketAdapter(NonnullRefPtr<Protocol::WebSocket> websocket) + : m_websocket(move(websocket)) +{ + m_websocket->on_open = [weak_this = make_weak_ptr()] { + if (auto strong_this = weak_this.strong_ref()) + if (strong_this->on_open) + strong_this->on_open(); + }; + m_websocket->on_message = [weak_this = make_weak_ptr()](auto message) { + if (auto strong_this = weak_this.strong_ref()) { + if (strong_this->on_message) { + strong_this->on_message(Web::WebSockets::WebSocketClientSocket::Message { + .data = move(message.data), + .is_text = message.is_text, + }); + } + } + }; + m_websocket->on_error = [weak_this = make_weak_ptr()](auto error) { + if (auto strong_this = weak_this.strong_ref()) { + if (strong_this->on_error) { + switch (error) { + case Protocol::WebSocket::Error::CouldNotEstablishConnection: + strong_this->on_error(Web::WebSockets::WebSocketClientSocket::Error::CouldNotEstablishConnection); + return; + case Protocol::WebSocket::Error::ConnectionUpgradeFailed: + strong_this->on_error(Web::WebSockets::WebSocketClientSocket::Error::ConnectionUpgradeFailed); + return; + case Protocol::WebSocket::Error::ServerClosedSocket: + strong_this->on_error(Web::WebSockets::WebSocketClientSocket::Error::ServerClosedSocket); + return; + } + VERIFY_NOT_REACHED(); + } + } + }; + m_websocket->on_close = [weak_this = make_weak_ptr()](u16 code, String reason, bool was_clean) { + if (auto strong_this = weak_this.strong_ref()) + if (strong_this->on_close) + strong_this->on_close(code, move(reason), was_clean); + }; + m_websocket->on_certificate_requested = [weak_this = make_weak_ptr()] { + if (auto strong_this = weak_this.strong_ref()) { + if (strong_this->on_certificate_requested) { + auto certificate_and_key = weak_this->on_certificate_requested(); + return Protocol::WebSocket::CertificateAndKey { + .certificate = move(certificate_and_key.certificate), + .key = move(certificate_and_key.key), + }; + } + } + return Protocol::WebSocket::CertificateAndKey {}; + }; +} + +WebSocketClientSocketAdapter::~WebSocketClientSocketAdapter() = default; + +Web::WebSockets::WebSocket::ReadyState WebSocketClientSocketAdapter::ready_state() +{ + switch (m_websocket->ready_state()) { + case Protocol::WebSocket::ReadyState::Connecting: + return Web::WebSockets::WebSocket::ReadyState::Connecting; + case Protocol::WebSocket::ReadyState::Open: + return Web::WebSockets::WebSocket::ReadyState::Open; + case Protocol::WebSocket::ReadyState::Closing: + return Web::WebSockets::WebSocket::ReadyState::Closing; + case Protocol::WebSocket::ReadyState::Closed: + return Web::WebSockets::WebSocket::ReadyState::Closed; + } + VERIFY_NOT_REACHED(); +} + +void WebSocketClientSocketAdapter::send(ByteBuffer binary_or_text_message, bool is_text) +{ + m_websocket->send(binary_or_text_message, is_text); +} + +void WebSocketClientSocketAdapter::send(StringView text_message) +{ + m_websocket->send(text_message); +} + +void WebSocketClientSocketAdapter::close(u16 code, String reason) +{ + m_websocket->close(code, reason); +} + +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 AK::URL& url, String const& origin) +{ + auto underlying_websocket = m_websocket_client->connect(url, origin); + if (!underlying_websocket) + return {}; + return WebSocketClientSocketAdapter::create(underlying_websocket.release_nonnull()); +} + +} diff --git a/Userland/Libraries/LibWebView/WebSocketClientAdapter.h b/Userland/Libraries/LibWebView/WebSocketClientAdapter.h new file mode 100644 index 0000000000..8f7856c5e5 --- /dev/null +++ b/Userland/Libraries/LibWebView/WebSocketClientAdapter.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022, Dex♪ <dexes.ttp@gmail.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/Error.h> +#include <AK/NonnullRefPtr.h> +#include <AK/Weakable.h> +#include <LibWeb/WebSockets/WebSocket.h> + +namespace Protocol { +class WebSocket; +class WebSocketClient; +}; + +namespace WebView { + +class WebSocketClientSocketAdapter + : public Web::WebSockets::WebSocketClientSocket + , public Weakable<WebSocketClientSocketAdapter> { +public: + static RefPtr<WebSocketClientSocketAdapter> create(NonnullRefPtr<Protocol::WebSocket>); + virtual ~WebSocketClientSocketAdapter() override; + + virtual Web::WebSockets::WebSocket::ReadyState ready_state() override; + + virtual void send(ByteBuffer binary_or_text_message, bool is_text) override; + virtual void send(StringView text_message) override; + virtual void close(u16 code = 1005, String reason = {}) override; + +private: + WebSocketClientSocketAdapter(NonnullRefPtr<Protocol::WebSocket>); + + NonnullRefPtr<Protocol::WebSocket> m_websocket; +}; + +class WebSocketClientManagerAdapter : public Web::WebSockets::WebSocketClientManager { +public: + static ErrorOr<NonnullRefPtr<WebSocketClientManagerAdapter>> try_create(); + + virtual ~WebSocketClientManagerAdapter() override; + + virtual RefPtr<Web::WebSockets::WebSocketClientSocket> connect(const AK::URL&, String const& origin) override; + +private: + WebSocketClientManagerAdapter(NonnullRefPtr<Protocol::WebSocketClient>); + + NonnullRefPtr<Protocol::WebSocketClient> m_websocket_client; +}; + +} diff --git a/Userland/Services/WebContent/main.cpp b/Userland/Services/WebContent/main.cpp index 42c5292dd9..b7bfccf6e4 100644 --- a/Userland/Services/WebContent/main.cpp +++ b/Userland/Services/WebContent/main.cpp @@ -10,7 +10,9 @@ #include <LibIPC/SingleServer.h> #include <LibMain/Main.h> #include <LibWeb/ImageDecoding.h> +#include <LibWeb/WebSockets/WebSocket.h> #include <LibWebView/ImageDecoderClientAdapter.h> +#include <LibWebView/WebSocketClientAdapter.h> #include <WebContent/ConnectionFromClient.h> ErrorOr<int> serenity_main(Main::Arguments) @@ -25,6 +27,7 @@ ErrorOr<int> serenity_main(Main::Arguments) TRY(Core::System::unveil(nullptr, nullptr)); Web::ImageDecoding::Decoder::initialize(WebView::ImageDecoderClientAdapter::create()); + Web::WebSockets::WebSocketClientManager::initialize(TRY(WebView::WebSocketClientManagerAdapter::try_create())); auto client = TRY(IPC::take_over_accepted_client_from_system_server<WebContent::ConnectionFromClient>()); return event_loop.exec(); |