mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 16:52:43 +00:00 
			
		
		
		
	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
					
				
					 56 changed files with 231 additions and 845 deletions
				
			
		|  | @ -56,11 +56,6 @@ | ||||||
|             android:enabled="true" |             android:enabled="true" | ||||||
|             android:exported="false" |             android:exported="false" | ||||||
|             android:process=":RequestServer" /> |             android:process=":RequestServer" /> | ||||||
|         <service |  | ||||||
|             android:name=".WebSocketService" |  | ||||||
|             android:enabled="true" |  | ||||||
|             android:exported="false" |  | ||||||
|             android:process=":WebSocket" /> |  | ||||||
|         <service |         <service | ||||||
|             android:name=".ImageDecoderService" |             android:name=".ImageDecoderService" | ||||||
|             android:enabled="true" |             android:enabled="true" | ||||||
|  |  | ||||||
|  | @ -28,7 +28,6 @@ | ||||||
| #include <LibWeb/Platform/AudioCodecPluginAgnostic.h> | #include <LibWeb/Platform/AudioCodecPluginAgnostic.h> | ||||||
| #include <LibWeb/Platform/EventLoopPluginSerenity.h> | #include <LibWeb/Platform/EventLoopPluginSerenity.h> | ||||||
| #include <LibWebView/RequestServerAdapter.h> | #include <LibWebView/RequestServerAdapter.h> | ||||||
| #include <LibWebView/WebSocketClientAdapter.h> |  | ||||||
| #include <WebContent/ConnectionFromClient.h> | #include <WebContent/ConnectionFromClient.h> | ||||||
| #include <WebContent/PageHost.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); |     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> | template ErrorOr<NonnullRefPtr<ImageDecoderClient::Client>, Error> | ||||||
| bind_service<ImageDecoderClient::Client>(void (*)(int, int)); | 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()); |     auto request_server_client = TRY(bind_request_server_service()); | ||||||
|     Web::ResourceLoader::initialize(TRY(WebView::RequestServerAdapter::try_create(move(request_server_client)))); |     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; |     bool is_layout_test_mode = false; | ||||||
| 
 | 
 | ||||||
|     Web::HTML::Window::set_internals_object_exposed(is_layout_test_mode); |     Web::HTML::Window::set_internals_object_exposed(is_layout_test_mode); | ||||||
|  |  | ||||||
|  | @ -11,7 +11,6 @@ | ||||||
| jobject global_instance; | jobject global_instance; | ||||||
| jclass global_class_reference; | jclass global_class_reference; | ||||||
| jmethodID bind_request_server_method; | jmethodID bind_request_server_method; | ||||||
| jmethodID bind_web_socket_method; |  | ||||||
| jmethodID bind_image_decoder_method; | jmethodID bind_image_decoder_method; | ||||||
| 
 | 
 | ||||||
| extern "C" JNIEXPORT void JNICALL | extern "C" JNIEXPORT void JNICALL | ||||||
|  | @ -30,11 +29,6 @@ Java_org_serenityos_ladybird_WebContentService_nativeInit(JNIEnv* env, jobject t | ||||||
|         TODO(); |         TODO(); | ||||||
|     bind_request_server_method = method; |     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"); |     method = env->GetMethodID(global_class_reference, "bindImageDecoder", "(II)V"); | ||||||
|     if (!method) |     if (!method) | ||||||
|         TODO(); |         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); |     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) | void bind_image_decoder_java(int ipc_socket, int fd_passing_socket) | ||||||
| { | { | ||||||
|     Ladybird::JavaEnvironment env(global_vm); |     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) |     private fun bindImageDecoder(ipcFd: Int, fdPassingFd: Int) | ||||||
|     { |     { | ||||||
|         val connector = LadybirdServiceConnection(ipcFd, fdPassingFd, resourceDir) |         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(SQLServer) | ||||||
| add_subdirectory(WebContent) | add_subdirectory(WebContent) | ||||||
| add_subdirectory(WebDriver) | add_subdirectory(WebDriver) | ||||||
| add_subdirectory(WebSocket) |  | ||||||
| add_subdirectory(WebWorker) | 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}) | add_dependencies(ladybird ${ladybird_helper_processes}) | ||||||
| 
 | 
 | ||||||
| function(create_ladybird_bundle target_name) | 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); |     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 <AK/StringView.h> | ||||||
| #include <LibImageDecoderClient/Client.h> | #include <LibImageDecoderClient/Client.h> | ||||||
| #include <LibProtocol/RequestClient.h> | #include <LibProtocol/RequestClient.h> | ||||||
| #include <LibProtocol/WebSocketClient.h> |  | ||||||
| #include <LibWeb/Worker/WebWorkerClient.h> | #include <LibWeb/Worker/WebWorkerClient.h> | ||||||
| #include <LibWebView/ViewImplementation.h> | #include <LibWebView/ViewImplementation.h> | ||||||
| #include <LibWebView/WebContentClient.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<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<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::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 "RequestManagerQt.h" | ||||||
|  | #include "WebSocketImplQt.h" | ||||||
|  | #include "WebSocketQt.h" | ||||||
| #include <AK/JsonObject.h> | #include <AK/JsonObject.h> | ||||||
| #include <QNetworkCookie> | #include <QNetworkCookie> | ||||||
| 
 | 
 | ||||||
