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.
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 | 2 +
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 +
.../webui/chrome_web_ui_controller_factory.cc | 3 +
chrome/browser/ui/webui/proxy_config_ui.cc | 393 ++++++++++++++++++
chrome/browser/ui/webui/proxy_config_ui.h | 31 ++
chrome/common/webui_url_constants.cc | 4 +
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/proxy_resolution/proxy_config.cc | 52 ++-
net/proxy_resolution/proxy_config.h | 3 +
25 files changed, 981 insertions(+), 17 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
@@ -27,6 +27,9 @@ found in the LICENSE file.
true
+ Proxy configuration
+ chrome://proxy
+
1200200
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
@@ -9,6 +9,10 @@ found in the LICENSE file.
+
+
+
+
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
@@ -388,7 +388,7 @@ absl::optional CreateProxyConfigDict(
return absl::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
+#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_ASH)
#include "chromeos/ash/components/network/proxy/proxy_config_service_impl.h"
@@ -70,7 +74,20 @@ ProxyServiceFactory::CreatePrefProxyConfigTrackerOfProfile(
return std::make_unique(
profile_prefs, local_state_prefs, nullptr);
#else
- return std::make_unique(profile_prefs, nullptr);
+ // Migrate from profile_prefs to local_state_prefs
+ if (local_state_prefs->GetBoolean("proxy_migrated") == false) {
+ const base::Value::Dict& 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(local_state_prefs, nullptr);
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
}
@@ -86,3 +103,8 @@ ProxyServiceFactory::CreatePrefProxyConfigTrackerOfLocalState(
nullptr);
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
}
+
+// 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
+#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
@@ -185,6 +185,8 @@
#include "rlz/buildflags/buildflags.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "chrome/browser/net/proxy_service_factory.h"
+
#if BUILDFLAG(ENABLE_BACKGROUND_MODE)
#include "chrome/browser/background/background_mode_manager.h"
#endif
@@ -1389,6 +1391,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
@@ -156,7 +156,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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Proxy configuration
+
+
+
+
+
+
Proxy configuration
+ Loading...
+
+
+
+
+
Proxy configuration
+
+
+ Reset will update the displayed configuration to match the one currently in use.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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.
+
+
+
+
+
+
+
+ Clicking on Clear will remove any proxy configuration preference currently in effect.
+
+
+
+
+
+
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 .
+*/
+
+import {$} from 'chrome://resources/js/util_ts.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
@@ -301,6 +301,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_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -63,6 +63,7 @@
#include "chrome/browser/ui/webui/ntp_tiles_internals_ui.h"
#include "chrome/browser/ui/webui/omnibox/omnibox_ui.h"
#include "chrome/browser/ui/webui/policy/policy_ui.h"
+#include "chrome/browser/ui/webui/proxy_config_ui.h"
#include "chrome/browser/ui/webui/predictors/predictors_ui.h"
#include "chrome/browser/ui/webui/segmentation_internals/segmentation_internals_ui.h"
#include "chrome/browser/ui/webui/signin_internals_ui.h"
@@ -496,6 +497,8 @@ WebUIFactoryFunction GetWebUIFactoryFunction(WebUI* web_ui,
return &NewWebUI;
if (url.host_piece() == chrome::kChromeUINetExportHost)
return &NewWebUI;
+ if (url.host_piece() == chrome::kChromeUIProxyConfigHost)
+ return &NewWebUI;
if (url.host_piece() == chrome::kChromeUINetInternalsHost)
return &NewWebUI;
if (url.host_piece() == chrome::kChromeUINTPTilesInternalsHost)
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,393 @@
+/*
+ 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 .
+*/
+
+#include "chrome/browser/ui/webui/proxy_config_ui.h"
+
+#include
+
+#include
+#include
+#include
+
+#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 base::SupportsWeakPtr,
+ 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::Value::List& args);
+ void OnApply(const base::Value::List& args);
+ void OnClear(const base::Value::List& 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 pref_service_;
+ std::unique_ptr proxy_config_service_;
+ // Monitors global and Profile prefs related to proxy configuration.
+ std::unique_ptr pref_proxy_config_tracker_;
+ bool is_observing_;
+
+ void encodeConfig(const net::ProxyConfig& config, base::Value::Dict& state);
+
+ void apply(const net::ProxyConfig& config);
+
+ base::WeakPtrFactory weak_ptr_factory_;
+};
+
+ProxyConfigMessageHandler::ProxyConfigMessageHandler(Profile *profile)
+ :
+ weak_ptr_factory_(this) {
+
+ // 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::Value::Dict 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::Value::Dict& 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();
+ break;
+ }
+ 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::Value::List& 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::Value::List& list) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ const base::Value::Dict cfg = ProxyConfigDictionary::CreateSystem();
+ pref_service_->SetDict(proxy_config::prefs::kProxy, cfg.Clone());
+ pref_service_->CommitPendingWrite();
+ OnEnableNotifyUIWithState(list);
+}
+
+void ProxyConfigMessageHandler::OnApply(const base::Value::List& list) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ if ((list.size() != 1) || !list[0].is_dict()) {
+ return;
+ }
+
+ const base::Value::Dict& 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")) {
+ absl::optional 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::Value::Dict* 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::Value::List 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;
+
+ absl::optional 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::Value::Dict cfg = ProxyConfigDictionary::CreateAutoDetect();
+ pref_service_->SetDict(proxy_config::prefs::kProxy, cfg.Clone());
+ } else if (proxyConfig.has_pac_url()) {
+ const base::Value::Dict 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::Value::Dict 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::Value::Dict cfg = ProxyConfigDictionary::CreateFixedServers(proxyRulesAsString,
+ bypassRulesAsString, proxyConfig.proxy_rules().reverse_bypass);
+ pref_service_->SetDict(proxy_config::prefs::kProxy, cfg.Clone());
+ }
+ pref_service_->CommitPendingWrite();
+
+ base::Value::List 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(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,31 @@
+/*
+ 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 .
+*/
+
+#ifndef CHROME_BROWSER_UI_WEBUI_PROXY_CONFIG_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_PROXY_CONFIG_UI_H_
+
+#include "content/public/browser/web_ui_controller.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);
+};
+
+#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
@@ -56,6 +56,8 @@ const char kChromeUICertificateViewerHost[] = "view-cert";
const char kChromeUICertificateViewerURL[] = "chrome://view-cert/";
const char kChromeUIChromeSigninHost[] = "chrome-signin";
const char kChromeUIChromeSigninURL[] = "chrome://chrome-signin/";
+const char kChromeUIProxyConfigHost[] = "proxy";
+const char kChromeUIProxyConfigURL[] = "chrome://proxy/";
const char kChromeUIChromeURLsHost[] = "chrome-urls";
const char kChromeUIChromeURLsURL[] = "chrome://chrome-urls/";
const char kChromeUIComponentsHost[] = "components";
@@ -450,6 +452,7 @@ bool IsSystemWebUIHost(base::StringPiece host) {
kChromeUILockScreenNetworkHost,
kChromeUILockScreenStartReauthHost,
kChromeUIMobileSetupHost,
+ kChromeUIProxyConfigHost,
kChromeUIMultiDeviceSetupHost,
kChromeUINetworkHost,
kChromeUINotificationTesterHost,
@@ -759,6 +762,7 @@ const char* const kChromeHostURLs[] = {
#if !BUILDFLAG(IS_ANDROID)
#if !BUILDFLAG(IS_CHROMEOS)
kChromeUIAppLauncherPageHost,
+ kChromeUIProxyConfigHost,
#endif
kChromeUIBookmarksHost,
kChromeUIDownloadsHost,
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
@@ -142,6 +142,8 @@ extern const char kChromeUINTPTilesInternalsHost[];
extern const char kChromeUINaClHost[];
extern const char kChromeUINetExportHost[];
extern const char kChromeUINetExportURL[];
+extern const char kChromeUIProxyConfigHost[];
+extern const char kChromeUIProxyConfigURL[];
extern const char kChromeUINetInternalsHost[];
extern const char kChromeUINetInternalsURL[];
extern const char kChromeUINewTabHost[];
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
@@ -244,14 +244,14 @@ PrefProxyConfigTrackerImpl::GetEffectiveProxyConfig(
// static
void PrefProxyConfigTrackerImpl::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterDictionaryPref(proxy_config::prefs::kProxy,
- ProxyConfigDictionary::CreateSystem());
+ ProxyConfigDictionary::CreateDirect());
}
// static
void PrefProxyConfigTrackerImpl::RegisterProfilePrefs(
PrefRegistrySimple* registry) {
registry->RegisterDictionaryPref(proxy_config::prefs::kProxy,
- ProxyConfigDictionary::CreateSystem());
+ ProxyConfigDictionary::CreateDirect());
registry->RegisterBooleanPref(proxy_config::prefs::kUseSharedProxies, false);
}
@@ -388,6 +388,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::ProxyBypassRules::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::Value::Dict& ProxyConfigDictionary::GetDictionary() const {
return dict_;
}
@@ -83,13 +93,13 @@ const base::Value::Dict& ProxyConfigDictionary::GetDictionary() const {
// static
base::Value::Dict ProxyConfigDictionary::CreateDirect() {
return CreateDictionary(ProxyPrefs::MODE_DIRECT, std::string(), false,
- std::string(), std::string());
+ std::string(), std::string(), false);
}
// static
base::Value::Dict 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::Value::Dict 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::Value::Dict 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::Value::Dict ProxyConfigDictionary::CreateFixedServers(
// static
base::Value::Dict 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::Value::Dict 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::Value::Dict dict;
dict.Set(kProxyMode, base::Value(ProxyModeToString(mode)));
if (!pac_url.empty()) {
@@ -133,8 +145,10 @@ base::Value::Dict 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::Value::Dict& GetDictionary() const;
@@ -50,7 +51,8 @@ class PROXY_CONFIG_EXPORT ProxyConfigDictionary {
static base::Value::Dict CreatePacScript(const std::string& pac_url,
bool pac_mandatory);
static base::Value::Dict CreateFixedServers(const std::string& proxy_server,
- const std::string& bypass_list);
+ const std::string& bypass_list,
+ bool reverse_bypass);
static base::Value::Dict CreateSystem();
// Encodes the proxy server as "=://".
@@ -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::Value::Dict 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
@@ -262,7 +262,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/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
@@ -112,7 +112,7 @@ void ProxyConfig::ProxyRules::ParseFromString(const std::string& proxy_rules) {
&single_proxies,
ProxyServer::SCHEME_HTTP);
type = Type::PROXY_LIST;
- return;
+ continue;
}
// Trim whitespace off the url scheme.
@@ -143,6 +143,56 @@ void ProxyConfig::ProxyRules::ParseFromString(const std::string& proxy_rules) {
}
}
+std::string ProxyConfig::ProxyRules::ToString() const {
+ if (type == Type::EMPTY) {
+ return "";
+ }
+
+ // special case: a single proxy servers list specified
+ if (type == Type::PROXY_LIST) {
+ std::string proxy_list;
+ for (const ProxyServer& proxy_server :
+ single_proxies.GetAll()) {
+ proxy_list += ProxyServerToProxyUri(proxy_server) + ";";
+ }
+ // remove last semicolon
+ if (proxy_list.length() != 0 ) {
+ proxy_list.pop_back();
+ }
+ return proxy_list;
+ }
+
+ if (type != Type::PROXY_LIST_PER_SCHEME) {
+ NOTREACHED();
+ // Unexpected LIST with fallback, or other type values
+ return "";
+ }
+
+ // start to build a per-scheme list
+ std::string list;
+ for (const ProxyServer& proxy_server :
+ proxies_for_http.GetAll()) {
+ list += "http=" + ProxyServerToProxyUri(proxy_server) + ";";
+ }
+ for (const ProxyServer& proxy_server :
+ proxies_for_https.GetAll()) {
+ list += "https=" + ProxyServerToProxyUri(proxy_server) + ";";
+ }
+ for (const ProxyServer& proxy_server :
+ proxies_for_ftp.GetAll()) {
+ list += "ftp=" + ProxyServerToProxyUri(proxy_server) + ";";
+ }
+ for (const ProxyServer& proxy_server :
+ fallback_proxies.GetAll()) {
+ list += "socks=" + ProxyServerToProxyUri(proxy_server) + ";";
+ }
+ if (list.length() != 0 ) {
+ // remove last semicolon
+ list.pop_back();
+ }
+ return list;
+}
+
const ProxyList* ProxyConfig::ProxyRules::MapUrlSchemeToProxyList(
const std::string& url_scheme) const {
const ProxyList* proxy_server_list = const_cast(this)->
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
@@ -103,6 +103,9 @@ class NET_EXPORT ProxyConfig {
// and use socks4://foopy2 for all other
// URLs.
void ParseFromString(const std::string& proxy_rules);
+ // 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.
--
2.25.1