WebSocket.cpp 22 KB

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