Add-a-proxy-configuration-page.patch 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399
  1. From: csagan5 <32685696+csagan5@users.noreply.github.com>
  2. Date: Thu, 29 Mar 2018 00:43:32 +0200
  3. Subject: Add a proxy configuration page
  4. Accessible from proxy settings and chrome://proxy
  5. Allows to use a PAC script URL, automatic configuration and explicit proxy
  6. settings.
  7. Offer auto-complete for the proxy page URL.
  8. Store proxy settings in LocalState instead of Profile, so that proxy is used
  9. for SimpleURLLoaders as well.
  10. License: GPL-3.0-only - https://spdx.org/licenses/GPL-3.0-only.html
  11. ---
  12. chrome/android/java/res/values/values.xml | 3 +
  13. .../java/res/xml/privacy_preferences.xml | 4 +
  14. .../privacy/settings/PrivacySettings.java | 1 +
  15. .../chrome_autocomplete_provider_client.cc | 2 +
  16. chrome/browser/browser_resources.grd | 6 +
  17. chrome/browser/net/proxy_service_factory.cc | 24 +-
  18. chrome/browser/net/proxy_service_factory.h | 3 +
  19. chrome/browser/prefs/browser_prefs.cc | 4 +
  20. .../prefs/chrome_command_line_pref_store.cc | 2 +-
  21. chrome/browser/resources/proxy_config.css | 61 +++
  22. chrome/browser/resources/proxy_config.html | 79 ++++
  23. chrome/browser/resources/proxy_config.js | 266 +++++++++++
  24. chrome/browser/ui/BUILD.gn | 2 +
  25. .../webui/chrome_web_ui_controller_factory.cc | 3 +
  26. chrome/browser/ui/webui/proxy_config_ui.cc | 418 ++++++++++++++++++
  27. chrome/browser/ui/webui/proxy_config_ui.h | 31 ++
  28. chrome/common/webui_url_constants.cc | 4 +
  29. chrome/common/webui_url_constants.h | 2 +
  30. .../pref_proxy_config_tracker_impl.cc | 1 +
  31. .../proxy_config/proxy_config_dictionary.cc | 30 +-
  32. .../proxy_config/proxy_config_dictionary.h | 7 +-
  33. .../proxy_config/proxy_policy_handler.cc | 2 +-
  34. net/proxy_resolution/proxy_config.cc | 52 ++-
  35. net/proxy_resolution/proxy_config.h | 3 +
  36. 24 files changed, 996 insertions(+), 14 deletions(-)
  37. create mode 100644 chrome/browser/resources/proxy_config.css
  38. create mode 100644 chrome/browser/resources/proxy_config.html
  39. create mode 100644 chrome/browser/resources/proxy_config.js
  40. create mode 100644 chrome/browser/ui/webui/proxy_config_ui.cc
  41. create mode 100644 chrome/browser/ui/webui/proxy_config_ui.h
  42. diff --git a/chrome/android/java/res/values/values.xml b/chrome/android/java/res/values/values.xml
  43. --- a/chrome/android/java/res/values/values.xml
  44. +++ b/chrome/android/java/res/values/values.xml
  45. @@ -25,6 +25,9 @@
  46. <!-- Compositor Tab Title Text -->
  47. <bool name="compositor_tab_title_fake_bold_text">true</bool>
  48. + <string name="proxy_title">Proxy configuration</string>
  49. + <string name="proxy_url">chrome://proxy</string>
  50. +
  51. <!-- Download InfoBar animation. -->
  52. <integer name="download_infobar_fill_in_delay">1200</integer>
  53. <integer name="download_infobar_fill_out_delay">200</integer>
  54. diff --git a/chrome/android/java/res/xml/privacy_preferences.xml b/chrome/android/java/res/xml/privacy_preferences.xml
  55. --- a/chrome/android/java/res/xml/privacy_preferences.xml
  56. +++ b/chrome/android/java/res/xml/privacy_preferences.xml
  57. @@ -6,6 +6,10 @@
  58. <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
  59. xmlns:app="http://schemas.android.com/apk/res-auto">
  60. + <org.chromium.chrome.browser.about_settings.HyperlinkPreference
  61. + android:key="proxy"
  62. + android:title="@string/proxy_title"
  63. + app:url="@string/proxy_url" />
  64. <Preference
  65. android:key="clear_browsing_data"
  66. android:title="@string/clear_browsing_data_title"
  67. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettings.java b/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettings.java
  68. --- a/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettings.java
  69. +++ b/chrome/android/java/src/org/chromium/chrome/browser/privacy/settings/PrivacySettings.java
  70. @@ -57,6 +57,7 @@ public class PrivacySettings
  71. private static final String PREF_DO_NOT_TRACK = "do_not_track";
  72. private static final String PREF_CLEAR_BROWSING_DATA = "clear_browsing_data";
  73. private static final String PREF_PRIVACY_SANDBOX = "privacy_sandbox";
  74. + private static final String PREF_PROXY_OPTIONS = "proxy";
  75. private static final String PREF_PRIVACY_REVIEW = "privacy_review";
  76. private static final String PREF_INCOGNITO_LOCK = "incognito_lock";
  77. diff --git a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
  78. --- a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
  79. +++ b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
  80. @@ -277,6 +277,8 @@ ChromeAutocompleteProviderClient::GetBuiltinsToProvideAsUserTypes() {
  81. builtins_to_provide.push_back(
  82. base::ASCIIToUTF16(chrome::kChromeUISettingsURL));
  83. #endif
  84. + builtins_to_provide.push_back(
  85. + base::ASCIIToUTF16(chrome::kChromeUIProxyConfigURL));
  86. builtins_to_provide.push_back(
  87. base::ASCIIToUTF16(chrome::kChromeUIVersionURL));
  88. return builtins_to_provide;
  89. diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
  90. --- a/chrome/browser/browser_resources.grd
  91. +++ b/chrome/browser/browser_resources.grd
  92. @@ -79,6 +79,12 @@
  93. <include name="IDR_CONTACT_CENTER_INSIGHTS_MANIFEST" file="resources\chromeos\contact_center_insights\manifest.json" type="BINDATA" />
  94. </if>
  95. + <!-- Bromite Proxy Configuration UI -->
  96. + <if expr="is_android">
  97. + <include name="IDR_PROXY_CONFIG_HTML" file="resources\proxy_config.html" flattenhtml="true" type="BINDATA" compress="gzip" />
  98. + <include name="IDR_PROXY_CONFIG_JS" file="resources\proxy_config.js" type="BINDATA" compress="gzip" />
  99. + </if>
  100. +
  101. <if expr="not is_android">
  102. <!-- Page not available for guest. -->
  103. <include name="IDR_PAGE_NOT_AVAILABLE_FOR_GUEST_APP_HTML" file="resources\page_not_available_for_guest\app.html" type="BINDATA" />
  104. diff --git a/chrome/browser/net/proxy_service_factory.cc b/chrome/browser/net/proxy_service_factory.cc
  105. --- a/chrome/browser/net/proxy_service_factory.cc
  106. +++ b/chrome/browser/net/proxy_service_factory.cc
  107. @@ -6,6 +6,7 @@
  108. #include <utility>
  109. +#include "base/logging.h"
  110. #include "base/threading/thread_task_runner_handle.h"
  111. #include "build/build_config.h"
  112. #include "build/chromeos_buildflags.h"
  113. @@ -14,6 +15,9 @@
  114. #include "content/public/browser/browser_thread.h"
  115. #include "net/proxy_resolution/configured_proxy_resolution_service.h"
  116. #include "net/proxy_resolution/proxy_config_service.h"
  117. +#include "components/proxy_config/proxy_config_pref_names.h"
  118. +#include "components/prefs/pref_service.h"
  119. +#include "components/prefs/pref_registry_simple.h"
  120. #if BUILDFLAG(IS_CHROMEOS_ASH)
  121. #include "chromeos/network/proxy/proxy_config_service_impl.h"
  122. @@ -72,7 +76,20 @@ ProxyServiceFactory::CreatePrefProxyConfigTrackerOfProfile(
  123. return std::make_unique<chromeos::ProxyConfigServiceImpl>(
  124. profile_prefs, local_state_prefs, nullptr);
  125. #else
  126. - return std::make_unique<PrefProxyConfigTrackerImpl>(profile_prefs, nullptr);
  127. + // Migrate from profile_prefs to local_state_prefs
  128. + if (local_state_prefs->GetBoolean("proxy_migrated") == false) {
  129. + const base::Value* dict =
  130. + profile_prefs->GetDictionary(proxy_config::prefs::kProxy);
  131. +
  132. + LOG(INFO) << "CreatePrefProxyConfigTrackerOfProfile: Migration from profile to local state";
  133. +
  134. + const base::Value /*ProxyConfigDictionary*/ proxy_dict(dict->Clone());
  135. + local_state_prefs->Set(proxy_config::prefs::kProxy, proxy_dict);
  136. +
  137. + local_state_prefs->SetBoolean("proxy_migrated", true);
  138. + local_state_prefs->CommitPendingWrite();
  139. + }
  140. + return std::make_unique<PrefProxyConfigTrackerImpl>(local_state_prefs, nullptr);
  141. #endif // BUILDFLAG(IS_CHROMEOS_ASH)
  142. }
  143. @@ -88,3 +105,8 @@ ProxyServiceFactory::CreatePrefProxyConfigTrackerOfLocalState(
  144. nullptr);
  145. #endif // BUILDFLAG(IS_CHROMEOS_ASH)
  146. }
  147. +
  148. +// static
  149. +void ProxyServiceFactory::RegisterPrefs(PrefRegistrySimple* registry) {
  150. + registry->RegisterBooleanPref("proxy_migrated", false);
  151. +}
  152. diff --git a/chrome/browser/net/proxy_service_factory.h b/chrome/browser/net/proxy_service_factory.h
  153. --- a/chrome/browser/net/proxy_service_factory.h
  154. +++ b/chrome/browser/net/proxy_service_factory.h
  155. @@ -6,6 +6,7 @@
  156. #define CHROME_BROWSER_NET_PROXY_SERVICE_FACTORY_H_
  157. #include <memory>
  158. +#include "components/prefs/pref_registry_simple.h"
  159. class PrefProxyConfigTracker;
  160. class PrefService;
  161. @@ -35,6 +36,8 @@ class ProxyServiceFactory {
  162. CreatePrefProxyConfigTrackerOfProfile(PrefService* profile_prefs,
  163. PrefService* local_state_prefs);
  164. + static void RegisterPrefs(PrefRegistrySimple* registry);
  165. +
  166. // Creates a PrefProxyConfigTracker that tracks local state only. This tracker
  167. // should be used for the system request context and the signin screen
  168. // (ChromeOS only).
  169. diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
  170. --- a/chrome/browser/prefs/browser_prefs.cc
  171. +++ b/chrome/browser/prefs/browser_prefs.cc
  172. @@ -161,6 +161,8 @@
  173. #include "printing/buildflags/buildflags.h"
  174. #include "rlz/buildflags/buildflags.h"
  175. +#include "chrome/browser/net/proxy_service_factory.h"
  176. +
  177. #if BUILDFLAG(ENABLE_BACKGROUND_MODE)
  178. #include "chrome/browser/background/background_mode_manager.h"
  179. #endif
  180. @@ -983,6 +985,8 @@ void RegisterLocalState(PrefRegistrySimple* registry) {
  181. chrome::enterprise_util::RegisterLocalStatePrefs(registry);
  182. component_updater::RegisterPrefs(registry);
  183. embedder_support::OriginTrialPrefs::RegisterPrefs(registry);
  184. + ProxyServiceFactory::RegisterPrefs(registry);
  185. +
  186. enterprise_reporting::RegisterLocalStatePrefs(registry);
  187. ExternalProtocolHandler::RegisterPrefs(registry);
  188. flags_ui::PrefServiceFlagsStorage::RegisterPrefs(registry);
  189. diff --git a/chrome/browser/prefs/chrome_command_line_pref_store.cc b/chrome/browser/prefs/chrome_command_line_pref_store.cc
  190. --- a/chrome/browser/prefs/chrome_command_line_pref_store.cc
  191. +++ b/chrome/browser/prefs/chrome_command_line_pref_store.cc
  192. @@ -157,7 +157,7 @@ void ChromeCommandLinePrefStore::ApplyProxyMode() {
  193. SetValue(
  194. proxy_config::prefs::kProxy,
  195. std::make_unique<base::Value>(ProxyConfigDictionary::CreateFixedServers(
  196. - proxy_server, bypass_list)),
  197. + proxy_server, bypass_list, false)),
  198. WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
  199. }
  200. }
  201. diff --git a/chrome/browser/resources/proxy_config.css b/chrome/browser/resources/proxy_config.css
  202. new file mode 100644
  203. --- /dev/null
  204. +++ b/chrome/browser/resources/proxy_config.css
  205. @@ -0,0 +1,61 @@
  206. +/* Copyright (c) 2013 The Chromium Authors. All rights reserved.
  207. + * Use of this source code is governed by a BSD-style license that can be
  208. + * found in the LICENSE file.
  209. + */
  210. +
  211. +body {
  212. + font-size: 80%;
  213. + margin: 1em;
  214. +}
  215. +
  216. +#main-container {
  217. + max-width: 60em;
  218. + margin-left: auto;
  219. + margin-right: auto;
  220. +}
  221. +
  222. +button {
  223. + display: block;
  224. + font-size: 110%;
  225. + font-weight: bold;
  226. + margin: 10px auto;
  227. + padding: 1em;
  228. + width: 15em;
  229. +}
  230. +
  231. +h2 {
  232. + color: #546E7A;
  233. + font-weight: normal;
  234. + font-size: 170%;
  235. + margin-bottom: 1.5em;
  236. +}
  237. +
  238. +.radio-button-div {
  239. + margin: 7px auto;
  240. +}
  241. +
  242. +.warning {
  243. + color: red;
  244. + font-size: 90%;
  245. +}
  246. +
  247. +.section-container {
  248. + margin-top: 2em;
  249. +}
  250. +
  251. +#file-path-logging,
  252. +#file-path-stopped {
  253. + font-family: monospace;
  254. +}
  255. +
  256. +.outline-box {
  257. + margin-top: 2em;
  258. + border: 1px solid #ababab;
  259. + padding: 0.5em;
  260. + line-height: 1.5em;
  261. +}
  262. +
  263. +textarea {
  264. + width: 95%;
  265. + height: 4em;
  266. +}
  267. diff --git a/chrome/browser/resources/proxy_config.html b/chrome/browser/resources/proxy_config.html
  268. new file mode 100644
  269. --- /dev/null
  270. +++ b/chrome/browser/resources/proxy_config.html
  271. @@ -0,0 +1,79 @@
  272. +<!doctype html>
  273. +<html>
  274. +<head>
  275. +<meta charset="utf-8">
  276. +<if expr="is_android">
  277. +<meta name="viewport" content="width=device-width">
  278. +</if>
  279. +
  280. +<if expr="is_ios">
  281. +<!-- TODO(crbug.com/487000): Remove this once injected by web. -->
  282. +<script src="chrome://resources/js/ios/web_ui.js"></script>
  283. +</if>
  284. +
  285. +<script src="chrome://resources/js/assert.js"></script>
  286. +<script src="chrome://resources/js/util.js"></script>
  287. +<script type="module" src="chrome://proxy/proxy_config.js"></script>
  288. +<link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
  289. +<link rel="stylesheet" href="proxy_config.css">
  290. +<title>Proxy configuration</title>
  291. +</head>
  292. +<body>
  293. + <div id="main-container">
  294. + <!--
  295. + =========================================================================
  296. + View for "pending" state.
  297. + * Only visible briefly, if at all
  298. + =========================================================================
  299. + -->
  300. + <div id="state-pending">
  301. + <h2>Proxy configuration</h2>
  302. + Loading...
  303. + </div>
  304. +
  305. + <!--
  306. + =========================================================================
  307. + View for "available" and "unset" states.
  308. + * Has controls to change or reset proxy configuration.
  309. + =========================================================================
  310. + -->
  311. + <div id="state-main" hidden>
  312. + <h2>Proxy configuration</h2>
  313. + <button id="reset">Reset</button>
  314. + <div class="section-container">
  315. + Reset will update the displayed configuration to match the one currently in use.
  316. + </div>
  317. + <div class="section-container">
  318. + <input type="radio" id="empty" name="mode" value="empty"><label for="empty">System Default</label><br/>
  319. + <input type="radio" id="direct" name="mode" value="direct"><label for="direct">Direct</label><br/>
  320. + <input type="radio" id="auto-detect" name="mode" value="auto-detect"><label for="auto-detect">Auto-detect (WPAD DHCP/DNS)</label><br/>
  321. + <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>
  322. + <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>
  323. + <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>):
  324. + <textarea id="single-proxies"></textarea>
  325. + </label><br/>
  326. + <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/>
  327. + <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/>
  328. + <textarea id="http-proxies"></textarea></label><br/>
  329. + <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/>
  330. + <textarea id="https-proxies"></textarea></label><br/>
  331. + <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/>
  332. + <textarea id="ftp-proxies"></textarea></label><br/>
  333. + <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/>
  334. + <textarea id="fallback-proxies"></textarea></label>
  335. + <div class="outline-box">
  336. + 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/>
  337. + <textarea id="bypass-rules"></textarea><br/>
  338. + <input type="checkbox" id="reverse-bypass" name="reverse-bypass"><label for="reverse-bypass">Reverse the meaning of bypass rules</label>
  339. + </div>
  340. + </div>
  341. + <button id="apply">Apply</button>
  342. + <button id="clear">Clear</button>
  343. + <div class="section-container">
  344. + Clicking on Clear will remove any proxy configuration preference currently in effect.
  345. + </div>
  346. + </div>
  347. +
  348. + </div>
  349. +</body>
  350. +</html>
  351. diff --git a/chrome/browser/resources/proxy_config.js b/chrome/browser/resources/proxy_config.js
  352. new file mode 100644
  353. --- /dev/null
  354. +++ b/chrome/browser/resources/proxy_config.js
  355. @@ -0,0 +1,266 @@
  356. +/*
  357. + This file is part of Bromite.
  358. +
  359. + Bromite is free software: you can redistribute it and/or modify
  360. + it under the terms of the GNU General Public License as published by
  361. + the Free Software Foundation, either version 3 of the License, or
  362. + (at your option) any later version.
  363. +
  364. + Bromite is distributed in the hope that it will be useful,
  365. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  366. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  367. + GNU General Public License for more details.
  368. +
  369. + You should have received a copy of the GNU General Public License
  370. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  371. +*/
  372. +
  373. +import {addSingletonGetter} from 'chrome://resources/js/cr.m.js';
  374. +
  375. +/**
  376. + * Main entry point called once the page has loaded.
  377. + */
  378. +function onLoad() {
  379. + ProxyConfigView.getInstance();
  380. +}
  381. +
  382. +document.addEventListener('DOMContentLoaded', onLoad);
  383. +
  384. +/**
  385. + * This class handles the presentation of the proxy-config view. Used as a
  386. + * singleton.
  387. + */
  388. +var ProxyConfigView = (function() {
  389. + 'use strict';
  390. +
  391. + // --------------------------------------------------------------------------
  392. +
  393. + var kIdStateDivUninitialized = 'state-pending';
  394. + var kIdStateDivMain = 'state-main';
  395. + var kIdApplyButton = 'apply';
  396. + var kIdResetButton = 'reset';
  397. + var kIdClearButton = 'clear';
  398. +
  399. + var kIdModeEmpty = 'empty';
  400. + var kIdModeDirect = 'direct';
  401. + var kIdModeAutoDetect = 'auto-detect';
  402. + var kIdModeUsePacURL = 'use-pac-url';
  403. +
  404. + var kIdModeUseSingleList = 'use-single-list';
  405. + var kIdModeUseListPerScheme = 'use-list-per-scheme';
  406. +
  407. + var kIdPacURL = 'pac-url';
  408. + var kIdPacMandatory = 'pac-mandatory';
  409. + var kIdBypassRules = 'bypass-rules';
  410. + var kIdReverseBypass = 'reverse-bypass';
  411. + var kIdSingleProxies = 'single-proxies';
  412. + var kIdHttpProxies = 'http-proxies';
  413. + var kIdHttpsProxies = 'https-proxies';
  414. + var kIdFtpProxies = 'ftp-proxies';
  415. + var kIdFallbackProxies = 'fallback-proxies';
  416. +
  417. + /**
  418. + * @constructor
  419. + */
  420. + function ProxyConfigView() {
  421. + this.currentConfig = null;
  422. +
  423. + $(kIdResetButton).onclick = this.onReset_.bind(this);
  424. + $(kIdApplyButton).onclick = this.onApply_.bind(this);
  425. + $(kIdClearButton).onclick = this.onClear_.bind(this);
  426. +
  427. + // Tell ProxyConfigMessageHandler to notify the UI of future state changes
  428. + // from this point on.
  429. + chrome.send('enableNotifyUIWithState');
  430. + }
  431. +
  432. + addSingletonGetter(ProxyConfigView);
  433. + window.ProxyConfigView = ProxyConfigView;
  434. +
  435. + ProxyConfigView.prototype = {
  436. + /**
  437. + * Updates the UI to reflect the current state. The state transitions are
  438. + * sent by the browser controller (ProxyConfigMessageHandler):
  439. + *
  440. + * * PENDING - This is the initial state when proxy configuration is opened
  441. + * for the first time, or there was an error during initialization.
  442. + * This state is short-lived and likely not observed; will
  443. + * immediately transition to AVAILABLE).
  444. + *
  445. + * * AVAILABLE - The reported proxy configuration is active; this state is entered
  446. + * on first page load (or right after PENDING if configuration was not
  447. + * available on page load) and every time some configuration change was applied.
  448. + * It can transition to either AVAILABLE or UNSET.
  449. + *
  450. + * * UNSET - Proxy configuration is reported to be currently not set.
  451. + *
  452. + */
  453. + onProxyConfigChanged: function(state) {
  454. + // may happen only on first load; leave the loading page as another update is expected
  455. + // when proxy configuration has finished loading
  456. + if (state.pending) {
  457. + $(kIdStateDivMain).hidden = true;
  458. + $(kIdStateDivUninitialized).hidden = false;
  459. + return;
  460. + }
  461. +
  462. + if (!state.hasOwnProperty('config')) {
  463. + // configuration has been unset, use an empty one
  464. + this.eraseCurrentConfig_();
  465. + } else {
  466. + // save the configuration as current and reset all controls to it
  467. + this.currentConfig = state.config;
  468. + }
  469. +
  470. + this.renderConfig_();
  471. +
  472. + this.toggleButtons_(false);
  473. + $(kIdStateDivUninitialized).hidden = true;
  474. + $(kIdStateDivMain).hidden = false;
  475. + },
  476. +
  477. + /**
  478. + * Set current configuration to an empty (default) one.
  479. + */
  480. + eraseCurrentConfig_: function() {
  481. + this.currentConfig = {
  482. + "auto_detect": false,
  483. + "pending": false,
  484. + "rules": {
  485. + "bypass_rules": "",
  486. + "reverse_bypass": false,
  487. + "type": "none"
  488. + }
  489. + };
  490. + },
  491. +
  492. + /**
  493. + * Serialize the user-selected configuration in an object.
  494. + */
  495. + serializeConfig_: function() {
  496. + if ($(kIdModeEmpty).checked) {
  497. + return {
  498. + "auto_detect": false,
  499. + "rules": {
  500. + "type": "none"
  501. + }
  502. + };
  503. + } else if ($(kIdModeDirect).checked) {
  504. + return {
  505. + "auto_detect": false,
  506. + "rules": {
  507. + "type": "direct"
  508. + }
  509. + };
  510. + } else if ($(kIdModeAutoDetect).checked) {
  511. + return {
  512. + "auto_detect": true
  513. + };
  514. + } else if ($(kIdModeUsePacURL).checked) {
  515. + return {
  516. + "auto_detect": false,
  517. + "pac_url": $(kIdPacURL).value.trim(),
  518. + "pac_mandatory": $(kIdPacMandatory).checked,
  519. + "rules": {}
  520. + };
  521. + } else if ($(kIdModeUseListPerScheme).checked || $(kIdModeUseSingleList).checked) {
  522. + var config = {
  523. + "auto_detect": false,
  524. + "rules": {
  525. + "bypass_rules": $(kIdBypassRules).value.trim(),
  526. + "reverse_bypass": $(kIdReverseBypass).checked,
  527. + "type": "list"
  528. + }
  529. + };
  530. +
  531. + if ($(kIdModeUseListPerScheme).checked) {
  532. + config.rules.type = "list_per_scheme";
  533. +
  534. + config.rules.proxies_for_http = $(kIdHttpProxies).value.trim();
  535. + config.rules.proxies_for_https = $(kIdHttpsProxies).value.trim();
  536. + config.rules.proxies_for_ftp = $(kIdFtpProxies).value.trim();
  537. + config.rules.fallback_proxies = $(kIdFallbackProxies).value.trim();
  538. + } else {
  539. + config.rules.single_proxies = $(kIdSingleProxies).value.trim();
  540. + }
  541. +
  542. + return config;
  543. + }
  544. +
  545. + throw new Error('unexpected mode');
  546. + },
  547. +
  548. + /**
  549. + * Updates the UI to display the current proxy configuration.
  550. + */
  551. + renderConfig_: function() {
  552. + if (this.currentConfig.auto_detect) {
  553. + $(kIdModeAutoDetect).checked = true;
  554. + } else if (this.currentConfig.hasOwnProperty('pac_url')) {
  555. + $(kIdPacURL).value = this.currentConfig.pac_url;
  556. + $(kIdPacMandatory).checked = this.currentConfig.pac_mandatory;
  557. + $(kIdModeUsePacURL).checked = true;
  558. + } else if (this.currentConfig.rules.type == "none") {
  559. + $(kIdModeEmpty).checked = true;
  560. + } else if (this.currentConfig.rules.type == "direct") {
  561. + $(kIdModeDirect).checked = true;
  562. + } else {
  563. + $(kIdBypassRules).value = this.currentConfig.rules.bypass_rules;
  564. + $(kIdReverseBypass).checked = this.currentConfig.rules.reverse_bypass;
  565. +
  566. + switch (this.currentConfig.rules.type) {
  567. + case "list":
  568. + $(kIdModeUseSingleList).checked = true;
  569. + $(kIdSingleProxies).value = this.currentConfig.rules.single_proxies;
  570. + break;
  571. + case "list_per_scheme":
  572. + $(kIdModeUseListPerScheme).checked = true;
  573. + $(kIdHttpProxies).value = this.currentConfig.rules.proxies_for_http;
  574. + $(kIdHttpsProxies).value = this.currentConfig.rules.proxies_for_https;
  575. + $(kIdFtpProxies).value = this.currentConfig.rules.proxies_for_ftp;
  576. + $(kIdFallbackProxies).value = this.currentConfig.rules.fallback_proxies;
  577. + break;
  578. + }
  579. + }
  580. + },
  581. +
  582. + /**
  583. + * Apply the configuration currently displayed.
  584. + */
  585. + onApply_: function() {
  586. + var config = this.serializeConfig_();
  587. +
  588. + // disable buttons; will be enabled back when UI receives a state update
  589. + this.toggleButtons_(true);
  590. + chrome.send('apply', [config]);
  591. + },
  592. +
  593. + /**
  594. + * Apply the configuration currently displayed.
  595. + */
  596. + onClear_: function() {
  597. + // disable buttons; will be enabled back when UI receives a state update
  598. + this.toggleButtons_(true);
  599. + this.eraseCurrentConfig_();
  600. + chrome.send('clear', []);
  601. + },
  602. +
  603. + /**
  604. + * Toggle the disabled status of the action buttons.
  605. + */
  606. + toggleButtons_: function(disabled) {
  607. + $(kIdApplyButton).disabled = disabled;
  608. + $(kIdResetButton).disabled = disabled;
  609. + $(kIdClearButton).disabled = disabled;
  610. + },
  611. +
  612. + /**
  613. + * Reset currently displayed configuration to the last known configuration in use.
  614. + */
  615. + onReset_: function() {
  616. + this.renderConfig_();
  617. + }
  618. + };
  619. +
  620. + return ProxyConfigView;
  621. +})();
  622. diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
  623. --- a/chrome/browser/ui/BUILD.gn
  624. +++ b/chrome/browser/ui/BUILD.gn
  625. @@ -286,6 +286,8 @@ static_library("ui") {
  626. "webui/metrics_handler.h",
  627. "webui/net_export_ui.cc",
  628. "webui/net_export_ui.h",
  629. + "webui/proxy_config_ui.cc",
  630. + "webui/proxy_config_ui.h",
  631. "webui/net_internals/net_internals_ui.cc",
  632. "webui/net_internals/net_internals_ui.h",
  633. "webui/ntp_tiles_internals_ui.cc",
  634. diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
  635. --- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
  636. +++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
  637. @@ -57,6 +57,7 @@
  638. #include "chrome/browser/ui/webui/ntp_tiles_internals_ui.h"
  639. #include "chrome/browser/ui/webui/omnibox/omnibox_ui.h"
  640. #include "chrome/browser/ui/webui/policy/policy_ui.h"
  641. +#include "chrome/browser/ui/webui/proxy_config_ui.h"
  642. #include "chrome/browser/ui/webui/predictors/predictors_ui.h"
  643. #include "chrome/browser/ui/webui/segmentation_internals/segmentation_internals_ui.h"
  644. #include "chrome/browser/ui/webui/signin_internals_ui.h"
  645. @@ -765,6 +766,8 @@ WebUIFactoryFunction GetWebUIFactoryFunction(WebUI* web_ui,
  646. return &NewWebUI<MemoryInternalsUI>;
  647. if (url.host_piece() == chrome::kChromeUINetExportHost)
  648. return &NewWebUI<NetExportUI>;
  649. + if (url.host_piece() == chrome::kChromeUIProxyConfigHost)
  650. + return &NewWebUI<ProxyConfigUI>;
  651. if (url.host_piece() == chrome::kChromeUINetInternalsHost)
  652. return &NewWebUI<NetInternalsUI>;
  653. if (url.host_piece() == chrome::kChromeUINTPTilesInternalsHost)
  654. diff --git a/chrome/browser/ui/webui/proxy_config_ui.cc b/chrome/browser/ui/webui/proxy_config_ui.cc
  655. new file mode 100644
  656. --- /dev/null
  657. +++ b/chrome/browser/ui/webui/proxy_config_ui.cc
  658. @@ -0,0 +1,418 @@
  659. +/*
  660. + This file is part of Bromite.
  661. +
  662. + Bromite is free software: you can redistribute it and/or modify
  663. + it under the terms of the GNU General Public License as published by
  664. + the Free Software Foundation, either version 3 of the License, or
  665. + (at your option) any later version.
  666. +
  667. + Bromite is distributed in the hope that it will be useful,
  668. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  669. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  670. + GNU General Public License for more details.
  671. +
  672. + You should have received a copy of the GNU General Public License
  673. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  674. +*/
  675. +
  676. +#include "chrome/browser/ui/webui/proxy_config_ui.h"
  677. +
  678. +#include <stdint.h>
  679. +
  680. +#include <memory>
  681. +#include <string>
  682. +#include <vector>
  683. +
  684. +#include "base/bind.h"
  685. +#include "base/command_line.h"
  686. +#include "base/lazy_instance.h"
  687. +#include "base/memory/ref_counted.h"
  688. +#include "base/strings/string_util.h"
  689. +#include "base/strings/utf_string_conversions.h"
  690. +#include "base/values.h"
  691. +#include "chrome/browser/browser_process.h"
  692. +#include "chrome/browser/net/proxy_service_factory.h"
  693. +#include "chrome/browser/platform_util.h"
  694. +#include "chrome/browser/profiles/profile.h"
  695. +#include "chrome/common/url_constants.h"
  696. +#include "chrome/grit/browser_resources.h"
  697. +#include "components/prefs/pref_service.h"
  698. +#include "components/proxy_config/pref_proxy_config_tracker_impl.h"
  699. +#include "components/proxy_config/proxy_config_pref_names.h"
  700. +#include "components/grit/components_resources.h"
  701. +#include "content/public/browser/browser_thread.h"
  702. +#include "content/public/browser/url_data_source.h"
  703. +#include "content/public/browser/web_contents.h"
  704. +#include "content/public/browser/web_ui.h"
  705. +#include "content/public/browser/web_ui_data_source.h"
  706. +#include "content/public/browser/web_ui_message_handler.h"
  707. +
  708. +#include "url/gurl.h"
  709. +
  710. +using content::BrowserThread;
  711. +using content::WebContents;
  712. +using content::WebUIMessageHandler;
  713. +
  714. +namespace {
  715. +
  716. +content::WebUIDataSource* CreateProxyConfigHTMLSource() {
  717. + content::WebUIDataSource* source =
  718. + content::WebUIDataSource::Create(chrome::kChromeUIProxyConfigHost);
  719. +
  720. + source->UseStringsJs();
  721. + source->AddResourcePath("proxy_config.js", IDR_PROXY_CONFIG_JS);
  722. + source->SetDefaultResource(IDR_PROXY_CONFIG_HTML);
  723. + return source;
  724. +}
  725. +
  726. +// This class receives javascript messages from the renderer.
  727. +// Note that the WebUI infrastructure runs on the UI thread, therefore all of
  728. +// this class's public methods are expected to run on the UI thread.
  729. +class ProxyConfigMessageHandler
  730. + : public WebUIMessageHandler,
  731. + public base::SupportsWeakPtr<ProxyConfigMessageHandler>,
  732. + public net::ProxyConfigService::Observer {
  733. + public:
  734. + ProxyConfigMessageHandler(const ProxyConfigMessageHandler&) = delete;
  735. + ProxyConfigMessageHandler& operator=(const ProxyConfigMessageHandler&) = delete;
  736. + // Creates a ProxyConfigMessageHandler that handles message exchanges with the Javascript
  737. + // side of the UI and gets proxy settings from the Web UI associated profile to watch for changes.
  738. + // The created ProxyConfigMessageHandler must be destroyed before |profile|.
  739. + ProxyConfigMessageHandler(Profile *profile);
  740. + ~ProxyConfigMessageHandler() override;
  741. +
  742. + // WebUIMessageHandler implementation.
  743. + void RegisterMessages() override;
  744. +
  745. + // Messages
  746. + void OnEnableNotifyUIWithState(const base::Value::List& args);
  747. + void OnApply(const base::Value::List& args);
  748. + void OnClear(const base::Value::List& args);
  749. +
  750. + // net::ProxyConfigService::Observer implementation:
  751. + // Calls ProxyConfigView.onProxyConfigChanged JavaScript function in the
  752. + // renderer.
  753. + void OnProxyConfigChanged(
  754. + const net::ProxyConfigWithAnnotation& config,
  755. + net::ProxyConfigService::ConfigAvailability availability) override;
  756. +
  757. + private:
  758. + // Not owned.
  759. + PrefService *pref_service_;
  760. + std::unique_ptr<net::ProxyConfigService> proxy_config_service_;
  761. + // Monitors global and Profile prefs related to proxy configuration.
  762. + std::unique_ptr<PrefProxyConfigTracker> pref_proxy_config_tracker_;
  763. + bool is_observing_;
  764. +
  765. + void encodeConfig(const net::ProxyConfig& config, base::DictionaryValue& state);
  766. +
  767. + void apply(const net::ProxyConfig& config);
  768. +
  769. + base::WeakPtrFactory<ProxyConfigMessageHandler> weak_ptr_factory_;
  770. +};
  771. +
  772. +ProxyConfigMessageHandler::ProxyConfigMessageHandler(Profile *profile)
  773. + :
  774. + weak_ptr_factory_(this) {
  775. +
  776. + // used to set new configuration preferences
  777. + pref_service_ = g_browser_process->local_state();
  778. + // observer is explicitly added only later in enableNotifyUIWithState
  779. + is_observing_ = false;
  780. +
  781. +// If this is the ChromeOS sign-in profile, just create the tracker from global
  782. +// state.
  783. +#if defined(OS_CHROMEOS)
  784. + if (chromeos::ProfileHelper::IsSigninProfile(profile)) {
  785. + pref_proxy_config_tracker_.reset(
  786. + ProxyServiceFactory::CreatePrefProxyConfigTrackerOfLocalState(
  787. + g_browser_process->local_state()));
  788. + }
  789. +#endif // defined(OS_CHROMEOS)
  790. +
  791. + if (!pref_proxy_config_tracker_) {
  792. + pref_proxy_config_tracker_ =
  793. + ProxyServiceFactory::CreatePrefProxyConfigTrackerOfProfile(
  794. + profile->GetPrefs(), g_browser_process->local_state());
  795. + }
  796. +
  797. + proxy_config_service_ = ProxyServiceFactory::CreateProxyConfigService(
  798. + pref_proxy_config_tracker_.get(), nullptr);
  799. +}
  800. +
  801. +void ProxyConfigMessageHandler::OnProxyConfigChanged(
  802. + const net::ProxyConfigWithAnnotation& config,
  803. + net::ProxyConfigService::ConfigAvailability availability) {
  804. + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
  805. + !BrowserThread::IsThreadInitialized(BrowserThread::UI));
  806. +
  807. + base::DictionaryValue state;
  808. + bool pending = false;
  809. + switch (availability) {
  810. + case net::ProxyConfigService::CONFIG_VALID:
  811. + encodeConfig(config.value(), state);
  812. + break;
  813. + case net::ProxyConfigService::CONFIG_UNSET:
  814. + state.SetPath({"config", "rules", "type"}, base::Value("none"));
  815. + break;
  816. + case net::ProxyConfigService::CONFIG_PENDING:
  817. + //NOTE: this can only happen when triggered manually first time
  818. + pending = true;
  819. + break;
  820. + }
  821. + state.SetKey("pending", base::Value(pending));
  822. +
  823. + // call Javascript function
  824. + web_ui()->CallJavascriptFunctionUnsafe("ProxyConfigView.getInstance().onProxyConfigChanged",
  825. + *state.CreateDeepCopy());
  826. +}
  827. +
  828. +const std::string omitDirect(const std::string pacString) {
  829. + if (pacString == "DIRECT") {
  830. + return "";
  831. + }
  832. + return pacString;
  833. +}
  834. +
  835. +void ProxyConfigMessageHandler::encodeConfig(const net::ProxyConfig& config, base::DictionaryValue& state) {
  836. + // when automatic settings are enabled they take precedence over manual settings
  837. + // automatic settings are either the "auto-detect" flag or the existance of a PAC URL
  838. +
  839. + state.SetPath({"config", "auto_detect"}, base::Value(config.auto_detect()));
  840. +
  841. + auto rules = config.proxy_rules();
  842. + if (config.has_pac_url()) {
  843. + state.SetPath({"config", "pac_url"}, base::Value(config.pac_url().spec()));
  844. + state.SetPath({"config", "pac_mandatory"}, base::Value(config.pac_mandatory()));
  845. + state.SetPath({"config", "rules", "type"}, base::Value("none"));
  846. + state.SetPath({"config", "rules", "bypass_rules"}, base::Value(rules.bypass_rules.ToString()));
  847. + state.SetPath({"config", "rules", "reverse_bypass"}, base::Value(rules.reverse_bypass));
  848. + return;
  849. + }
  850. +
  851. + const char *type;
  852. + switch (rules.type) {
  853. + case net::ProxyConfig::ProxyRules::Type::EMPTY:
  854. + type = "direct";
  855. + break;
  856. + case net::ProxyConfig::ProxyRules::Type::PROXY_LIST:
  857. + type = "list";
  858. +
  859. + state.SetPath({"config", "rules", "single_proxies"}, base::Value(omitDirect(rules.single_proxies.ToPacString())));
  860. + break;
  861. + case net::ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME:
  862. + type = "list_per_scheme";
  863. +
  864. + state.SetPath({"config", "rules", "proxies_for_http"}, base::Value(omitDirect(rules.proxies_for_http.ToPacString())));
  865. + state.SetPath({"config", "rules", "proxies_for_https"}, base::Value(omitDirect(rules.proxies_for_https.ToPacString())));
  866. + state.SetPath({"config", "rules", "proxies_for_ftp"}, base::Value(omitDirect(rules.proxies_for_ftp.ToPacString())));
  867. + state.SetPath({"config", "rules", "fallback_proxies"}, base::Value(omitDirect(rules.fallback_proxies.ToPacString())));
  868. + break;
  869. + default:
  870. + NOTREACHED();
  871. + break;
  872. + }
  873. + state.SetPath({"config", "rules", "type"}, base::Value(type));
  874. + state.SetPath({"config", "rules", "bypass_rules"}, base::Value(rules.bypass_rules.ToString()));
  875. + state.SetPath({"config", "rules", "reverse_bypass"}, base::Value(rules.reverse_bypass));
  876. +}
  877. +
  878. +ProxyConfigMessageHandler::~ProxyConfigMessageHandler() {
  879. + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
  880. + !BrowserThread::IsThreadInitialized(BrowserThread::UI));
  881. + if (is_observing_) {
  882. + proxy_config_service_->RemoveObserver(this);
  883. + }
  884. + pref_proxy_config_tracker_->DetachFromPrefService();
  885. +}
  886. +
  887. +void ProxyConfigMessageHandler::RegisterMessages() {
  888. + DCHECK_CURRENTLY_ON(BrowserThread::UI);
  889. +
  890. + web_ui()->RegisterMessageCallback(
  891. + "enableNotifyUIWithState",
  892. + base::BindRepeating(&ProxyConfigMessageHandler::OnEnableNotifyUIWithState,
  893. + base::Unretained(this)));
  894. + web_ui()->RegisterMessageCallback(
  895. + "apply",
  896. + base::BindRepeating(&ProxyConfigMessageHandler::OnApply,
  897. + base::Unretained(this)));
  898. + web_ui()->RegisterMessageCallback(
  899. + "clear",
  900. + base::BindRepeating(&ProxyConfigMessageHandler::OnClear,
  901. + base::Unretained(this)));
  902. +}
  903. +
  904. +// The proxy configuration UI is not notified of state changes until this function runs.
  905. +// After this function, OnProxyConfigChanged() will be called on all proxy state changes.
  906. +void ProxyConfigMessageHandler::OnEnableNotifyUIWithState(
  907. + const base::Value::List& list) {
  908. + DCHECK_CURRENTLY_ON(BrowserThread::UI);
  909. +
  910. + if (!is_observing_) {
  911. + is_observing_ = true;
  912. + proxy_config_service_->AddObserver(this);
  913. + }
  914. +
  915. + net::ProxyConfigWithAnnotation config;
  916. + auto availability = proxy_config_service_->GetLatestProxyConfig(&config);
  917. +
  918. + const base::Value* dict =
  919. + pref_service_->GetDictionary(proxy_config::prefs::kProxy);
  920. + ProxyConfigDictionary proxy_dict(dict->Clone());
  921. + ProxyPrefs::ProxyMode mode;
  922. + if (!proxy_dict.GetMode(&mode) || mode == ProxyPrefs::MODE_SYSTEM) {
  923. + availability = net::ProxyConfigService::CONFIG_UNSET;
  924. + }
  925. +
  926. + OnProxyConfigChanged(config, availability);
  927. +}
  928. +
  929. +void ProxyConfigMessageHandler::OnClear(const base::Value::List& list) {
  930. + DCHECK_CURRENTLY_ON(BrowserThread::UI);
  931. +
  932. + const base::Value cfg = ProxyConfigDictionary::CreateSystem();
  933. + pref_service_->Set(proxy_config::prefs::kProxy, cfg);
  934. + pref_service_->CommitPendingWrite();
  935. + OnEnableNotifyUIWithState(list);
  936. +}
  937. +
  938. +void ProxyConfigMessageHandler::OnApply(const base::Value::List& list) {
  939. + DCHECK_CURRENTLY_ON(BrowserThread::UI);
  940. +
  941. + if ((list.size() != 1) || !list[0].is_dict()) {
  942. + return;
  943. + }
  944. +
  945. + const base::DictionaryValue* config = nullptr;
  946. + if (!list[0].GetAsDictionary(&config))
  947. + return;
  948. +
  949. + const base::Value *autoDetect = config->FindKeyOfType("auto_detect", base::Value::Type::BOOLEAN);
  950. + if (autoDetect == nullptr)
  951. + return;
  952. +
  953. + if (autoDetect->GetBool()) {
  954. + apply(net::ProxyConfig::CreateAutoDetect());
  955. + return;
  956. + }
  957. +
  958. + const base::Value *pacURL = config->FindKeyOfType("pac_url", base::Value::Type::STRING);
  959. + if (pacURL != nullptr) {
  960. + const base::Value *pacMandatory = config->FindKeyOfType("pac_mandatory", base::Value::Type::BOOLEAN);
  961. + if (pacMandatory == nullptr)
  962. + return;
  963. + auto proxyConfig = net::ProxyConfig::CreateFromCustomPacURL(GURL(pacURL->GetString()));
  964. + proxyConfig.set_pac_mandatory(pacMandatory->GetBool());
  965. +
  966. + apply(proxyConfig);
  967. + return;
  968. + }
  969. +
  970. + const base::Value *rules = config->FindKeyOfType("rules", base::Value::Type::DICTIONARY);
  971. + if (rules == nullptr)
  972. + return;
  973. +
  974. + const base::Value *type = rules->FindKeyOfType("type", base::Value::Type::STRING);
  975. + if (type == nullptr)
  976. + return;
  977. +
  978. + net::ProxyConfig proxyConfig;
  979. +
  980. + bool readBypass = false;
  981. +
  982. + auto t = type->GetString();
  983. + if (t == "list") {
  984. + const base::Value *single_proxies = rules->FindKeyOfType("single_proxies", base::Value::Type::STRING);
  985. + if (single_proxies == nullptr)
  986. + return;
  987. + proxyConfig.proxy_rules().type = net::ProxyConfig::ProxyRules::Type::PROXY_LIST;
  988. + proxyConfig.proxy_rules().single_proxies.SetFromPacString(single_proxies->GetString());
  989. + readBypass = true;
  990. + } else if (t == "list_per_scheme") {
  991. + const base::Value *http = rules->FindKeyOfType("proxies_for_http", base::Value::Type::STRING);
  992. + if (http == nullptr)
  993. + return;
  994. +
  995. + const base::Value *https = rules->FindKeyOfType("proxies_for_https", base::Value::Type::STRING);
  996. + if (https == nullptr)
  997. + return;
  998. +
  999. + const base::Value *ftp = rules->FindKeyOfType("proxies_for_ftp", base::Value::Type::STRING);
  1000. + if (ftp == nullptr)
  1001. + return;
  1002. +
  1003. + const base::Value *fallback = rules->FindKeyOfType("fallback_proxies", base::Value::Type::STRING);
  1004. + if (fallback == nullptr)
  1005. + return;
  1006. +
  1007. + proxyConfig.proxy_rules().type = net::ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME;
  1008. + proxyConfig.proxy_rules().proxies_for_http.SetFromPacString(http->GetString());
  1009. + proxyConfig.proxy_rules().proxies_for_https.SetFromPacString(https->GetString());
  1010. + proxyConfig.proxy_rules().proxies_for_ftp.SetFromPacString(ftp->GetString());
  1011. + proxyConfig.proxy_rules().fallback_proxies.SetFromPacString(fallback->GetString());
  1012. + readBypass = true;
  1013. + } else if (t == "direct") {
  1014. + proxyConfig.proxy_rules().type = net::ProxyConfig::ProxyRules::Type::EMPTY;
  1015. + } else if (t == "none") {
  1016. + base::Value::List empty;
  1017. + OnClear(empty);
  1018. + return;
  1019. + } else {
  1020. + // invalid type
  1021. + LOG(WARNING) << "invalid proxy configuration type";
  1022. + return;
  1023. + }
  1024. +
  1025. + // bypass rules and reverse flag are common to both list types of proxy rules
  1026. + if (readBypass) {
  1027. + const base::Value *bypass_rules = rules->FindKeyOfType("bypass_rules", base::Value::Type::STRING);
  1028. + if (bypass_rules == nullptr)
  1029. + return;
  1030. +
  1031. + const base::Value *reverse_bypass = rules->FindKeyOfType("reverse_bypass", base::Value::Type::BOOLEAN);
  1032. + if (reverse_bypass == nullptr)
  1033. + return;
  1034. +
  1035. + proxyConfig.proxy_rules().bypass_rules.ParseFromString(bypass_rules->GetString());
  1036. + proxyConfig.proxy_rules().reverse_bypass = reverse_bypass->GetBool();
  1037. + }
  1038. +
  1039. + apply(proxyConfig);
  1040. +}
  1041. +
  1042. +void ProxyConfigMessageHandler::apply(const net::ProxyConfig& proxyConfig) {
  1043. + if (proxyConfig.auto_detect()) {
  1044. + const base::Value cfg = ProxyConfigDictionary::CreateAutoDetect();
  1045. + pref_service_->Set(proxy_config::prefs::kProxy, cfg);
  1046. + } else if (proxyConfig.has_pac_url()) {
  1047. + const base::Value cfg = ProxyConfigDictionary::CreatePacScript(proxyConfig.pac_url().spec(), proxyConfig.pac_mandatory());
  1048. + pref_service_->Set(proxy_config::prefs::kProxy, cfg);
  1049. + } else if (proxyConfig.proxy_rules().type == net::ProxyConfig::ProxyRules::Type::EMPTY) {
  1050. + const base::Value cfg = ProxyConfigDictionary::CreateDirect();
  1051. + pref_service_->Set(proxy_config::prefs::kProxy, cfg);
  1052. + } else {
  1053. + auto proxyRulesAsString = proxyConfig.proxy_rules().ToString();
  1054. + auto bypassRulesAsString = proxyConfig.proxy_rules().bypass_rules.ToString();
  1055. +
  1056. + // fixed servers
  1057. + const base::Value cfg = ProxyConfigDictionary::CreateFixedServers(proxyRulesAsString,
  1058. + bypassRulesAsString, proxyConfig.proxy_rules().reverse_bypass);
  1059. + pref_service_->Set(proxy_config::prefs::kProxy, cfg);
  1060. + }
  1061. + pref_service_->CommitPendingWrite();
  1062. +
  1063. + base::Value::List empty;
  1064. + OnEnableNotifyUIWithState(empty);
  1065. +}
  1066. +
  1067. +} // namespace
  1068. +
  1069. +ProxyConfigUI::ProxyConfigUI(content::WebUI* web_ui) : WebUIController(web_ui) {
  1070. + Profile* profile = Profile::FromWebUI(web_ui);
  1071. +
  1072. + web_ui->AddMessageHandler(std::make_unique<ProxyConfigMessageHandler>(profile));
  1073. +
  1074. + // Set up the chrome://proxy/ source.
  1075. + content::WebUIDataSource::Add(profile, CreateProxyConfigHTMLSource());
  1076. +}
  1077. diff --git a/chrome/browser/ui/webui/proxy_config_ui.h b/chrome/browser/ui/webui/proxy_config_ui.h
  1078. new file mode 100644
  1079. --- /dev/null
  1080. +++ b/chrome/browser/ui/webui/proxy_config_ui.h
  1081. @@ -0,0 +1,31 @@
  1082. +/*
  1083. + This file is part of Bromite.
  1084. +
  1085. + Bromite is free software: you can redistribute it and/or modify
  1086. + it under the terms of the GNU General Public License as published by
  1087. + the Free Software Foundation, either version 3 of the License, or
  1088. + (at your option) any later version.
  1089. +
  1090. + Bromite is distributed in the hope that it will be useful,
  1091. + but WITHOUT ANY WARRANTY; without even the implied warranty of
  1092. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  1093. + GNU General Public License for more details.
  1094. +
  1095. + You should have received a copy of the GNU General Public License
  1096. + along with Bromite. If not, see <https://www.gnu.org/licenses/>.
  1097. +*/
  1098. +
  1099. +#ifndef CHROME_BROWSER_UI_WEBUI_PROXY_CONFIG_UI_H_
  1100. +#define CHROME_BROWSER_UI_WEBUI_PROXY_CONFIG_UI_H_
  1101. +
  1102. +#include "content/public/browser/web_ui_controller.h"
  1103. +
  1104. +// The WebUI for chrome://proxy/.
  1105. +class ProxyConfigUI : public content::WebUIController {
  1106. + public:
  1107. + ProxyConfigUI(const ProxyConfigUI&) = delete;
  1108. + ProxyConfigUI& operator=(const ProxyConfigUI&) = delete;
  1109. + explicit ProxyConfigUI(content::WebUI* web_ui);
  1110. +};
  1111. +
  1112. +#endif // CHROME_BROWSER_UI_WEBUI_PROXY_CONFIG_UI_H_
  1113. diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc
  1114. --- a/chrome/common/webui_url_constants.cc
  1115. +++ b/chrome/common/webui_url_constants.cc
  1116. @@ -45,6 +45,8 @@ const char kChromeUICertificateViewerHost[] = "view-cert";
  1117. const char kChromeUICertificateViewerURL[] = "chrome://view-cert/";
  1118. const char kChromeUIChromeSigninHost[] = "chrome-signin";
  1119. const char kChromeUIChromeSigninURL[] = "chrome://chrome-signin/";
  1120. +const char kChromeUIProxyConfigHost[] = "proxy";
  1121. +const char kChromeUIProxyConfigURL[] = "chrome://proxy/";
  1122. const char kChromeUIChromeURLsHost[] = "chrome-urls";
  1123. const char kChromeUIChromeURLsURL[] = "chrome://chrome-urls/";
  1124. const char kChromeUIComponentsHost[] = "components";
  1125. @@ -419,6 +421,7 @@ bool IsSystemWebUIHost(base::StringPiece host) {
  1126. kChromeUIMobileSetupHost,
  1127. kChromeUIMultiDeviceSetupHost,
  1128. kChromeUINetworkHost,
  1129. + kChromeUIProxyConfigHost,
  1130. kChromeUIOobeHost,
  1131. kChromeUIOSCreditsHost,
  1132. kChromeUIOSSettingsHost,
  1133. @@ -671,6 +674,7 @@ const char* const kChromeHostURLs[] = {
  1134. #if !BUILDFLAG(IS_ANDROID)
  1135. #if !BUILDFLAG(IS_CHROMEOS_ASH)
  1136. kChromeUIAppLauncherPageHost,
  1137. + kChromeUIProxyConfigHost,
  1138. #endif
  1139. kChromeUIBookmarksHost,
  1140. kChromeUIDownloadsHost,
  1141. diff --git a/chrome/common/webui_url_constants.h b/chrome/common/webui_url_constants.h
  1142. --- a/chrome/common/webui_url_constants.h
  1143. +++ b/chrome/common/webui_url_constants.h
  1144. @@ -133,6 +133,8 @@ extern const char kChromeUIMemoryInternalsHost[];
  1145. extern const char kChromeUINTPTilesInternalsHost[];
  1146. extern const char kChromeUINaClHost[];
  1147. extern const char kChromeUINetExportHost[];
  1148. +extern const char kChromeUIProxyConfigHost[];
  1149. +extern const char kChromeUIProxyConfigURL[];
  1150. extern const char kChromeUINetInternalsHost[];
  1151. extern const char kChromeUINetInternalsURL[];
  1152. extern const char kChromeUINewTabHost[];
  1153. diff --git a/components/proxy_config/pref_proxy_config_tracker_impl.cc b/components/proxy_config/pref_proxy_config_tracker_impl.cc
  1154. --- a/components/proxy_config/pref_proxy_config_tracker_impl.cc
  1155. +++ b/components/proxy_config/pref_proxy_config_tracker_impl.cc
  1156. @@ -381,6 +381,7 @@ bool PrefProxyConfigTrackerImpl::PrefConfigToNetConfig(
  1157. if (proxy_dict.GetBypassList(&proxy_bypass)) {
  1158. proxy_config.proxy_rules().bypass_rules.ParseFromString(proxy_bypass);
  1159. }
  1160. + proxy_config.proxy_rules().reverse_bypass = proxy_dict.HasReverseBypass();
  1161. *config = net::ProxyConfigWithAnnotation(
  1162. proxy_config, kSettingsProxyConfigTrafficAnnotation);
  1163. return true;
  1164. diff --git a/components/proxy_config/proxy_config_dictionary.cc b/components/proxy_config/proxy_config_dictionary.cc
  1165. --- a/components/proxy_config/proxy_config_dictionary.cc
  1166. +++ b/components/proxy_config/proxy_config_dictionary.cc
  1167. @@ -30,6 +30,8 @@ const char kProxyPacMandatory[] = "pac_mandatory";
  1168. // String containing proxy bypass rules. For a specification of the
  1169. // expected syntax see net::ProxyBypassRules::ParseFromString().
  1170. const char kProxyBypassList[] = "bypass_list";
  1171. +// Boolean telling whether to reverse the meaning of the bypass list.
  1172. +const char kProxyReverseBypass[] = "reverse_bypass";
  1173. } // namespace
  1174. @@ -78,6 +80,14 @@ bool ProxyConfigDictionary::HasBypassList() const {
  1175. return dict_.FindKey(kProxyBypassList);
  1176. }
  1177. +bool ProxyConfigDictionary::HasReverseBypass() const {
  1178. + const base::Value* value = dict_.FindKey(kProxyReverseBypass);
  1179. + if (!value || !value->is_bool()) {
  1180. + return false;
  1181. + }
  1182. + return value->GetBool();
  1183. +}
  1184. +
  1185. const base::Value& ProxyConfigDictionary::GetDictionary() const {
  1186. return dict_;
  1187. }
  1188. @@ -85,29 +95,30 @@ const base::Value& ProxyConfigDictionary::GetDictionary() const {
  1189. // static
  1190. base::Value ProxyConfigDictionary::CreateDirect() {
  1191. return CreateDictionary(ProxyPrefs::MODE_DIRECT, std::string(), false,
  1192. - std::string(), std::string());
  1193. + std::string(), std::string(), false);
  1194. }
  1195. // static
  1196. base::Value ProxyConfigDictionary::CreateAutoDetect() {
  1197. return CreateDictionary(ProxyPrefs::MODE_AUTO_DETECT, std::string(), false,
  1198. - std::string(), std::string());
  1199. + std::string(), std::string(), false);
  1200. }
  1201. // static
  1202. base::Value ProxyConfigDictionary::CreatePacScript(const std::string& pac_url,
  1203. bool pac_mandatory) {
  1204. return CreateDictionary(ProxyPrefs::MODE_PAC_SCRIPT, pac_url, pac_mandatory,
  1205. - std::string(), std::string());
  1206. + std::string(), std::string(), false);
  1207. }
  1208. // static
  1209. base::Value ProxyConfigDictionary::CreateFixedServers(
  1210. const std::string& proxy_server,
  1211. - const std::string& bypass_list) {
  1212. + const std::string& bypass_list,
  1213. + bool reverse_bypass) {
  1214. if (!proxy_server.empty()) {
  1215. return CreateDictionary(ProxyPrefs::MODE_FIXED_SERVERS, std::string(),
  1216. - false, proxy_server, bypass_list);
  1217. + false, proxy_server, bypass_list, reverse_bypass);
  1218. } else {
  1219. return CreateDirect();
  1220. }
  1221. @@ -116,7 +127,7 @@ base::Value ProxyConfigDictionary::CreateFixedServers(
  1222. // static
  1223. base::Value ProxyConfigDictionary::CreateSystem() {
  1224. return CreateDictionary(ProxyPrefs::MODE_SYSTEM, std::string(), false,
  1225. - std::string(), std::string());
  1226. + std::string(), std::string(), false);
  1227. }
  1228. // static
  1229. @@ -125,7 +136,8 @@ base::Value ProxyConfigDictionary::CreateDictionary(
  1230. const std::string& pac_url,
  1231. bool pac_mandatory,
  1232. const std::string& proxy_server,
  1233. - const std::string& bypass_list) {
  1234. + const std::string& bypass_list,
  1235. + bool reverse_bypass) {
  1236. base::Value dict(base::Value::Type::DICTIONARY);
  1237. dict.SetKey(kProxyMode, base::Value(ProxyModeToString(mode)));
  1238. if (!pac_url.empty()) {
  1239. @@ -134,8 +146,10 @@ base::Value ProxyConfigDictionary::CreateDictionary(
  1240. }
  1241. if (!proxy_server.empty())
  1242. dict.SetKey(kProxyServer, base::Value(proxy_server));
  1243. - if (!bypass_list.empty())
  1244. + if (!bypass_list.empty()) {
  1245. dict.SetKey(kProxyBypassList, base::Value(bypass_list));
  1246. + dict.SetKey(kProxyReverseBypass, base::Value(reverse_bypass));
  1247. + }
  1248. return dict;
  1249. }
  1250. diff --git a/components/proxy_config/proxy_config_dictionary.h b/components/proxy_config/proxy_config_dictionary.h
  1251. --- a/components/proxy_config/proxy_config_dictionary.h
  1252. +++ b/components/proxy_config/proxy_config_dictionary.h
  1253. @@ -42,6 +42,7 @@ class PROXY_CONFIG_EXPORT ProxyConfigDictionary {
  1254. bool GetProxyServer(std::string* out) const;
  1255. bool GetBypassList(std::string* out) const;
  1256. bool HasBypassList() const;
  1257. + bool HasReverseBypass() const;
  1258. const base::Value& GetDictionary() const;
  1259. @@ -50,7 +51,8 @@ class PROXY_CONFIG_EXPORT ProxyConfigDictionary {
  1260. static base::Value CreatePacScript(const std::string& pac_url,
  1261. bool pac_mandatory);
  1262. static base::Value CreateFixedServers(const std::string& proxy_server,
  1263. - const std::string& bypass_list);
  1264. + const std::string& bypass_list,
  1265. + bool reverse_bypass);
  1266. static base::Value CreateSystem();
  1267. // Encodes the proxy server as "<url-scheme>=<proxy-scheme>://<proxy>".
  1268. @@ -66,7 +68,8 @@ class PROXY_CONFIG_EXPORT ProxyConfigDictionary {
  1269. const std::string& pac_url,
  1270. bool pac_mandatory,
  1271. const std::string& proxy_server,
  1272. - const std::string& bypass_list);
  1273. + const std::string& bypass_list,
  1274. + bool reverse_bypass);
  1275. base::Value dict_;
  1276. };
  1277. diff --git a/components/proxy_config/proxy_policy_handler.cc b/components/proxy_config/proxy_policy_handler.cc
  1278. --- a/components/proxy_config/proxy_policy_handler.cc
  1279. +++ b/components/proxy_config/proxy_policy_handler.cc
  1280. @@ -260,7 +260,7 @@ void ProxyPolicyHandler::ApplyPolicySettings(const PolicyMap& policies,
  1281. ProxyConfigDictionary::CreateFixedServers(
  1282. server->GetString(), bypass_list && bypass_list->is_string()
  1283. ? bypass_list->GetString()
  1284. - : std::string()));
  1285. + : std::string(), false));
  1286. }
  1287. break;
  1288. }
  1289. diff --git a/net/proxy_resolution/proxy_config.cc b/net/proxy_resolution/proxy_config.cc
  1290. --- a/net/proxy_resolution/proxy_config.cc
  1291. +++ b/net/proxy_resolution/proxy_config.cc
  1292. @@ -112,7 +112,7 @@ void ProxyConfig::ProxyRules::ParseFromString(const std::string& proxy_rules) {
  1293. &single_proxies,
  1294. ProxyServer::SCHEME_HTTP);
  1295. type = Type::PROXY_LIST;
  1296. - return;
  1297. + continue;
  1298. }
  1299. // Trim whitespace off the url scheme.
  1300. @@ -143,6 +143,56 @@ void ProxyConfig::ProxyRules::ParseFromString(const std::string& proxy_rules) {
  1301. }
  1302. }
  1303. +std::string ProxyConfig::ProxyRules::ToString() const {
  1304. + if (type == Type::EMPTY) {
  1305. + return "";
  1306. + }
  1307. +
  1308. + // special case: a single proxy servers list specified
  1309. + if (type == Type::PROXY_LIST) {
  1310. + std::string proxy_list;
  1311. + for (const ProxyServer& proxy_server :
  1312. + single_proxies.GetAll()) {
  1313. + proxy_list += ProxyServerToProxyUri(proxy_server) + ";";
  1314. + }
  1315. + // remove last semicolon
  1316. + if (proxy_list.length() != 0 ) {
  1317. + proxy_list.pop_back();
  1318. + }
  1319. + return proxy_list;
  1320. + }
  1321. +
  1322. + if (type != Type::PROXY_LIST_PER_SCHEME) {
  1323. + NOTREACHED();
  1324. + // Unexpected LIST with fallback, or other type values
  1325. + return "";
  1326. + }
  1327. +
  1328. + // start to build a per-scheme list
  1329. + std::string list;
  1330. + for (const ProxyServer& proxy_server :
  1331. + proxies_for_http.GetAll()) {
  1332. + list += "http=" + ProxyServerToProxyUri(proxy_server) + ";";
  1333. + }
  1334. + for (const ProxyServer& proxy_server :
  1335. + proxies_for_https.GetAll()) {
  1336. + list += "https=" + ProxyServerToProxyUri(proxy_server) + ";";
  1337. + }
  1338. + for (const ProxyServer& proxy_server :
  1339. + proxies_for_ftp.GetAll()) {
  1340. + list += "ftp=" + ProxyServerToProxyUri(proxy_server) + ";";
  1341. + }
  1342. + for (const ProxyServer& proxy_server :
  1343. + fallback_proxies.GetAll()) {
  1344. + list += "socks=" + ProxyServerToProxyUri(proxy_server) + ";";
  1345. + }
  1346. + if (list.length() != 0 ) {
  1347. + // remove last semicolon
  1348. + list.pop_back();
  1349. + }
  1350. + return list;
  1351. +}
  1352. +
  1353. const ProxyList* ProxyConfig::ProxyRules::MapUrlSchemeToProxyList(
  1354. const std::string& url_scheme) const {
  1355. const ProxyList* proxy_server_list = const_cast<ProxyRules*>(this)->
  1356. diff --git a/net/proxy_resolution/proxy_config.h b/net/proxy_resolution/proxy_config.h
  1357. --- a/net/proxy_resolution/proxy_config.h
  1358. +++ b/net/proxy_resolution/proxy_config.h
  1359. @@ -103,6 +103,9 @@ class NET_EXPORT ProxyConfig {
  1360. // and use socks4://foopy2 for all other
  1361. // URLs.
  1362. void ParseFromString(const std::string& proxy_rules);
  1363. + // Returns the proxy rules in a format that can be parsed by ParseFromString;
  1364. + // all information except bypass rules is used.
  1365. + std::string ToString() const;
  1366. // Returns one of {&proxies_for_http, &proxies_for_https, &proxies_for_ftp,
  1367. // &fallback_proxies}, or NULL if there is no proxy to use.
  1368. --
  1369. 2.25.1