summaryrefslogtreecommitdiff
path: root/Userland/Services/WebSocket/ConnectionFromClient.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Userland/Services/WebSocket/ConnectionFromClient.cpp')
-rw-r--r--Userland/Services/WebSocket/ConnectionFromClient.cpp139
1 files changed, 139 insertions, 0 deletions
diff --git a/Userland/Services/WebSocket/ConnectionFromClient.cpp b/Userland/Services/WebSocket/ConnectionFromClient.cpp
new file mode 100644
index 0000000000..52ee645895
--- /dev/null
+++ b/Userland/Services/WebSocket/ConnectionFromClient.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2021, Dexβ™ͺ <dexes.ttp@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibWebSocket/ConnectionInfo.h>
+#include <LibWebSocket/Message.h>
+#include <WebSocket/ConnectionFromClient.h>
+#include <WebSocket/WebSocketClientEndpoint.h>
+
+namespace WebSocket {
+
+static HashMap<int, RefPtr<ConnectionFromClient>> s_connections;
+
+ConnectionFromClient::ConnectionFromClient(NonnullOwnPtr<Core::Stream::LocalSocket> socket)
+ : IPC::ConnectionFromClient<WebSocketClientEndpoint, WebSocketServerEndpoint>(*this, move(socket), 1)
+{
+ s_connections.set(1, *this);
+}
+
+ConnectionFromClient::~ConnectionFromClient()
+{
+}
+
+void ConnectionFromClient::die()
+{
+ s_connections.remove(client_id());
+ if (s_connections.is_empty())
+ Core::EventLoop::current().quit(0);
+}
+
+Messages::WebSocketServer::ConnectResponse ConnectionFromClient::connect(URL const& url, String const& origin,
+ Vector<String> const& protocols, Vector<String> const& extensions, IPC::Dictionary const& additional_request_headers)
+{
+ if (!url.is_valid()) {
+ dbgln("WebSocket::Connect: Invalid URL requested: '{}'", url);
+ return -1;
+ }
+
+ ConnectionInfo connection_info(url);
+ connection_info.set_origin(origin);
+ connection_info.set_protocols(protocols);
+ connection_info.set_extensions(extensions);
+
+ Vector<ConnectionInfo::Header> headers;
+ for (auto const& header : additional_request_headers.entries()) {
+ headers.append({ header.key, header.value });
+ }
+ connection_info.set_headers(headers);
+
+ VERIFY(m_connection_ids < NumericLimits<i32>::max());
+ auto id = ++m_connection_ids;
+ auto connection = WebSocket::create(move(connection_info));
+ connection->on_open = [this, id]() {
+ did_connect(id);
+ };
+ connection->on_message = [this, id](auto message) {
+ did_receive_message(id, move(message));
+ };
+ connection->on_error = [this, id](auto message) {
+ did_error(id, (i32)message);
+ };
+ connection->on_close = [this, id](u16 code, String reason, bool was_clean) {
+ did_close(id, code, move(reason), was_clean);
+ };
+
+ connection->start();
+ m_connections.set(id, move(connection));
+ return id;
+}
+
+Messages::WebSocketServer::ReadyStateResponse ConnectionFromClient::ready_state(i32 connection_id)
+{
+ RefPtr<WebSocket> connection = m_connections.get(connection_id).value_or({});
+ if (connection) {
+ return (u32)connection->ready_state();
+ }
+ return (u32)ReadyState::Closed;
+}
+
+void ConnectionFromClient::send(i32 connection_id, bool is_text, ByteBuffer const& data)
+{
+ RefPtr<WebSocket> connection = m_connections.get(connection_id).value_or({});
+ if (connection && connection->ready_state() == ReadyState::Open) {
+ Message websocket_message(data, is_text);
+ connection->send(websocket_message);
+ }
+}
+
+void ConnectionFromClient::close(i32 connection_id, u16 code, String const& reason)
+{
+ RefPtr<WebSocket> connection = m_connections.get(connection_id).value_or({});
+ if (connection && connection->ready_state() == ReadyState::Open)
+ connection->close(code, reason);
+}
+
+Messages::WebSocketServer::SetCertificateResponse ConnectionFromClient::set_certificate(i32 connection_id,
+ [[maybe_unused]] String const& certificate, [[maybe_unused]] String const& key)
+{
+ RefPtr<WebSocket> connection = m_connections.get(connection_id).value_or({});
+ bool success = false;
+ if (connection) {
+ // NO OP here
+ // connection->set_certificate(certificate, key);
+ success = true;
+ }
+ return success;
+}
+
+void ConnectionFromClient::did_connect(i32 connection_id)
+{
+ async_connected(connection_id);
+}
+
+void ConnectionFromClient::did_receive_message(i32 connection_id, Message message)
+{
+ async_received(connection_id, message.is_text(), message.data());
+}
+
+void ConnectionFromClient::did_error(i32 connection_id, i32 message)
+{
+ async_errored(connection_id, message);
+}
+
+void ConnectionFromClient::did_close(i32 connection_id, u16 code, String reason, bool was_clean)
+{
+ async_closed(connection_id, code, reason, was_clean);
+ deferred_invoke([this, connection_id] {
+ m_connections.remove(connection_id);
+ });
+}
+
+void ConnectionFromClient::did_request_certificates(i32 connection_id)
+{
+ async_certificate_requested(connection_id);
+}
+
+}