diff --git a/webview/platform/linux/webview_linux_webkitgtk.cpp b/webview/platform/linux/webview_linux_webkitgtk.cpp index 375445f..48cc012 100644 --- a/webview/platform/linux/webview_linux_webkitgtk.cpp +++ b/webview/platform/linux/webview_linux_webkitgtk.cpp @@ -17,6 +17,7 @@ #include "base/weak_ptr.h" #include "base/event_filter.h" #include "ui/gl/gl_detection.h" +#include "webview/webview_interface.h" #include #include @@ -885,10 +886,40 @@ bool Instance::create(Config config) { const auto baseCache = base + "/cache"; const auto baseData = base + "/data"; + const auto proxySettings = [&]() -> WebKitNetworkProxySettings* { + if (!config.proxySettings + || config.proxySettings->type != ProxyType::SOCKS5) { + return nullptr; + } + const auto &proxy = *config.proxySettings; + const auto uri = proxy.username.empty() + ? std::format( + "socks5://{}:{}", + proxy.host, + proxy.port) + : std::format( + "socks5://{}:{}@{}:{}", + proxy.username, + proxy.password, + proxy.host, + proxy.port); + return webkit_network_proxy_settings_new(uri.c_str(), nullptr); + }(); + const auto proxyGuard = gsl::finally([&] { + if (proxySettings) { + webkit_network_proxy_settings_free(proxySettings); + } + }); if (webkit_network_session_new) { WebKitNetworkSession *session = webkit_network_session_new( baseData.c_str(), baseCache.c_str()); + if (proxySettings && webkit_network_session_set_proxy_settings) { + webkit_network_session_set_proxy_settings( + session, + WEBKIT_NETWORK_PROXY_MODE_CUSTOM, + proxySettings); + } _webview = WEBKIT_WEB_VIEW(g_object_new( WEBKIT_TYPE_WEB_VIEW, "network-session", @@ -900,6 +931,13 @@ bool Instance::create(Config config) { "base-cache-directory", baseCache.c_str(), "base-data-directory", baseData.c_str(), nullptr); + if (proxySettings + && webkit_website_data_manager_set_network_proxy_settings) { + webkit_website_data_manager_set_network_proxy_settings( + data, + WEBKIT_NETWORK_PROXY_MODE_CUSTOM, + proxySettings); + } WebKitWebContext *context = webkit_web_context_new_with_website_data_manager(data); g_object_unref(data); diff --git a/webview/platform/linux/webview_linux_webkitgtk_library.cpp b/webview/platform/linux/webview_linux_webkitgtk_library.cpp index 558d06c..5133fc9 100644 --- a/webview/platform/linux/webview_linux_webkitgtk_library.cpp +++ b/webview/platform/linux/webview_linux_webkitgtk_library.cpp @@ -81,6 +81,8 @@ ResolveResult Resolve(const Platform &platform, WindowMode mode) { || (LOAD_LIBRARY_SYMBOL(lib, webkit_web_view_new_with_context) && LOAD_LIBRARY_SYMBOL(lib, webkit_website_data_manager_new) && LOAD_LIBRARY_SYMBOL(lib, webkit_web_context_new_with_website_data_manager))) + && LOAD_LIBRARY_SYMBOL(lib, webkit_network_proxy_settings_new) + && LOAD_LIBRARY_SYMBOL(lib, webkit_network_proxy_settings_free) && LOAD_LIBRARY_SYMBOL(lib, webkit_authentication_request_authenticate) && LOAD_LIBRARY_SYMBOL(lib, webkit_authentication_request_get_host) && LOAD_LIBRARY_SYMBOL(lib, webkit_authentication_request_get_port) @@ -100,6 +102,8 @@ ResolveResult Resolve(const Platform &platform, WindowMode mode) { LOAD_LIBRARY_SYMBOL(lib, gdk_screen_get_rgba_visual); LOAD_LIBRARY_SYMBOL(lib, webkit_javascript_result_get_js_value); LOAD_LIBRARY_SYMBOL(lib, webkit_website_data_manager_new); + LOAD_LIBRARY_SYMBOL(lib, webkit_website_data_manager_set_network_proxy_settings); + LOAD_LIBRARY_SYMBOL(lib, webkit_network_session_set_proxy_settings); LOAD_LIBRARY_SYMBOL(lib, webkit_web_context_new_with_website_data_manager); LOAD_LIBRARY_SYMBOL(lib, gtk_gesture_click_new); LOAD_LIBRARY_SYMBOL(lib, gtk_event_controller_key_new); diff --git a/webview/platform/linux/webview_linux_webkitgtk_library.h b/webview/platform/linux/webview_linux_webkitgtk_library.h index d24fc77..062427d 100644 --- a/webview/platform/linux/webview_linux_webkitgtk_library.h +++ b/webview/platform/linux/webview_linux_webkitgtk_library.h @@ -118,6 +118,7 @@ typedef struct _WebKitScriptDialog WebKitScriptDialog; typedef struct _WebKitWebsiteDataManager WebKitWebsiteDataManager; typedef struct _WebKitWebContext WebKitWebContext; typedef struct _WebKitNetworkSession WebKitNetworkSession; +typedef struct _WebKitNetworkProxySettings WebKitNetworkProxySettings; typedef struct _WebKitAuthenticationRequest WebKitAuthenticationRequest; typedef struct _WebKitCredential WebKitCredential; @@ -198,6 +199,12 @@ typedef enum { WEBKIT_CREDENTIAL_PERSISTENCE_PERMANENT, } WebKitCredentialPersistence; +typedef enum { + WEBKIT_NETWORK_PROXY_MODE_DEFAULT, + WEBKIT_NETWORK_PROXY_MODE_NO_PROXY, + WEBKIT_NETWORK_PROXY_MODE_CUSTOM +} WebKitNetworkProxyMode; + namespace Webview::WebKitGTK::Library { inline gboolean (*gtk_init_check)(int *argc, char ***argv); @@ -442,11 +449,24 @@ inline void (*webkit_web_view_set_background_color)( inline WebKitWebsiteDataManager *(*webkit_website_data_manager_new)( const gchar *first_option_name, ...); +inline void (*webkit_website_data_manager_set_network_proxy_settings)( + WebKitWebsiteDataManager *manager, + WebKitNetworkProxyMode proxy_mode, + WebKitNetworkProxySettings *proxy_settings); inline WebKitWebContext *(*webkit_web_context_new_with_website_data_manager)( WebKitWebsiteDataManager* manager); inline WebKitNetworkSession *(*webkit_network_session_new)( const char* data_directory, const char* cache_directory); +inline void (*webkit_network_session_set_proxy_settings)( + WebKitNetworkSession *session, + WebKitNetworkProxyMode proxy_mode, + WebKitNetworkProxySettings *proxy_settings); +inline WebKitNetworkProxySettings *(*webkit_network_proxy_settings_new)( + const gchar* default_proxy_uri, + const gchar* const* ignore_hosts); +inline void (*webkit_network_proxy_settings_free)( + WebKitNetworkProxySettings *proxy_settings); inline void (*webkit_authentication_request_authenticate)( WebKitAuthenticationRequest *request, WebKitCredential *credential); diff --git a/webview/platform/mac/webview_mac.mm b/webview/platform/mac/webview_mac.mm index 034ca50..f08f761 100644 --- a/webview/platform/mac/webview_mac.mm +++ b/webview/platform/mac/webview_mac.mm @@ -25,6 +25,7 @@ #import #import +#import namespace { @@ -483,6 +484,27 @@ void taskDone( [configuration setWebsiteDataStore:[WKWebsiteDataStore dataStoreForIdentifier:uuid]]; [uuid release]; } + if (config.proxySettings + && config.proxySettings->type == ProxyType::SOCKS5) { + const auto &proxy = *config.proxySettings; + auto store = configuration.websiteDataStore; + if (!store) { + store = [WKWebsiteDataStore defaultDataStore]; + [configuration setWebsiteDataStore:store]; + } + nw_endpoint_t endpoint = nw_endpoint_create_host( + proxy.server.c_str(), + proxy.port.c_str()); + nw_proxy_config_t proxyConfig + = nw_proxy_config_create_socksv5(endpoint); + if (!proxy.username.empty()) { + nw_proxy_config_set_username_and_password( + proxyConfig, + proxy.username.c_str(), + proxy.password.c_str()); + } + store.proxyConfigurations = @[ (id)proxyConfig ]; + } } _webview = [[WKWebView alloc] initWithFrame:NSZeroRect configuration:configuration]; if (@available(macOS 13.3, *)) { diff --git a/webview/platform/win/webview_windows_edge_chromium.cpp b/webview/platform/win/webview_windows_edge_chromium.cpp index dbca001..367db6c 100644 --- a/webview/platform/win/webview_windows_edge_chromium.cpp +++ b/webview/platform/win/webview_windows_edge_chromium.cpp @@ -743,11 +743,25 @@ Instance::~Instance() { } void Instance::start(Config &&config) { + auto arguments = std::wstring(L"--disable-features=ElasticOverscroll"); + if (config.proxySettings + && config.proxySettings->type == ProxyType::SOCKS5) { + const auto &proxy = *config.proxySettings; + arguments += L" --proxy-server=socks5://"; + if (!proxy.username.empty()) { + arguments += ToWide(proxy.username); + arguments += L":"; + arguments += ToWide(proxy.password); + arguments += L"@"; + } + arguments += ToWide(proxy.server); + arguments += L":"; + arguments += ToWide(proxy.port); + } auto options = winrt::com_ptr( Microsoft::WRL::Make().Detach(), winrt::take_ownership_from_abi); - options->put_AdditionalBrowserArguments( - L"--disable-features=ElasticOverscroll"); + options->put_AdditionalBrowserArguments(arguments.c_str()); auto handler = (Handler*)nullptr; const auto ready = [=] { diff --git a/webview/webview_embed.cpp b/webview/webview_embed.cpp index 9316eb5..c832c03 100644 --- a/webview/webview_embed.cpp +++ b/webview/webview_embed.cpp @@ -76,6 +76,7 @@ bool Window::createWebView(QWidget *parent, const WindowConfig &config) { .windowMargins = config.windowMargins, .initialSize = config.initialSize, .shellMessageToken = config.shellMessageToken.toStdString(), + .proxySettings = config.proxySettings, }); return (_webview != nullptr); } diff --git a/webview/webview_embed.h b/webview/webview_embed.h index 82495bb..e23eb88 100644 --- a/webview/webview_embed.h +++ b/webview/webview_embed.h @@ -47,6 +47,7 @@ struct WindowConfig { QMargins windowMargins; QSize initialSize; QString shellMessageToken; + std::optional proxySettings; }; class Window final { diff --git a/webview/webview_interface.h b/webview/webview_interface.h index 17a715b..cb607e2 100644 --- a/webview/webview_interface.h +++ b/webview/webview_interface.h @@ -144,6 +144,19 @@ struct Message { std::string sourceUrl; }; +enum class ProxyType { + SOCKS5, + Unsupported +}; + +struct ProxySettings { + ProxyType type; + std::string host; + std::string port; + std::string username; + std::string password; +}; + struct Config { QWidget *parent = nullptr; QColor opaqueBg; @@ -164,6 +177,7 @@ struct Config { QMargins windowMargins; QSize initialSize; std::string shellMessageToken; + std::optional proxySettings; }; struct Available {