/* * Copyright (c) 2021, The SerenityOS developers. * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include namespace WebSocket { enum class ReadyState { Connecting = 0, Open = 1, Closing = 2, Closed = 3, }; class WebSocket final : public Core::Object { C_OBJECT(WebSocket) public: static NonnullRefPtr create(ConnectionInfo); virtual ~WebSocket() override; URL const& url() const { return m_connection.url(); } ReadyState ready_state(); // Call this to start the WebSocket connection. void start(); // This can only be used if the `ready_state` is `ReadyState::Open` void send(Message); // This can only be used if the `ready_state` is `ReadyState::Open` void close(u16 code = 1005, String reason = {}); Function on_open; Function on_close; Function on_message; enum class Error { CouldNotEstablishConnection, ConnectionUpgradeFailed, ServerClosedSocket, }; Function on_error; private: explicit WebSocket(ConnectionInfo); // As defined in section 5.2 enum class OpCode : u8 { Continuation = 0x0, Text = 0x1, Binary = 0x2, ConnectionClose = 0x8, Ping = 0x9, Pong = 0xA, }; void drain_read(); void send_client_handshake(); void read_server_handshake(); void read_frame(); void send_frame(OpCode, ReadonlyBytes, bool is_final); void notify_open(); void notify_close(u16 code, String reason, bool was_clean); void notify_error(Error); void notify_message(Message); void fatal_error(Error); void discard_connection(); enum class InternalState { NotStarted, EstablishingProtocolConnection, SendingClientHandshake, WaitingForServerHandshake, Open, Closing, Closed, Errored, }; InternalState m_state { InternalState::NotStarted }; String m_websocket_key; bool m_has_read_server_handshake_first_line { false }; bool m_has_read_server_handshake_upgrade { false }; bool m_has_read_server_handshake_connection { false }; bool m_has_read_server_handshake_accept { false }; u16 m_last_close_code { 1005 }; String m_last_close_message; ConnectionInfo m_connection; RefPtr m_impl; }; }