diff options
58 files changed, 786 insertions, 788 deletions
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 @@ -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 <LibGUI/MessageBox.h> #include <LibGUI/Progressbar.h> #include <LibGUI/Window.h> -#include <LibProtocol/Client.h> +#include <LibProtocol/RequestClient.h> #include <LibWeb/Loader/ResourceLoader.h> #include <math.h> @@ -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<u32> 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 <LibCore/FileStream.h> #include <LibGUI/Progressbar.h> #include <LibGUI/Widget.h> -#include <LibProtocol/Download.h> +#include <LibProtocol/Request.h> namespace Browser { @@ -29,7 +29,7 @@ private: URL m_url; String m_destination_path; - RefPtr<Protocol::Download> m_download; + RefPtr<Protocol::Request> m_download; RefPtr<GUI::Progressbar> m_progressbar; RefPtr<GUI::Label> m_progress_label; RefPtr<GUI::Button> 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 <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include <AK/FileStream.h> -#include <LibProtocol/Client.h> -#include <LibProtocol/Download.h> - -namespace Protocol { - -Client::Client() - : IPC::ServerConnection<ProtocolClientEndpoint, ProtocolServerEndpoint>(*this, "/tmp/portal/protocol") -{ - handshake(); -} - -void Client::handshake() -{ - send_sync<Messages::ProtocolServer::Greet>(); -} - -bool Client::is_supported_protocol(const String& protocol) -{ - return send_sync<Messages::ProtocolServer::IsSupportedProtocol>(protocol)->supported(); -} - -template<typename RequestHashMapTraits> -RefPtr<Download> Client::start_download(const String& method, const String& url, const HashMap<String, String, RequestHashMapTraits>& 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<Messages::ProtocolServer::StartDownload>(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& download) -{ - if (!m_downloads.contains(download.id())) - return false; - return send_sync<Messages::ProtocolServer::StopDownload>(download.id())->success(); -} - -bool Client::set_certificate(Badge<Download>, Download& download, String certificate, String key) -{ - if (!m_downloads.contains(download.id())) - return false; - return send_sync<Messages::ProtocolServer::SetCertificate>(download.id(), move(certificate), move(key))->success(); -} - -void Client::handle(const Messages::ProtocolClient::DownloadFinished& message) -{ - RefPtr<Download> 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<Download*>(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<Download*>(m_downloads.get(message.download_id()).value_or(nullptr))) { - HashMap<String, String, CaseInsensitiveStringTraits> headers; - message.response_headers().for_each_entry([&](auto& name, auto& value) { headers.set(name, value); }); - download->did_receive_headers({}, headers, message.status_code()); - } -} - -OwnPtr<Messages::ProtocolClient::CertificateRequestedResponse> Client::handle(const Messages::ProtocolClient::CertificateRequested& message) -{ - if (auto download = const_cast<Download*>(m_downloads.get(message.download_id()).value_or(nullptr))) { - download->did_request_certificates({}); - } - - return make<Messages::ProtocolClient::CertificateRequestedResponse>(); -} - -} - -template RefPtr<Protocol::Download> Protocol::Client::start_download(const String& method, const String& url, const HashMap<String, String>& request_headers, ReadonlyBytes request_body); -template RefPtr<Protocol::Download> Protocol::Client::start_download(const String& method, const String& url, const HashMap<String, String, CaseInsensitiveStringTraits>& 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 <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include <AK/HashMap.h> -#include <LibIPC/ServerConnection.h> -#include <ProtocolServer/ProtocolClientEndpoint.h> -#include <ProtocolServer/ProtocolServerEndpoint.h> - -namespace Protocol { - -class Download; - -class Client - : public IPC::ServerConnection<ProtocolClientEndpoint, ProtocolServerEndpoint> - , public ProtocolClientEndpoint { - C_OBJECT(Client); - -public: - virtual void handshake() override; - - bool is_supported_protocol(const String&); - template<typename RequestHashMapTraits = Traits<String>> - RefPtr<Download> start_download(const String& method, const String& url, const HashMap<String, String, RequestHashMapTraits>& request_headers = {}, ReadonlyBytes request_body = {}); - - bool stop_download(Badge<Download>, Download&); - bool set_certificate(Badge<Download>, Download&, String, String); - -private: - Client(); - - virtual void handle(const Messages::ProtocolClient::DownloadProgress&) override; - virtual void handle(const Messages::ProtocolClient::DownloadFinished&) override; - virtual OwnPtr<Messages::ProtocolClient::CertificateRequestedResponse> handle(const Messages::ProtocolClient::CertificateRequested&) override; - virtual void handle(const Messages::ProtocolClient::HeadersBecameAvailable&) override; - - HashMap<i32, RefPtr<Download>> m_downloads; -}; - -} diff --git a/Userland/Libraries/LibProtocol/Download.cpp b/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 <LibProtocol/Client.h> -#include <LibProtocol/Download.h> +#include <LibProtocol/Request.h> +#include <LibProtocol/RequestClient.h> 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<InternalBufferedData>(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<Client>, bool success, u32 total_size) +void Request::did_finish(Badge<RequestClient>, bool success, u32 total_size) { if (!on_finish) return; @@ -97,24 +97,24 @@ void Download::did_finish(Badge<Client>, bool success, u32 total_size) on_finish(success, total_size); } -void Download::did_progress(Badge<Client>, Optional<u32> total_size, u32 downloaded_size) +void Request::did_progress(Badge<RequestClient>, Optional<u32> total_size, u32 downloaded_size) { if (on_progress) on_progress(total_size, downloaded_size); } -void Download::did_receive_headers(Badge<Client>, const HashMap<String, String, CaseInsensitiveStringTraits>& response_headers, Optional<u32> response_code) +void Request::did_receive_headers(Badge<RequestClient>, const HashMap<String, String, CaseInsensitiveStringTraits>& response_headers, Optional<u32> response_code) { if (on_headers_received) on_headers_received(response_headers, response_code); } -void Download::did_request_certificates(Badge<Client>) +void Request::did_request_certificates(Badge<RequestClient>) { 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 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<Download> { +class Request : public RefCounted<Request> { public: struct CertificateAndKey { String certificate; String key; }; - static NonnullRefPtr<Download> create_from_id(Badge<Client>, Client& client, i32 download_id) + static NonnullRefPtr<Request> create_from_id(Badge<RequestClient>, 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<void(bool success, u32 total_size, const HashMap<String, String, CaseInsensitiveStringTraits>& response_headers, Optional<u32> response_code, ReadonlyBytes payload)> on_buffered_download_finish; + Function<void(bool success, u32 total_size, const HashMap<String, String, CaseInsensitiveStringTraits>& response_headers, Optional<u32> response_code, ReadonlyBytes payload)> on_buffered_request_finish; Function<void(bool success, u32 total_size)> on_finish; Function<void(Optional<u32> total_size, u32 downloaded_size)> on_progress; Function<void(const HashMap<String, String, CaseInsensitiveStringTraits>& response_headers, Optional<u32> response_code)> on_headers_received; Function<CertificateAndKey()> on_certificate_requested; - void did_finish(Badge<Client>, bool success, u32 total_size); - void did_progress(Badge<Client>, Optional<u32> total_size, u32 downloaded_size); - void did_receive_headers(Badge<Client>, const HashMap<String, String, CaseInsensitiveStringTraits>& response_headers, Optional<u32> response_code); - void did_request_certificates(Badge<Client>); + void did_finish(Badge<RequestClient>, bool success, u32 total_size); + void did_progress(Badge<RequestClient>, Optional<u32> total_size, u32 downloaded_size); + void did_receive_headers(Badge<RequestClient>, const HashMap<String, String, CaseInsensitiveStringTraits>& response_headers, Optional<u32> response_code); + void did_request_certificates(Badge<RequestClient>); - RefPtr<Core::Notifier>& write_notifier(Badge<Client>) { return m_write_notifier; } - void set_download_fd(Badge<Client>, int fd) { m_fd = fd; } + RefPtr<Core::Notifier>& write_notifier(Badge<RequestClient>) { return m_write_notifier; } + void set_request_fd(Badge<RequestClient>, int fd) { m_fd = fd; } private: - explicit Download(Client&, i32 download_id); - WeakPtr<Client> m_client; - int m_download_id { -1 }; + explicit Request(RequestClient&, i32 request_id); + WeakPtr<RequestClient> m_client; + int m_request_id { -1 }; RefPtr<Core::Notifier> m_write_notifier; int m_fd { -1 }; bool m_should_buffer_all_input { false }; @@ -88,7 +88,7 @@ private: RefPtr<Core::Notifier> read_notifier; bool success; u32 total_size { 0 }; - bool download_done { false }; + bool request_done { false }; }; OwnPtr<InternalBufferedData> 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 <kling@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <AK/FileStream.h> +#include <LibProtocol/Request.h> +#include <LibProtocol/RequestClient.h> + +namespace Protocol { + +RequestClient::RequestClient() + : IPC::ServerConnection<RequestClientEndpoint, RequestServerEndpoint>(*this, "/tmp/portal/request") +{ + handshake(); +} + +void RequestClient::handshake() +{ + send_sync<Messages::RequestServer::Greet>(); +} + +bool RequestClient::is_supported_protocol(const String& protocol) +{ + return send_sync<Messages::RequestServer::IsSupportedProtocol>(protocol)->supported(); +} + +template<typename RequestHashMapTraits> +RefPtr<Request> RequestClient::start_request(const String& method, const String& url, const HashMap<String, String, RequestHashMapTraits>& 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<Messages::RequestServer::StartRequest>(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& request) +{ + if (!m_requests.contains(request.id())) + return false; + return send_sync<Messages::RequestServer::StopRequest>(request.id())->success(); +} + +bool RequestClient::set_certificate(Badge<Request>, Request& request, String certificate, String key) +{ + if (!m_requests.contains(request.id())) + return false; + return send_sync<Messages::RequestServer::SetCertificate>(request.id(), move(certificate), move(key))->success(); +} + +void RequestClient::handle(const Messages::RequestClient::RequestFinished& message) +{ + RefPtr<Request> 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<Request*>(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<Request*>(m_requests.get(message.request_id()).value_or(nullptr))) { + HashMap<String, String, CaseInsensitiveStringTraits> headers; + message.response_headers().for_each_entry([&](auto& name, auto& value) { headers.set(name, value); }); + request->did_receive_headers({}, headers, message.status_code()); + } +} + +OwnPtr<Messages::RequestClient::CertificateRequestedResponse> RequestClient::handle(const Messages::RequestClient::CertificateRequested& message) +{ + if (auto request = const_cast<Request*>(m_requests.get(message.request_id()).value_or(nullptr))) { + request->did_request_certificates({}); + } + + return make<Messages::RequestClient::CertificateRequestedResponse>(); +} + +} + +template RefPtr<Protocol::Request> Protocol::RequestClient::start_request(const String& method, const String& url, const HashMap<String, String>& request_headers, ReadonlyBytes request_body); +template RefPtr<Protocol::Request> Protocol::RequestClient::start_request(const String& method, const String& url, const HashMap<String, String, CaseInsensitiveStringTraits>& 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 <kling@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/HashMap.h> +#include <LibIPC/ServerConnection.h> +#include <RequestServer/RequestClientEndpoint.h> +#include <RequestServer/RequestServerEndpoint.h> + +namespace Protocol { + +class Request; + +class RequestClient + : public IPC::ServerConnection<RequestClientEndpoint, RequestServerEndpoint> + , public RequestClientEndpoint { + C_OBJECT(RequestClient); + +public: + virtual void handshake() override; + + bool is_supported_protocol(const String&); + template<typename RequestHashMapTraits = Traits<String>> + RefPtr<Request> start_request(const String& method, const String& url, const HashMap<String, String, RequestHashMapTraits>& request_headers = {}, ReadonlyBytes request_body = {}); + + bool stop_request(Badge<Request>, Request&); + bool set_certificate(Badge<Request>, Request&, String, String); + +private: + RequestClient(); + + virtual void handle(const Messages::RequestClient::RequestProgress&) override; + virtual void handle(const Messages::RequestClient::RequestFinished&) override; + virtual OwnPtr<Messages::RequestClient::CertificateRequestedResponse> handle(const Messages::RequestClient::CertificateRequested&) override; + virtual void handle(const Messages::RequestClient::HeadersBecameAvailable&) override; + + HashMap<i32, RefPtr<Request>> 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 <AK/JsonObject.h> #include <LibCore/EventLoop.h> #include <LibCore/File.h> -#include <LibProtocol/Client.h> -#include <LibProtocol/Download.h> +#include <LibProtocol/Request.h> +#include <LibProtocol/RequestClient.h> #include <LibWeb/Loader/ContentFilter.h> #include <LibWeb/Loader/LoadRequest.h> #include <LibWeb/Loader/Resource.h> @@ -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, Function<void(ReadonlyByte headers.set(it.key, it.value); } - auto download = protocol_client().start_download(request.method(), url.to_string_encoded(), headers, request.body()); - if (!download) { + auto protocol_request = protocol_client().start_request(request.method(), url.to_string_encoded(), headers, request.body()); + if (!protocol_request) { if (error_callback) error_callback("Failed to initiate load", {}); return; } - download->on_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<void(ReadonlyByte error_callback("HTTP load failed", {}); return; } - deferred_invoke([download](auto&) { - // Clear circular reference of `download` captured by copy - const_cast<Protocol::Download&>(*download).on_buffered_download_finish = nullptr; + deferred_invoke([protocol_request](auto&) { + // Clear circular reference of `protocol_request` captured by copy + const_cast<Protocol::Request&>(*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 <LibWeb/Loader/Resource.h> 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<Protocol::Client> m_protocol_client; + RefPtr<Protocol::RequestClient> 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 <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include <AK/Badge.h> -#include <ProtocolServer/ClientConnection.h> -#include <ProtocolServer/Download.h> -#include <ProtocolServer/Protocol.h> -#include <ProtocolServer/ProtocolClientEndpoint.h> - -namespace ProtocolServer { - -static HashMap<int, RefPtr<ClientConnection>> s_connections; - -ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> socket, int client_id) - : IPC::ClientConnection<ProtocolClientEndpoint, ProtocolServerEndpoint>(*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<Messages::ProtocolServer::IsSupportedProtocolResponse> ClientConnection::handle(const Messages::ProtocolServer::IsSupportedProtocol& message) -{ - bool supported = Protocol::find_by_name(message.protocol().to_lowercase()); - return make<Messages::ProtocolServer::IsSupportedProtocolResponse>(supported); -} - -OwnPtr<Messages::ProtocolServer::StartDownloadResponse> ClientConnection::handle(const Messages::ProtocolServer::StartDownload& message) -{ - const auto& url = message.url(); - if (!url.is_valid()) { - dbgln("StartDownload: Invalid URL requested: '{}'", url); - return make<Messages::ProtocolServer::StartDownloadResponse>(-1, Optional<IPC::File> {}); - } - auto* protocol = Protocol::find_by_name(url.protocol()); - if (!protocol) { - dbgln("StartDownload: No protocol handler for URL: '{}'", url); - return make<Messages::ProtocolServer::StartDownloadResponse>(-1, Optional<IPC::File> {}); - } - 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<Messages::ProtocolServer::StartDownloadResponse>(-1, Optional<IPC::File> {}); - } - auto id = download->id(); - auto fd = download->download_fd(); - m_downloads.set(id, move(download)); - return make<Messages::ProtocolServer::StartDownloadResponse>(id, IPC::File(fd, IPC::File::CloseAfterSending)); -} - -OwnPtr<Messages::ProtocolServer::StopDownloadResponse> ClientConnection::handle(const Messages::ProtocolServer::StopDownload& message) -{ - auto* download = const_cast<Download*>(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<Messages::ProtocolServer::StopDownloadResponse>(success); -} - -void ClientConnection::did_receive_headers(Badge<Download>, 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& 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& download) -{ - post_message(Messages::ProtocolClient::DownloadProgress(download.id(), download.total_size(), download.downloaded_size())); -} - -void ClientConnection::did_request_certificates(Badge<Download>, Download& download) -{ - post_message(Messages::ProtocolClient::CertificateRequested(download.id())); -} - -OwnPtr<Messages::ProtocolServer::GreetResponse> ClientConnection::handle(const Messages::ProtocolServer::Greet&) -{ - return make<Messages::ProtocolServer::GreetResponse>(); -} - -OwnPtr<Messages::ProtocolServer::SetCertificateResponse> ClientConnection::handle(const Messages::ProtocolServer::SetCertificate& message) -{ - auto* download = const_cast<Download*>(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<Messages::ProtocolServer::SetCertificateResponse>(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 <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include <AK/HashMap.h> -#include <LibIPC/ClientConnection.h> -#include <ProtocolServer/Forward.h> -#include <ProtocolServer/ProtocolClientEndpoint.h> -#include <ProtocolServer/ProtocolServerEndpoint.h> - -namespace ProtocolServer { - -class ClientConnection final - : public IPC::ClientConnection<ProtocolClientEndpoint, ProtocolServerEndpoint> - , public ProtocolServerEndpoint { - C_OBJECT(ClientConnection); - -public: - explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>, int client_id); - ~ClientConnection() override; - - virtual void die() override; - - void did_receive_headers(Badge<Download>, Download&); - void did_finish_download(Badge<Download>, Download&, bool success); - void did_progress_download(Badge<Download>, Download&); - void did_request_certificates(Badge<Download>, Download&); - -private: - virtual OwnPtr<Messages::ProtocolServer::GreetResponse> handle(const Messages::ProtocolServer::Greet&) override; - virtual OwnPtr<Messages::ProtocolServer::IsSupportedProtocolResponse> handle(const Messages::ProtocolServer::IsSupportedProtocol&) override; - virtual OwnPtr<Messages::ProtocolServer::StartDownloadResponse> handle(const Messages::ProtocolServer::StartDownload&) override; - virtual OwnPtr<Messages::ProtocolServer::StopDownloadResponse> handle(const Messages::ProtocolServer::StopDownload&) override; - virtual OwnPtr<Messages::ProtocolServer::SetCertificateResponse> handle(const Messages::ProtocolServer::SetCertificate&) override; - - HashMap<i32, OwnPtr<Download>> 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 <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include <AK/Badge.h> -#include <ProtocolServer/ClientConnection.h> -#include <ProtocolServer/Download.h> - -namespace ProtocolServer { - -// FIXME: What about rollover? -static i32 s_next_id = 1; - -Download::Download(ClientConnection& client, NonnullOwnPtr<OutputFileStream>&& 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<String, String, CaseInsensitiveStringTraits>& 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<u32> 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 <AK/Badge.h> -#include <LibCore/Forward.h> -#include <LibGemini/Forward.h> -#include <ProtocolServer/Download.h> - -namespace ProtocolServer { - -class GeminiDownload final : public Download { -public: - virtual ~GeminiDownload() override; - static NonnullOwnPtr<GeminiDownload> create_with_job(Badge<GeminiProtocol>, ClientConnection&, NonnullRefPtr<Gemini::GeminiJob>, NonnullOwnPtr<OutputFileStream>&&); - -private: - explicit GeminiDownload(ClientConnection&, NonnullRefPtr<Gemini::GeminiJob>, NonnullOwnPtr<OutputFileStream>&&); - - virtual void set_certificate(String certificate, String key) override; - - NonnullRefPtr<Gemini::GeminiJob> 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 <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include <LibHTTP/HttpJob.h> -#include <ProtocolServer/HttpCommon.h> -#include <ProtocolServer/HttpDownload.h> -#include <ProtocolServer/HttpProtocol.h> - -namespace ProtocolServer { - -HttpDownload::HttpDownload(ClientConnection& client, NonnullRefPtr<HTTP::HttpJob> job, NonnullOwnPtr<OutputFileStream>&& 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> HttpDownload::create_with_job(Badge<HttpProtocol>&&, ClientConnection& client, NonnullRefPtr<HTTP::HttpJob> job, NonnullOwnPtr<OutputFileStream>&& 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 <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include <AK/Badge.h> -#include <AK/NonnullOwnPtr.h> -#include <LibCore/Forward.h> -#include <LibHTTP/Forward.h> -#include <ProtocolServer/Download.h> - -namespace ProtocolServer { - -class HttpDownload final : public Download { -public: - virtual ~HttpDownload() override; - static NonnullOwnPtr<HttpDownload> create_with_job(Badge<HttpProtocol>&&, ClientConnection&, NonnullRefPtr<HTTP::HttpJob>, NonnullOwnPtr<OutputFileStream>&&); - - HTTP::HttpJob& job() { return m_job; } - -private: - explicit HttpDownload(ClientConnection&, NonnullRefPtr<HTTP::HttpJob>, NonnullOwnPtr<OutputFileStream>&&); - - NonnullRefPtr<HTTP::HttpJob> 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 <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include <AK/Badge.h> -#include <AK/ByteBuffer.h> -#include <AK/HashMap.h> -#include <AK/OwnPtr.h> -#include <AK/String.h> -#include <AK/URL.h> -#include <LibHTTP/HttpJob.h> -#include <ProtocolServer/ClientConnection.h> -#include <ProtocolServer/Download.h> -#include <ProtocolServer/HttpCommon.h> -#include <ProtocolServer/HttpDownload.h> -#include <ProtocolServer/HttpProtocol.h> - -namespace ProtocolServer { - -HttpProtocol::HttpProtocol() - : Protocol("http") -{ -} - -OwnPtr<Download> HttpProtocol::start_download(ClientConnection& client, const String& method, const URL& url, const HashMap<String, String>& headers, ReadonlyBytes body) -{ - return Detail::start_download(Badge<HttpProtocol> {}, 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 <LibHTTP/HttpsJob.h> -#include <ProtocolServer/HttpCommon.h> -#include <ProtocolServer/HttpsDownload.h> -#include <ProtocolServer/HttpsProtocol.h> - -namespace ProtocolServer { - -HttpsDownload::HttpsDownload(ClientConnection& client, NonnullRefPtr<HTTP::HttpsJob> job, NonnullOwnPtr<OutputFileStream>&& 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> HttpsDownload::create_with_job(Badge<HttpsProtocol>&&, ClientConnection& client, NonnullRefPtr<HTTP::HttpsJob> job, NonnullOwnPtr<OutputFileStream>&& 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 <AK/Badge.h> -#include <LibCore/Forward.h> -#include <LibHTTP/HttpsJob.h> -#include <ProtocolServer/Download.h> - -namespace ProtocolServer { - -class HttpsDownload final : public Download { -public: - virtual ~HttpsDownload() override; - static NonnullOwnPtr<HttpsDownload> create_with_job(Badge<HttpsProtocol>&&, ClientConnection&, NonnullRefPtr<HTTP::HttpsJob>, NonnullOwnPtr<OutputFileStream>&&); - - HTTP::HttpsJob& job() { return m_job; } - -private: - explicit HttpsDownload(ClientConnection&, NonnullRefPtr<HTTP::HttpsJob>, NonnullOwnPtr<OutputFileStream>&&); - - virtual void set_certificate(String certificate, String key) override; - - NonnullRefPtr<HTTP::HttpsJob> 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 <AK/Badge.h> -#include <AK/ByteBuffer.h> -#include <AK/HashMap.h> -#include <AK/OwnPtr.h> -#include <AK/String.h> -#include <AK/URL.h> -#include <LibHTTP/HttpsJob.h> -#include <ProtocolServer/ClientConnection.h> -#include <ProtocolServer/Download.h> -#include <ProtocolServer/HttpCommon.h> -#include <ProtocolServer/HttpsDownload.h> -#include <ProtocolServer/HttpsProtocol.h> - -namespace ProtocolServer { - -HttpsProtocol::HttpsProtocol() - : Protocol("https") -{ -} - -OwnPtr<Download> HttpsProtocol::start_download(ClientConnection& client, const String& method, const URL& url, const HashMap<String, String>& headers, ReadonlyBytes body) -{ - return Detail::start_download(Badge<HttpsProtocol> {}, 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<u32> total_size, u32 downloaded_size) =| - DownloadFinished(i32 download_id, bool success, u32 total_size) =| - HeadersBecameAvailable(i32 download_id, IPC::Dictionary response_headers, Optional<u32> 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<IPC::File> 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 <kling@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <AK/Badge.h> +#include <RequestServer/ClientConnection.h> +#include <RequestServer/Protocol.h> +#include <RequestServer/Request.h> +#include <RequestServer/RequestClientEndpoint.h> + +namespace RequestServer { + +static HashMap<int, RefPtr<ClientConnection>> s_connections; + +ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> socket, int client_id) + : IPC::ClientConnection<RequestClientEndpoint, RequestServerEndpoint>(*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<Messages::RequestServer::IsSupportedProtocolResponse> ClientConnection::handle(const Messages::RequestServer::IsSupportedProtocol& message) +{ + bool supported = Protocol::find_by_name(message.protocol().to_lowercase()); + return make<Messages::RequestServer::IsSupportedProtocolResponse>(supported); +} + +OwnPtr<Messages::RequestServer::StartRequestResponse> ClientConnection::handle(const Messages::RequestServer::StartRequest& message) +{ + const auto& url = message.url(); + if (!url.is_valid()) { + dbgln("StartRequest: Invalid URL requested: '{}'", url); + return make<Messages::RequestServer::StartRequestResponse>(-1, Optional<IPC::File> {}); + } + auto* protocol = Protocol::find_by_name(url.protocol()); + if (!protocol) { + dbgln("StartRequest: No protocol handler for URL: '{}'", url); + return make<Messages::RequestServer::StartRequestResponse>(-1, Optional<IPC::File> {}); + } + 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<Messages::RequestServer::StartRequestResponse>(-1, Optional<IPC::File> {}); + } + auto id = request->id(); + auto fd = request->request_fd(); + m_requests.set(id, move(request)); + return make<Messages::RequestServer::StartRequestResponse>(id, IPC::File(fd, IPC::File::CloseAfterSending)); +} + +OwnPtr<Messages::RequestServer::StopRequestResponse> ClientConnection::handle(const Messages::RequestServer::StopRequest& message) +{ + auto* request = const_cast<Request*>(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<Messages::RequestServer::StopRequestResponse>(success); +} + +void ClientConnection::did_receive_headers(Badge<Request>, 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& 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& request) +{ + post_message(Messages::RequestClient::RequestProgress(request.id(), request.total_size(), request.downloaded_size())); +} + +void ClientConnection::did_request_certificates(Badge<Request>, Request& request) +{ + post_message(Messages::RequestClient::CertificateRequested(request.id())); +} + +OwnPtr<Messages::RequestServer::GreetResponse> ClientConnection::handle(const Messages::RequestServer::Greet&) +{ + return make<Messages::RequestServer::GreetResponse>(); +} + +OwnPtr<Messages::RequestServer::SetCertificateResponse> ClientConnection::handle(const Messages::RequestServer::SetCertificate& message) +{ + auto* request = const_cast<Request*>(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<Messages::RequestServer::SetCertificateResponse>(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 <kling@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/HashMap.h> +#include <LibIPC/ClientConnection.h> +#include <RequestServer/Forward.h> +#include <RequestServer/RequestClientEndpoint.h> +#include <RequestServer/RequestServerEndpoint.h> + +namespace RequestServer { + +class ClientConnection final + : public IPC::ClientConnection<RequestClientEndpoint, RequestServerEndpoint> + , public RequestServerEndpoint { + C_OBJECT(ClientConnection); + +public: + explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>, int client_id); + ~ClientConnection() override; + + virtual void die() override; + + void did_receive_headers(Badge<Request>, Request&); + void did_finish_request(Badge<Request>, Request&, bool success); + void did_progress_request(Badge<Request>, Request&); + void did_request_certificates(Badge<Request>, Request&); + +private: + virtual OwnPtr<Messages::RequestServer::GreetResponse> handle(const Messages::RequestServer::Greet&) override; + virtual OwnPtr<Messages::RequestServer::IsSupportedProtocolResponse> handle(const Messages::RequestServer::IsSupportedProtocol&) override; + virtual OwnPtr<Messages::RequestServer::StartRequestResponse> handle(const Messages::RequestServer::StartRequest&) override; + virtual OwnPtr<Messages::RequestServer::StopRequestResponse> handle(const Messages::RequestServer::StopRequest&) override; + virtual OwnPtr<Messages::RequestServer::SetCertificateResponse> handle(const Messages::RequestServer::SetCertificate&) override; + + HashMap<i32, OwnPtr<Request>> m_requests; +}; + +} diff --git a/Userland/Services/ProtocolServer/Forward.h b/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 index cdddba36e7..243dddce5d 100644 --- a/Userland/Services/ProtocolServer/GeminiProtocol.cpp +++ b/Userland/Services/RequestServer/GeminiProtocol.cpp @@ -6,11 +6,11 @@ #include <LibGemini/GeminiJob.h> #include <LibGemini/GeminiRequest.h> -#include <ProtocolServer/GeminiDownload.h> -#include <ProtocolServer/GeminiProtocol.h> +#include <RequestServer/GeminiProtocol.h> +#include <RequestServer/GeminiRequest.h> #include <fcntl.h> -namespace ProtocolServer { +namespace RequestServer { GeminiProtocol::GeminiProtocol() : Protocol("gemini") @@ -21,22 +21,22 @@ GeminiProtocol::~GeminiProtocol() { } -OwnPtr<Download> GeminiProtocol::start_download(ClientConnection& client, const String&, const URL& url, const HashMap<String, String>&, ReadonlyBytes) +OwnPtr<Request> GeminiProtocol::start_request(ClientConnection& client, const String&, const URL& url, const HashMap<String, String>&, 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<OutputFileStream>(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 index 33e4e8a554..4b530d71d0 100644 --- a/Userland/Services/ProtocolServer/GeminiProtocol.h +++ b/Userland/Services/RequestServer/GeminiProtocol.h @@ -6,16 +6,16 @@ #pragma once -#include <ProtocolServer/Protocol.h> +#include <RequestServer/Protocol.h> -namespace ProtocolServer { +namespace RequestServer { class GeminiProtocol final : public Protocol { public: GeminiProtocol(); virtual ~GeminiProtocol() override; - virtual OwnPtr<Download> start_download(ClientConnection&, const String& method, const URL&, const HashMap<String, String>&, ReadonlyBytes body) override; + virtual OwnPtr<Request> start_request(ClientConnection&, const String& method, const URL&, const HashMap<String, String>&, ReadonlyBytes body) override; }; } diff --git a/Userland/Services/ProtocolServer/GeminiDownload.cpp b/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 <LibGemini/GeminiJob.h> #include <LibGemini/GeminiResponse.h> -#include <ProtocolServer/GeminiDownload.h> +#include <RequestServer/GeminiRequest.h> -namespace ProtocolServer { +namespace RequestServer { -GeminiDownload::GeminiDownload(ClientConnection& client, NonnullRefPtr<Gemini::GeminiJob> job, NonnullOwnPtr<OutputFileStream>&& output_stream) - : Download(client, move(output_stream)) +GeminiRequest::GeminiRequest(ClientConnection& client, NonnullRefPtr<Gemini::GeminiJob> job, NonnullOwnPtr<OutputFileStream>&& 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, NonnullRefPtr<Gemini::G } } - // signal 100% download progress so any listeners can react + // signal 100% request progress so any listeners can react // appropriately did_progress(downloaded_size(), downloaded_size()); @@ -44,21 +44,21 @@ GeminiDownload::GeminiDownload(ClientConnection& client, NonnullRefPtr<Gemini::G }; } -void GeminiDownload::set_certificate(String certificate, String key) +void GeminiRequest::set_certificate(String certificate, String key) { m_job->set_certificate(move(certificate), move(key)); } -GeminiDownload::~GeminiDownload() +GeminiRequest::~GeminiRequest() { m_job->on_finish = nullptr; m_job->on_progress = nullptr; m_job->shutdown(); } -NonnullOwnPtr<GeminiDownload> GeminiDownload::create_with_job(Badge<GeminiProtocol>, ClientConnection& client, NonnullRefPtr<Gemini::GeminiJob> job, NonnullOwnPtr<OutputFileStream>&& output_stream) +NonnullOwnPtr<GeminiRequest> GeminiRequest::create_with_job(Badge<GeminiProtocol>, ClientConnection& client, NonnullRefPtr<Gemini::GeminiJob> job, NonnullOwnPtr<OutputFileStream>&& 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 <AK/Badge.h> +#include <LibCore/Forward.h> +#include <LibGemini/Forward.h> +#include <RequestServer/Request.h> + +namespace RequestServer { + +class GeminiRequest final : public Request { +public: + virtual ~GeminiRequest() override; + static NonnullOwnPtr<GeminiRequest> create_with_job(Badge<GeminiProtocol>, ClientConnection&, NonnullRefPtr<Gemini::GeminiJob>, NonnullOwnPtr<OutputFileStream>&&); + +private: + explicit GeminiRequest(ClientConnection&, NonnullRefPtr<Gemini::GeminiJob>, NonnullOwnPtr<OutputFileStream>&&); + + virtual void set_certificate(String certificate, String key) override; + + NonnullRefPtr<Gemini::GeminiJob> m_job; +}; + +} diff --git a/Userland/Services/ProtocolServer/HttpCommon.h b/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 <AK/String.h> #include <AK/Types.h> #include <LibHTTP/HttpRequest.h> -#include <ProtocolServer/ClientConnection.h> -#include <ProtocolServer/Download.h> +#include <RequestServer/ClientConnection.h> +#include <RequestServer/Request.h> -namespace ProtocolServer::Detail { +namespace RequestServer::Detail { template<typename TSelf, typename TJob> 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<typename TBadgedProtocol, typename TPipeResult> -OwnPtr<Download> start_download(TBadgedProtocol&& protocol, ClientConnection& client, const String& method, const URL& url, const HashMap<String, String>& headers, ReadonlyBytes body, TPipeResult&& pipe_result) +OwnPtr<Request> start_request(TBadgedProtocol&& protocol, ClientConnection& client, const String& method, const URL& url, const HashMap<String, String>& 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<Download> start_download(TBadgedProtocol&& protocol, ClientConnection& cl auto output_stream = make<OutputFileStream>(pipe_result.value().write_fd); output_stream->make_unbuffered(); auto job = TJob::construct(request, *output_stream); - auto download = TDownload::create_with_job(forward<TBadgedProtocol>(protocol), client, (TJob&)*job, move(output_stream)); - download->set_download_fd(pipe_result.value().read_fd); + auto protocol_request = TRequest::create_with_job(forward<TBadgedProtocol>(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 <kling@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <AK/Badge.h> +#include <AK/ByteBuffer.h> +#include <AK/HashMap.h> +#include <AK/OwnPtr.h> +#include <AK/String.h> +#include <AK/URL.h> +#include <LibHTTP/HttpJob.h> +#include <RequestServer/ClientConnection.h> +#include <RequestServer/HttpCommon.h> +#include <RequestServer/HttpProtocol.h> +#include <RequestServer/HttpRequest.h> +#include <RequestServer/Request.h> + +namespace RequestServer { + +HttpProtocol::HttpProtocol() + : Protocol("http") +{ +} + +OwnPtr<Request> HttpProtocol::start_request(ClientConnection& client, const String& method, const URL& url, const HashMap<String, String>& headers, ReadonlyBytes body) +{ + return Detail::start_request(Badge<HttpProtocol> {}, client, method, url, headers, body, get_pipe_for_request()); +} + +} diff --git a/Userland/Services/ProtocolServer/HttpProtocol.h b/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 <AK/String.h> #include <AK/URL.h> #include <LibHTTP/HttpJob.h> -#include <ProtocolServer/ClientConnection.h> -#include <ProtocolServer/Download.h> -#include <ProtocolServer/HttpDownload.h> -#include <ProtocolServer/Protocol.h> +#include <RequestServer/ClientConnection.h> +#include <RequestServer/HttpRequest.h> +#include <RequestServer/Protocol.h> +#include <RequestServer/Request.h> -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<Download> start_download(ClientConnection&, const String& method, const URL&, const HashMap<String, String>& headers, ReadonlyBytes body) override; + virtual OwnPtr<Request> start_request(ClientConnection&, const String& method, const URL&, const HashMap<String, String>& 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 <kling@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <LibHTTP/HttpJob.h> +#include <RequestServer/HttpCommon.h> +#include <RequestServer/HttpProtocol.h> +#include <RequestServer/HttpRequest.h> + +namespace RequestServer { + +HttpRequest::HttpRequest(ClientConnection& client, NonnullRefPtr<HTTP::HttpJob> job, NonnullOwnPtr<OutputFileStream>&& 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> HttpRequest::create_with_job(Badge<HttpProtocol>&&, ClientConnection& client, NonnullRefPtr<HTTP::HttpJob> job, NonnullOwnPtr<OutputFileStream>&& 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 <kling@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/Badge.h> +#include <AK/NonnullOwnPtr.h> +#include <LibCore/Forward.h> +#include <LibHTTP/Forward.h> +#include <RequestServer/Request.h> + +namespace RequestServer { + +class HttpRequest final : public Request { +public: + virtual ~HttpRequest() override; + static NonnullOwnPtr<HttpRequest> create_with_job(Badge<HttpProtocol>&&, ClientConnection&, NonnullRefPtr<HTTP::HttpJob>, NonnullOwnPtr<OutputFileStream>&&); + + HTTP::HttpJob& job() { return m_job; } + +private: + explicit HttpRequest(ClientConnection&, NonnullRefPtr<HTTP::HttpJob>, NonnullOwnPtr<OutputFileStream>&&); + + NonnullRefPtr<HTTP::HttpJob> 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 <AK/Badge.h> +#include <AK/ByteBuffer.h> +#include <AK/HashMap.h> +#include <AK/OwnPtr.h> +#include <AK/String.h> +#include <AK/URL.h> +#include <LibHTTP/HttpsJob.h> +#include <RequestServer/ClientConnection.h> +#include <RequestServer/HttpCommon.h> +#include <RequestServer/HttpsProtocol.h> +#include <RequestServer/HttpsRequest.h> +#include <RequestServer/Request.h> + +namespace RequestServer { + +HttpsProtocol::HttpsProtocol() + : Protocol("https") +{ +} + +OwnPtr<Request> HttpsProtocol::start_request(ClientConnection& client, const String& method, const URL& url, const HashMap<String, String>& headers, ReadonlyBytes body) +{ + return Detail::start_request(Badge<HttpsProtocol> {}, client, method, url, headers, body, get_pipe_for_request()); +} + +} diff --git a/Userland/Services/ProtocolServer/HttpsProtocol.h b/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 <AK/String.h> #include <AK/URL.h> #include <LibHTTP/HttpsJob.h> -#include <ProtocolServer/ClientConnection.h> -#include <ProtocolServer/Download.h> -#include <ProtocolServer/HttpsDownload.h> -#include <ProtocolServer/Protocol.h> +#include <RequestServer/ClientConnection.h> +#include <RequestServer/HttpsRequest.h> +#include <RequestServer/Protocol.h> +#include <RequestServer/Request.h> -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<Download> start_download(ClientConnection&, const String& method, const URL&, const HashMap<String, String>& headers, ReadonlyBytes body) override; + virtual OwnPtr<Request> start_request(ClientConnection&, const String& method, const URL&, const HashMap<String, String>& 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 <LibHTTP/HttpsJob.h> +#include <RequestServer/HttpCommon.h> +#include <RequestServer/HttpsProtocol.h> +#include <RequestServer/HttpsRequest.h> + +namespace RequestServer { + +HttpsRequest::HttpsRequest(ClientConnection& client, NonnullRefPtr<HTTP::HttpsJob> job, NonnullOwnPtr<OutputFileStream>&& 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> HttpsRequest::create_with_job(Badge<HttpsProtocol>&&, ClientConnection& client, NonnullRefPtr<HTTP::HttpsJob> job, NonnullOwnPtr<OutputFileStream>&& 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 <AK/Badge.h> +#include <LibCore/Forward.h> +#include <LibHTTP/HttpsJob.h> +#include <RequestServer/Request.h> + +namespace RequestServer { + +class HttpsRequest final : public Request { +public: + virtual ~HttpsRequest() override; + static NonnullOwnPtr<HttpsRequest> create_with_job(Badge<HttpsProtocol>&&, ClientConnection&, NonnullRefPtr<HTTP::HttpsJob>, NonnullOwnPtr<OutputFileStream>&&); + + HTTP::HttpsJob& job() { return m_job; } + +private: + explicit HttpsRequest(ClientConnection&, NonnullRefPtr<HTTP::HttpsJob>, NonnullOwnPtr<OutputFileStream>&&); + + virtual void set_certificate(String certificate, String key) override; + + NonnullRefPtr<HTTP::HttpsJob> m_job; +}; + +} diff --git a/Userland/Services/ProtocolServer/Protocol.cpp b/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 <AK/HashMap.h> -#include <ProtocolServer/Protocol.h> +#include <RequestServer/Protocol.h> #include <errno.h> #include <fcntl.h> #include <string.h> #include <unistd.h> -namespace ProtocolServer { +namespace RequestServer { static HashMap<String, Protocol*>& all_protocols() { @@ -34,7 +34,7 @@ Protocol::~Protocol() VERIFY_NOT_REACHED(); } -Result<Protocol::Pipe, String> Protocol::get_pipe_for_download() +Result<Protocol::Pipe, String> 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 index fcfc44e267..b153ba8765 100644 --- a/Userland/Services/ProtocolServer/Protocol.h +++ b/Userland/Services/RequestServer/Protocol.h @@ -9,16 +9,16 @@ #include <AK/RefPtr.h> #include <AK/Result.h> #include <AK/URL.h> -#include <ProtocolServer/Forward.h> +#include <RequestServer/Forward.h> -namespace ProtocolServer { +namespace RequestServer { class Protocol { public: virtual ~Protocol(); const String& name() const { return m_name; } - virtual OwnPtr<Download> start_download(ClientConnection&, const String& method, const URL&, const HashMap<String, String>& headers, ReadonlyBytes body) = 0; + virtual OwnPtr<Request> start_request(ClientConnection&, const String& method, const URL&, const HashMap<String, String>& 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<Pipe, String> get_pipe_for_download(); + static Result<Pipe, String> 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 <kling@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <AK/Badge.h> +#include <RequestServer/ClientConnection.h> +#include <RequestServer/Request.h> + +namespace RequestServer { + +// FIXME: What about rollover? +static i32 s_next_id = 1; + +Request::Request(ClientConnection& client, NonnullOwnPtr<OutputFileStream>&& 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<String, String, CaseInsensitiveStringTraits>& 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<u32> 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 index c60a56776d..324f027c93 100644 --- a/Userland/Services/ProtocolServer/Download.h +++ b/Userland/Services/RequestServer/Request.h @@ -12,13 +12,13 @@ #include <AK/Optional.h> #include <AK/RefCounted.h> #include <AK/URL.h> -#include <ProtocolServer/Forward.h> +#include <RequestServer/Forward.h> -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<Protocol>, 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<u32> total_size, u32 downloaded_size); @@ -44,12 +44,12 @@ public: const OutputFileStream& output_stream() const { return *m_output_stream; } protected: - explicit Download(ClientConnection&, NonnullOwnPtr<OutputFileStream>&&); + explicit Request(ClientConnection&, NonnullOwnPtr<OutputFileStream>&&); 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<u32> m_status_code; Optional<u32> 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<u32> total_size, u32 downloaded_size) =| + RequestFinished(i32 request_id, bool success, u32 total_size) =| + HeadersBecameAvailable(i32 request_id, IPC::Dictionary response_headers, Optional<u32> 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<IPC::File> 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 index 36622372be..0038c891f4 100644 --- a/Userland/Services/ProtocolServer/main.cpp +++ b/Userland/Services/RequestServer/main.cpp @@ -8,10 +8,10 @@ #include <LibCore/LocalServer.h> #include <LibIPC/ClientConnection.h> #include <LibTLS/Certificate.h> -#include <ProtocolServer/ClientConnection.h> -#include <ProtocolServer/GeminiProtocol.h> -#include <ProtocolServer/HttpProtocol.h> -#include <ProtocolServer/HttpsProtocol.h> +#include <RequestServer/ClientConnection.h> +#include <RequestServer/GeminiProtocol.h> +#include <RequestServer/HttpProtocol.h> +#include <RequestServer/HttpsProtocol.h> 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<ProtocolServer::ClientConnection>(socket.release_nonnull(), 1); + IPC::new_client_connection<RequestServer::ClientConnection>(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 <LibCore/ArgsParser.h> #include <LibCore/EventLoop.h> #include <LibCore/File.h> -#include <LibProtocol/Client.h> -#include <LibProtocol/Download.h> +#include <LibProtocol/Request.h> +#include <LibProtocol/RequestClient.h> #include <ctype.h> #include <stdio.h> @@ -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<u32> maybe_total_size, u32 downloaded_size) { + request->on_progress = [&](Optional<u32> 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. |