From 71d27abb97acc656256f3fef6d2a67878d520f12 Mon Sep 17 00:00:00 2001 From: DexesTTP Date: Fri, 23 Apr 2021 22:45:52 +0200 Subject: [PATCH] Services: Rename ProtocolServer to RequestServer The current ProtocolServer was really only used for requests, and with the recent introduction of the WebSocket service, long-lasting connections with another server are not part of it. To better reflect this, this commit renames it to RequestServer. This commit also changes the existing 'protocol' portal to 'request', the existing 'protocol' user and group to 'request', and most mentions of the 'download' aspect of the request to 'request' when relevant, to make everything consistent across the system. Note that LibProtocol still exists as-is, but the more generic Client class and the more specific Download class have both been renamed to a more accurate RequestClient and Request to match the new names. This commit only change names, not behaviors. --- Base/etc/SystemServer.ini | 6 +- Base/etc/group | 4 +- Base/etc/passwd | 2 +- Documentation/Browser/ProcessArchitecture.md | 12 +- README.md | 2 +- .../Applications/Browser/DownloadWidget.cpp | 4 +- .../Applications/Browser/DownloadWidget.h | 4 +- Userland/Applications/Browser/main.cpp | 2 +- Userland/Libraries/LibProtocol/CMakeLists.txt | 8 +- Userland/Libraries/LibProtocol/Client.cpp | 98 --------------- Userland/Libraries/LibProtocol/Client.h | 44 ------- .../LibProtocol/{Download.cpp => Request.cpp} | 34 ++--- .../LibProtocol/{Download.h => Request.h} | 34 ++--- .../Libraries/LibProtocol/RequestClient.cpp | 98 +++++++++++++++ .../Libraries/LibProtocol/RequestClient.h | 44 +++++++ Userland/Libraries/LibWeb/CMakeLists.txt | 4 +- .../LibWeb/Loader/ResourceLoader.cpp | 22 ++-- .../Libraries/LibWeb/Loader/ResourceLoader.h | 6 +- Userland/Services/CMakeLists.txt | 2 +- .../Services/ProtocolServer/CMakeLists.txt | 20 --- .../ProtocolServer/ClientConnection.cpp | 119 ------------------ .../ProtocolServer/ClientConnection.h | 43 ------- Userland/Services/ProtocolServer/Download.cpp | 59 --------- .../Services/ProtocolServer/GeminiDownload.h | 29 ----- .../Services/ProtocolServer/HttpDownload.cpp | 33 ----- .../Services/ProtocolServer/HttpDownload.h | 30 ----- .../Services/ProtocolServer/HttpProtocol.cpp | 32 ----- .../Services/ProtocolServer/HttpsDownload.cpp | 38 ------ .../Services/ProtocolServer/HttpsDownload.h | 31 ----- .../Services/ProtocolServer/HttpsProtocol.cpp | 32 ----- .../ProtocolServer/ProtocolClient.ipc | 10 -- .../ProtocolServer/ProtocolServer.ipc | 13 -- .../Services/RequestServer/CMakeLists.txt | 20 +++ .../RequestServer/ClientConnection.cpp | 119 ++++++++++++++++++ .../Services/RequestServer/ClientConnection.h | 43 +++++++ .../Forward.h | 8 +- .../GeminiProtocol.cpp | 16 +-- .../GeminiProtocol.h | 6 +- .../GeminiRequest.cpp} | 18 +-- .../Services/RequestServer/GeminiRequest.h | 29 +++++ .../HttpCommon.h | 18 +-- .../Services/RequestServer/HttpProtocol.cpp | 32 +++++ .../HttpProtocol.h | 14 +-- .../Services/RequestServer/HttpRequest.cpp | 33 +++++ Userland/Services/RequestServer/HttpRequest.h | 30 +++++ .../Services/RequestServer/HttpsProtocol.cpp | 32 +++++ .../HttpsProtocol.h | 14 +-- .../Services/RequestServer/HttpsRequest.cpp | 38 ++++++ .../Services/RequestServer/HttpsRequest.h | 31 +++++ .../Protocol.cpp | 6 +- .../Protocol.h | 8 +- Userland/Services/RequestServer/Request.cpp | 59 +++++++++ .../Download.h => RequestServer/Request.h} | 16 +-- .../Services/RequestServer/RequestClient.ipc | 9 ++ .../Services/RequestServer/RequestServer.ipc | 12 ++ .../main.cpp | 16 +-- Userland/Services/WebContent/main.cpp | 2 +- Userland/Utilities/pro.cpp | 26 ++-- 58 files changed, 786 insertions(+), 788 deletions(-) delete mode 100644 Userland/Libraries/LibProtocol/Client.cpp delete mode 100644 Userland/Libraries/LibProtocol/Client.h rename Userland/Libraries/LibProtocol/{Download.cpp => Request.cpp} (74%) rename Userland/Libraries/LibProtocol/{Download.h => Request.h} (66%) create mode 100644 Userland/Libraries/LibProtocol/RequestClient.cpp create mode 100644 Userland/Libraries/LibProtocol/RequestClient.h delete mode 100644 Userland/Services/ProtocolServer/CMakeLists.txt delete mode 100644 Userland/Services/ProtocolServer/ClientConnection.cpp delete mode 100644 Userland/Services/ProtocolServer/ClientConnection.h delete mode 100644 Userland/Services/ProtocolServer/Download.cpp delete mode 100644 Userland/Services/ProtocolServer/GeminiDownload.h delete mode 100644 Userland/Services/ProtocolServer/HttpDownload.cpp delete mode 100644 Userland/Services/ProtocolServer/HttpDownload.h delete mode 100644 Userland/Services/ProtocolServer/HttpProtocol.cpp delete mode 100644 Userland/Services/ProtocolServer/HttpsDownload.cpp delete mode 100644 Userland/Services/ProtocolServer/HttpsDownload.h delete mode 100644 Userland/Services/ProtocolServer/HttpsProtocol.cpp delete mode 100644 Userland/Services/ProtocolServer/ProtocolClient.ipc delete mode 100644 Userland/Services/ProtocolServer/ProtocolServer.ipc create mode 100644 Userland/Services/RequestServer/CMakeLists.txt create mode 100644 Userland/Services/RequestServer/ClientConnection.cpp create mode 100644 Userland/Services/RequestServer/ClientConnection.h rename Userland/Services/{ProtocolServer => RequestServer}/Forward.h (73%) rename Userland/Services/{ProtocolServer => RequestServer}/GeminiProtocol.cpp (54%) rename Userland/Services/{ProtocolServer => RequestServer}/GeminiProtocol.h (52%) rename Userland/Services/{ProtocolServer/GeminiDownload.cpp => RequestServer/GeminiRequest.cpp} (68%) create mode 100644 Userland/Services/RequestServer/GeminiRequest.h rename Userland/Services/{ProtocolServer => RequestServer}/HttpCommon.h (75%) create mode 100644 Userland/Services/RequestServer/HttpProtocol.cpp rename Userland/Services/{ProtocolServer => RequestServer}/HttpProtocol.h (52%) create mode 100644 Userland/Services/RequestServer/HttpRequest.cpp create mode 100644 Userland/Services/RequestServer/HttpRequest.h create mode 100644 Userland/Services/RequestServer/HttpsProtocol.cpp rename Userland/Services/{ProtocolServer => RequestServer}/HttpsProtocol.h (52%) create mode 100644 Userland/Services/RequestServer/HttpsRequest.cpp create mode 100644 Userland/Services/RequestServer/HttpsRequest.h rename Userland/Services/{ProtocolServer => RequestServer}/Protocol.cpp (87%) rename Userland/Services/{ProtocolServer => RequestServer}/Protocol.h (64%) create mode 100644 Userland/Services/RequestServer/Request.cpp rename Userland/Services/{ProtocolServer/Download.h => RequestServer/Request.h} (82%) create mode 100644 Userland/Services/RequestServer/RequestClient.ipc create mode 100644 Userland/Services/RequestServer/RequestServer.ipc rename Userland/Services/{ProtocolServer => RequestServer}/main.cpp (69%) diff --git a/Base/etc/SystemServer.ini b/Base/etc/SystemServer.ini index 70602d3648..777ea191d9 100644 --- a/Base/etc/SystemServer.ini +++ b/Base/etc/SystemServer.ini @@ -1,9 +1,9 @@ -[ProtocolServer] -Socket=/tmp/portal/protocol +[RequestServer] +Socket=/tmp/portal/request SocketPermissions=660 Lazy=1 Priority=low -User=protocol +User=request BootModes=text,graphical,self-test MultiInstance=1 AcceptSocketConnections=1 diff --git a/Base/etc/group b/Base/etc/group index d3f1194dc7..8ffb201951 100644 --- a/Base/etc/group +++ b/Base/etc/group @@ -4,8 +4,8 @@ tty:x:2: phys:x:3:window,anon audio:x:4:anon utmp:x:5: -lookup:x:10:protocol,websocket,anon -protocol:x:11:webcontent,anon +lookup:x:10:request,websocket,anon +request:x:11:webcontent,anon notify:x:12:anon window:x:13:anon,notify clipboard:x:14:anon,notify diff --git a/Base/etc/passwd b/Base/etc/passwd index 101bf0263c..e01bffe145 100644 --- a/Base/etc/passwd +++ b/Base/etc/passwd @@ -1,6 +1,6 @@ root::0:0:root:/root:/bin/sh lookup:!:10:10:LookupServer,,,:/:/bin/false -protocol:!:11:11:ProtocolServer,,,:/:/bin/false +request:!:11:11:RequestServer,,,:/:/bin/false notify:!:12:12:NotificationServer,,,:/:/bin/false window:!:13:13:WindowServer,,,:/:/bin/false clipboard:!:14:14:Clipboard,,,:/:/bin/false diff --git a/Documentation/Browser/ProcessArchitecture.md b/Documentation/Browser/ProcessArchitecture.md index 9437840c1e..a7dafa9b8e 100644 --- a/Documentation/Browser/ProcessArchitecture.md +++ b/Documentation/Browser/ProcessArchitecture.md @@ -10,19 +10,19 @@ The SerenityOS web browser (**"Browser"**) uses a multi-process architecture to Every instance of the **Browser** application can have one or more tabs open. Each tab has a unique **WebContent** service process spawned on its behalf. -Two important aspects of web browsing are further separated from the **WebContent** process: *network protocols* and *image decoding*, segregated to the **ProtocolServer** and **ImageDecoder** processes respectively. +Two important aspects of web browsing are further separated from the **WebContent** process: *network requests* and *image decoding*, segregated to the **RequestServer** and **ImageDecoder** processes respectively. All processes and are aggressively sandboxed using the `pledge()` and `unveil()` mechanisms. Furthermore, all processes except **Browser** run as an unprivileged user, separate from the primary logged-in desktop user. ### Process: WebContent -This process hosts the main HTML/CSS engine (**LibWeb**.) It also runs JavaScript (**LibJS**.) It gets input events from **Browser** and paints the web content into shared bitmaps. It can only communicate with the outside world via **ProtocolServer**. +This process hosts the main HTML/CSS engine (**LibWeb**.) It also runs JavaScript (**LibJS**.) It gets input events from **Browser** and paints the web content into shared bitmaps. It can only communicate with the outside world via **RequestServer**. -### Process: ProtocolServer +### Process: RequestServer -This process can speak networking protocols (like HTTP, HTTPS, and Gemini) to the outside world. Each **WebContent** process gets its own **ProtocolServer** to do networking on its behalf. +This process can use networking protocols (like HTTP, HTTPS, and Gemini) to request files from the outside world. Each **WebContent** process gets its own **RequestServer** to do uploading or downloading on its behalf. -For DNS lookups, **ProtocolServer** asks for help from the system's global **LookupServer** service, which handles all outgoing DNS requests. +For DNS lookups, **RequestServer** asks for help from the system's global **LookupServer** service, which handles all outgoing DNS requests. ### Process: ImageDecoder @@ -32,7 +32,7 @@ This process can decode images (PNG, JPEG, BMP, ICO, PBM, etc.) into bitmaps. Ea To get a fresh **WebContent** process, anyone with the suitable file system permissions can spawn one by connecting to the socket at `/tmp/portal/webcontent`. This socket is managed by **SystemServer** and will spawn a new instance of **WebContent** for every connection. -The same basic concept applies to **ProtocolServer** and **ImageDecoder** as well, except that those services are spawned by **WebContent** as needed, not by **Browser**. +The same basic concept applies to **RequestServer** and **ImageDecoder** as well, except that those services are spawned by **WebContent** as needed, not by **Browser**. ## Class overview diff --git a/README.md b/README.md index 38fcdd17ae..d5423faafb 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ I'm also on [Patreon](https://www.patreon.com/serenityos) and [GitHub Sponsors]( * Compositing window server (WindowServer) * Text console manager (TTYServer) * DNS client (LookupServer) -* Network protocols server (ProtocolServer) +* Network protocols server (RequestServer and WebSocket) * Software-mixing sound daemon (AudioServer) * Desktop notifications (NotificationServer) * HTTP server (WebServer) diff --git a/Userland/Applications/Browser/DownloadWidget.cpp b/Userland/Applications/Browser/DownloadWidget.cpp index bcc7f89beb..39bd4bf82c 100644 --- a/Userland/Applications/Browser/DownloadWidget.cpp +++ b/Userland/Applications/Browser/DownloadWidget.cpp @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include @@ -36,7 +36,7 @@ DownloadWidget::DownloadWidget(const URL& url) } m_elapsed_timer.start(); - m_download = Web::ResourceLoader::the().protocol_client().start_download("GET", url.to_string()); + m_download = Web::ResourceLoader::the().protocol_client().start_request("GET", url.to_string()); VERIFY(m_download); m_download->on_progress = [this](Optional total_size, u32 downloaded_size) { did_progress(total_size.value(), downloaded_size); diff --git a/Userland/Applications/Browser/DownloadWidget.h b/Userland/Applications/Browser/DownloadWidget.h index cbcb766e32..2071cf650e 100644 --- a/Userland/Applications/Browser/DownloadWidget.h +++ b/Userland/Applications/Browser/DownloadWidget.h @@ -11,7 +11,7 @@ #include #include #include -#include +#include namespace Browser { @@ -29,7 +29,7 @@ private: URL m_url; String m_destination_path; - RefPtr m_download; + RefPtr m_download; RefPtr m_progressbar; RefPtr m_progress_label; RefPtr m_cancel_button; diff --git a/Userland/Applications/Browser/main.cpp b/Userland/Applications/Browser/main.cpp index 77675724cf..0c53f64d9c 100644 --- a/Userland/Applications/Browser/main.cpp +++ b/Userland/Applications/Browser/main.cpp @@ -67,7 +67,7 @@ int main(int argc, char** argv) auto app = GUI::Application::construct(argc, argv); - // Connect to the ProtocolServer and the WebSocket service immediately so we can drop the "unix" pledge. + // Connect to the RequestServer and the WebSocket service immediately so we can drop the "unix" pledge. Web::ResourceLoader::the(); Web::HTML::WebSocketClientManager::the(); diff --git a/Userland/Libraries/LibProtocol/CMakeLists.txt b/Userland/Libraries/LibProtocol/CMakeLists.txt index a17b5e728b..8156474c0b 100644 --- a/Userland/Libraries/LibProtocol/CMakeLists.txt +++ b/Userland/Libraries/LibProtocol/CMakeLists.txt @@ -1,13 +1,13 @@ set(SOURCES - Client.cpp - Download.cpp + Request.cpp + RequestClient.cpp WebSocket.cpp WebSocketClient.cpp ) set(GENERATED_SOURCES - ../../Services/ProtocolServer/ProtocolClientEndpoint.h - ../../Services/ProtocolServer/ProtocolServerEndpoint.h + ../../Services/RequestServer/RequestClientEndpoint.h + ../../Services/RequestServer/RequestServerEndpoint.h ../../Services/WebSocket/WebSocketClientEndpoint.h ../../Services/WebSocket/WebSocketServerEndpoint.h ) diff --git a/Userland/Libraries/LibProtocol/Client.cpp b/Userland/Libraries/LibProtocol/Client.cpp deleted file mode 100644 index cd77c6bfe6..0000000000 --- a/Userland/Libraries/LibProtocol/Client.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include - -namespace Protocol { - -Client::Client() - : IPC::ServerConnection(*this, "/tmp/portal/protocol") -{ - handshake(); -} - -void Client::handshake() -{ - send_sync(); -} - -bool Client::is_supported_protocol(const String& protocol) -{ - return send_sync(protocol)->supported(); -} - -template -RefPtr Client::start_download(const String& method, const String& url, const HashMap& request_headers, ReadonlyBytes request_body) -{ - IPC::Dictionary header_dictionary; - for (auto& it : request_headers) - header_dictionary.add(it.key, it.value); - - auto response = send_sync(method, url, header_dictionary, ByteBuffer::copy(request_body)); - auto download_id = response->download_id(); - if (download_id < 0 || !response->response_fd().has_value()) - return nullptr; - auto response_fd = response->response_fd().value().take_fd(); - auto download = Download::create_from_id({}, *this, download_id); - download->set_download_fd({}, response_fd); - m_downloads.set(download_id, download); - return download; -} - -bool Client::stop_download(Badge, Download& download) -{ - if (!m_downloads.contains(download.id())) - return false; - return send_sync(download.id())->success(); -} - -bool Client::set_certificate(Badge, Download& download, String certificate, String key) -{ - if (!m_downloads.contains(download.id())) - return false; - return send_sync(download.id(), move(certificate), move(key))->success(); -} - -void Client::handle(const Messages::ProtocolClient::DownloadFinished& message) -{ - RefPtr download; - if ((download = m_downloads.get(message.download_id()).value_or(nullptr))) { - download->did_finish({}, message.success(), message.total_size()); - } - m_downloads.remove(message.download_id()); -} - -void Client::handle(const Messages::ProtocolClient::DownloadProgress& message) -{ - if (auto download = const_cast(m_downloads.get(message.download_id()).value_or(nullptr))) { - download->did_progress({}, message.total_size(), message.downloaded_size()); - } -} - -void Client::handle(const Messages::ProtocolClient::HeadersBecameAvailable& message) -{ - if (auto download = const_cast(m_downloads.get(message.download_id()).value_or(nullptr))) { - HashMap headers; - message.response_headers().for_each_entry([&](auto& name, auto& value) { headers.set(name, value); }); - download->did_receive_headers({}, headers, message.status_code()); - } -} - -OwnPtr Client::handle(const Messages::ProtocolClient::CertificateRequested& message) -{ - if (auto download = const_cast(m_downloads.get(message.download_id()).value_or(nullptr))) { - download->did_request_certificates({}); - } - - return make(); -} - -} - -template RefPtr Protocol::Client::start_download(const String& method, const String& url, const HashMap& request_headers, ReadonlyBytes request_body); -template RefPtr Protocol::Client::start_download(const String& method, const String& url, const HashMap& request_headers, ReadonlyBytes request_body); diff --git a/Userland/Libraries/LibProtocol/Client.h b/Userland/Libraries/LibProtocol/Client.h deleted file mode 100644 index d5ff62e1ad..0000000000 --- a/Userland/Libraries/LibProtocol/Client.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include - -namespace Protocol { - -class Download; - -class Client - : public IPC::ServerConnection - , public ProtocolClientEndpoint { - C_OBJECT(Client); - -public: - virtual void handshake() override; - - bool is_supported_protocol(const String&); - template> - RefPtr start_download(const String& method, const String& url, const HashMap& request_headers = {}, ReadonlyBytes request_body = {}); - - bool stop_download(Badge, Download&); - bool set_certificate(Badge, Download&, String, String); - -private: - Client(); - - virtual void handle(const Messages::ProtocolClient::DownloadProgress&) override; - virtual void handle(const Messages::ProtocolClient::DownloadFinished&) override; - virtual OwnPtr handle(const Messages::ProtocolClient::CertificateRequested&) override; - virtual void handle(const Messages::ProtocolClient::HeadersBecameAvailable&) override; - - HashMap> m_downloads; -}; - -} diff --git a/Userland/Libraries/LibProtocol/Download.cpp b/Userland/Libraries/LibProtocol/Request.cpp similarity index 74% rename from Userland/Libraries/LibProtocol/Download.cpp rename to Userland/Libraries/LibProtocol/Request.cpp index 9e3752acb2..0094b875ab 100644 --- a/Userland/Libraries/LibProtocol/Download.cpp +++ b/Userland/Libraries/LibProtocol/Request.cpp @@ -4,23 +4,23 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include -#include +#include +#include namespace Protocol { -Download::Download(Client& client, i32 download_id) +Request::Request(RequestClient& client, i32 request_id) : m_client(client) - , m_download_id(download_id) + , m_request_id(request_id) { } -bool Download::stop() +bool Request::stop() { - return m_client->stop_download({}, *this); + return m_client->stop_request({}, *this); } -void Download::stream_into(OutputStream& stream) +void Request::stream_into(OutputStream& stream) { VERIFY(!m_internal_stream_data); @@ -33,7 +33,7 @@ void Download::stream_into(OutputStream& stream) on_finish = [this](auto success, auto total_size) { m_internal_stream_data->success = success; m_internal_stream_data->total_size = total_size; - m_internal_stream_data->download_done = true; + m_internal_stream_data->request_done = true; }; notifier->on_ready_to_read = [this, &stream, user_on_finish = move(user_on_finish)] { @@ -45,7 +45,7 @@ void Download::stream_into(OutputStream& stream) TODO(); } - if (m_internal_stream_data->read_stream.eof() && m_internal_stream_data->download_done) { + if (m_internal_stream_data->read_stream.eof() && m_internal_stream_data->request_done) { m_internal_stream_data->read_notifier->close(); user_on_finish(m_internal_stream_data->success, m_internal_stream_data->total_size); } else { @@ -54,7 +54,7 @@ void Download::stream_into(OutputStream& stream) }; } -void Download::set_should_buffer_all_input(bool value) +void Request::set_should_buffer_all_input(bool value) { if (m_should_buffer_all_input == value) return; @@ -67,7 +67,7 @@ void Download::set_should_buffer_all_input(bool value) VERIFY(!m_internal_stream_data); VERIFY(!m_internal_buffered_data); - VERIFY(on_buffered_download_finish); // Not having this set makes no sense. + VERIFY(on_buffered_request_finish); // Not having this set makes no sense. m_internal_buffered_data = make(fd()); m_should_buffer_all_input = true; @@ -78,7 +78,7 @@ void Download::set_should_buffer_all_input(bool value) on_finish = [this](auto success, u32 total_size) { auto output_buffer = m_internal_buffered_data->payload_stream.copy_into_contiguous_buffer(); - on_buffered_download_finish( + on_buffered_request_finish( success, total_size, m_internal_buffered_data->response_headers, @@ -89,7 +89,7 @@ void Download::set_should_buffer_all_input(bool value) stream_into(m_internal_buffered_data->payload_stream); } -void Download::did_finish(Badge, bool success, u32 total_size) +void Request::did_finish(Badge, bool success, u32 total_size) { if (!on_finish) return; @@ -97,24 +97,24 @@ void Download::did_finish(Badge, bool success, u32 total_size) on_finish(success, total_size); } -void Download::did_progress(Badge, Optional total_size, u32 downloaded_size) +void Request::did_progress(Badge, Optional total_size, u32 downloaded_size) { if (on_progress) on_progress(total_size, downloaded_size); } -void Download::did_receive_headers(Badge, const HashMap& response_headers, Optional response_code) +void Request::did_receive_headers(Badge, const HashMap& response_headers, Optional response_code) { if (on_headers_received) on_headers_received(response_headers, response_code); } -void Download::did_request_certificates(Badge) +void Request::did_request_certificates(Badge) { if (on_certificate_requested) { auto result = on_certificate_requested(); if (!m_client->set_certificate({}, *this, result.certificate, result.key)) { - dbgln("Download: set_certificate failed"); + dbgln("Request: set_certificate failed"); } } } diff --git a/Userland/Libraries/LibProtocol/Download.h b/Userland/Libraries/LibProtocol/Request.h similarity index 66% rename from Userland/Libraries/LibProtocol/Download.h rename to Userland/Libraries/LibProtocol/Request.h index 8dfdd47036..91f2d1eb9c 100644 --- a/Userland/Libraries/LibProtocol/Download.h +++ b/Userland/Libraries/LibProtocol/Request.h @@ -19,49 +19,49 @@ namespace Protocol { -class Client; +class RequestClient; -class Download : public RefCounted { +class Request : public RefCounted { public: struct CertificateAndKey { String certificate; String key; }; - static NonnullRefPtr create_from_id(Badge, Client& client, i32 download_id) + static NonnullRefPtr create_from_id(Badge, RequestClient& client, i32 request_id) { - return adopt_ref(*new Download(client, download_id)); + return adopt_ref(*new Request(client, request_id)); } - int id() const { return m_download_id; } + int id() const { return m_request_id; } int fd() const { return m_fd; } bool stop(); void stream_into(OutputStream&); bool should_buffer_all_input() const { return m_should_buffer_all_input; } - /// Note: Will override `on_finish', and `on_headers_received', and expects `on_buffered_download_finish' to be set! + /// Note: Will override `on_finish', and `on_headers_received', and expects `on_buffered_request_finish' to be set! void set_should_buffer_all_input(bool); /// Note: Must be set before `set_should_buffer_all_input(true)`. - Function& response_headers, Optional response_code, ReadonlyBytes payload)> on_buffered_download_finish; + Function& response_headers, Optional response_code, ReadonlyBytes payload)> on_buffered_request_finish; Function on_finish; Function total_size, u32 downloaded_size)> on_progress; Function& response_headers, Optional response_code)> on_headers_received; Function on_certificate_requested; - void did_finish(Badge, bool success, u32 total_size); - void did_progress(Badge, Optional total_size, u32 downloaded_size); - void did_receive_headers(Badge, const HashMap& response_headers, Optional response_code); - void did_request_certificates(Badge); + void did_finish(Badge, bool success, u32 total_size); + void did_progress(Badge, Optional total_size, u32 downloaded_size); + void did_receive_headers(Badge, const HashMap& response_headers, Optional response_code); + void did_request_certificates(Badge); - RefPtr& write_notifier(Badge) { return m_write_notifier; } - void set_download_fd(Badge, int fd) { m_fd = fd; } + RefPtr& write_notifier(Badge) { return m_write_notifier; } + void set_request_fd(Badge, int fd) { m_fd = fd; } private: - explicit Download(Client&, i32 download_id); - WeakPtr m_client; - int m_download_id { -1 }; + explicit Request(RequestClient&, i32 request_id); + WeakPtr m_client; + int m_request_id { -1 }; RefPtr m_write_notifier; int m_fd { -1 }; bool m_should_buffer_all_input { false }; @@ -88,7 +88,7 @@ private: RefPtr read_notifier; bool success; u32 total_size { 0 }; - bool download_done { false }; + bool request_done { false }; }; OwnPtr m_internal_buffered_data; diff --git a/Userland/Libraries/LibProtocol/RequestClient.cpp b/Userland/Libraries/LibProtocol/RequestClient.cpp new file mode 100644 index 0000000000..44a1a98b8d --- /dev/null +++ b/Userland/Libraries/LibProtocol/RequestClient.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +namespace Protocol { + +RequestClient::RequestClient() + : IPC::ServerConnection(*this, "/tmp/portal/request") +{ + handshake(); +} + +void RequestClient::handshake() +{ + send_sync(); +} + +bool RequestClient::is_supported_protocol(const String& protocol) +{ + return send_sync(protocol)->supported(); +} + +template +RefPtr RequestClient::start_request(const String& method, const String& url, const HashMap& request_headers, ReadonlyBytes request_body) +{ + IPC::Dictionary header_dictionary; + for (auto& it : request_headers) + header_dictionary.add(it.key, it.value); + + auto response = send_sync(method, url, header_dictionary, ByteBuffer::copy(request_body)); + auto request_id = response->request_id(); + if (request_id < 0 || !response->response_fd().has_value()) + return nullptr; + auto response_fd = response->response_fd().value().take_fd(); + auto request = Request::create_from_id({}, *this, request_id); + request->set_request_fd({}, response_fd); + m_requests.set(request_id, request); + return request; +} + +bool RequestClient::stop_request(Badge, Request& request) +{ + if (!m_requests.contains(request.id())) + return false; + return send_sync(request.id())->success(); +} + +bool RequestClient::set_certificate(Badge, Request& request, String certificate, String key) +{ + if (!m_requests.contains(request.id())) + return false; + return send_sync(request.id(), move(certificate), move(key))->success(); +} + +void RequestClient::handle(const Messages::RequestClient::RequestFinished& message) +{ + RefPtr request; + if ((request = m_requests.get(message.request_id()).value_or(nullptr))) { + request->did_finish({}, message.success(), message.total_size()); + } + m_requests.remove(message.request_id()); +} + +void RequestClient::handle(const Messages::RequestClient::RequestProgress& message) +{ + if (auto request = const_cast(m_requests.get(message.request_id()).value_or(nullptr))) { + request->did_progress({}, message.total_size(), message.downloaded_size()); + } +} + +void RequestClient::handle(const Messages::RequestClient::HeadersBecameAvailable& message) +{ + if (auto request = const_cast(m_requests.get(message.request_id()).value_or(nullptr))) { + HashMap headers; + message.response_headers().for_each_entry([&](auto& name, auto& value) { headers.set(name, value); }); + request->did_receive_headers({}, headers, message.status_code()); + } +} + +OwnPtr RequestClient::handle(const Messages::RequestClient::CertificateRequested& message) +{ + if (auto request = const_cast(m_requests.get(message.request_id()).value_or(nullptr))) { + request->did_request_certificates({}); + } + + return make(); +} + +} + +template RefPtr Protocol::RequestClient::start_request(const String& method, const String& url, const HashMap& request_headers, ReadonlyBytes request_body); +template RefPtr Protocol::RequestClient::start_request(const String& method, const String& url, const HashMap& request_headers, ReadonlyBytes request_body); diff --git a/Userland/Libraries/LibProtocol/RequestClient.h b/Userland/Libraries/LibProtocol/RequestClient.h new file mode 100644 index 0000000000..269f0d97ad --- /dev/null +++ b/Userland/Libraries/LibProtocol/RequestClient.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include + +namespace Protocol { + +class Request; + +class RequestClient + : public IPC::ServerConnection + , public RequestClientEndpoint { + C_OBJECT(RequestClient); + +public: + virtual void handshake() override; + + bool is_supported_protocol(const String&); + template> + RefPtr start_request(const String& method, const String& url, const HashMap& request_headers = {}, ReadonlyBytes request_body = {}); + + bool stop_request(Badge, Request&); + bool set_certificate(Badge, Request&, String, String); + +private: + RequestClient(); + + virtual void handle(const Messages::RequestClient::RequestProgress&) override; + virtual void handle(const Messages::RequestClient::RequestFinished&) override; + virtual OwnPtr handle(const Messages::RequestClient::CertificateRequested&) override; + virtual void handle(const Messages::RequestClient::HeadersBecameAvailable&) override; + + HashMap> m_requests; +}; + +} diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index ce78a85158..cd3d7cf247 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -225,8 +225,8 @@ set(SOURCES ) set(GENERATED_SOURCES - ../../Services/ProtocolServer/ProtocolClientEndpoint.h - ../../Services/ProtocolServer/ProtocolServerEndpoint.h + ../../Services/RequestServer/RequestClientEndpoint.h + ../../Services/RequestServer/RequestServerEndpoint.h ../../Services/WebContent/WebContentClientEndpoint.h ../../Services/WebContent/WebContentServerEndpoint.h ) diff --git a/Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp b/Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp index 5331d1bb53..e8b144449a 100644 --- a/Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp +++ b/Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp @@ -9,8 +9,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include @@ -27,7 +27,7 @@ ResourceLoader& ResourceLoader::the() } ResourceLoader::ResourceLoader() - : m_protocol_client(Protocol::Client::construct()) + : m_protocol_client(Protocol::RequestClient::construct()) , m_user_agent(default_user_agent) { } @@ -156,13 +156,13 @@ void ResourceLoader::load(const LoadRequest& request, Functionon_buffered_download_finish = [this, success_callback = move(success_callback), error_callback = move(error_callback), download](bool success, auto, auto& response_headers, auto status_code, ReadonlyBytes payload) { + protocol_request->on_buffered_request_finish = [this, success_callback = move(success_callback), error_callback = move(error_callback), protocol_request](bool success, auto, auto& response_headers, auto status_code, ReadonlyBytes payload) { --m_pending_loads; if (on_load_counter_change) on_load_counter_change(); @@ -171,14 +171,14 @@ void ResourceLoader::load(const LoadRequest& request, Function(*download).on_buffered_download_finish = nullptr; + deferred_invoke([protocol_request](auto&) { + // Clear circular reference of `protocol_request` captured by copy + const_cast(*protocol_request).on_buffered_request_finish = nullptr; }); success_callback(payload, response_headers, status_code); }; - download->set_should_buffer_all_input(true); - download->on_certificate_requested = []() -> Protocol::Download::CertificateAndKey { + protocol_request->set_should_buffer_all_input(true); + protocol_request->on_certificate_requested = []() -> Protocol::Request::CertificateAndKey { return {}; }; ++m_pending_loads; diff --git a/Userland/Libraries/LibWeb/Loader/ResourceLoader.h b/Userland/Libraries/LibWeb/Loader/ResourceLoader.h index 50d535ff97..867825c44d 100644 --- a/Userland/Libraries/LibWeb/Loader/ResourceLoader.h +++ b/Userland/Libraries/LibWeb/Loader/ResourceLoader.h @@ -12,7 +12,7 @@ #include namespace Protocol { -class Client; +class RequestClient; } namespace Web { @@ -34,7 +34,7 @@ public: int pending_loads() const { return m_pending_loads; } - Protocol::Client& protocol_client() { return *m_protocol_client; } + Protocol::RequestClient& protocol_client() { return *m_protocol_client; } const String& user_agent() const { return m_user_agent; } void set_user_agent(const String& user_agent) { m_user_agent = user_agent; } @@ -47,7 +47,7 @@ private: int m_pending_loads { 0 }; - RefPtr m_protocol_client; + RefPtr m_protocol_client; String m_user_agent; }; diff --git a/Userland/Services/CMakeLists.txt b/Userland/Services/CMakeLists.txt index 55eec246f9..a1428e6eb8 100644 --- a/Userland/Services/CMakeLists.txt +++ b/Userland/Services/CMakeLists.txt @@ -9,7 +9,7 @@ add_subdirectory(ImageDecoder) add_subdirectory(LaunchServer) add_subdirectory(LookupServer) add_subdirectory(NotificationServer) -add_subdirectory(ProtocolServer) +add_subdirectory(RequestServer) add_subdirectory(SymbolServer) add_subdirectory(SystemServer) add_subdirectory(Taskbar) diff --git a/Userland/Services/ProtocolServer/CMakeLists.txt b/Userland/Services/ProtocolServer/CMakeLists.txt deleted file mode 100644 index 4fb0757759..0000000000 --- a/Userland/Services/ProtocolServer/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -compile_ipc(ProtocolServer.ipc ProtocolServerEndpoint.h) -compile_ipc(ProtocolClient.ipc ProtocolClientEndpoint.h) - -set(SOURCES - ClientConnection.cpp - Download.cpp - GeminiDownload.cpp - GeminiProtocol.cpp - HttpDownload.cpp - HttpProtocol.cpp - HttpsDownload.cpp - HttpsProtocol.cpp - main.cpp - Protocol.cpp - ProtocolServerEndpoint.h - ProtocolClientEndpoint.h -) - -serenity_bin(ProtocolServer) -target_link_libraries(ProtocolServer LibCore LibIPC LibGemini LibHTTP) diff --git a/Userland/Services/ProtocolServer/ClientConnection.cpp b/Userland/Services/ProtocolServer/ClientConnection.cpp deleted file mode 100644 index 43f501c6ca..0000000000 --- a/Userland/Services/ProtocolServer/ClientConnection.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include - -namespace ProtocolServer { - -static HashMap> s_connections; - -ClientConnection::ClientConnection(NonnullRefPtr socket, int client_id) - : IPC::ClientConnection(*this, move(socket), client_id) -{ - s_connections.set(client_id, *this); -} - -ClientConnection::~ClientConnection() -{ -} - -void ClientConnection::die() -{ - s_connections.remove(client_id()); - if (s_connections.is_empty()) - Core::EventLoop::current().quit(0); -} - -OwnPtr ClientConnection::handle(const Messages::ProtocolServer::IsSupportedProtocol& message) -{ - bool supported = Protocol::find_by_name(message.protocol().to_lowercase()); - return make(supported); -} - -OwnPtr ClientConnection::handle(const Messages::ProtocolServer::StartDownload& message) -{ - const auto& url = message.url(); - if (!url.is_valid()) { - dbgln("StartDownload: Invalid URL requested: '{}'", url); - return make(-1, Optional {}); - } - auto* protocol = Protocol::find_by_name(url.protocol()); - if (!protocol) { - dbgln("StartDownload: No protocol handler for URL: '{}'", url); - return make(-1, Optional {}); - } - auto download = protocol->start_download(*this, message.method(), url, message.request_headers().entries(), message.request_body()); - if (!download) { - dbgln("StartDownload: Protocol handler failed to start download: '{}'", url); - return make(-1, Optional {}); - } - auto id = download->id(); - auto fd = download->download_fd(); - m_downloads.set(id, move(download)); - return make(id, IPC::File(fd, IPC::File::CloseAfterSending)); -} - -OwnPtr ClientConnection::handle(const Messages::ProtocolServer::StopDownload& message) -{ - auto* download = const_cast(m_downloads.get(message.download_id()).value_or(nullptr)); - bool success = false; - if (download) { - download->stop(); - m_downloads.remove(message.download_id()); - success = true; - } - return make(success); -} - -void ClientConnection::did_receive_headers(Badge, Download& download) -{ - IPC::Dictionary response_headers; - for (auto& it : download.response_headers()) - response_headers.add(it.key, it.value); - - post_message(Messages::ProtocolClient::HeadersBecameAvailable(download.id(), move(response_headers), download.status_code())); -} - -void ClientConnection::did_finish_download(Badge, Download& download, bool success) -{ - VERIFY(download.total_size().has_value()); - - post_message(Messages::ProtocolClient::DownloadFinished(download.id(), success, download.total_size().value())); - - m_downloads.remove(download.id()); -} - -void ClientConnection::did_progress_download(Badge, Download& download) -{ - post_message(Messages::ProtocolClient::DownloadProgress(download.id(), download.total_size(), download.downloaded_size())); -} - -void ClientConnection::did_request_certificates(Badge, Download& download) -{ - post_message(Messages::ProtocolClient::CertificateRequested(download.id())); -} - -OwnPtr ClientConnection::handle(const Messages::ProtocolServer::Greet&) -{ - return make(); -} - -OwnPtr ClientConnection::handle(const Messages::ProtocolServer::SetCertificate& message) -{ - auto* download = const_cast(m_downloads.get(message.download_id()).value_or(nullptr)); - bool success = false; - if (download) { - download->set_certificate(message.certificate(), message.key()); - success = true; - } - return make(success); -} - -} diff --git a/Userland/Services/ProtocolServer/ClientConnection.h b/Userland/Services/ProtocolServer/ClientConnection.h deleted file mode 100644 index d17c10c596..0000000000 --- a/Userland/Services/ProtocolServer/ClientConnection.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include - -namespace ProtocolServer { - -class ClientConnection final - : public IPC::ClientConnection - , public ProtocolServerEndpoint { - C_OBJECT(ClientConnection); - -public: - explicit ClientConnection(NonnullRefPtr, int client_id); - ~ClientConnection() override; - - virtual void die() override; - - void did_receive_headers(Badge, Download&); - void did_finish_download(Badge, Download&, bool success); - void did_progress_download(Badge, Download&); - void did_request_certificates(Badge, Download&); - -private: - virtual OwnPtr handle(const Messages::ProtocolServer::Greet&) override; - virtual OwnPtr handle(const Messages::ProtocolServer::IsSupportedProtocol&) override; - virtual OwnPtr handle(const Messages::ProtocolServer::StartDownload&) override; - virtual OwnPtr handle(const Messages::ProtocolServer::StopDownload&) override; - virtual OwnPtr handle(const Messages::ProtocolServer::SetCertificate&) override; - - HashMap> m_downloads; -}; - -} diff --git a/Userland/Services/ProtocolServer/Download.cpp b/Userland/Services/ProtocolServer/Download.cpp deleted file mode 100644 index c6b8bdf310..0000000000 --- a/Userland/Services/ProtocolServer/Download.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include - -namespace ProtocolServer { - -// FIXME: What about rollover? -static i32 s_next_id = 1; - -Download::Download(ClientConnection& client, NonnullOwnPtr&& output_stream) - : m_client(client) - , m_id(s_next_id++) - , m_output_stream(move(output_stream)) -{ -} - -Download::~Download() -{ -} - -void Download::stop() -{ - m_client.did_finish_download({}, *this, false); -} - -void Download::set_response_headers(const HashMap& response_headers) -{ - m_response_headers = response_headers; - m_client.did_receive_headers({}, *this); -} - -void Download::set_certificate(String, String) -{ -} - -void Download::did_finish(bool success) -{ - m_client.did_finish_download({}, *this, success); -} - -void Download::did_progress(Optional total_size, u32 downloaded_size) -{ - m_total_size = total_size; - m_downloaded_size = downloaded_size; - m_client.did_progress_download({}, *this); -} - -void Download::did_request_certificates() -{ - m_client.did_request_certificates({}, *this); -} - -} diff --git a/Userland/Services/ProtocolServer/GeminiDownload.h b/Userland/Services/ProtocolServer/GeminiDownload.h deleted file mode 100644 index 20d0e79f47..0000000000 --- a/Userland/Services/ProtocolServer/GeminiDownload.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2020, The SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include - -namespace ProtocolServer { - -class GeminiDownload final : public Download { -public: - virtual ~GeminiDownload() override; - static NonnullOwnPtr create_with_job(Badge, ClientConnection&, NonnullRefPtr, NonnullOwnPtr&&); - -private: - explicit GeminiDownload(ClientConnection&, NonnullRefPtr, NonnullOwnPtr&&); - - virtual void set_certificate(String certificate, String key) override; - - NonnullRefPtr m_job; -}; - -} diff --git a/Userland/Services/ProtocolServer/HttpDownload.cpp b/Userland/Services/ProtocolServer/HttpDownload.cpp deleted file mode 100644 index 9396f02ddd..0000000000 --- a/Userland/Services/ProtocolServer/HttpDownload.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include - -namespace ProtocolServer { - -HttpDownload::HttpDownload(ClientConnection& client, NonnullRefPtr job, NonnullOwnPtr&& output_stream) - : Download(client, move(output_stream)) - , m_job(job) -{ - Detail::init(this, job); -} - -HttpDownload::~HttpDownload() -{ - m_job->on_finish = nullptr; - m_job->on_progress = nullptr; - m_job->shutdown(); -} - -NonnullOwnPtr HttpDownload::create_with_job(Badge&&, ClientConnection& client, NonnullRefPtr job, NonnullOwnPtr&& output_stream) -{ - return adopt_own(*new HttpDownload(client, move(job), move(output_stream))); -} - -} diff --git a/Userland/Services/ProtocolServer/HttpDownload.h b/Userland/Services/ProtocolServer/HttpDownload.h deleted file mode 100644 index f435cf0d24..0000000000 --- a/Userland/Services/ProtocolServer/HttpDownload.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include - -namespace ProtocolServer { - -class HttpDownload final : public Download { -public: - virtual ~HttpDownload() override; - static NonnullOwnPtr create_with_job(Badge&&, ClientConnection&, NonnullRefPtr, NonnullOwnPtr&&); - - HTTP::HttpJob& job() { return m_job; } - -private: - explicit HttpDownload(ClientConnection&, NonnullRefPtr, NonnullOwnPtr&&); - - NonnullRefPtr m_job; -}; - -} diff --git a/Userland/Services/ProtocolServer/HttpProtocol.cpp b/Userland/Services/ProtocolServer/HttpProtocol.cpp deleted file mode 100644 index 6d973c0a7e..0000000000 --- a/Userland/Services/ProtocolServer/HttpProtocol.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ProtocolServer { - -HttpProtocol::HttpProtocol() - : Protocol("http") -{ -} - -OwnPtr HttpProtocol::start_download(ClientConnection& client, const String& method, const URL& url, const HashMap& headers, ReadonlyBytes body) -{ - return Detail::start_download(Badge {}, client, method, url, headers, body, get_pipe_for_download()); -} - -} diff --git a/Userland/Services/ProtocolServer/HttpsDownload.cpp b/Userland/Services/ProtocolServer/HttpsDownload.cpp deleted file mode 100644 index 046b7c64d8..0000000000 --- a/Userland/Services/ProtocolServer/HttpsDownload.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2020, The SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include - -namespace ProtocolServer { - -HttpsDownload::HttpsDownload(ClientConnection& client, NonnullRefPtr job, NonnullOwnPtr&& output_stream) - : Download(client, move(output_stream)) - , m_job(job) -{ - Detail::init(this, job); -} - -void HttpsDownload::set_certificate(String certificate, String key) -{ - m_job->set_certificate(move(certificate), move(key)); -} - -HttpsDownload::~HttpsDownload() -{ - m_job->on_finish = nullptr; - m_job->on_progress = nullptr; - m_job->shutdown(); -} - -NonnullOwnPtr HttpsDownload::create_with_job(Badge&&, ClientConnection& client, NonnullRefPtr job, NonnullOwnPtr&& output_stream) -{ - return adopt_own(*new HttpsDownload(client, move(job), move(output_stream))); -} - -} diff --git a/Userland/Services/ProtocolServer/HttpsDownload.h b/Userland/Services/ProtocolServer/HttpsDownload.h deleted file mode 100644 index 8d17baccee..0000000000 --- a/Userland/Services/ProtocolServer/HttpsDownload.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2020, The SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include - -namespace ProtocolServer { - -class HttpsDownload final : public Download { -public: - virtual ~HttpsDownload() override; - static NonnullOwnPtr create_with_job(Badge&&, ClientConnection&, NonnullRefPtr, NonnullOwnPtr&&); - - HTTP::HttpsJob& job() { return m_job; } - -private: - explicit HttpsDownload(ClientConnection&, NonnullRefPtr, NonnullOwnPtr&&); - - virtual void set_certificate(String certificate, String key) override; - - NonnullRefPtr m_job; -}; - -} diff --git a/Userland/Services/ProtocolServer/HttpsProtocol.cpp b/Userland/Services/ProtocolServer/HttpsProtocol.cpp deleted file mode 100644 index 9567f3ed54..0000000000 --- a/Userland/Services/ProtocolServer/HttpsProtocol.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2018-2020, The SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ProtocolServer { - -HttpsProtocol::HttpsProtocol() - : Protocol("https") -{ -} - -OwnPtr HttpsProtocol::start_download(ClientConnection& client, const String& method, const URL& url, const HashMap& headers, ReadonlyBytes body) -{ - return Detail::start_download(Badge {}, client, method, url, headers, body, get_pipe_for_download()); -} - -} diff --git a/Userland/Services/ProtocolServer/ProtocolClient.ipc b/Userland/Services/ProtocolServer/ProtocolClient.ipc deleted file mode 100644 index 37707472a6..0000000000 --- a/Userland/Services/ProtocolServer/ProtocolClient.ipc +++ /dev/null @@ -1,10 +0,0 @@ -endpoint ProtocolClient -{ - // Download notifications - DownloadProgress(i32 download_id, Optional total_size, u32 downloaded_size) =| - DownloadFinished(i32 download_id, bool success, u32 total_size) =| - HeadersBecameAvailable(i32 download_id, IPC::Dictionary response_headers, Optional status_code) =| - - // Certificate requests - CertificateRequested(i32 download_id) => () -} diff --git a/Userland/Services/ProtocolServer/ProtocolServer.ipc b/Userland/Services/ProtocolServer/ProtocolServer.ipc deleted file mode 100644 index 2348e01af8..0000000000 --- a/Userland/Services/ProtocolServer/ProtocolServer.ipc +++ /dev/null @@ -1,13 +0,0 @@ -endpoint ProtocolServer -{ - // Basic protocol - Greet() => () - - // Test if a specific protocol is supported, e.g "http" - IsSupportedProtocol(String protocol) => (bool supported) - - // Download API - StartDownload(String method, URL url, IPC::Dictionary request_headers, ByteBuffer request_body) => (i32 download_id, Optional response_fd) - StopDownload(i32 download_id) => (bool success) - SetCertificate(i32 download_id, String certificate, String key) => (bool success) -} diff --git a/Userland/Services/RequestServer/CMakeLists.txt b/Userland/Services/RequestServer/CMakeLists.txt new file mode 100644 index 0000000000..c027c7e4ea --- /dev/null +++ b/Userland/Services/RequestServer/CMakeLists.txt @@ -0,0 +1,20 @@ +compile_ipc(RequestServer.ipc RequestServerEndpoint.h) +compile_ipc(RequestClient.ipc RequestClientEndpoint.h) + +set(SOURCES + ClientConnection.cpp + Request.cpp + RequestClientEndpoint.h + RequestServerEndpoint.h + GeminiRequest.cpp + GeminiProtocol.cpp + HttpRequest.cpp + HttpProtocol.cpp + HttpsRequest.cpp + HttpsProtocol.cpp + main.cpp + Protocol.cpp +) + +serenity_bin(RequestServer) +target_link_libraries(RequestServer LibCore LibIPC LibGemini LibHTTP) diff --git a/Userland/Services/RequestServer/ClientConnection.cpp b/Userland/Services/RequestServer/ClientConnection.cpp new file mode 100644 index 0000000000..8324f32ca6 --- /dev/null +++ b/Userland/Services/RequestServer/ClientConnection.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include + +namespace RequestServer { + +static HashMap> s_connections; + +ClientConnection::ClientConnection(NonnullRefPtr socket, int client_id) + : IPC::ClientConnection(*this, move(socket), client_id) +{ + s_connections.set(client_id, *this); +} + +ClientConnection::~ClientConnection() +{ +} + +void ClientConnection::die() +{ + s_connections.remove(client_id()); + if (s_connections.is_empty()) + Core::EventLoop::current().quit(0); +} + +OwnPtr ClientConnection::handle(const Messages::RequestServer::IsSupportedProtocol& message) +{ + bool supported = Protocol::find_by_name(message.protocol().to_lowercase()); + return make(supported); +} + +OwnPtr ClientConnection::handle(const Messages::RequestServer::StartRequest& message) +{ + const auto& url = message.url(); + if (!url.is_valid()) { + dbgln("StartRequest: Invalid URL requested: '{}'", url); + return make(-1, Optional {}); + } + auto* protocol = Protocol::find_by_name(url.protocol()); + if (!protocol) { + dbgln("StartRequest: No protocol handler for URL: '{}'", url); + return make(-1, Optional {}); + } + auto request = protocol->start_request(*this, message.method(), url, message.request_headers().entries(), message.request_body()); + if (!request) { + dbgln("StartRequest: Protocol handler failed to start request: '{}'", url); + return make(-1, Optional {}); + } + auto id = request->id(); + auto fd = request->request_fd(); + m_requests.set(id, move(request)); + return make(id, IPC::File(fd, IPC::File::CloseAfterSending)); +} + +OwnPtr ClientConnection::handle(const Messages::RequestServer::StopRequest& message) +{ + auto* request = const_cast(m_requests.get(message.request_id()).value_or(nullptr)); + bool success = false; + if (request) { + request->stop(); + m_requests.remove(message.request_id()); + success = true; + } + return make(success); +} + +void ClientConnection::did_receive_headers(Badge, Request& request) +{ + IPC::Dictionary response_headers; + for (auto& it : request.response_headers()) + response_headers.add(it.key, it.value); + + post_message(Messages::RequestClient::HeadersBecameAvailable(request.id(), move(response_headers), request.status_code())); +} + +void ClientConnection::did_finish_request(Badge, Request& request, bool success) +{ + VERIFY(request.total_size().has_value()); + + post_message(Messages::RequestClient::RequestFinished(request.id(), success, request.total_size().value())); + + m_requests.remove(request.id()); +} + +void ClientConnection::did_progress_request(Badge, Request& request) +{ + post_message(Messages::RequestClient::RequestProgress(request.id(), request.total_size(), request.downloaded_size())); +} + +void ClientConnection::did_request_certificates(Badge, Request& request) +{ + post_message(Messages::RequestClient::CertificateRequested(request.id())); +} + +OwnPtr ClientConnection::handle(const Messages::RequestServer::Greet&) +{ + return make(); +} + +OwnPtr ClientConnection::handle(const Messages::RequestServer::SetCertificate& message) +{ + auto* request = const_cast(m_requests.get(message.request_id()).value_or(nullptr)); + bool success = false; + if (request) { + request->set_certificate(message.certificate(), message.key()); + success = true; + } + return make(success); +} + +} diff --git a/Userland/Services/RequestServer/ClientConnection.h b/Userland/Services/RequestServer/ClientConnection.h new file mode 100644 index 0000000000..6760d75aee --- /dev/null +++ b/Userland/Services/RequestServer/ClientConnection.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace RequestServer { + +class ClientConnection final + : public IPC::ClientConnection + , public RequestServerEndpoint { + C_OBJECT(ClientConnection); + +public: + explicit ClientConnection(NonnullRefPtr, int client_id); + ~ClientConnection() override; + + virtual void die() override; + + void did_receive_headers(Badge, Request&); + void did_finish_request(Badge, Request&, bool success); + void did_progress_request(Badge, Request&); + void did_request_certificates(Badge, Request&); + +private: + virtual OwnPtr handle(const Messages::RequestServer::Greet&) override; + virtual OwnPtr handle(const Messages::RequestServer::IsSupportedProtocol&) override; + virtual OwnPtr handle(const Messages::RequestServer::StartRequest&) override; + virtual OwnPtr handle(const Messages::RequestServer::StopRequest&) override; + virtual OwnPtr handle(const Messages::RequestServer::SetCertificate&) override; + + HashMap> m_requests; +}; + +} diff --git a/Userland/Services/ProtocolServer/Forward.h b/Userland/Services/RequestServer/Forward.h similarity index 73% rename from Userland/Services/ProtocolServer/Forward.h rename to Userland/Services/RequestServer/Forward.h index f2caea5ae8..436c7bf4f8 100644 --- a/Userland/Services/ProtocolServer/Forward.h +++ b/Userland/Services/RequestServer/Forward.h @@ -6,14 +6,14 @@ #pragma once -namespace ProtocolServer { +namespace RequestServer { class ClientConnection; -class Download; +class Request; class GeminiProtocol; -class HttpDownload; +class HttpRequest; class HttpProtocol; -class HttpsDownload; +class HttpsRequest; class HttpsProtocol; class Protocol; diff --git a/Userland/Services/ProtocolServer/GeminiProtocol.cpp b/Userland/Services/RequestServer/GeminiProtocol.cpp similarity index 54% rename from Userland/Services/ProtocolServer/GeminiProtocol.cpp rename to Userland/Services/RequestServer/GeminiProtocol.cpp index cdddba36e7..243dddce5d 100644 --- a/Userland/Services/ProtocolServer/GeminiProtocol.cpp +++ b/Userland/Services/RequestServer/GeminiProtocol.cpp @@ -6,11 +6,11 @@ #include #include -#include -#include +#include +#include #include -namespace ProtocolServer { +namespace RequestServer { GeminiProtocol::GeminiProtocol() : Protocol("gemini") @@ -21,22 +21,22 @@ GeminiProtocol::~GeminiProtocol() { } -OwnPtr GeminiProtocol::start_download(ClientConnection& client, const String&, const URL& url, const HashMap&, ReadonlyBytes) +OwnPtr GeminiProtocol::start_request(ClientConnection& client, const String&, const URL& url, const HashMap&, ReadonlyBytes) { Gemini::GeminiRequest request; request.set_url(url); - auto pipe_result = get_pipe_for_download(); + auto pipe_result = get_pipe_for_request(); if (pipe_result.is_error()) return {}; auto output_stream = make(pipe_result.value().write_fd); output_stream->make_unbuffered(); auto job = Gemini::GeminiJob::construct(request, *output_stream); - auto download = GeminiDownload::create_with_job({}, client, (Gemini::GeminiJob&)*job, move(output_stream)); - download->set_download_fd(pipe_result.value().read_fd); + auto protocol_request = GeminiRequest::create_with_job({}, client, (Gemini::GeminiJob&)*job, move(output_stream)); + protocol_request->set_request_fd(pipe_result.value().read_fd); job->start(); - return download; + return protocol_request; } } diff --git a/Userland/Services/ProtocolServer/GeminiProtocol.h b/Userland/Services/RequestServer/GeminiProtocol.h similarity index 52% rename from Userland/Services/ProtocolServer/GeminiProtocol.h rename to Userland/Services/RequestServer/GeminiProtocol.h index 33e4e8a554..4b530d71d0 100644 --- a/Userland/Services/ProtocolServer/GeminiProtocol.h +++ b/Userland/Services/RequestServer/GeminiProtocol.h @@ -6,16 +6,16 @@ #pragma once -#include +#include -namespace ProtocolServer { +namespace RequestServer { class GeminiProtocol final : public Protocol { public: GeminiProtocol(); virtual ~GeminiProtocol() override; - virtual OwnPtr start_download(ClientConnection&, const String& method, const URL&, const HashMap&, ReadonlyBytes body) override; + virtual OwnPtr start_request(ClientConnection&, const String& method, const URL&, const HashMap&, ReadonlyBytes body) override; }; } diff --git a/Userland/Services/ProtocolServer/GeminiDownload.cpp b/Userland/Services/RequestServer/GeminiRequest.cpp similarity index 68% rename from Userland/Services/ProtocolServer/GeminiDownload.cpp rename to Userland/Services/RequestServer/GeminiRequest.cpp index a68d4d26af..39224e4197 100644 --- a/Userland/Services/ProtocolServer/GeminiDownload.cpp +++ b/Userland/Services/RequestServer/GeminiRequest.cpp @@ -6,12 +6,12 @@ #include #include -#include +#include -namespace ProtocolServer { +namespace RequestServer { -GeminiDownload::GeminiDownload(ClientConnection& client, NonnullRefPtr job, NonnullOwnPtr&& output_stream) - : Download(client, move(output_stream)) +GeminiRequest::GeminiRequest(ClientConnection& client, NonnullRefPtr job, NonnullOwnPtr&& output_stream) + : Request(client, move(output_stream)) , m_job(job) { m_job->on_finish = [this](bool success) { @@ -30,7 +30,7 @@ GeminiDownload::GeminiDownload(ClientConnection& client, NonnullRefPtrset_certificate(move(certificate), move(key)); } -GeminiDownload::~GeminiDownload() +GeminiRequest::~GeminiRequest() { m_job->on_finish = nullptr; m_job->on_progress = nullptr; m_job->shutdown(); } -NonnullOwnPtr GeminiDownload::create_with_job(Badge, ClientConnection& client, NonnullRefPtr job, NonnullOwnPtr&& output_stream) +NonnullOwnPtr GeminiRequest::create_with_job(Badge, ClientConnection& client, NonnullRefPtr job, NonnullOwnPtr&& output_stream) { - return adopt_own(*new GeminiDownload(client, move(job), move(output_stream))); + return adopt_own(*new GeminiRequest(client, move(job), move(output_stream))); } } diff --git a/Userland/Services/RequestServer/GeminiRequest.h b/Userland/Services/RequestServer/GeminiRequest.h new file mode 100644 index 0000000000..9bce9ec587 --- /dev/null +++ b/Userland/Services/RequestServer/GeminiRequest.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020, The SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include + +namespace RequestServer { + +class GeminiRequest final : public Request { +public: + virtual ~GeminiRequest() override; + static NonnullOwnPtr create_with_job(Badge, ClientConnection&, NonnullRefPtr, NonnullOwnPtr&&); + +private: + explicit GeminiRequest(ClientConnection&, NonnullRefPtr, NonnullOwnPtr&&); + + virtual void set_certificate(String certificate, String key) override; + + NonnullRefPtr m_job; +}; + +} diff --git a/Userland/Services/ProtocolServer/HttpCommon.h b/Userland/Services/RequestServer/HttpCommon.h similarity index 75% rename from Userland/Services/ProtocolServer/HttpCommon.h rename to Userland/Services/RequestServer/HttpCommon.h index baa584c0f1..a79a6fbce8 100644 --- a/Userland/Services/ProtocolServer/HttpCommon.h +++ b/Userland/Services/RequestServer/HttpCommon.h @@ -14,10 +14,10 @@ #include #include #include -#include -#include +#include +#include -namespace ProtocolServer::Detail { +namespace RequestServer::Detail { template void init(TSelf* self, TJob job) @@ -35,7 +35,7 @@ void init(TSelf* self, TJob job) self->set_downloaded_size(self->output_stream().size()); } - // if we didn't know the total size, pretend that the download finished successfully + // if we didn't know the total size, pretend that the request finished successfully // and set the total size to the downloaded size if (!self->total_size().has_value()) self->did_progress(self->downloaded_size(), self->downloaded_size()); @@ -53,10 +53,10 @@ void init(TSelf* self, TJob job) } template -OwnPtr start_download(TBadgedProtocol&& protocol, ClientConnection& client, const String& method, const URL& url, const HashMap& headers, ReadonlyBytes body, TPipeResult&& pipe_result) +OwnPtr start_request(TBadgedProtocol&& protocol, ClientConnection& client, const String& method, const URL& url, const HashMap& headers, ReadonlyBytes body, TPipeResult&& pipe_result) { using TJob = TBadgedProtocol::Type::JobType; - using TDownload = TBadgedProtocol::Type::DownloadType; + using TRequest = TBadgedProtocol::Type::RequestType; if (pipe_result.is_error()) { return {}; @@ -74,10 +74,10 @@ OwnPtr start_download(TBadgedProtocol&& protocol, ClientConnection& cl auto output_stream = make(pipe_result.value().write_fd); output_stream->make_unbuffered(); auto job = TJob::construct(request, *output_stream); - auto download = TDownload::create_with_job(forward(protocol), client, (TJob&)*job, move(output_stream)); - download->set_download_fd(pipe_result.value().read_fd); + auto protocol_request = TRequest::create_with_job(forward(protocol), client, (TJob&)*job, move(output_stream)); + protocol_request->set_request_fd(pipe_result.value().read_fd); job->start(); - return download; + return protocol_request; } } diff --git a/Userland/Services/RequestServer/HttpProtocol.cpp b/Userland/Services/RequestServer/HttpProtocol.cpp new file mode 100644 index 0000000000..fb21f56074 --- /dev/null +++ b/Userland/Services/RequestServer/HttpProtocol.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace RequestServer { + +HttpProtocol::HttpProtocol() + : Protocol("http") +{ +} + +OwnPtr HttpProtocol::start_request(ClientConnection& client, const String& method, const URL& url, const HashMap& headers, ReadonlyBytes body) +{ + return Detail::start_request(Badge {}, client, method, url, headers, body, get_pipe_for_request()); +} + +} diff --git a/Userland/Services/ProtocolServer/HttpProtocol.h b/Userland/Services/RequestServer/HttpProtocol.h similarity index 52% rename from Userland/Services/ProtocolServer/HttpProtocol.h rename to Userland/Services/RequestServer/HttpProtocol.h index c4ba1a3d84..5641142e32 100644 --- a/Userland/Services/ProtocolServer/HttpProtocol.h +++ b/Userland/Services/RequestServer/HttpProtocol.h @@ -12,22 +12,22 @@ #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include -namespace ProtocolServer { +namespace RequestServer { class HttpProtocol final : public Protocol { public: using JobType = HTTP::HttpJob; - using DownloadType = HttpDownload; + using RequestType = HttpRequest; HttpProtocol(); ~HttpProtocol() override = default; - virtual OwnPtr start_download(ClientConnection&, const String& method, const URL&, const HashMap& headers, ReadonlyBytes body) override; + virtual OwnPtr start_request(ClientConnection&, const String& method, const URL&, const HashMap& headers, ReadonlyBytes body) override; }; } diff --git a/Userland/Services/RequestServer/HttpRequest.cpp b/Userland/Services/RequestServer/HttpRequest.cpp new file mode 100644 index 0000000000..0a13a520ca --- /dev/null +++ b/Userland/Services/RequestServer/HttpRequest.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include + +namespace RequestServer { + +HttpRequest::HttpRequest(ClientConnection& client, NonnullRefPtr job, NonnullOwnPtr&& output_stream) + : Request(client, move(output_stream)) + , m_job(job) +{ + Detail::init(this, job); +} + +HttpRequest::~HttpRequest() +{ + m_job->on_finish = nullptr; + m_job->on_progress = nullptr; + m_job->shutdown(); +} + +NonnullOwnPtr HttpRequest::create_with_job(Badge&&, ClientConnection& client, NonnullRefPtr job, NonnullOwnPtr&& output_stream) +{ + return adopt_own(*new HttpRequest(client, move(job), move(output_stream))); +} + +} diff --git a/Userland/Services/RequestServer/HttpRequest.h b/Userland/Services/RequestServer/HttpRequest.h new file mode 100644 index 0000000000..aa7e7f999d --- /dev/null +++ b/Userland/Services/RequestServer/HttpRequest.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace RequestServer { + +class HttpRequest final : public Request { +public: + virtual ~HttpRequest() override; + static NonnullOwnPtr create_with_job(Badge&&, ClientConnection&, NonnullRefPtr, NonnullOwnPtr&&); + + HTTP::HttpJob& job() { return m_job; } + +private: + explicit HttpRequest(ClientConnection&, NonnullRefPtr, NonnullOwnPtr&&); + + NonnullRefPtr m_job; +}; + +} diff --git a/Userland/Services/RequestServer/HttpsProtocol.cpp b/Userland/Services/RequestServer/HttpsProtocol.cpp new file mode 100644 index 0000000000..a3a1cfcb65 --- /dev/null +++ b/Userland/Services/RequestServer/HttpsProtocol.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2018-2020, The SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace RequestServer { + +HttpsProtocol::HttpsProtocol() + : Protocol("https") +{ +} + +OwnPtr HttpsProtocol::start_request(ClientConnection& client, const String& method, const URL& url, const HashMap& headers, ReadonlyBytes body) +{ + return Detail::start_request(Badge {}, client, method, url, headers, body, get_pipe_for_request()); +} + +} diff --git a/Userland/Services/ProtocolServer/HttpsProtocol.h b/Userland/Services/RequestServer/HttpsProtocol.h similarity index 52% rename from Userland/Services/ProtocolServer/HttpsProtocol.h rename to Userland/Services/RequestServer/HttpsProtocol.h index 622edf86cb..9c67c3ee0c 100644 --- a/Userland/Services/ProtocolServer/HttpsProtocol.h +++ b/Userland/Services/RequestServer/HttpsProtocol.h @@ -12,22 +12,22 @@ #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include -namespace ProtocolServer { +namespace RequestServer { class HttpsProtocol final : public Protocol { public: using JobType = HTTP::HttpsJob; - using DownloadType = HttpsDownload; + using RequestType = HttpsRequest; HttpsProtocol(); ~HttpsProtocol() override = default; - virtual OwnPtr start_download(ClientConnection&, const String& method, const URL&, const HashMap& headers, ReadonlyBytes body) override; + virtual OwnPtr start_request(ClientConnection&, const String& method, const URL&, const HashMap& headers, ReadonlyBytes body) override; }; } diff --git a/Userland/Services/RequestServer/HttpsRequest.cpp b/Userland/Services/RequestServer/HttpsRequest.cpp new file mode 100644 index 0000000000..a115397049 --- /dev/null +++ b/Userland/Services/RequestServer/HttpsRequest.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020, The SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include + +namespace RequestServer { + +HttpsRequest::HttpsRequest(ClientConnection& client, NonnullRefPtr job, NonnullOwnPtr&& output_stream) + : Request(client, move(output_stream)) + , m_job(job) +{ + Detail::init(this, job); +} + +void HttpsRequest::set_certificate(String certificate, String key) +{ + m_job->set_certificate(move(certificate), move(key)); +} + +HttpsRequest::~HttpsRequest() +{ + m_job->on_finish = nullptr; + m_job->on_progress = nullptr; + m_job->shutdown(); +} + +NonnullOwnPtr HttpsRequest::create_with_job(Badge&&, ClientConnection& client, NonnullRefPtr job, NonnullOwnPtr&& output_stream) +{ + return adopt_own(*new HttpsRequest(client, move(job), move(output_stream))); +} + +} diff --git a/Userland/Services/RequestServer/HttpsRequest.h b/Userland/Services/RequestServer/HttpsRequest.h new file mode 100644 index 0000000000..05952887c0 --- /dev/null +++ b/Userland/Services/RequestServer/HttpsRequest.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2020, The SerenityOS developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include + +namespace RequestServer { + +class HttpsRequest final : public Request { +public: + virtual ~HttpsRequest() override; + static NonnullOwnPtr create_with_job(Badge&&, ClientConnection&, NonnullRefPtr, NonnullOwnPtr&&); + + HTTP::HttpsJob& job() { return m_job; } + +private: + explicit HttpsRequest(ClientConnection&, NonnullRefPtr, NonnullOwnPtr&&); + + virtual void set_certificate(String certificate, String key) override; + + NonnullRefPtr m_job; +}; + +} diff --git a/Userland/Services/ProtocolServer/Protocol.cpp b/Userland/Services/RequestServer/Protocol.cpp similarity index 87% rename from Userland/Services/ProtocolServer/Protocol.cpp rename to Userland/Services/RequestServer/Protocol.cpp index ebc259102c..19f9fdb1f4 100644 --- a/Userland/Services/ProtocolServer/Protocol.cpp +++ b/Userland/Services/RequestServer/Protocol.cpp @@ -5,13 +5,13 @@ */ #include -#include +#include #include #include #include #include -namespace ProtocolServer { +namespace RequestServer { static HashMap& all_protocols() { @@ -34,7 +34,7 @@ Protocol::~Protocol() VERIFY_NOT_REACHED(); } -Result Protocol::get_pipe_for_download() +Result Protocol::get_pipe_for_request() { int fd_pair[2] { 0 }; if (pipe(fd_pair) != 0) { diff --git a/Userland/Services/ProtocolServer/Protocol.h b/Userland/Services/RequestServer/Protocol.h similarity index 64% rename from Userland/Services/ProtocolServer/Protocol.h rename to Userland/Services/RequestServer/Protocol.h index fcfc44e267..b153ba8765 100644 --- a/Userland/Services/ProtocolServer/Protocol.h +++ b/Userland/Services/RequestServer/Protocol.h @@ -9,16 +9,16 @@ #include #include #include -#include +#include -namespace ProtocolServer { +namespace RequestServer { class Protocol { public: virtual ~Protocol(); const String& name() const { return m_name; } - virtual OwnPtr start_download(ClientConnection&, const String& method, const URL&, const HashMap& headers, ReadonlyBytes body) = 0; + virtual OwnPtr start_request(ClientConnection&, const String& method, const URL&, const HashMap& headers, ReadonlyBytes body) = 0; static Protocol* find_by_name(const String&); @@ -28,7 +28,7 @@ protected: int read_fd { -1 }; int write_fd { -1 }; }; - static Result get_pipe_for_download(); + static Result get_pipe_for_request(); private: String m_name; diff --git a/Userland/Services/RequestServer/Request.cpp b/Userland/Services/RequestServer/Request.cpp new file mode 100644 index 0000000000..14870cb23b --- /dev/null +++ b/Userland/Services/RequestServer/Request.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +namespace RequestServer { + +// FIXME: What about rollover? +static i32 s_next_id = 1; + +Request::Request(ClientConnection& client, NonnullOwnPtr&& output_stream) + : m_client(client) + , m_id(s_next_id++) + , m_output_stream(move(output_stream)) +{ +} + +Request::~Request() +{ +} + +void Request::stop() +{ + m_client.did_finish_request({}, *this, false); +} + +void Request::set_response_headers(const HashMap& response_headers) +{ + m_response_headers = response_headers; + m_client.did_receive_headers({}, *this); +} + +void Request::set_certificate(String, String) +{ +} + +void Request::did_finish(bool success) +{ + m_client.did_finish_request({}, *this, success); +} + +void Request::did_progress(Optional total_size, u32 downloaded_size) +{ + m_total_size = total_size; + m_downloaded_size = downloaded_size; + m_client.did_progress_request({}, *this); +} + +void Request::did_request_certificates() +{ + m_client.did_request_certificates({}, *this); +} + +} diff --git a/Userland/Services/ProtocolServer/Download.h b/Userland/Services/RequestServer/Request.h similarity index 82% rename from Userland/Services/ProtocolServer/Download.h rename to Userland/Services/RequestServer/Request.h index c60a56776d..324f027c93 100644 --- a/Userland/Services/ProtocolServer/Download.h +++ b/Userland/Services/RequestServer/Request.h @@ -12,13 +12,13 @@ #include #include #include -#include +#include -namespace ProtocolServer { +namespace RequestServer { -class Download { +class Request { public: - virtual ~Download(); + virtual ~Request(); i32 id() const { return m_id; } URL url() const { return m_url; } @@ -32,8 +32,8 @@ public: virtual void set_certificate(String, String); // FIXME: Want Badge, but can't make one from HttpProtocol, etc. - void set_download_fd(int fd) { m_download_fd = fd; } - int download_fd() const { return m_download_fd; } + void set_request_fd(int fd) { m_request_fd = fd; } + int request_fd() const { return m_request_fd; } void did_finish(bool success); void did_progress(Optional total_size, u32 downloaded_size); @@ -44,12 +44,12 @@ public: const OutputFileStream& output_stream() const { return *m_output_stream; } protected: - explicit Download(ClientConnection&, NonnullOwnPtr&&); + explicit Request(ClientConnection&, NonnullOwnPtr&&); private: ClientConnection& m_client; i32 m_id { 0 }; - int m_download_fd { -1 }; // Passed to client. + int m_request_fd { -1 }; // Passed to client. URL m_url; Optional m_status_code; Optional m_total_size {}; diff --git a/Userland/Services/RequestServer/RequestClient.ipc b/Userland/Services/RequestServer/RequestClient.ipc new file mode 100644 index 0000000000..4aedc80248 --- /dev/null +++ b/Userland/Services/RequestServer/RequestClient.ipc @@ -0,0 +1,9 @@ +endpoint RequestClient +{ + RequestProgress(i32 request_id, Optional total_size, u32 downloaded_size) =| + RequestFinished(i32 request_id, bool success, u32 total_size) =| + HeadersBecameAvailable(i32 request_id, IPC::Dictionary response_headers, Optional status_code) =| + + // Certificate requests + CertificateRequested(i32 request_id) => () +} diff --git a/Userland/Services/RequestServer/RequestServer.ipc b/Userland/Services/RequestServer/RequestServer.ipc new file mode 100644 index 0000000000..8b35a52df4 --- /dev/null +++ b/Userland/Services/RequestServer/RequestServer.ipc @@ -0,0 +1,12 @@ +endpoint RequestServer +{ + // Basic protocol + Greet() => () + + // Test if a specific protocol is supported, e.g "http" + IsSupportedProtocol(String protocol) => (bool supported) + + StartRequest(String method, URL url, IPC::Dictionary request_headers, ByteBuffer request_body) => (i32 request_id, Optional response_fd) + StopRequest(i32 request_id) => (bool success) + SetCertificate(i32 request_id, String certificate, String key) => (bool success) +} diff --git a/Userland/Services/ProtocolServer/main.cpp b/Userland/Services/RequestServer/main.cpp similarity index 69% rename from Userland/Services/ProtocolServer/main.cpp rename to Userland/Services/RequestServer/main.cpp index 36622372be..0038c891f4 100644 --- a/Userland/Services/ProtocolServer/main.cpp +++ b/Userland/Services/RequestServer/main.cpp @@ -8,10 +8,10 @@ #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include int main(int, char**) { @@ -38,12 +38,12 @@ int main(int, char**) return 1; } - [[maybe_unused]] auto gemini = new ProtocolServer::GeminiProtocol; - [[maybe_unused]] auto http = new ProtocolServer::HttpProtocol; - [[maybe_unused]] auto https = new ProtocolServer::HttpsProtocol; + [[maybe_unused]] auto gemini = new RequestServer::GeminiProtocol; + [[maybe_unused]] auto http = new RequestServer::HttpProtocol; + [[maybe_unused]] auto https = new RequestServer::HttpsProtocol; auto socket = Core::LocalSocket::take_over_accepted_socket_from_system_server(); VERIFY(socket); - IPC::new_client_connection(socket.release_nonnull(), 1); + IPC::new_client_connection(socket.release_nonnull(), 1); return event_loop.exec(); } diff --git a/Userland/Services/WebContent/main.cpp b/Userland/Services/WebContent/main.cpp index 4f1677001d..aa37ad0cf8 100644 --- a/Userland/Services/WebContent/main.cpp +++ b/Userland/Services/WebContent/main.cpp @@ -20,7 +20,7 @@ int main(int, char**) perror("unveil"); return 1; } - if (unveil("/tmp/portal/protocol", "rw") < 0) { + if (unveil("/tmp/portal/request", "rw") < 0) { perror("unveil"); return 1; } diff --git a/Userland/Utilities/pro.cpp b/Userland/Utilities/pro.cpp index e5055f1846..9b6da33ba3 100644 --- a/Userland/Utilities/pro.cpp +++ b/Userland/Utilities/pro.cpp @@ -12,8 +12,8 @@ #include #include #include -#include -#include +#include +#include #include #include @@ -151,7 +151,7 @@ int main(int argc, char** argv) Core::ArgsParser args_parser; args_parser.set_general_help( - "Download a file from an arbitrary URL. This command uses ProtocolServer, " + "Request a file from an arbitrary URL. This command uses RequestServer, " "and thus supports at least http, https, and gemini."); args_parser.add_option(save_at_provided_name, "Write to a file named as the remote file", nullptr, 'O'); args_parser.add_option(data, "(HTTP only) Send the provided data via an HTTP POST request", "data", 'd', "data"); @@ -184,11 +184,11 @@ int main(int argc, char** argv) } Core::EventLoop loop; - auto protocol_client = Protocol::Client::construct(); + auto protocol_client = Protocol::RequestClient::construct(); - auto download = protocol_client->start_download(method, url.to_string(), request_headers, data ? StringView { data }.bytes() : ReadonlyBytes {}); - if (!download) { - fprintf(stderr, "Failed to start download for '%s'\n", url_str); + auto request = protocol_client->start_request(method, url.to_string(), request_headers, data ? StringView { data }.bytes() : ReadonlyBytes {}); + if (!request) { + fprintf(stderr, "Failed to start request for '%s'\n", url_str); return 1; } @@ -200,7 +200,7 @@ int main(int argc, char** argv) bool received_actual_headers = false; - download->on_progress = [&](Optional maybe_total_size, u32 downloaded_size) { + request->on_progress = [&](Optional maybe_total_size, u32 downloaded_size) { fprintf(stderr, "\r\033[2K"); if (maybe_total_size.has_value()) { fprintf(stderr, "\033]9;%d;%d;\033\\", downloaded_size, maybe_total_size.value()); @@ -227,7 +227,7 @@ int main(int argc, char** argv) }; if (save_at_provided_name) { - download->on_headers_received = [&](auto& response_headers, auto status_code) { + request->on_headers_received = [&](auto& response_headers, auto status_code) { if (received_actual_headers) return; dbgln("Received headers! response code = {}", status_code.value_or(0)); @@ -263,18 +263,18 @@ int main(int argc, char** argv) } }; } - download->on_finish = [&](bool success, auto) { + request->on_finish = [&](bool success, auto) { fprintf(stderr, "\033]9;-1;\033\\"); fprintf(stderr, "\n"); if (!success) - fprintf(stderr, "Download failed :(\n"); + fprintf(stderr, "Request failed :(\n"); loop.quit(0); }; auto output_stream = ConditionalOutputFileStream { [&] { return save_at_provided_name ? received_actual_headers : true; }, stdout }; - download->stream_into(output_stream); + request->stream_into(output_stream); - dbgln("started download with id {}", download->id()); + dbgln("started request with id {}", request->id()); auto rc = loop.exec(); // FIXME: This shouldn't be needed.