RequestServer+LibProtocol: Allow users to specify a per-request proxy

This commit is contained in:
Ali Mohammad Pur 2022-04-07 21:10:33 +04:30 committed by Andreas Kling
parent cd9d740107
commit 45867435c4
Notes: sideshowbarker 2024-07-17 14:15:00 +09:00
16 changed files with 52 additions and 24 deletions

View file

@ -8,7 +8,7 @@
#include "DownloadWidget.h"
#include <AK/NumberFormat.h>
#include <AK/StringBuilder.h>
#include <LibConfig/Client.h>
#include <LibCore/Proxy.h>
#include <LibCore/StandardPaths.h>
#include <LibCore/Stream.h>
#include <LibDesktop/Launcher.h>
@ -20,9 +20,11 @@
#include <LibGUI/MessageBox.h>
#include <LibGUI/Progressbar.h>
#include <LibGUI/Window.h>
#include <LibProtocol/RequestClient.h>
#include <LibWeb/Loader/ResourceLoader.h>
#include <LibConfig/Client.h>
#include <LibProtocol/RequestClient.h>
namespace Browser {
DownloadWidget::DownloadWidget(const URL& url)

View file

@ -8,6 +8,7 @@
#include <AK/URL.h>
#include <LibCore/AnonymousBuffer.h>
#include <LibCore/DateTime.h>
#include <LibCore/Proxy.h>
#include <LibIPC/Decoder.h>
#include <LibIPC/Dictionary.h>
#include <LibIPC/File.h>
@ -185,4 +186,14 @@ ErrorOr<void> decode(Decoder& decoder, Core::DateTime& datetime)
return {};
}
ErrorOr<void> decode(Decoder& decoder, Core::ProxyData& data)
{
UnderlyingType<decltype(data.type)> type;
TRY(decoder.decode(type));
data.type = static_cast<Core::ProxyData::Type>(type);
TRY(decoder.decode(data.host_ipv4));
TRY(decoder.decode(data.port));
return {};
}
}

View file

@ -11,6 +11,7 @@
#include <AK/URL.h>
#include <LibCore/AnonymousBuffer.h>
#include <LibCore/DateTime.h>
#include <LibCore/Proxy.h>
#include <LibIPC/Dictionary.h>
#include <LibIPC/Encoder.h>
#include <LibIPC/File.h>
@ -203,4 +204,12 @@ bool encode(Encoder& encoder, Core::DateTime const& datetime)
return true;
}
bool encode(Encoder& encoder, Core::ProxyData const& proxy)
{
encoder << to_underlying(proxy.type);
encoder << proxy.host_ipv4;
encoder << proxy.port;
return true;
}
}

View file

