Everywhere: Merge the WebSocket service into RequestServer
This keeps the APIs separate as they are wildly different, a future improvement could be to somehow unify the APIs (if possible). Closes #23080.
This commit is contained in:
parent
daf5484d6b
commit
6dfb2f9dc8
Notes:
sideshowbarker
2024-07-17 02:57:43 +09:00
Author: https://github.com/alimpfard Commit: https://github.com/SerenityOS/serenity/commit/6dfb2f9dc8 Pull-request: https://github.com/SerenityOS/serenity/pull/23485 Issue: https://github.com/SerenityOS/serenity/issues/23080 Reviewed-by: https://github.com/ADKaster
56 changed files with 231 additions and 845 deletions
|
@ -56,11 +56,6 @@
|
|||
android:enabled="true"
|
||||
android:exported="false"
|
||||
android:process=":RequestServer" />
|
||||
<service
|
||||
android:name=".WebSocketService"
|
||||
android:enabled="true"
|
||||
android:exported="false"
|
||||
android:process=":WebSocket" />
|
||||
<service
|
||||
android:name=".ImageDecoderService"
|
||||
android:enabled="true"
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#include <LibWeb/Platform/AudioCodecPluginAgnostic.h>
|
||||
#include <LibWeb/Platform/EventLoopPluginSerenity.h>
|
||||
#include <LibWebView/RequestServerAdapter.h>
|
||||
#include <LibWebView/WebSocketClientAdapter.h>
|
||||
#include <WebContent/ConnectionFromClient.h>
|
||||
#include <WebContent/PageHost.h>
|
||||
|
||||
|
@ -37,11 +36,6 @@ static ErrorOr<NonnullRefPtr<Protocol::RequestClient>> bind_request_server_servi
|
|||
return bind_service<Protocol::RequestClient>(&bind_request_server_java);
|
||||
}
|
||||
|
||||
static ErrorOr<NonnullRefPtr<Protocol::WebSocketClient>> bind_web_socket_service()
|
||||
{
|
||||
return bind_service<Protocol::WebSocketClient>(&bind_web_socket_java);
|
||||
}
|
||||
|
||||
template ErrorOr<NonnullRefPtr<ImageDecoderClient::Client>, Error>
|
||||
bind_service<ImageDecoderClient::Client>(void (*)(int, int));
|
||||
|
||||
|
@ -64,9 +58,6 @@ ErrorOr<int> service_main(int ipc_socket, int fd_passing_socket)
|
|||
auto request_server_client = TRY(bind_request_server_service());
|
||||
Web::ResourceLoader::initialize(TRY(WebView::RequestServerAdapter::try_create(move(request_server_client))));
|
||||
|
||||
auto web_socket_client = TRY(bind_web_socket_service());
|
||||
Web::WebSockets::WebSocketClientManager::initialize(TRY(WebView::WebSocketClientManagerAdapter::try_create(move(web_socket_client))));
|
||||
|
||||
bool is_layout_test_mode = false;
|
||||
|
||||
Web::HTML::Window::set_internals_object_exposed(is_layout_test_mode);
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
jobject global_instance;
|
||||
jclass global_class_reference;
|
||||
jmethodID bind_request_server_method;
|
||||
jmethodID bind_web_socket_method;
|
||||
jmethodID bind_image_decoder_method;
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
|
@ -30,11 +29,6 @@ Java_org_serenityos_ladybird_WebContentService_nativeInit(JNIEnv* env, jobject t
|
|||
TODO();
|
||||
bind_request_server_method = method;
|
||||
|
||||
method = env->GetMethodID(global_class_reference, "bindWebSocket", "(II)V");
|
||||
if (!method)
|
||||
TODO();
|
||||
bind_web_socket_method = method;
|
||||
|
||||
method = env->GetMethodID(global_class_reference, "bindImageDecoder", "(II)V");
|
||||
if (!method)
|
||||
TODO();
|
||||
|
@ -47,12 +41,6 @@ void bind_request_server_java(int ipc_socket, int fd_passing_socket)
|
|||
env.get()->CallVoidMethod(global_instance, bind_request_server_method, ipc_socket, fd_passing_socket);
|
||||
}
|
||||
|
||||
void bind_web_socket_java(int ipc_socket, int fd_passing_socket)
|
||||
{
|
||||
Ladybird::JavaEnvironment env(global_vm);
|
||||
env.get()->CallVoidMethod(global_instance, bind_web_socket_method, ipc_socket, fd_passing_socket);
|
||||
}
|
||||
|
||||
void bind_image_decoder_java(int ipc_socket, int fd_passing_socket)
|
||||
{
|
||||
Ladybird::JavaEnvironment env(global_vm);
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Dex♪ <dexes.ttp@gmail.com>
|
||||
* Copyright (c) 2023, Andrew Kaster <akaster@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/LexicalPath.h>
|
||||
#include <Ladybird/Utilities.h>
|
||||
#include <LibCore/ArgsParser.h>
|
||||
#include <LibCore/EventLoop.h>
|
||||
#include <LibCore/LocalServer.h>
|
||||
#include <LibCore/System.h>
|
||||
#include <LibFileSystem/FileSystem.h>
|
||||
#include <LibIPC/SingleServer.h>
|
||||
#include <LibTLS/Certificate.h>
|
||||
#include <WebSocket/ConnectionFromClient.h>
|
||||
|
||||
// FIXME: Share b/w RequestServer and WebSocket
|
||||
ErrorOr<ByteString> find_certificates(StringView serenity_resource_root)
|
||||
{
|
||||
auto cert_path = ByteString::formatted("{}/ladybird/cacert.pem", serenity_resource_root);
|
||||
if (!FileSystem::exists(cert_path))
|
||||
return Error::from_string_view("Don't know how to load certs!"sv);
|
||||
return cert_path;
|
||||
}
|
||||
|
||||
ErrorOr<int> service_main(int ipc_socket, int fd_passing_socket)
|
||||
{
|
||||
// Ensure the certificates are read out here.
|
||||
DefaultRootCACertificates::set_default_certificate_paths(Vector { TRY(find_certificates(s_serenity_resource_root)) });
|
||||
[[maybe_unused]] auto& certs = DefaultRootCACertificates::the();
|
||||
|
||||
Core::EventLoop event_loop;
|
||||
|
||||
auto socket = TRY(Core::LocalSocket::adopt_fd(ipc_socket));
|
||||
auto client = TRY(WebSocket::ConnectionFromClient::try_create(move(socket)));
|
||||
client->set_fd_passing_socket(TRY(Core::LocalSocket::adopt_fd(fd_passing_socket)));
|
||||
|
||||
return event_loop.exec();
|
||||
}
|
|
@ -35,21 +35,6 @@ class WebContentService : LadybirdServiceBase("WebContentService") {
|
|||
)
|
||||
}
|
||||
|
||||
private fun bindWebSocket(ipcFd: Int, fdPassingFd: Int)
|
||||
{
|
||||
val connector = LadybirdServiceConnection(ipcFd, fdPassingFd, resourceDir)
|
||||
connector.onDisconnect = {
|
||||
// FIXME: Notify impl that service is dead and might need restarted
|
||||
Log.e(TAG, "WebSocket Died! :(")
|
||||
}
|
||||
// FIXME: Unbind this at some point maybe
|
||||
bindService(
|
||||
Intent(this, WebSocketService::class.java),
|
||||
connector,
|
||||
Context.BIND_AUTO_CREATE
|
||||
)
|
||||
}
|
||||
|
||||
private fun bindImageDecoder(ipcFd: Int, fdPassingFd: Int)
|
||||
{
|
||||
val connector = LadybirdServiceConnection(ipcFd, fdPassingFd, resourceDir)
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2023, Andrew Kaster <akaster@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
package org.serenityos.ladybird
|
||||
|
||||
import android.os.Message
|
||||
|
||||
class WebSocketService : LadybirdServiceBase("WebSocketService") {
|
||||
override fun handleServiceSpecificMessage(msg: Message): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
companion object {
|
||||
init {
|
||||
System.loadLibrary("websocket")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -226,10 +226,9 @@ add_subdirectory(RequestServer)
|
|||
add_subdirectory(SQLServer)
|
||||
add_subdirectory(WebContent)
|
||||
add_subdirectory(WebDriver)
|
||||
add_subdirectory(WebSocket)
|
||||
add_subdirectory(WebWorker)
|
||||
|
||||
set(ladybird_helper_processes ImageDecoder RequestServer SQLServer WebContent WebDriver WebSocketServer WebWorker headless-browser)
|
||||
set(ladybird_helper_processes ImageDecoder RequestServer SQLServer WebContent WebDriver WebWorker headless-browser)
|
||||
add_dependencies(ladybird ${ladybird_helper_processes})
|
||||
|
||||
function(create_ladybird_bundle target_name)
|
||||
|
|
|
@ -178,8 +178,3 @@ ErrorOr<NonnullRefPtr<Protocol::RequestClient>> launch_request_server_process(Re
|
|||
{
|
||||
return launch_generic_server_process<Protocol::RequestClient>(candidate_request_server_paths, serenity_resource_root, certificates, "RequestServer"sv);
|
||||
}
|
||||
|
||||
ErrorOr<NonnullRefPtr<Protocol::WebSocketClient>> launch_web_socket_process(ReadonlySpan<ByteString> candidate_web_socket_paths, StringView serenity_resource_root, Vector<ByteString> const& certificates)
|
||||
{
|
||||
return launch_generic_server_process<Protocol::WebSocketClient>(candidate_web_socket_paths, serenity_resource_root, certificates, "WebSocket"sv);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include <AK/StringView.h>
|
||||
#include <LibImageDecoderClient/Client.h>
|
||||
#include <LibProtocol/RequestClient.h>
|
||||
#include <LibProtocol/WebSocketClient.h>
|
||||
#include <LibWeb/Worker/WebWorkerClient.h>
|
||||
#include <LibWebView/ViewImplementation.h>
|
||||
#include <LibWebView/WebContentClient.h>
|
||||
|
@ -25,4 +24,3 @@ ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_web_content_process(
|
|||
ErrorOr<NonnullRefPtr<ImageDecoderClient::Client>> launch_image_decoder_process(ReadonlySpan<ByteString> candidate_image_decoder_paths);
|
||||
ErrorOr<NonnullRefPtr<Web::HTML::WebWorkerClient>> launch_web_worker_process(ReadonlySpan<ByteString> candidate_web_worker_paths, Vector<ByteString> const& certificates);
|
||||
ErrorOr<NonnullRefPtr<Protocol::RequestClient>> launch_request_server_process(ReadonlySpan<ByteString> candidate_request_server_paths, StringView serenity_resource_root, Vector<ByteString> const& certificates);
|
||||
ErrorOr<NonnullRefPtr<Protocol::WebSocketClient>> launch_web_socket_process(ReadonlySpan<ByteString> candidate_web_socket_paths, StringView serenity_resource_root, Vector<ByteString> const& certificates);
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
*/
|
||||
|
||||
#include "RequestManagerQt.h"
|
||||
#include "WebSocketImplQt.h"
|
||||
#include "WebSocketQt.h"
|
||||
#include <AK/JsonObject.h>
|
||||
#include <QNetworkCookie>
|
||||
|
||||
|
@ -76,6 +78,18 @@ ErrorOr<NonnullRefPtr<RequestManagerQt::Request>> RequestManagerQt::Request::cre
|
|||
return adopt_ref(*new Request(*reply));
|
||||
}
|
||||
|
||||
RefPtr<Web::WebSockets::WebSocketClientSocket> RequestManagerQt::websocket_connect(AK::URL const& url, AK::ByteString const& origin, Vector<AK::ByteString> const& protocols)
|
||||
{
|
||||
WebSocket::ConnectionInfo connection_info(url);
|
||||
connection_info.set_origin(origin);
|
||||
connection_info.set_protocols(protocols);
|
||||
|
||||
auto impl = adopt_ref(*new WebSocketImplQt);
|
||||
auto web_socket = WebSocket::WebSocket::create(move(connection_info), move(impl));
|
||||
web_socket->start();
|
||||
return WebSocketQt::create(web_socket);
|
||||
}
|
||||
|
||||
RequestManagerQt::Request::Request(QNetworkReply& reply)
|
||||
: m_reply(reply)
|
||||
{
|
||||
|
|
|
@ -28,6 +28,7 @@ public:
|
|||
virtual void preconnect(URL const&) override { }
|
||||
|
||||
virtual RefPtr<Web::ResourceLoaderConnectorRequest> start_request(ByteString const& method, URL const&, HashMap<ByteString, ByteString> const& request_headers, ReadonlyBytes request_body, Core::ProxyData const&) override;
|
||||
virtual RefPtr<Web::WebSockets::WebSocketClientSocket> websocket_connect(const URL&, ByteString const& origin, Vector<ByteString> const& protocols) override;
|
||||
|
||||
private slots:
|
||||
void reply_finished(QNetworkReply*);
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Dex♪ <dexes.ttp@gmail.com>
|
||||
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "WebSocketClientManagerQt.h"
|
||||
#include "WebSocketImplQt.h"
|
||||
#include "WebSocketQt.h"
|
||||
|
||||
namespace Ladybird {
|
||||
|
||||
NonnullRefPtr<WebSocketClientManagerQt> WebSocketClientManagerQt::create()
|
||||
{
|
||||
return adopt_ref(*new WebSocketClientManagerQt());
|
||||
}
|
||||
|
||||
WebSocketClientManagerQt::WebSocketClientManagerQt() = default;
|
||||
WebSocketClientManagerQt::~WebSocketClientManagerQt() = default;
|
||||
|
||||
RefPtr<Web::WebSockets::WebSocketClientSocket> WebSocketClientManagerQt::connect(URL const& url, ByteString const& origin, Vector<ByteString> const& protocols)
|
||||
{
|
||||
WebSocket::ConnectionInfo connection_info(url);
|
||||
connection_info.set_origin(origin);
|
||||
connection_info.set_protocols(protocols);
|
||||
|
||||
auto impl = adopt_ref(*new WebSocketImplQt);
|
||||
auto web_socket = WebSocket::WebSocket::create(move(connection_info), move(impl));
|
||||
web_socket->start();
|
||||
return WebSocketQt::create(web_socket);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2022, Dex♪ <dexes.ttp@gmail.com>
|
||||
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibWeb/WebSockets/WebSocket.h>
|
||||
#include <LibWebSocket/ConnectionInfo.h>
|
||||
#include <LibWebSocket/Message.h>
|
||||
#include <LibWebSocket/WebSocket.h>
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Ladybird {
|
||||
|
||||
class WebSocketClientManagerQt : public Web::WebSockets::WebSocketClientManager {
|
||||
public:
|
||||
static NonnullRefPtr<WebSocketClientManagerQt> create();
|
||||
|
||||
virtual ~WebSocketClientManagerQt() override;
|
||||
virtual RefPtr<Web::WebSockets::WebSocketClientSocket> connect(URL const&, ByteString const& origin, Vector<ByteString> const& protocols) override;
|
||||
|
||||
private:
|
||||
WebSocketClientManagerQt();
|
||||
};
|
||||
|
||||
}
|
|
@ -33,7 +33,7 @@ target_link_libraries(RequestServer PRIVATE requestserver)
|
|||
|
||||
target_include_directories(requestserver PRIVATE ${SERENITY_SOURCE_DIR}/Userland/Services/)
|
||||
target_include_directories(requestserver PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/..)
|
||||
target_link_libraries(requestserver PUBLIC LibCore LibMain LibCrypto LibFileSystem LibGemini LibHTTP LibIPC LibMain LibTLS LibWebView)
|
||||
target_link_libraries(requestserver PUBLIC LibCore LibMain LibCrypto LibFileSystem LibGemini LibHTTP LibIPC LibMain LibTLS LibWebView LibWebSocket)
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
|
||||
# Solaris has socket and networking related functions in two extra libraries
|
||||
target_link_libraries(requestserver PUBLIC nsl socket)
|
||||
|
|
|
@ -21,7 +21,6 @@ if (ENABLE_QT)
|
|||
../Qt/EventLoopImplementationQtEventTarget.cpp
|
||||
../Qt/RequestManagerQt.cpp
|
||||
../Qt/StringUtils.cpp
|
||||
../Qt/WebSocketClientManagerQt.cpp
|
||||
../Qt/WebSocketQt.cpp
|
||||
../Qt/WebSocketImplQt.cpp
|
||||
main.cpp
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
#if defined(HAVE_QT)
|
||||
# include <Ladybird/Qt/EventLoopImplementationQt.h>
|
||||
# include <Ladybird/Qt/RequestManagerQt.h>
|
||||
# include <Ladybird/Qt/WebSocketClientManagerQt.h>
|
||||
# include <QCoreApplication>
|
||||
|
||||
# if defined(HAVE_QT_MULTIMEDIA)
|
||||
|
@ -109,14 +108,11 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
}
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
if (!use_lagom_networking) {
|
||||
if (!use_lagom_networking)
|
||||
Web::ResourceLoader::initialize(Ladybird::RequestManagerQt::create());
|
||||
Web::WebSockets::WebSocketClientManager::initialize(Ladybird::WebSocketClientManagerQt::create());
|
||||
} else
|
||||
else
|
||||
#endif
|
||||
{
|
||||
TRY(initialize_lagom_networking(certificates));
|
||||
}
|
||||
|
||||
Web::HTML::Window::set_internals_object_exposed(is_layout_test_mode);
|
||||
|
||||
|
@ -195,9 +191,5 @@ static ErrorOr<void> initialize_lagom_networking(Vector<ByteString> const& certi
|
|||
auto request_server_client = TRY(launch_request_server_process(candidate_request_server_paths, s_serenity_resource_root, certificates));
|
||||
Web::ResourceLoader::initialize(TRY(WebView::RequestServerAdapter::try_create(move(request_server_client))));
|
||||
|
||||
auto candidate_web_socket_paths = TRY(get_paths_for_helper_process("WebSocket"sv));
|
||||
auto web_socket_client = TRY(launch_web_socket_process(candidate_web_socket_paths, s_serenity_resource_root, certificates));
|
||||
Web::WebSockets::WebSocketClientManager::initialize(TRY(WebView::WebSocketClientManagerAdapter::try_create(move(web_socket_client))));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
set(SOURCES
|
||||
"${SERENITY_SOURCE_DIR}/Userland/Services/WebSocket/ConnectionFromClient.cpp"
|
||||
)
|
||||
|
||||
if (ANDROID)
|
||||
add_library(websocket SHARED
|
||||
${SOURCES}
|
||||
../Android/src/main/cpp/WebSocketService.cpp
|
||||
../Android/src/main/cpp/LadybirdServiceBaseJNI.cpp
|
||||
../Utilities.cpp
|
||||
)
|
||||
else()
|
||||
add_library(websocket STATIC ${SOURCES})
|
||||
endif()
|
||||
add_executable(WebSocketServer main.cpp)
|
||||
target_link_libraries(WebSocketServer PRIVATE websocket)
|
||||
set_target_properties(WebSocketServer PROPERTIES OUTPUT_NAME WebSocket)
|
||||
target_link_libraries(websocket PUBLIC LibCore LibFileSystem LibIPC LibMain LibTLS LibWebSocket LibWebView)
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Dex♪ <dexes.ttp@gmail.com>
|
||||
* Copyright (c) 2023, Andrew Kaster <akaster@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/LexicalPath.h>
|
||||
#include <LibCore/ArgsParser.h>
|
||||
#include <LibCore/EventLoop.h>
|
||||
#include <LibCore/LocalServer.h>
|
||||
#include <LibCore/System.h>
|
||||
#include <LibFileSystem/FileSystem.h>
|
||||
#include <LibIPC/SingleServer.h>
|
||||
#include <LibMain/Main.h>
|
||||
#include <LibTLS/Certificate.h>
|
||||
#include <WebSocket/ConnectionFromClient.h>
|
||||
|
||||
// FIXME: Share b/w RequestServer and WebSocket
|
||||
ErrorOr<ByteString> find_certificates(StringView serenity_resource_root)
|
||||
{
|
||||
auto cert_path = ByteString::formatted("{}/ladybird/cacert.pem", serenity_resource_root);
|
||||
if (!FileSystem::exists(cert_path))
|
||||
return Error::from_string_view("Don't know how to load certs!"sv);
|
||||
return cert_path;
|
||||
}
|
||||
|
||||
ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||
{
|
||||
AK::set_rich_debug_enabled(true);
|
||||
|
||||
int fd_passing_socket { -1 };
|
||||
StringView serenity_resource_root;
|
||||
Vector<ByteString> certificates;
|
||||
|
||||
Core::ArgsParser args_parser;
|
||||
args_parser.add_option(fd_passing_socket, "File descriptor of the fd passing socket", "fd-passing-socket", 'c', "fd-passing-socket");
|
||||
args_parser.add_option(certificates, "Path to a certificate file", "certificate", 'C', "certificate");
|
||||
args_parser.add_option(serenity_resource_root, "Absolute path to directory for serenity resources", "serenity-resource-root", 'r', "serenity-resource-root");
|
||||
args_parser.parse(arguments);
|
||||
|
||||
// Ensure the certificates are read out here.
|
||||
if (certificates.is_empty())
|
||||
certificates.append(TRY(find_certificates(serenity_resource_root)));
|
||||
DefaultRootCACertificates::set_default_certificate_paths(certificates.span());
|
||||
[[maybe_unused]] auto& certs = DefaultRootCACertificates::the();
|
||||
|
||||
Core::EventLoop event_loop;
|
||||
|
||||
auto client = TRY(IPC::take_over_accepted_client_from_system_server<WebSocket::ConnectionFromClient>());
|
||||
client->set_fd_passing_socket(TRY(Core::LocalSocket::adopt_fd(fd_passing_socket)));
|
||||
|
||||
return event_loop.exec();
|
||||
}
|
|
@ -67,9 +67,5 @@ static ErrorOr<void> initialize_lagom_networking(Vector<ByteString> const& certi
|
|||
auto request_server_client = TRY(launch_request_server_process(candidate_request_server_paths, s_serenity_resource_root, certificates));
|
||||
Web::ResourceLoader::initialize(TRY(WebView::RequestServerAdapter::try_create(move(request_server_client))));
|
||||
|
||||
auto candidate_web_socket_paths = TRY(get_paths_for_helper_process("WebSocket"sv));
|
||||
auto web_socket_client = TRY(launch_web_socket_process(candidate_web_socket_paths, s_serenity_resource_root, certificates));
|
||||
Web::WebSockets::WebSocketClientManager::initialize(TRY(WebView::WebSocketClientManagerAdapter::try_create(move(web_socket_client))));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -486,8 +486,6 @@ if (BUILD_LAGOM)
|
|||
# These are needed for both LibWeb and LibProtocol.
|
||||
compile_ipc(${SERENITY_PROJECT_ROOT}/Userland/Services/RequestServer/RequestClient.ipc Userland/Services/RequestServer/RequestClientEndpoint.h)
|
||||
compile_ipc(${SERENITY_PROJECT_ROOT}/Userland/Services/RequestServer/RequestServer.ipc Userland/Services/RequestServer/RequestServerEndpoint.h)
|
||||
compile_ipc(${SERENITY_PROJECT_ROOT}/Userland/Services/WebSocket/WebSocketClient.ipc Userland/Services/WebSocket/WebSocketClientEndpoint.h)
|
||||
compile_ipc(${SERENITY_PROJECT_ROOT}/Userland/Services/WebSocket/WebSocketServer.ipc Userland/Services/WebSocket/WebSocketServerEndpoint.h)
|
||||
|
||||
if (ENABLE_LAGOM_LIBWEB)
|
||||
list(APPEND lagom_standard_libraries Web WebView)
|
||||
|
|
|
@ -335,7 +335,6 @@ if (current_os != "mac") {
|
|||
"$root_out_dir/libexec/SQLServer",
|
||||
"$root_out_dir/libexec/WebContent",
|
||||
"$root_out_dir/libexec/WebDriver",
|
||||
"$root_out_dir/libexec/WebSocket",
|
||||
"$root_out_dir/libexec/WebWorker",
|
||||
"$root_out_dir/libexec/headless-browser",
|
||||
]
|
||||
|
|
|
@ -15,6 +15,7 @@ executable("RequestServer") {
|
|||
"//Userland/Libraries/LibMain",
|
||||
"//Userland/Libraries/LibProtocol",
|
||||
"//Userland/Libraries/LibTLS",
|
||||
"//Userland/Libraries/LibWebSocket",
|
||||
]
|
||||
sources = [
|
||||
"//Userland/Services/RequestServer/ConnectionCache.cpp",
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
executable("WebSocket") {
|
||||
configs += [ "//Ladybird:ladybird_config" ]
|
||||
include_dirs = [
|
||||
"//Userland/Libraries",
|
||||
"//Userland/Services",
|
||||
]
|
||||
deps = [
|
||||
"//AK",
|
||||
"//Userland/Libraries/LibCore",
|
||||
"//Userland/Libraries/LibFileSystem",
|
||||
"//Userland/Libraries/LibIPC",
|
||||
"//Userland/Libraries/LibMain",
|
||||
"//Userland/Libraries/LibProtocol",
|
||||
"//Userland/Libraries/LibTLS",
|
||||
"//Userland/Libraries/LibWebSocket",
|
||||
]
|
||||
sources = [
|
||||
"//Userland/Services/WebSocket/ConnectionFromClient.cpp",
|
||||
"main.cpp",
|
||||
]
|
||||
output_dir = "$root_out_dir/libexec"
|
||||
}
|
|
@ -22,28 +22,6 @@ compiled_action("RequestServerEndpoint") {
|
|||
]
|
||||
}
|
||||
|
||||
compiled_action("WebSocketClientEndpoint") {
|
||||
tool = "//Meta/Lagom/Tools/CodeGenerators/IPCCompiler"
|
||||
inputs = [ "//Userland/Services/WebSocket/WebSocketClient.ipc" ]
|
||||
outputs = [ "$root_gen_dir/WebSocket/WebSocketClientEndpoint.h" ]
|
||||
args = [
|
||||
rebase_path(inputs[0], root_build_dir),
|
||||
"-o",
|
||||
rebase_path(outputs[0], root_build_dir),
|
||||
]
|
||||
}
|
||||
|
||||
compiled_action("WebSocketServerEndpoint") {
|
||||
tool = "//Meta/Lagom/Tools/CodeGenerators/IPCCompiler"
|
||||
inputs = [ "//Userland/Services/WebSocket/WebSocketServer.ipc" ]
|
||||
outputs = [ "$root_gen_dir/WebSocket/WebSocketServerEndpoint.h" ]
|
||||
args = [
|
||||
rebase_path(inputs[0], root_build_dir),
|
||||
"-o",
|
||||
rebase_path(outputs[0], root_build_dir),
|
||||
]
|
||||
}
|
||||
|
||||
shared_library("LibProtocol") {
|
||||
output_name = "protocol"
|
||||
include_dirs = [
|
||||
|
@ -53,8 +31,6 @@ shared_library("LibProtocol") {
|
|||
deps = [
|
||||
":RequestClientEndpoint",
|
||||
":RequestServerEndpoint",
|
||||
":WebSocketClientEndpoint",
|
||||
":WebSocketServerEndpoint",
|
||||
"//AK",
|
||||
"//Userland/Libraries/LibCore",
|
||||
"//Userland/Libraries/LibIPC",
|
||||
|
@ -63,10 +39,7 @@ shared_library("LibProtocol") {
|
|||
"Request.cpp",
|
||||
"RequestClient.cpp",
|
||||
"WebSocket.cpp",
|
||||
"WebSocketClient.cpp",
|
||||
]
|
||||
sources += get_target_outputs(":RequestClientEndpoint") +
|
||||
get_target_outputs(":RequestServerEndpoint") +
|
||||
get_target_outputs(":WebSocketClientEndpoint") +
|
||||
get_target_outputs(":WebSocketServerEndpoint")
|
||||
get_target_outputs(":RequestServerEndpoint")
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ serenity_component(
|
|||
Browser
|
||||
RECOMMENDED
|
||||
TARGETS Browser
|
||||
DEPENDS BrowserSettings ImageDecoder RequestServer WebContent WebSocket
|
||||
DEPENDS BrowserSettings ImageDecoder RequestServer WebContent
|
||||
)
|
||||
|
||||
stringify_gml(BrowserWindow.gml BrowserWindowGML.h browser_window_gml)
|
||||
|
|
|
@ -2,14 +2,11 @@ set(SOURCES
|
|||
Request.cpp
|
||||
RequestClient.cpp
|
||||
WebSocket.cpp
|
||||
WebSocketClient.cpp
|
||||
)
|
||||
|
||||
set(GENERATED_SOURCES
|
||||
../../Services/RequestServer/RequestClientEndpoint.h
|
||||
../../Services/RequestServer/RequestServerEndpoint.h
|
||||
../../Services/WebSocket/WebSocketClientEndpoint.h
|
||||
../../Services/WebSocket/WebSocketServerEndpoint.h
|
||||
)
|
||||
|
||||
serenity_lib(LibProtocol protocol)
|
||||
|
|
|
@ -103,6 +103,54 @@ void RequestClient::certificate_requested(i32 request_id)
|
|||
}
|
||||
}
|
||||
|
||||
RefPtr<WebSocket> RequestClient::websocket_connect(const URL& url, ByteString const& origin, Vector<ByteString> const& protocols, Vector<ByteString> const& extensions, HashMap<ByteString, ByteString> const& request_headers)
|
||||
{
|
||||
auto headers_or_error = request_headers.clone();
|
||||
if (headers_or_error.is_error())
|
||||
return nullptr;
|
||||
auto connection_id = IPCProxy::websocket_connect(url, origin, protocols, extensions, headers_or_error.release_value());
|
||||
if (connection_id < 0)
|
||||
return nullptr;
|
||||
auto connection = WebSocket::create_from_id({}, *this, connection_id);
|
||||
m_websockets.set(connection_id, connection);
|
||||
return connection;
|
||||
}
|
||||
|
||||
void RequestClient::websocket_connected(i32 connection_id)
|
||||
{
|
||||
auto maybe_connection = m_websockets.get(connection_id);
|
||||
if (maybe_connection.has_value())
|
||||
maybe_connection.value()->did_open({});
|
||||
}
|
||||
|
||||
void RequestClient::websocket_received(i32 connection_id, bool is_text, ByteBuffer const& data)
|
||||
{
|
||||
auto maybe_connection = m_websockets.get(connection_id);
|
||||
if (maybe_connection.has_value())
|
||||
maybe_connection.value()->did_receive({}, data, is_text);
|
||||
}
|
||||
|
||||
void RequestClient::websocket_errored(i32 connection_id, i32 message)
|
||||
{
|
||||
auto maybe_connection = m_websockets.get(connection_id);
|
||||
if (maybe_connection.has_value())
|
||||
maybe_connection.value()->did_error({}, message);
|
||||
}
|
||||
|
||||
void RequestClient::websocket_closed(i32 connection_id, u16 code, ByteString const& reason, bool clean)
|
||||
{
|
||||
auto maybe_connection = m_websockets.get(connection_id);
|
||||
if (maybe_connection.has_value())
|
||||
maybe_connection.value()->did_close({}, code, reason, clean);
|
||||
}
|
||||
|
||||
void RequestClient::websocket_certificate_requested(i32 connection_id)
|
||||
{
|
||||
auto maybe_connection = m_websockets.get(connection_id);
|
||||
if (maybe_connection.has_value())
|
||||
maybe_connection.value()->did_request_certificates({});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template RefPtr<Protocol::Request> Protocol::RequestClient::start_request(ByteString const& method, URL const&, HashMap<ByteString, ByteString> const& request_headers, ReadonlyBytes request_body, Core::ProxyData const&);
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
#include <AK/HashMap.h>
|
||||
#include <LibIPC/ConnectionToServer.h>
|
||||
#include <LibProtocol/WebSocket.h>
|
||||
#include <LibWebSocket/WebSocket.h>
|
||||
#include <RequestServer/RequestClientEndpoint.h>
|
||||
#include <RequestServer/RequestServerEndpoint.h>
|
||||
|
||||
|
@ -26,6 +28,8 @@ public:
|
|||
template<typename RequestHashMapTraits = Traits<ByteString>>
|
||||
RefPtr<Request> start_request(ByteString const& method, URL const&, HashMap<ByteString, ByteString, RequestHashMapTraits> const& request_headers = {}, ReadonlyBytes request_body = {}, Core::ProxyData const& = {});
|
||||
|
||||
RefPtr<WebSocket> websocket_connect(const URL&, ByteString const& origin = {}, Vector<ByteString> const& protocols = {}, Vector<ByteString> const& extensions = {}, HashMap<ByteString, ByteString> const& request_headers = {});
|
||||
|
||||
void ensure_connection(URL const&, ::RequestServer::CacheLevel);
|
||||
|
||||
bool stop_request(Badge<Request>, Request&);
|
||||
|
@ -38,7 +42,14 @@ private:
|
|||
virtual void certificate_requested(i32) override;
|
||||
virtual void headers_became_available(i32, HashMap<ByteString, ByteString, CaseInsensitiveStringTraits> const&, Optional<u32> const&) override;
|
||||
|
||||
virtual void websocket_connected(i32) override;
|
||||
virtual void websocket_received(i32, bool, ByteBuffer const&) override;
|
||||
virtual void websocket_errored(i32, i32) override;
|
||||
virtual void websocket_closed(i32, u16, ByteString const&, bool) override;
|
||||
virtual void websocket_certificate_requested(i32) override;
|
||||
|
||||
HashMap<i32, RefPtr<Request>> m_requests;
|
||||
HashMap<i32, NonnullRefPtr<WebSocket>> m_websockets;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibProtocol/RequestClient.h>
|
||||
#include <LibProtocol/WebSocket.h>
|
||||
#include <LibProtocol/WebSocketClient.h>
|
||||
|
||||
namespace Protocol {
|
||||
|
||||
WebSocket::WebSocket(WebSocketClient& client, i32 connection_id)
|
||||
WebSocket::WebSocket(RequestClient& client, i32 connection_id)
|
||||
: m_client(client)
|
||||
, m_connection_id(connection_id)
|
||||
{
|
||||
|
@ -17,17 +17,17 @@ WebSocket::WebSocket(WebSocketClient& client, i32 connection_id)
|
|||
|
||||
WebSocket::ReadyState WebSocket::ready_state()
|
||||
{
|
||||
return (WebSocket::ReadyState)m_client->ready_state({}, *this);
|
||||
return static_cast<WebSocket::ReadyState>(m_client->websocket_ready_state(m_connection_id));
|
||||
}
|
||||
|
||||
ByteString WebSocket::subprotocol_in_use()
|
||||
{
|
||||
return m_client->subprotocol_in_use({}, *this);
|
||||
return m_client->websocket_subprotocol_in_use(m_connection_id);
|
||||
}
|
||||
|
||||
void WebSocket::send(ByteBuffer binary_or_text_message, bool is_text)
|
||||
{
|
||||
m_client->send({}, *this, move(binary_or_text_message), is_text);
|
||||
m_client->async_websocket_send(m_connection_id, is_text, move(binary_or_text_message));
|
||||
}
|
||||
|
||||
void WebSocket::send(StringView text_message)
|
||||
|
@ -37,38 +37,38 @@ void WebSocket::send(StringView text_message)
|
|||
|
||||
void WebSocket::close(u16 code, ByteString reason)
|
||||
{
|
||||
m_client->close({}, *this, code, move(reason));
|
||||
m_client->async_websocket_close(m_connection_id, code, move(reason));
|
||||
}
|
||||
|
||||
void WebSocket::did_open(Badge<WebSocketClient>)
|
||||
void WebSocket::did_open(Badge<RequestClient>)
|
||||
{
|
||||
if (on_open)
|
||||
on_open();
|
||||
}
|
||||
|
||||
void WebSocket::did_receive(Badge<WebSocketClient>, ByteBuffer data, bool is_text)
|
||||
void WebSocket::did_receive(Badge<RequestClient>, ByteBuffer data, bool is_text)
|
||||
{
|
||||
if (on_message)
|
||||
on_message(WebSocket::Message { move(data), is_text });
|
||||
}
|
||||
|
||||
void WebSocket::did_error(Badge<WebSocketClient>, i32 error_code)
|
||||
void WebSocket::did_error(Badge<RequestClient>, i32 error_code)
|
||||
{
|
||||
if (on_error)
|
||||
on_error((WebSocket::Error)error_code);
|
||||
}
|
||||
|
||||
void WebSocket::did_close(Badge<WebSocketClient>, u16 code, ByteString reason, bool was_clean)
|
||||
void WebSocket::did_close(Badge<RequestClient>, u16 code, ByteString reason, bool was_clean)
|
||||
{
|
||||
if (on_close)
|
||||
on_close(code, move(reason), was_clean);
|
||||
}
|
||||
|
||||
void WebSocket::did_request_certificates(Badge<WebSocketClient>)
|
||||
void WebSocket::did_request_certificates(Badge<RequestClient>)
|
||||
{
|
||||
if (on_certificate_requested) {
|
||||
auto result = on_certificate_requested();
|
||||
if (!m_client->set_certificate({}, *this, result.certificate, result.key))
|
||||
if (!m_client->websocket_set_certificate(m_connection_id, result.certificate, result.key))
|
||||
dbgln("WebSocket: set_certificate failed");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
namespace Protocol {
|
||||
|
||||
class WebSocketClient;
|
||||
class RequestClient;
|
||||
|
||||
class WebSocket : public RefCounted<WebSocket> {
|
||||
public:
|
||||
|
@ -44,7 +44,7 @@ public:
|
|||
Closed = 3,
|
||||
};
|
||||
|
||||
static NonnullRefPtr<WebSocket> create_from_id(Badge<WebSocketClient>, WebSocketClient& client, i32 connection_id)
|
||||
static NonnullRefPtr<WebSocket> create_from_id(Badge<RequestClient>, RequestClient& client, i32 connection_id)
|
||||
{
|
||||
return adopt_ref(*new WebSocket(client, connection_id));
|
||||
}
|
||||
|
@ -65,15 +65,15 @@ public:
|
|||
Function<void(u16 code, ByteString reason, bool was_clean)> on_close;
|
||||
Function<CertificateAndKey()> on_certificate_requested;
|
||||
|
||||
void did_open(Badge<WebSocketClient>);
|
||||
void did_receive(Badge<WebSocketClient>, ByteBuffer, bool);
|
||||
void did_error(Badge<WebSocketClient>, i32);
|
||||
void did_close(Badge<WebSocketClient>, u16, ByteString, bool);
|
||||
void did_request_certificates(Badge<WebSocketClient>);
|
||||
void did_open(Badge<RequestClient>);
|
||||
void did_receive(Badge<RequestClient>, ByteBuffer, bool);
|
||||
void did_error(Badge<RequestClient>, i32);
|
||||
void did_close(Badge<RequestClient>, u16, ByteString, bool);
|
||||
void did_request_certificates(Badge<RequestClient>);
|
||||
|
||||
private:
|
||||
explicit WebSocket(WebSocketClient&, i32 connection_id);
|
||||
WeakPtr<WebSocketClient> m_client;
|
||||
explicit WebSocket(RequestClient&, i32 connection_id);
|
||||
WeakPtr<RequestClient> m_client;
|
||||
int m_connection_id { -1 };
|
||||
};
|
||||
|
||||
|
|
|
@ -1,100 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Dex♪ <dexes.ttp@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibProtocol/WebSocket.h>
|
||||
#include <LibProtocol/WebSocketClient.h>
|
||||
|
||||
namespace Protocol {
|
||||
|
||||
WebSocketClient::WebSocketClient(NonnullOwnPtr<Core::LocalSocket> socket)
|
||||
: IPC::ConnectionToServer<WebSocketClientEndpoint, WebSocketServerEndpoint>(*this, move(socket))
|
||||
{
|
||||
}
|
||||
|
||||
RefPtr<WebSocket> WebSocketClient::connect(const URL& url, ByteString const& origin, Vector<ByteString> const& protocols, Vector<ByteString> const& extensions, HashMap<ByteString, ByteString> const& request_headers)
|
||||
{
|
||||
auto headers_or_error = request_headers.clone();
|
||||
if (headers_or_error.is_error())
|
||||
return nullptr;
|
||||
auto connection_id = IPCProxy::connect(url, origin, protocols, extensions, headers_or_error.release_value());
|
||||
if (connection_id < 0)
|
||||
return nullptr;
|
||||
auto connection = WebSocket::create_from_id({}, *this, connection_id);
|
||||
m_connections.set(connection_id, connection);
|
||||
return connection;
|
||||
}
|
||||
|
||||
u32 WebSocketClient::ready_state(Badge<WebSocket>, WebSocket& connection)
|
||||
{
|
||||
if (!m_connections.contains(connection.id()))
|
||||
return (u32)WebSocket::ReadyState::Closed;
|
||||
return IPCProxy::ready_state(connection.id());
|
||||
}
|
||||
|
||||
ByteString WebSocketClient::subprotocol_in_use(Badge<WebSocket>, WebSocket& connection)
|
||||
{
|
||||
if (!m_connections.contains(connection.id()))
|
||||
return ByteString::empty();
|
||||
return IPCProxy::subprotocol_in_use(connection.id());
|
||||
}
|
||||
|
||||
void WebSocketClient::send(Badge<WebSocket>, WebSocket& connection, ByteBuffer data, bool is_text)
|
||||
{
|
||||
if (!m_connections.contains(connection.id()))
|
||||
return;
|
||||
async_send(connection.id(), is_text, move(data));
|
||||
}
|
||||
|
||||
void WebSocketClient::close(Badge<WebSocket>, WebSocket& connection, u16 code, ByteString message)
|
||||
{
|
||||
if (!m_connections.contains(connection.id()))
|
||||
return;
|
||||
async_close(connection.id(), code, move(message));
|
||||
}
|
||||
|
||||
bool WebSocketClient::set_certificate(Badge<WebSocket>, WebSocket& connection, ByteString certificate, ByteString key)
|
||||
{
|
||||
if (!m_connections.contains(connection.id()))
|
||||
return false;
|
||||
return IPCProxy::set_certificate(connection.id(), move(certificate), move(key));
|
||||
}
|
||||
|
||||
void WebSocketClient::connected(i32 connection_id)
|
||||
{
|
||||
auto maybe_connection = m_connections.get(connection_id);
|
||||
if (maybe_connection.has_value())
|
||||
maybe_connection.value()->did_open({});
|
||||
}
|
||||
|
||||
void WebSocketClient::received(i32 connection_id, bool is_text, ByteBuffer const& data)
|
||||
{
|
||||
auto maybe_connection = m_connections.get(connection_id);
|
||||
if (maybe_connection.has_value())
|
||||
maybe_connection.value()->did_receive({}, data, is_text);
|
||||
}
|
||||
|
||||
void WebSocketClient::errored(i32 connection_id, i32 message)
|
||||
{
|
||||
auto maybe_connection = m_connections.get(connection_id);
|
||||
if (maybe_connection.has_value())
|
||||
maybe_connection.value()->did_error({}, message);
|
||||
}
|
||||
|
||||
void WebSocketClient::closed(i32 connection_id, u16 code, ByteString const& reason, bool clean)
|
||||
{
|
||||
auto maybe_connection = m_connections.get(connection_id);
|
||||
if (maybe_connection.has_value())
|
||||
maybe_connection.value()->did_close({}, code, reason, clean);
|
||||
}
|
||||
|
||||
void WebSocketClient::certificate_requested(i32 connection_id)
|
||||
{
|
||||
auto maybe_connection = m_connections.get(connection_id);
|
||||
if (maybe_connection.has_value())
|
||||
maybe_connection.value()->did_request_certificates({});
|
||||
}
|
||||
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Dex♪ <dexes.ttp@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/HashMap.h>
|
||||
#include <LibIPC/ConnectionToServer.h>
|
||||
#include <WebSocket/WebSocketClientEndpoint.h>
|
||||
#include <WebSocket/WebSocketServerEndpoint.h>
|
||||
|
||||
namespace Protocol {
|
||||
|
||||
class WebSocket;
|
||||
|
||||
class WebSocketClient final
|
||||
: public IPC::ConnectionToServer<WebSocketClientEndpoint, WebSocketServerEndpoint>
|
||||
, public WebSocketClientEndpoint {
|
||||
IPC_CLIENT_CONNECTION(WebSocketClient, "/tmp/session/%sid/portal/websocket"sv)
|
||||
|
||||
public:
|
||||
explicit WebSocketClient(NonnullOwnPtr<Core::LocalSocket>);
|
||||
|
||||
RefPtr<WebSocket> connect(const URL&, ByteString const& origin = {}, Vector<ByteString> const& protocols = {}, Vector<ByteString> const& extensions = {}, HashMap<ByteString, ByteString> const& request_headers = {});
|
||||
|
||||
u32 ready_state(Badge<WebSocket>, WebSocket&);
|
||||
ByteString subprotocol_in_use(Badge<WebSocket>, WebSocket&);
|
||||
void send(Badge<WebSocket>, WebSocket&, ByteBuffer, bool is_text);
|
||||
void close(Badge<WebSocket>, WebSocket&, u16 code, ByteString reason);
|
||||
bool set_certificate(Badge<WebSocket>, WebSocket&, ByteString, ByteString);
|
||||
|
||||
private:
|
||||
virtual void connected(i32) override;
|
||||
virtual void received(i32, bool, ByteBuffer const&) override;
|
||||
virtual void errored(i32, i32) override;
|
||||
virtual void closed(i32, u16, ByteString const&, bool) override;
|
||||
virtual void certificate_requested(i32) override;
|
||||
|
||||
HashMap<i32, NonnullRefPtr<WebSocket>> m_connections;
|
||||
};
|
||||
|
||||
}
|
|
@ -66,6 +66,10 @@ namespace Web {
|
|||
constexpr auto default_user_agent = "Mozilla/5.0 (" OS_STRING "; " CPU_STRING ") " BROWSER_NAME "/" BROWSER_VERSION ""sv;
|
||||
constexpr auto default_platform = OS_STRING " " CPU_STRING ""sv;
|
||||
|
||||
namespace WebSockets {
|
||||
class WebSocketClientSocket;
|
||||
}
|
||||
|
||||
class ResourceLoaderConnectorRequest : public RefCounted<ResourceLoaderConnectorRequest> {
|
||||
public:
|
||||
virtual ~ResourceLoaderConnectorRequest();
|
||||
|
@ -97,6 +101,7 @@ public:
|
|||
virtual void preconnect(URL const&) = 0;
|
||||
|
||||
virtual RefPtr<ResourceLoaderConnectorRequest> start_request(ByteString const& method, URL const&, HashMap<ByteString, ByteString> const& request_headers = {}, ReadonlyBytes request_body = {}, Core::ProxyData const& = {}) = 0;
|
||||
virtual RefPtr<Web::WebSockets::WebSocketClientSocket> websocket_connect(const URL&, ByteString const& origin, Vector<ByteString> const& protocols) = 0;
|
||||
|
||||
protected:
|
||||
explicit ResourceLoaderConnector();
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <LibWeb/HTML/MessageEvent.h>
|
||||
#include <LibWeb/HTML/Origin.h>
|
||||
#include <LibWeb/HTML/Window.h>
|
||||
#include <LibWeb/Loader/ResourceLoader.h>
|
||||
#include <LibWeb/WebIDL/AbstractOperations.h>
|
||||
#include <LibWeb/WebIDL/Buffers.h>
|
||||
#include <LibWeb/WebIDL/DOMException.h>
|
||||
|
@ -29,28 +30,8 @@ namespace Web::WebSockets {
|
|||
|
||||
JS_DEFINE_ALLOCATOR(WebSocket);
|
||||
|
||||
static RefPtr<WebSocketClientManager> s_websocket_client_manager;
|
||||
|
||||
void WebSocketClientManager::initialize(RefPtr<WebSocketClientManager> websocket_client_manager)
|
||||
{
|
||||
s_websocket_client_manager = websocket_client_manager;
|
||||
}
|
||||
|
||||
WebSocketClientManager& WebSocketClientManager::the()
|
||||
{
|
||||
if (!s_websocket_client_manager) [[unlikely]] {
|
||||
dbgln("Web::WebSockets::WebSocketClientManager was not initialized!");
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
return *s_websocket_client_manager;
|
||||
}
|
||||
|
||||
WebSocketClientSocket::WebSocketClientSocket() = default;
|
||||
|
||||
WebSocketClientSocket::~WebSocketClientSocket() = default;
|
||||
|
||||
WebSocketClientManager::WebSocketClientManager() = default;
|
||||
|
||||
// https://websockets.spec.whatwg.org/#dom-websocket-websocket
|
||||
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebSocket>> WebSocket::construct_impl(JS::Realm& realm, String const& url, Optional<Variant<String, Vector<String>>> const& protocols)
|
||||
{
|
||||
|
@ -148,7 +129,7 @@ ErrorOr<void> WebSocket::establish_web_socket_connection(URL& url_record, Vector
|
|||
for (auto const& protocol : protocols)
|
||||
TRY(protcol_byte_strings.try_append(protocol.to_byte_string()));
|
||||
|
||||
m_websocket = WebSocketClientManager::the().connect(url_record, origin_string, protcol_byte_strings);
|
||||
m_websocket = ResourceLoader::the().connector().websocket_connect(url_record, origin_string, protcol_byte_strings);
|
||||
m_websocket->on_open = [weak_this = make_weak_ptr<WebSocket>()] {
|
||||
if (!weak_this)
|
||||
return;
|
||||
|
|
|
@ -114,19 +114,7 @@ public:
|
|||
Function<CertificateAndKey()> on_certificate_requested;
|
||||
|
||||
protected:
|
||||
explicit WebSocketClientSocket();
|
||||
};
|
||||
|
||||
class WebSocketClientManager : public Core::EventReceiver {
|
||||
C_OBJECT_ABSTRACT(WebSocketClientManager)
|
||||
public:
|
||||
static void initialize(RefPtr<WebSocketClientManager>);
|
||||
static WebSocketClientManager& the();
|
||||
|
||||
virtual RefPtr<WebSocketClientSocket> connect(URL const&, ByteString const& origin, Vector<ByteString> const& protocols) = 0;
|
||||
|
||||
protected:
|
||||
explicit WebSocketClientManager();
|
||||
explicit WebSocketClientSocket() = default;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -40,8 +40,6 @@ set(GENERATED_SOURCES
|
|||
../../Services/WebContent/WebContentServerEndpoint.h
|
||||
../../Services/WebContent/WebDriverClientEndpoint.h
|
||||
../../Services/WebContent/WebDriverServerEndpoint.h
|
||||
../../Services/WebSocket/WebSocketClientEndpoint.h
|
||||
../../Services/WebSocket/WebSocketServerEndpoint.h
|
||||
NativeStyleSheetSource.cpp
|
||||
)
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "WebSocketClientAdapter.h"
|
||||
#include <LibProtocol/Request.h>
|
||||
#include <LibProtocol/RequestClient.h>
|
||||
#include <LibWebView/RequestServerAdapter.h>
|
||||
|
@ -94,6 +95,14 @@ RefPtr<Web::ResourceLoaderConnectorRequest> RequestServerAdapter::start_request(
|
|||
return RequestServerRequestAdapter::try_create(protocol_request.release_nonnull()).release_value_but_fixme_should_propagate_errors();
|
||||
}
|
||||
|
||||
RefPtr<Web::WebSockets::WebSocketClientSocket> RequestServerAdapter::websocket_connect(AK::URL const& url, AK::ByteString const& origin, Vector<AK::ByteString> const& protocols)
|
||||
{
|
||||
auto underlying_websocket = m_protocol_client->websocket_connect(url, origin, protocols);
|
||||
if (!underlying_websocket)
|
||||
return {};
|
||||
return WebSocketClientSocketAdapter::create(underlying_websocket.release_nonnull());
|
||||
}
|
||||
|
||||
void RequestServerAdapter::prefetch_dns(URL const& url)
|
||||
{
|
||||
m_protocol_client->ensure_connection(url, RequestServer::CacheLevel::ResolveOnly);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <AK/Function.h>
|
||||
#include <AK/URL.h>
|
||||
#include <LibWeb/Loader/ResourceLoader.h>
|
||||
#include <LibWeb/WebSockets/WebSocket.h>
|
||||
|
||||
namespace Protocol {
|
||||
class Request;
|
||||
|
@ -46,6 +47,7 @@ public:
|
|||
virtual void preconnect(URL const& url) override;
|
||||
|
||||
virtual RefPtr<Web::ResourceLoaderConnectorRequest> start_request(ByteString const& method, URL const&, HashMap<ByteString, ByteString> const& request_headers = {}, ReadonlyBytes request_body = {}, Core::ProxyData const& = {}) override;
|
||||
virtual RefPtr<Web::WebSockets::WebSocketClientSocket> websocket_connect(const URL&, ByteString const& origin, Vector<ByteString> const& protocols) override;
|
||||
|
||||
private:
|
||||
RefPtr<Protocol::RequestClient> m_protocol_client;
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibProtocol/RequestClient.h>
|
||||
#include <LibProtocol/WebSocket.h>
|
||||
#include <LibProtocol/WebSocketClient.h>
|
||||
#include <LibWebView/WebSocketClientAdapter.h>
|
||||
|
||||
namespace WebView {
|
||||
|
@ -107,30 +107,4 @@ void WebSocketClientSocketAdapter::close(u16 code, ByteString reason)
|
|||
m_websocket->close(code, reason);
|
||||
}
|
||||
|
||||
ErrorOr<NonnullRefPtr<WebSocketClientManagerAdapter>> WebSocketClientManagerAdapter::try_create(NonnullRefPtr<Protocol::WebSocketClient> websocket_client)
|
||||
{
|
||||
return adopt_nonnull_ref_or_enomem(new (nothrow) WebSocketClientManagerAdapter(move(websocket_client)));
|
||||
}
|
||||
|
||||
ErrorOr<NonnullRefPtr<WebSocketClientManagerAdapter>> WebSocketClientManagerAdapter::try_create()
|
||||
{
|
||||
auto websocket_client = TRY(Protocol::WebSocketClient::try_create());
|
||||
return adopt_nonnull_ref_or_enomem(new (nothrow) WebSocketClientManagerAdapter(move(websocket_client)));
|
||||
}
|
||||
|
||||
WebSocketClientManagerAdapter::WebSocketClientManagerAdapter(NonnullRefPtr<Protocol::WebSocketClient> websocket_client)
|
||||
: m_websocket_client(move(websocket_client))
|
||||
{
|
||||
}
|
||||
|
||||
WebSocketClientManagerAdapter::~WebSocketClientManagerAdapter() = default;
|
||||
|
||||
RefPtr<Web::WebSockets::WebSocketClientSocket> WebSocketClientManagerAdapter::connect(const URL& url, ByteString const& origin, Vector<ByteString> const& protocols)
|
||||
{
|
||||
auto underlying_websocket = m_websocket_client->connect(url, origin, protocols);
|
||||
if (!underlying_websocket)
|
||||
return {};
|
||||
return WebSocketClientSocketAdapter::create(underlying_websocket.release_nonnull());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
namespace Protocol {
|
||||
class WebSocket;
|
||||
class WebSocketClient;
|
||||
class RequestClient;
|
||||
};
|
||||
|
||||
namespace WebView {
|
||||
|
@ -38,19 +38,4 @@ private:
|
|||
NonnullRefPtr<Protocol::WebSocket> m_websocket;
|
||||
};
|
||||
|
||||
class WebSocketClientManagerAdapter : public Web::WebSockets::WebSocketClientManager {
|
||||
public:
|
||||
static ErrorOr<NonnullRefPtr<WebSocketClientManagerAdapter>> try_create(NonnullRefPtr<Protocol::WebSocketClient>);
|
||||
static ErrorOr<NonnullRefPtr<WebSocketClientManagerAdapter>> try_create();
|
||||
|
||||
virtual ~WebSocketClientManagerAdapter() override;
|
||||
|
||||
virtual RefPtr<Web::WebSockets::WebSocketClientSocket> connect(const URL&, ByteString const& origin, Vector<ByteString> const& protocols) override;
|
||||
|
||||
private:
|
||||
WebSocketClientManagerAdapter(NonnullRefPtr<Protocol::WebSocketClient>);
|
||||
|
||||
NonnullRefPtr<Protocol::WebSocketClient> m_websocket_client;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ if (SERENITYOS)
|
|||
add_subdirectory(TelnetServer)
|
||||
add_subdirectory(WebContent)
|
||||
add_subdirectory(WebDriver)
|
||||
add_subdirectory(WebSocket)
|
||||
add_subdirectory(WebWorker)
|
||||
add_subdirectory(WindowServer)
|
||||
endif()
|
||||
|
|
|
@ -26,4 +26,4 @@ set(GENERATED_SOURCES
|
|||
)
|
||||
|
||||
serenity_bin(RequestServer)
|
||||
target_link_libraries(RequestServer PRIVATE LibCore LibCrypto LibIPC LibGemini LibHTTP LibMain LibTLS)
|
||||
target_link_libraries(RequestServer PRIVATE LibCore LibCrypto LibIPC LibGemini LibHTTP LibMain LibTLS LibWebSocket)
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include <AK/Weakable.h>
|
||||
#include <LibCore/Proxy.h>
|
||||
#include <LibCore/Socket.h>
|
||||
#include <LibWebSocket/ConnectionInfo.h>
|
||||
#include <LibWebSocket/Message.h>
|
||||
#include <RequestServer/ConnectionFromClient.h>
|
||||
#include <RequestServer/Protocol.h>
|
||||
#include <RequestServer/Request.h>
|
||||
|
@ -187,4 +189,80 @@ void ConnectionFromClient::ensure_connection(URL const& url, ::RequestServer::Ca
|
|||
dbgln("EnsureConnection: Invalid URL scheme: '{}'", url.scheme());
|
||||
}
|
||||
|
||||
static i32 s_next_websocket_id = 1;
|
||||
Messages::RequestServer::WebsocketConnectResponse ConnectionFromClient::websocket_connect(URL const& url, ByteString const& origin, Vector<ByteString> const& protocols, Vector<ByteString> const& extensions, HashMap<ByteString, ByteString> const& additional_request_headers)
|
||||
{
|
||||
if (!url.is_valid()) {
|
||||
dbgln("WebSocket::Connect: Invalid URL requested: '{}'", url);
|
||||
return -1;
|
||||
}
|
||||
|
||||
WebSocket::ConnectionInfo connection_info(url);
|
||||
connection_info.set_origin(origin);
|
||||
connection_info.set_protocols(protocols);
|
||||
connection_info.set_extensions(extensions);
|
||||
|
||||
Vector<WebSocket::ConnectionInfo::Header> headers;
|
||||
for (auto const& header : additional_request_headers) {
|
||||
headers.append({ header.key, header.value });
|
||||
}
|
||||
connection_info.set_headers(headers);
|
||||
|
||||
auto id = ++s_next_websocket_id;
|
||||
auto connection = WebSocket::WebSocket::create(move(connection_info));
|
||||
connection->on_open = [this, id]() {
|
||||
async_websocket_connected(id);
|
||||
};
|
||||
connection->on_message = [this, id](auto message) {
|
||||
async_websocket_received(id, message.is_text(), message.data());
|
||||
};
|
||||
connection->on_error = [this, id](auto message) {
|
||||
async_websocket_errored(id, (i32)message);
|
||||
};
|
||||
connection->on_close = [this, id](u16 code, ByteString reason, bool was_clean) {
|
||||
async_websocket_closed(id, code, move(reason), was_clean);
|
||||
};
|
||||
|
||||
connection->start();
|
||||
m_websockets.set(id, move(connection));
|
||||
return id;
|
||||
}
|
||||
|
||||
Messages::RequestServer::WebsocketReadyStateResponse ConnectionFromClient::websocket_ready_state(i32 connection_id)
|
||||
{
|
||||
if (auto connection = m_websockets.get(connection_id).value_or({}))
|
||||
return (u32)connection->ready_state();
|
||||
return (u32)WebSocket::ReadyState::Closed;
|
||||
}
|
||||
|
||||
Messages::RequestServer::WebsocketSubprotocolInUseResponse ConnectionFromClient::websocket_subprotocol_in_use(i32 connection_id)
|
||||
{
|
||||
if (auto connection = m_websockets.get(connection_id).value_or({}))
|
||||
return connection->subprotocol_in_use();
|
||||
return ByteString::empty();
|
||||
}
|
||||
|
||||
void ConnectionFromClient::websocket_send(i32 connection_id, bool is_text, ByteBuffer const& data)
|
||||
{
|
||||
if (auto connection = m_websockets.get(connection_id).value_or({}); connection && connection->ready_state() == WebSocket::ReadyState::Open)
|
||||
connection->send(WebSocket::Message { data, is_text });
|
||||
}
|
||||
|
||||
void ConnectionFromClient::websocket_close(i32 connection_id, u16 code, ByteString const& reason)
|
||||
{
|
||||
if (auto connection = m_websockets.get(connection_id).value_or({}); connection && connection->ready_state() == WebSocket::ReadyState::Open)
|
||||
connection->close(code, reason);
|
||||
}
|
||||
|
||||
Messages::RequestServer::WebsocketSetCertificateResponse ConnectionFromClient::websocket_set_certificate(i32 connection_id, ByteString const&, ByteString const&)
|
||||
{
|
||||
auto success = false;
|
||||
if (auto connection = m_websockets.get(connection_id).value_or({}); connection) {
|
||||
// NO OP here
|
||||
// connection->set_certificate(certificate, key);
|
||||
success = true;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <AK/HashMap.h>
|
||||
#include <LibIPC/ConnectionFromClient.h>
|
||||
#include <LibWebSocket/WebSocket.h>
|
||||
#include <RequestServer/Forward.h>
|
||||
#include <RequestServer/RequestClientEndpoint.h>
|
||||
#include <RequestServer/RequestServerEndpoint.h>
|
||||
|
@ -37,7 +38,15 @@ private:
|
|||
virtual Messages::RequestServer::SetCertificateResponse set_certificate(i32, ByteString const&, ByteString const&) override;
|
||||
virtual void ensure_connection(URL const& url, ::RequestServer::CacheLevel const& cache_level) override;
|
||||
|
||||
virtual Messages::RequestServer::WebsocketConnectResponse websocket_connect(URL const&, ByteString const&, Vector<ByteString> const&, Vector<ByteString> const&, HashMap<ByteString, ByteString> const&) override;
|
||||
virtual Messages::RequestServer::WebsocketReadyStateResponse websocket_ready_state(i32) override;
|
||||
virtual Messages::RequestServer::WebsocketSubprotocolInUseResponse websocket_subprotocol_in_use(i32) override;
|
||||
virtual void websocket_send(i32, bool, ByteBuffer const&) override;
|
||||
virtual void websocket_close(i32, u16, ByteString const&) override;
|
||||
virtual Messages::RequestServer::WebsocketSetCertificateResponse websocket_set_certificate(i32, ByteString const&, ByteString const&) override;
|
||||
|
||||
HashMap<i32, OwnPtr<Request>> m_requests;
|
||||
HashMap<i32, RefPtr<WebSocket::WebSocket>> m_websockets;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -7,6 +7,14 @@ endpoint RequestClient
|
|||
request_finished(i32 request_id, bool success, u64 total_size) =|
|
||||
headers_became_available(i32 request_id, HashMap<ByteString,ByteString,CaseInsensitiveStringTraits> response_headers, Optional<u32> status_code) =|
|
||||
|
||||
// Websocket API
|
||||
// FIXME: See if this can be merged with the regular APIs
|
||||
websocket_connected(i32 connection_id) =|
|
||||
websocket_received(i32 connection_id, bool is_text, ByteBuffer data) =|
|
||||
websocket_errored(i32 connection_id, i32 message) =|
|
||||
websocket_closed(i32 connection_id, u16 code, ByteString reason, bool clean) =|
|
||||
websocket_certificate_requested(i32 request_id) =|
|
||||
|
||||
// Certificate requests
|
||||
certificate_requested(i32 request_id) =|
|
||||
}
|
||||
|
|
|
@ -11,4 +11,12 @@ endpoint RequestServer
|
|||
set_certificate(i32 request_id, ByteString certificate, ByteString key) => (bool success)
|
||||
|
||||
ensure_connection(URL url, ::RequestServer::CacheLevel cache_level) =|
|
||||
|
||||
// Websocket Connection API
|
||||
websocket_connect(URL url, ByteString origin, Vector<ByteString> protocols, Vector<ByteString> extensions, HashMap<ByteString,ByteString> additional_request_headers) => (i32 connection_id)
|
||||
websocket_ready_state(i32 connection_id) => (u32 ready_state)
|
||||
websocket_subprotocol_in_use(i32 connection_id) => (ByteString subprotocol_in_use)
|
||||
websocket_send(i32 connection_id, bool is_text, ByteBuffer data) =|
|
||||
websocket_close(i32 connection_id, u16 code, ByteString reason) =|
|
||||
websocket_set_certificate(i32 request_id, ByteString certificate, ByteString key) => (bool success)
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ include(accelerated_graphics)
|
|||
serenity_component(
|
||||
WebContent
|
||||
TARGETS WebContent
|
||||
DEPENDS ImageDecoder RequestServer WebSocket
|
||||
DEPENDS ImageDecoder RequestServer
|
||||
)
|
||||
|
||||
compile_ipc(WebContentServer.ipc WebContentServerEndpoint.h)
|
||||
|
|
|
@ -40,7 +40,6 @@ ErrorOr<int> serenity_main(Main::Arguments)
|
|||
TRY(Core::System::unveil("/tmp/session/%sid/portal/audio", "rw"));
|
||||
TRY(Core::System::unveil("/tmp/session/%sid/portal/request", "rw"));
|
||||
TRY(Core::System::unveil("/tmp/session/%sid/portal/image", "rw"));
|
||||
TRY(Core::System::unveil("/tmp/session/%sid/portal/websocket", "rw"));
|
||||
TRY(Core::System::unveil(nullptr, nullptr));
|
||||
|
||||
Web::Platform::EventLoopPlugin::install(*new Web::Platform::EventLoopPluginSerenity);
|
||||
|
@ -51,7 +50,6 @@ ErrorOr<int> serenity_main(Main::Arguments)
|
|||
return Web::Platform::AudioCodecPluginAgnostic::create(move(loader));
|
||||
});
|
||||
|
||||
Web::WebSockets::WebSocketClientManager::initialize(TRY(WebView::WebSocketClientManagerAdapter::try_create()));
|
||||
Web::ResourceLoader::initialize(TRY(WebView::RequestServerAdapter::try_create()));
|
||||
TRY(Web::Bindings::initialize_main_thread_vm());
|
||||
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
serenity_component(
|
||||
WebSocket
|
||||
TARGETS WebSocketServer
|
||||
)
|
||||
|
||||
compile_ipc(WebSocketServer.ipc WebSocketServerEndpoint.h)
|
||||
compile_ipc(WebSocketClient.ipc WebSocketClientEndpoint.h)
|
||||
|
||||
set(SOURCES
|
||||
ConnectionFromClient.cpp
|
||||
main.cpp
|
||||
)
|
||||
|
||||
set(GENERATED_SOURCES
|
||||
WebSocketClientEndpoint.h
|
||||
WebSocketServerEndpoint.h
|
||||
)
|
||||
|
||||
# Note: We use a target name of WebSocketServer here to deconflict with the
|
||||
# Lagom namespaced target name for LibWebSocket, Lagom::WebSocket.
|
||||
# The server binary name is still WebSocket.
|
||||
serenity_bin(WebSocketServer)
|
||||
set_target_properties(WebSocketServer PROPERTIES OUTPUT_NAME WebSocket)
|
||||
target_link_libraries(WebSocketServer PRIVATE LibCore LibIPC LibWebSocket LibMain LibTLS)
|
|
@ -1,144 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Dex♪ <dexes.ttp@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibWebSocket/ConnectionInfo.h>
|
||||
#include <LibWebSocket/Message.h>
|
||||
#include <WebSocket/ConnectionFromClient.h>
|
||||
#include <WebSocket/WebSocketClientEndpoint.h>
|
||||
|
||||
namespace WebSocket {
|
||||
|
||||
static HashMap<int, RefPtr<ConnectionFromClient>> s_connections;
|
||||
|
||||
ConnectionFromClient::ConnectionFromClient(NonnullOwnPtr<Core::LocalSocket> socket)
|
||||
: IPC::ConnectionFromClient<WebSocketClientEndpoint, WebSocketServerEndpoint>(*this, move(socket), 1)
|
||||
{
|
||||
s_connections.set(1, *this);
|
||||
}
|
||||
|
||||
void ConnectionFromClient::die()
|
||||
{
|
||||
s_connections.remove(client_id());
|
||||
if (s_connections.is_empty())
|
||||
Core::EventLoop::current().quit(0);
|
||||
}
|
||||
|
||||
Messages::WebSocketServer::ConnectResponse ConnectionFromClient::connect(URL const& url, ByteString const& origin,
|
||||
Vector<ByteString> const& protocols, Vector<ByteString> const& extensions, HashMap<ByteString, ByteString> const& additional_request_headers)
|
||||
{
|
||||
if (!url.is_valid()) {
|
||||
dbgln("WebSocket::Connect: Invalid URL requested: '{}'", url);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ConnectionInfo connection_info(url);
|
||||
connection_info.set_origin(origin);
|
||||
connection_info.set_protocols(protocols);
|
||||
connection_info.set_extensions(extensions);
|
||||
|
||||
Vector<ConnectionInfo::Header> headers;
|
||||
for (auto const& header : additional_request_headers) {
|
||||
headers.append({ header.key, header.value });
|
||||
}
|
||||
connection_info.set_headers(headers);
|
||||
|
||||
VERIFY(m_connection_ids < NumericLimits<i32>::max());
|
||||
auto id = ++m_connection_ids;
|
||||
auto connection = WebSocket::create(move(connection_info));
|
||||
connection->on_open = [this, id]() {
|
||||
did_connect(id);
|
||||
};
|
||||
connection->on_message = [this, id](auto message) {
|
||||
did_receive_message(id, move(message));
|
||||
};
|
||||
connection->on_error = [this, id](auto message) {
|
||||
did_error(id, (i32)message);
|
||||
};
|
||||
connection->on_close = [this, id](u16 code, ByteString reason, bool was_clean) {
|
||||
did_close(id, code, move(reason), was_clean);
|
||||
};
|
||||
|
||||
connection->start();
|
||||
m_connections.set(id, move(connection));
|
||||
return id;
|
||||
}
|
||||
|
||||
Messages::WebSocketServer::ReadyStateResponse ConnectionFromClient::ready_state(i32 connection_id)
|
||||
{
|
||||
RefPtr<WebSocket> connection = m_connections.get(connection_id).value_or({});
|
||||
if (connection) {
|
||||
return (u32)connection->ready_state();
|
||||
}
|
||||
return (u32)ReadyState::Closed;
|
||||
}
|
||||
|
||||
Messages::WebSocketServer::SubprotocolInUseResponse ConnectionFromClient::subprotocol_in_use(i32 connection_id)
|
||||
{
|
||||
RefPtr<WebSocket> connection = m_connections.get(connection_id).value_or({});
|
||||
if (connection) {
|
||||
return connection->subprotocol_in_use();
|
||||
}
|
||||
return ByteString::empty();
|
||||
}
|
||||
|
||||
void ConnectionFromClient::send(i32 connection_id, bool is_text, ByteBuffer const& data)
|
||||
{
|
||||
RefPtr<WebSocket> connection = m_connections.get(connection_id).value_or({});
|
||||
if (connection && connection->ready_state() == ReadyState::Open) {
|
||||
Message websocket_message(data, is_text);
|
||||
connection->send(websocket_message);
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionFromClient::close(i32 connection_id, u16 code, ByteString const& reason)
|
||||
{
|
||||
RefPtr<WebSocket> connection = m_connections.get(connection_id).value_or({});
|
||||
if (connection && connection->ready_state() == ReadyState::Open)
|
||||
connection->close(code, reason);
|
||||
}
|
||||
|
||||
Messages::WebSocketServer::SetCertificateResponse ConnectionFromClient::set_certificate(i32 connection_id,
|
||||
[[maybe_unused]] ByteString const& certificate, [[maybe_unused]] ByteString const& key)
|
||||
{
|
||||
RefPtr<WebSocket> connection = m_connections.get(connection_id).value_or({});
|
||||
bool success = false;
|
||||
if (connection) {
|
||||
// NO OP here
|
||||
// connection->set_certificate(certificate, key);
|
||||
success = true;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
void ConnectionFromClient::did_connect(i32 connection_id)
|
||||
{
|
||||
async_connected(connection_id);
|
||||
}
|
||||
|
||||
void ConnectionFromClient::did_receive_message(i32 connection_id, Message message)
|
||||
{
|
||||
async_received(connection_id, message.is_text(), message.data());
|
||||
}
|
||||
|
||||
void ConnectionFromClient::did_error(i32 connection_id, i32 message)
|
||||
{
|
||||
async_errored(connection_id, message);
|
||||
}
|
||||
|
||||
void ConnectionFromClient::did_close(i32 connection_id, u16 code, ByteString reason, bool was_clean)
|
||||
{
|
||||
async_closed(connection_id, code, reason, was_clean);
|
||||
deferred_invoke([this, connection_id] {
|
||||
m_connections.remove(connection_id);
|
||||
});
|
||||
}
|
||||
|
||||
void ConnectionFromClient::did_request_certificates(i32 connection_id)
|
||||
{
|
||||
async_certificate_requested(connection_id);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Dex♪ <dexes.ttp@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/HashMap.h>
|
||||
#include <LibIPC/ConnectionFromClient.h>
|
||||
#include <LibWebSocket/WebSocket.h>
|
||||
#include <WebSocket/WebSocketClientEndpoint.h>
|
||||
#include <WebSocket/WebSocketServerEndpoint.h>
|
||||
|
||||
namespace WebSocket {
|
||||
|
||||
class ConnectionFromClient final
|
||||
: public IPC::ConnectionFromClient<WebSocketClientEndpoint, WebSocketServerEndpoint> {
|
||||
C_OBJECT(ConnectionFromClient);
|
||||
|
||||
public:
|
||||
~ConnectionFromClient() override = default;
|
||||
|
||||
virtual void die() override;
|
||||
|
||||
private:
|
||||
explicit ConnectionFromClient(NonnullOwnPtr<Core::LocalSocket>);
|
||||
|
||||
virtual Messages::WebSocketServer::ConnectResponse connect(URL const&, ByteString const&, Vector<ByteString> const&, Vector<ByteString> const&, HashMap<ByteString, ByteString> const&) override;
|
||||
virtual Messages::WebSocketServer::ReadyStateResponse ready_state(i32) override;
|
||||
virtual Messages::WebSocketServer::SubprotocolInUseResponse subprotocol_in_use(i32) override;
|
||||
virtual void send(i32, bool, ByteBuffer const&) override;
|
||||
virtual void close(i32, u16, ByteString const&) override;
|
||||
virtual Messages::WebSocketServer::SetCertificateResponse set_certificate(i32, ByteString const&, ByteString const&) override;
|
||||
|
||||
void did_connect(i32);
|
||||
void did_receive_message(i32, Message);
|
||||
void did_error(i32, i32 message);
|
||||
void did_close(i32, u16 code, ByteString reason, bool was_clean);
|
||||
void did_request_certificates(i32);
|
||||
|
||||
i32 m_connection_ids { 0 };
|
||||
HashMap<i32, RefPtr<WebSocket>> m_connections;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
#include <AK/URL.h>
|
||||
|
||||
endpoint WebSocketClient
|
||||
{
|
||||
// Connection API
|
||||
connected(i32 connection_id) =|
|
||||
received(i32 connection_id, bool is_text, ByteBuffer data) =|
|
||||
errored(i32 connection_id, i32 message) =|
|
||||
closed(i32 connection_id, u16 code, ByteString reason, bool clean) =|
|
||||
|
||||
// Certificate requests
|
||||
certificate_requested(i32 connection_id) =|
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
#include <AK/URL.h>
|
||||
|
||||
endpoint WebSocketServer
|
||||
{
|
||||
// Connection API
|
||||
connect(URL url, ByteString origin, Vector<ByteString> protocols, Vector<ByteString> extensions, HashMap<ByteString,ByteString> additional_request_headers) => (i32 connection_id)
|
||||
ready_state(i32 connection_id) => (u32 ready_state)
|
||||
subprotocol_in_use(i32 connection_id) => (ByteString subprotocol_in_use)
|
||||
send(i32 connection_id, bool is_text, ByteBuffer data) =|
|
||||
close(i32 connection_id, u16 code, ByteString reason) =|
|
||||
|
||||
set_certificate(i32 connection_id, ByteString certificate, ByteString key) => (bool success)
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Dex♪ <dexes.ttp@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibCore/EventLoop.h>
|
||||
#include <LibCore/LocalServer.h>
|
||||
#include <LibCore/System.h>
|
||||
#include <LibIPC/SingleServer.h>
|
||||
#include <LibMain/Main.h>
|
||||
#include <LibTLS/Certificate.h>
|
||||
#include <WebSocket/ConnectionFromClient.h>
|
||||
|
||||
ErrorOr<int> serenity_main(Main::Arguments)
|
||||
{
|
||||
TRY(Core::System::pledge("stdio inet unix rpath sendfd recvfd"));
|
||||
|
||||
// Ensure the certificates are read out here.
|
||||
// FIXME: Allow specifying extra certificates on the command line, or in other configuration.
|
||||
[[maybe_unused]] auto& certs = DefaultRootCACertificates::the();
|
||||
|
||||
Core::EventLoop event_loop;
|
||||
// FIXME: Establish a connection to LookupServer and then drop "unix"?
|
||||
TRY(Core::System::unveil("/tmp/portal/lookup", "rw"));
|
||||
TRY(Core::System::unveil("/etc/timezone", "r"));
|
||||
TRY(Core::System::unveil(nullptr, nullptr));
|
||||
|
||||
auto client = TRY(IPC::take_over_accepted_client_from_system_server<WebSocket::ConnectionFromClient>());
|
||||
|
||||
return event_loop.exec();
|
||||
}
|
|
@ -30,13 +30,11 @@ ErrorOr<int> serenity_main(Main::Arguments)
|
|||
TRY(Core::System::unveil("/etc/timezone", "r"));
|
||||
TRY(Core::System::unveil("/tmp/session/%sid/portal/request", "rw"));
|
||||
TRY(Core::System::unveil("/tmp/session/%sid/portal/image", "rw"));
|
||||
TRY(Core::System::unveil("/tmp/session/%sid/portal/websocket", "rw"));
|
||||
TRY(Core::System::unveil(nullptr, nullptr));
|
||||
|
||||
Web::Platform::EventLoopPlugin::install(*new Web::Platform::EventLoopPluginSerenity);
|
||||
Web::Platform::FontPlugin::install(*new Web::Platform::FontPluginSerenity);
|
||||
|
||||
Web::WebSockets::WebSocketClientManager::initialize(TRY(WebView::WebSocketClientManagerAdapter::try_create()));
|
||||
Web::ResourceLoader::initialize(TRY(WebView::RequestServerAdapter::try_create()));
|
||||
TRY(Web::Bindings::initialize_main_thread_vm());
|
||||
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
#include <LibCore/System.h>
|
||||
#include <LibLine/Editor.h>
|
||||
#include <LibMain/Main.h>
|
||||
#include <LibProtocol/RequestClient.h>
|
||||
#include <LibProtocol/WebSocket.h>
|
||||
#include <LibProtocol/WebSocketClient.h>
|
||||
|
||||
ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||
{
|
||||
|
@ -38,7 +38,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
|
||||
Core::EventLoop loop;
|
||||
|
||||
auto maybe_websocket_client = Protocol::WebSocketClient::try_create();
|
||||
auto maybe_websocket_client = Protocol::RequestClient::try_create();
|
||||
if (maybe_websocket_client.is_error()) {
|
||||
warnln("Failed to connect to the websocket server: {}\n", maybe_websocket_client.error());
|
||||
return maybe_websocket_client.release_error();
|
||||
|
@ -47,7 +47,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
|
||||
RefPtr<Line::Editor> editor = Line::Editor::construct();
|
||||
bool should_quit = false;
|
||||
auto socket = websocket_client->connect(url, origin);
|
||||
auto socket = websocket_client->websocket_connect(url, origin);
|
||||
if (!socket) {
|
||||
warnln("Failed to start socket for '{}'\n", url);
|
||||
return 1;
|
||||
|
|
Loading…
Add table
Reference in a new issue