Files
cromite/build/patches/Add-a-proxy-configuration-page.patch

1441 lines
59 KiB
Diff
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
From: csagan5 <32685696+csagan5@users.noreply.github.com>
Date: Thu, 29 Mar 2018 00:43:32 +0200
Subject: Add a proxy configuration page
Accessible from proxy settings and chrome://proxy
Allows to use a PAC script URL, automatic configuration and explicit proxy settings.
Offer auto-complete for the proxy page URL.
Store proxy settings in LocalState instead of Profile, so that proxy is used for SimpleURLLoaders as well;
this implementation is the same as the one in ChromeOS which gets proxy information from the LocalState
for the system network context; this is strictly not correct on Android because the network context is
never connected to any user profile and only gets proxy information from the system.
Existing settings on Profile are migrated to LocalState on startup.
Enable the support for multiple proxy chain via the bracketed [] sintax
Credits to @uazo for the LocalState integration.
License: GPL-3.0-only - https://spdx.org/licenses/GPL-3.0-only.html
---
chrome/android/java/res/values/values.xml | 3 +
.../java/res/xml/privacy_preferences.xml | 4 +
.../privacy/settings/PrivacySettings.java | 1 +
.../chrome_autocomplete_provider_client.cc | 1 +
chrome/browser/browser_resources.grd | 3 +
.../extensions/api/proxy/proxy_api_helpers.cc | 2 +-
chrome/browser/net/proxy_service_factory.cc | 24 +-
chrome/browser/net/proxy_service_factory.h | 3 +
chrome/browser/prefs/browser_prefs.cc | 4 +
.../prefs/chrome_command_line_pref_store.cc | 2 +-
chrome/browser/resources/proxy_config.css | 61 +++
chrome/browser/resources/proxy_config.html | 77 ++++
chrome/browser/resources/proxy_config.js | 278 +++++++++++++
chrome/browser/ui/BUILD.gn | 2 +
.../browser/ui/webui/chrome_web_ui_configs.cc | 5 +-
chrome/browser/ui/webui/proxy_config_ui.cc | 389 ++++++++++++++++++
chrome/browser/ui/webui/proxy_config_ui.h | 41 ++
chrome/common/webui_url_constants.cc | 1 +
chrome/common/webui_url_constants.h | 2 +
.../pref_proxy_config_tracker_impl.cc | 5 +-
.../proxy_config/proxy_config_dictionary.cc | 30 +-
.../proxy_config/proxy_config_dictionary.h | 7 +-
.../proxy_config/proxy_policy_handler.cc | 2 +-
net/features.gni | 2 +-
net/proxy_resolution/pac_file_fetcher_impl.cc | 8 -
net/proxy_resolution/proxy_config.cc | 53 ++-
net/proxy_resolution/proxy_config.h | 3 +
27 files changed, 986 insertions(+), 27 deletions(-)
create mode 100644 chrome/browser/resources/proxy_config.css
create mode 100644 chrome/browser/resources/proxy_config.html
create mode 100644 chrome/browser/resources/proxy_config.js
create mode 100644 chrome/browser/ui/webui/proxy_config_ui.cc
create mode 100644 chrome/browser/ui/webui/proxy_config_ui.h
diff --git a/chrome/android/java/res/values/values.xml b/chrome/android/java/res/values/values.xml
--- a/chrome/android/java/res/values/values.xml
+++ b/chrome/android/java/res/values/values.xml
@@ -22,6 +22,9 @@ found in the LICENSE file.
<!-- Compositor Tab Title Text -->
<bool name="compositor_tab_title_fake_bold_text">true</bool>
+ <string name="proxy_title">Proxy configuration</string>
+ <string name="proxy_url">chrome://proxy</string>
+
<!-- Download InfoBar animation. -->
<integer name="download_infobar_fill_in_delay">1200</integer>
<integer name="download_infobar_fill_out_delay">200</integer>
diff --git a/chrome/android/java/res/xml/privacy_preferences.xml b/chrome/android/java/res/xml/privacy_preferences.xml
--- a/chrome/android/java/res/xml/privacy_preferences.xml
+++ b/chrome/android/java/res/xml/privacy_preferences.xml
@@ -10,6 +10,10 @@ found in the LICENSE file.
<PreferenceCategory
android:key="privacy_section"
android:title="@string/privacy_section_title" />
+ <org.chromium.chrome.browser.about_settings.HyperlinkPreference
+ android:key="proxy"
+ android:title="@string/proxy_title"
+ app:url="@string/proxy_url" />
<Preference
android:key="clear_browsing_data"
android:title="@string/clear_browsing_data_title"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettings.java b/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettings.java
--- a/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettings.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettings.java
@@ -110,6 +110,7 @@ public class PrivacySettings extends ChromeBaseSettingsFragment
private static final String PREF_PASSWORD_LEAK_DETECTION = "password_leak_detection";
private static final String PREF_SYNC_AND_SERVICES_LINK = "sync_and_services_link";
private static final String PREF_PRIVACY_SANDBOX = "privacy_sandbox";
+ private static final String PREF_PROXY_OPTIONS = "proxy";
private static final String PREF_PRIVACY_GUIDE = "privacy_guide";
private static final String PREF_INCOGNITO_LOCK = "incognito_lock";
private static final String PREF_JAVASCRIPT_OPTIMIZER = "javascript_optimizer";
diff --git a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
--- a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
+++ b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
@@ -420,6 +420,7 @@ ChromeAutocompleteProviderClient::GetBuiltinsToProvideAsUserTypes() {
builtins_to_provide.push_back(chrome::kChromeUISettingsURL16);
#endif
builtins_to_provide.push_back(chrome::kChromeUIVersionURL16);
+ builtins_to_provide.push_back(chrome::kChromeUIProxyConfigURL16);
return builtins_to_provide;
}
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -236,6 +236,9 @@
<if expr="_google_chrome">
<include name="IDR_PREF_HASH_SEED_BIN" file="resources\settings\internal\pref_hash_seed.bin" type="BINDATA" />
</if>
+ <!-- Bromite Proxy Configuration UI -->
+ <include name="IDR_PROXY_CONFIG_HTML" file="resources\proxy_config.html" flattenhtml="true" type="BINDATA" compress="gzip" />
+ <include name="IDR_PROXY_CONFIG_JS" file="resources\proxy_config.js" type="BINDATA" compress="gzip" />
<if expr="not is_android or enable_extensions_core">
<!-- Page not available for guest. -->
<include name="IDR_PAGE_NOT_AVAILABLE_FOR_GUEST_APP_HTML" file="resources\page_not_available_for_guest\app.html" type="BINDATA" />
diff --git a/chrome/browser/extensions/api/proxy/proxy_api_helpers.cc b/chrome/browser/extensions/api/proxy/proxy_api_helpers.cc
--- a/chrome/browser/extensions/api/proxy/proxy_api_helpers.cc
+++ b/chrome/browser/extensions/api/proxy/proxy_api_helpers.cc
@@ -383,7 +383,7 @@ std::optional<base::DictValue> CreateProxyConfigDict(
return std::nullopt;
}
return ProxyConfigDictionary::CreateFixedServers(proxy_rules_string,
- bypass_list);
+ bypass_list, /*reverse_bypass*/false);
}
case ProxyPrefs::MODE_SYSTEM:
return ProxyConfigDictionary::CreateSystem();
diff --git a/chrome/browser/net/proxy_service_factory.cc b/chrome/browser/net/proxy_service_factory.cc
--- a/chrome/browser/net/proxy_service_factory.cc
+++ b/chrome/browser/net/proxy_service_factory.cc
@@ -6,6 +6,7 @@
#include <utility>
+#include "base/logging.h"
#include "base/task/single_thread_task_runner.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
@@ -13,6 +14,9 @@
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "net/proxy_resolution/proxy_config_service.h"
+#include "components/proxy_config/proxy_config_pref_names.h"
+#include "components/prefs/pref_service.h"
+#include "components/prefs/pref_registry_simple.h"
#if BUILDFLAG(IS_CHROMEOS)
#include "chromeos/ash/components/network/proxy/proxy_config_service_impl.h"
@@ -57,7 +61,20 @@ ProxyServiceFactory::CreatePrefProxyConfigTrackerOfProfile(
return std::make_unique<ash::ProxyConfigServiceImpl>(
profile_prefs, local_state_prefs, nullptr);
#else
- return std::make_unique<PrefProxyConfigTrackerImpl>(profile_prefs, nullptr);
+ // Migrate from profile_prefs to local_state_prefs
+ if (local_state_prefs->GetBoolean("proxy_migrated") == false) {
+ const base::DictValue& dict =
+ profile_prefs->GetDict(proxy_config::prefs::kProxy);
+
+ LOG(INFO) << "CreatePrefProxyConfigTrackerOfProfile: Migration from profile to local state";
+
+ const base::Value /*ProxyConfigDictionary*/ proxy_dict(dict.Clone());
+ local_state_prefs->Set(proxy_config::prefs::kProxy, proxy_dict);
+
+ local_state_prefs->SetBoolean("proxy_migrated", true);
+ local_state_prefs->CommitPendingWrite();
+ }
+ return std::make_unique<PrefProxyConfigTrackerImpl>(local_state_prefs, nullptr);
#endif // BUILDFLAG(IS_CHROMEOS)
}
@@ -73,3 +90,8 @@ ProxyServiceFactory::CreatePrefProxyConfigTrackerOfLocalState(
nullptr);
#endif // BUILDFLAG(IS_CHROMEOS)
}
+
+// static
+void ProxyServiceFactory::RegisterPrefs(PrefRegistrySimple* registry) {
+ registry->RegisterBooleanPref("proxy_migrated", false);
+}
diff --git a/chrome/browser/net/proxy_service_factory.h b/chrome/browser/net/proxy_service_factory.h
--- a/chrome/browser/net/proxy_service_factory.h
+++ b/chrome/browser/net/proxy_service_factory.h
@@ -6,6 +6,7 @@
#define CHROME_BROWSER_NET_PROXY_SERVICE_FACTORY_H_
#include <memory>
+#include "components/prefs/pref_registry_simple.h"
class PrefProxyConfigTracker;
class PrefService;
@@ -35,6 +36,8 @@ class ProxyServiceFactory {
CreatePrefProxyConfigTrackerOfProfile(PrefService* profile_prefs,
PrefService* local_state_prefs);
+ static void RegisterPrefs(PrefRegistrySimple* registry);
+
// Creates a PrefProxyConfigTracker that tracks local state only. This tracker
// should be used for the system request context and the signin screen
// (ChromeOS only).
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -212,6 +212,8 @@
#include "printing/buildflags/buildflags.h"
#include "rlz/buildflags/buildflags.h"
+#include "chrome/browser/net/proxy_service_factory.h"
+
#if BUILDFLAG(ENABLE_BACKGROUND_MODE)
#include "chrome/browser/background/extensions/background_mode_manager.h"
#endif
@@ -1374,6 +1376,8 @@ void RegisterLocalState(PrefRegistrySimple* registry) {
component_updater::RegisterPrefs(registry);
domain_reliability::RegisterPrefs(registry);
embedder_support::OriginTrialPrefs::RegisterPrefs(registry);
+ ProxyServiceFactory::RegisterPrefs(registry);
+
enterprise_reporting::RegisterLocalStatePrefs(registry);
ExternalProtocolHandler::RegisterPrefs(registry);
flags_ui::PrefServiceFlagsStorage::RegisterPrefs(registry);
diff --git a/chrome/browser/prefs/chrome_command_line_pref_store.cc b/chrome/browser/prefs/chrome_command_line_pref_store.cc
--- a/chrome/browser/prefs/chrome_command_line_pref_store.cc
+++ b/chrome/browser/prefs/chrome_command_line_pref_store.cc
@@ -161,7 +161,7 @@ void ChromeCommandLinePrefStore::ApplyProxyMode() {
command_line()->GetSwitchValueASCII(switches::kProxyBypassList);
SetValue(proxy_config::prefs::kProxy,
base::Value(ProxyConfigDictionary::CreateFixedServers(
- proxy_server, bypass_list)),
+ proxy_server, bypass_list, false)),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
}
}
diff --git a/chrome/browser/resources/proxy_config.css b/chrome/browser/resources/proxy_config.css
new file mode 100644
--- /dev/null
+++ b/chrome/browser/resources/proxy_config.css
@@ -0,0 +1,61 @@
+/* Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+body {
+ font-size: 80%;
+ margin: 1em;
+}
+
+#main-container {
+ max-width: 60em;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+button {
+ display: block;
+ font-size: 110%;
+ font-weight: bold;
+ margin: 10px auto;
+ padding: 1em;
+ width: 15em;
+}
+
+h2 {
+ color: #546E7A;
+ font-weight: normal;
+ font-size: 170%;
+ margin-bottom: 1.5em;
+}
+
+.radio-button-div {
+ margin: 7px auto;
+}
+
+.warning {
+ color: red;
+ font-size: 90%;
+}
+
+.section-container {
+ margin-top: 2em;
+}
+
+#file-path-logging,
+#file-path-stopped {
+ font-family: monospace;
+}
+
+.outline-box {
+ margin-top: 2em;
+ border: 1px solid #ababab;
+ padding: 0.5em;
+ line-height: 1.5em;
+}
+
+textarea {
+ width: 95%;
+ height: 4em;
+}
diff --git a/chrome/browser/resources/proxy_config.html b/chrome/browser/resources/proxy_config.html
new file mode 100644
--- /dev/null
+++ b/chrome/browser/resources/proxy_config.html
@@ -0,0 +1,77 @@
+<!doctype html>
+<html>
+<head>
+<meta charset="utf-8">
+<if expr="is_android">
+<meta name="viewport" content="width=device-width">
+</if>
+
+<if expr="is_ios">
+<!-- TODO(crbug.com/487000): Remove this once injected by web. -->
+<script src="chrome://resources/js/ios/web_ui.js"></script>
+</if>
+
+<script type="module" src="chrome://proxy/proxy_config.js"></script>
+<link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
+<link rel="stylesheet" href="proxy_config.css">
+<title>Proxy configuration</title>
+</head>
+<body>
+ <div id="main-container">
+ <!--
+ =========================================================================
+ View for "pending" state.
+ * Only visible briefly, if at all
+ =========================================================================
+ -->
+ <div id="state-pending">
+ <h2>Proxy configuration</h2>
+ Loading...
+ </div>
+
+ <!--
+ =========================================================================
+ View for "available" and "unset" states.
+ * Has controls to change or reset proxy configuration.
+ =========================================================================
+ -->
+ <div id="state-main" hidden>
+ <h2>Proxy configuration</h2>
+ <button id="reset">Reset</button>
+ <div class="section-container">
+ Reset will update the displayed configuration to match the one currently in use.
+ </div>
+ <div class="section-container">
+ <input type="radio" id="empty" name="mode" value="empty"><label for="empty">System Default</label><br/>
+ <input type="radio" id="direct" name="mode" value="direct"><label for="direct">Direct</label><br/>
+ <input type="radio" id="auto-detect" name="mode" value="auto-detect"><label for="auto-detect">Auto-detect (WPAD DHCP/DNS)</label><br/>
+ <input type="radio" id="use-pac-url" name="mode" value="use-pac-url"><label for="use-pac-url">Use PAC URL: <input id='pac-url' value="" size="40" /></label>
+ <p><input type="checkbox" id="pac-mandatory" name="pac-mandatory"><label for="pac-mandatory">Do not allow fallback to direct connection in case PAC script fails</label></p>
+ <input type="radio" id="use-single-list" name="mode" value="use-single-list"><label for="use-single-list">Use a single proxy list for all schemes (<a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Proxy_servers_and_tunneling/Proxy_Auto-Configuration_(PAC)_file#Description">PAC format</a>):
+ <textarea id="single-proxies"></textarea>
+ </label><br/>
+ <input type="radio" id="use-list-per-scheme" name="mode" value="use-list-per-scheme"><label for="use-list-per-scheme">Use a proxy list per scheme:</label><br/>
+ <label for="use-list-per-scheme">HTTP (<a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Proxy_servers_and_tunneling/Proxy_Auto-Configuration_(PAC)_file#Description">PAC format</a>):<br/>
+ <textarea id="http-proxies"></textarea></label><br/>
+ <label for="use-list-per-scheme">HTTPS (<a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Proxy_servers_and_tunneling/Proxy_Auto-Configuration_(PAC)_file#Description">PAC format</a>):<br/>
+ <textarea id="https-proxies"></textarea></label><br/>
+ <label for="use-list-per-scheme">FTP (<a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Proxy_servers_and_tunneling/Proxy_Auto-Configuration_(PAC)_file#Description">PAC format</a>):<br/>
+ <textarea id="ftp-proxies"></textarea></label><br/>
+ <label for="use-list-per-scheme">Fallback (used when the URL does not match any of the standard schemes, <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Proxy_servers_and_tunneling/Proxy_Auto-Configuration_(PAC)_file#Description">PAC format</a>):<br/>
+ <textarea id="fallback-proxies"></textarea></label>
+ <div class="outline-box">
+ Bypass rules (a list of matching expressions for the hostname separated by comma or semicolon, can use asterisk; matches against port numbers and IPv4/IPv6); in use only with single or per-scheme proxy lists.<br/>
+ <textarea id="bypass-rules"></textarea><br/>
+ <input type="checkbox" id="reverse-bypass" name="reverse-bypass"><label for="reverse-bypass">Reverse the meaning of bypass rules</label>
+ </div>
+ </div>
+ <button id="apply">Apply</button>
+ <button id="clear">Clear</button>
+ <div class="section-container">
+ Clicking on Clear will remove any proxy configuration preference currently in effect.
+ </div>
+ </div>
+
+ </div>
+</body>
+</html>
diff --git a/chrome/browser/resources/proxy_config.js b/chrome/browser/resources/proxy_config.js
new file mode 100644
--- /dev/null
+++ b/chrome/browser/resources/proxy_config.js
@@ -0,0 +1,278 @@
+/*
+ This file is part of Bromite.
+
+ Bromite is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Bromite is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Bromite. If not, see <https://www.gnu.org/licenses/>.
+*/
+
+import {$} from 'chrome://resources/js/util.js';
+
+/**
+ * Main entry point called once the page has loaded.
+ */
+function onLoad() {
+ ProxyConfigView.getInstance();
+}
+
+document.addEventListener('DOMContentLoaded', onLoad);
+
+/**
+ * This class handles the presentation of the proxy-config view. Used as a
+ * singleton.
+ */
+var ProxyConfigView = (function() {
+ 'use strict';
+
+ // --------------------------------------------------------------------------
+
+ var kIdStateDivUninitialized = 'state-pending';
+ var kIdStateDivMain = 'state-main';
+ var kIdApplyButton = 'apply';
+ var kIdResetButton = 'reset';
+ var kIdClearButton = 'clear';
+
+ var kIdModeEmpty = 'empty';
+ var kIdModeDirect = 'direct';
+ var kIdModeAutoDetect = 'auto-detect';
+ var kIdModeUsePacURL = 'use-pac-url';
+
+ var kIdModeUseSingleList = 'use-single-list';
+ var kIdModeUseListPerScheme = 'use-list-per-scheme';
+
+ var kIdPacURL = 'pac-url';
+ var kIdPacMandatory = 'pac-mandatory';
+ var kIdBypassRules = 'bypass-rules';
+ var kIdReverseBypass = 'reverse-bypass';
+ var kIdSingleProxies = 'single-proxies';
+ var kIdHttpProxies = 'http-proxies';
+ var kIdHttpsProxies = 'https-proxies';
+ var kIdFtpProxies = 'ftp-proxies';
+ var kIdFallbackProxies = 'fallback-proxies';
+
+ /**
+ * Adds a {@code getInstance} static method that always return the same
+ * instance object.
+ * @param {!Function} ctor The constructor for the class to add the static
+ * method to.
+ */
+ function addSingletonGetter(ctor) {
+ ctor.getInstance = function() {
+ return ctor.instance_ || (ctor.instance_ = new ctor());
+ };
+ }
+
+ /**
+ * @constructor
+ */
+ function ProxyConfigView() {
+ this.currentConfig = null;
+
+ $(kIdResetButton).onclick = this.onReset_.bind(this);
+ $(kIdApplyButton).onclick = this.onApply_.bind(this);
+ $(kIdClearButton).onclick = this.onClear_.bind(this);
+
+ // Tell ProxyConfigMessageHandler to notify the UI of future state changes
+ // from this point on.
+ chrome.send('enableNotifyUIWithState');
+ }
+
+ addSingletonGetter(ProxyConfigView);
+ window.ProxyConfigView = ProxyConfigView;
+
+ ProxyConfigView.prototype = {
+ /**
+ * Updates the UI to reflect the current state. The state transitions are
+ * sent by the browser controller (ProxyConfigMessageHandler):
+ *
+ * * PENDING - This is the initial state when proxy configuration is opened
+ * for the first time, or there was an error during initialization.
+ * This state is short-lived and likely not observed; will
+ * immediately transition to AVAILABLE).
+ *
+ * * AVAILABLE - The reported proxy configuration is active; this state is entered
+ * on first page load (or right after PENDING if configuration was not
+ * available on page load) and every time some configuration change was applied.
+ * It can transition to either AVAILABLE or UNSET.
+ *
+ * * UNSET - Proxy configuration is reported to be currently not set.
+ *
+ */
+ onProxyConfigChanged: function(state) {
+ // may happen only on first load; leave the loading page as another update is expected
+ // when proxy configuration has finished loading
+ if (state.pending) {
+ $(kIdStateDivMain).hidden = true;
+ $(kIdStateDivUninitialized).hidden = false;
+ return;
+ }
+
+ if (!state.hasOwnProperty('config')) {
+ // configuration has been unset, use an empty one
+ this.eraseCurrentConfig_();
+ } else {
+ // save the configuration as current and reset all controls to it
+ this.currentConfig = state.config;
+ }
+
+ this.renderConfig_();
+
+ this.toggleButtons_(false);
+ $(kIdStateDivUninitialized).hidden = true;
+ $(kIdStateDivMain).hidden = false;
+ },
+
+ /**
+ * Set current configuration to an empty (default) one.
+ */
+ eraseCurrentConfig_: function() {
+ this.currentConfig = {
+ "auto_detect": false,
+ "pending": false,
+ "rules": {
+ "bypass_rules": "",
+ "reverse_bypass": false,
+ "type": "none"
+ }
+ };
+ },
+
+ /**
+ * Serialize the user-selected configuration in an object.
+ */
+ serializeConfig_: function() {
+ if ($(kIdModeEmpty).checked) {
+ return {
+ "auto_detect": false,
+ "rules": {
+ "type": "none"
+ }
+ };
+ } else if ($(kIdModeDirect).checked) {
+ return {
+ "auto_detect": false,
+ "rules": {
+ "type": "direct"
+ }
+ };
+ } else if ($(kIdModeAutoDetect).checked) {
+ return {
+ "auto_detect": true
+ };
+ } else if ($(kIdModeUsePacURL).checked) {
+ return {
+ "auto_detect": false,
+ "pac_url": $(kIdPacURL).value.trim(),
+ "pac_mandatory": $(kIdPacMandatory).checked,
+ "rules": {}
+ };
+ } else if ($(kIdModeUseListPerScheme).checked || $(kIdModeUseSingleList).checked) {
+ var config = {
+ "auto_detect": false,
+ "rules": {
+ "bypass_rules": $(kIdBypassRules).value.trim(),
+ "reverse_bypass": $(kIdReverseBypass).checked,
+ "type": "list"
+ }
+ };
+
+ if ($(kIdModeUseListPerScheme).checked) {
+ config.rules.type = "list_per_scheme";
+
+ config.rules.proxies_for_http = $(kIdHttpProxies).value.trim();
+ config.rules.proxies_for_https = $(kIdHttpsProxies).value.trim();
+ config.rules.proxies_for_ftp = $(kIdFtpProxies).value.trim();
+ config.rules.fallback_proxies = $(kIdFallbackProxies).value.trim();
+ } else {
+ config.rules.single_proxies = $(kIdSingleProxies).value.trim();
+ }
+
+ return config;
+ }
+
+ throw new Error('unexpected mode');
+ },
+
+ /**
+ * Updates the UI to display the current proxy configuration.
+ */
+ renderConfig_: function() {
+ if (this.currentConfig.auto_detect) {
+ $(kIdModeAutoDetect).checked = true;
+ } else if (this.currentConfig.hasOwnProperty('pac_url')) {
+ $(kIdPacURL).value = this.currentConfig.pac_url;
+ $(kIdPacMandatory).checked = this.currentConfig.pac_mandatory;
+ $(kIdModeUsePacURL).checked = true;
+ } else if (this.currentConfig.rules.type == "none") {
+ $(kIdModeEmpty).checked = true;
+ } else if (this.currentConfig.rules.type == "direct") {
+ $(kIdModeDirect).checked = true;
+ } else {
+ $(kIdBypassRules).value = this.currentConfig.rules.bypass_rules;
+ $(kIdReverseBypass).checked = this.currentConfig.rules.reverse_bypass;
+
+ switch (this.currentConfig.rules.type) {
+ case "list":
+ $(kIdModeUseSingleList).checked = true;
+ $(kIdSingleProxies).value = this.currentConfig.rules.single_proxies;
+ break;
+ case "list_per_scheme":
+ $(kIdModeUseListPerScheme).checked = true;
+ $(kIdHttpProxies).value = this.currentConfig.rules.proxies_for_http;
+ $(kIdHttpsProxies).value = this.currentConfig.rules.proxies_for_https;
+ $(kIdFtpProxies).value = this.currentConfig.rules.proxies_for_ftp;
+ $(kIdFallbackProxies).value = this.currentConfig.rules.fallback_proxies;
+ break;
+ }
+ }
+ },
+
+ /**
+ * Apply the configuration currently displayed.
+ */
+ onApply_: function() {
+ var config = this.serializeConfig_();
+
+ // disable buttons; will be enabled back when UI receives a state update
+ this.toggleButtons_(true);
+ chrome.send('apply', [config]);
+ },
+
+ /**
+ * Apply the configuration currently displayed.
+ */
+ onClear_: function() {
+ // disable buttons; will be enabled back when UI receives a state update
+ this.toggleButtons_(true);
+ this.eraseCurrentConfig_();
+ chrome.send('clear', []);
+ },
+
+ /**
+ * Toggle the disabled status of the action buttons.
+ */
+ toggleButtons_: function(disabled) {
+ $(kIdApplyButton).disabled = disabled;
+ $(kIdResetButton).disabled = disabled;
+ $(kIdClearButton).disabled = disabled;
+ },
+
+ /**
+ * Reset currently displayed configuration to the last known configuration in use.
+ */
+ onReset_: function() {
+ this.renderConfig_();
+ }
+ };
+
+ return ProxyConfigView;
+})();
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -156,6 +156,8 @@ static_library("ui") {
"webui/metrics_internals/metrics_internals_ui.h",
"webui/net_export_ui.cc",
"webui/net_export_ui.h",
+ "webui/proxy_config_ui.cc",
+ "webui/proxy_config_ui.h",
"webui/net_internals/net_internals_ui.cc",
"webui/net_internals/net_internals_ui.h",
"webui/ntp_tiles_internals_ui.cc",
diff --git a/chrome/browser/ui/webui/chrome_web_ui_configs.cc b/chrome/browser/ui/webui/chrome_web_ui_configs.cc
--- a/chrome/browser/ui/webui/chrome_web_ui_configs.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_configs.cc
@@ -64,6 +64,9 @@
#include "extensions/buildflags/buildflags.h"
#include "printing/buildflags/buildflags.h"
+#include "chrome/browser/ui/webui/proxy_config_ui.h"
+
+
#if BUILDFLAG(ENABLE_WEBUI_CERTIFICATE_VIEWER)
#include "chrome/browser/ui/webui/certificate_viewer/certificate_viewer_ui.h"
#endif
@@ -453,7 +456,7 @@ void RegisterChromeWebUIConfigs() {
map.AddWebUIConfig(std::make_unique<SigninErrorUIConfig>());
map.AddWebUIConfig(std::make_unique<SigninEmailConfirmationUIConfig>());
#endif // !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_ANDROID)
-
+ map.AddWebUIConfig(std::make_unique<ProxyConfigUIConfig>());
#if BUILDFLAG(SAFE_BROWSING_AVAILABLE)
map.AddWebUIConfig(
std::make_unique<safe_browsing::ChromeSafeBrowsingUIConfig>());
diff --git a/chrome/browser/ui/webui/proxy_config_ui.cc b/chrome/browser/ui/webui/proxy_config_ui.cc
new file mode 100644
--- /dev/null
+++ b/chrome/browser/ui/webui/proxy_config_ui.cc
@@ -0,0 +1,389 @@
+/*
+ This file is part of Bromite.
+
+ Bromite is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Bromite is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Bromite. If not, see <https://www.gnu.org/licenses/>.
+*/
+
+#include "chrome/browser/ui/webui/proxy_config_ui.h"
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/lazy_instance.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/net/proxy_service_factory.h"
+#include "chrome/browser/platform_util.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/grit/browser_resources.h"
+#include "components/prefs/pref_service.h"
+#include "components/proxy_config/pref_proxy_config_tracker_impl.h"
+#include "components/proxy_config/proxy_config_pref_names.h"
+#include "components/grit/components_resources.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/url_data_source.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_ui.h"
+#include "content/public/browser/web_ui_data_source.h"
+#include "content/public/browser/web_ui_message_handler.h"
+
+#include "url/gurl.h"
+
+using content::BrowserThread;
+using content::WebContents;
+using content::WebUIMessageHandler;
+
+namespace {
+
+// This class receives javascript messages from the renderer.
+// Note that the WebUI infrastructure runs on the UI thread, therefore all of
+// this class's public methods are expected to run on the UI thread.
+class ProxyConfigMessageHandler
+ : public WebUIMessageHandler,
+ public net::ProxyConfigService::Observer {
+ public:
+ ProxyConfigMessageHandler(const ProxyConfigMessageHandler&) = delete;
+ ProxyConfigMessageHandler& operator=(const ProxyConfigMessageHandler&) = delete;
+ // Creates a ProxyConfigMessageHandler that handles message exchanges with the Javascript
+ // side of the UI and gets proxy settings from the Web UI associated profile to watch for changes.
+ // The created ProxyConfigMessageHandler must be destroyed before |profile|.
+ ProxyConfigMessageHandler(Profile *profile);
+ ~ProxyConfigMessageHandler() override;
+
+ // WebUIMessageHandler implementation.
+ void RegisterMessages() override;
+
+ // Messages
+ void OnEnableNotifyUIWithState(const base::ListValue& args);
+ void OnApply(const base::ListValue& args);
+ void OnClear(const base::ListValue& args);
+
+ // net::ProxyConfigService::Observer implementation:
+ // Calls ProxyConfigView.onProxyConfigChanged JavaScript function in the
+ // renderer.
+ void OnProxyConfigChanged(
+ const net::ProxyConfigWithAnnotation& config,
+ net::ProxyConfigService::ConfigAvailability availability) override;
+
+ private:
+ // Not owned.
+ raw_ptr<PrefService> pref_service_;
+ std::unique_ptr<net::ProxyConfigService> proxy_config_service_;
+ // Monitors global and Profile prefs related to proxy configuration.
+ std::unique_ptr<PrefProxyConfigTracker> pref_proxy_config_tracker_;
+ bool is_observing_;
+
+ void encodeConfig(const net::ProxyConfig& config, base::DictValue& state);
+
+ void apply(const net::ProxyConfig& config);
+
+ base::WeakPtrFactory<ProxyConfigMessageHandler> weak_ptr_factory_{this};
+};
+
+ProxyConfigMessageHandler::ProxyConfigMessageHandler(Profile *profile) {
+
+ // used to set new configuration preferences
+ pref_service_ = g_browser_process->local_state();
+ // observer is explicitly added only later in enableNotifyUIWithState
+ is_observing_ = false;
+
+// If this is the ChromeOS sign-in profile, just create the tracker from global
+// state.
+#if defined(OS_CHROMEOS)
+ if (chromeos::ProfileHelper::IsSigninProfile(profile)) {
+ pref_proxy_config_tracker_.reset(
+ ProxyServiceFactory::CreatePrefProxyConfigTrackerOfLocalState(
+ g_browser_process->local_state()));
+ }
+#endif // defined(OS_CHROMEOS)
+
+ if (!pref_proxy_config_tracker_) {
+ pref_proxy_config_tracker_ =
+ ProxyServiceFactory::CreatePrefProxyConfigTrackerOfProfile(
+ profile->GetPrefs(), g_browser_process->local_state());
+ }
+
+ proxy_config_service_ = ProxyServiceFactory::CreateProxyConfigService(
+ pref_proxy_config_tracker_.get(), nullptr);
+}
+
+void ProxyConfigMessageHandler::OnProxyConfigChanged(
+ const net::ProxyConfigWithAnnotation& config,
+ net::ProxyConfigService::ConfigAvailability availability) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
+ !BrowserThread::IsThreadInitialized(BrowserThread::UI));
+
+ base::DictValue state;
+ bool pending = false;
+ switch (availability) {
+ case net::ProxyConfigService::CONFIG_VALID:
+ encodeConfig(config.value(), state);
+ break;
+ case net::ProxyConfigService::CONFIG_UNSET:
+ state.SetByDottedPath("config.rules.type", base::Value("none"));
+ break;
+ case net::ProxyConfigService::CONFIG_PENDING:
+ //NOTE: this can only happen when triggered manually first time
+ pending = true;
+ break;
+ }
+ state.Set("pending", base::Value(pending));
+
+ // call Javascript function
+ web_ui()->CallJavascriptFunctionUnsafe("ProxyConfigView.getInstance().onProxyConfigChanged",
+ state.Clone());
+}
+
+const std::string omitDirect(const std::string pacString) {
+ if (pacString == "DIRECT") {
+ return "";
+ }
+ return pacString;
+}
+
+void ProxyConfigMessageHandler::encodeConfig(const net::ProxyConfig& config, base::DictValue& state) {
+ // when automatic settings are enabled they take precedence over manual settings
+ // automatic settings are either the "auto-detect" flag or the existance of a PAC URL
+
+ state.SetByDottedPath("config.auto_detect", base::Value(config.auto_detect()));
+
+ auto rules = config.proxy_rules();
+ if (config.has_pac_url()) {
+ state.SetByDottedPath("config.pac_url", base::Value(config.pac_url().spec()));
+ state.SetByDottedPath("config.pac_mandatory", base::Value(config.pac_mandatory()));
+ state.SetByDottedPath("config.rules.type", base::Value("none"));
+ state.SetByDottedPath("config.rules.bypass_rules", base::Value(rules.bypass_rules.ToString()));
+ state.SetByDottedPath("config.rules.reverse_bypass", base::Value(rules.reverse_bypass));
+ return;
+ }
+
+ const char *type;
+ switch (rules.type) {
+ case net::ProxyConfig::ProxyRules::Type::EMPTY:
+ type = "direct";
+ break;
+ case net::ProxyConfig::ProxyRules::Type::PROXY_LIST:
+ type = "list";
+
+ state.SetByDottedPath("config.rules.single_proxies", base::Value(omitDirect(rules.single_proxies.ToPacString())));
+ break;
+ case net::ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME:
+ type = "list_per_scheme";
+
+ state.SetByDottedPath("config.rules.proxies_for_http", base::Value(omitDirect(rules.proxies_for_http.ToPacString())));
+ state.SetByDottedPath("config.rules.proxies_for_https", base::Value(omitDirect(rules.proxies_for_https.ToPacString())));
+ state.SetByDottedPath("config.rules.proxies_for_ftp", base::Value(omitDirect(rules.proxies_for_ftp.ToPacString())));
+ state.SetByDottedPath("config.rules.fallback_proxies", base::Value(omitDirect(rules.fallback_proxies.ToPacString())));
+ break;
+ default:
+ NOTREACHED();
+ }
+ state.SetByDottedPath("config.rules.type", base::Value(type));
+ state.SetByDottedPath("config.rules.bypass_rules", base::Value(rules.bypass_rules.ToString()));
+ state.SetByDottedPath("config.rules.reverse_bypass", base::Value(rules.reverse_bypass));
+}
+
+ProxyConfigMessageHandler::~ProxyConfigMessageHandler() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
+ !BrowserThread::IsThreadInitialized(BrowserThread::UI));
+ if (is_observing_) {
+ proxy_config_service_->RemoveObserver(this);
+ }
+ pref_proxy_config_tracker_->DetachFromPrefService();
+}
+
+void ProxyConfigMessageHandler::RegisterMessages() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ web_ui()->RegisterMessageCallback(
+ "enableNotifyUIWithState",
+ base::BindRepeating(&ProxyConfigMessageHandler::OnEnableNotifyUIWithState,
+ base::Unretained(this)));
+ web_ui()->RegisterMessageCallback(
+ "apply",
+ base::BindRepeating(&ProxyConfigMessageHandler::OnApply,
+ base::Unretained(this)));
+ web_ui()->RegisterMessageCallback(
+ "clear",
+ base::BindRepeating(&ProxyConfigMessageHandler::OnClear,
+ base::Unretained(this)));
+}
+
+// The proxy configuration UI is not notified of state changes until this function runs.
+// After this function, OnProxyConfigChanged() will be called on all proxy state changes.
+void ProxyConfigMessageHandler::OnEnableNotifyUIWithState(
+ const base::ListValue& list) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ if (!is_observing_) {
+ is_observing_ = true;
+ proxy_config_service_->AddObserver(this);
+ }
+
+ net::ProxyConfigWithAnnotation config;
+ auto availability = proxy_config_service_->GetLatestProxyConfig(&config);
+
+ const PrefService::Preference* const pref =
+ pref_service_->FindPreference(proxy_config::prefs::kProxy);
+ ProxyConfigDictionary proxy_dict(pref->GetValue()->GetDict().Clone());
+ ProxyPrefs::ProxyMode mode;
+ if (!proxy_dict.GetMode(&mode) || mode == ProxyPrefs::MODE_SYSTEM) {
+ availability = net::ProxyConfigService::CONFIG_UNSET;
+ }
+
+ OnProxyConfigChanged(config, availability);
+}
+
+void ProxyConfigMessageHandler::OnClear(const base::ListValue& list) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ const base::DictValue cfg = ProxyConfigDictionary::CreateSystem();
+ pref_service_->SetDict(proxy_config::prefs::kProxy, cfg.Clone());
+ pref_service_->CommitPendingWrite();
+ OnEnableNotifyUIWithState(list);
+}
+
+void ProxyConfigMessageHandler::OnApply(const base::ListValue& list) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ if ((list.size() != 1) || !list[0].is_dict()) {
+ return;
+ }
+
+ const base::DictValue& config = list[0].GetDict();
+
+ if (config.FindBool("auto_detect").value_or(false)) {
+ apply(net::ProxyConfig::CreateAutoDetect());
+ return;
+ }
+
+ if (const std::string* pacURL = config.FindString("pac_url")) {
+ std::optional<bool> pacMandatory = config.FindBool("pac_mandatory");
+ auto proxyConfig = net::ProxyConfig::CreateFromCustomPacURL(
+ GURL(*pacURL));
+ proxyConfig.set_pac_mandatory(pacMandatory.value_or(false));
+ apply(proxyConfig);
+ return;
+ }
+
+ const base::DictValue* rules = config.FindDict("rules");
+ if (rules == nullptr)
+ return;
+
+ net::ProxyConfig proxyConfig;
+ bool readBypass = false;
+
+ const std::string* type = rules->FindString("type");
+ if (type == nullptr)
+ return;
+
+ if (*type == "list") {
+ const std::string* single_proxies = rules->FindString("single_proxies");
+ if (single_proxies == nullptr)
+ return;
+ proxyConfig.proxy_rules().type = net::ProxyConfig::ProxyRules::Type::PROXY_LIST;
+ proxyConfig.proxy_rules().single_proxies.SetFromPacString(*single_proxies);
+ readBypass = true;
+ } else if (*type == "list_per_scheme") {
+ const std::string* http = rules->FindString("proxies_for_http");
+ const std::string* https = rules->FindString("proxies_for_https");
+ const std::string* ftp = rules->FindString("proxies_for_ftp");
+ const std::string* fallback = rules->FindString("fallback_proxies");
+
+ proxyConfig.proxy_rules().type = net::ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME;
+ if (http)
+ proxyConfig.proxy_rules().proxies_for_http.SetFromPacString(*http);
+ if (https)
+ proxyConfig.proxy_rules().proxies_for_https.SetFromPacString(*https);
+ if (ftp)
+ proxyConfig.proxy_rules().proxies_for_ftp.SetFromPacString(*ftp);
+ if (fallback)
+ proxyConfig.proxy_rules().fallback_proxies.SetFromPacString(*fallback);
+ readBypass = true;
+ } else if (*type == "direct") {
+ proxyConfig.proxy_rules().type = net::ProxyConfig::ProxyRules::Type::EMPTY;
+ } else if (*type == "none") {
+ base::ListValue empty;
+ OnClear(empty);
+ return;
+ } else {
+ // invalid type
+ LOG(WARNING) << "invalid proxy configuration type";
+ return;
+ }
+
+ // bypass rules and reverse flag are common to both list types of proxy rules
+ if (readBypass) {
+ const std::string* bypass_rules = rules->FindString("bypass_rules");
+ if (bypass_rules == nullptr)
+ return;
+
+ std::optional<bool> reverse_bypass = rules->FindBool("reverse_bypass");
+
+ proxyConfig.proxy_rules().bypass_rules.ParseFromString(*bypass_rules);
+ proxyConfig.proxy_rules().reverse_bypass = reverse_bypass.value_or(false);
+ }
+
+ apply(proxyConfig);
+}
+
+void ProxyConfigMessageHandler::apply(const net::ProxyConfig& proxyConfig) {
+ if (proxyConfig.auto_detect()) {
+ const base::DictValue cfg = ProxyConfigDictionary::CreateAutoDetect();
+ pref_service_->SetDict(proxy_config::prefs::kProxy, cfg.Clone());
+ } else if (proxyConfig.has_pac_url()) {
+ const base::DictValue cfg = ProxyConfigDictionary::CreatePacScript(proxyConfig.pac_url().spec(), proxyConfig.pac_mandatory());
+ pref_service_->SetDict(proxy_config::prefs::kProxy, cfg.Clone());
+ } else if (proxyConfig.proxy_rules().type == net::ProxyConfig::ProxyRules::Type::EMPTY) {
+ const base::DictValue cfg = ProxyConfigDictionary::CreateDirect();
+ pref_service_->SetDict(proxy_config::prefs::kProxy, cfg.Clone());
+ } else {
+ auto proxyRulesAsString = proxyConfig.proxy_rules().ToString();
+ auto bypassRulesAsString = proxyConfig.proxy_rules().bypass_rules.ToString();
+
+ // fixed servers
+ const base::DictValue cfg = ProxyConfigDictionary::CreateFixedServers(proxyRulesAsString,
+ bypassRulesAsString, proxyConfig.proxy_rules().reverse_bypass);
+ pref_service_->SetDict(proxy_config::prefs::kProxy, cfg.Clone());
+ }
+ pref_service_->CommitPendingWrite();
+
+ base::ListValue empty;
+ OnEnableNotifyUIWithState(empty);
+}
+
+} // namespace
+
+ProxyConfigUI::ProxyConfigUI(content::WebUI* web_ui) : WebUIController(web_ui) {
+ Profile* profile = Profile::FromWebUI(web_ui);
+
+ web_ui->AddMessageHandler(std::make_unique<ProxyConfigMessageHandler>(profile));
+
+ // Set up the chrome://proxy/ source.
+ content::WebUIDataSource* source =
+ content::WebUIDataSource::CreateAndAdd(web_ui->GetWebContents()->GetBrowserContext(),
+ chrome::kChromeUIProxyConfigHost);
+
+ source->UseStringsJs();
+ source->AddResourcePath("proxy_config.js", IDR_PROXY_CONFIG_JS);
+ source->SetDefaultResource(IDR_PROXY_CONFIG_HTML);
+}
diff --git a/chrome/browser/ui/webui/proxy_config_ui.h b/chrome/browser/ui/webui/proxy_config_ui.h
new file mode 100644
--- /dev/null
+++ b/chrome/browser/ui/webui/proxy_config_ui.h
@@ -0,0 +1,41 @@
+/*
+ This file is part of Bromite.
+
+ Bromite is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Bromite is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Bromite. If not, see <https://www.gnu.org/licenses/>.
+*/
+
+#ifndef CHROME_BROWSER_UI_WEBUI_PROXY_CONFIG_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_PROXY_CONFIG_UI_H_
+
+#include "chrome/common/webui_url_constants.h"
+#include "content/public/browser/web_ui_controller.h"
+#include "content/public/browser/webui_config.h"
+
+// The WebUI for chrome://proxy/.
+class ProxyConfigUI : public content::WebUIController {
+ public:
+ ProxyConfigUI(const ProxyConfigUI&) = delete;
+ ProxyConfigUI& operator=(const ProxyConfigUI&) = delete;
+ explicit ProxyConfigUI(content::WebUI* web_ui);
+};
+
+class ProxyConfigUIConfig
+ : public content::DefaultWebUIConfig<ProxyConfigUI> {
+ public:
+ ProxyConfigUIConfig()
+ : DefaultWebUIConfig(content::kChromeUIScheme,
+ chrome::kChromeUIProxyConfigHost) {}
+};
+
+#endif // CHROME_BROWSER_UI_WEBUI_PROXY_CONFIG_UI_H_
diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc
--- a/chrome/common/webui_url_constants.cc
+++ b/chrome/common/webui_url_constants.cc
@@ -120,6 +120,7 @@ bool IsSystemWebUIHost(std::string_view host) {
// These hosts will also be suggested by BuiltinProvider.
base::span<const base::cstring_view> ChromeURLHosts() {
static constexpr auto kChromeURLHosts = std::to_array<base::cstring_view>({
+ kChromeUIProxyConfigHost,
kChromeUIAboutHost,
kChromeUIAccessibilityHost,
kChromeUIActorInternalsHost,
diff --git a/chrome/common/webui_url_constants.h b/chrome/common/webui_url_constants.h
--- a/chrome/common/webui_url_constants.h
+++ b/chrome/common/webui_url_constants.h
@@ -210,6 +210,8 @@ inline constexpr char kChromeUINetInternalsHost[] = "net-internals";
inline constexpr char kChromeUINetInternalsURL[] = "chrome://net-internals/";
inline constexpr char kChromeUINewTabHost[] = "newtab";
inline constexpr char kChromeUINewTabFooterHost[] = "newtab-footer";
+inline constexpr char16_t kChromeUIProxyConfigURL16[] = u"chrome://proxy/";
+inline constexpr char kChromeUIProxyConfigHost[] = "proxy";
inline constexpr char kChromeUINewTabPageHost[] = "new-tab-page";
inline constexpr char kChromeUINewTabPageThirdPartyHost[] =
"new-tab-page-third-party";
diff --git a/components/proxy_config/pref_proxy_config_tracker_impl.cc b/components/proxy_config/pref_proxy_config_tracker_impl.cc
--- a/components/proxy_config/pref_proxy_config_tracker_impl.cc
+++ b/components/proxy_config/pref_proxy_config_tracker_impl.cc
@@ -525,7 +525,7 @@ PrefProxyConfigTrackerImpl::GetEffectiveProxyConfig(
// static
void PrefProxyConfigTrackerImpl::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterDictionaryPref(proxy_config::prefs::kProxy,
- ProxyConfigDictionary::CreateSystem());
+ ProxyConfigDictionary::CreateDirect());
registry->RegisterListPref(proxy_config::prefs::kProxyOverrideRules);
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
registry->RegisterIntegerPref(
@@ -541,7 +541,7 @@ void PrefProxyConfigTrackerImpl::RegisterPrefs(PrefRegistrySimple* registry) {
void PrefProxyConfigTrackerImpl::RegisterProfilePrefs(
PrefRegistrySimple* registry) {
registry->RegisterDictionaryPref(proxy_config::prefs::kProxy,
- ProxyConfigDictionary::CreateSystem());
+ ProxyConfigDictionary::CreateDirect());
registry->RegisterBooleanPref(proxy_config::prefs::kUseSharedProxies, false);
registry->RegisterListPref(proxy_config::prefs::kProxyOverrideRules);
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
@@ -705,6 +705,7 @@ bool PrefProxyConfigTrackerImpl::PrefConfigToNetConfig(
if (proxy_dict.GetBypassList(&proxy_bypass)) {
proxy_config.proxy_rules().bypass_rules.ParseFromString(proxy_bypass);
}
+ proxy_config.proxy_rules().reverse_bypass = proxy_dict.HasReverseBypass();
*config = net::ProxyConfigWithAnnotation(
proxy_config, kSettingsProxyConfigTrafficAnnotation);
return true;
diff --git a/components/proxy_config/proxy_config_dictionary.cc b/components/proxy_config/proxy_config_dictionary.cc
--- a/components/proxy_config/proxy_config_dictionary.cc
+++ b/components/proxy_config/proxy_config_dictionary.cc
@@ -30,6 +30,8 @@ const char kProxyPacMandatory[] = "pac_mandatory";
// String containing proxy bypass rules. For a specification of the
// expected syntax see net::ProxyHostMatchingRules::ParseFromString().
const char kProxyBypassList[] = "bypass_list";
+// Boolean telling whether to reverse the meaning of the bypass list.
+const char kProxyReverseBypass[] = "reverse_bypass";
} // namespace
@@ -76,6 +78,14 @@ bool ProxyConfigDictionary::HasBypassList() const {
return dict_.Find(kProxyBypassList);
}
+bool ProxyConfigDictionary::HasReverseBypass() const {
+ const base::Value* value = dict_.Find(kProxyReverseBypass);
+ if (!value || !value->is_bool()) {
+ return false;
+ }
+ return value->GetBool();
+}
+
const base::DictValue& ProxyConfigDictionary::GetDictionary() const {
return dict_;
}
@@ -83,13 +93,13 @@ const base::DictValue& ProxyConfigDictionary::GetDictionary() const {
// static
base::DictValue ProxyConfigDictionary::CreateDirect() {
return CreateDictionary(ProxyPrefs::MODE_DIRECT, std::string(), false,
- std::string(), std::string());
+ std::string(), std::string(), false);
}
// static
base::DictValue ProxyConfigDictionary::CreateAutoDetect() {
return CreateDictionary(ProxyPrefs::MODE_AUTO_DETECT, std::string(), false,
- std::string(), std::string());
+ std::string(), std::string(), false);
}
// static
@@ -97,16 +107,17 @@ base::DictValue ProxyConfigDictionary::CreatePacScript(
const std::string& pac_url,
bool pac_mandatory) {
return CreateDictionary(ProxyPrefs::MODE_PAC_SCRIPT, pac_url, pac_mandatory,
- std::string(), std::string());
+ std::string(), std::string(), false);
}
// static
base::DictValue ProxyConfigDictionary::CreateFixedServers(
const std::string& proxy_server,
- const std::string& bypass_list) {
+ const std::string& bypass_list,
+ bool reverse_bypass) {
if (!proxy_server.empty()) {
return CreateDictionary(ProxyPrefs::MODE_FIXED_SERVERS, std::string(),
- false, proxy_server, bypass_list);
+ false, proxy_server, bypass_list, reverse_bypass);
} else {
return CreateDirect();
}
@@ -115,7 +126,7 @@ base::DictValue ProxyConfigDictionary::CreateFixedServers(
// static
base::DictValue ProxyConfigDictionary::CreateSystem() {
return CreateDictionary(ProxyPrefs::MODE_SYSTEM, std::string(), false,
- std::string(), std::string());
+ std::string(), std::string(), false);
}
// static
@@ -124,7 +135,8 @@ base::DictValue ProxyConfigDictionary::CreateDictionary(
const std::string& pac_url,
bool pac_mandatory,
const std::string& proxy_server,
- const std::string& bypass_list) {
+ const std::string& bypass_list,
+ bool reverse_bypass) {
base::DictValue dict;
dict.Set(kProxyMode, base::Value(ProxyModeToString(mode)));
if (!pac_url.empty()) {
@@ -133,8 +145,10 @@ base::DictValue ProxyConfigDictionary::CreateDictionary(
}
if (!proxy_server.empty())
dict.Set(kProxyServer, base::Value(proxy_server));
- if (!bypass_list.empty())
+ if (!bypass_list.empty()) {
dict.Set(kProxyBypassList, base::Value(bypass_list));
+ dict.Set(kProxyReverseBypass, base::Value(reverse_bypass));
+ }
return dict;
}
diff --git a/components/proxy_config/proxy_config_dictionary.h b/components/proxy_config/proxy_config_dictionary.h
--- a/components/proxy_config/proxy_config_dictionary.h
+++ b/components/proxy_config/proxy_config_dictionary.h
@@ -42,6 +42,7 @@ class PROXY_CONFIG_EXPORT ProxyConfigDictionary {
bool GetProxyServer(std::string* out) const;
bool GetBypassList(std::string* out) const;
bool HasBypassList() const;
+ bool HasReverseBypass() const;
const base::DictValue& GetDictionary() const;
@@ -50,7 +51,8 @@ class PROXY_CONFIG_EXPORT ProxyConfigDictionary {
static base::DictValue CreatePacScript(const std::string& pac_url,
bool pac_mandatory);
static base::DictValue CreateFixedServers(const std::string& proxy_server,
- const std::string& bypass_list);
+ const std::string& bypass_list,
+ bool reverse_bypass);
static base::DictValue CreateSystem();
// Encodes the proxy server as "<url-scheme>=<proxy-scheme>://<proxy>".
@@ -66,7 +68,8 @@ class PROXY_CONFIG_EXPORT ProxyConfigDictionary {
const std::string& pac_url,
bool pac_mandatory,
const std::string& proxy_server,
- const std::string& bypass_list);
+ const std::string& bypass_list,
+ bool reverse_bypass);
base::DictValue dict_;
};
diff --git a/components/proxy_config/proxy_policy_handler.cc b/components/proxy_config/proxy_policy_handler.cc
--- a/components/proxy_config/proxy_policy_handler.cc
+++ b/components/proxy_config/proxy_policy_handler.cc
@@ -378,7 +378,7 @@ void ProxyPolicyHandler::ApplyPolicySettings(const PolicyMap& policies,
set_proxy_pref_value(ProxyConfigDictionary::CreateFixedServers(
server->GetString(), bypass_list && bypass_list->is_string()
? bypass_list->GetString()
- : std::string()));
+ : std::string(), false));
}
break;
}
diff --git a/net/features.gni b/net/features.gni
--- a/net/features.gni
+++ b/net/features.gni
@@ -62,7 +62,7 @@ declare_args() {
# Bracketed URIs parsing is only available for debug builds.
# TODO(crbug.com/365771838): Ensure tests are updated if needed if this
# feature is changed at all.
- enable_bracketed_proxy_uris = is_debug
+ enable_bracketed_proxy_uris = true
# General QUIC proxy support is only available for debug builds.
# TODO(crbug.com/367400641): If flag is changed or removed, ensure all
diff --git a/net/proxy_resolution/pac_file_fetcher_impl.cc b/net/proxy_resolution/pac_file_fetcher_impl.cc
--- a/net/proxy_resolution/pac_file_fetcher_impl.cc
+++ b/net/proxy_resolution/pac_file_fetcher_impl.cc
@@ -364,14 +364,6 @@ bool PacFileFetcherImpl::ConsumeBytesRead(URLRequest* request, int num_bytes) {
return false;
}
- // Enforce maximum size bound.
- if (num_bytes + bytes_read_so_far_.size() >
- static_cast<size_t>(max_response_bytes_)) {
- result_code_ = ERR_FILE_TOO_BIG;
- request->Cancel();
- return false;
- }
-
bytes_read_so_far_.append(buf_->data(), num_bytes);
return true;
}
diff --git a/net/proxy_resolution/proxy_config.cc b/net/proxy_resolution/proxy_config.cc
--- a/net/proxy_resolution/proxy_config.cc
+++ b/net/proxy_resolution/proxy_config.cc
@@ -133,7 +133,7 @@ void ProxyConfig::ProxyRules::ParseFromString(std::string_view proxy_rules,
url_scheme, &single_proxies, ProxyServer::SCHEME_HTTP,
allow_bracketed_proxy_chains, is_quic_allowed);
type = Type::PROXY_LIST;
- return;
+ continue;
}
// Trim whitespace off the url scheme.
@@ -164,6 +164,57 @@ void ProxyConfig::ProxyRules::ParseFromString(std::string_view proxy_rules,
}
}
+std::string ProxyConfig::ProxyRules::ToString() const {
+ if (type == Type::PROXY_LIST) {
+ std::string proxy_list;
+ for (const auto& proxy_chain : single_proxies.AllChains()) {
+ if (proxy_chain.length()) {
+ net::ProxyServer proxy_server = proxy_chain.GetProxyServer(/*chain_index=*/0);
+ proxy_list += ProxyServerToProxyUri(proxy_server) + ";";
+ }
+ }
+ // remove last semicolon
+ if (proxy_list.length() != 0 ) {
+ proxy_list.pop_back();
+ }
+ return proxy_list;
+ } else if (type == Type::PROXY_LIST_PER_SCHEME) {
+ // start to build a per-scheme list
+ std::string list;
+ for (const auto& proxy_chain : proxies_for_http.AllChains()) {
+ if (proxy_chain.length()) {
+ net::ProxyServer proxy_server = proxy_chain.First();
+ list += "http=" + ProxyServerToProxyUri(proxy_server) + ";";
+ }
+ }
+ for (const auto& proxy_chain : proxies_for_https.AllChains()) {
+ if (proxy_chain.length()) {
+ net::ProxyServer proxy_server = proxy_chain.First();
+ list += "https=" + ProxyServerToProxyUri(proxy_server) + ";";
+ }
+ }
+ for (const auto& proxy_chain : proxies_for_ftp.AllChains()) {
+ if (proxy_chain.length()) {
+ net::ProxyServer proxy_server = proxy_chain.First();
+ list += "ftp=" + ProxyServerToProxyUri(proxy_server) + ";";
+ }
+ }
+ for (const auto& proxy_chain : fallback_proxies.AllChains()) {
+ if (proxy_chain.length()) {
+ net::ProxyServer proxy_server = proxy_chain.First();
+ list += "socks=" + ProxyServerToProxyUri(proxy_server) + ";";
+ }
+ }
+ if (list.length() != 0 ) {
+ // remove last semicolon
+ list.pop_back();
+ }
+ return list;
+ } else {
+ return "";
+ }
+}
+
const ProxyList* ProxyConfig::ProxyRules::MapUrlSchemeToProxyList(
const std::string& url_scheme) const {
const ProxyList* proxy_server_list =
diff --git a/net/proxy_resolution/proxy_config.h b/net/proxy_resolution/proxy_config.h
--- a/net/proxy_resolution/proxy_config.h
+++ b/net/proxy_resolution/proxy_config.h
@@ -106,6 +106,9 @@ class NET_EXPORT ProxyConfig {
void ParseFromString(std::string_view proxy_rules,
bool allow_bracketed_proxy_chains = false,
bool is_quic_allowed = false);
+ // Returns the proxy rules in a format that can be parsed by ParseFromString;
+ // all information except bypass rules is used.
+ std::string ToString() const;
// Returns one of {&proxies_for_http, &proxies_for_https, &proxies_for_ftp,
// &fallback_proxies}, or NULL if there is no proxy to use.
--