@ -21,7 +21,7 @@ void RequestClient::ensure_connection(URL const& url, ::RequestServer::CacheLeve
}
template<typename RequestHashMapTraits>
RefPtr<Request> RequestClient::start_request(String const& method, URL const& url, HashMap<String, String, RequestHashMapTraits> const& request_headers, ReadonlyBytes request_body)
RefPtr<Request> RequestClient::start_request(String const& method, URL const& url, HashMap<String, String, RequestHashMapTraits> const& request_headers, ReadonlyBytes request_body, Core::ProxyData const& proxy_data)
{
IPC::Dictionary header_dictionary;
for (auto& it : request_headers)
@ -31,7 +31,7 @@ RefPtr<Request> RequestClient::start_request(String const& method, URL const& ur
if (body_result.is_error())
return nullptr;
auto response = IPCProxy::start_request(method, url, header_dictionary, body_result.release_value());
auto response = IPCProxy::start_request(method, url, header_dictionary, body_result.release_value(), proxy_data);
auto request_id = response.request_id();
if (request_id < 0 || !response.response_fd().has_value())
return nullptr;
@ -91,5 +91,5 @@ void RequestClient::certificate_requested(i32 request_id)
}
template RefPtr<Protocol::Request> Protocol::RequestClient::start_request(String const& method, URL const&, HashMap<String, String> const& request_headers, ReadonlyBytes request_body);
template RefPtr<Protocol::Request> Protocol::RequestClient::start_request(String const& method, URL const&, HashMap<String, String, CaseInsensitiveStringTraits> const& request_headers, ReadonlyBytes request_body);
template RefPtr<Protocol::Request> Protocol::RequestClient::start_request(String const& method, URL const&, HashMap<String, String> const& request_headers, ReadonlyBytes request_body, Core::ProxyData const&);
template RefPtr<Protocol::Request> Protocol::RequestClient::start_request(String const& method, URL const&, HashMap<String, String, CaseInsensitiveStringTraits> const& request_headers, ReadonlyBytes request_body, Core::ProxyData const&);

View file

@ -7,6 +7,8 @@
#pragma once
#include <AK/HashMap.h>
// Need to include this before RequestClientEndpoint.h as that one includes LibIPC/(De En)coder.h, which would bomb if included before this.
#include <LibCore/Proxy.h>
#include <LibIPC/ConnectionToServer.h>
#include <RequestServer/RequestClientEndpoint.h>
#include <RequestServer/RequestServerEndpoint.h>
@ -22,7 +24,7 @@ class RequestClient final
public:
template<typename RequestHashMapTraits = Traits<String>>
RefPtr<Request> start_request(String const& method, URL const&, HashMap<String, String, RequestHashMapTraits> const& request_headers = {}, ReadonlyBytes request_body = {});
RefPtr<Request> start_request(String const& method, URL const&, HashMap<String, String, RequestHashMapTraits> const& request_headers = {}, ReadonlyBytes request_body = {}, Core::ProxyData const& = {});
void ensure_connection(URL const&, ::RequestServer::CacheLevel);

View file

@ -6,6 +6,7 @@
#include <AK/Badge.h>
#include <AK/NonnullOwnPtr.h>
#include <LibCore/Proxy.h>
#include <RequestServer/ConnectionFromClient.h>
#include <RequestServer/Protocol.h>
#include <RequestServer/Request.h>
@ -35,7 +36,7 @@ Messages::RequestServer::IsSupportedProtocolResponse ConnectionFromClient::is_su
return supported;
}
Messages::RequestServer::StartRequestResponse ConnectionFromClient::start_request(String const& method, URL const& url, IPC::Dictionary const& request_headers, ByteBuffer const& request_body)
Messages::RequestServer::StartRequestResponse ConnectionFromClient::start_request(String const& method, URL const& url, IPC::Dictionary const& request_headers, ByteBuffer const& request_body, Core::ProxyData const& proxy_data)
{
if (!url.is_valid()) {
dbgln("StartRequest: Invalid URL requested: '{}'", url);
@ -46,7 +47,7 @@ Messages::RequestServer::StartRequestResponse ConnectionFromClient::start_reques
dbgln("StartRequest: No protocol handler for URL: '{}'", url);
return { -1, Optional<IPC::File> {} };
}
auto request = protocol->start_request(*this, method, url, request_headers.entries(), request_body);
auto request = protocol->start_request(*this, method, url, request_headers.entries(), request_body, proxy_data);
if (!request) {
dbgln("StartRequest: Protocol handler failed to start request: '{}'", url);
return { -1, Optional<IPC::File> {} };

View file

@ -7,6 +7,8 @@
#pragma once
#include <AK/HashMap.h>
// Need to include this before RequestClientEndpoint.h as that one includes LibIPC/(De En)coder.h, which would bomb if included before this.
#include <LibCore/Proxy.h>
#include <LibIPC/ConnectionFromClient.h>
#include <RequestServer/Forward.h>
#include <RequestServer/RequestClientEndpoint.h>
@ -32,7 +34,7 @@ private:
explicit ConnectionFromClient(NonnullOwnPtr<Core::Stream::LocalSocket>);
virtual Messages::RequestServer::IsSupportedProtocolResponse is_supported_protocol(String const&) override;
virtual Messages::RequestServer::StartRequestResponse start_request(String const&, URL const&, IPC::Dictionary const&, ByteBuffer const&) override;
virtual Messages::RequestServer::StartRequestResponse start_request(String const&, URL const&, IPC::Dictionary const&, ByteBuffer const&, Core::ProxyData const&) override;
virtual Messages::RequestServer::StopRequestResponse stop_request(i32) override;
virtual Messages::RequestServer::SetCertificateResponse set_certificate(i32, String const&, String const&) override;
virtual void ensure_connection(URL const& url, ::RequestServer::CacheLevel const& cache_level) override;

View file

@ -17,7 +17,7 @@ GeminiProtocol::GeminiProtocol()
{
}
OwnPtr<Request> GeminiProtocol::start_request(ConnectionFromClient& client, String const&, const URL& url, HashMap<String, String> const&, ReadonlyBytes)
OwnPtr<Request> GeminiProtocol::start_request(ConnectionFromClient& client, String const&, const URL& url, HashMap<String, String> const&, ReadonlyBytes, Core::ProxyData proxy_data)
{
Gemini::GeminiRequest request;
request.set_url(url);
@ -31,7 +31,7 @@ OwnPtr<Request> GeminiProtocol::start_request(ConnectionFromClient& client, Stri
auto protocol_request = GeminiRequest::create_with_job({}, client, *job, move(output_stream));
protocol_request->set_request_fd(pipe_result.value().read_fd);
ConnectionCache::get_or_create_connection(ConnectionCache::g_tls_connection_cache, url, *job);
ConnectionCache::get_or_create_connection(ConnectionCache::g_tls_connection_cache, url, *job, proxy_data);
return protocol_request;
}

View file

@ -15,7 +15,7 @@ public:
GeminiProtocol();
virtual ~GeminiProtocol() override = default;
virtual OwnPtr<Request> start_request(ConnectionFromClient&, String const& method, const URL&, HashMap<String, String> const&, ReadonlyBytes body) override;
virtual OwnPtr<Request> start_request(ConnectionFromClient&, String const& method, const URL&, HashMap<String, String> const&, ReadonlyBytes body, Core::ProxyData proxy_data = {}) override;
};
}

View file

@ -61,7 +61,7 @@ void init(TSelf* self, TJob job)
}
template<typename TBadgedProtocol, typename TPipeResult>
OwnPtr<Request> start_request(TBadgedProtocol&& protocol, ConnectionFromClient& client, String const& method, const URL& url, HashMap<String, String> const& headers, ReadonlyBytes body, TPipeResult&& pipe_result)
OwnPtr<Request> start_request(TBadgedProtocol&& protocol, ConnectionFromClient& client, String const& method, const URL& url, HashMap<String, String> const& headers, ReadonlyBytes body, TPipeResult&& pipe_result, Core::ProxyData proxy_data = {})
{
using TJob = typename TBadgedProtocol::Type::JobType;
using TRequest = typename TBadgedProtocol::Type::RequestType;
@ -89,9 +89,9 @@ OwnPtr<Request> start_request(TBadgedProtocol&& protocol, ConnectionFromClient&
protocol_request->set_request_fd(pipe_result.value().read_fd);
if constexpr (IsSame<typename TBadgedProtocol::Type, HttpsProtocol>)
ConnectionCache::get_or_create_connection(ConnectionCache::g_tls_connection_cache, url, *job);
ConnectionCache::get_or_create_connection(ConnectionCache::g_tls_connection_cache, url, *job, proxy_data);
else
ConnectionCache::get_or_create_connection(ConnectionCache::g_tcp_connection_cache, url, *job);
ConnectionCache::get_or_create_connection(ConnectionCache::g_tcp_connection_cache, url, *job, proxy_data);
return protocol_request;
}

View file

@ -22,9 +22,9 @@ HttpProtocol::HttpProtocol()
{
}
OwnPtr<Request> HttpProtocol::start_request(ConnectionFromClient& client, String const& method, const URL& url, HashMap<String, String> const& headers, ReadonlyBytes body)
OwnPtr<Request> HttpProtocol::start_request(ConnectionFromClient& client, String const& method, const URL& url, HashMap<String, String> const& headers, ReadonlyBytes body, Core::ProxyData proxy_data)
{
return Detail::start_request(Badge<HttpProtocol> {}, client, method, url, headers, body, get_pipe_for_request());
return Detail::start_request(Badge<HttpProtocol> {}, client, method, url, headers, body, get_pipe_for_request(), proxy_data);
}
}

