mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-03 21:10:30 +00:00
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.
This commit is contained in:
parent
22413ef729
commit
71d27abb97
Notes:
sideshowbarker
2024-07-18 19:05:41 +09:00
Author: https://github.com/Dexesttp Commit: https://github.com/SerenityOS/serenity/commit/71d27abb97a Pull-request: https://github.com/SerenityOS/serenity/pull/6610 Reviewed-by: https://github.com/awesomekling Reviewed-by: https://github.com/linusg
58 changed files with 786 additions and 788 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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);
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
98
Userland/Libraries/LibProtocol/RequestClient.cpp
Normal file
98
Userland/Libraries/LibProtocol/RequestClient.cpp
Normal file
|
@ -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);
|
44
Userland/Libraries/LibProtocol/RequestClient.h
Normal file
44
Userland/Libraries/LibProtocol/RequestClient.h
Normal file
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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)));
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
|
@ -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)));
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
|
@ -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) => ()
|
||||
}
|
|
@ -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)
|
||||
}
|
20
Userland/Services/RequestServer/CMakeLists.txt
Normal file
20
Userland/Services/RequestServer/CMakeLists.txt
Normal file
|
@ -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)
|
119
Userland/Services/RequestServer/ClientConnection.cpp
Normal file
119
Userland/Services/RequestServer/ClientConnection.cpp
Normal file
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
43
Userland/Services/RequestServer/ClientConnection.h
Normal file
43
Userland/Services/RequestServer/ClientConnection.h
Normal file
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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)));
|
||||
}
|
||||
|
||||
}
|
29
Userland/Services/RequestServer/GeminiRequest.h
Normal file
29
Userland/Services/RequestServer/GeminiRequest.h
Normal file
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
32
Userland/Services/RequestServer/HttpProtocol.cpp
Normal file
32
Userland/Services/RequestServer/HttpProtocol.cpp
Normal file
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
33
Userland/Services/RequestServer/HttpRequest.cpp
Normal file
33
Userland/Services/RequestServer/HttpRequest.cpp
Normal file
|
@ -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)));
|
||||
}
|
||||
|
||||
}
|
30
Userland/Services/RequestServer/HttpRequest.h
Normal file
30
Userland/Services/RequestServer/HttpRequest.h
Normal file
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
32
Userland/Services/RequestServer/HttpsProtocol.cpp
Normal file
32
Userland/Services/RequestServer/HttpsProtocol.cpp
Normal file
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
38
Userland/Services/RequestServer/HttpsRequest.cpp
Normal file
38
Userland/Services/RequestServer/HttpsRequest.cpp
Normal file
|
@ -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)));
|
||||
}
|
||||
|
||||
}
|
31
Userland/Services/RequestServer/HttpsRequest.h
Normal file
31
Userland/Services/RequestServer/HttpsRequest.h
Normal file
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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) {
|
|
@ -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;
|
59
Userland/Services/RequestServer/Request.cpp
Normal file
59
Userland/Services/RequestServer/Request.cpp
Normal file
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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 {};
|
9
Userland/Services/RequestServer/RequestClient.ipc
Normal file
9
Userland/Services/RequestServer/RequestClient.ipc
Normal file
|
@ -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) => ()
|
||||
}
|
12
Userland/Services/RequestServer/RequestServer.ipc
Normal file
12
Userland/Services/RequestServer/RequestServer.ipc
Normal file
|
@ -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)
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue