summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorDexesTTP <dexes.ttp@gmail.com>2022-04-30 11:26:21 +0200
committerAndreas Kling <kling@serenityos.org>2022-05-15 12:17:36 +0200
commit2a359695c6d2b96080c64bdbcf8cd553bcab71d5 (patch)
tree6a227686ce4673e4c1165241edf5a0b1bb7159fe /Userland
parent2198091bbcd8ccd9445f12b6628e4b2d1268451b (diff)
downloadserenity-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.cpp49
-rw-r--r--Userland/Libraries/LibWeb/WebSockets/WebSocket.h72
-rw-r--r--Userland/Libraries/LibWebView/CMakeLists.txt3
-rw-r--r--Userland/Libraries/LibWebView/WebSocketClientAdapter.cpp126
-rw-r--r--Userland/Libraries/LibWebView/WebSocketClientAdapter.h54
-rw-r--r--Userland/Services/WebContent/main.cpp3
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();