View file

@ -27,7 +27,7 @@ public:
HttpProtocol();
~HttpProtocol() override = default;
virtual OwnPtr<Request> start_request(ConnectionFromClient&, String const& method, const URL&, HashMap<String, String> const& headers, ReadonlyBytes body) override;
virtual OwnPtr<Request> start_request(ConnectionFromClient&, String const& method, const URL&, HashMap<String, String> const& headers, ReadonlyBytes body, Core::ProxyData proxy_data = {}) override;
};
}

View file

@ -22,9 +22,9 @@ HttpsProtocol::HttpsProtocol()
{
}
OwnPtr<Request> HttpsProtocol::start_request(ConnectionFromClient& client, String const& method, const URL& url, HashMap<String, String> const& headers, ReadonlyBytes body)
OwnPtr<Request> HttpsProtocol::start_request(ConnectionFromClient& client, String const& method, const URL& url, HashMap<String, String> const& headers, ReadonlyBytes body, Core::ProxyData proxy_data)
{
return Detail::start_request(Badge<HttpsProtocol> {}, client, method, url, headers, body, get_pipe_for_request());
return Detail::start_request(Badge<HttpsProtocol> {}, client, method, url, headers, body, get_pipe_for_request(), proxy_data);
}
}

View file

@ -27,7 +27,7 @@ public:
HttpsProtocol();
~HttpsProtocol() override = default;
virtual OwnPtr<Request> start_request(ConnectionFromClient&, String const& method, const URL&, HashMap<String, String> const& headers, ReadonlyBytes body) override;
virtual OwnPtr<Request> start_request(ConnectionFromClient&, String const& method, const URL&, HashMap<String, String> const& headers, ReadonlyBytes body, Core::ProxyData proxy_data = {}) override;
};
}

