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