Explorar o código

Release 71.0.3578.88

csagan5 %!s(int64=6) %!d(string=hai) anos
pai
achega
65c50e3ec9

+ 5 - 0
CHANGELOG.md

@@ -1,4 +1,9 @@
+# 71.0.3578.88
+* add proxy configuration page (see https://github.com/bromite/bromite/wiki/ProxyConfiguration)
+* use more recent versions in User-Agent (fixes https://github.com/bromite/bromite/issues/156)
+
 # 71.0.3578.85
+* fix blurry adaptive icon (fixes https://github.com/bromite/bromite/issues/197)
 
 # 71.0.3578.76
 

+ 1 - 0
README.md

@@ -76,6 +76,7 @@ Yes, since version 69. While the desktop version of Chromium has an option to di
 * baked-in adblock engine with filters from EasyList, EasyPrivacy and others
 * remove click-tracking and AMP from search results
 * DNS-over-HTTPS support via Google, Cloudflare and Quad9 servers
+* [proxy configuration page](https://github.com/bromite/bromite/wiki/ProxyConfiguration) with PAC and custom proxy lists support
 * [StartPage](https://startpage.com/), [DuckDuckGo](https://duckduckgo.com/) and [Qwant](https://www.qwant.com/) search engines
 * chrome flags to disable custom intents and clear session on exit
 * always-incognito mode

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 115 - 12
filters/adblock_entries.h


+ 39 - 6
patches/BRM052_Bromite-adblock-engine.patch

@@ -18,12 +18,12 @@ New mechanism for adblocking based on Brave's adblocking hook
  .../browser/appmenu/AppMenuPropertiesDelegate.java |  38 +++
  .../CustomTabAppMenuPropertiesDelegate.java        |   2 +
  .../java/strings/android_chrome_strings.grd        |  11 +
- chrome/browser/net/chrome_network_delegate.cc      |  83 ++++--
+ chrome/browser/net/chrome_network_delegate.cc      |  83 +++--
  .../subresource_filter_content_settings_manager.cc |   1 +
  net/BUILD.gn                                       |   7 +
- net/url_request/adblock_intercept.cc               | 325 +++++++++++++++++++++
- net/url_request/adblock_intercept.h                |  24 ++
- 12 files changed, 510 insertions(+), 20 deletions(-)
+ net/url_request/adblock_intercept.cc               | 341 +++++++++++++++++++++
+ net/url_request/adblock_intercept.h                |  41 +++
+ 12 files changed, 543 insertions(+), 20 deletions(-)
  create mode 100644 net/url_request/adblock_intercept.cc
  create mode 100644 net/url_request/adblock_intercept.h
 
@@ -341,7 +341,23 @@ diff --git a/net/url_request/adblock_intercept.cc b/net/url_request/adblock_inte
 new file mode 100644
 --- /dev/null
 +++ b/net/url_request/adblock_intercept.cc
-@@ -0,0 +1,325 @@
+@@ -0,0 +1,341 @@
++/*
++    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 "url/gurl.h"
 +
 +#ifdef ADB_TESTER
@@ -671,7 +687,24 @@ diff --git a/net/url_request/adblock_intercept.h b/net/url_request/adblock_inter
 new file mode 100644
 --- /dev/null
 +++ b/net/url_request/adblock_intercept.h
-@@ -0,0 +1,24 @@
+@@ -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 NET_URL_REQUEST_ADBLOCK_INTERCEPT_H_
 +#define NET_URL_REQUEST_ADBLOCK_INTERCEPT_H_
 +

+ 24 - 28
patches/BRM053_User-Agent-anonymize.patch

@@ -2,16 +2,17 @@ From: csagan5 <32685696+csagan5@users.noreply.github.com>
 Date: Wed, 21 Mar 2018 14:15:28 +0100
 Subject: User Agent: anonymize
 
-Use a fixed device name and Chrome product version.
+Use a fixed device name and Chrome product version with the goal of not
+disclosing the specific build of Bromite.
 ---
- components/version_info/version_info.cc | 17 +++++++-
- content/common/user_agent.cc            | 73 +++++++++++++++++++++------------
- 2 files changed, 62 insertions(+), 28 deletions(-)
+ components/version_info/version_info.cc | 13 +++++-
+ content/common/user_agent.cc            | 72 ++++++++++++++++++++-------------
+ 2 files changed, 57 insertions(+), 28 deletions(-)
 
 diff --git a/components/version_info/version_info.cc b/components/version_info/version_info.cc
 --- a/components/version_info/version_info.cc
 +++ b/components/version_info/version_info.cc
-@@ -7,13 +7,28 @@
+@@ -7,13 +7,24 @@
  #include "base/logging.h"
  #include "base/no_destructor.h"
  #include "base/version.h"
@@ -28,16 +29,12 @@ diff --git a/components/version_info/version_info.cc b/components/version_info/v
 +                                               &minor,
 +                                               &bugfix);
 +  switch (major) {
-+    case 7:
-+      return "Chrome/63.0.3239.111";
-+    case 6:
-+      return "Chrome/63.0.3239.83";
-+    case 5:
 +    case 4:
-+      return "Chrome/62.0.3202.84";
++      return "Chrome/69.0.3497.100";
 +  }
-+  // version 8 and above
-+  return "Chrome/67.0.3396.87";
++
++  // version 5 and above
++  return "Chrome/70.0.3538.80";
  }
  
  std::string GetProductName() {
@@ -56,7 +53,7 @@ diff --git a/content/common/user_agent.cc b/content/common/user_agent.cc
  std::string GetWebKitVersion() {
    return base::StringPrintf("%d.%d (%s)",
                              WEBKIT_VERSION_MAJOR,
-@@ -66,7 +61,33 @@ std::string BuildOSCpuInfo(bool include_android_build_number) {
+@@ -66,7 +61,32 @@ std::string BuildOSCpuInfo(bool include_android_build_number) {
    }
  #elif defined(OS_ANDROID)
    std::string android_version_str = base::SysInfo::OperatingSystemVersion();
@@ -66,24 +63,23 @@ diff --git a/content/common/user_agent.cc b/content/common/user_agent.cc
 +  // Send information about the device and build ID.
 +  // Use a common device/build ID based on Android major version.
 +  switch (os_major_version) {
++    default: // version 9 and above
++      android_info_str = "ONEPLUS A6000";
++      break;
++    case 8:
++      android_info_str = "FIG-LX3";
++      break;
 +    case 7:
-+      // Chrome/63.0.3239.111
-+      android_info_str = "SM-J730GM Build/NRD90M";
++      android_info_str = "SM-G610M";
 +      break;
 +    case 6:
-+      // Chrome/63.0.3239.83
-+      android_info_str = "SM-G532G Build/MMB29T";
++      android_info_str = "SM-J700M";
 +      break;
 +    case 5:
-+      // Chrome/62.0.3202.84
-+      android_info_str = "A37fw Build/LMY47V";
++      android_info_str = "XT1033";
 +      break;
 +    case 4:
-+      // Chrome/62.0.3202.84
-+      android_info_str = "SM-G7102 Build/KOT49H";
-+      break;
-+    default: // version 8 and above
-+      android_info_str = "SM-G950U Build/R16NW";
++      android_info_str = "ZTE Blade C370 Build/KOT49H";
 +      break;
 +  }
 +
@@ -91,7 +87,7 @@ diff --git a/content/common/user_agent.cc b/content/common/user_agent.cc
  #elif (defined(OS_POSIX) && !defined(OS_MACOSX)) || defined(OS_FUCHSIA)
    // Should work on any Posix system.
    struct utsname unixinfo;
-@@ -102,7 +123,7 @@ std::string BuildOSCpuInfo(bool include_android_build_number) {
+@@ -102,7 +122,7 @@ std::string BuildOSCpuInfo(bool include_android_build_number) {
        os_minor_version,
        os_bugfix_version
  #elif defined(OS_ANDROID)
@@ -100,7 +96,7 @@ diff --git a/content/common/user_agent.cc b/content/common/user_agent.cc
        android_version_str.c_str(),
        android_info_str.c_str()
  #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
-@@ -137,18 +158,6 @@ std::string BuildUserAgentFromProduct(const std::string& product) {
+@@ -137,18 +157,6 @@ std::string BuildUserAgentFromProduct(const std::string& product) {
    return BuildUserAgentFromOSAndProduct(os_info, product);
  }
  
@@ -119,7 +115,7 @@ diff --git a/content/common/user_agent.cc b/content/common/user_agent.cc
  std::string GetAndroidOSInfo(bool include_android_build_number) {
    std::string android_info_str;
  
-@@ -162,18 +171,28 @@ std::string GetAndroidOSInfo(bool include_android_build_number) {
+@@ -162,18 +170,28 @@ std::string GetAndroidOSInfo(bool include_android_build_number) {
    }
  
    // Append the build ID.

+ 1213 - 0
patches/BRM102_Add-a-proxy-configuration-page.patch

@@ -0,0 +1,1213 @@
+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.
+---
+ chrome/android/java/res/values/values.xml          |   3 +
+ .../android/java/res/xml/privacy_preferences.xml   |   5 +
+ .../chrome_autocomplete_provider_client.cc         |   2 +
+ chrome/browser/browser_resources.grd               |   2 +
+ .../prefs/chrome_command_line_pref_store.cc        |   2 +-
+ chrome/browser/resources/proxy_config.css          |  61 ++++
+ chrome/browser/resources/proxy_config.html         |  78 ++++
+ chrome/browser/resources/proxy_config.js           | 252 +++++++++++++
+ chrome/browser/ui/BUILD.gn                         |   2 +
+ .../ui/webui/chrome_web_ui_controller_factory.cc   |   3 +
+ chrome/browser/ui/webui/proxy_config_ui.cc         | 399 +++++++++++++++++++++
+ chrome/browser/ui/webui/proxy_config_ui.h          |  33 ++
+ chrome/common/webui_url_constants.cc               |   4 +
+ chrome/common/webui_url_constants.h                |   2 +
+ .../policy/core/browser/proxy_policy_handler.cc    |   2 +-
+ components/proxy_config/proxy_config_dictionary.cc |  22 +-
+ components/proxy_config/proxy_config_dictionary.h  |   6 +-
+ net/proxy_resolution/proxy_config.cc               |  47 ++-
+ net/proxy_resolution/proxy_config.h                |   3 +
+ 19 files changed, 915 insertions(+), 13 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
+@@ -80,6 +80,9 @@
+     <integer name="list_item_level_selected">1</integer>
+     <integer name="list_item_level_incognito">2</integer>
+ 
++    <string name="proxy_title">Proxy configuration</string>
++    <string name="proxy_url">chrome://proxy</string>
++
+     <!-- Download InfoBar animation. -->
+     <integer name="download_infobar_sweep_up_delay">500</integer>
+     <integer name="download_infobar_sweep_down_delay">800</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
+@@ -5,8 +5,13 @@
+ 
+ <PreferenceScreen
+     xmlns:android="http://schemas.android.com/apk/res/android"
++    xmlns:app="http://schemas.android.com/apk/res-auto"
+     xmlns:tools="http://schemas.android.com/tools">
+ 
++    <org.chromium.chrome.browser.preferences.HyperlinkPreference
++        android:key="proxy"
++        android:title="@string/proxy_title"
++        app:url="@string/proxy_url" />
+     <org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference
+         android:key="navigation_error"
+         android:title="@string/navigation_error_title"
+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
+@@ -244,6 +244,8 @@ ChromeAutocompleteProviderClient::GetBuiltinsToProvideAsUserTypes() {
+   builtins_to_provide.push_back(
+       base::ASCIIToUTF16(chrome::kChromeUIFlagsURL));
+   builtins_to_provide.push_back(
++      base::ASCIIToUTF16(chrome::kChromeUIProxyConfigURL));
++  builtins_to_provide.push_back(
+       base::ASCIIToUTF16(chrome::kChromeUIChromeURLsURL));
+ #if !defined(OS_ANDROID)
+   builtins_to_provide.push_back(
+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
+@@ -228,6 +228,8 @@
+         <include name="IDR_SNIPPETS_INTERNALS_CSS" file="resources\snippets_internals\snippets_internals.css" compress="gzip" type="BINDATA" />
+         <include name="IDR_SNIPPETS_INTERNALS_JS" file="resources\snippets_internals\snippets_internals.js" compress="gzip" type="BINDATA" />
+         <include name="IDR_SNIPPETS_INTERNALS_MOJO_JS" file="${root_gen_dir}\chrome\browser\ui\webui\snippets_internals\snippets_internals.mojom.js" use_base_dir="false" type="BINDATA" compress="gzip" />
++        <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>
+       <include name="IDR_SUPERVISED_USER_INTERNALS_HTML" file="resources\supervised_user_internals.html" allowexternalscript="true" compress="gzip" type="BINDATA" />
+       <include name="IDR_SUPERVISED_USER_INTERNALS_CSS" file="resources\supervised_user_internals.css" compress="gzip" type="BINDATA" />
+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
+@@ -157,7 +157,7 @@ void ChromeCommandLinePrefStore::ApplyProxyMode() {
+     SetValue(
+         proxy_config::prefs::kProxy,
+         std::make_unique<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,78 @@
++<!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 src="chrome://resources/js/util.js"></script>
++<script src="chrome://resources/js/cr.js"></script>
++<script 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" checked><label for="empty">None</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,252 @@
++/*
++    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/>.
++*/
++
++/**
++ * 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 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';
++
++  /**
++   * @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');
++  }
++
++  cr.addSingletonGetter(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": "empty"
++          }
++        };
++    },
++
++    /**
++     * Serialize the user-selected configuration in an object.
++     */
++    serializeConfig_: function() {
++      if ($(kIdModeEmpty).checked) {
++        return {
++          "auto_detect": false,
++          "rules": {
++            "type": "empty"
++          }
++        };
++      } 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
++        };
++      } 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.rules.type == "empty")
++        $(kIdModeEmpty).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 {
++        $(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
+@@ -271,6 +271,8 @@ jumbo_split_static_library("ui") {
+     "webui/metrics_handler.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
+@@ -50,6 +50,7 @@
+ #include "chrome/browser/ui/webui/policy_tool_ui.h"
+ #include "chrome/browser/ui/webui/policy_ui.h"
+ #include "chrome/browser/ui/webui/predictors/predictors_ui.h"
++#include "chrome/browser/ui/webui/proxy_config_ui.h"
+ #include "chrome/browser/ui/webui/quota_internals/quota_internals_ui.h"
+ #include "chrome/browser/ui/webui/settings/md_settings_ui.h"
+ #include "chrome/browser/ui/webui/settings_utils.h"
+@@ -533,6 +534,8 @@ WebUIFactoryFunction GetWebUIFactoryFunction(WebUI* web_ui,
+     return &NewWebUI<SnippetsInternalsUI>;
+   if (url.host_piece() == chrome::kChromeUIWebApksHost)
+     return &NewWebUI<WebApksUI>;
++  if (url.host_piece() == chrome::kChromeUIProxyConfigHost)
++    return &NewWebUI<ProxyConfigUI>;
+ #else
+   if (url.SchemeIs(content::kChromeDevToolsScheme)) {
+     if (!DevToolsUIBindings::IsValidFrontendURL(url))
+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,399 @@
++/*
++    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/bind.h"
++#include "base/command_line.h"
++#include "base/lazy_instance.h"
++#include "base/macros.h"
++#include "base/memory/ref_counted.h"
++#include "base/scoped_observer.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/io_thread.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 {
++
++content::WebUIDataSource* CreateProxyConfigHTMLSource() {
++  content::WebUIDataSource* source =
++      content::WebUIDataSource::Create(chrome::kChromeUIProxyConfigHost);
++
++  source->SetJsonPath("strings.js");
++  source->AddResourcePath("proxy_config.js", IDR_PROXY_CONFIG_JS);
++  source->SetDefaultResource(IDR_PROXY_CONFIG_HTML);
++  source->UseGzip();
++  return source;
++}
++
++// 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<ProxyConfigMessageHandler>,
++      public net::ProxyConfigService::Observer {
++ public:
++  // 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* list);
++  void OnApply(const base::ListValue* config);
++  void OnClear(const base::ListValue* config);
++
++  // 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.
++  Profile *profile_;
++  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::DictionaryValue& state);
++
++  void apply(const net::ProxyConfig& config);
++
++  base::WeakPtrFactory<ProxyConfigMessageHandler> weak_ptr_factory_;
++
++  DISALLOW_COPY_AND_ASSIGN(ProxyConfigMessageHandler);
++};
++
++ProxyConfigMessageHandler::ProxyConfigMessageHandler(Profile *profile)
++    :
++      weak_ptr_factory_(this) {
++
++  // used to set new configuration preferences
++  profile_ = profile;
++  // 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_.reset(
++        ProxyServiceFactory::CreatePrefProxyConfigTrackerOfProfile(
++            profile->GetPrefs(), g_browser_process->local_state()));
++  }
++
++  proxy_config_service_ = ProxyServiceFactory::CreateProxyConfigService(
++      pref_proxy_config_tracker_.get());
++}
++
++void ProxyConfigMessageHandler::OnProxyConfigChanged(
++    const net::ProxyConfigWithAnnotation& config,
++    net::ProxyConfigService::ConfigAvailability availability) {
++  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
++         !BrowserThread::IsThreadInitialized(BrowserThread::UI));
++
++  base::DictionaryValue state;
++  bool pending = false;
++  switch (availability) {
++    case net::ProxyConfigService::CONFIG_VALID:
++      encodeConfig(config.value(), state);
++      break;
++    case net::ProxyConfigService::CONFIG_UNSET:
++      // nothing will be populated
++      break;
++    case net::ProxyConfigService::CONFIG_PENDING:
++      //NOTE: this can only happen when triggered manually first time
++      pending = true;
++      break;
++  }
++  state.SetKey("pending", base::Value(pending));
++
++  // call Javascript function
++  web_ui()->CallJavascriptFunctionUnsafe("ProxyConfigView.getInstance().onProxyConfigChanged",
++                                         *state.CreateDeepCopy());
++}
++
++const std::string omitDirect(const std::string pacString) {
++  if (pacString == "DIRECT") {
++    return "";
++  }
++  return pacString;
++}
++
++void ProxyConfigMessageHandler::encodeConfig(const net::ProxyConfig& config, base::DictionaryValue& 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.SetPath({"config", "auto_detect"}, base::Value(config.auto_detect()));
++
++  if (config.has_pac_url()) {
++    state.SetPath({"config", "pac_url"}, base::Value(config.pac_url().spec()));
++    state.SetPath({"config", "pac_mandatory"}, base::Value(config.pac_mandatory()));
++  }
++
++  auto rules = config.proxy_rules();
++  const char *type;
++  switch (rules.type) {
++    case net::ProxyConfig::ProxyRules::Type::EMPTY:
++      type = "empty";
++      break;
++    case net::ProxyConfig::ProxyRules::Type::PROXY_LIST:
++      type = "list";
++
++      state.SetPath({"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.SetPath({"config", "rules", "proxies_for_http"}, base::Value(omitDirect(rules.proxies_for_http.ToPacString())));
++      state.SetPath({"config", "rules", "proxies_for_https"}, base::Value(omitDirect(rules.proxies_for_https.ToPacString())));
++      state.SetPath({"config", "rules", "proxies_for_ftp"}, base::Value(omitDirect(rules.proxies_for_ftp.ToPacString())));
++      state.SetPath({"config", "rules", "fallback_proxies"}, base::Value(omitDirect(rules.fallback_proxies.ToPacString())));
++      break;
++    default:
++     NOTREACHED();
++     break;
++  }
++  state.SetPath({"config", "rules", "type"}, base::Value(type));
++  state.SetPath({"config", "rules", "bypass_rules"}, base::Value(rules.bypass_rules.ToString()));
++  state.SetPath({"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);
++  OnProxyConfigChanged(config, availability);
++}
++
++void ProxyConfigMessageHandler::OnClear(const base::ListValue* list) {
++  DCHECK_CURRENTLY_ON(BrowserThread::UI);
++
++  profile_->GetPrefs()->ClearPref(proxy_config::prefs::kProxy);
++}
++
++void ProxyConfigMessageHandler::OnApply(const base::ListValue* list) {
++  DCHECK_CURRENTLY_ON(BrowserThread::UI);
++
++  const base::Value::ListStorage& params = list->GetList();
++
++  if ((params.size() != 1) || !params[0].is_dict()) {
++    return;
++  }
++
++  const base::DictionaryValue* config = nullptr;
++  if (!list->GetDictionary(0, &config))
++    return;
++
++  const base::Value *autoDetect = config->FindKeyOfType("auto_detect", base::Value::Type::BOOLEAN);
++  if (autoDetect == nullptr)
++    return;
++
++  if (autoDetect->GetBool()) {
++    apply(net::ProxyConfig::CreateAutoDetect());
++    return;
++  }
++
++  const base::Value *pacURL = config->FindKeyOfType("pac_url", base::Value::Type::STRING);
++  if (pacURL != nullptr) {
++    const base::Value *pacMandatory = config->FindKeyOfType("pac_mandatory", base::Value::Type::BOOLEAN);
++    if (pacMandatory == nullptr)
++      return;
++    auto proxyConfig = net::ProxyConfig::CreateFromCustomPacURL(GURL(pacURL->GetString()));
++    proxyConfig.set_pac_mandatory(pacMandatory->GetBool());
++
++    apply(proxyConfig);
++    return;
++  }
++
++  const base::Value *rules = config->FindKeyOfType("rules", base::Value::Type::DICTIONARY);
++  if (rules == nullptr)
++    return;
++
++  const base::Value *type = rules->FindKeyOfType("type", base::Value::Type::STRING);
++  if (type == nullptr)
++    return;
++
++  net::ProxyConfig proxyConfig;
++
++  bool readBypass = false;
++
++  auto t = type->GetString();
++  if (t == "list") {
++      const base::Value *single_proxies = rules->FindKeyOfType("single_proxies", base::Value::Type::STRING);
++      if (single_proxies == nullptr)
++        return;
++      proxyConfig.proxy_rules().type = net::ProxyConfig::ProxyRules::Type::PROXY_LIST;
++      proxyConfig.proxy_rules().single_proxies.SetFromPacString(single_proxies->GetString());
++      readBypass = true;
++  } else if (t == "list_per_scheme") {
++      const base::Value *http = rules->FindKeyOfType("proxies_for_http", base::Value::Type::STRING);
++      if (http == nullptr)
++        return;
++
++      const base::Value *https = rules->FindKeyOfType("proxies_for_https", base::Value::Type::STRING);
++      if (https == nullptr)
++        return;
++
++      const base::Value *ftp = rules->FindKeyOfType("proxies_for_ftp", base::Value::Type::STRING);
++      if (ftp == nullptr)
++        return;
++
++      const base::Value *fallback = rules->FindKeyOfType("fallback_proxies", base::Value::Type::STRING);
++      if (fallback == nullptr)
++        return;
++
++      proxyConfig.proxy_rules().type = net::ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME;
++      proxyConfig.proxy_rules().proxies_for_http.SetFromPacString(http->GetString());
++      proxyConfig.proxy_rules().proxies_for_https.SetFromPacString(https->GetString());
++      proxyConfig.proxy_rules().proxies_for_ftp.SetFromPacString(ftp->GetString());
++      proxyConfig.proxy_rules().fallback_proxies.SetFromPacString(fallback->GetString());
++      readBypass = true;
++  } else if (t == "empty") {
++      proxyConfig.proxy_rules().type = net::ProxyConfig::ProxyRules::Type::EMPTY;
++  } 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 base::Value *bypass_rules = rules->FindKeyOfType("bypass_rules", base::Value::Type::STRING);
++    if (bypass_rules == nullptr)
++      return;
++
++    const base::Value *reverse_bypass = rules->FindKeyOfType("reverse_bypass", base::Value::Type::BOOLEAN);
++    if (reverse_bypass == nullptr)
++      return;
++
++    proxyConfig.proxy_rules().bypass_rules.ParseFromString(bypass_rules->GetString());
++    proxyConfig.proxy_rules().reverse_bypass = reverse_bypass->GetBool();
++  }
++
++  apply(proxyConfig);
++}
++
++void ProxyConfigMessageHandler::apply(const net::ProxyConfig& proxyConfig) {
++  if (proxyConfig.auto_detect()) {
++    const base::Value cfg = ProxyConfigDictionary::CreateAutoDetect();
++    profile_->GetPrefs()->Set(proxy_config::prefs::kProxy, cfg);
++    return;
++  } else if (proxyConfig.has_pac_url()) {
++    const base::Value cfg = ProxyConfigDictionary::CreatePacScript(proxyConfig.pac_url().spec(), proxyConfig.pac_mandatory());
++    profile_->GetPrefs()->Set(proxy_config::prefs::kProxy, cfg);
++    return;
++  }
++
++  auto proxyRulesAsString = proxyConfig.proxy_rules().ToString();
++  auto bypassRulesAsString = proxyConfig.proxy_rules().bypass_rules.ToString();
++
++  // fixed servers
++  const base::Value cfg = ProxyConfigDictionary::CreateFixedServers(proxyRulesAsString,
++                          bypassRulesAsString, proxyConfig.proxy_rules().reverse_bypass);
++  profile_->GetPrefs()->Set(proxy_config::prefs::kProxy, cfg);
++}
++
++}  // 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::Add(profile, CreateProxyConfigHTMLSource());
++}
+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,33 @@
++/*
++    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 "base/macros.h"
++#include "content/public/browser/web_ui_controller.h"
++
++// The WebUI for chrome://proxy/.
++class ProxyConfigUI : public content::WebUIController {
++ public:
++  explicit ProxyConfigUI(content::WebUI* web_ui);
++
++ private:
++  DISALLOW_COPY_AND_ASSIGN(ProxyConfigUI);
++};
++
++#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
+@@ -185,6 +185,8 @@ const char kChromeUINativePhysicalWebDiagnosticsURL[] =
+ const char kChromeUINativeScheme[] = "chrome-native";
+ const char kChromeUIOfflineInternalsHost[] = "offline-internals";
+ const char kChromeUIPhysicalWebDiagnosticsHost[] = "physical-web-diagnostics";
++const char kChromeUIProxyConfigHost[] = "proxy";
++const char kChromeUIProxyConfigURL[] = "chrome://proxy/";
+ const char kChromeUISnippetsInternalsHost[] = "snippets-internals";
+ const char kChromeUIWebApksHost[] = "webapks";
+ #endif
+@@ -345,6 +347,7 @@ const char* const kChromeHostURLs[] = {
+     kChromeUIPasswordManagerInternalsHost,
+     kChromeUIPolicyHost,
+     kChromeUIPredictorsHost,
++    kChromeUIProxyConfigHost,
+     kChromeUIQuotaInternalsHost,
+     kChromeUISignInInternalsHost,
+     kChromeUISiteEngagementHost,
+@@ -379,6 +382,7 @@ const char* const kChromeHostURLs[] = {
+ #if !defined(OS_ANDROID)
+ #if !defined(OS_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
+@@ -105,6 +105,8 @@ extern const char kChromeUIMemoryInternalsHost[];
+ extern const char kChromeUINTPTilesInternalsHost[];
+ extern const char kChromeUINaClHost[];
+ extern const char kChromeUINetExportHost[];
++extern const char kChromeUIProxyConfigHost[];
++extern const char kChromeUIProxyConfigURL[];
+ extern const char kChromeUINetInternalsHost[];
+ extern const char kChromeUINetInternalsURL[];
+ extern const char kChromeUINewTabHost[];
+diff --git a/components/policy/core/browser/proxy_policy_handler.cc b/components/policy/core/browser/proxy_policy_handler.cc
+--- a/components/policy/core/browser/proxy_policy_handler.cc
++++ b/components/policy/core/browser/proxy_policy_handler.cc
+@@ -203,7 +203,7 @@ void ProxyPolicyHandler::ApplyPolicySettings(const PolicyMap& policies,
+         prefs->SetValue(proxy_config::prefs::kProxy,
+                         std::make_unique<base::Value>(
+                             ProxyConfigDictionary::CreateFixedServers(
+-                                proxy_server, bypass_list_string)));
++                                proxy_server, bypass_list_string, false)));
+       }
+       break;
+     }
+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
+@@ -28,6 +28,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
+ 
+@@ -79,29 +81,30 @@ const base::Value& ProxyConfigDictionary::GetDictionary() const {
+ // static
+ base::Value ProxyConfigDictionary::CreateDirect() {
+   return CreateDictionary(ProxyPrefs::MODE_DIRECT, std::string(), false,
+-                          std::string(), std::string());
++                          std::string(), std::string(), false);
+ }
+ 
+ // static
+ base::Value ProxyConfigDictionary::CreateAutoDetect() {
+   return CreateDictionary(ProxyPrefs::MODE_AUTO_DETECT, std::string(), false,
+-                          std::string(), std::string());
++                          std::string(), std::string(), false);
+ }
+ 
+ // static
+ base::Value 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 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();
+   }
+@@ -110,7 +113,7 @@ base::Value ProxyConfigDictionary::CreateFixedServers(
+ // static
+ base::Value ProxyConfigDictionary::CreateSystem() {
+   return CreateDictionary(ProxyPrefs::MODE_SYSTEM, std::string(), false,
+-                          std::string(), std::string());
++                          std::string(), std::string(), false);
+ }
+ 
+ // static
+@@ -119,7 +122,8 @@ base::Value 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(base::Value::Type::DICTIONARY);
+   dict.SetKey(kProxyMode, base::Value(ProxyModeToString(mode)));
+   if (!pac_url.empty()) {
+@@ -128,8 +132,10 @@ base::Value ProxyConfigDictionary::CreateDictionary(
+   }
+   if (!proxy_server.empty())
+     dict.SetKey(kProxyServer, base::Value(proxy_server));
+-  if (!bypass_list.empty())
++  if (!bypass_list.empty()) {
+     dict.SetKey(kProxyBypassList, base::Value(bypass_list));
++    dict.SetKey(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
+@@ -46,7 +46,8 @@ class PROXY_CONFIG_EXPORT ProxyConfigDictionary {
+   static base::Value CreatePacScript(const std::string& pac_url,
+                                      bool pac_mandatory);
+   static base::Value CreateFixedServers(const std::string& proxy_server,
+-                                        const std::string& bypass_list);
++                                        const std::string& bypass_list,
++                                        bool reverse_bypass);
+   static base::Value CreateSystem();
+ 
+   // Encodes the proxy server as "<url-scheme>=<proxy-scheme>://<proxy>".
+@@ -62,7 +63,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_;
+ 
+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
+@@ -143,6 +143,51 @@ 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 server specified
++  if (type == Type::PROXY_LIST) {
++    if (single_proxies.size() == 1) {
++      return single_proxies.Get().ToURI();
++    }
++    // more than 1 proxies or 0 proxies is unexpected
++    return "";
++  }
++
++  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=" + proxy_server.ToURI() + ";";
++  }
++  for (const ProxyServer& proxy_server :
++       proxies_for_https.GetAll()) {
++    list += "https=" + proxy_server.ToURI() + ";";
++  }
++  for (const ProxyServer& proxy_server :
++       proxies_for_ftp.GetAll()) {
++    list += "ftp=" + proxy_server.ToURI() + ";";
++  }
++  for (const ProxyServer& proxy_server :
++       fallback_proxies.GetAll()) {
++    list += "socks=" + proxy_server.ToURI() + ";";
++  }
++  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<ProxyRules*>(this)->
+@@ -270,4 +315,4 @@ std::unique_ptr<base::DictionaryValue> ProxyConfig::ToValue() const {
+   return dict;
+ }
+ 
+-}  // namespace net
+\ No newline at end of file
++}  // namespace net
+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
+@@ -104,6 +104,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.11.0
+

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio