WebSocket.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. /*
  2. * Copyright (c) 2021, Dex♪ <dexes.ttp@gmail.com>
  3. * Copyright (c) 2022, the SerenityOS developers.
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <AK/Base64.h>
  8. #include <AK/Random.h>
  9. #include <LibCrypto/Hash/HashManager.h>
  10. #include <LibWebSocket/Impl/WebSocketImplSerenity.h>
  11. #include <LibWebSocket/WebSocket.h>
  12. #include <unistd.h>
  13. namespace WebSocket {
  14. // Note : The websocket protocol is defined by RFC 6455, found at https://tools.ietf.org/html/rfc6455
  15. // In this file, section numbers will refer to the RFC 6455
  16. NonnullRefPtr<WebSocket> WebSocket::create(ConnectionInfo connection, RefPtr<WebSocketImpl> impl)
  17. {
  18. return adopt_ref(*new WebSocket(move(connection), move(impl)));
  19. }
  20. WebSocket::WebSocket(ConnectionInfo connection, RefPtr<WebSocketImpl> impl)
  21. : m_connection(move(connection))
  22. , m_impl(move(impl))
  23. {
  24. }
  25. void WebSocket::start()
  26. {
  27. VERIFY(m_state == WebSocket::InternalState::NotStarted);
  28. if (!m_impl)
  29. m_impl = adopt_ref(*new WebSocketImplSerenity);
  30. m_impl->on_connection_error = [this] {
  31. dbgln("WebSocket: Connection error (underlying socket)");
  32. fatal_error(WebSocket::Error::CouldNotEstablishConnection);
  33. };
  34. m_impl->on_connected = [this] {
  35. if (m_state != WebSocket::InternalState::EstablishingProtocolConnection)
  36. return;
  37. m_state = WebSocket::InternalState::SendingClientHandshake;
  38. send_client_handshake();
  39. drain_read();
  40. };
  41. m_impl->on_ready_to_read = [this] {
  42. drain_read();
  43. };
  44. m_state = WebSocket::InternalState::EstablishingProtocolConnection;
  45. m_impl->connect(m_connection);
  46. }
  47. ReadyState WebSocket::ready_state()
  48. {
  49. switch (m_state) {
  50. case WebSocket::InternalState::NotStarted:
  51. case WebSocket::InternalState::EstablishingProtocolConnection:
  52. case WebSocket::InternalState::SendingClientHandshake:
  53. case WebSocket::InternalState::WaitingForServerHandshake:
  54. return ReadyState::Connecting;
  55. case WebSocket::InternalState::Open:
  56. return ReadyState::Open;
  57. case WebSocket::InternalState::Closing:
  58. return ReadyState::Closing;
  59. case WebSocket::InternalState::Closed:
  60. case WebSocket::InternalState::Errored:
  61. return ReadyState::Closed;
  62. default:
  63. VERIFY_NOT_REACHED();
  64. return ReadyState::Closed;
  65. }
  66. }
  67. ByteString WebSocket::subprotocol_in_use()
  68. {
  69. return m_subprotocol_in_use;
  70. }
  71. void WebSocket::send(Message const& message)
  72. {
  73. // Calling send on a socket that is not opened is not allowed
  74. VERIFY(m_state == WebSocket::InternalState::Open);
  75. VERIFY(m_impl);
  76. if (message.is_text())
  77. send_frame(WebSocket::OpCode::Text, message.data(), true);
  78. else
  79. send_frame(WebSocket::OpCode::Binary, message.data(), true);
  80. }
  81. void WebSocket::close(u16 code, ByteString const& message)
  82. {
  83. VERIFY(m_impl);
  84. switch (m_state) {
  85. case InternalState::NotStarted:
  86. case InternalState::EstablishingProtocolConnection:
  87. case InternalState::SendingClientHandshake:
  88. case InternalState::WaitingForServerHandshake:
  89. // FIXME: Fail the connection.
  90. m_state = InternalState::Closing;
  91. break;
  92. case InternalState::Open: {
  93. auto message_bytes = message.bytes();
  94. auto close_payload = ByteBuffer::create_uninitialized(message_bytes.size() + 2).release_value_but_fixme_should_propagate_errors(); // FIXME: Handle possible OOM situation.
  95. close_payload.overwrite(0, (u8*)&code, 2);
  96. close_payload.overwrite(2, message_bytes.data(), message_bytes.size());
  97. send_frame(WebSocket::OpCode::ConnectionClose, close_payload, true);
  98. m_state = InternalState::Closing;
  99. break;
  100. }
  101. default:
  102. break;
  103. }
  104. }
  105. void WebSocket::drain_read()
  106. {
  107. if (m_impl->eof()) {
  108. // The connection got closed by the server
  109. m_state = WebSocket::InternalState::Closed;
  110. notify_close(m_last_close_code, m_last_close_message, true);
  111. discard_connection();
  112. return;
  113. }
  114. switch (m_state) {
  115. case InternalState::NotStarted:
  116. case InternalState::EstablishingProtocolConnection:
  117. case InternalState::SendingClientHandshake: {
  118. auto initializing_bytes = m_impl->read(1024);
  119. if (!initializing_bytes.is_error())
  120. dbgln("drain_read() was called on a websocket that isn't opened yet. Read {} bytes from the socket.", initializing_bytes.value().size());
  121. } break;
  122. case InternalState::WaitingForServerHandshake: {
  123. read_server_handshake();
  124. } break;
  125. case InternalState::Open:
  126. case InternalState::Closing: {
  127. auto result = m_impl->read(65536);
  128. if (result.is_error()) {
  129. fatal_error(WebSocket::Error::ServerClosedSocket);
  130. return;
  131. }
  132. auto bytes = result.release_value();
  133. m_buffered_data.append(bytes.data(), bytes.size());
  134. read_frame();
  135. } break;
  136. case InternalState::Closed:
  137. case InternalState::Errored: {
  138. auto closed_bytes = m_impl->read(1024);
  139. if (!closed_bytes.is_error())
  140. dbgln("drain_read() was called on a closed websocket. Read {} bytes from the socket.", closed_bytes.value().size());
  141. } break;
  142. default:
  143. VERIFY_NOT_REACHED();
  144. }
  145. }
  146. // The client handshake message is defined in the second list of section 4.1
  147. void WebSocket::send_client_handshake()
  148. {
  149. VERIFY(m_impl);
  150. VERIFY(m_state == WebSocket::InternalState::SendingClientHandshake);
  151. StringBuilder builder;
  152. // 2. and 3. GET /resource name/ HTTP 1.1
  153. builder.appendff("GET {} HTTP/1.1\r\n", m_connection.resource_name());
  154. // 4. Host
  155. auto url = m_connection.url();
  156. builder.appendff("Host: {}", url.serialized_host().release_value_but_fixme_should_propagate_errors());
  157. if (!m_connection.is_secure() && url.port_or_default() != 80)
  158. builder.appendff(":{}", url.port_or_default());
  159. else if (m_connection.is_secure() && url.port_or_default() != 443)
  160. builder.appendff(":{}", url.port_or_default());
  161. builder.append("\r\n"sv);
  162. // 5. and 6. Connection Upgrade
  163. builder.append("Upgrade: websocket\r\n"sv);
  164. builder.append("Connection: Upgrade\r\n"sv);
  165. // 7. 16-byte nonce encoded as Base64
  166. u8 nonce_data[16];
  167. fill_with_random(nonce_data);
  168. // FIXME: change to TRY() and make method fallible
  169. m_websocket_key = MUST(encode_base64({ nonce_data, 16 })).to_byte_string();
  170. builder.appendff("Sec-WebSocket-Key: {}\r\n", m_websocket_key);
  171. // 8. Origin (optional field)
  172. if (!m_connection.origin().is_empty()) {
  173. builder.appendff("Origin: {}\r\n", m_connection.origin());
  174. }
  175. // 9. Websocket version
  176. builder.append("Sec-WebSocket-Version: 13\r\n"sv);
  177. // 10. Websocket protocol (optional field)
  178. if (!m_connection.protocols().is_empty()) {
  179. builder.append("Sec-WebSocket-Protocol: "sv);
  180. builder.join(',', m_connection.protocols());
  181. builder.append("\r\n"sv);
  182. }
  183. // 11. Websocket extensions (optional field)
  184. if (!m_connection.extensions().is_empty()) {
  185. builder.append("Sec-WebSocket-Extensions: "sv);
  186. builder.join(',', m_connection.extensions());
  187. builder.append("\r\n"sv);
  188. }
  189. // 12. Additional headers
  190. for (auto& header : m_connection.headers()) {
  191. builder.appendff("{}: {}\r\n", header.name, header.value);
  192. }
  193. builder.append("\r\n"sv);
  194. m_state = WebSocket::InternalState::WaitingForServerHandshake;
  195. auto success = m_impl->send(builder.string_view().bytes());
  196. VERIFY(success);
  197. }
  198. // The server handshake message is defined in the third list of section 4.1
  199. void WebSocket::read_server_handshake()
  200. {
  201. VERIFY(m_impl);
  202. VERIFY(m_state == WebSocket::InternalState::WaitingForServerHandshake);
  203. // Read the server handshake
  204. if (!m_impl->can_read_line())
  205. return;
  206. if (!m_has_read_server_handshake_first_line) {
  207. auto header = m_impl->read_line(PAGE_SIZE).release_value_but_fixme_should_propagate_errors();
  208. auto parts = header.split(' ');
  209. if (parts.size() < 2) {
  210. dbgln("WebSocket: Server HTTP Handshake contained HTTP header was malformed");
  211. fatal_error(WebSocket::Error::ConnectionUpgradeFailed);
  212. discard_connection();
  213. return;
  214. }
  215. if (parts[0] != "HTTP/1.1") {
  216. dbgln("WebSocket: Server HTTP Handshake contained HTTP header {} which isn't supported", parts[0]);
  217. fatal_error(WebSocket::Error::ConnectionUpgradeFailed);
  218. discard_connection();
  219. return;
  220. }
  221. if (parts[1] != "101") {
  222. // 1. If the status code is not 101, handle as per HTTP procedures.
  223. // FIXME : This could be a redirect or a 401 authentication request, which we do not handle.
  224. dbgln("WebSocket: Server HTTP Handshake return status {} which isn't supported", parts[1]);
  225. fatal_error(WebSocket::Error::ConnectionUpgradeFailed);
  226. return;
  227. }
  228. m_has_read_server_handshake_first_line = true;
  229. }
  230. // Read the rest of the reply until we find an empty line
  231. while (m_impl->can_read_line()) {
  232. auto line = m_impl->read_line(PAGE_SIZE).release_value_but_fixme_should_propagate_errors();
  233. if (line.is_whitespace()) {
  234. // We're done with the HTTP headers.
  235. // Fail the connection if we're missing any of the following:
  236. if (!m_has_read_server_handshake_upgrade) {
  237. // 2. |Upgrade| should be present
  238. dbgln("WebSocket: Server HTTP Handshake didn't contain an |Upgrade| header");
  239. fatal_error(WebSocket::Error::ConnectionUpgradeFailed);
  240. return;
  241. }
  242. if (!m_has_read_server_handshake_connection) {
  243. // 2. |Connection| should be present
  244. dbgln("WebSocket: Server HTTP Handshake didn't contain a |Connection| header");
  245. fatal_error(WebSocket::Error::ConnectionUpgradeFailed);
  246. return;
  247. }
  248. if (!m_has_read_server_handshake_accept) {
  249. // 2. |Sec-WebSocket-Accept| should be present
  250. dbgln("WebSocket: Server HTTP Handshake didn't contain a |Sec-WebSocket-Accept| header");
  251. fatal_error(WebSocket::Error::ConnectionUpgradeFailed);
  252. return;
  253. }
  254. m_state = WebSocket::InternalState::Open;
  255. notify_open();
  256. return;
  257. }
  258. auto parts = line.split(':');
  259. if (parts.size() < 2) {
  260. // The header field is not valid
  261. dbgln("WebSocket: Got invalid header line {} in the Server HTTP handshake", line);
  262. fatal_error(WebSocket::Error::ConnectionUpgradeFailed);
  263. return;
  264. }
  265. auto header_name = parts[0];
  266. if (header_name.equals_ignoring_ascii_case("Upgrade"sv)) {
  267. // 2. |Upgrade| should be case-insensitive "websocket"
  268. if (!parts[1].trim_whitespace().equals_ignoring_ascii_case("websocket"sv)) {
  269. dbgln("WebSocket: Server HTTP Handshake Header |Upgrade| should be 'websocket', got '{}'. Failing connection.", parts[1]);
  270. fatal_error(WebSocket::Error::ConnectionUpgradeFailed);
  271. return;
  272. }
  273. m_has_read_server_handshake_upgrade = true;
  274. continue;
  275. }
  276. if (header_name.equals_ignoring_ascii_case("Connection"sv)) {
  277. // 3. |Connection| should be case-insensitive "Upgrade"
  278. if (!parts[1].trim_whitespace().equals_ignoring_ascii_case("Upgrade"sv)) {
  279. dbgln("WebSocket: Server HTTP Handshake Header |Connection| should be 'Upgrade', got '{}'. Failing connection.", parts[1]);
  280. return;
  281. }
  282. m_has_read_server_handshake_connection = true;
  283. continue;
  284. }
  285. if (header_name.equals_ignoring_ascii_case("Sec-WebSocket-Accept"sv)) {
  286. // 4. |Sec-WebSocket-Accept| should be base64(SHA1(|Sec-WebSocket-Key| + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"))
  287. auto expected_content = ByteString::formatted("{}258EAFA5-E914-47DA-95CA-C5AB0DC85B11", m_websocket_key);
  288. Crypto::Hash::Manager hash;
  289. hash.initialize(Crypto::Hash::HashKind::SHA1);
  290. hash.update(expected_content);
  291. auto expected_sha1 = hash.digest();
  292. // FIXME: change to TRY() and make method fallible
  293. auto expected_sha1_string = MUST(encode_base64({ expected_sha1.immutable_data(), expected_sha1.data_length() }));
  294. if (!parts[1].trim_whitespace().equals_ignoring_ascii_case(expected_sha1_string)) {
  295. dbgln("WebSocket: Server HTTP Handshake Header |Sec-Websocket-Accept| should be '{}', got '{}'. Failing connection.", expected_sha1_string, parts[1]);
  296. fatal_error(WebSocket::Error::ConnectionUpgradeFailed);
  297. return;
  298. }
  299. m_has_read_server_handshake_accept = true;
  300. continue;
  301. }
  302. if (header_name.equals_ignoring_ascii_case("Sec-WebSocket-Extensions"sv)) {
  303. // 5. |Sec-WebSocket-Extensions| should not contain an extension that doesn't appear in m_connection->extensions()
  304. auto server_extensions = parts[1].split(',');
  305. for (auto const& extension : server_extensions) {
  306. auto trimmed_extension = extension.trim_whitespace();
  307. bool found_extension = false;
  308. for (auto const& supported_extension : m_connection.extensions()) {
  309. if (trimmed_extension.equals_ignoring_ascii_case(supported_extension)) {
  310. found_extension = true;
  311. }
  312. }
  313. if (!found_extension) {
  314. dbgln("WebSocket: Server HTTP Handshake Header |Sec-WebSocket-Extensions| contains '{}', which is not supported by the client. Failing connection.", trimmed_extension);
  315. fatal_error(WebSocket::Error::ConnectionUpgradeFailed);
  316. return;
  317. }
  318. }
  319. continue;
  320. }
  321. if (header_name.equals_ignoring_ascii_case("Sec-WebSocket-Protocol"sv)) {
  322. // 6. If the response includes a |Sec-WebSocket-Protocol| header field and this header field indicates the use of a subprotocol that was not present in the client's handshake (the server has indicated a subprotocol not requested by the client), the client MUST _Fail the WebSocket Connection_.
  323. // Additionally, Section 4.2.2 says this is "Either a single value representing the subprotocol the server is ready to use or null."
  324. auto server_protocol = parts[1].trim_whitespace();
  325. bool found_protocol = false;
  326. for (auto const& supported_protocol : m_connection.protocols()) {
  327. if (server_protocol.equals_ignoring_ascii_case(supported_protocol)) {
  328. found_protocol = true;
  329. }
  330. }
  331. if (!found_protocol) {
  332. dbgln("WebSocket: Server HTTP Handshake Header |Sec-WebSocket-Protocol| contains '{}', which is not supported by the client. Failing connection.", server_protocol);
  333. fatal_error(WebSocket::Error::ConnectionUpgradeFailed);
  334. return;
  335. }
  336. m_subprotocol_in_use = server_protocol;
  337. continue;
  338. }
  339. }
  340. // If needed, we will keep reading the header on the next drain_read call
  341. }
  342. void WebSocket::read_frame()
  343. {
  344. VERIFY(m_impl);
  345. VERIFY(m_state == WebSocket::InternalState::Open || m_state == WebSocket::InternalState::Closing);
  346. size_t cursor = 0;
  347. auto get_buffered_bytes = [&](size_t count) -> ReadonlyBytes {
  348. if (cursor + count > m_buffered_data.size())
  349. return {};
  350. auto bytes = m_buffered_data.span().slice(cursor, count);
  351. cursor += count;
  352. return bytes;
  353. };
  354. auto head_bytes = get_buffered_bytes(2);
  355. if (head_bytes.is_null() || head_bytes.is_empty()) {
  356. // The connection got closed.
  357. m_state = WebSocket::InternalState::Closed;
  358. notify_close(m_last_close_code, m_last_close_message, true);
  359. discard_connection();
  360. return;
  361. }
  362. auto op_code = (WebSocket::OpCode)(head_bytes[0] & 0x0f);
  363. bool is_final_frame = head_bytes[0] & 0x80;
  364. bool is_masked = head_bytes[1] & 0x80;
  365. // Parse the payload length.
  366. size_t payload_length;
  367. auto payload_length_bits = head_bytes[1] & 0x7f;
  368. if (payload_length_bits == 127) {
  369. // A code of 127 means that the next 8 bytes contains the payload length
  370. auto actual_bytes = get_buffered_bytes(8);
  371. if (actual_bytes.is_null())
  372. return;
  373. u64 full_payload_length = (u64)((u64)(actual_bytes[0] & 0xff) << 56)
  374. | (u64)((u64)(actual_bytes[1] & 0xff) << 48)
  375. | (u64)((u64)(actual_bytes[2] & 0xff) << 40)
  376. | (u64)((u64)(actual_bytes[3] & 0xff) << 32)
  377. | (u64)((u64)(actual_bytes[4] & 0xff) << 24)
  378. | (u64)((u64)(actual_bytes[5] & 0xff) << 16)
  379. | (u64)((u64)(actual_bytes[6] & 0xff) << 8)
  380. | (u64)((u64)(actual_bytes[7] & 0xff) << 0);
  381. VERIFY(full_payload_length <= NumericLimits<size_t>::max());
  382. payload_length = (size_t)full_payload_length;
  383. } else if (payload_length_bits == 126) {
  384. // A code of 126 means that the next 2 bytes contains the payload length
  385. auto actual_bytes = get_buffered_bytes(2);
  386. if (actual_bytes.is_null())
  387. return;
  388. payload_length = (size_t)((size_t)(actual_bytes[0] & 0xff) << 8)
  389. | (size_t)((size_t)(actual_bytes[1] & 0xff) << 0);
  390. } else {
  391. payload_length = (size_t)payload_length_bits;
  392. }
  393. // Parse the mask, if it exists.
  394. // Note : this is technically non-conformant with Section 5.1 :
  395. // > A server MUST NOT mask any frames that it sends to the client.
  396. // > A client MUST close a connection if it detects a masked frame.
  397. // > (These rules might be relaxed in a future specification.)
  398. // But because it doesn't cost much, we can support receiving masked frames anyways.
  399. u8 masking_key[4];
  400. if (is_masked) {
  401. auto masking_key_data = get_buffered_bytes(4);
  402. if (masking_key_data.is_null())
  403. return;
  404. masking_key[0] = masking_key_data[0];
  405. masking_key[1] = masking_key_data[1];
  406. masking_key[2] = masking_key_data[2];
  407. masking_key[3] = masking_key_data[3];
  408. }
  409. auto payload = ByteBuffer::create_uninitialized(payload_length).release_value_but_fixme_should_propagate_errors(); // FIXME: Handle possible OOM situation.
  410. u64 read_length = 0;
  411. while (read_length < payload_length) {
  412. auto payload_part = get_buffered_bytes(payload_length - read_length);
  413. if (payload_part.is_null())
  414. return;
  415. // We read at most "actual_length - read" bytes, so this is safe to do.
  416. payload.overwrite(read_length, payload_part.data(), payload_part.size());
  417. read_length += payload_part.size();
  418. }
  419. if (cursor == m_buffered_data.size()) {
  420. m_buffered_data.clear();
  421. } else {
  422. Vector<u8> new_buffered_data;
  423. new_buffered_data.append(m_buffered_data.data() + cursor, m_buffered_data.size() - cursor);
  424. m_buffered_data = move(new_buffered_data);
  425. }
  426. if (is_masked) {
  427. // Unmask the payload
  428. for (size_t i = 0; i < payload.size(); ++i) {
  429. payload[i] = payload[i] ^ (masking_key[i % 4]);
  430. }
  431. }
  432. if (op_code == WebSocket::OpCode::ConnectionClose) {
  433. if (payload.size() > 1) {
  434. m_last_close_code = (((u16)(payload[0] & 0xff) << 8) | ((u16)(payload[1] & 0xff)));
  435. m_last_close_message = ByteString(ReadonlyBytes(payload.offset_pointer(2), payload.size() - 2));
  436. }
  437. m_state = WebSocket::InternalState::Closing;
  438. return;
  439. }
  440. if (op_code == WebSocket::OpCode::Ping) {
  441. // Immediately send a pong frame as a reply, with the given payload.
  442. send_frame(WebSocket::OpCode::Pong, payload, true);
  443. return;
  444. }
  445. if (op_code == WebSocket::OpCode::Pong) {
  446. // We can safely ignore the pong
  447. return;
  448. }
  449. if (!is_final_frame) {
  450. if (op_code != WebSocket::OpCode::Continuation) {
  451. // First fragmented message
  452. m_initial_fragment_opcode = op_code;
  453. }
  454. // First and next fragmented message
  455. m_fragmented_data_buffer.append(payload.data(), payload_length);
  456. return;
  457. }
  458. if (is_final_frame && op_code == WebSocket::OpCode::Continuation) {
  459. // Last fragmented message
  460. m_fragmented_data_buffer.append(payload.data(), payload_length);
  461. op_code = m_initial_fragment_opcode;
  462. payload.clear();
  463. payload.append(m_fragmented_data_buffer.data(), m_fragmented_data_buffer.size());
  464. m_fragmented_data_buffer.clear();
  465. }
  466. if (op_code == WebSocket::OpCode::Text) {
  467. notify_message(Message(payload, true));
  468. return;
  469. }
  470. if (op_code == WebSocket::OpCode::Binary) {
  471. notify_message(Message(payload, false));
  472. return;
  473. }
  474. dbgln("Websocket: Found unknown opcode {}", (u8)op_code);
  475. }
  476. void WebSocket::send_frame(WebSocket::OpCode op_code, ReadonlyBytes payload, bool is_final)
  477. {
  478. VERIFY(m_impl);
  479. VERIFY(m_state == WebSocket::InternalState::Open);
  480. u8 frame_head[1] = { (u8)((is_final ? 0x80 : 0x00) | ((u8)(op_code)&0xf)) };
  481. m_impl->send(ReadonlyBytes(frame_head, 1));
  482. // Section 5.1 : a client MUST mask all frames that it sends to the server
  483. bool has_mask = true;
  484. // FIXME: If the payload has a size > size_t max on a 32-bit platform, we could
  485. // technically stream it via non-final packets. However, the size was already
  486. // truncated earlier in the call stack when stuffing into a ReadonlyBytes
  487. if (payload.size() > NumericLimits<u16>::max()) {
  488. // Send (the 'mask' flag + 127) + the 8-byte payload length
  489. if constexpr (sizeof(size_t) >= 8) {
  490. u8 payload_length[9] = {
  491. (u8)((has_mask ? 0x80 : 0x00) | 127),
  492. (u8)((payload.size() >> 56) & 0xff),
  493. (u8)((payload.size() >> 48) & 0xff),
  494. (u8)((payload.size() >> 40) & 0xff),
  495. (u8)((payload.size() >> 32) & 0xff),
  496. (u8)((payload.size() >> 24) & 0xff),
  497. (u8)((payload.size() >> 16) & 0xff),
  498. (u8)((payload.size() >> 8) & 0xff),
  499. (u8)((payload.size() >> 0) & 0xff),
  500. };
  501. m_impl->send(ReadonlyBytes(payload_length, 9));
  502. } else {
  503. u8 payload_length[9] = {
  504. (u8)((has_mask ? 0x80 : 0x00) | 127),
  505. 0,
  506. 0,
  507. 0,
  508. 0,
  509. (u8)((payload.size() >> 24) & 0xff),
  510. (u8)((payload.size() >> 16) & 0xff),
  511. (u8)((payload.size() >> 8) & 0xff),
  512. (u8)((payload.size() >> 0) & 0xff),
  513. };
  514. m_impl->send(ReadonlyBytes(payload_length, 9));
  515. }
  516. } else if (payload.size() >= 126) {
  517. // Send (the 'mask' flag + 126) + the 2-byte payload length
  518. u8 payload_length[3] = {
  519. (u8)((has_mask ? 0x80 : 0x00) | 126),
  520. (u8)((payload.size() >> 8) & 0xff),
  521. (u8)((payload.size() >> 0) & 0xff),
  522. };
  523. m_impl->send(ReadonlyBytes(payload_length, 3));
  524. } else {
  525. // Send the mask flag + the payload in a single byte
  526. u8 payload_length[1] = {
  527. (u8)((has_mask ? 0x80 : 0x00) | (u8)(payload.size() & 0x7f)),
  528. };
  529. m_impl->send(ReadonlyBytes(payload_length, 1));
  530. }
  531. if (has_mask) {
  532. // Section 10.3 :
  533. // > Clients MUST choose a new masking key for each frame, using an algorithm
  534. // > that cannot be predicted by end applications that provide data
  535. u8 masking_key[4];
  536. fill_with_random(masking_key);
  537. m_impl->send(ReadonlyBytes(masking_key, 4));
  538. // don't try to send empty payload
  539. if (payload.size() == 0)
  540. return;
  541. // Mask the payload
  542. auto buffer_result = ByteBuffer::create_uninitialized(payload.size());
  543. if (!buffer_result.is_error()) {
  544. auto& masked_payload = buffer_result.value();
  545. for (size_t i = 0; i < payload.size(); ++i) {
  546. masked_payload[i] = payload[i] ^ (masking_key[i % 4]);
  547. }
  548. m_impl->send(masked_payload);
  549. }
  550. } else if (payload.size() > 0) {
  551. m_impl->send(payload);
  552. }
  553. }
  554. void WebSocket::fatal_error(WebSocket::Error error)
  555. {
  556. m_state = WebSocket::InternalState::Errored;
  557. notify_error(error);
  558. discard_connection();
  559. }
  560. void WebSocket::discard_connection()
  561. {
  562. deferred_invoke([this] {
  563. VERIFY(m_impl);
  564. m_impl->discard_connection();
  565. m_impl->on_connection_error = nullptr;
  566. m_impl->on_connected = nullptr;
  567. m_impl->on_ready_to_read = nullptr;
  568. m_impl = nullptr;
  569. });
  570. }
  571. void WebSocket::notify_open()
  572. {
  573. if (!on_open)
  574. return;
  575. on_open();
  576. }
  577. void WebSocket::notify_close(u16 code, ByteString reason, bool was_clean)
  578. {
  579. if (!on_close)
  580. return;
  581. on_close(code, move(reason), was_clean);
  582. }
  583. void WebSocket::notify_error(WebSocket::Error error)
  584. {
  585. if (!on_error)
  586. return;
  587. on_error(error);
  588. }
  589. void WebSocket::notify_message(Message message)
  590. {
  591. if (!on_message)
  592. return;
  593. on_message(move(message));
  594. }
  595. }