OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "net/proxy/proxy_config_service_linux.h" |
| 6 |
| 7 #include <gconf/gconf-client.h> |
| 8 #include <gdk/gdk.h> |
| 9 #include <stdlib.h> |
| 10 |
| 11 #include "base/logging.h" |
| 12 #include "base/string_tokenizer.h" |
| 13 #include "base/string_util.h" |
| 14 #include "googleurl/src/url_canon.h" |
| 15 #include "net/base/net_errors.h" |
| 16 #include "net/http/http_util.h" |
| 17 #include "net/proxy/proxy_config.h" |
| 18 #include "net/proxy/proxy_server.h" |
| 19 |
| 20 namespace net { |
| 21 |
| 22 namespace { |
| 23 |
| 24 class EnvironmentVariableGetterImpl |
| 25 : public ProxyConfigServiceLinux::EnvironmentVariableGetter { |
| 26 public: |
| 27 virtual bool Getenv(const char* variable_name, std::string* result) { |
| 28 const char* env_value = ::getenv(variable_name); |
| 29 if (env_value) { |
| 30 // Note that the variable may be defined but empty. |
| 31 *result = env_value; |
| 32 return true; |
| 33 } |
| 34 // Some commonly used variable names are uppercase while others |
| 35 // are lowercase, which is inconsistent. Let's try to be helpful |
| 36 // and look for a variable name with the reverse case. |
| 37 char first_char = variable_name[0]; |
| 38 std::string alternate_case_var; |
| 39 if (first_char >= 'a' && first_char <= 'z') |
| 40 alternate_case_var = StringToUpperASCII(std::string(variable_name)); |
| 41 else if (first_char >= 'A' && first_char <= 'Z') |
| 42 alternate_case_var = StringToLowerASCII(std::string(variable_name)); |
| 43 else |
| 44 return false; |
| 45 env_value = ::getenv(alternate_case_var.c_str()); |
| 46 if (env_value) { |
| 47 *result = env_value; |
| 48 return true; |
| 49 } |
| 50 return false; |
| 51 } |
| 52 }; |
| 53 |
| 54 // Given a proxy hostname from a setting, returns that hostname with |
| 55 // an appropriate proxy server scheme prefix. |
| 56 // scheme indicates the desired proxy scheme: usually http, with |
| 57 // socks 4 or 5 as special cases. |
| 58 std::string FixupProxyHostScheme(ProxyServer::Scheme scheme, |
| 59 std::string host) { |
| 60 if (scheme == ProxyServer::SCHEME_SOCKS4 && |
| 61 StartsWithASCII(host, "socks5://", false)) { |
| 62 // We default to socks 4, but if the user specifically set it to |
| 63 // socks5://, then use that. |
| 64 scheme = ProxyServer::SCHEME_SOCKS5; |
| 65 } |
| 66 // Strip the scheme if any. |
| 67 std::string::size_type colon = host.find("://"); |
| 68 if (colon != std::string::npos) |
| 69 host = host.substr(colon + 3); |
| 70 // If a username and perhaps password are specified, give a warning. |
| 71 std::string::size_type at_sign = host.find("@"); |
| 72 // Should this be supported? |
| 73 if (at_sign != std::string::npos) { |
| 74 LOG(ERROR) << "ProxyConfigServiceLinux: proxy authentication " |
| 75 "not supported"; |
| 76 // Disregard the authentication parameters and continue with this hostname. |
| 77 host = host.substr(at_sign + 1); |
| 78 } |
| 79 // If this is a socks proxy, prepend a scheme so as to tell |
| 80 // ProxyServer. This also allows ProxyServer to choose the right |
| 81 // default port. |
| 82 if (scheme == ProxyServer::SCHEME_SOCKS4) |
| 83 host = "socks4://" + host; |
| 84 else if (scheme == ProxyServer::SCHEME_SOCKS5) |
| 85 host = "socks5://" + host; |
| 86 return host; |
| 87 } |
| 88 |
| 89 } // namespace |
| 90 |
| 91 bool ProxyConfigServiceLinux::GetProxyFromEnvVarForScheme( |
| 92 const char* variable, ProxyServer::Scheme scheme, |
| 93 ProxyServer* result_server) { |
| 94 std::string env_value; |
| 95 if (env_var_getter_->Getenv(variable, &env_value)) { |
| 96 if (!env_value.empty()) { |
| 97 env_value = FixupProxyHostScheme(scheme, env_value); |
| 98 ProxyServer proxy_server = ProxyServer::FromURI(env_value); |
| 99 if (proxy_server.is_valid() && !proxy_server.is_direct()) { |
| 100 *result_server = proxy_server; |
| 101 return true; |
| 102 } else { |
| 103 LOG(ERROR) << "ProxyConfigServiceLinux: failed to parse " |
| 104 << "environment variable " << variable; |
| 105 } |
| 106 } |
| 107 } |
| 108 return false; |
| 109 } |
| 110 |
| 111 bool ProxyConfigServiceLinux::GetProxyFromEnvVar( |
| 112 const char* variable, ProxyServer* result_server) { |
| 113 return GetProxyFromEnvVarForScheme(variable, ProxyServer::SCHEME_HTTP, |
| 114 result_server); |
| 115 } |
| 116 |
| 117 namespace { |
| 118 |
| 119 // Returns true if the given string represents an IP address. |
| 120 bool IsIPAddress(const std::string& domain) { |
| 121 // From GURL::HostIsIPAddress() |
| 122 url_canon::RawCanonOutputT<char, 128> ignored_output; |
| 123 url_parse::Component ignored_component; |
| 124 url_parse::Component domain_comp(0, domain.size()); |
| 125 return url_canon::CanonicalizeIPAddress(domain.c_str(), domain_comp, |
| 126 &ignored_output, |
| 127 &ignored_component); |
| 128 } |
| 129 |
| 130 } // namespace |
| 131 |
| 132 void ProxyConfigServiceLinux::ParseNoProxyList(const std::string& no_proxy, |
| 133 ProxyConfig* config) { |
| 134 if (no_proxy.empty()) |
| 135 return; |
| 136 // Traditional semantics: |
| 137 // A single "*" is specifically allowed and unproxies anything. |
| 138 // "*" wildcards other than a single "*" entry are not universally |
| 139 // supported. We will support them, as we get * wildcards for free |
| 140 // (see MatchPattern() called from ProxyService::ShouldBypassProxyForURL()). |
| 141 // no_proxy is a comma-separated list of <trailing_domain>[:<port>]. |
| 142 // If no port is specified then any port matches. |
| 143 // The historical definition has trailing_domain match using a simple |
| 144 // string "endswith" test, so that the match need not correspond to a |
| 145 // "." boundary. For example: "google.com" matches "igoogle.com" too. |
| 146 // Seems like that could be confusing, but we'll obey tradition. |
| 147 // IP CIDR patterns are supposed to be supported too. We intend |
| 148 // to do this in proxy_service.cc, but it's currently a TODO. |
| 149 // See: http://crbug.com/9835. |
| 150 StringTokenizer no_proxy_list(no_proxy, ","); |
| 151 while (no_proxy_list.GetNext()) { |
| 152 std::string bypass_entry = no_proxy_list.token(); |
| 153 TrimWhitespaceASCII(bypass_entry, TRIM_ALL, &bypass_entry); |
| 154 if (bypass_entry.empty()) |
| 155 continue; |
| 156 if (bypass_entry.at(0) != '*') { |
| 157 // Insert a wildcard * to obtain an endsWith match, unless the |
| 158 // entry looks like it might be an IP or CIDR. |
| 159 // First look for either a :<port> or CIDR mask length suffix. |
| 160 std::string::const_iterator begin = bypass_entry.begin(); |
| 161 std::string::const_iterator scan = bypass_entry.end() - 1; |
| 162 while (scan > begin && IsAsciiDigit(*scan)) |
| 163 --scan; |
| 164 std::string potential_ip; |
| 165 if (*scan == '/' || *scan == ':') |
| 166 potential_ip = std::string(begin, scan - 1); |
| 167 else |
| 168 potential_ip = bypass_entry; |
| 169 if (!IsIPAddress(potential_ip)) { |
| 170 // Do insert a wildcard. |
| 171 bypass_entry.insert(0, "*"); |
| 172 } |
| 173 // TODO(sdoyon): When CIDR matching is implemented in |
| 174 // proxy_service.cc, consider making config->proxy_bypass more |
| 175 // sophisticated to avoid parsing out the string on every |
| 176 // request. |
| 177 } |
| 178 config->proxy_bypass.push_back(bypass_entry); |
| 179 } |
| 180 } |
| 181 |
| 182 bool ProxyConfigServiceLinux::GetConfigFromEnv(ProxyConfig* config) { |
| 183 // Check for automatic configuration first, in |
| 184 // "auto_proxy". Possibly only the "environment_proxy" firefox |
| 185 // extension has ever used this, but it still sounds like a good |
| 186 // idea. |
| 187 std::string auto_proxy; |
| 188 if (env_var_getter_->Getenv("auto_proxy", &auto_proxy)) { |
| 189 if (auto_proxy.empty()) { |
| 190 // Defined and empty => autodetect |
| 191 config->auto_detect = true; |
| 192 } else { |
| 193 // specified autoconfig URL |
| 194 config->pac_url = GURL(auto_proxy); |
| 195 } |
| 196 return true; |
| 197 } |
| 198 // "all_proxy" is a shortcut to avoid defining {http,https,ftp}_proxy. |
| 199 ProxyServer proxy_server; |
| 200 if (GetProxyFromEnvVar("all_proxy", &proxy_server)) { |
| 201 config->proxy_rules.type = ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY; |
| 202 config->proxy_rules.single_proxy = proxy_server; |
| 203 } else { |
| 204 bool have_http = GetProxyFromEnvVar("http_proxy", &proxy_server); |
| 205 if (have_http) |
| 206 config->proxy_rules.proxy_for_http = proxy_server; |
| 207 // It would be tempting to let http_proxy apply for all protocols |
| 208 // if https_proxy and ftp_proxy are not defined. Googling turns up |
| 209 // several documents that mention only http_proxy. But then the |
| 210 // user really might not want to proxy https. And it doesn't seem |
| 211 // like other apps do this. So we will refrain. |
| 212 bool have_https = GetProxyFromEnvVar("https_proxy", &proxy_server); |
| 213 if (have_https) |
| 214 config->proxy_rules.proxy_for_https = proxy_server; |
| 215 bool have_ftp = GetProxyFromEnvVar("ftp_proxy", &proxy_server); |
| 216 if (have_ftp) |
| 217 config->proxy_rules.proxy_for_ftp = proxy_server; |
| 218 if (have_http || have_https || have_ftp) { |
| 219 // mustn't change type unless some rules are actually set. |
| 220 config->proxy_rules.type = ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME; |
| 221 } |
| 222 } |
| 223 if (config->proxy_rules.empty()) { |
| 224 // If the above were not defined, try for socks. |
| 225 ProxyServer::Scheme scheme = ProxyServer::SCHEME_SOCKS4; |
| 226 std::string env_version; |
| 227 if (env_var_getter_->Getenv("SOCKS_VERSION", &env_version) |
| 228 && env_version.compare("5") == 0) |
| 229 scheme = ProxyServer::SCHEME_SOCKS5; |
| 230 if (GetProxyFromEnvVarForScheme("SOCKS_SERVER", scheme, &proxy_server)) { |
| 231 config->proxy_rules.type = ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY; |
| 232 config->proxy_rules.single_proxy = proxy_server; |
| 233 } |
| 234 } |
| 235 // Look for the proxy bypass list. |
| 236 std::string no_proxy; |
| 237 env_var_getter_->Getenv("no_proxy", &no_proxy); |
| 238 if (config->proxy_rules.empty()) { |
| 239 // Having only "no_proxy" set, presumably to "*", makes it |
| 240 // explicit that env vars do specify a configuration: having no |
| 241 // rules specified only means the user explicitly asks for direct |
| 242 // connections. |
| 243 return !no_proxy.empty(); |
| 244 } |
| 245 ParseNoProxyList(no_proxy, config); |
| 246 return true; |
| 247 } |
| 248 |
| 249 namespace { |
| 250 |
| 251 class GConfSettingGetterImpl |
| 252 : public ProxyConfigServiceLinux::GConfSettingGetter { |
| 253 public: |
| 254 GConfSettingGetterImpl() : client_(NULL) {} |
| 255 virtual ~GConfSettingGetterImpl() { |
| 256 if (client_) |
| 257 g_object_unref(client_); |
| 258 } |
| 259 |
| 260 virtual void Enter() { |
| 261 gdk_threads_enter(); |
| 262 } |
| 263 virtual void Leave() { |
| 264 gdk_threads_leave(); |
| 265 } |
| 266 |
| 267 virtual bool InitIfNeeded() { |
| 268 if (!client_) { |
| 269 Enter(); |
| 270 client_ = gconf_client_get_default(); |
| 271 Leave(); |
| 272 // It's not clear whether/when this can return NULL. |
| 273 if (!client_) |
| 274 LOG(ERROR) << "ProxyConfigServiceLinux: Unable to create " |
| 275 "a gconf client"; |
| 276 } |
| 277 return client_ != NULL; |
| 278 } |
| 279 |
| 280 virtual bool GetString(const char* key, std::string* result) { |
| 281 CHECK(client_); |
| 282 GError* error = NULL; |
| 283 gchar* value = gconf_client_get_string(client_, key, &error); |
| 284 if (HandleGError(error, key)) |
| 285 return false; |
| 286 if (!value) |
| 287 return false; |
| 288 *result = value; |
| 289 g_free(value); |
| 290 return true; |
| 291 } |
| 292 virtual bool GetBoolean(const char* key, bool* result) { |
| 293 CHECK(client_); |
| 294 GError* error = NULL; |
| 295 // We want to distinguish unset values from values defaulting to |
| 296 // false. For that we need to use the type-generic |
| 297 // gconf_client_get() rather than gconf_client_get_bool(). |
| 298 GConfValue* gconf_value = gconf_client_get(client_, key, &error); |
| 299 if (HandleGError(error, key)) |
| 300 return false; |
| 301 if (!gconf_value) { |
| 302 // Unset. |
| 303 return false; |
| 304 } |
| 305 if (gconf_value->type != GCONF_VALUE_BOOL) { |
| 306 gconf_value_free(gconf_value); |
| 307 return false; |
| 308 } |
| 309 gboolean bool_value = gconf_value_get_bool(gconf_value); |
| 310 *result = static_cast<bool>(bool_value); |
| 311 gconf_value_free(gconf_value); |
| 312 return true; |
| 313 } |
| 314 virtual bool GetInt(const char* key, int* result) { |
| 315 CHECK(client_); |
| 316 GError* error = NULL; |
| 317 int value = gconf_client_get_int(client_, key, &error); |
| 318 if (HandleGError(error, key)) |
| 319 return false; |
| 320 // We don't bother to distinguish an unset value because callers |
| 321 // don't care. 0 is returned if unset. |
| 322 *result = value; |
| 323 return true; |
| 324 } |
| 325 virtual bool GetStringList(const char* key, |
| 326 std::vector<std::string>* result) { |
| 327 CHECK(client_); |
| 328 GError* error = NULL; |
| 329 GSList* list = gconf_client_get_list(client_, key, |
| 330 GCONF_VALUE_STRING, &error); |
| 331 if (HandleGError(error, key)) |
| 332 return false; |
| 333 if (!list) { |
| 334 // unset |
| 335 return false; |
| 336 } |
| 337 for (GSList *it = list; it; it = it->next) { |
| 338 result->push_back(static_cast<char*>(it->data)); |
| 339 g_free(it->data); |
| 340 } |
| 341 g_slist_free(list); |
| 342 return true; |
| 343 } |
| 344 |
| 345 private: |
| 346 // Logs and frees a glib error. Returns false if there was no error |
| 347 // (error is NULL). |
| 348 bool HandleGError(GError* error, const char* key) { |
| 349 if (error != NULL) { |
| 350 LOG(ERROR) << "ProxyConfigServiceLinux: error getting gconf value for " |
| 351 << key << ": " << error->message; |
| 352 g_error_free(error); |
| 353 return true; |
| 354 } |
| 355 return false; |
| 356 } |
| 357 |
| 358 GConfClient* client_; |
| 359 |
| 360 DISALLOW_COPY_AND_ASSIGN(GConfSettingGetterImpl); |
| 361 }; |
| 362 |
| 363 } // namespace |
| 364 |
| 365 bool ProxyConfigServiceLinux::GetProxyFromGConf( |
| 366 const char* key_prefix, bool is_socks, ProxyServer* result_server) { |
| 367 std::string key(key_prefix); |
| 368 std::string host; |
| 369 if (!gconf_getter_->GetString((key + "host").c_str(), &host) |
| 370 || host.empty()) { |
| 371 // Unset or empty. |
| 372 return false; |
| 373 } |
| 374 // Check for an optional port. |
| 375 int port; |
| 376 gconf_getter_->GetInt((key + "port").c_str(), &port); |
| 377 if (port != 0) { |
| 378 // If a port is set and non-zero: |
| 379 host += ":" + IntToString(port); |
| 380 } |
| 381 host = FixupProxyHostScheme( |
| 382 is_socks ? ProxyServer::SCHEME_SOCKS4 : ProxyServer::SCHEME_HTTP, |
| 383 host); |
| 384 ProxyServer proxy_server = ProxyServer::FromURI(host); |
| 385 if (proxy_server.is_valid()) { |
| 386 *result_server = proxy_server; |
| 387 return true; |
| 388 } |
| 389 return false; |
| 390 } |
| 391 |
| 392 bool ProxyConfigServiceLinux::GetConfigFromGConf(ProxyConfig* config) { |
| 393 std::string mode; |
| 394 if (!gconf_getter_->GetString("/system/proxy/mode", &mode)) { |
| 395 // We expect this to always be set, so if we don't see it then we |
| 396 // probably have a gconf problem, and so we don't have a valid |
| 397 // proxy config. |
| 398 return false; |
| 399 } |
| 400 if (mode.compare("none") == 0) |
| 401 // Specifically specifies no proxy. |
| 402 return true; |
| 403 |
| 404 if (mode.compare("auto") == 0) { |
| 405 // automatic proxy config |
| 406 std::string pac_url_str; |
| 407 if (gconf_getter_->GetString("/system/proxy/autoconfig_url", |
| 408 &pac_url_str)) { |
| 409 if (!pac_url_str.empty()) { |
| 410 GURL pac_url(pac_url_str); |
| 411 if (!pac_url.is_valid()) |
| 412 return false; |
| 413 config->pac_url = pac_url; |
| 414 return true; |
| 415 } |
| 416 } |
| 417 config->auto_detect = true; |
| 418 return true; |
| 419 } |
| 420 |
| 421 if (mode.compare("manual") != 0) { |
| 422 // Mode is unrecognized. |
| 423 return false; |
| 424 } |
| 425 bool use_http_proxy; |
| 426 if (gconf_getter_->GetBoolean("/system/http_proxy/use_http_proxy", |
| 427 &use_http_proxy) |
| 428 && !use_http_proxy) { |
| 429 // Another master switch for some reason. If set to false, then no |
| 430 // proxy. But we don't panic if the key doesn't exist. |
| 431 return true; |
| 432 } |
| 433 |
| 434 bool same_proxy = false; |
| 435 // Indicates to use the http proxy for all protocols. This one may |
| 436 // not exist (presumably on older versions), assume false in that |
| 437 // case. |
| 438 gconf_getter_->GetBoolean("/system/http_proxy/use_same_proxy", |
| 439 &same_proxy); |
| 440 |
| 441 ProxyServer proxy_server; |
| 442 if (!same_proxy) { |
| 443 // Try socks. |
| 444 if (GetProxyFromGConf("/system/proxy/socks_", true, &proxy_server)) { |
| 445 // gconf settings do not appear to distinguish between socks |
| 446 // version. We default to version 4. |
| 447 config->proxy_rules.type = ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY; |
| 448 config->proxy_rules.single_proxy = proxy_server; |
| 449 } |
| 450 } |
| 451 if (config->proxy_rules.empty()) { |
| 452 bool have_http = GetProxyFromGConf("/system/http_proxy/", false, |
| 453 &proxy_server); |
| 454 if (same_proxy) { |
| 455 if (have_http) { |
| 456 config->proxy_rules.type = ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY; |
| 457 config->proxy_rules.single_proxy = proxy_server; |
| 458 } |
| 459 } else { |
| 460 // Protocol specific settings. |
| 461 if (have_http) |
| 462 config->proxy_rules.proxy_for_http = proxy_server; |
| 463 bool have_secure = GetProxyFromGConf("/system/proxy/secure_", false, |
| 464 &proxy_server); |
| 465 if (have_secure) |
| 466 config->proxy_rules.proxy_for_https = proxy_server; |
| 467 bool have_ftp = GetProxyFromGConf("/system/proxy/ftp_", false, |
| 468 &proxy_server); |
| 469 if (have_ftp) |
| 470 config->proxy_rules.proxy_for_ftp = proxy_server; |
| 471 if (have_http || have_secure || have_ftp) |
| 472 config->proxy_rules.type = |
| 473 ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME; |
| 474 } |
| 475 } |
| 476 |
| 477 if (config->proxy_rules.empty()) { |
| 478 // Manual mode but we couldn't parse any rules. |
| 479 return false; |
| 480 } |
| 481 |
| 482 // Check for authentication, just so we can warn. |
| 483 bool use_auth; |
| 484 gconf_getter_->GetBoolean("/system/http_proxy/use_authentication", |
| 485 &use_auth); |
| 486 if (use_auth) |
| 487 LOG(ERROR) << "ProxyConfigServiceLinux: proxy authentication " |
| 488 "not supported"; |
| 489 |
| 490 // Now the bypass list. |
| 491 gconf_getter_->GetStringList("/system/http_proxy/ignore_hosts", |
| 492 &config->proxy_bypass); |
| 493 // Note that there are no settings with semantics corresponding to |
| 494 // config->proxy_bypass_local_names. |
| 495 |
| 496 return true; |
| 497 } |
| 498 |
| 499 ProxyConfigServiceLinux::ProxyConfigServiceLinux( |
| 500 EnvironmentVariableGetter* env_var_getter, |
| 501 GConfSettingGetter* gconf_getter) |
| 502 : env_var_getter_(env_var_getter), gconf_getter_(gconf_getter) { |
| 503 } |
| 504 |
| 505 ProxyConfigServiceLinux::ProxyConfigServiceLinux() |
| 506 : env_var_getter_(new EnvironmentVariableGetterImpl()), |
| 507 gconf_getter_(new GConfSettingGetterImpl()) { |
| 508 } |
| 509 |
| 510 int ProxyConfigServiceLinux::GetProxyConfig(ProxyConfig* config) { |
| 511 // GNOME_DESKTOP_SESSION_ID being defined is a good indication that |
| 512 // we are probably running under GNOME. |
| 513 // Note: KDE_FULL_SESSION is a corresponding env var to recognize KDE. |
| 514 std::string dummy, desktop_session; |
| 515 bool ok = false; |
| 516 if (env_var_getter_->Getenv("GNOME_DESKTOP_SESSION_ID", &dummy) |
| 517 || (env_var_getter_->Getenv("DESKTOP_SESSION", &desktop_session) |
| 518 && desktop_session.compare("gnome"))) { |
| 519 // Get settings from gconf. |
| 520 // |
| 521 // I (sdoyon) would have liked to prioritize environment variables |
| 522 // and only fallback to gconf if env vars were unset. But |
| 523 // gnome-terminal "helpfully" sets http_proxy and no_proxy, and it |
| 524 // does so even if the proxy mode is set to auto, which would |
| 525 // mislead us. |
| 526 // |
| 527 // We could introduce a CHROME_PROXY_OBEY_ENV_VARS variable...?? |
| 528 if (gconf_getter_->InitIfNeeded()) { |
| 529 gconf_getter_->Enter(); |
| 530 ok = GetConfigFromGConf(config); |
| 531 gconf_getter_->Leave(); |
| 532 if (ok) |
| 533 LOG(INFO) << "ProxyConfigServiceLinux: obtained proxy setting " |
| 534 "from gconf"; |
| 535 // If gconf proxy mode is "none", meaning direct, then we take |
| 536 // that to be a valid config and will not check environment variables. |
| 537 // The alternative would have been to look for a proxy whereever |
| 538 // we can find one. |
| 539 // |
| 540 // TODO(sdoyon): Consider wiring in the gconf notification |
| 541 // system. Cache this result config to return on subsequent calls, |
| 542 // and only call GetConfigFromGConf() when we know things have |
| 543 // actually changed. |
| 544 } |
| 545 } |
| 546 // An implementation for KDE settings would be welcome here. |
| 547 if (!ok) { |
| 548 ok = GetConfigFromEnv(config); |
| 549 if (ok) |
| 550 LOG(INFO) << "ProxyConfigServiceLinux: obtained proxy setting " |
| 551 "from environment variables"; |
| 552 } |
| 553 return ok ? OK : ERR_FAILED; |
| 554 } |
| 555 |
| 556 } // namespace net |
OLD | NEW |