Serenity Operating System
1/*
2 * Copyright (c) 2021, Dex♪ <dexes.ttp@gmail.com>
3 * Copyright (c) 2022, Ali Mohammad Pur <mpfard@serenityos.org>
4 * Copyright (c) 2022, the SerenityOS developers.
5 * Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
6 *
7 * SPDX-License-Identifier: BSD-2-Clause
8 */
9
10#define AK_DONT_REPLACE_STD
11
12#include "WebSocketImplQt.h"
13#include "Utilities.h"
14#include <LibCore/EventLoop.h>
15#include <QSslSocket>
16#include <QTcpSocket>
17
18namespace Ladybird {
19
20WebSocketImplQt::~WebSocketImplQt() = default;
21WebSocketImplQt::WebSocketImplQt() = default;
22
23bool WebSocketImplQt::can_read_line()
24{
25 return m_socket->canReadLine();
26}
27
28bool WebSocketImplQt::send(ReadonlyBytes bytes)
29{
30 auto bytes_written = m_socket->write(reinterpret_cast<char const*>(bytes.data()), bytes.size());
31 if (bytes_written == -1)
32 return false;
33 VERIFY(static_cast<size_t>(bytes_written) == bytes.size());
34 return true;
35}
36
37bool WebSocketImplQt::eof()
38{
39 return m_socket->state() == QTcpSocket::SocketState::UnconnectedState
40 && !m_socket->bytesAvailable();
41}
42
43void WebSocketImplQt::discard_connection()
44{
45 m_socket = nullptr;
46}
47
48void WebSocketImplQt::connect(WebSocket::ConnectionInfo const& connection_info)
49{
50 VERIFY(!m_socket);
51 VERIFY(on_connected);
52 VERIFY(on_connection_error);
53 VERIFY(on_ready_to_read);
54
55 if (connection_info.is_secure()) {
56 auto ssl_socket = make<QSslSocket>();
57 ssl_socket->connectToHostEncrypted(
58 qstring_from_ak_deprecated_string(connection_info.url().host()),
59 connection_info.url().port_or_default());
60 QObject::connect(ssl_socket.ptr(), &QSslSocket::alertReceived, [this](QSsl::AlertLevel level, QSsl::AlertType, QString const&) {
61 if (level == QSsl::AlertLevel::Fatal)
62 on_connection_error();
63 });
64 m_socket = move(ssl_socket);
65 } else {
66 m_socket = make<QTcpSocket>();
67 m_socket->connectToHost(
68 qstring_from_ak_deprecated_string(connection_info.url().host()),
69 connection_info.url().port_or_default());
70 }
71
72 QObject::connect(m_socket.ptr(), &QTcpSocket::readyRead, [this] {
73 on_ready_to_read();
74 });
75
76 QObject::connect(m_socket.ptr(), &QTcpSocket::connected, [this] {
77 on_connected();
78 });
79}
80
81ErrorOr<ByteBuffer> WebSocketImplQt::read(int max_size)
82{
83 auto buffer = TRY(ByteBuffer::create_uninitialized(max_size));
84 auto bytes_read = m_socket->read(reinterpret_cast<char*>(buffer.data()), buffer.size());
85 if (bytes_read == -1)
86 return Error::from_string_literal("WebSocketImplQt::read(): Error reading from socket");
87 return buffer.slice(0, bytes_read);
88}
89
90ErrorOr<DeprecatedString> WebSocketImplQt::read_line(size_t size)
91{
92 auto buffer = TRY(ByteBuffer::create_uninitialized(size));
93 auto bytes_read = m_socket->readLine(reinterpret_cast<char*>(buffer.data()), buffer.size());
94 if (bytes_read == -1)
95 return Error::from_string_literal("WebSocketImplQt::read_line(): Error reading from socket");
96 return DeprecatedString::copy(buffer.span().slice(0, bytes_read));
97}
98
99}