|  | @ -76,6 +78,18 @@ ErrorOr<NonnullRefPtr<RequestManagerQt::Request>> RequestManagerQt::Request::cre | ||||||
|     return adopt_ref(*new Request(*reply)); |     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) | RequestManagerQt::Request::Request(QNetworkReply& reply) | ||||||
|     : m_reply(reply) |     : m_reply(reply) | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -28,6 +28,7 @@ public: | ||||||
|     virtual void preconnect(URL const&) override { } |     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::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: | private slots: | ||||||
|     void reply_finished(QNetworkReply*); |     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 ${SERENITY_SOURCE_DIR}/Userland/Services/) | ||||||
| target_include_directories(requestserver PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/..) | 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") | if (${CMAKE_SYSTEM_NAME} MATCHES "SunOS") | ||||||
|     # Solaris has socket and networking related functions in two extra libraries |     # Solaris has socket and networking related functions in two extra libraries | ||||||
|     target_link_libraries(requestserver PUBLIC nsl socket) |     target_link_libraries(requestserver PUBLIC nsl socket) | ||||||
|  |  | ||||||
|  | @ -21,7 +21,6 @@ if (ENABLE_QT) | ||||||
|         ../Qt/EventLoopImplementationQtEventTarget.cpp |         ../Qt/EventLoopImplementationQtEventTarget.cpp | ||||||
|         ../Qt/RequestManagerQt.cpp |         ../Qt/RequestManagerQt.cpp | ||||||
|         ../Qt/StringUtils.cpp |         ../Qt/StringUtils.cpp | ||||||
|         ../Qt/WebSocketClientManagerQt.cpp |  | ||||||
|         ../Qt/WebSocketQt.cpp |         ../Qt/WebSocketQt.cpp | ||||||
|         ../Qt/WebSocketImplQt.cpp |         ../Qt/WebSocketImplQt.cpp | ||||||
|         main.cpp |         main.cpp | ||||||
|  |  | ||||||
|  | @ -38,7 +38,6 @@ | ||||||
| #if defined(HAVE_QT) | #if defined(HAVE_QT) | ||||||
| #    include <Ladybird/Qt/EventLoopImplementationQt.h> | #    include <Ladybird/Qt/EventLoopImplementationQt.h> | ||||||
| #    include <Ladybird/Qt/RequestManagerQt.h> | #    include <Ladybird/Qt/RequestManagerQt.h> | ||||||
| #    include <Ladybird/Qt/WebSocketClientManagerQt.h> |  | ||||||
| #    include <QCoreApplication> | #    include <QCoreApplication> | ||||||
| 
 | 
 | ||||||