View file

@ -8,6 +8,7 @@
#include <AK/RefPtr.h>
#include <AK/URL.h>
#include <LibCore/Proxy.h>
#include <RequestServer/Forward.h>
namespace RequestServer {
@ -17,7 +18,7 @@ public:
virtual ~Protocol();
String const& name() const { return m_name; }
virtual OwnPtr<Request> start_request(ConnectionFromClient&, String const& method, const URL&, HashMap<String, String> const& headers, ReadonlyBytes body) = 0;
virtual OwnPtr<Request> start_request(ConnectionFromClient&, String const& method, const URL&, HashMap<String, String> const& headers, ReadonlyBytes body, Core::ProxyData proxy_data = {}) = 0;
static Protocol* find_by_name(String const&);

View file

@ -6,7 +6,7 @@ endpoint RequestServer
// Test if a specific protocol is supported, e.g "http"
is_supported_protocol(String protocol) => (bool supported)
start_request(String method, URL url, IPC::Dictionary request_headers, ByteBuffer request_body) => (i32 request_id, Optional<IPC::File> response_fd)
start_request(String method, URL url, IPC::Dictionary request_headers, ByteBuffer request_body, Core::ProxyData proxy_data) => (i32 request_id, Optional<IPC::File> response_fd)
stop_request(i32 request_id) => (bool success)
set_certificate(i32 request_id, String certificate, String key) => (bool success)