diff --git a/Ladybird/WebContent/CMakeLists.txt b/Ladybird/WebContent/CMakeLists.txt index 99d752ddc8..141bc730da 100644 --- a/Ladybird/WebContent/CMakeLists.txt +++ b/Ladybird/WebContent/CMakeLists.txt @@ -13,6 +13,7 @@ set(WEBCONTENT_SOURCES ../Utilities.cpp ../WebSocketClientManagerLadybird.cpp ../WebSocketLadybird.cpp + ../WebSocketImplQt.cpp main.cpp ) diff --git a/Ladybird/WebSocketClientManagerLadybird.cpp b/Ladybird/WebSocketClientManagerLadybird.cpp index e059a73e4a..1a086dfcf6 100644 --- a/Ladybird/WebSocketClientManagerLadybird.cpp +++ b/Ladybird/WebSocketClientManagerLadybird.cpp @@ -6,6 +6,7 @@ */ #include "WebSocketClientManagerLadybird.h" +#include "WebSocketImplQt.h" #include "WebSocketLadybird.h" namespace Ladybird { @@ -23,8 +24,10 @@ RefPtr WebSocketClientManagerLadybird::c WebSocket::ConnectionInfo connection_info(url); connection_info.set_origin(origin); - auto connection = WebSocketLadybird::create(WebSocket::WebSocket::create(move(connection_info))); - return connection; + auto impl = adopt_ref(*new WebSocketImplQt); + auto web_socket = WebSocket::WebSocket::create(move(connection_info), move(impl)); + web_socket->start(); + return WebSocketLadybird::create(web_socket); } } diff --git a/Ladybird/WebSocketImplQt.cpp b/Ladybird/WebSocketImplQt.cpp new file mode 100644 index 0000000000..d3ffa956d6 --- /dev/null +++ b/Ladybird/WebSocketImplQt.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2021, Dex♪ + * Copyright (c) 2022, Ali Mohammad Pur + * Copyright (c) 2022, the SerenityOS developers. + * Copyright (c) 2022, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#define AK_DONT_REPLACE_STD + +#include "WebSocketImplQt.h" +#include "Utilities.h" +#include +#include +#include + +namespace Ladybird { + +WebSocketImplQt::~WebSocketImplQt() = default; +WebSocketImplQt::WebSocketImplQt() = default; + +bool WebSocketImplQt::can_read_line() +{ + return m_socket->canReadLine(); +} + +bool WebSocketImplQt::send(ReadonlyBytes bytes) +{ + auto bytes_written = m_socket->write(reinterpret_cast(bytes.data()), bytes.size()); + if (bytes_written == -1) + return false; + VERIFY(static_cast(bytes_written) == bytes.size()); + return true; +} + +bool WebSocketImplQt::eof() +{ + return m_socket->state() == QTcpSocket::SocketState::UnconnectedState + && !m_socket->bytesAvailable(); +} + +void WebSocketImplQt::discard_connection() +{ + m_socket = nullptr; +} + +void WebSocketImplQt::connect(WebSocket::ConnectionInfo const& connection_info) +{ + VERIFY(!m_socket); + VERIFY(on_connected); + VERIFY(on_connection_error); + VERIFY(on_ready_to_read); + + if (connection_info.is_secure()) { + auto ssl_socket = make(); + ssl_socket->connectToHostEncrypted( + qstring_from_akstring(connection_info.url().host()), + connection_info.url().port_or_default()); + QObject::connect(ssl_socket.ptr(), &QSslSocket::alertReceived, [this](QSsl::AlertLevel level, QSsl::AlertType, QString const&) { + if (level == QSsl::AlertLevel::Fatal) + on_connection_error(); + }); + m_socket = move(ssl_socket); + } else { + m_socket = make(); + m_socket->connectToHost( + qstring_from_akstring(connection_info.url().host()), + connection_info.url().port_or_default()); + } + + QObject::connect(m_socket.ptr(), &QTcpSocket::readyRead, [this] { + on_ready_to_read(); + }); + + QObject::connect(m_socket.ptr(), &QTcpSocket::connected, [this] { + on_connected(); + }); +} + +ErrorOr WebSocketImplQt::read(int max_size) +{ + auto buffer = TRY(ByteBuffer::create_uninitialized(max_size)); + auto bytes_read = m_socket->read(reinterpret_cast(buffer.data()), buffer.size()); + if (bytes_read == -1) + return Error::from_string_literal("WebSocketImplQt::read(): Error reading from socket"); + return buffer.slice(0, bytes_read); +} + +ErrorOr WebSocketImplQt::read_line(size_t size) +{ + auto buffer = TRY(ByteBuffer::create_uninitialized(size)); + auto bytes_read = m_socket->readLine(reinterpret_cast(buffer.data()), buffer.size()); + if (bytes_read == -1) + return Error::from_string_literal("WebSocketImplQt::read_line(): Error reading from socket"); + return String::copy(buffer.span().slice(0, bytes_read)); +} + +} diff --git a/Ladybird/WebSocketImplQt.h b/Ladybird/WebSocketImplQt.h new file mode 100644 index 0000000000..ff0b508cd3 --- /dev/null +++ b/Ladybird/WebSocketImplQt.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021, Dex♪ + * Copyright (c) 2022, Ali Mohammad Pur + * Copyright (c) 2022, the SerenityOS developers. + * Copyright (c) 2022, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +class QTcpSocket; + +namespace Ladybird { + +class WebSocketImplQt final : public WebSocket::WebSocketImpl { +public: + explicit WebSocketImplQt(); + virtual ~WebSocketImplQt() override; + + virtual void connect(WebSocket::ConnectionInfo const&) override; + virtual bool can_read_line() override; + virtual ErrorOr read_line(size_t) override; + virtual ErrorOr read(int max_size) override; + virtual bool send(ReadonlyBytes) override; + virtual bool eof() override; + virtual void discard_connection() override; + +private: + OwnPtr m_socket; +}; + +}