| #    if defined(HAVE_QT_MULTIMEDIA) | #    if defined(HAVE_QT_MULTIMEDIA) | ||||||
|  | @ -109,14 +108,11 @@ ErrorOr<int> serenity_main(Main::Arguments arguments) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| #if defined(HAVE_QT) | #if defined(HAVE_QT) | ||||||
|     if (!use_lagom_networking) { |     if (!use_lagom_networking) | ||||||
|         Web::ResourceLoader::initialize(Ladybird::RequestManagerQt::create()); |         Web::ResourceLoader::initialize(Ladybird::RequestManagerQt::create()); | ||||||
|         Web::WebSockets::WebSocketClientManager::initialize(Ladybird::WebSocketClientManagerQt::create()); |     else | ||||||
|     } else |  | ||||||
| #endif | #endif | ||||||
|     { |  | ||||||
|         TRY(initialize_lagom_networking(certificates)); |         TRY(initialize_lagom_networking(certificates)); | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     Web::HTML::Window::set_internals_object_exposed(is_layout_test_mode); |     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)); |     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)))); |     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 {}; |     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)); |     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)))); |     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 {}; |     return {}; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -486,8 +486,6 @@ if (BUILD_LAGOM) | ||||||
|     # These are needed for both LibWeb and LibProtocol. |     # 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/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/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) |     if (ENABLE_LAGOM_LIBWEB) | ||||||
|         list(APPEND lagom_standard_libraries Web WebView) |         list(APPEND lagom_standard_libraries Web WebView) | ||||||
|  |  | ||||||
|  | @ -335,7 +335,6 @@ if (current_os != "mac") { | ||||||
|       "$root_out_dir/libexec/SQLServer", |       "$root_out_dir/libexec/SQLServer", | ||||||
|       "$root_out_dir/libexec/WebContent", |       "$root_out_dir/libexec/WebContent", | ||||||
|       "$root_out_dir/libexec/WebDriver", |       "$root_out_dir/libexec/WebDriver", | ||||||
|       "$root_out_dir/libexec/WebSocket", |  | ||||||
|       "$root_out_dir/libexec/WebWorker", |       "$root_out_dir/libexec/WebWorker", | ||||||
|       "$root_out_dir/libexec/headless-browser", |       "$root_out_dir/libexec/headless-browser", | ||||||
|     ] |     ] | ||||||
|  |  | ||||||
|  | @ -15,6 +15,7 @@ executable("RequestServer") { | ||||||
|     "//Userland/Libraries/LibMain", |     "//Userland/Libraries/LibMain", | ||||||
|     "//Userland/Libraries/LibProtocol", |     "//Userland/Libraries/LibProtocol", | ||||||
|     "//Userland/Libraries/LibTLS", |     "//Userland/Libraries/LibTLS", | ||||||
|  |     "//Userland/Libraries/LibWebSocket", | ||||||
|   ] |   ] | ||||||
|   sources = [ |   sources = [ | ||||||
|     "//Userland/Services/RequestServer/ConnectionCache.cpp", |     "//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") { | shared_library("LibProtocol") { | ||||||
|   output_name = "protocol" |   output_name = "protocol" | ||||||
|   include_dirs = [ |   include_dirs = [ | ||||||
|  | @ -53,8 +31,6 @@ shared_library("LibProtocol") { | ||||||
|   deps = [ |   deps = [ | ||||||
|     ":RequestClientEndpoint", |     ":RequestClientEndpoint", | ||||||
|     ":RequestServerEndpoint", |     ":RequestServerEndpoint", | ||||||
|     ":WebSocketClientEndpoint", |  | ||||||
|     ":WebSocketServerEndpoint", |  | ||||||
|     "//AK", |     "//AK", | ||||||
|     "//Userland/Libraries/LibCore", |     "//Userland/Libraries/LibCore", | ||||||
|     "//Userland/Libraries/LibIPC", |     "//Userland/Libraries/LibIPC", | ||||||
|  | @ -63,10 +39,7 @@ shared_library("LibProtocol") { | ||||||
|     "Request.cpp", |     "Request.cpp", | ||||||
|     "RequestClient.cpp", |     "RequestClient.cpp", | ||||||
|     "WebSocket.cpp", |     "WebSocket.cpp", | ||||||
|     "WebSocketClient.cpp", |  | ||||||
|   ] |   ] | ||||||
|   sources += get_target_outputs(":RequestClientEndpoint") + |   sources += get_target_outputs(":RequestClientEndpoint") + | ||||||
|              get_target_outputs(":RequestServerEndpoint") + |              get_target_outputs(":RequestServerEndpoint") | ||||||
|              get_target_outputs(":WebSocketClientEndpoint") + |  | ||||||
|              get_target_outputs(":WebSocketServerEndpoint") |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -2,7 +2,7 @@ serenity_component( | ||||||
|     Browser |     Browser | ||||||
|     RECOMMENDED |     RECOMMENDED | ||||||
|     TARGETS Browser |     TARGETS Browser | ||||||
|     DEPENDS BrowserSettings ImageDecoder RequestServer WebContent WebSocket |     DEPENDS BrowserSettings ImageDecoder RequestServer WebContent | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| stringify_gml(BrowserWindow.gml BrowserWindowGML.h browser_window_gml) | stringify_gml(BrowserWindow.gml BrowserWindowGML.h browser_window_gml) | ||||||
|  |  | ||||||
|  | @ -2,14 +2,11 @@ set(SOURCES | ||||||
|     Request.cpp |     Request.cpp | ||||||
|     RequestClient.cpp |     RequestClient.cpp | ||||||
|     WebSocket.cpp |     WebSocket.cpp | ||||||
|     WebSocketClient.cpp |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| set(GENERATED_SOURCES | set(GENERATED_SOURCES | ||||||
|     ../../Services/RequestServer/RequestClientEndpoint.h |     ../../Services/RequestServer/RequestClientEndpoint.h | ||||||
|     ../../Services/RequestServer/RequestServerEndpoint.h |     ../../Services/RequestServer/RequestServerEndpoint.h | ||||||
|     ../../Services/WebSocket/WebSocketClientEndpoint.h |  | ||||||
|     ../../Services/WebSocket/WebSocketServerEndpoint.h |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| serenity_lib(LibProtocol protocol) | 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&); | 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 <AK/HashMap.h> | ||||||
| #include <LibIPC/ConnectionToServer.h> | #include <LibIPC/ConnectionToServer.h> | ||||||
|  | #include <LibProtocol/WebSocket.h> | ||||||
|  | #include <LibWebSocket/WebSocket.h> | ||||||
| #include <RequestServer/RequestClientEndpoint.h> | #include <RequestServer/RequestClientEndpoint.h> | ||||||
| #include <RequestServer/RequestServerEndpoint.h> | #include <RequestServer/RequestServerEndpoint.h> | ||||||
| 
 | 
 | ||||||
|  | @ -26,6 +28,8 @@ public: | ||||||
|     template<typename RequestHashMapTraits = Traits<ByteString>> |     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<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); |     void ensure_connection(URL const&, ::RequestServer::CacheLevel); | ||||||
| 
 | 
 | ||||||
|     bool stop_request(Badge<Request>, Request&); |     bool stop_request(Badge<Request>, Request&); | ||||||
|  | @ -38,7 +42,14 @@ private: | ||||||
|     virtual void certificate_requested(i32) override; |     virtual void certificate_requested(i32) override; | ||||||
|     virtual void headers_became_available(i32, HashMap<ByteString, ByteString, CaseInsensitiveStringTraits> const&, Optional<u32> const&) 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, RefPtr<Request>> m_requests; | ||||||
|  |     HashMap<i32, NonnullRefPtr<WebSocket>> m_websockets; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -4,12 +4,12 @@ | ||||||
|  * SPDX-License-Identifier: BSD-2-Clause |  * SPDX-License-Identifier: BSD-2-Clause | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
|  | #include <LibProtocol/RequestClient.h> | ||||||
| #include <LibProtocol/WebSocket.h> | #include <LibProtocol/WebSocket.h> | ||||||
| #include <LibProtocol/WebSocketClient.h> |  | ||||||
| 
 | 
 | ||||||
| namespace Protocol { | namespace Protocol { | ||||||
| 
 | 
 | ||||||
| WebSocket::WebSocket(WebSocketClient& client, i32 connection_id) | WebSocket::WebSocket(RequestClient& client, i32 connection_id) | ||||||
|     : m_client(client) |     : m_client(client) | ||||||
|     , m_connection_id(connection_id) |     , m_connection_id(connection_id) | ||||||
| { | { | ||||||
|  | @ -17,17 +17,17 @@ WebSocket::WebSocket(WebSocketClient& client, i32 connection_id) | ||||||
| 
 | 
 | ||||||
| WebSocket::ReadyState WebSocket::ready_state() | 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() | 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) | 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) | void WebSocket::send(StringView text_message) | ||||||
|  | @ -37,38 +37,38 @@ void WebSocket::send(StringView text_message) | ||||||
| 
 | 
 | ||||||
| void WebSocket::close(u16 code, ByteString reason) | 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) |     if (on_open) | ||||||
|         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) |     if (on_message) | ||||||
|         on_message(WebSocket::Message { move(data), is_text }); |         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) |     if (on_error) | ||||||
|         on_error((WebSocket::Error)error_code); |         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) |     if (on_close) | ||||||
|         on_close(code, move(reason), was_clean); |         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) { |     if (on_certificate_requested) { | ||||||
|         auto result = 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"); |             dbgln("WebSocket: set_certificate failed"); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -17,7 +17,7 @@ | ||||||
| 
 | 
 | ||||||
| namespace Protocol { | namespace Protocol { | ||||||
| 
 | 
 | ||||||
| class WebSocketClient; | class RequestClient; | ||||||
| 
 | 
 | ||||||
| class WebSocket : public RefCounted<WebSocket> { | class WebSocket : public RefCounted<WebSocket> { | ||||||
| public: | public: | ||||||
|  | @ -44,7 +44,7 @@ public: | ||||||
|         Closed = 3, |         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)); |         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<void(u16 code, ByteString reason, bool was_clean)> on_close; | ||||||
|     Function<CertificateAndKey()> on_certificate_requested; |     Function<CertificateAndKey()> on_certificate_requested; | ||||||
| 
 | 
 | ||||||
|     void did_open(Badge<WebSocketClient>); |     void did_open(Badge<RequestClient>); | ||||||
|     void did_receive(Badge<WebSocketClient>, ByteBuffer, bool); |     void did_receive(Badge<RequestClient>, ByteBuffer, bool); | ||||||
|     void did_error(Badge<WebSocketClient>, i32); |     void did_error(Badge<RequestClient>, i32); | ||||||
|     void did_close(Badge<WebSocketClient>, u16, ByteString, bool); |     void did_close(Badge<RequestClient>, u16, ByteString, bool); | ||||||
|     void did_request_certificates(Badge<WebSocketClient>); |     void did_request_certificates(Badge<RequestClient>); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     explicit WebSocket(WebSocketClient&, i32 connection_id); |     explicit WebSocket(RequestClient&, i32 connection_id); | ||||||
|     WeakPtr<WebSocketClient> m_client; |     WeakPtr<RequestClient> m_client; | ||||||
|     int m_connection_id { -1 }; |     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_user_agent = "Mozilla/5.0 (" OS_STRING "; " CPU_STRING ") " BROWSER_NAME "/" BROWSER_VERSION ""sv; | ||||||
| constexpr auto default_platform = OS_STRING " " CPU_STRING ""sv; | constexpr auto default_platform = OS_STRING " " CPU_STRING ""sv; | ||||||
| 
 | 
 | ||||||
|  | namespace WebSockets { | ||||||
|  | class WebSocketClientSocket; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| class ResourceLoaderConnectorRequest : public RefCounted<ResourceLoaderConnectorRequest> { | class ResourceLoaderConnectorRequest : public RefCounted<ResourceLoaderConnectorRequest> { | ||||||
| public: | public: | ||||||
|     virtual ~ResourceLoaderConnectorRequest(); |     virtual ~ResourceLoaderConnectorRequest(); | ||||||
|  | @ -97,6 +101,7 @@ public: | ||||||
|     virtual void preconnect(URL const&) = 0; |     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<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: | protected: | ||||||
|     explicit ResourceLoaderConnector(); |     explicit ResourceLoaderConnector(); | ||||||
|  |  | ||||||
|  | @ -19,6 +19,7 @@ | ||||||
| #include <LibWeb/HTML/MessageEvent.h> | #include <LibWeb/HTML/MessageEvent.h> | ||||||
| #include <LibWeb/HTML/Origin.h> | #include <LibWeb/HTML/Origin.h> | ||||||
| #include <LibWeb/HTML/Window.h> | #include <LibWeb/HTML/Window.h> | ||||||
|  | #include <LibWeb/Loader/ResourceLoader.h> | ||||||
| #include <LibWeb/WebIDL/AbstractOperations.h> | #include <LibWeb/WebIDL/AbstractOperations.h> | ||||||
| #include <LibWeb/WebIDL/Buffers.h> | #include <LibWeb/WebIDL/Buffers.h> | ||||||
| #include <LibWeb/WebIDL/DOMException.h> | #include <LibWeb/WebIDL/DOMException.h> | ||||||
|  | @ -29,28 +30,8 @@ namespace Web::WebSockets { | ||||||
| 
 | 
 | ||||||
| JS_DEFINE_ALLOCATOR(WebSocket); | 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; | WebSocketClientSocket::~WebSocketClientSocket() = default; | ||||||
| 
 | 
 | ||||||
| WebSocketClientManager::WebSocketClientManager() = default; |  | ||||||
| 
 |  | ||||||
| // https://websockets.spec.whatwg.org/#dom-websocket-websocket
 | // 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) | 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) |     for (auto const& protocol : protocols) | ||||||
|         TRY(protcol_byte_strings.try_append(protocol.to_byte_string())); |         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>()] { |     m_websocket->on_open = [weak_this = make_weak_ptr<WebSocket>()] { | ||||||
|         if (!weak_this) |         if (!weak_this) | ||||||
|             return; |             return; | ||||||
|  |  | ||||||
|  | @ -114,19 +114,7 @@ public: | ||||||
|     Function<CertificateAndKey()> on_certificate_requested; |     Function<CertificateAndKey()> on_certificate_requested; | ||||||
| 
 | 
 | ||||||
| protected: | protected: | ||||||
|     explicit WebSocketClientSocket(); |     explicit WebSocketClientSocket() = default; | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| 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(); |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -40,8 +40,6 @@ set(GENERATED_SOURCES | ||||||
|     ../../Services/WebContent/WebContentServerEndpoint.h |     ../../Services/WebContent/WebContentServerEndpoint.h | ||||||
|     ../../Services/WebContent/WebDriverClientEndpoint.h |     ../../Services/WebContent/WebDriverClientEndpoint.h | ||||||
|     ../../Services/WebContent/WebDriverServerEndpoint.h |     ../../Services/WebContent/WebDriverServerEndpoint.h | ||||||
|     ../../Services/WebSocket/WebSocketClientEndpoint.h |  | ||||||
|     ../../Services/WebSocket/WebSocketServerEndpoint.h |  | ||||||
|     NativeStyleSheetSource.cpp |     NativeStyleSheetSource.cpp | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -4,6 +4,7 @@ | ||||||
|  * SPDX-License-Identifier: BSD-2-Clause |  * SPDX-License-Identifier: BSD-2-Clause | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
|  | #include "WebSocketClientAdapter.h" | ||||||
| #include <LibProtocol/Request.h> | #include <LibProtocol/Request.h> | ||||||
| #include <LibProtocol/RequestClient.h> | #include <LibProtocol/RequestClient.h> | ||||||
| #include <LibWebView/RequestServerAdapter.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(); |     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) | void RequestServerAdapter::prefetch_dns(URL const& url) | ||||||
| { | { | ||||||
|     m_protocol_client->ensure_connection(url, RequestServer::CacheLevel::ResolveOnly); |     m_protocol_client->ensure_connection(url, RequestServer::CacheLevel::ResolveOnly); | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ | ||||||
| #include <AK/Function.h> | #include <AK/Function.h> | ||||||
| #include <AK/URL.h> | #include <AK/URL.h> | ||||||
| #include <LibWeb/Loader/ResourceLoader.h> | #include <LibWeb/Loader/ResourceLoader.h> | ||||||
|  | #include <LibWeb/WebSockets/WebSocket.h> | ||||||
| 
 | 
 | ||||||
| namespace Protocol { | namespace Protocol { | ||||||
| class Request; | class Request; | ||||||
|  | @ -46,6 +47,7 @@ public: | ||||||
|     virtual void preconnect(URL const& url) override; |     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::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: | private: | ||||||
|     RefPtr<Protocol::RequestClient> m_protocol_client; |     RefPtr<Protocol::RequestClient> m_protocol_client; | ||||||
|  |  | ||||||
|  | @ -4,8 +4,8 @@ | ||||||
|  * SPDX-License-Identifier: BSD-2-Clause |  * SPDX-License-Identifier: BSD-2-Clause | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
|  | #include <LibProtocol/RequestClient.h> | ||||||
| #include <LibProtocol/WebSocket.h> | #include <LibProtocol/WebSocket.h> | ||||||
| #include <LibProtocol/WebSocketClient.h> |  | ||||||
| #include <LibWebView/WebSocketClientAdapter.h> | #include <LibWebView/WebSocketClientAdapter.h> | ||||||
| 
 | 
 | ||||||
| namespace WebView { | namespace WebView { | ||||||
|  | @ -107,30 +107,4 @@ void WebSocketClientSocketAdapter::close(u16 code, ByteString reason) | ||||||
|     m_websocket->close(code, 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 { | namespace Protocol { | ||||||
| class WebSocket; | class WebSocket; | ||||||
| class WebSocketClient; | class RequestClient; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| namespace WebView { | namespace WebView { | ||||||
|  | @ -38,19 +38,4 @@ private: | ||||||
|     NonnullRefPtr<Protocol::WebSocket> m_websocket; |     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(TelnetServer) | ||||||
|     add_subdirectory(WebContent) |     add_subdirectory(WebContent) | ||||||
|     add_subdirectory(WebDriver) |     add_subdirectory(WebDriver) | ||||||
|     add_subdirectory(WebSocket) |  | ||||||
|     add_subdirectory(WebWorker) |     add_subdirectory(WebWorker) | ||||||
|     add_subdirectory(WindowServer) |     add_subdirectory(WindowServer) | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
|  | @ -26,4 +26,4 @@ set(GENERATED_SOURCES | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| serenity_bin(RequestServer) | 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 <AK/Weakable.h> | ||||||
| #include <LibCore/Proxy.h> | #include <LibCore/Proxy.h> | ||||||
| #include <LibCore/Socket.h> | #include <LibCore/Socket.h> | ||||||
|  | #include <LibWebSocket/ConnectionInfo.h> | ||||||
|  | #include <LibWebSocket/Message.h> | ||||||
| #include <RequestServer/ConnectionFromClient.h> | #include <RequestServer/ConnectionFromClient.h> | ||||||
| #include <RequestServer/Protocol.h> | #include <RequestServer/Protocol.h> | ||||||
| #include <RequestServer/Request.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()); |         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 <AK/HashMap.h> | ||||||
| #include <LibIPC/ConnectionFromClient.h> | #include <LibIPC/ConnectionFromClient.h> | ||||||
|  | #include <LibWebSocket/WebSocket.h> | ||||||
| #include <RequestServer/Forward.h> | #include <RequestServer/Forward.h> | ||||||
| #include <RequestServer/RequestClientEndpoint.h> | #include <RequestServer/RequestClientEndpoint.h> | ||||||
| #include <RequestServer/RequestServerEndpoint.h> | #include <RequestServer/RequestServerEndpoint.h> | ||||||
|  | @ -37,7 +38,15 @@ private: | ||||||
|     virtual Messages::RequestServer::SetCertificateResponse set_certificate(i32, ByteString const&, ByteString const&) override; |     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 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, 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) =| |     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) =| |     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 requests | ||||||
|     certificate_requested(i32 request_id) =| |     certificate_requested(i32 request_id) =| | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -11,4 +11,12 @@ endpoint RequestServer | ||||||
|     set_certificate(i32 request_id, ByteString certificate, ByteString key) => (bool success) |     set_certificate(i32 request_id, ByteString certificate, ByteString key) => (bool success) | ||||||
| 
 | 
 | ||||||
|     ensure_connection(URL url, ::RequestServer::CacheLevel cache_level) =| |     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( | serenity_component( | ||||||
|     WebContent |     WebContent | ||||||
|     TARGETS WebContent |     TARGETS WebContent | ||||||
|     DEPENDS ImageDecoder RequestServer WebSocket |     DEPENDS ImageDecoder RequestServer | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| compile_ipc(WebContentServer.ipc WebContentServerEndpoint.h) | 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/audio", "rw")); | ||||||
|     TRY(Core::System::unveil("/tmp/session/%sid/portal/request", "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/image", "rw")); | ||||||
|     TRY(Core::System::unveil("/tmp/session/%sid/portal/websocket", "rw")); |  | ||||||
|     TRY(Core::System::unveil(nullptr, nullptr)); |     TRY(Core::System::unveil(nullptr, nullptr)); | ||||||
| 
 | 
 | ||||||
|     Web::Platform::EventLoopPlugin::install(*new Web::Platform::EventLoopPluginSerenity); |     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)); |         return Web::Platform::AudioCodecPluginAgnostic::create(move(loader)); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     Web::WebSockets::WebSocketClientManager::initialize(TRY(WebView::WebSocketClientManagerAdapter::try_create())); |  | ||||||
|     Web::ResourceLoader::initialize(TRY(WebView::RequestServerAdapter::try_create())); |     Web::ResourceLoader::initialize(TRY(WebView::RequestServerAdapter::try_create())); | ||||||
|     TRY(Web::Bindings::initialize_main_thread_vm()); |     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("/etc/timezone", "r")); | ||||||
|     TRY(Core::System::unveil("/tmp/session/%sid/portal/request", "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/image", "rw")); | ||||||
|     TRY(Core::System::unveil("/tmp/session/%sid/portal/websocket", "rw")); |  | ||||||
|     TRY(Core::System::unveil(nullptr, nullptr)); |     TRY(Core::System::unveil(nullptr, nullptr)); | ||||||
| 
 | 
 | ||||||
|     Web::Platform::EventLoopPlugin::install(*new Web::Platform::EventLoopPluginSerenity); |     Web::Platform::EventLoopPlugin::install(*new Web::Platform::EventLoopPluginSerenity); | ||||||
|     Web::Platform::FontPlugin::install(*new Web::Platform::FontPluginSerenity); |     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())); |     Web::ResourceLoader::initialize(TRY(WebView::RequestServerAdapter::try_create())); | ||||||
|     TRY(Web::Bindings::initialize_main_thread_vm()); |     TRY(Web::Bindings::initialize_main_thread_vm()); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -12,8 +12,8 @@ | ||||||
| #include <LibCore/System.h> | #include <LibCore/System.h> | ||||||
| #include <LibLine/Editor.h> | #include <LibLine/Editor.h> | ||||||
| #include <LibMain/Main.h> | #include <LibMain/Main.h> | ||||||
|  | #include <LibProtocol/RequestClient.h> | ||||||
| #include <LibProtocol/WebSocket.h> | #include <LibProtocol/WebSocket.h> | ||||||
| #include <LibProtocol/WebSocketClient.h> |  | ||||||
| 
 | 
 | ||||||
| ErrorOr<int> serenity_main(Main::Arguments arguments) | ErrorOr<int> serenity_main(Main::Arguments arguments) | ||||||
| { | { | ||||||
|  | @ -38,7 +38,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments) | ||||||
| 
 | 
 | ||||||
|     Core::EventLoop loop; |     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()) { |     if (maybe_websocket_client.is_error()) { | ||||||
|         warnln("Failed to connect to the websocket server: {}\n", maybe_websocket_client.error()); |         warnln("Failed to connect to the websocket server: {}\n", maybe_websocket_client.error()); | ||||||
|         return maybe_websocket_client.release_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(); |     RefPtr<Line::Editor> editor = Line::Editor::construct(); | ||||||
|     bool should_quit = false; |     bool should_quit = false; | ||||||
|     auto socket = websocket_client->connect(url, origin); |     auto socket = websocket_client->websocket_connect(url, origin); | ||||||
|     if (!socket) { |     if (!socket) { | ||||||
|         warnln("Failed to start socket for '{}'\n", url); |         warnln("Failed to start socket for '{}'\n", url); | ||||||
|         return 1; |         return 1; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Ali Mohammad Pur
						Ali Mohammad Pur