WebSocket.cpp 23 KB

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