Serenity Operating System
1/*
2 * Copyright (c) 2021, Dex♪ <dexes.ttp@gmail.com>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <LibWebSocket/ConnectionInfo.h>
8#include <LibWebSocket/Message.h>
9#include <WebSocket/ConnectionFromClient.h>
10#include <WebSocket/WebSocketClientEndpoint.h>
11
12namespace WebSocket {
13
14static HashMap<int, RefPtr<ConnectionFromClient>> s_connections;
15
16ConnectionFromClient::ConnectionFromClient(NonnullOwnPtr<Core::LocalSocket> socket)
17 : IPC::ConnectionFromClient<WebSocketClientEndpoint, WebSocketServerEndpoint>(*this, move(socket), 1)
18{
19 s_connections.set(1, *this);
20}
21
22void ConnectionFromClient::die()
23{
24 s_connections.remove(client_id());
25 if (s_connections.is_empty())
26 Core::EventLoop::current().quit(0);
27}
28
29Messages::WebSocketServer::ConnectResponse ConnectionFromClient::connect(URL const& url, DeprecatedString const& origin,
30 Vector<DeprecatedString> const& protocols, Vector<DeprecatedString> const& extensions, IPC::Dictionary const& additional_request_headers)
31{
32 if (!url.is_valid()) {
33 dbgln("WebSocket::Connect: Invalid URL requested: '{}'", url);
34 return -1;
35 }
36
37 ConnectionInfo connection_info(url);
38 connection_info.set_origin(origin);
39 connection_info.set_protocols(protocols);
40 connection_info.set_extensions(extensions);
41
42 Vector<ConnectionInfo::Header> headers;
43 for (auto const& header : additional_request_headers.entries()) {
44 headers.append({ header.key, header.value });
45 }
46 connection_info.set_headers(headers);
47
48 VERIFY(m_connection_ids < NumericLimits<i32>::max());
49 auto id = ++m_connection_ids;
50 auto connection = WebSocket::create(move(connection_info));
51 connection->on_open = [this, id]() {
52 did_connect(id);
53 };
54 connection->on_message = [this, id](auto message) {
55 did_receive_message(id, move(message));
56 };
57 connection->on_error = [this, id](auto message) {
58 did_error(id, (i32)message);
59 };
60 connection->on_close = [this, id](u16 code, DeprecatedString reason, bool was_clean) {
61 did_close(id, code, move(reason), was_clean);
62 };
63
64 connection->start();
65 m_connections.set(id, move(connection));
66 return id;
67}
68
69Messages::WebSocketServer::ReadyStateResponse ConnectionFromClient::ready_state(i32 connection_id)
70{
71 RefPtr<WebSocket> connection = m_connections.get(connection_id).value_or({});
72 if (connection) {
73 return (u32)connection->ready_state();
74 }
75 return (u32)ReadyState::Closed;
76}
77
78Messages::WebSocketServer::SubprotocolInUseResponse ConnectionFromClient::subprotocol_in_use(i32 connection_id)
79{
80 RefPtr<WebSocket> connection = m_connections.get(connection_id).value_or({});
81 if (connection) {
82 return connection->subprotocol_in_use();
83 }
84 return DeprecatedString::empty();
85}
86
87void ConnectionFromClient::send(i32 connection_id, bool is_text, ByteBuffer const& data)
88{
89 RefPtr<WebSocket> connection = m_connections.get(connection_id).value_or({});
90 if (connection && connection->ready_state() == ReadyState::Open) {
91 Message websocket_message(data, is_text);
92 connection->send(websocket_message);
93 }
94}
95
96void ConnectionFromClient::close(i32 connection_id, u16 code, DeprecatedString const& reason)
97{
98 RefPtr<WebSocket> connection = m_connections.get(connection_id).value_or({});
99 if (connection && connection->ready_state() == ReadyState::Open)
100 connection->close(code, reason);
101}
102
103Messages::WebSocketServer::SetCertificateResponse ConnectionFromClient::set_certificate(i32 connection_id,
104 [[maybe_unused]] DeprecatedString const& certificate, [[maybe_unused]] DeprecatedString const& key)
105{
106 RefPtr<WebSocket> connection = m_connections.get(connection_id).value_or({});
107 bool success = false;
108 if (connection) {
109 // NO OP here
110 // connection->set_certificate(certificate, key);
111 success = true;
112 }
113 return success;
114}
115
116void ConnectionFromClient::did_connect(i32 connection_id)
117{
118 async_connected(connection_id);
119}
120
121void ConnectionFromClient::did_receive_message(i32 connection_id, Message message)
122{
123 async_received(connection_id, message.is_text(), message.data());
124}
125
126void ConnectionFromClient::did_error(i32 connection_id, i32 message)
127{
128 async_errored(connection_id, message);
129}
130
131void ConnectionFromClient::did_close(i32 connection_id, u16 code, DeprecatedString reason, bool was_clean)
132{
133 async_closed(connection_id, code, reason, was_clean);
134 deferred_invoke([this, connection_id] {
135 m_connections.remove(connection_id);
136 });
137}
138
139void ConnectionFromClient::did_request_certificates(i32 connection_id)
140{
141 async_certificate_requested(connection_id);
142}
143
144}