mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 20:07:35 +00:00
Browser+LibWeb+WebContent: Implement per-URL-pattern proxies
...at least for SOCKS5.
This commit is contained in:
parent
f9fc28931f
commit
a42e03b01a
15 changed files with 155 additions and 6 deletions
|
@ -14,6 +14,8 @@ namespace Browser {
|
||||||
extern String g_home_url;
|
extern String g_home_url;
|
||||||
extern String g_search_engine;
|
extern String g_search_engine;
|
||||||
extern Vector<String> g_content_filters;
|
extern Vector<String> g_content_filters;
|
||||||
|
extern Vector<String> g_proxies;
|
||||||
|
extern HashMap<String, size_t> g_proxy_mappings;
|
||||||
extern bool g_content_filters_enabled;
|
extern bool g_content_filters_enabled;
|
||||||
extern IconBag g_icon_bag;
|
extern IconBag g_icon_bag;
|
||||||
|
|
||||||
|
|
|
@ -575,15 +575,34 @@ void BrowserWindow::content_filters_changed()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BrowserWindow::proxy_mappings_changed()
|
||||||
|
{
|
||||||
|
tab_widget().for_each_child_of_type<Browser::Tab>([](auto& tab) {
|
||||||
|
tab.proxy_mappings_changed();
|
||||||
|
return IterationDecision::Continue;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void BrowserWindow::config_string_did_change(String const& domain, String const& group, String const& key, String const& value)
|
void BrowserWindow::config_string_did_change(String const& domain, String const& group, String const& key, String const& value)
|
||||||
{
|
{
|
||||||
if (domain != "Browser" || group != "Preferences")
|
if (domain != "Browser")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (key == "SearchEngine")
|
if (group == "Preferences") {
|
||||||
Browser::g_search_engine = value;
|
if (key == "SearchEngine")
|
||||||
else if (key == "Home")
|
Browser::g_search_engine = value;
|
||||||
Browser::g_home_url = value;
|
else if (key == "Home")
|
||||||
|
Browser::g_home_url = value;
|
||||||
|
} else if (group.starts_with("Proxy:")) {
|
||||||
|
dbgln("Proxy mapping changed: {}/{} = {}", group, key, value);
|
||||||
|
auto proxy_spec = group.substring_view(6);
|
||||||
|
auto existing_proxy = Browser::g_proxies.find(proxy_spec);
|
||||||
|
if (existing_proxy.is_end())
|
||||||
|
Browser::g_proxies.append(proxy_spec);
|
||||||
|
|
||||||
|
Browser::g_proxy_mappings.set(key, existing_proxy.index());
|
||||||
|
proxy_mappings_changed();
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: ColorScheme
|
// TODO: ColorScheme
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ public:
|
||||||
GUI::Action& inspect_dom_node_action() { return *m_inspect_dom_node_action; }
|
GUI::Action& inspect_dom_node_action() { return *m_inspect_dom_node_action; }
|
||||||
|
|
||||||
void content_filters_changed();
|
void content_filters_changed();
|
||||||
|
void proxy_mappings_changed();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit BrowserWindow(CookieJar&, URL);
|
explicit BrowserWindow(CookieJar&, URL);
|
||||||
|
|
|
@ -118,6 +118,8 @@ Tab::Tab(BrowserWindow& window)
|
||||||
else
|
else
|
||||||
m_web_content_view->set_content_filters({});
|
m_web_content_view->set_content_filters({});
|
||||||
|
|
||||||
|
m_web_content_view->set_proxy_mappings(g_proxies, g_proxy_mappings);
|
||||||
|
|
||||||
auto& go_back_button = toolbar.add_action(window.go_back_action());
|
auto& go_back_button = toolbar.add_action(window.go_back_action());
|
||||||
go_back_button.on_context_menu_request = [this](auto& context_menu_event) {
|
go_back_button.on_context_menu_request = [this](auto& context_menu_event) {
|
||||||
if (!m_history.can_go_back())
|
if (!m_history.can_go_back())
|
||||||
|
@ -516,6 +518,11 @@ void Tab::content_filters_changed()
|
||||||
m_web_content_view->set_content_filters({});
|
m_web_content_view->set_content_filters({});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Tab::proxy_mappings_changed()
|
||||||
|
{
|
||||||
|
m_web_content_view->set_proxy_mappings(g_proxies, g_proxy_mappings);
|
||||||
|
}
|
||||||
|
|
||||||
void Tab::action_entered(GUI::Action& action)
|
void Tab::action_entered(GUI::Action& action)
|
||||||
{
|
{
|
||||||
m_statusbar->set_override_text(action.status_tip());
|
m_statusbar->set_override_text(action.status_tip());
|
||||||
|
|
|
@ -51,6 +51,7 @@ public:
|
||||||
void did_become_active();
|
void did_become_active();
|
||||||
void context_menu_requested(Gfx::IntPoint const& screen_position);
|
void context_menu_requested(Gfx::IntPoint const& screen_position);
|
||||||
void content_filters_changed();
|
void content_filters_changed();
|
||||||
|
void proxy_mappings_changed();
|
||||||
|
|
||||||
void action_entered(GUI::Action&);
|
void action_entered(GUI::Action&);
|
||||||
void action_left(GUI::Action&);
|
void action_left(GUI::Action&);
|
||||||
|
|
|
@ -31,6 +31,8 @@ String g_search_engine;
|
||||||
String g_home_url;
|
String g_home_url;
|
||||||
Vector<String> g_content_filters;
|
Vector<String> g_content_filters;
|
||||||
bool g_content_filters_enabled { true };
|
bool g_content_filters_enabled { true };
|
||||||
|
Vector<String> g_proxies;
|
||||||
|
HashMap<String, size_t> g_proxy_mappings;
|
||||||
IconBag g_icon_bag;
|
IconBag g_icon_bag;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -96,6 +98,20 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
||||||
|
|
||||||
TRY(load_content_filters());
|
TRY(load_content_filters());
|
||||||
|
|
||||||
|
for (auto& group : Config::list_groups("Browser")) {
|
||||||
|
if (!group.starts_with("Proxy:"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (auto& key : Config::list_keys("Browser", group)) {
|
||||||
|
auto proxy_spec = group.substring_view(6);
|
||||||
|
auto existing_proxy = Browser::g_proxies.find(proxy_spec);
|
||||||
|
if (existing_proxy.is_end())
|
||||||
|
Browser::g_proxies.append(proxy_spec);
|
||||||
|
|
||||||
|
Browser::g_proxy_mappings.set(key, existing_proxy.index());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
URL first_url = Browser::url_from_user_input(Browser::g_home_url);
|
URL first_url = Browser::url_from_user_input(Browser::g_home_url);
|
||||||
if (specified_url) {
|
if (specified_url) {
|
||||||
if (Core::File::exists(specified_url)) {
|
if (Core::File::exists(specified_url)) {
|
||||||
|
|
|
@ -280,6 +280,7 @@ set(SOURCES
|
||||||
Loader/ImageLoader.cpp
|
Loader/ImageLoader.cpp
|
||||||
Loader/ImageResource.cpp
|
Loader/ImageResource.cpp
|
||||||
Loader/LoadRequest.cpp
|
Loader/LoadRequest.cpp
|
||||||
|
Loader/ProxyMappings.cpp
|
||||||
Loader/Resource.cpp
|
Loader/Resource.cpp
|
||||||
Loader/ResourceLoader.cpp
|
Loader/ResourceLoader.cpp
|
||||||
MimeSniff/MimeType.cpp
|
MimeSniff/MimeType.cpp
|
||||||
|
|
41
Userland/Libraries/LibWeb/Loader/ProxyMappings.cpp
Normal file
41
Userland/Libraries/LibWeb/Loader/ProxyMappings.cpp
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022, Ali Mohammad Pur <mpfard@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ProxyMappings.h"
|
||||||
|
|
||||||
|
Web::ProxyMappings& Web::ProxyMappings::the()
|
||||||
|
{
|
||||||
|
static ProxyMappings instance {};
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::ProxyData Web::ProxyMappings::proxy_for_url(AK::URL const& url) const
|
||||||
|
{
|
||||||
|
auto url_string = url.to_string();
|
||||||
|
for (auto& it : m_mappings) {
|
||||||
|
dbgln("Checking {} against {}...", url, it.key);
|
||||||
|
if (url_string.matches(it.key)) {
|
||||||
|
dbgln("Matched!");
|
||||||
|
auto result = Core::ProxyData::parse_url(m_proxies[it.value]);
|
||||||
|
if (result.is_error()) {
|
||||||
|
dbgln("Failed to parse proxy URL: {}", m_proxies[it.value]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return result.release_value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dbgln("No luck!");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void Web::ProxyMappings::set_mappings(Vector<String> proxies, OrderedHashMap<String, size_t> mappings)
|
||||||
|
{
|
||||||
|
m_proxies = move(proxies);
|
||||||
|
m_mappings = move(mappings);
|
||||||
|
|
||||||
|
dbgln("Proxy mappings updated: proxies: {}", m_proxies);
|
||||||
|
}
|
31
Userland/Libraries/LibWeb/Loader/ProxyMappings.h
Normal file
31
Userland/Libraries/LibWeb/Loader/ProxyMappings.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022, Ali Mohammad Pur <mpfard@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/HashMap.h>
|
||||||
|
#include <AK/URL.h>
|
||||||
|
#include <AK/Vector.h>
|
||||||
|
#include <LibCore/Proxy.h>
|
||||||
|
|
||||||
|
namespace Web {
|
||||||
|
|
||||||
|
class ProxyMappings {
|
||||||
|
public:
|
||||||
|
static ProxyMappings& the();
|
||||||
|
|
||||||
|
Core::ProxyData proxy_for_url(AK::URL const&) const;
|
||||||
|
void set_mappings(Vector<String> proxies, OrderedHashMap<String, size_t> mappings);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ProxyMappings() = default;
|
||||||
|
~ProxyMappings() = default;
|
||||||
|
|
||||||
|
Vector<String> m_proxies;
|
||||||
|
OrderedHashMap<String, size_t> m_mappings;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -14,6 +14,7 @@
|
||||||
#include <LibProtocol/RequestClient.h>
|
#include <LibProtocol/RequestClient.h>
|
||||||
#include <LibWeb/Loader/ContentFilter.h>
|
#include <LibWeb/Loader/ContentFilter.h>
|
||||||
#include <LibWeb/Loader/LoadRequest.h>
|
#include <LibWeb/Loader/LoadRequest.h>
|
||||||
|
#include <LibWeb/Loader/ProxyMappings.h>
|
||||||
#include <LibWeb/Loader/Resource.h>
|
#include <LibWeb/Loader/Resource.h>
|
||||||
#include <LibWeb/Loader/ResourceLoader.h>
|
#include <LibWeb/Loader/ResourceLoader.h>
|
||||||
#include <serenity.h>
|
#include <serenity.h>
|
||||||
|
@ -213,6 +214,9 @@ void ResourceLoader::load(LoadRequest& request, Function<void(ReadonlyBytes, Has
|
||||||
}
|
}
|
||||||
|
|
||||||
if (url.protocol() == "http" || url.protocol() == "https" || url.protocol() == "gemini") {
|
if (url.protocol() == "http" || url.protocol() == "https" || url.protocol() == "gemini") {
|
||||||
|
auto proxy = ProxyMappings::the().proxy_for_url(url);
|
||||||
|
dbgln("Proxy for {} is {}", url, proxy.type == decltype(proxy.type)::SOCKS5 ? IPv4Address(proxy.host_ipv4).to_string() : "(direct)");
|
||||||
|
|
||||||
HashMap<String, String> headers;
|
HashMap<String, String> headers;
|
||||||
headers.set("User-Agent", m_user_agent);
|
headers.set("User-Agent", m_user_agent);
|
||||||
headers.set("Accept-Encoding", "gzip, deflate");
|
headers.set("Accept-Encoding", "gzip, deflate");
|
||||||
|
@ -221,7 +225,7 @@ void ResourceLoader::load(LoadRequest& request, Function<void(ReadonlyBytes, Has
|
||||||
headers.set(it.key, it.value);
|
headers.set(it.key, it.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto protocol_request = protocol_client().start_request(request.method(), url, headers, request.body());
|
auto protocol_request = protocol_client().start_request(request.method(), url, headers, request.body(), proxy);
|
||||||
if (!protocol_request) {
|
if (!protocol_request) {
|
||||||
auto start_request_failure_msg = "Failed to initiate load"sv;
|
auto start_request_failure_msg = "Failed to initiate load"sv;
|
||||||
log_failure(request, start_request_failure_msg);
|
log_failure(request, start_request_failure_msg);
|
||||||
|
|
|
@ -500,6 +500,11 @@ void OutOfProcessWebView::set_content_filters(Vector<String> filters)
|
||||||
client().async_set_content_filters(filters);
|
client().async_set_content_filters(filters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OutOfProcessWebView::set_proxy_mappings(Vector<String> proxies, HashMap<String, size_t> mappings)
|
||||||
|
{
|
||||||
|
client().async_set_proxy_mappings(move(proxies), move(mappings));
|
||||||
|
}
|
||||||
|
|
||||||
void OutOfProcessWebView::set_preferred_color_scheme(Web::CSS::PreferredColorScheme color_scheme)
|
void OutOfProcessWebView::set_preferred_color_scheme(Web::CSS::PreferredColorScheme color_scheme)
|
||||||
{
|
{
|
||||||
client().async_set_preferred_color_scheme(color_scheme);
|
client().async_set_preferred_color_scheme(color_scheme);
|
||||||
|
|
|
@ -55,6 +55,7 @@ public:
|
||||||
OrderedHashMap<String, String> get_local_storage_entries();
|
OrderedHashMap<String, String> get_local_storage_entries();
|
||||||
|
|
||||||
void set_content_filters(Vector<String>);
|
void set_content_filters(Vector<String>);
|
||||||
|
void set_proxy_mappings(Vector<String> proxies, HashMap<String, size_t> mappings);
|
||||||
void set_preferred_color_scheme(Web::CSS::PreferredColorScheme);
|
void set_preferred_color_scheme(Web::CSS::PreferredColorScheme);
|
||||||
|
|
||||||
Function<void(Gfx::IntPoint const& screen_position)> on_context_menu_request;
|
Function<void(Gfx::IntPoint const& screen_position)> on_context_menu_request;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include <AK/Debug.h>
|
#include <AK/Debug.h>
|
||||||
#include <AK/JsonObject.h>
|
#include <AK/JsonObject.h>
|
||||||
|
#include <AK/QuickSort.h>
|
||||||
#include <LibGfx/Bitmap.h>
|
#include <LibGfx/Bitmap.h>
|
||||||
#include <LibGfx/FontDatabase.h>
|
#include <LibGfx/FontDatabase.h>
|
||||||
#include <LibGfx/SystemTheme.h>
|
#include <LibGfx/SystemTheme.h>
|
||||||
|
@ -24,6 +25,7 @@
|
||||||
#include <LibWeb/HTML/Window.h>
|
#include <LibWeb/HTML/Window.h>
|
||||||
#include <LibWeb/Layout/InitialContainingBlock.h>
|
#include <LibWeb/Layout/InitialContainingBlock.h>
|
||||||
#include <LibWeb/Loader/ContentFilter.h>
|
#include <LibWeb/Loader/ContentFilter.h>
|
||||||
|
#include <LibWeb/Loader/ProxyMappings.h>
|
||||||
#include <LibWeb/Loader/ResourceLoader.h>
|
#include <LibWeb/Loader/ResourceLoader.h>
|
||||||
#include <LibWeb/Painting/PaintableBox.h>
|
#include <LibWeb/Painting/PaintableBox.h>
|
||||||
#include <LibWeb/Painting/StackingContext.h>
|
#include <LibWeb/Painting/StackingContext.h>
|
||||||
|
@ -454,6 +456,22 @@ void ConnectionFromClient::set_content_filters(Vector<String> const& filters)
|
||||||
Web::ContentFilter::the().add_pattern(filter);
|
Web::ContentFilter::the().add_pattern(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConnectionFromClient::set_proxy_mappings(Vector<String> const& proxies, HashMap<String, size_t> const& mappings)
|
||||||
|
{
|
||||||
|
auto keys = mappings.keys();
|
||||||
|
quick_sort(keys, [&](auto& a, auto& b) { return a.length() < b.length(); });
|
||||||
|
|
||||||
|
OrderedHashMap<String, size_t> sorted_mappings;
|
||||||
|
for (auto& key : keys) {
|
||||||
|
auto value = *mappings.get(key);
|
||||||
|
if (value >= proxies.size())
|
||||||
|
continue;
|
||||||
|
sorted_mappings.set(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Web::ProxyMappings::the().set_mappings(proxies, move(sorted_mappings));
|
||||||
|
}
|
||||||
|
|
||||||
void ConnectionFromClient::set_preferred_color_scheme(Web::CSS::PreferredColorScheme const& color_scheme)
|
void ConnectionFromClient::set_preferred_color_scheme(Web::CSS::PreferredColorScheme const& color_scheme)
|
||||||
{
|
{
|
||||||
m_page_host->set_preferred_color_scheme(color_scheme);
|
m_page_host->set_preferred_color_scheme(color_scheme);
|
||||||
|
|
|
@ -59,6 +59,7 @@ private:
|
||||||
virtual Messages::WebContentServer::GetHoveredNodeIdResponse get_hovered_node_id() override;
|
virtual Messages::WebContentServer::GetHoveredNodeIdResponse get_hovered_node_id() override;
|
||||||
virtual Messages::WebContentServer::DumpLayoutTreeResponse dump_layout_tree() override;
|
virtual Messages::WebContentServer::DumpLayoutTreeResponse dump_layout_tree() override;
|
||||||
virtual void set_content_filters(Vector<String> const&) override;
|
virtual void set_content_filters(Vector<String> const&) override;
|
||||||
|
virtual void set_proxy_mappings(Vector<String> const&, HashMap<String, size_t> const&) override;
|
||||||
virtual void set_preferred_color_scheme(Web::CSS::PreferredColorScheme const&) override;
|
virtual void set_preferred_color_scheme(Web::CSS::PreferredColorScheme const&) override;
|
||||||
virtual void set_has_focus(bool) override;
|
virtual void set_has_focus(bool) override;
|
||||||
virtual void set_is_scripting_enabled(bool) override;
|
virtual void set_is_scripting_enabled(bool) override;
|
||||||
|
|
|
@ -43,6 +43,7 @@ endpoint WebContentServer
|
||||||
select_all() =|
|
select_all() =|
|
||||||
|
|
||||||
set_content_filters(Vector<String> filters) =|
|
set_content_filters(Vector<String> filters) =|
|
||||||
|
set_proxy_mappings(Vector<String> proxies, HashMap<String,size_t> mappings) =|
|
||||||
set_preferred_color_scheme(Web::CSS::PreferredColorScheme color_scheme) =|
|
set_preferred_color_scheme(Web::CSS::PreferredColorScheme color_scheme) =|
|
||||||
set_has_focus(bool has_focus) =|
|
set_has_focus(bool has_focus) =|
|
||||||
set_is_scripting_enabled(bool is_scripting_enabled) =|
|
set_is_scripting_enabled(bool is_scripting_enabled) =|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue