From 7d7c419ce63d6ba70bff076962063b266d9c51ad Mon Sep 17 00:00:00 2001 From: Andrew Kaster Date: Wed, 2 Aug 2023 18:13:23 -0600 Subject: [PATCH] Ladybird: Add WebSocket server for use by Lagom networking Hide its use behind the same flag as RequestServer in WebContent. --- Ladybird/CMakeLists.txt | 4 +- Ladybird/HelperProcess.cpp | 33 ++++++++---- Ladybird/HelperProcess.h | 2 + Ladybird/RequestServer/main.cpp | 1 + Ladybird/WebContent/main.cpp | 12 +++-- Ladybird/WebSocket/CMakeLists.txt | 8 +++ Ladybird/WebSocket/main.cpp | 53 +++++++++++++++++++ Ladybird/cmake/InstallRules.cmake | 2 +- Meta/Lagom/CMakeLists.txt | 5 ++ Meta/gn/secondary/Ladybird/BUILD.gn | 3 ++ Meta/gn/secondary/Ladybird/WebSocket/BUILD.gn | 21 ++++++++ .../Userland/Libraries/LibProtocol/BUILD.gn | 32 +++++++++-- .../Userland/Libraries/LibWebView/BUILD.gn | 1 + Userland/Libraries/LibProtocol/CMakeLists.txt | 15 ++---- Userland/Services/CMakeLists.txt | 2 +- 15 files changed, 162 insertions(+), 32 deletions(-) create mode 100644 Ladybird/WebSocket/CMakeLists.txt create mode 100644 Ladybird/WebSocket/main.cpp create mode 100644 Meta/gn/secondary/Ladybird/WebSocket/BUILD.gn diff --git a/Ladybird/CMakeLists.txt b/Ladybird/CMakeLists.txt index 04c4c370ae4..3290d797c65 100644 --- a/Ladybird/CMakeLists.txt +++ b/Ladybird/CMakeLists.txt @@ -144,8 +144,9 @@ add_custom_target(debug${LADYBIRD_CUSTOM_TARGET_SUFFIX} add_subdirectory(SQLServer) add_subdirectory(WebContent) add_subdirectory(WebDriver) +add_subdirectory(WebSocket) add_subdirectory(RequestServer) -add_dependencies(ladybird SQLServer WebContent WebDriver RequestServer headless-browser) +add_dependencies(ladybird SQLServer WebContent WebDriver WebSocketServer RequestServer headless-browser) if (APPLE) # FIXME: Create a proper app bundle for each helper process @@ -156,6 +157,7 @@ if (APPLE) COMMAND "${CMAKE_COMMAND}" -E copy_if_different "$" "${app_dir}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "$" "${app_dir}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "$" "${app_dir}" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "$" "${app_dir}" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "$" "${app_dir}" ) endif() diff --git a/Ladybird/HelperProcess.cpp b/Ladybird/HelperProcess.cpp index 15bcab16ad0..c8453b221fd 100644 --- a/Ladybird/HelperProcess.cpp +++ b/Ladybird/HelperProcess.cpp @@ -87,36 +87,37 @@ ErrorOr> launch_web_content_process(Web return new_client; } -ErrorOr> launch_request_server_process(ReadonlySpan candidate_request_server_paths, StringView serenity_resource_root) +template +ErrorOr> launch_generic_server_process(ReadonlySpan candidate_server_paths, StringView serenity_resource_root, StringView server_name) { int socket_fds[2] {}; TRY(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fds)); int ui_fd = socket_fds[0]; - int rc_fd = socket_fds[1]; + int server_fd = socket_fds[1]; int fd_passing_socket_fds[2] {}; TRY(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, fd_passing_socket_fds)); int ui_fd_passing_fd = fd_passing_socket_fds[0]; - int rc_fd_passing_fd = fd_passing_socket_fds[1]; + int server_fd_passing_fd = fd_passing_socket_fds[1]; if (auto child_pid = TRY(Core::System::fork()); child_pid == 0) { TRY(Core::System::close(ui_fd)); TRY(Core::System::close(ui_fd_passing_fd)); - auto takeover_string = TRY(String::formatted("RequestServer:{}", rc_fd)); + auto takeover_string = TRY(String::formatted("{}:{}", server_name, server_fd)); TRY(Core::System::setenv("SOCKET_TAKEOVER"sv, takeover_string, true)); - auto fd_passing_socket_string = TRY(String::number(rc_fd_passing_fd)); + auto fd_passing_socket_string = TRY(String::number(server_fd_passing_fd)); ErrorOr result; - for (auto const& path : candidate_request_server_paths) { + for (auto const& path : candidate_server_paths) { if (Core::System::access(path, X_OK).is_error()) continue; - auto arguments = Vector { + auto arguments = Vector { path.bytes_as_string_view(), "--fd-passing-socket"sv, fd_passing_socket_string, @@ -130,18 +131,28 @@ ErrorOr> launch_request_server_process(Re } if (result.is_error()) - warnln("Could not launch any of {}: {}", candidate_request_server_paths, result.error()); + warnln("Could not launch any of {}: {}", candidate_server_paths, result.error()); VERIFY_NOT_REACHED(); } - TRY(Core::System::close(rc_fd)); - TRY(Core::System::close(rc_fd_passing_fd)); + TRY(Core::System::close(server_fd)); + TRY(Core::System::close(server_fd_passing_fd)); auto socket = TRY(Core::LocalSocket::adopt_fd(ui_fd)); TRY(socket->set_blocking(true)); - auto new_client = TRY(try_make_ref_counted(move(socket))); + auto new_client = TRY(try_make_ref_counted(move(socket))); new_client->set_fd_passing_socket(TRY(Core::LocalSocket::adopt_fd(ui_fd_passing_fd))); return new_client; } + +ErrorOr> launch_request_server_process(ReadonlySpan candidate_request_server_paths, StringView serenity_resource_root) +{ + return launch_generic_server_process(candidate_request_server_paths, serenity_resource_root, "RequestServer"sv); +} + +ErrorOr> launch_web_socket_process(ReadonlySpan candidate_web_socket_paths, StringView serenity_resource_root) +{ + return launch_generic_server_process(candidate_web_socket_paths, serenity_resource_root, "WebSocket"sv); +} diff --git a/Ladybird/HelperProcess.h b/Ladybird/HelperProcess.h index 29eac705641..d5013bc5383 100644 --- a/Ladybird/HelperProcess.h +++ b/Ladybird/HelperProcess.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -22,3 +23,4 @@ ErrorOr> launch_web_content_process(Web Ladybird::UseLagomNetworking); ErrorOr> launch_request_server_process(ReadonlySpan candidate_request_server_paths, StringView serenity_resource_root); +ErrorOr> launch_web_socket_process(ReadonlySpan candidate_web_socket_paths, StringView serenity_resource_root); diff --git a/Ladybird/RequestServer/main.cpp b/Ladybird/RequestServer/main.cpp index a8ceb567eb5..a0934eea9fa 100644 --- a/Ladybird/RequestServer/main.cpp +++ b/Ladybird/RequestServer/main.cpp @@ -20,6 +20,7 @@ #include #include +// FIXME: Share b/w RequestServer and WebSocket ErrorOr find_certificates(StringView serenity_resource_root) { auto cert_path = TRY(String::formatted("{}/res/ladybird/cacert.pem", serenity_resource_root)); diff --git a/Ladybird/WebContent/main.cpp b/Ladybird/WebContent/main.cpp index edaf4388491..233e25adf30 100644 --- a/Ladybird/WebContent/main.cpp +++ b/Ladybird/WebContent/main.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -56,8 +57,6 @@ ErrorOr serenity_main(Main::Arguments arguments) return Ladybird::AudioCodecPluginQt::create(move(loader)); }); - Web::WebSockets::WebSocketClientManager::initialize(Ladybird::WebSocketClientManagerQt::create()); - Web::FrameLoader::set_default_favicon_path(DeprecatedString::formatted("{}/res/icons/16x16/app-browser.png", s_serenity_resource_root)); int webcontent_fd_passing_socket { -1 }; @@ -74,10 +73,15 @@ ErrorOr serenity_main(Main::Arguments arguments) if (use_lagom_networking) { auto candidate_request_server_paths = TRY(get_paths_for_helper_process("RequestServer"sv)); - auto protocol_client = TRY(launch_request_server_process(candidate_request_server_paths, s_serenity_resource_root)); - Web::ResourceLoader::initialize(TRY(WebView::RequestServerAdapter::try_create(move(protocol_client)))); + auto request_server_client = TRY(launch_request_server_process(candidate_request_server_paths, s_serenity_resource_root)); + 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)); + Web::WebSockets::WebSocketClientManager::initialize(TRY(WebView::WebSocketClientManagerAdapter::try_create(move(web_socket_client)))); } else { Web::ResourceLoader::initialize(Ladybird::RequestManagerQt::create()); + Web::WebSockets::WebSocketClientManager::initialize(Ladybird::WebSocketClientManagerQt::create()); } JS::Bytecode::Interpreter::set_enabled(use_javascript_bytecode); diff --git a/Ladybird/WebSocket/CMakeLists.txt b/Ladybird/WebSocket/CMakeLists.txt new file mode 100644 index 00000000000..86066d836d3 --- /dev/null +++ b/Ladybird/WebSocket/CMakeLists.txt @@ -0,0 +1,8 @@ +set(SOURCES + "${SERENITY_SOURCE_DIR}/Userland/Services/WebSocket/ConnectionFromClient.cpp" + main.cpp +) + +add_executable(WebSocketServer ${SOURCES}) +set_target_properties(WebSocketServer PROPERTIES OUTPUT_NAME WebSocket) +target_link_libraries(WebSocketServer PRIVATE LibCore LibFileSystem LibIPC LibMain LibTLS LibWebSocket LibWebView) diff --git a/Ladybird/WebSocket/main.cpp b/Ladybird/WebSocket/main.cpp new file mode 100644 index 00000000000..0e2de2395b9 --- /dev/null +++ b/Ladybird/WebSocket/main.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2021, Dex♪ + * Copyright (c) 2023, Andrew Kaster + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// FIXME: Share b/w RequestServer and WebSocket +ErrorOr find_certificates(StringView serenity_resource_root) +{ + auto cert_path = TRY(String::formatted("{}/res/ladybird/cacert.pem", serenity_resource_root)); + if (!FileSystem::exists(cert_path)) { + auto app_dir = LexicalPath::dirname(TRY(Core::System::current_executable_path()).to_deprecated_string()); + + cert_path = TRY(String::formatted("{}/cacert.pem", LexicalPath(app_dir).parent())); + if (!FileSystem::exists(cert_path)) + return Error::from_string_view("Don't know how to load certs!"sv); + } + return cert_path; +} + +ErrorOr serenity_main(Main::Arguments arguments) +{ + int fd_passing_socket { -1 }; + StringView serenity_resource_root; + + 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(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. + DefaultRootCACertificates::set_default_certificate_path(TRY(find_certificates(serenity_resource_root))); + [[maybe_unused]] auto& certs = DefaultRootCACertificates::the(); + + Core::EventLoop event_loop; + + auto client = TRY(IPC::take_over_accepted_client_from_system_server()); + client->set_fd_passing_socket(TRY(Core::LocalSocket::adopt_fd(fd_passing_socket))); + + return event_loop.exec(); +} diff --git a/Ladybird/cmake/InstallRules.cmake b/Ladybird/cmake/InstallRules.cmake index 0b9e690b19a..5b71df7d71b 100644 --- a/Ladybird/cmake/InstallRules.cmake +++ b/Ladybird/cmake/InstallRules.cmake @@ -4,7 +4,7 @@ include(GNUInstallDirs) set(package ladybird) -set(ladybird_applications ladybird SQLServer WebContent WebDriver RequestServer headless-browser) +set(ladybird_applications ladybird SQLServer WebContent WebDriver WebSocketServer RequestServer headless-browser) set(app_install_targets ${ladybird_applications}) if (ANDROID) diff --git a/Meta/Lagom/CMakeLists.txt b/Meta/Lagom/CMakeLists.txt index 718b27992f7..4c8725a4cf6 100644 --- a/Meta/Lagom/CMakeLists.txt +++ b/Meta/Lagom/CMakeLists.txt @@ -432,6 +432,7 @@ if (BUILD_LAGOM) list(APPEND LIBWEBVIEW_SOURCES "../../Userland/Libraries/LibWebView/ViewImplementation.cpp") list(APPEND LIBWEBVIEW_SOURCES "../../Userland/Libraries/LibWebView/WebContentClient.cpp") list(APPEND LIBWEBVIEW_SOURCES "../../Userland/Libraries/LibWebView/RequestServerAdapter.cpp") + list(APPEND LIBWEBVIEW_SOURCES "../../Userland/Libraries/LibWebView/WebSocketClientAdapter.cpp") compile_ipc(${SERENITY_PROJECT_ROOT}/Userland/Services/WebContent/WebContentServer.ipc WebContent/WebContentServerEndpoint.h) compile_ipc(${SERENITY_PROJECT_ROOT}/Userland/Services/WebContent/WebContentClient.ipc WebContent/WebContentClientEndpoint.h) @@ -439,6 +440,8 @@ if (BUILD_LAGOM) compile_ipc(${SERENITY_PROJECT_ROOT}/Userland/Services/WebContent/WebDriverServer.ipc WebContent/WebDriverServerEndpoint.h) compile_ipc(${SERENITY_PROJECT_ROOT}/Userland/Services/RequestServer/RequestClient.ipc RequestServer/RequestClientEndpoint.h) compile_ipc(${SERENITY_PROJECT_ROOT}/Userland/Services/RequestServer/RequestServer.ipc RequestServer/RequestServerEndpoint.h) + compile_ipc(${SERENITY_PROJECT_ROOT}/Userland/Services/WebSocket/WebSocketClient.ipc WebSocket/WebSocketClientEndpoint.h) + compile_ipc(${SERENITY_PROJECT_ROOT}/Userland/Services/WebSocket/WebSocketServer.ipc WebSocket/WebSocketServerEndpoint.h) list(APPEND LIBWEBVIEW_GENERATED_SOURCES WebContent/WebContentClientEndpoint.h) list(APPEND LIBWEBVIEW_GENERATED_SOURCES WebContent/WebContentServerEndpoint.h) @@ -446,6 +449,8 @@ if (BUILD_LAGOM) list(APPEND LIBWEBVIEW_GENERATED_SOURCES WebContent/WebDriverServerEndpoint.h) list(APPEND LIBWEBVIEW_GENERATED_SOURCES RequestServer/RequestClientEndpoint.h) list(APPEND LIBWEBVIEW_GENERATED_SOURCES RequestServer/RequestServerEndpoint.h) + list(APPEND LIBWEBVIEW_GENERATED_SOURCES WebSocket/WebSocketClientEndpoint.h) + list(APPEND LIBWEBVIEW_GENERATED_SOURCES WebSocket/WebSocketServerEndpoint.h) set(GENERATED_SOURCES ${LIBWEBVIEW_GENERATED_SOURCES}) lagom_lib(LibWebView webview diff --git a/Meta/gn/secondary/Ladybird/BUILD.gn b/Meta/gn/secondary/Ladybird/BUILD.gn index 0b3be502f03..8d6ffc9488e 100644 --- a/Meta/gn/secondary/Ladybird/BUILD.gn +++ b/Meta/gn/secondary/Ladybird/BUILD.gn @@ -56,6 +56,7 @@ executable("ladybird_executable") { "SQLServer", "WebContent", "WebDriver", + "WebSocket", ] deps = [ ":compile_resource_file", @@ -149,12 +150,14 @@ if (current_os == "mac") { "SQLServer", "WebContent", "WebDriver", + "WebSocket", ] sources = [ "$root_out_dir/bin/RequestServer", "$root_out_dir/bin/SQLServer", "$root_out_dir/bin/WebContent", "$root_out_dir/bin/WebDriver", + "$root_out_dir/bin/WebSocket", "$root_out_dir/bin/headless-browser", "$root_out_dir/bin/ladybird", ] diff --git a/Meta/gn/secondary/Ladybird/WebSocket/BUILD.gn b/Meta/gn/secondary/Ladybird/WebSocket/BUILD.gn new file mode 100644 index 00000000000..da599caf6c3 --- /dev/null +++ b/Meta/gn/secondary/Ladybird/WebSocket/BUILD.gn @@ -0,0 +1,21 @@ +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", + ] +} diff --git a/Meta/gn/secondary/Userland/Libraries/LibProtocol/BUILD.gn b/Meta/gn/secondary/Userland/Libraries/LibProtocol/BUILD.gn index d394a5ec84e..4c35a513391 100644 --- a/Meta/gn/secondary/Userland/Libraries/LibProtocol/BUILD.gn +++ b/Meta/gn/secondary/Userland/Libraries/LibProtocol/BUILD.gn @@ -22,6 +22,28 @@ 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 = [ @@ -31,6 +53,8 @@ shared_library("LibProtocol") { deps = [ ":RequestClientEndpoint", ":RequestServerEndpoint", + ":WebSocketClientEndpoint", + ":WebSocketServerEndpoint", "//AK", "//Userland/Libraries/LibCore", "//Userland/Libraries/LibIPC", @@ -38,9 +62,11 @@ shared_library("LibProtocol") { sources = [ "Request.cpp", "RequestClient.cpp", - - # TODO: Add WebSocket sources + IPC + "WebSocket.cpp", + "WebSocketClient.cpp", ] sources += get_target_outputs(":RequestClientEndpoint") + - get_target_outputs(":RequestServerEndpoint") + get_target_outputs(":RequestServerEndpoint") + + get_target_outputs(":WebSocketClientEndpoint") + + get_target_outputs(":WebSocketServerEndpoint") } diff --git a/Meta/gn/secondary/Userland/Libraries/LibWebView/BUILD.gn b/Meta/gn/secondary/Userland/Libraries/LibWebView/BUILD.gn index d0b6ca71d64..63f91ad8526 100644 --- a/Meta/gn/secondary/Userland/Libraries/LibWebView/BUILD.gn +++ b/Meta/gn/secondary/Userland/Libraries/LibWebView/BUILD.gn @@ -71,6 +71,7 @@ shared_library("LibWebView") { "StylePropertiesModel.cpp", "ViewImplementation.cpp", "WebContentClient.cpp", + "WebSocketClientAdapter.cpp", ] sources += get_target_outputs(":WebContentClientEndpoint") + get_target_outputs(":WebContentServerEndpoint") + diff --git a/Userland/Libraries/LibProtocol/CMakeLists.txt b/Userland/Libraries/LibProtocol/CMakeLists.txt index 3491da7ffbc..95d340b6993 100644 --- a/Userland/Libraries/LibProtocol/CMakeLists.txt +++ b/Userland/Libraries/LibProtocol/CMakeLists.txt @@ -1,23 +1,16 @@ 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 ) -if (SERENITYOS) - list(APPEND SOURCES - WebSocket.cpp - WebSocketClient.cpp - ) - list(APPEND GENERATED_SOURCES - ../../Services/WebSocket/WebSocketClientEndpoint.h - ../../Services/WebSocket/WebSocketServerEndpoint.h - ) -endif() - serenity_lib(LibProtocol protocol) target_link_libraries(LibProtocol PRIVATE LibCore LibIPC) diff --git a/Userland/Services/CMakeLists.txt b/Userland/Services/CMakeLists.txt index b023e6cfabb..cbdea1d640a 100644 --- a/Userland/Services/CMakeLists.txt +++ b/Userland/Services/CMakeLists.txt @@ -4,7 +4,6 @@ add_subdirectory(FileOperation) add_subdirectory(ImageDecoder) add_subdirectory(LookupServer) add_subdirectory(WebServer) -add_subdirectory(WebSocket) if (SERENITYOS) add_subdirectory(AudioServer) @@ -26,5 +25,6 @@ if (SERENITYOS) add_subdirectory(TelnetServer) add_subdirectory(WebContent) add_subdirectory(WebDriver) + add_subdirectory(WebSocket) add_subdirectory(WindowServer) endif()