blob: 62ad8e5185a8632f0b0468e75b26fe005b4323d6 [file] [log] [blame]
Avi Drissman64595482022-09-14 20:52:291// Copyright 2012 The Chromium Authors
[email protected]861c6c62009-04-20 16:50:562// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Lily Houghton582d4622018-01-22 22:43:405#include "net/proxy_resolution/proxy_config_service_linux.h"
[email protected]861c6c62009-04-20 16:50:566
[email protected]d7395e732009-08-28 23:13:437#include <errno.h>
[email protected]d7395e732009-08-28 23:13:438#include <limits.h>
[email protected]d7395e732009-08-28 23:13:439#include <sys/inotify.h>
10#include <unistd.h>
[email protected]861c6c62009-04-20 16:50:5611
[email protected]9bc8cff2010-04-03 01:05:3912#include <map>
Peter Boström08e7ed82021-04-19 17:49:5913#include <memory>
thestig0c412e852016-06-30 08:04:4014#include <utility>
[email protected]9bc8cff2010-04-03 01:05:3915
gabf4f904e2017-05-10 20:55:0216#include "base/files/file_descriptor_watcher_posix.h"
[email protected]57999812013-02-24 05:40:5217#include "base/files/file_path.h"
thestigd8df0332014-09-04 06:33:2918#include "base/files/file_util.h"
[email protected]b9b4a572014-03-17 23:11:1219#include "base/files/scoped_file.h"
Avi Drissman41c4a412023-01-11 22:45:3720#include "base/functional/bind.h"
[email protected]861c6c62009-04-20 16:50:5621#include "base/logging.h"
Eric Romancd032fb62018-05-18 21:40:1322#include "base/memory/ptr_util.h"
Keishi Hattorif28f4f82022-06-21 11:32:1523#include "base/memory/raw_ptr.h"
[email protected]3a29593d2011-04-11 10:07:5224#include "base/nix/xdg_util.h"
David Sandersde5fee542022-03-23 02:47:4425#include "base/observer_list.h"
[email protected]fc9be5802013-06-11 10:56:5126#include "base/strings/string_number_conversions.h"
Slava Aseev9ffd8a62022-05-25 07:09:0927#include "base/strings/string_split.h"
[email protected]f4ebe772013-02-02 00:21:3928#include "base/strings/string_tokenizer.h"
[email protected]66e96c42013-06-28 15:20:3129#include "base/strings/string_util.h"
Patrick Monette643cdf62021-10-15 19:13:4230#include "base/task/sequenced_task_runner.h"
31#include "base/task/single_thread_task_runner.h"
Gabriel Charette44db1422018-08-06 11:19:3332#include "base/task/task_traits.h"
Gabriel Charette99f5df32021-03-19 19:55:5533#include "base/task/thread_pool.h"
[email protected]9a8c4022011-01-25 14:25:3334#include "base/threading/thread_restrictions.h"
[email protected]66e96c42013-06-28 15:20:3135#include "base/timer/timer.h"
Lily Houghton582d4622018-01-22 22:43:4036#include "net/base/proxy_server.h"
Eric Orth5ccc3f02021-09-23 00:01:5737#include "net/base/proxy_string_util.h"
[email protected]861c6c62009-04-20 16:50:5638
[email protected]3fc24f52012-11-30 21:22:3439#if defined(USE_GIO)
Tim Brown1c307cc2017-12-08 02:40:3840#include <gio/gio.h>
[email protected]3fc24f52012-11-30 21:22:3441#endif // defined(USE_GIO)
42
[email protected]861c6c62009-04-20 16:50:5643namespace net {
44
Etienne Pierre-doray89272912022-11-07 22:35:3845class ScopedAllowBlockingForSettingGetter : public base::ScopedAllowBlocking {};
46
[email protected]861c6c62009-04-20 16:50:5647namespace {
48
Shimi Zhang13eace252020-01-31 01:49:1949// This turns all rules with a hostname into wildcard matches, which will
50// match not just the indicated hostname but also any hostname that ends with
51// it.
52void RewriteRulesForSuffixMatching(ProxyBypassRules* out) {
53 // Prepend a wildcard (*) to any hostname based rules, provided it isn't an IP
54 // address.
55 for (size_t i = 0; i < out->rules().size(); ++i) {
56 if (!out->rules()[i]->IsHostnamePatternRule())
57 continue;
58
59 const SchemeHostPortMatcherHostnamePatternRule* prev_rule =
60 static_cast<const SchemeHostPortMatcherHostnamePatternRule*>(
61 out->rules()[i].get());
62 out->ReplaceRule(i, prev_rule->GenerateSuffixMatchingRule());
63 }
64}
65
[email protected]861c6c62009-04-20 16:50:5666// Given a proxy hostname from a setting, returns that hostname with
67// an appropriate proxy server scheme prefix.
68// scheme indicates the desired proxy scheme: usually http, with
69// socks 4 or 5 as special cases.
[email protected]87a102b2009-07-14 05:23:3070// TODO(arindam): Remove URI string manipulation by using MapUrlSchemeToProxy.
[email protected]861c6c62009-04-20 16:50:5671std::string FixupProxyHostScheme(ProxyServer::Scheme scheme,
72 std::string host) {
[email protected]e8c50812010-09-28 00:16:1773 if (scheme == ProxyServer::SCHEME_SOCKS5 &&
brettw3a2c6902015-07-06 19:43:2974 base::StartsWith(host, "socks4://",
75 base::CompareCase::INSENSITIVE_ASCII)) {
[email protected]e8c50812010-09-28 00:16:1776 // We default to socks 5, but if the user specifically set it to
77 // socks4://, then use that.
78 scheme = ProxyServer::SCHEME_SOCKS4;
[email protected]861c6c62009-04-20 16:50:5679 }
80 // Strip the scheme if any.
81 std::string::size_type colon = host.find("://");
82 if (colon != std::string::npos)
83 host = host.substr(colon + 3);
84 // If a username and perhaps password are specified, give a warning.
85 std::string::size_type at_sign = host.find("@");
86 // Should this be supported?
87 if (at_sign != std::string::npos) {
[email protected]62749f182009-07-15 13:16:5488 // ProxyConfig does not support authentication parameters, but Chrome
89 // will prompt for the password later. Disregard the
90 // authentication parameters and continue with this hostname.
91 LOG(WARNING) << "Proxy authentication parameters ignored, see bug 16709";
[email protected]861c6c62009-04-20 16:50:5692 host = host.substr(at_sign + 1);
93 }
94 // If this is a socks proxy, prepend a scheme so as to tell
95 // ProxyServer. This also allows ProxyServer to choose the right
96 // default port.
97 if (scheme == ProxyServer::SCHEME_SOCKS4)
98 host = "socks4://" + host;
99 else if (scheme == ProxyServer::SCHEME_SOCKS5)
100 host = "socks5://" + host;
[email protected]d7395e732009-08-28 23:13:43101 // If there is a trailing slash, remove it so |host| will parse correctly
102 // even if it includes a port number (since the slash is not numeric).
pkasting9022cb42016-02-05 00:08:56103 if (!host.empty() && host.back() == '/')
[email protected]d7395e732009-08-28 23:13:43104 host.resize(host.length() - 1);
[email protected]861c6c62009-04-20 16:50:56105 return host;
106}
107
Ramin Halavatica8d5252018-03-12 05:33:49108ProxyConfigWithAnnotation GetConfigOrDirect(
Anton Bikineev068d2912021-05-15 20:43:52109 const absl::optional<ProxyConfigWithAnnotation>& optional_config) {
Eric Roman750af4b12018-02-22 22:38:53110 if (optional_config)
111 return optional_config.value();
112
Ramin Halavatica8d5252018-03-12 05:33:49113 ProxyConfigWithAnnotation config = ProxyConfigWithAnnotation::CreateDirect();
Eric Roman750af4b12018-02-22 22:38:53114 return config;
115}
116
[email protected]861c6c62009-04-20 16:50:56117} // namespace
118
Chris Watkins3a13f632017-12-04 00:41:15119ProxyConfigServiceLinux::Delegate::~Delegate() = default;
[email protected]8e1845e12010-09-15 19:22:24120
[email protected]3e44697f2009-05-22 14:37:39121bool ProxyConfigServiceLinux::Delegate::GetProxyFromEnvVarForScheme(
thestig0c412e852016-06-30 08:04:40122 base::StringPiece variable,
123 ProxyServer::Scheme scheme,
[email protected]861c6c62009-04-20 16:50:56124 ProxyServer* result_server) {
125 std::string env_value;
thestig0c412e852016-06-30 08:04:40126 if (!env_var_getter_->GetVar(variable, &env_value))
127 return false;
128
129 if (env_value.empty())
130 return false;
131
132 env_value = FixupProxyHostScheme(scheme, env_value);
133 ProxyServer proxy_server =
Eric Orth5ccc3f02021-09-23 00:01:57134 ProxyUriToProxyServer(env_value, ProxyServer::SCHEME_HTTP);
thestig0c412e852016-06-30 08:04:40135 if (proxy_server.is_valid() && !proxy_server.is_direct()) {
136 *result_server = proxy_server;
137 return true;
[email protected]861c6c62009-04-20 16:50:56138 }
thestig0c412e852016-06-30 08:04:40139 LOG(ERROR) << "Failed to parse environment variable " << variable;
[email protected]861c6c62009-04-20 16:50:56140 return false;
141}
142
[email protected]3e44697f2009-05-22 14:37:39143bool ProxyConfigServiceLinux::Delegate::GetProxyFromEnvVar(
thestig0c412e852016-06-30 08:04:40144 base::StringPiece variable,
145 ProxyServer* result_server) {
[email protected]861c6c62009-04-20 16:50:56146 return GetProxyFromEnvVarForScheme(variable, ProxyServer::SCHEME_HTTP,
147 result_server);
148}
149
Anton Bikineev068d2912021-05-15 20:43:52150absl::optional<ProxyConfigWithAnnotation>
Eric Roman750af4b12018-02-22 22:38:53151ProxyConfigServiceLinux::Delegate::GetConfigFromEnv() {
Ramin Halavatica8d5252018-03-12 05:33:49152 ProxyConfig config;
Eric Roman750af4b12018-02-22 22:38:53153
[email protected]861c6c62009-04-20 16:50:56154 // Check for automatic configuration first, in
155 // "auto_proxy". Possibly only the "environment_proxy" firefox
156 // extension has ever used this, but it still sounds like a good
157 // idea.
158 std::string auto_proxy;
[email protected]3ba7e082010-08-07 02:57:59159 if (env_var_getter_->GetVar("auto_proxy", &auto_proxy)) {
[email protected]861c6c62009-04-20 16:50:56160 if (auto_proxy.empty()) {
161 // Defined and empty => autodetect
Ramin Halavatica8d5252018-03-12 05:33:49162 config.set_auto_detect(true);
[email protected]861c6c62009-04-20 16:50:56163 } else {
164 // specified autoconfig URL
Ramin Halavatica8d5252018-03-12 05:33:49165 config.set_pac_url(GURL(auto_proxy));
[email protected]861c6c62009-04-20 16:50:56166 }
Ramin Halavatica8d5252018-03-12 05:33:49167 return ProxyConfigWithAnnotation(
168 config, NetworkTrafficAnnotationTag(traffic_annotation_));
[email protected]861c6c62009-04-20 16:50:56169 }
170 // "all_proxy" is a shortcut to avoid defining {http,https,ftp}_proxy.
171 ProxyServer proxy_server;
172 if (GetProxyFromEnvVar("all_proxy", &proxy_server)) {
Ramin Halavatica8d5252018-03-12 05:33:49173 config.proxy_rules().type = ProxyConfig::ProxyRules::Type::PROXY_LIST;
174 config.proxy_rules().single_proxies.SetSingleProxyServer(proxy_server);
[email protected]861c6c62009-04-20 16:50:56175 } else {
176 bool have_http = GetProxyFromEnvVar("http_proxy", &proxy_server);
177 if (have_http)
Ramin Halavatica8d5252018-03-12 05:33:49178 config.proxy_rules().proxies_for_http.SetSingleProxyServer(proxy_server);
[email protected]861c6c62009-04-20 16:50:56179 // It would be tempting to let http_proxy apply for all protocols
180 // if https_proxy and ftp_proxy are not defined. Googling turns up
181 // several documents that mention only http_proxy. But then the
182 // user really might not want to proxy https. And it doesn't seem
183 // like other apps do this. So we will refrain.
184 bool have_https = GetProxyFromEnvVar("https_proxy", &proxy_server);
185 if (have_https)
Ramin Halavatica8d5252018-03-12 05:33:49186 config.proxy_rules().proxies_for_https.SetSingleProxyServer(proxy_server);
[email protected]861c6c62009-04-20 16:50:56187 bool have_ftp = GetProxyFromEnvVar("ftp_proxy", &proxy_server);
188 if (have_ftp)
Ramin Halavatica8d5252018-03-12 05:33:49189 config.proxy_rules().proxies_for_ftp.SetSingleProxyServer(proxy_server);
[email protected]861c6c62009-04-20 16:50:56190 if (have_http || have_https || have_ftp) {
191 // mustn't change type unless some rules are actually set.
Ramin Halavatica8d5252018-03-12 05:33:49192 config.proxy_rules().type =
Lily Houghtone6b617e2018-01-19 20:13:07193 ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME;
[email protected]861c6c62009-04-20 16:50:56194 }
195 }
Ramin Halavatica8d5252018-03-12 05:33:49196 if (config.proxy_rules().empty()) {
[email protected]861c6c62009-04-20 16:50:56197 // If the above were not defined, try for socks.
[email protected]e8c50812010-09-28 00:16:17198 // For environment variables, we default to version 5, per the gnome
199 // documentation: http://library.gnome.org/devel/gnet/stable/gnet-socks.html
200 ProxyServer::Scheme scheme = ProxyServer::SCHEME_SOCKS5;
[email protected]861c6c62009-04-20 16:50:56201 std::string env_version;
[email protected]3ba7e082010-08-07 02:57:59202 if (env_var_getter_->GetVar("SOCKS_VERSION", &env_version)
[email protected]e8c50812010-09-28 00:16:17203 && env_version == "4")
204 scheme = ProxyServer::SCHEME_SOCKS4;
[email protected]861c6c62009-04-20 16:50:56205 if (GetProxyFromEnvVarForScheme("SOCKS_SERVER", scheme, &proxy_server)) {
Ramin Halavatica8d5252018-03-12 05:33:49206 config.proxy_rules().type = ProxyConfig::ProxyRules::Type::PROXY_LIST;
207 config.proxy_rules().single_proxies.SetSingleProxyServer(proxy_server);
[email protected]861c6c62009-04-20 16:50:56208 }
209 }
210 // Look for the proxy bypass list.
211 std::string no_proxy;
[email protected]3ba7e082010-08-07 02:57:59212 env_var_getter_->GetVar("no_proxy", &no_proxy);
Ramin Halavatica8d5252018-03-12 05:33:49213 if (config.proxy_rules().empty()) {
[email protected]861c6c62009-04-20 16:50:56214 // Having only "no_proxy" set, presumably to "*", makes it
215 // explicit that env vars do specify a configuration: having no
216 // rules specified only means the user explicitly asks for direct
217 // connections.
Ramin Halavatica8d5252018-03-12 05:33:49218 return !no_proxy.empty()
219 ? ProxyConfigWithAnnotation(
220 config, NetworkTrafficAnnotationTag(traffic_annotation_))
Anton Bikineev068d2912021-05-15 20:43:52221 : absl::optional<ProxyConfigWithAnnotation>();
[email protected]861c6c62009-04-20 16:50:56222 }
[email protected]7541206c2010-02-19 20:24:06223 // Note that this uses "suffix" matching. So a bypass of "google.com"
224 // is understood to mean a bypass of "*google.com".
Shimi Zhang13eace252020-01-31 01:49:19225 config.proxy_rules().bypass_rules.ParseFromString(no_proxy);
226 RewriteRulesForSuffixMatching(&config.proxy_rules().bypass_rules);
227
Ramin Halavatica8d5252018-03-12 05:33:49228 return ProxyConfigWithAnnotation(
229 config, NetworkTrafficAnnotationTag(traffic_annotation_));
[email protected]861c6c62009-04-20 16:50:56230}
231
232namespace {
233
[email protected]d7395e732009-08-28 23:13:43234const int kDebounceTimeoutMilliseconds = 250;
[email protected]3e44697f2009-05-22 14:37:39235
[email protected]8c20e3d2011-05-19 21:03:57236#if defined(USE_GIO)
Tim Brown1c307cc2017-12-08 02:40:38237const char kProxyGSettingsSchema[] = "org.gnome.system.proxy";
[email protected]2297bb22014-06-19 06:30:14238
[email protected]8c20e3d2011-05-19 21:03:57239// This setting getter uses gsettings, as used in most GNOME 3 desktops.
240class SettingGetterImplGSettings
241 : public ProxyConfigServiceLinux::SettingGetter {
242 public:
Tsuyoshi Horof8861cb2022-07-05 23:50:20243 SettingGetterImplGSettings()
244 : debounce_timer_(std::make_unique<base::OneShotTimer>()) {}
[email protected]8c20e3d2011-05-19 21:03:57245
Peter Boström293b1342021-09-22 17:31:43246 SettingGetterImplGSettings(const SettingGetterImplGSettings&) = delete;
247 SettingGetterImplGSettings& operator=(const SettingGetterImplGSettings&) =
248 delete;
249
dcheng67be2b1f2014-10-27 21:47:29250 ~SettingGetterImplGSettings() override {
[email protected]8c20e3d2011-05-19 21:03:57251 // client_ should have been released before now, from
252 // Delegate::OnDestroy(), while running on the UI thread. However
253 // on exiting the process, it may happen that
254 // Delegate::OnDestroy() task is left pending on the glib loop
255 // after the loop was quit, and pending tasks may then be deleted
256 // without being run.
257 if (client_) {
Tim Brown2a19f3b2017-12-12 01:08:40258 // gsettings client was not cleaned up.
eroman0070d412017-06-22 22:18:24259 if (task_runner_->RunsTasksInCurrentSequence()) {
Mostyn Bramley-Moore699c5312018-05-01 10:48:09260 // We are on the UI thread so we can clean it safely.
[email protected]8c20e3d2011-05-19 21:03:57261 VLOG(1) << "~SettingGetterImplGSettings: releasing gsettings client";
262 ShutDown();
263 } else {
264 LOG(WARNING) << "~SettingGetterImplGSettings: leaking gsettings client";
thestig0c412e852016-06-30 08:04:40265 client_ = nullptr;
[email protected]8c20e3d2011-05-19 21:03:57266 }
267 }
268 DCHECK(!client_);
[email protected]8c20e3d2011-05-19 21:03:57269 }
270
Tim Brown1c307cc2017-12-08 02:40:38271 // CheckVersion() must be called *before* Init()!
272 bool CheckVersion(base::Environment* env);
[email protected]8c20e3d2011-05-19 21:03:57273
eroman0070d412017-06-22 22:18:24274 bool Init(const scoped_refptr<base::SingleThreadTaskRunner>& glib_task_runner)
mostynbba063d6032014-10-09 11:01:13275 override {
eroman0070d412017-06-22 22:18:24276 DCHECK(glib_task_runner->RunsTasksInCurrentSequence());
[email protected]8c20e3d2011-05-19 21:03:57277 DCHECK(!client_);
[email protected]90499482013-06-01 00:39:50278 DCHECK(!task_runner_.get());
[email protected]4cf80f0b2011-05-20 20:30:26279
Tim Brown1c307cc2017-12-08 02:40:38280 if (!g_settings_schema_source_lookup(g_settings_schema_source_get_default(),
Jan-Michael Brummer12854ff2022-10-16 18:57:09281 kProxyGSettingsSchema, TRUE) ||
Tim Brown1c307cc2017-12-08 02:40:38282 !(client_ = g_settings_new(kProxyGSettingsSchema))) {
[email protected]8c20e3d2011-05-19 21:03:57283 // It's not clear whether/when this can return NULL.
284 LOG(ERROR) << "Unable to create a gsettings client";
285 return false;
286 }
sergeyu3f923062014-09-05 01:39:40287 task_runner_ = glib_task_runner;
[email protected]8c20e3d2011-05-19 21:03:57288 // We assume these all work if the above call worked.
Tim Brown1c307cc2017-12-08 02:40:38289 http_client_ = g_settings_get_child(client_, "http");
290 https_client_ = g_settings_get_child(client_, "https");
291 ftp_client_ = g_settings_get_child(client_, "ftp");
292 socks_client_ = g_settings_get_child(client_, "socks");
[email protected]8c20e3d2011-05-19 21:03:57293 DCHECK(http_client_ && https_client_ && ftp_client_ && socks_client_);
294 return true;
295 }
296
dcheng67be2b1f2014-10-27 21:47:29297 void ShutDown() override {
[email protected]8c20e3d2011-05-19 21:03:57298 if (client_) {
eroman0070d412017-06-22 22:18:24299 DCHECK(task_runner_->RunsTasksInCurrentSequence());
[email protected]8c20e3d2011-05-19 21:03:57300 // This also disables gsettings notifications.
301 g_object_unref(socks_client_);
302 g_object_unref(ftp_client_);
303 g_object_unref(https_client_);
304 g_object_unref(http_client_);
305 g_object_unref(client_);
306 // We only need to null client_ because it's the only one that we check.
thestig0c412e852016-06-30 08:04:40307 client_ = nullptr;
308 task_runner_ = nullptr;
[email protected]8c20e3d2011-05-19 21:03:57309 }
marshall8e5fe942015-03-06 19:22:40310 debounce_timer_.reset();
[email protected]8c20e3d2011-05-19 21:03:57311 }
312
dcheng67be2b1f2014-10-27 21:47:29313 bool SetUpNotifications(
mostynbba063d6032014-10-09 11:01:13314 ProxyConfigServiceLinux::Delegate* delegate) override {
[email protected]8c20e3d2011-05-19 21:03:57315 DCHECK(client_);
eroman0070d412017-06-22 22:18:24316 DCHECK(task_runner_->RunsTasksInCurrentSequence());
[email protected]8c20e3d2011-05-19 21:03:57317 notify_delegate_ = delegate;
318 // We could watch for the change-event signal instead of changed, but
319 // since we have to watch more than one object, we'd still have to
320 // debounce change notifications. This is conceptually simpler.
Keishi Hattorif28f4f82022-06-21 11:32:15321 g_signal_connect(G_OBJECT(client_.get()), "changed",
[email protected]8c20e3d2011-05-19 21:03:57322 G_CALLBACK(OnGSettingsChangeNotification), this);
Keishi Hattorif28f4f82022-06-21 11:32:15323 g_signal_connect(G_OBJECT(http_client_.get()), "changed",
[email protected]8c20e3d2011-05-19 21:03:57324 G_CALLBACK(OnGSettingsChangeNotification), this);
Keishi Hattorif28f4f82022-06-21 11:32:15325 g_signal_connect(G_OBJECT(https_client_.get()), "changed",
[email protected]8c20e3d2011-05-19 21:03:57326 G_CALLBACK(OnGSettingsChangeNotification), this);
Keishi Hattorif28f4f82022-06-21 11:32:15327 g_signal_connect(G_OBJECT(ftp_client_.get()), "changed",
[email protected]8c20e3d2011-05-19 21:03:57328 G_CALLBACK(OnGSettingsChangeNotification), this);
Keishi Hattorif28f4f82022-06-21 11:32:15329 g_signal_connect(G_OBJECT(socks_client_.get()), "changed",
[email protected]8c20e3d2011-05-19 21:03:57330 G_CALLBACK(OnGSettingsChangeNotification), this);
331 // Simulate a change to avoid possibly losing updates before this point.
332 OnChangeNotification();
333 return true;
334 }
335
eroman0070d412017-06-22 22:18:24336 const scoped_refptr<base::SequencedTaskRunner>& GetNotificationTaskRunner()
dcheng67be2b1f2014-10-27 21:47:29337 override {
sergeyu3f923062014-09-05 01:39:40338 return task_runner_;
[email protected]8c20e3d2011-05-19 21:03:57339 }
340
dcheng67be2b1f2014-10-27 21:47:29341 bool GetString(StringSetting key, std::string* result) override {
[email protected]8c20e3d2011-05-19 21:03:57342 DCHECK(client_);
343 switch (key) {
344 case PROXY_MODE:
345 return GetStringByPath(client_, "mode", result);
346 case PROXY_AUTOCONF_URL:
347 return GetStringByPath(client_, "autoconfig-url", result);
348 case PROXY_HTTP_HOST:
349 return GetStringByPath(http_client_, "host", result);
350 case PROXY_HTTPS_HOST:
351 return GetStringByPath(https_client_, "host", result);
352 case PROXY_FTP_HOST:
353 return GetStringByPath(ftp_client_, "host", result);
354 case PROXY_SOCKS_HOST:
355 return GetStringByPath(socks_client_, "host", result);
[email protected]8c20e3d2011-05-19 21:03:57356 }
[email protected]6b5fe742011-05-20 21:46:48357 return false; // Placate compiler.
[email protected]8c20e3d2011-05-19 21:03:57358 }
dcheng67be2b1f2014-10-27 21:47:29359 bool GetBool(BoolSetting key, bool* result) override {
[email protected]8c20e3d2011-05-19 21:03:57360 DCHECK(client_);
361 switch (key) {
362 case PROXY_USE_HTTP_PROXY:
363 // Although there is an "enabled" boolean in http_client_, it is not set
364 // to true by the proxy config utility. We ignore it and return false.
365 return false;
366 case PROXY_USE_SAME_PROXY:
367 // Similarly, although there is a "use-same-proxy" boolean in client_,
368 // it is never set to false by the proxy config utility. We ignore it.
369 return false;
370 case PROXY_USE_AUTHENTICATION:
371 // There is also no way to set this in the proxy config utility, but it
372 // doesn't hurt us to get the actual setting (unlike the two above).
373 return GetBoolByPath(http_client_, "use-authentication", result);
[email protected]8c20e3d2011-05-19 21:03:57374 }
[email protected]6b5fe742011-05-20 21:46:48375 return false; // Placate compiler.
[email protected]8c20e3d2011-05-19 21:03:57376 }
dcheng67be2b1f2014-10-27 21:47:29377 bool GetInt(IntSetting key, int* result) override {
[email protected]8c20e3d2011-05-19 21:03:57378 DCHECK(client_);
379 switch (key) {
380 case PROXY_HTTP_PORT:
381 return GetIntByPath(http_client_, "port", result);
382 case PROXY_HTTPS_PORT:
383 return GetIntByPath(https_client_, "port", result);
384 case PROXY_FTP_PORT:
385 return GetIntByPath(ftp_client_, "port", result);
386 case PROXY_SOCKS_PORT:
387 return GetIntByPath(socks_client_, "port", result);
[email protected]8c20e3d2011-05-19 21:03:57388 }
[email protected]6b5fe742011-05-20 21:46:48389 return false; // Placate compiler.
[email protected]8c20e3d2011-05-19 21:03:57390 }
dcheng67be2b1f2014-10-27 21:47:29391 bool GetStringList(StringListSetting key,
392 std::vector<std::string>* result) override {
[email protected]8c20e3d2011-05-19 21:03:57393 DCHECK(client_);
394 switch (key) {
395 case PROXY_IGNORE_HOSTS:
396 return GetStringListByPath(client_, "ignore-hosts", result);
[email protected]8c20e3d2011-05-19 21:03:57397 }
[email protected]6b5fe742011-05-20 21:46:48398 return false; // Placate compiler.
[email protected]8c20e3d2011-05-19 21:03:57399 }
400
dcheng67be2b1f2014-10-27 21:47:29401 bool BypassListIsReversed() override {
[email protected]8c20e3d2011-05-19 21:03:57402 // This is a KDE-specific setting.
403 return false;
404 }
405
Shimi Zhang13eace252020-01-31 01:49:19406 bool UseSuffixMatching() override { return false; }
[email protected]8c20e3d2011-05-19 21:03:57407
408 private:
thestig0c412e852016-06-30 08:04:40409 bool GetStringByPath(GSettings* client,
410 base::StringPiece key,
[email protected]8c20e3d2011-05-19 21:03:57411 std::string* result) {
eroman0070d412017-06-22 22:18:24412 DCHECK(task_runner_->RunsTasksInCurrentSequence());
Tim Brown1c307cc2017-12-08 02:40:38413 gchar* value = g_settings_get_string(client, key.data());
[email protected]8c20e3d2011-05-19 21:03:57414 if (!value)
415 return false;
416 *result = value;
417 g_free(value);
418 return true;
419 }
thestig0c412e852016-06-30 08:04:40420 bool GetBoolByPath(GSettings* client, base::StringPiece key, bool* result) {
eroman0070d412017-06-22 22:18:24421 DCHECK(task_runner_->RunsTasksInCurrentSequence());
Tim Brown1c307cc2017-12-08 02:40:38422 *result = static_cast<bool>(g_settings_get_boolean(client, key.data()));
[email protected]8c20e3d2011-05-19 21:03:57423 return true;
424 }
thestig0c412e852016-06-30 08:04:40425 bool GetIntByPath(GSettings* client, base::StringPiece key, int* result) {
eroman0070d412017-06-22 22:18:24426 DCHECK(task_runner_->RunsTasksInCurrentSequence());
Tim Brown1c307cc2017-12-08 02:40:38427 *result = g_settings_get_int(client, key.data());
[email protected]8c20e3d2011-05-19 21:03:57428 return true;
429 }
thestig0c412e852016-06-30 08:04:40430 bool GetStringListByPath(GSettings* client,
431 base::StringPiece key,
[email protected]8c20e3d2011-05-19 21:03:57432 std::vector<std::string>* result) {
eroman0070d412017-06-22 22:18:24433 DCHECK(task_runner_->RunsTasksInCurrentSequence());
Tim Brown1c307cc2017-12-08 02:40:38434 gchar** list = g_settings_get_strv(client, key.data());
[email protected]8c20e3d2011-05-19 21:03:57435 if (!list)
436 return false;
437 for (size_t i = 0; list[i]; ++i) {
438 result->push_back(static_cast<char*>(list[i]));
439 g_free(list[i]);
440 }
441 g_free(list);
442 return true;
443 }
444
445 // This is the callback from the debounce timer.
446 void OnDebouncedNotification() {
eroman0070d412017-06-22 22:18:24447 DCHECK(task_runner_->RunsTasksInCurrentSequence());
[email protected]8c20e3d2011-05-19 21:03:57448 CHECK(notify_delegate_);
449 // Forward to a method on the proxy config service delegate object.
450 notify_delegate_->OnCheckProxyConfigSettings();
451 }
452
453 void OnChangeNotification() {
454 // We don't use Reset() because the timer may not yet be running.
455 // (In that case Stop() is a no-op.)
marshall8e5fe942015-03-06 19:22:40456 debounce_timer_->Stop();
Peter Kastinge5a38ed2021-10-02 03:06:35457 debounce_timer_->Start(
458 FROM_HERE, base::Milliseconds(kDebounceTimeoutMilliseconds), this,
459 &SettingGetterImplGSettings::OnDebouncedNotification);
[email protected]8c20e3d2011-05-19 21:03:57460 }
461
462 // gsettings notification callback, dispatched on the default glib main loop.
463 static void OnGSettingsChangeNotification(GSettings* client, gchar* key,
464 gpointer user_data) {
465 VLOG(1) << "gsettings change notification for key " << key;
466 // We don't track which key has changed, just that something did change.
467 SettingGetterImplGSettings* setting_getter =
468 reinterpret_cast<SettingGetterImplGSettings*>(user_data);
469 setting_getter->OnChangeNotification();
470 }
471
Keishi Hattorif28f4f82022-06-21 11:32:15472 raw_ptr<GSettings> client_ = nullptr;
473 raw_ptr<GSettings> http_client_ = nullptr;
474 raw_ptr<GSettings> https_client_ = nullptr;
475 raw_ptr<GSettings> ftp_client_ = nullptr;
476 raw_ptr<GSettings> socks_client_ = nullptr;
477 raw_ptr<ProxyConfigServiceLinux::Delegate> notify_delegate_ = nullptr;
danakj8a98ca22016-04-16 02:47:36478 std::unique_ptr<base::OneShotTimer> debounce_timer_;
[email protected]8c20e3d2011-05-19 21:03:57479
[email protected]76722472012-05-24 08:26:46480 // Task runner for the thread that we make gsettings calls on. It should
[email protected]8c20e3d2011-05-19 21:03:57481 // be the UI thread and all our methods should be called on this
482 // thread. Only for assertions.
eroman0070d412017-06-22 22:18:24483 scoped_refptr<base::SequencedTaskRunner> task_runner_;
[email protected]8c20e3d2011-05-19 21:03:57484};
485
Tim Brown1c307cc2017-12-08 02:40:38486bool SettingGetterImplGSettings::CheckVersion(
[email protected]8c20e3d2011-05-19 21:03:57487 base::Environment* env) {
Tim Brown1c307cc2017-12-08 02:40:38488 // CheckVersion() must be called *before* Init()!
[email protected]8c20e3d2011-05-19 21:03:57489 DCHECK(!client_);
490
thestig0c412e852016-06-30 08:04:40491 GSettings* client = nullptr;
Tim Brown1c307cc2017-12-08 02:40:38492 if (g_settings_schema_source_lookup(g_settings_schema_source_get_default(),
Jan-Michael Brummer12854ff2022-10-16 18:57:09493 kProxyGSettingsSchema, TRUE)) {
Tim Brown1c307cc2017-12-08 02:40:38494 client = g_settings_new(kProxyGSettingsSchema);
[email protected]4bbb72d2014-06-06 18:05:51495 }
496 if (!client) {
Tim Brown2a19f3b2017-12-12 01:08:40497 VLOG(1) << "Cannot create gsettings client.";
[email protected]8c20e3d2011-05-19 21:03:57498 return false;
499 }
500 g_object_unref(client);
501
[email protected]8c20e3d2011-05-19 21:03:57502 VLOG(1) << "All gsettings tests OK. Will get proxy config from gsettings.";
503 return true;
504}
505#endif // defined(USE_GIO)
506
eromane44498c2017-06-30 00:02:37507// Converts |value| from a decimal string to an int. If there was a failure
508// parsing, returns |default_value|.
509int StringToIntOrDefault(base::StringPiece value, int default_value) {
510 int result;
511 if (base::StringToInt(value, &result))
512 return result;
513 return default_value;
514}
515
Tim Brown2a19f3b2017-12-12 01:08:40516// This is the KDE version that reads kioslaverc and simulates gsettings.
[email protected]d7395e732009-08-28 23:13:43517// Doing this allows the main Delegate code, as well as the unit tests
518// for it, to stay the same - and the settings map fairly well besides.
gabf4f904e2017-05-10 20:55:02519class SettingGetterImplKDE : public ProxyConfigServiceLinux::SettingGetter {
[email protected]d7395e732009-08-28 23:13:43520 public:
[email protected]573c0502011-05-17 22:19:50521 explicit SettingGetterImplKDE(base::Environment* env_var_getter)
Tsuyoshi Horof8861cb2022-07-05 23:50:20522 : debounce_timer_(std::make_unique<base::OneShotTimer>()),
Tsuyoshi Horo432981d52022-06-09 09:50:13523 env_var_getter_(env_var_getter) {
[email protected]9a8c4022011-01-25 14:25:33524 // This has to be called on the UI thread (http://crbug.com/69057).
Etienne Pierre-doray89272912022-11-07 22:35:38525 ScopedAllowBlockingForSettingGetter allow_blocking;
[email protected]9a8c4022011-01-25 14:25:33526
Slava Aseev9ffd8a62022-05-25 07:09:09527 // Derive the location(s) of the kde config dir from the environment.
[email protected]92d2dc82010-04-08 17:49:59528 std::string home;
[email protected]3ba7e082010-08-07 02:57:59529 if (env_var_getter->GetVar("KDEHOME", &home) && !home.empty()) {
[email protected]2e8cfe22010-06-12 00:26:24530 // $KDEHOME is set. Use it unconditionally.
Slava Aseev9ffd8a62022-05-25 07:09:09531 kde_config_dirs_.emplace_back(KDEHomeToConfigPath(base::FilePath(home)));
[email protected]92d2dc82010-04-08 17:49:59532 } else {
[email protected]2e8cfe22010-06-12 00:26:24533 // $KDEHOME is unset. Try to figure out what to use. This seems to be
[email protected]92d2dc82010-04-08 17:49:59534 // the common case on most distributions.
[email protected]3ba7e082010-08-07 02:57:59535 if (!env_var_getter->GetVar(base::env_vars::kHome, &home))
[email protected]d7395e732009-08-28 23:13:43536 // User has no $HOME? Give up. Later we'll report the failure.
537 return;
[email protected]6b0349ef2010-10-16 04:56:06538 if (base::nix::GetDesktopEnvironment(env_var_getter) ==
539 base::nix::DESKTOP_ENVIRONMENT_KDE3) {
[email protected]92d2dc82010-04-08 17:49:59540 // KDE3 always uses .kde for its configuration.
[email protected]6cdfd7f2013-02-08 20:40:15541 base::FilePath kde_path = base::FilePath(home).Append(".kde");
Slava Aseev9ffd8a62022-05-25 07:09:09542 kde_config_dirs_.emplace_back(KDEHomeToConfigPath(kde_path));
edward.baker53bec302015-10-02 16:57:49543 } else if (base::nix::GetDesktopEnvironment(env_var_getter) ==
544 base::nix::DESKTOP_ENVIRONMENT_KDE4) {
[email protected]92d2dc82010-04-08 17:49:59545 // Some distributions patch KDE4 to use .kde4 instead of .kde, so that
[email protected]fad9c8a52010-06-10 22:30:53546 // both can be installed side-by-side. Sadly they don't all do this, and
547 // they don't always do this: some distributions have started switching
548 // back as well. So if there is a .kde4 directory, check the timestamps
549 // of the config directories within and use the newest one.
[email protected]92d2dc82010-04-08 17:49:59550 // Note that we should currently be running in the UI thread, because in
Tim Brown2a19f3b2017-12-12 01:08:40551 // the gsettings version, that is the only thread that can access the
552 // proxy settings (a gsettings restriction). As noted below, the initial
553 // read of the proxy settings will be done in this thread anyway, so we
554 // check for .kde4 here in this thread as well.
[email protected]6cdfd7f2013-02-08 20:40:15555 base::FilePath kde3_path = base::FilePath(home).Append(".kde");
556 base::FilePath kde3_config = KDEHomeToConfigPath(kde3_path);
557 base::FilePath kde4_path = base::FilePath(home).Append(".kde4");
558 base::FilePath kde4_config = KDEHomeToConfigPath(kde4_path);
[email protected]fad9c8a52010-06-10 22:30:53559 bool use_kde4 = false;
[email protected]dcd16612013-07-15 20:18:09560 if (base::DirectoryExists(kde4_path)) {
[email protected]54124ed02014-01-07 10:06:58561 base::File::Info kde3_info;
562 base::File::Info kde4_info;
[email protected]9eae4e62013-12-04 20:56:49563 if (base::GetFileInfo(kde4_config, &kde4_info)) {
564 if (base::GetFileInfo(kde3_config, &kde3_info)) {
[email protected]fad9c8a52010-06-10 22:30:53565 use_kde4 = kde4_info.last_modified >= kde3_info.last_modified;
566 } else {
567 use_kde4 = true;
568 }
569 }
570 }
571 if (use_kde4) {
Slava Aseev9ffd8a62022-05-25 07:09:09572 kde_config_dirs_.emplace_back(KDEHomeToConfigPath(kde4_path));
[email protected]92d2dc82010-04-08 17:49:59573 } else {
Slava Aseev9ffd8a62022-05-25 07:09:09574 kde_config_dirs_.emplace_back(KDEHomeToConfigPath(kde3_path));
[email protected]92d2dc82010-04-08 17:49:59575 }
edward.baker53bec302015-10-02 16:57:49576 } else {
577 // KDE 5 migrated to ~/.config for storing kioslaverc.
Slava Aseev9ffd8a62022-05-25 07:09:09578 kde_config_dirs_.emplace_back(base::FilePath(home).Append(".config"));
579
580 // kioslaverc also can be stored in any of XDG_CONFIG_DIRS
581 std::string config_dirs;
582 if (env_var_getter_->GetVar("XDG_CONFIG_DIRS", &config_dirs)) {
583 auto dirs = base::SplitString(config_dirs, ":", base::KEEP_WHITESPACE,
584 base::SPLIT_WANT_NONEMPTY);
585 for (const auto& dir : dirs) {
586 kde_config_dirs_.emplace_back(dir);
587 }
588 }
589
590 // Reverses the order of paths to store them in ascending order of
591 // priority
592 std::reverse(kde_config_dirs_.begin(), kde_config_dirs_.end());
[email protected]92d2dc82010-04-08 17:49:59593 }
[email protected]d7395e732009-08-28 23:13:43594 }
[email protected]d7395e732009-08-28 23:13:43595 }
596
Peter Boström293b1342021-09-22 17:31:43597 SettingGetterImplKDE(const SettingGetterImplKDE&) = delete;
598 SettingGetterImplKDE& operator=(const SettingGetterImplKDE&) = delete;
599
dcheng67be2b1f2014-10-27 21:47:29600 ~SettingGetterImplKDE() override {
[email protected]d7395e732009-08-28 23:13:43601 // inotify_fd_ should have been closed before now, from
602 // Delegate::OnDestroy(), while running on the file thread. However
603 // on exiting the process, it may happen that Delegate::OnDestroy()
604 // task is left pending on the file loop after the loop was quit,
605 // and pending tasks may then be deleted without being run.
606 // Here in the KDE version, we can safely close the file descriptor
607 // anyway. (Not that it really matters; the process is exiting.)
608 if (inotify_fd_ >= 0)
[email protected]d3066142011-05-10 02:36:20609 ShutDown();
thestig0c412e852016-06-30 08:04:40610 DCHECK_LT(inotify_fd_, 0);
[email protected]d7395e732009-08-28 23:13:43611 }
612
eroman0070d412017-06-22 22:18:24613 bool Init(const scoped_refptr<base::SingleThreadTaskRunner>& glib_task_runner)
mostynbba063d6032014-10-09 11:01:13614 override {
[email protected]9a8c4022011-01-25 14:25:33615 // This has to be called on the UI thread (http://crbug.com/69057).
Etienne Pierre-doray89272912022-11-07 22:35:38616 ScopedAllowBlockingForSettingGetter allow_blocking;
thestig0c412e852016-06-30 08:04:40617 DCHECK_LT(inotify_fd_, 0);
[email protected]d7395e732009-08-28 23:13:43618 inotify_fd_ = inotify_init();
619 if (inotify_fd_ < 0) {
[email protected]57b765672009-10-13 18:27:40620 PLOG(ERROR) << "inotify_init failed";
[email protected]d7395e732009-08-28 23:13:43621 return false;
622 }
tfarina89b4ae1c2015-12-16 18:59:18623 if (!base::SetNonBlocking(inotify_fd_)) {
624 PLOG(ERROR) << "base::SetNonBlocking failed";
[email protected]d7395e732009-08-28 23:13:43625 close(inotify_fd_);
626 inotify_fd_ = -1;
627 return false;
628 }
eroman0070d412017-06-22 22:18:24629
Gabriel Charette4049d422020-02-29 00:43:27630 constexpr base::TaskTraits kTraits = {base::TaskPriority::USER_VISIBLE,
631 base::MayBlock()};
632 file_task_runner_ = base::ThreadPool::CreateSequencedTaskRunner(kTraits);
eroman0070d412017-06-22 22:18:24633
sergeyu3f923062014-09-05 01:39:40634 // The initial read is done on the current thread, not
635 // |file_task_runner_|, since we will need to have it for
636 // SetUpAndFetchInitialConfig().
[email protected]d7395e732009-08-28 23:13:43637 UpdateCachedSettings();
638 return true;
639 }
640
dcheng67be2b1f2014-10-27 21:47:29641 void ShutDown() override {
[email protected]d7395e732009-08-28 23:13:43642 if (inotify_fd_ >= 0) {
643 ResetCachedSettings();
gabf4f904e2017-05-10 20:55:02644 inotify_watcher_.reset();
[email protected]d7395e732009-08-28 23:13:43645 close(inotify_fd_);
646 inotify_fd_ = -1;
647 }
marshall8e5fe942015-03-06 19:22:40648 debounce_timer_.reset();
[email protected]d7395e732009-08-28 23:13:43649 }
650
dcheng67be2b1f2014-10-27 21:47:29651 bool SetUpNotifications(
mostynbba063d6032014-10-09 11:01:13652 ProxyConfigServiceLinux::Delegate* delegate) override {
thestig0c412e852016-06-30 08:04:40653 DCHECK_GE(inotify_fd_, 0);
eroman0070d412017-06-22 22:18:24654 DCHECK(file_task_runner_->RunsTasksInCurrentSequence());
[email protected]d7395e732009-08-28 23:13:43655 // We can't just watch the kioslaverc file directly, since KDE will write
656 // a new copy of it and then rename it whenever settings are changed and
657 // inotify watches inodes (so we'll be watching the old deleted file after
658 // the first change, and it will never change again). So, we watch the
659 // directory instead. We then act only on changes to the kioslaverc entry.
eroman6b0ca662017-06-22 00:16:36660 // TODO(eroman): What if the file is deleted? (handle with IN_DELETE).
Slava Aseev9ffd8a62022-05-25 07:09:09661 size_t failed_dirs = 0;
662 for (const auto& kde_config_dir : kde_config_dirs_) {
663 if (inotify_add_watch(inotify_fd_, kde_config_dir.value().c_str(),
664 IN_MODIFY | IN_MOVED_TO) < 0) {
665 ++failed_dirs;
666 }
667 }
668 // Fail if inotify_add_watch failed with every directory
669 if (failed_dirs == kde_config_dirs_.size()) {
[email protected]d7395e732009-08-28 23:13:43670 return false;
sergeyu3f923062014-09-05 01:39:40671 }
[email protected]d7395e732009-08-28 23:13:43672 notify_delegate_ = delegate;
gabf4f904e2017-05-10 20:55:02673 inotify_watcher_ = base::FileDescriptorWatcher::WatchReadable(
Anna Malovaae7007aa2020-03-09 16:48:48674 inotify_fd_,
675 base::BindRepeating(&SettingGetterImplKDE::OnChangeNotification,
676 base::Unretained(this)));
[email protected]d3066142011-05-10 02:36:20677 // Simulate a change to avoid possibly losing updates before this point.
678 OnChangeNotification();
679 return true;
[email protected]d7395e732009-08-28 23:13:43680 }
681
eroman0070d412017-06-22 22:18:24682 const scoped_refptr<base::SequencedTaskRunner>& GetNotificationTaskRunner()
dcheng67be2b1f2014-10-27 21:47:29683 override {
sergeyu3f923062014-09-05 01:39:40684 return file_task_runner_;
[email protected]d7395e732009-08-28 23:13:43685 }
686
dcheng67be2b1f2014-10-27 21:47:29687 bool GetString(StringSetting key, std::string* result) override {
jdoerrie22a91d8b92018-10-05 08:43:26688 auto it = string_table_.find(key);
[email protected]d7395e732009-08-28 23:13:43689 if (it == string_table_.end())
690 return false;
691 *result = it->second;
692 return true;
693 }
dcheng67be2b1f2014-10-27 21:47:29694 bool GetBool(BoolSetting key, bool* result) override {
[email protected]d7395e732009-08-28 23:13:43695 // We don't ever have any booleans.
696 return false;
697 }
dcheng67be2b1f2014-10-27 21:47:29698 bool GetInt(IntSetting key, int* result) override {
[email protected]d7395e732009-08-28 23:13:43699 // We don't ever have any integers. (See AddProxy() below about ports.)
700 return false;
701 }
dcheng67be2b1f2014-10-27 21:47:29702 bool GetStringList(StringListSetting key,
703 std::vector<std::string>* result) override {
jdoerrie22a91d8b92018-10-05 08:43:26704 auto it = strings_table_.find(key);
[email protected]d7395e732009-08-28 23:13:43705 if (it == strings_table_.end())
706 return false;
707 *result = it->second;
708 return true;
709 }
710
dcheng67be2b1f2014-10-27 21:47:29711 bool BypassListIsReversed() override { return reversed_bypass_list_; }
[email protected]a48bf4a2010-06-14 18:24:53712
Shimi Zhang13eace252020-01-31 01:49:19713 bool UseSuffixMatching() override { return true; }
[email protected]1a597192010-07-09 16:58:38714
[email protected]d7395e732009-08-28 23:13:43715 private:
716 void ResetCachedSettings() {
717 string_table_.clear();
718 strings_table_.clear();
719 indirect_manual_ = false;
720 auto_no_pac_ = false;
[email protected]a48bf4a2010-06-14 18:24:53721 reversed_bypass_list_ = false;
[email protected]d7395e732009-08-28 23:13:43722 }
723
[email protected]6cdfd7f2013-02-08 20:40:15724 base::FilePath KDEHomeToConfigPath(const base::FilePath& kde_home) {
[email protected]92d2dc82010-04-08 17:49:59725 return kde_home.Append("share").Append("config");
726 }
727
[email protected]6b5fe742011-05-20 21:46:48728 void AddProxy(StringSetting host_key, const std::string& value) {
[email protected]d7395e732009-08-28 23:13:43729 if (value.empty() || value.substr(0, 3) == "//:")
730 // No proxy.
731 return;
[email protected]4b90c202012-04-24 23:27:55732 size_t space = value.find(' ');
733 if (space != std::string::npos) {
734 // Newer versions of KDE use a space rather than a colon to separate the
735 // port number from the hostname. If we find this, we need to convert it.
736 std::string fixed = value;
737 fixed[space] = ':';
738 string_table_[host_key] = fixed;
739 } else {
740 // We don't need to parse the port number out; GetProxyFromSettings()
741 // would only append it right back again. So we just leave the port
742 // number right in the host string.
743 string_table_[host_key] = value;
744 }
[email protected]d7395e732009-08-28 23:13:43745 }
746
[email protected]6b5fe742011-05-20 21:46:48747 void AddHostList(StringListSetting key, const std::string& value) {
[email protected]f18fde22010-05-18 23:49:54748 std::vector<std::string> tokens;
[email protected]f4ebe772013-02-02 00:21:39749 base::StringTokenizer tk(value, ", ");
[email protected]f18fde22010-05-18 23:49:54750 while (tk.GetNext()) {
751 std::string token = tk.token();
752 if (!token.empty())
753 tokens.push_back(token);
754 }
755 strings_table_[key] = tokens;
756 }
757
[email protected]9a3d8d42009-09-03 17:01:46758 void AddKDESetting(const std::string& key, const std::string& value) {
[email protected]d7395e732009-08-28 23:13:43759 if (key == "ProxyType") {
760 const char* mode = "none";
761 indirect_manual_ = false;
762 auto_no_pac_ = false;
eromane44498c2017-06-30 00:02:37763 int int_value = StringToIntOrDefault(value, 0);
[email protected]e83326f2010-07-31 17:29:25764 switch (int_value) {
[email protected]d7395e732009-08-28 23:13:43765 case 1: // Manual configuration.
766 mode = "manual";
767 break;
768 case 2: // PAC URL.
769 mode = "auto";
770 break;
771 case 3: // WPAD.
772 mode = "auto";
773 auto_no_pac_ = true;
774 break;
775 case 4: // Indirect manual via environment variables.
776 mode = "manual";
777 indirect_manual_ = true;
778 break;
eromane44498c2017-06-30 00:02:37779 default: // No proxy, or maybe kioslaverc syntax error.
780 break;
[email protected]d7395e732009-08-28 23:13:43781 }
[email protected]573c0502011-05-17 22:19:50782 string_table_[PROXY_MODE] = mode;
[email protected]d7395e732009-08-28 23:13:43783 } else if (key == "Proxy Config Script") {
[email protected]573c0502011-05-17 22:19:50784 string_table_[PROXY_AUTOCONF_URL] = value;
[email protected]d7395e732009-08-28 23:13:43785 } else if (key == "httpProxy") {
[email protected]573c0502011-05-17 22:19:50786 AddProxy(PROXY_HTTP_HOST, value);
[email protected]d7395e732009-08-28 23:13:43787 } else if (key == "httpsProxy") {
[email protected]573c0502011-05-17 22:19:50788 AddProxy(PROXY_HTTPS_HOST, value);
[email protected]d7395e732009-08-28 23:13:43789 } else if (key == "ftpProxy") {
[email protected]573c0502011-05-17 22:19:50790 AddProxy(PROXY_FTP_HOST, value);
[email protected]bfeb7232012-06-08 00:58:37791 } else if (key == "socksProxy") {
792 // Older versions of KDE configure SOCKS in a weird way involving
793 // LD_PRELOAD and a library that intercepts network calls to SOCKSify
794 // them. We don't support it. KDE 4.8 added a proper SOCKS setting.
795 AddProxy(PROXY_SOCKS_HOST, value);
[email protected]d7395e732009-08-28 23:13:43796 } else if (key == "ReversedException") {
797 // We count "true" or any nonzero number as true, otherwise false.
eromane44498c2017-06-30 00:02:37798 // A failure parsing the integer will also mean false.
799 reversed_bypass_list_ =
800 (value == "true" || StringToIntOrDefault(value, 0) != 0);
[email protected]d7395e732009-08-28 23:13:43801 } else if (key == "NoProxyFor") {
[email protected]573c0502011-05-17 22:19:50802 AddHostList(PROXY_IGNORE_HOSTS, value);
[email protected]d7395e732009-08-28 23:13:43803 } else if (key == "AuthMode") {
804 // Check for authentication, just so we can warn.
eromane44498c2017-06-30 00:02:37805 int mode = StringToIntOrDefault(value, 0);
[email protected]d7395e732009-08-28 23:13:43806 if (mode) {
807 // ProxyConfig does not support authentication parameters, but
808 // Chrome will prompt for the password later. So we ignore this.
809 LOG(WARNING) <<
810 "Proxy authentication parameters ignored, see bug 16709";
811 }
812 }
813 }
814
[email protected]6b5fe742011-05-20 21:46:48815 void ResolveIndirect(StringSetting key) {
jdoerrie22a91d8b92018-10-05 08:43:26816 auto it = string_table_.find(key);
[email protected]d7395e732009-08-28 23:13:43817 if (it != string_table_.end()) {
[email protected]f18fde22010-05-18 23:49:54818 std::string value;
[email protected]3ba7e082010-08-07 02:57:59819 if (env_var_getter_->GetVar(it->second.c_str(), &value))
[email protected]d7395e732009-08-28 23:13:43820 it->second = value;
[email protected]8425adc02010-04-18 17:45:31821 else
822 string_table_.erase(it);
[email protected]d7395e732009-08-28 23:13:43823 }
824 }
825
[email protected]6b5fe742011-05-20 21:46:48826 void ResolveIndirectList(StringListSetting key) {
jdoerrie22a91d8b92018-10-05 08:43:26827 auto it = strings_table_.find(key);
[email protected]f18fde22010-05-18 23:49:54828 if (it != strings_table_.end()) {
829 std::string value;
830 if (!it->second.empty() &&
[email protected]3ba7e082010-08-07 02:57:59831 env_var_getter_->GetVar(it->second[0].c_str(), &value))
[email protected]f18fde22010-05-18 23:49:54832 AddHostList(key, value);
833 else
834 strings_table_.erase(it);
835 }
836 }
837
[email protected]d7395e732009-08-28 23:13:43838 // The settings in kioslaverc could occur in any order, but some affect
839 // others. Rather than read the whole file in and then query them in an
840 // order that allows us to handle that, we read the settings in whatever
841 // order they occur and do any necessary tweaking after we finish.
842 void ResolveModeEffects() {
843 if (indirect_manual_) {
[email protected]573c0502011-05-17 22:19:50844 ResolveIndirect(PROXY_HTTP_HOST);
845 ResolveIndirect(PROXY_HTTPS_HOST);
846 ResolveIndirect(PROXY_FTP_HOST);
Maks Orlovichfee43b12021-06-17 21:10:08847 ResolveIndirect(PROXY_SOCKS_HOST);
[email protected]573c0502011-05-17 22:19:50848 ResolveIndirectList(PROXY_IGNORE_HOSTS);
[email protected]d7395e732009-08-28 23:13:43849 }
850 if (auto_no_pac_) {
851 // Remove the PAC URL; we're not supposed to use it.
[email protected]573c0502011-05-17 22:19:50852 string_table_.erase(PROXY_AUTOCONF_URL);
[email protected]d7395e732009-08-28 23:13:43853 }
[email protected]d7395e732009-08-28 23:13:43854 }
855
Slava Aseev9ffd8a62022-05-25 07:09:09856 // Reads kioslaverc from all paths one line at a time and calls
857 // AddKDESetting() to add each relevant name-value pair to the appropriate
858 // value table. Each value can be overwritten by values from configs from
859 // the following paths.
[email protected]d7395e732009-08-28 23:13:43860 void UpdateCachedSettings() {
Slava Aseev9ffd8a62022-05-25 07:09:09861 bool at_least_one_kioslaverc_opened = false;
862 for (const auto& kde_config_dir : kde_config_dirs_) {
863 base::FilePath kioslaverc = kde_config_dir.Append("kioslaverc");
864 base::ScopedFILE input(base::OpenFile(kioslaverc, "r"));
865 if (!input.get())
[email protected]d7395e732009-08-28 23:13:43866 continue;
Slava Aseev9ffd8a62022-05-25 07:09:09867
868 // Reset cached settings once only if some config was successfully opened
869 if (!at_least_one_kioslaverc_opened) {
870 ResetCachedSettings();
[email protected]d7395e732009-08-28 23:13:43871 }
Slava Aseev9ffd8a62022-05-25 07:09:09872 at_least_one_kioslaverc_opened = true;
873 bool in_proxy_settings = false;
874 bool line_too_long = false;
875 char line[BUFFER_SIZE];
876 // fgets() will return NULL on EOF or error.
877 while (fgets(line, sizeof(line), input.get())) {
878 // fgets() guarantees the line will be properly terminated.
879 size_t length = strlen(line);
880 if (!length)
881 continue;
882 // This should be true even with CRLF endings.
883 if (line[length - 1] != '\n') {
884 line_too_long = true;
885 continue;
886 }
887 if (line_too_long) {
888 // The previous line had no line ending, but this one does. This is
889 // the end of the line that was too long, so warn here and skip it.
890 LOG(WARNING) << "skipped very long line in " << kioslaverc.value();
891 line_too_long = false;
892 continue;
893 }
894 // Remove the LF at the end, and the CR if there is one.
[email protected]d7395e732009-08-28 23:13:43895 line[--length] = '\0';
Slava Aseev9ffd8a62022-05-25 07:09:09896 if (length && line[length - 1] == '\r')
897 line[--length] = '\0';
898 // Now parse the line.
899 if (line[0] == '[') {
900 // Switching sections. All we care about is whether this is
901 // the (a?) proxy settings section, for both KDE3 and KDE4.
902 in_proxy_settings = !strncmp(line, "[Proxy Settings]", 16);
903 } else if (in_proxy_settings) {
904 // A regular line, in the (a?) proxy settings section.
905 char* split = strchr(line, '=');
906 // Skip this line if it does not contain an = sign.
907 if (!split)
[email protected]d7395e732009-08-28 23:13:43908 continue;
Slava Aseev9ffd8a62022-05-25 07:09:09909 // Split the line on the = and advance |split|.
910 *(split++) = 0;
911 std::string key = line;
912 std::string value = split;
913 base::TrimWhitespaceASCII(key, base::TRIM_ALL, &key);
914 base::TrimWhitespaceASCII(value, base::TRIM_ALL, &value);
915 // Skip this line if the key name is empty.
[email protected]9a3d8d42009-09-03 17:01:46916 if (key.empty())
917 continue;
Slava Aseev9ffd8a62022-05-25 07:09:09918 // Is the value name localized?
919 if (key[key.length() - 1] == ']') {
920 // Find the matching bracket.
921 length = key.rfind('[');
922 // Skip this line if the localization indicator is malformed.
923 if (length == std::string::npos)
924 continue;
925 // Trim the localization indicator off.
926 key.resize(length);
927 // Remove any resulting trailing whitespace.
928 base::TrimWhitespaceASCII(key, base::TRIM_TRAILING, &key);
929 // Skip this line if the key name is now empty.
930 if (key.empty())
931 continue;
932 }
933 // Now fill in the tables.
934 AddKDESetting(key, value);
[email protected]d7395e732009-08-28 23:13:43935 }
[email protected]d7395e732009-08-28 23:13:43936 }
Slava Aseev9ffd8a62022-05-25 07:09:09937 if (ferror(input.get()))
938 LOG(ERROR) << "error reading " << kioslaverc.value();
[email protected]d7395e732009-08-28 23:13:43939 }
Slava Aseev9ffd8a62022-05-25 07:09:09940 if (at_least_one_kioslaverc_opened) {
941 ResolveModeEffects();
942 }
[email protected]d7395e732009-08-28 23:13:43943 }
944
945 // This is the callback from the debounce timer.
946 void OnDebouncedNotification() {
eroman0070d412017-06-22 22:18:24947 DCHECK(file_task_runner_->RunsTasksInCurrentSequence());
[email protected]b30a3f52010-10-16 01:05:46948 VLOG(1) << "inotify change notification for kioslaverc";
[email protected]d7395e732009-08-28 23:13:43949 UpdateCachedSettings();
[email protected]961ac942011-04-28 18:18:14950 CHECK(notify_delegate_);
[email protected]d7395e732009-08-28 23:13:43951 // Forward to a method on the proxy config service delegate object.
952 notify_delegate_->OnCheckProxyConfigSettings();
953 }
954
955 // Called by OnFileCanReadWithoutBlocking() on the file thread. Reads
956 // from the inotify file descriptor and starts up a debounce timer if
957 // an event for kioslaverc is seen.
958 void OnChangeNotification() {
[email protected]d2e6d592012-02-03 21:49:04959 DCHECK_GE(inotify_fd_, 0);
eroman0070d412017-06-22 22:18:24960 DCHECK(file_task_runner_->RunsTasksInCurrentSequence());
[email protected]d7395e732009-08-28 23:13:43961 char event_buf[(sizeof(inotify_event) + NAME_MAX + 1) * 4];
962 bool kioslaverc_touched = false;
963 ssize_t r;
964 while ((r = read(inotify_fd_, event_buf, sizeof(event_buf))) > 0) {
965 // inotify returns variable-length structures, which is why we have
966 // this strange-looking loop instead of iterating through an array.
967 char* event_ptr = event_buf;
968 while (event_ptr < event_buf + r) {
969 inotify_event* event = reinterpret_cast<inotify_event*>(event_ptr);
970 // The kernel always feeds us whole events.
[email protected]b1f031dd2010-03-02 23:19:33971 CHECK_LE(event_ptr + sizeof(inotify_event), event_buf + r);
972 CHECK_LE(event->name + event->len, event_buf + r);
[email protected]d7395e732009-08-28 23:13:43973 if (!strcmp(event->name, "kioslaverc"))
974 kioslaverc_touched = true;
975 // Advance the pointer just past the end of the filename.
976 event_ptr = event->name + event->len;
977 }
978 // We keep reading even if |kioslaverc_touched| is true to drain the
979 // inotify event queue.
980 }
981 if (!r)
982 // Instead of returning -1 and setting errno to EINVAL if there is not
983 // enough buffer space, older kernels (< 2.6.21) return 0. Simulate the
984 // new behavior (EINVAL) so we can reuse the code below.
985 errno = EINVAL;
986 if (errno != EAGAIN) {
[email protected]57b765672009-10-13 18:27:40987 PLOG(WARNING) << "error reading inotify file descriptor";
[email protected]d7395e732009-08-28 23:13:43988 if (errno == EINVAL) {
989 // Our buffer is not large enough to read the next event. This should
990 // not happen (because its size is calculated to always be sufficiently
991 // large), but if it does we'd warn continuously since |inotify_fd_|
992 // would be forever ready to read. Close it and stop watching instead.
993 LOG(ERROR) << "inotify failure; no longer watching kioslaverc!";
gabf4f904e2017-05-10 20:55:02994 inotify_watcher_.reset();
[email protected]d7395e732009-08-28 23:13:43995 close(inotify_fd_);
996 inotify_fd_ = -1;
997 }
998 }
999 if (kioslaverc_touched) {
eroman6b0ca662017-06-22 00:16:361000 LOG(ERROR) << "kioslaverc_touched";
[email protected]d7395e732009-08-28 23:13:431001 // We don't use Reset() because the timer may not yet be running.
1002 // (In that case Stop() is a no-op.)
marshall8e5fe942015-03-06 19:22:401003 debounce_timer_->Stop();
Peter Kastinge5a38ed2021-10-02 03:06:351004 debounce_timer_->Start(
1005 FROM_HERE, base::Milliseconds(kDebounceTimeoutMilliseconds), this,
[email protected]573c0502011-05-17 22:19:501006 &SettingGetterImplKDE::OnDebouncedNotification);
[email protected]d7395e732009-08-28 23:13:431007 }
1008 }
1009
[email protected]6b5fe742011-05-20 21:46:481010 typedef std::map<StringSetting, std::string> string_map_type;
1011 typedef std::map<StringListSetting,
1012 std::vector<std::string> > strings_map_type;
[email protected]d7395e732009-08-28 23:13:431013
Tsuyoshi Horo4478fd32022-06-09 01:41:251014 int inotify_fd_ = -1;
gabf4f904e2017-05-10 20:55:021015 std::unique_ptr<base::FileDescriptorWatcher::Controller> inotify_watcher_;
Keishi Hattorif28f4f82022-06-21 11:32:151016 raw_ptr<ProxyConfigServiceLinux::Delegate> notify_delegate_ = nullptr;
danakj8a98ca22016-04-16 02:47:361017 std::unique_ptr<base::OneShotTimer> debounce_timer_;
Slava Aseev9ffd8a62022-05-25 07:09:091018 std::vector<base::FilePath> kde_config_dirs_;
Tsuyoshi Horo4478fd32022-06-09 01:41:251019 bool indirect_manual_ = false;
1020 bool auto_no_pac_ = false;
1021 bool reversed_bypass_list_ = false;
[email protected]f18fde22010-05-18 23:49:541022 // We don't own |env_var_getter_|. It's safe to hold a pointer to it, since
1023 // both it and us are owned by ProxyConfigServiceLinux::Delegate, and have the
1024 // same lifetime.
Keishi Hattorif28f4f82022-06-21 11:32:151025 raw_ptr<base::Environment> env_var_getter_;
[email protected]d7395e732009-08-28 23:13:431026
1027 // We cache these settings whenever we re-read the kioslaverc file.
1028 string_map_type string_table_;
1029 strings_map_type strings_table_;
1030
eroman0070d412017-06-22 22:18:241031 // Task runner for doing blocking file IO on, as well as handling inotify
1032 // events on.
1033 scoped_refptr<base::SequencedTaskRunner> file_task_runner_;
[email protected]861c6c62009-04-20 16:50:561034};
1035
1036} // namespace
1037
[email protected]573c0502011-05-17 22:19:501038bool ProxyConfigServiceLinux::Delegate::GetProxyFromSettings(
[email protected]6b5fe742011-05-20 21:46:481039 SettingGetter::StringSetting host_key,
[email protected]573c0502011-05-17 22:19:501040 ProxyServer* result_server) {
[email protected]861c6c62009-04-20 16:50:561041 std::string host;
[email protected]573c0502011-05-17 22:19:501042 if (!setting_getter_->GetString(host_key, &host) || host.empty()) {
[email protected]861c6c62009-04-20 16:50:561043 // Unset or empty.
1044 return false;
1045 }
1046 // Check for an optional port.
[email protected]d7395e732009-08-28 23:13:431047 int port = 0;
[email protected]6b5fe742011-05-20 21:46:481048 SettingGetter::IntSetting port_key =
[email protected]573c0502011-05-17 22:19:501049 SettingGetter::HostSettingToPortSetting(host_key);
1050 setting_getter_->GetInt(port_key, &port);
[email protected]861c6c62009-04-20 16:50:561051 if (port != 0) {
1052 // If a port is set and non-zero:
Raul Tambre8c1981d2019-02-08 02:22:261053 host += ":" + base::NumberToString(port);
[email protected]861c6c62009-04-20 16:50:561054 }
[email protected]76960f3d2011-04-30 02:15:231055
Tim Brown2a19f3b2017-12-12 01:08:401056 // gsettings settings do not appear to distinguish between SOCKS version. We
[email protected]573c0502011-05-17 22:19:501057 // default to version 5. For more information on this policy decision, see:
[email protected]76960f3d2011-04-30 02:15:231058 // http://code.google.com/p/chromium/issues/detail?id=55912#c2
[email protected]573c0502011-05-17 22:19:501059 ProxyServer::Scheme scheme = (host_key == SettingGetter::PROXY_SOCKS_HOST) ?
1060 ProxyServer::SCHEME_SOCKS5 : ProxyServer::SCHEME_HTTP;
1061 host = FixupProxyHostScheme(scheme, host);
Eric Orth5ccc3f02021-09-23 00:01:571062 ProxyServer proxy_server =
1063 ProxyUriToProxyServer(host, ProxyServer::SCHEME_HTTP);
[email protected]861c6c62009-04-20 16:50:561064 if (proxy_server.is_valid()) {
1065 *result_server = proxy_server;
1066 return true;
1067 }
1068 return false;
1069}
1070
Anton Bikineev068d2912021-05-15 20:43:521071absl::optional<ProxyConfigWithAnnotation>
Eric Roman750af4b12018-02-22 22:38:531072ProxyConfigServiceLinux::Delegate::GetConfigFromSettings() {
Ramin Halavatica8d5252018-03-12 05:33:491073 ProxyConfig config;
Shubham Aggarwal1f6a5a12021-09-29 21:48:161074 config.set_from_system(true);
Eric Roman750af4b12018-02-22 22:38:531075
[email protected]861c6c62009-04-20 16:50:561076 std::string mode;
[email protected]573c0502011-05-17 22:19:501077 if (!setting_getter_->GetString(SettingGetter::PROXY_MODE, &mode)) {
Tim Brown2a19f3b2017-12-12 01:08:401078 // We expect this to always be set, so if we don't see it then we probably
1079 // have a gsettings problem, and so we don't have a valid proxy config.
Anton Bikineev068d2912021-05-15 20:43:521080 return absl::nullopt;
[email protected]861c6c62009-04-20 16:50:561081 }
[email protected]3e44697f2009-05-22 14:37:391082 if (mode == "none") {
[email protected]861c6c62009-04-20 16:50:561083 // Specifically specifies no proxy.
Ramin Halavatica8d5252018-03-12 05:33:491084 return ProxyConfigWithAnnotation(
1085 config, NetworkTrafficAnnotationTag(traffic_annotation_));
[email protected]3e44697f2009-05-22 14:37:391086 }
[email protected]861c6c62009-04-20 16:50:561087
[email protected]3e44697f2009-05-22 14:37:391088 if (mode == "auto") {
[email protected]aa3ac2cc2012-06-19 00:28:041089 // Automatic proxy config.
[email protected]861c6c62009-04-20 16:50:561090 std::string pac_url_str;
[email protected]573c0502011-05-17 22:19:501091 if (setting_getter_->GetString(SettingGetter::PROXY_AUTOCONF_URL,
1092 &pac_url_str)) {
[email protected]861c6c62009-04-20 16:50:561093 if (!pac_url_str.empty()) {
[email protected]aa3ac2cc2012-06-19 00:28:041094 // If the PAC URL is actually a file path, then put file:// in front.
1095 if (pac_url_str[0] == '/')
1096 pac_url_str = "file://" + pac_url_str;
[email protected]861c6c62009-04-20 16:50:561097 GURL pac_url(pac_url_str);
1098 if (!pac_url.is_valid())
Anton Bikineev068d2912021-05-15 20:43:521099 return absl::nullopt;
Ramin Halavatica8d5252018-03-12 05:33:491100 config.set_pac_url(pac_url);
1101 return ProxyConfigWithAnnotation(
1102 config, NetworkTrafficAnnotationTag(traffic_annotation_));
[email protected]861c6c62009-04-20 16:50:561103 }
1104 }
Ramin Halavatica8d5252018-03-12 05:33:491105 config.set_auto_detect(true);
1106 return ProxyConfigWithAnnotation(
1107 config, NetworkTrafficAnnotationTag(traffic_annotation_));
[email protected]861c6c62009-04-20 16:50:561108 }
1109
[email protected]3e44697f2009-05-22 14:37:391110 if (mode != "manual") {
[email protected]861c6c62009-04-20 16:50:561111 // Mode is unrecognized.
Anton Bikineev068d2912021-05-15 20:43:521112 return absl::nullopt;
[email protected]861c6c62009-04-20 16:50:561113 }
1114 bool use_http_proxy;
[email protected]573c0502011-05-17 22:19:501115 if (setting_getter_->GetBool(SettingGetter::PROXY_USE_HTTP_PROXY,
1116 &use_http_proxy)
[email protected]861c6c62009-04-20 16:50:561117 && !use_http_proxy) {
1118 // Another master switch for some reason. If set to false, then no
1119 // proxy. But we don't panic if the key doesn't exist.
Ramin Halavatica8d5252018-03-12 05:33:491120 return ProxyConfigWithAnnotation(
1121 config, NetworkTrafficAnnotationTag(traffic_annotation_));
[email protected]861c6c62009-04-20 16:50:561122 }
1123
1124 bool same_proxy = false;
1125 // Indicates to use the http proxy for all protocols. This one may
[email protected]573c0502011-05-17 22:19:501126 // not exist (presumably on older versions); we assume false in that
[email protected]861c6c62009-04-20 16:50:561127 // case.
[email protected]573c0502011-05-17 22:19:501128 setting_getter_->GetBool(SettingGetter::PROXY_USE_SAME_PROXY,
1129 &same_proxy);
[email protected]861c6c62009-04-20 16:50:561130
[email protected]76960f3d2011-04-30 02:15:231131 ProxyServer proxy_for_http;
1132 ProxyServer proxy_for_https;
1133 ProxyServer proxy_for_ftp;
1134 ProxyServer socks_proxy; // (socks)
1135
1136 // This counts how many of the above ProxyServers were defined and valid.
1137 size_t num_proxies_specified = 0;
1138
1139 // Extract the per-scheme proxies. If we failed to parse it, or no proxy was
1140 // specified for the scheme, then the resulting ProxyServer will be invalid.
[email protected]573c0502011-05-17 22:19:501141 if (GetProxyFromSettings(SettingGetter::PROXY_HTTP_HOST, &proxy_for_http))
[email protected]76960f3d2011-04-30 02:15:231142 num_proxies_specified++;
[email protected]573c0502011-05-17 22:19:501143 if (GetProxyFromSettings(SettingGetter::PROXY_HTTPS_HOST, &proxy_for_https))
[email protected]76960f3d2011-04-30 02:15:231144 num_proxies_specified++;
[email protected]573c0502011-05-17 22:19:501145 if (GetProxyFromSettings(SettingGetter::PROXY_FTP_HOST, &proxy_for_ftp))
[email protected]76960f3d2011-04-30 02:15:231146 num_proxies_specified++;
[email protected]573c0502011-05-17 22:19:501147 if (GetProxyFromSettings(SettingGetter::PROXY_SOCKS_HOST, &socks_proxy))
[email protected]76960f3d2011-04-30 02:15:231148 num_proxies_specified++;
1149
1150 if (same_proxy) {
1151 if (proxy_for_http.is_valid()) {
1152 // Use the http proxy for all schemes.
Ramin Halavatica8d5252018-03-12 05:33:491153 config.proxy_rules().type = ProxyConfig::ProxyRules::Type::PROXY_LIST;
1154 config.proxy_rules().single_proxies.SetSingleProxyServer(proxy_for_http);
[email protected]861c6c62009-04-20 16:50:561155 }
[email protected]76960f3d2011-04-30 02:15:231156 } else if (num_proxies_specified > 0) {
1157 if (socks_proxy.is_valid() && num_proxies_specified == 1) {
1158 // If the only proxy specified was for SOCKS, use it for all schemes.
Ramin Halavatica8d5252018-03-12 05:33:491159 config.proxy_rules().type = ProxyConfig::ProxyRules::Type::PROXY_LIST;
1160 config.proxy_rules().single_proxies.SetSingleProxyServer(socks_proxy);
[email protected]861c6c62009-04-20 16:50:561161 } else {
[email protected]2189e092013-03-16 18:02:021162 // Otherwise use the indicated proxies per-scheme.
Ramin Halavatica8d5252018-03-12 05:33:491163 config.proxy_rules().type =
Lily Houghtone6b617e2018-01-19 20:13:071164 ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME;
Ramin Halavatica8d5252018-03-12 05:33:491165 config.proxy_rules().proxies_for_http.SetSingleProxyServer(
1166 proxy_for_http);
1167 config.proxy_rules().proxies_for_https.SetSingleProxyServer(
1168 proxy_for_https);
1169 config.proxy_rules().proxies_for_ftp.SetSingleProxyServer(proxy_for_ftp);
1170 config.proxy_rules().fallback_proxies.SetSingleProxyServer(socks_proxy);
[email protected]861c6c62009-04-20 16:50:561171 }
1172 }
1173
Ramin Halavatica8d5252018-03-12 05:33:491174 if (config.proxy_rules().empty()) {
[email protected]861c6c62009-04-20 16:50:561175 // Manual mode but we couldn't parse any rules.
Anton Bikineev068d2912021-05-15 20:43:521176 return absl::nullopt;
[email protected]861c6c62009-04-20 16:50:561177 }
1178
1179 // Check for authentication, just so we can warn.
[email protected]d7395e732009-08-28 23:13:431180 bool use_auth = false;
[email protected]573c0502011-05-17 22:19:501181 setting_getter_->GetBool(SettingGetter::PROXY_USE_AUTHENTICATION,
1182 &use_auth);
[email protected]62749f182009-07-15 13:16:541183 if (use_auth) {
1184 // ProxyConfig does not support authentication parameters, but
1185 // Chrome will prompt for the password later. So we ignore
1186 // /system/http_proxy/*auth* settings.
1187 LOG(WARNING) << "Proxy authentication parameters ignored, see bug 16709";
1188 }
[email protected]861c6c62009-04-20 16:50:561189
1190 // Now the bypass list.
[email protected]7541206c2010-02-19 20:24:061191 std::vector<std::string> ignore_hosts_list;
Ramin Halavatica8d5252018-03-12 05:33:491192 config.proxy_rules().bypass_rules.Clear();
[email protected]573c0502011-05-17 22:19:501193 if (setting_getter_->GetStringList(SettingGetter::PROXY_IGNORE_HOSTS,
1194 &ignore_hosts_list)) {
Eric Romanda790f92018-11-07 19:17:151195 for (const auto& rule : ignore_hosts_list) {
Shimi Zhang13eace252020-01-31 01:49:191196 config.proxy_rules().bypass_rules.AddRuleFromString(rule);
[email protected]1a597192010-07-09 16:58:381197 }
[email protected]a8185d02010-06-11 00:19:501198 }
Shimi Zhang13eace252020-01-31 01:49:191199
1200 if (setting_getter_->UseSuffixMatching()) {
1201 RewriteRulesForSuffixMatching(&config.proxy_rules().bypass_rules);
1202 }
1203
[email protected]861c6c62009-04-20 16:50:561204 // Note that there are no settings with semantics corresponding to
[email protected]1a597192010-07-09 16:58:381205 // bypass of local names in GNOME. In KDE, "<local>" is supported
1206 // as a hostname rule.
[email protected]861c6c62009-04-20 16:50:561207
[email protected]a48bf4a2010-06-14 18:24:531208 // KDE allows one to reverse the bypass rules.
Ramin Halavatica8d5252018-03-12 05:33:491209 config.proxy_rules().reverse_bypass = setting_getter_->BypassListIsReversed();
[email protected]a48bf4a2010-06-14 18:24:531210
Ramin Halavatica8d5252018-03-12 05:33:491211 return ProxyConfigWithAnnotation(
1212 config, NetworkTrafficAnnotationTag(traffic_annotation_));
[email protected]861c6c62009-04-20 16:50:561213}
1214
thestig0c412e852016-06-30 08:04:401215ProxyConfigServiceLinux::Delegate::Delegate(
Ramin Halavatica8d5252018-03-12 05:33:491216 std::unique_ptr<base::Environment> env_var_getter,
Anton Bikineev068d2912021-05-15 20:43:521217 absl::optional<std::unique_ptr<SettingGetter>> setting_getter,
1218 absl::optional<NetworkTrafficAnnotationTag> traffic_annotation)
Eric Romancd032fb62018-05-18 21:40:131219 : env_var_getter_(std::move(env_var_getter)) {
1220 if (traffic_annotation) {
1221 traffic_annotation_ =
1222 MutableNetworkTrafficAnnotationTag(traffic_annotation.value());
1223 }
1224
1225 if (setting_getter) {
1226 setting_getter_ = std::move(setting_getter.value());
1227 return;
1228 }
1229
[email protected]573c0502011-05-17 22:19:501230 // Figure out which SettingGetterImpl to use, if any.
thestig0c412e852016-06-30 08:04:401231 switch (base::nix::GetDesktopEnvironment(env_var_getter_.get())) {
Tim Brownd9bd4752017-12-14 20:26:341232 case base::nix::DESKTOP_ENVIRONMENT_CINNAMON:
Xinchao Tianf952aa12022-06-09 21:14:531233 case base::nix::DESKTOP_ENVIRONMENT_DEEPIN:
[email protected]6b0349ef2010-10-16 04:56:061234 case base::nix::DESKTOP_ENVIRONMENT_GNOME:
Tom Andersonac4d6f42017-10-13 20:14:201235 case base::nix::DESKTOP_ENVIRONMENT_PANTHEON:
Xinchao Tianb3ecbfa2022-03-24 04:14:481236 case base::nix::DESKTOP_ENVIRONMENT_UKUI:
[email protected]9e6c9bde2012-07-17 23:40:171237 case base::nix::DESKTOP_ENVIRONMENT_UNITY:
[email protected]8c20e3d2011-05-19 21:03:571238#if defined(USE_GIO)
1239 {
Tsuyoshi Horof8861cb2022-07-05 23:50:201240 auto gs_getter = std::make_unique<SettingGetterImplGSettings>();
danakj8a98ca22016-04-16 02:47:361241 // We have to load symbols and check the GNOME version in use to decide
Tim Brown1c307cc2017-12-08 02:40:381242 // if we should use the gsettings getter. See CheckVersion().
1243 if (gs_getter->CheckVersion(env_var_getter_.get()))
inlinechan894515af2016-12-09 02:40:101244 setting_getter_ = std::move(gs_getter);
[email protected]8c20e3d2011-05-19 21:03:571245 }
1246#endif
[email protected]d7395e732009-08-28 23:13:431247 break;
[email protected]6b0349ef2010-10-16 04:56:061248 case base::nix::DESKTOP_ENVIRONMENT_KDE3:
1249 case base::nix::DESKTOP_ENVIRONMENT_KDE4:
edward.baker53bec302015-10-02 16:57:491250 case base::nix::DESKTOP_ENVIRONMENT_KDE5:
Peter Boström08e7ed82021-04-19 17:49:591251 setting_getter_ =
1252 std::make_unique<SettingGetterImplKDE>(env_var_getter_.get());
[email protected]d7395e732009-08-28 23:13:431253 break;
[email protected]6b0349ef2010-10-16 04:56:061254 case base::nix::DESKTOP_ENVIRONMENT_XFCE:
Tom Andersoncee33d42022-09-08 03:45:311255 case base::nix::DESKTOP_ENVIRONMENT_LXQT:
[email protected]6b0349ef2010-10-16 04:56:061256 case base::nix::DESKTOP_ENVIRONMENT_OTHER:
[email protected]d7395e732009-08-28 23:13:431257 break;
1258 }
1259}
1260
[email protected]d3066142011-05-10 02:36:201261void ProxyConfigServiceLinux::Delegate::SetUpAndFetchInitialConfig(
sergeyu3f923062014-09-05 01:39:401262 const scoped_refptr<base::SingleThreadTaskRunner>& glib_task_runner,
Ramin Halavatica8d5252018-03-12 05:33:491263 const scoped_refptr<base::SequencedTaskRunner>& main_task_runner,
1264 const NetworkTrafficAnnotationTag& traffic_annotation) {
1265 traffic_annotation_ = MutableNetworkTrafficAnnotationTag(traffic_annotation);
1266
[email protected]3e44697f2009-05-22 14:37:391267 // We should be running on the default glib main loop thread right
Tim Brown2a19f3b2017-12-12 01:08:401268 // now. gsettings can only be accessed from this thread.
eroman0070d412017-06-22 22:18:241269 DCHECK(glib_task_runner->RunsTasksInCurrentSequence());
sergeyu3f923062014-09-05 01:39:401270 glib_task_runner_ = glib_task_runner;
Matt Menke75765062017-11-21 01:21:161271 main_task_runner_ = main_task_runner;
[email protected]3e44697f2009-05-22 14:37:391272
Matt Menke75765062017-11-21 01:21:161273 // If we are passed a NULL |main_task_runner|, then don't set up proxy
eroman0070d412017-06-22 22:18:241274 // setting change notifications. This should not be the usual case but is
1275 // intended to/ simplify test setups.
Matt Menke75765062017-11-21 01:21:161276 if (!main_task_runner_.get())
[email protected]b30a3f52010-10-16 01:05:461277 VLOG(1) << "Monitoring of proxy setting changes is disabled";
[email protected]3e44697f2009-05-22 14:37:391278
1279 // Fetch and cache the current proxy config. The config is left in
Matt Menke75765062017-11-21 01:21:161280 // cached_config_, where GetLatestProxyConfig() running on the main TaskRunner
[email protected]3e44697f2009-05-22 14:37:391281 // will expect to find it. This is safe to do because we return
1282 // before this ProxyConfigServiceLinux is passed on to
Nicolas Arciniegad2013f92020-02-07 23:00:561283 // the ConfiguredProxyResolutionService.
[email protected]d6cb85b2009-07-23 22:10:531284
1285 // Note: It would be nice to prioritize environment variables
Tim Brown2a19f3b2017-12-12 01:08:401286 // and only fall back to gsettings if env vars were unset. But
[email protected]d6cb85b2009-07-23 22:10:531287 // gnome-terminal "helpfully" sets http_proxy and no_proxy, and it
1288 // does so even if the proxy mode is set to auto, which would
1289 // mislead us.
1290
Anton Bikineev068d2912021-05-15 20:43:521291 cached_config_ = absl::nullopt;
Eric Roman750af4b12018-02-22 22:38:531292 if (setting_getter_ && setting_getter_->Init(glib_task_runner)) {
1293 cached_config_ = GetConfigFromSettings();
1294 }
1295 if (cached_config_) {
Ramin Halavatica8d5252018-03-12 05:33:491296 VLOG(1) << "Obtained proxy settings from annotation hash code "
1297 << cached_config_->traffic_annotation().unique_id_hash_code;
[email protected]d3066142011-05-10 02:36:201298
Tim Brown2a19f3b2017-12-12 01:08:401299 // If gsettings proxy mode is "none", meaning direct, then we take
[email protected]d3066142011-05-10 02:36:201300 // that to be a valid config and will not check environment
1301 // variables. The alternative would have been to look for a proxy
Eric Roman750af4b12018-02-22 22:38:531302 // wherever we can find one.
[email protected]d3066142011-05-10 02:36:201303
1304 // Keep a copy of the config for use from this thread for
1305 // comparison with updated settings when we get notifications.
1306 reference_config_ = cached_config_;
[email protected]d3066142011-05-10 02:36:201307
Matt Menke75765062017-11-21 01:21:161308 // We only set up notifications if we have the main and file loops
1309 // available. We do this after getting the initial configuration so that we
1310 // don't have to worry about cancelling it if the initial fetch above fails.
1311 // Note that setting up notifications has the side effect of simulating a
1312 // change, so that we won't lose any updates that may have happened after
1313 // the initial fetch and before setting up notifications. We'll detect the
1314 // common case of no changes in OnCheckProxyConfigSettings() (or sooner) and
1315 // ignore it.
1316 if (main_task_runner.get()) {
eroman0070d412017-06-22 22:18:241317 scoped_refptr<base::SequencedTaskRunner> required_loop =
[email protected]76722472012-05-24 08:26:461318 setting_getter_->GetNotificationTaskRunner();
eroman0070d412017-06-22 22:18:241319 if (!required_loop.get() || required_loop->RunsTasksInCurrentSequence()) {
[email protected]d3066142011-05-10 02:36:201320 // In this case we are already on an acceptable thread.
1321 SetUpNotifications();
[email protected]d7395e732009-08-28 23:13:431322 } else {
[email protected]d3066142011-05-10 02:36:201323 // Post a task to set up notifications. We don't wait for success.
kylecharf4fe5172019-02-15 18:53:491324 required_loop->PostTask(
1325 FROM_HERE,
1326 base::BindOnce(
1327 &ProxyConfigServiceLinux::Delegate::SetUpNotifications, this));
[email protected]d6cb85b2009-07-23 22:10:531328 }
[email protected]d7395e732009-08-28 23:13:431329 }
[email protected]861c6c62009-04-20 16:50:561330 }
[email protected]d6cb85b2009-07-23 22:10:531331
Eric Roman750af4b12018-02-22 22:38:531332 if (!cached_config_) {
[email protected]d6cb85b2009-07-23 22:10:531333 // We fall back on environment variables.
[email protected]3e44697f2009-05-22 14:37:391334 //
[email protected]d3066142011-05-10 02:36:201335 // Consulting environment variables doesn't need to be done from the
1336 // default glib main loop, but it's a tiny enough amount of work.
Eric Roman750af4b12018-02-22 22:38:531337 cached_config_ = GetConfigFromEnv();
1338 if (cached_config_) {
[email protected]b30a3f52010-10-16 01:05:461339 VLOG(1) << "Obtained proxy settings from environment variables";
[email protected]3e44697f2009-05-22 14:37:391340 }
[email protected]861c6c62009-04-20 16:50:561341 }
[email protected]3e44697f2009-05-22 14:37:391342}
1343
[email protected]573c0502011-05-17 22:19:501344// Depending on the SettingGetter in use, this method will be called
Tim Brown2a19f3b2017-12-12 01:08:401345// on either the UI thread (GSettings) or the file thread (KDE).
[email protected]d3066142011-05-10 02:36:201346void ProxyConfigServiceLinux::Delegate::SetUpNotifications() {
eroman0070d412017-06-22 22:18:241347 scoped_refptr<base::SequencedTaskRunner> required_loop =
[email protected]76722472012-05-24 08:26:461348 setting_getter_->GetNotificationTaskRunner();
eroman0070d412017-06-22 22:18:241349 DCHECK(!required_loop.get() || required_loop->RunsTasksInCurrentSequence());
[email protected]573c0502011-05-17 22:19:501350 if (!setting_getter_->SetUpNotifications(this))
[email protected]d3066142011-05-10 02:36:201351 LOG(ERROR) << "Unable to set up proxy configuration change notifications";
1352}
1353
[email protected]119655002010-07-23 06:02:401354void ProxyConfigServiceLinux::Delegate::AddObserver(Observer* observer) {
1355 observers_.AddObserver(observer);
1356}
1357
1358void ProxyConfigServiceLinux::Delegate::RemoveObserver(Observer* observer) {
1359 observers_.RemoveObserver(observer);
1360}
1361
[email protected]3a29593d2011-04-11 10:07:521362ProxyConfigService::ConfigAvailability
Ramin Halavatica8d5252018-03-12 05:33:491363ProxyConfigServiceLinux::Delegate::GetLatestProxyConfig(
1364 ProxyConfigWithAnnotation* config) {
Matt Menke75765062017-11-21 01:21:161365 // This is called from the main TaskRunner.
1366 DCHECK(!main_task_runner_.get() ||
1367 main_task_runner_->RunsTasksInCurrentSequence());
[email protected]3e44697f2009-05-22 14:37:391368
1369 // Simply return the last proxy configuration that glib_default_loop
1370 // notified us of.
Eric Roman750af4b12018-02-22 22:38:531371 *config = GetConfigOrDirect(cached_config_);
[email protected]119655002010-07-23 06:02:401372
[email protected]3a29593d2011-04-11 10:07:521373 // We return CONFIG_VALID to indicate that *config was filled in. It is always
[email protected]119655002010-07-23 06:02:401374 // going to be available since we initialized eagerly on the UI thread.
1375 // TODO(eroman): do lazy initialization instead, so we no longer need
1376 // to construct ProxyConfigServiceLinux on the UI thread.
1377 // In which case, we may return false here.
[email protected]3a29593d2011-04-11 10:07:521378 return CONFIG_VALID;
[email protected]3e44697f2009-05-22 14:37:391379}
1380
[email protected]573c0502011-05-17 22:19:501381// Depending on the SettingGetter in use, this method will be called
Tim Brown2a19f3b2017-12-12 01:08:401382// on either the UI thread (GSettings) or the file thread (KDE).
[email protected]3e44697f2009-05-22 14:37:391383void ProxyConfigServiceLinux::Delegate::OnCheckProxyConfigSettings() {
eroman0070d412017-06-22 22:18:241384 scoped_refptr<base::SequencedTaskRunner> required_loop =
[email protected]76722472012-05-24 08:26:461385 setting_getter_->GetNotificationTaskRunner();
eroman0070d412017-06-22 22:18:241386 DCHECK(!required_loop.get() || required_loop->RunsTasksInCurrentSequence());
Anton Bikineev068d2912021-05-15 20:43:521387 absl::optional<ProxyConfigWithAnnotation> new_config =
Ramin Halavatica8d5252018-03-12 05:33:491388 GetConfigFromSettings();
[email protected]3e44697f2009-05-22 14:37:391389
[email protected]119655002010-07-23 06:02:401390 // See if it is different from what we had before.
Eric Roman750af4b12018-02-22 22:38:531391 if (new_config.has_value() != reference_config_.has_value() ||
Eric Roman3e185842018-06-01 18:10:521392 (new_config.has_value() &&
1393 !new_config->value().Equals(reference_config_->value()))) {
Matt Menke75765062017-11-21 01:21:161394 // Post a task to the main TaskRunner with the new configuration, so it can
[email protected]3e44697f2009-05-22 14:37:391395 // update |cached_config_|.
Matt Menke75765062017-11-21 01:21:161396 main_task_runner_->PostTask(
1397 FROM_HERE,
kylecharf4fe5172019-02-15 18:53:491398 base::BindOnce(&ProxyConfigServiceLinux::Delegate::SetNewProxyConfig,
1399 this, new_config));
[email protected]d1f9d472009-08-13 19:59:301400 // Update the thread-private copy in |reference_config_| as well.
1401 reference_config_ = new_config;
[email protected]d3066142011-05-10 02:36:201402 } else {
1403 VLOG(1) << "Detected no-op change to proxy settings. Doing nothing.";
[email protected]3e44697f2009-05-22 14:37:391404 }
1405}
1406
1407void ProxyConfigServiceLinux::Delegate::SetNewProxyConfig(
Anton Bikineev068d2912021-05-15 20:43:521408 const absl::optional<ProxyConfigWithAnnotation>& new_config) {
Matt Menke75765062017-11-21 01:21:161409 DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
[email protected]b30a3f52010-10-16 01:05:461410 VLOG(1) << "Proxy configuration changed";
[email protected]3e44697f2009-05-22 14:37:391411 cached_config_ = new_config;
Eric Roman750af4b12018-02-22 22:38:531412 for (auto& observer : observers_) {
1413 observer.OnProxyConfigChanged(GetConfigOrDirect(new_config),
1414 ProxyConfigService::CONFIG_VALID);
1415 }
[email protected]3e44697f2009-05-22 14:37:391416}
1417
1418void ProxyConfigServiceLinux::Delegate::PostDestroyTask() {
thestig0c412e852016-06-30 08:04:401419 if (!setting_getter_)
[email protected]d7395e732009-08-28 23:13:431420 return;
thestig0c412e852016-06-30 08:04:401421
eroman0070d412017-06-22 22:18:241422 scoped_refptr<base::SequencedTaskRunner> shutdown_loop =
[email protected]76722472012-05-24 08:26:461423 setting_getter_->GetNotificationTaskRunner();
eroman0070d412017-06-22 22:18:241424 if (!shutdown_loop.get() || shutdown_loop->RunsTasksInCurrentSequence()) {
[email protected]3e44697f2009-05-22 14:37:391425 // Already on the right thread, call directly.
1426 // This is the case for the unittests.
1427 OnDestroy();
1428 } else {
[email protected]d7395e732009-08-28 23:13:431429 // Post to shutdown thread. Note that on browser shutdown, we may quit
1430 // this MessageLoop and exit the program before ever running this.
kylecharf4fe5172019-02-15 18:53:491431 shutdown_loop->PostTask(
1432 FROM_HERE,
1433 base::BindOnce(&ProxyConfigServiceLinux::Delegate::OnDestroy, this));
[email protected]3e44697f2009-05-22 14:37:391434 }
1435}
1436void ProxyConfigServiceLinux::Delegate::OnDestroy() {
eroman0070d412017-06-22 22:18:241437 scoped_refptr<base::SequencedTaskRunner> shutdown_loop =
[email protected]76722472012-05-24 08:26:461438 setting_getter_->GetNotificationTaskRunner();
eroman0070d412017-06-22 22:18:241439 DCHECK(!shutdown_loop.get() || shutdown_loop->RunsTasksInCurrentSequence());
[email protected]573c0502011-05-17 22:19:501440 setting_getter_->ShutDown();
[email protected]3e44697f2009-05-22 14:37:391441}
1442
1443ProxyConfigServiceLinux::ProxyConfigServiceLinux()
Tsuyoshi Horo2c0a5042022-07-06 05:53:071444 : delegate_(base::MakeRefCounted<Delegate>(base::Environment::Create(),
1445 absl::nullopt,
1446 absl::nullopt)) {}
[email protected]3e44697f2009-05-22 14:37:391447
[email protected]8e1845e12010-09-15 19:22:241448ProxyConfigServiceLinux::~ProxyConfigServiceLinux() {
1449 delegate_->PostDestroyTask();
1450}
1451
[email protected]3e44697f2009-05-22 14:37:391452ProxyConfigServiceLinux::ProxyConfigServiceLinux(
Ramin Halavatica8d5252018-03-12 05:33:491453 std::unique_ptr<base::Environment> env_var_getter,
1454 const NetworkTrafficAnnotationTag& traffic_annotation)
Tsuyoshi Horo2c0a5042022-07-06 05:53:071455 : delegate_(base::MakeRefCounted<Delegate>(std::move(env_var_getter),
1456 absl::nullopt,
1457 traffic_annotation)) {}
[email protected]9a3d8d42009-09-03 17:01:461458
1459ProxyConfigServiceLinux::ProxyConfigServiceLinux(
thestig0c412e852016-06-30 08:04:401460 std::unique_ptr<base::Environment> env_var_getter,
Tsuyoshi Horo5f63d342022-07-11 02:00:471461 std::unique_ptr<SettingGetter> setting_getter,
Ramin Halavatica8d5252018-03-12 05:33:491462 const NetworkTrafficAnnotationTag& traffic_annotation)
Tsuyoshi Horo2c0a5042022-07-06 05:53:071463 : delegate_(base::MakeRefCounted<Delegate>(std::move(env_var_getter),
Tsuyoshi Horo5f63d342022-07-11 02:00:471464 std::move(setting_getter),
Tsuyoshi Horo2c0a5042022-07-06 05:53:071465 traffic_annotation)) {}
[email protected]861c6c62009-04-20 16:50:561466
[email protected]e4be2dd2010-12-14 00:44:391467void ProxyConfigServiceLinux::AddObserver(Observer* observer) {
1468 delegate_->AddObserver(observer);
1469}
1470
1471void ProxyConfigServiceLinux::RemoveObserver(Observer* observer) {
1472 delegate_->RemoveObserver(observer);
1473}
1474
[email protected]3a29593d2011-04-11 10:07:521475ProxyConfigService::ConfigAvailability
Ramin Halavatica8d5252018-03-12 05:33:491476ProxyConfigServiceLinux::GetLatestProxyConfig(
1477 ProxyConfigWithAnnotation* config) {
[email protected]e4be2dd2010-12-14 00:44:391478 return delegate_->GetLatestProxyConfig(config);
1479}
1480
[email protected]861c6c62009-04-20 16:50:561481} // namespace net