15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/proxy/proxy_config_service_linux.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <fcntl.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_GCONF)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <gconf/gconf-client.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // defined(USE_GCONF)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <limits.h>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h>
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/inotify.h>
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unistd.h>
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <map>
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
2246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/debug/leak_annotations.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/environment.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/files/scoped_file.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
28ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/message_loop.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/nix/xdg_util.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/single_thread_task_runner.h"
315e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_tokenizer.h"
33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/strings/string_util.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread_restrictions.h"
35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/timer/timer.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_util.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/proxy/proxy_config.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/proxy/proxy_server.h"
407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/url_canon.h"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(USE_GIO)
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "library_loaders/libgio.h"
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif  // defined(USE_GIO)
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Given a proxy hostname from a setting, returns that hostname with
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// an appropriate proxy server scheme prefix.
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// scheme indicates the desired proxy scheme: usually http, with
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// socks 4 or 5 as special cases.
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(arindam): Remove URI string manipulation by using MapUrlSchemeToProxy.
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string FixupProxyHostScheme(ProxyServer::Scheme scheme,
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 std::string host) {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (scheme == ProxyServer::SCHEME_SOCKS5 &&
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      StartsWithASCII(host, "socks4://", false)) {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We default to socks 5, but if the user specifically set it to
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // socks4://, then use that.
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scheme = ProxyServer::SCHEME_SOCKS4;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Strip the scheme if any.
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string::size_type colon = host.find("://");
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (colon != std::string::npos)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host = host.substr(colon + 3);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If a username and perhaps password are specified, give a warning.
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string::size_type at_sign = host.find("@");
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Should this be supported?
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (at_sign != std::string::npos) {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // ProxyConfig does not support authentication parameters, but Chrome
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // will prompt for the password later. Disregard the
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // authentication parameters and continue with this hostname.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Proxy authentication parameters ignored, see bug 16709";
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host = host.substr(at_sign + 1);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If this is a socks proxy, prepend a scheme so as to tell
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ProxyServer. This also allows ProxyServer to choose the right
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // default port.
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (scheme == ProxyServer::SCHEME_SOCKS4)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host = "socks4://" + host;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else if (scheme == ProxyServer::SCHEME_SOCKS5)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host = "socks5://" + host;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If there is a trailing slash, remove it so |host| will parse correctly
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // even if it includes a port number (since the slash is not numeric).
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (host.length() && host[host.length() - 1] == '/')
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host.resize(host.length() - 1);
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return host;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProxyConfigServiceLinux::Delegate::~Delegate() {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProxyConfigServiceLinux::Delegate::GetProxyFromEnvVarForScheme(
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* variable, ProxyServer::Scheme scheme,
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProxyServer* result_server) {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string env_value;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (env_var_getter_->GetVar(variable, &env_value)) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!env_value.empty()) {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      env_value = FixupProxyHostScheme(scheme, env_value);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ProxyServer proxy_server =
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ProxyServer::FromURI(env_value, ProxyServer::SCHEME_HTTP);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (proxy_server.is_valid() && !proxy_server.is_direct()) {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *result_server = proxy_server;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return true;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(ERROR) << "Failed to parse environment variable " << variable;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProxyConfigServiceLinux::Delegate::GetProxyFromEnvVar(
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* variable, ProxyServer* result_server) {
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetProxyFromEnvVarForScheme(variable, ProxyServer::SCHEME_HTTP,
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     result_server);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProxyConfigServiceLinux::Delegate::GetConfigFromEnv(ProxyConfig* config) {
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check for automatic configuration first, in
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // "auto_proxy". Possibly only the "environment_proxy" firefox
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // extension has ever used this, but it still sounds like a good
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // idea.
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string auto_proxy;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (env_var_getter_->GetVar("auto_proxy", &auto_proxy)) {
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (auto_proxy.empty()) {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Defined and empty => autodetect
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      config->set_auto_detect(true);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // specified autoconfig URL
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      config->set_pac_url(GURL(auto_proxy));
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // "all_proxy" is a shortcut to avoid defining {http,https,ftp}_proxy.
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProxyServer proxy_server;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GetProxyFromEnvVar("all_proxy", &proxy_server)) {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    config->proxy_rules().type = ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY;
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    config->proxy_rules().single_proxies.SetSingleProxyServer(proxy_server);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool have_http = GetProxyFromEnvVar("http_proxy", &proxy_server);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (have_http)
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      config->proxy_rules().proxies_for_http.SetSingleProxyServer(proxy_server);
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // It would be tempting to let http_proxy apply for all protocols
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // if https_proxy and ftp_proxy are not defined. Googling turns up
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // several documents that mention only http_proxy. But then the
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // user really might not want to proxy https. And it doesn't seem
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // like other apps do this. So we will refrain.
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool have_https = GetProxyFromEnvVar("https_proxy", &proxy_server);
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (have_https)
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      config->proxy_rules().proxies_for_https.
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          SetSingleProxyServer(proxy_server);
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool have_ftp = GetProxyFromEnvVar("ftp_proxy", &proxy_server);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (have_ftp)
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      config->proxy_rules().proxies_for_ftp.SetSingleProxyServer(proxy_server);
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (have_http || have_https || have_ftp) {
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // mustn't change type unless some rules are actually set.
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      config->proxy_rules().type =
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (config->proxy_rules().empty()) {
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the above were not defined, try for socks.
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // For environment variables, we default to version 5, per the gnome
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // documentation: http://library.gnome.org/devel/gnet/stable/gnet-socks.html
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProxyServer::Scheme scheme = ProxyServer::SCHEME_SOCKS5;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string env_version;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (env_var_getter_->GetVar("SOCKS_VERSION", &env_version)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        && env_version == "4")
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scheme = ProxyServer::SCHEME_SOCKS4;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (GetProxyFromEnvVarForScheme("SOCKS_SERVER", scheme, &proxy_server)) {
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      config->proxy_rules().type = ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY;
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      config->proxy_rules().single_proxies.SetSingleProxyServer(proxy_server);
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Look for the proxy bypass list.
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string no_proxy;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  env_var_getter_->GetVar("no_proxy", &no_proxy);
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (config->proxy_rules().empty()) {
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Having only "no_proxy" set, presumably to "*", makes it
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // explicit that env vars do specify a configuration: having no
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // rules specified only means the user explicitly asks for direct
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // connections.
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return !no_proxy.empty();
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that this uses "suffix" matching. So a bypass of "google.com"
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is understood to mean a bypass of "*google.com".
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  config->proxy_rules().bypass_rules.ParseFromStringUsingSuffixMatching(
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      no_proxy);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kDebounceTimeoutMilliseconds = 250;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_GCONF)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This setting getter uses gconf, as used in GNOME 2 and some GNOME 3 desktops.
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SettingGetterImplGConf : public ProxyConfigServiceLinux::SettingGetter {
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SettingGetterImplGConf()
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : client_(NULL), system_proxy_id_(0), system_http_proxy_id_(0),
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        notify_delegate_(NULL) {
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~SettingGetterImplGConf() {
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // client_ should have been released before now, from
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Delegate::OnDestroy(), while running on the UI thread. However
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // on exiting the process, it may happen that Delegate::OnDestroy()
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // task is left pending on the glib loop after the loop was quit,
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // and pending tasks may then be deleted without being run.
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (client_) {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // gconf client was not cleaned up.
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (task_runner_->BelongsToCurrentThread()) {
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // We are on the UI thread so we can clean it safely. This is
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // the case at least for ui_tests running under Valgrind in
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // bug 16076.
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        VLOG(1) << "~SettingGetterImplGConf: releasing gconf client";
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ShutDown();
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // This is very bad! We are deleting the setting getter but we're not on
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // the UI thread. This is not supposed to happen: the setting getter is
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // owned by the proxy config service's delegate, which is supposed to be
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // destroyed on the UI thread only. We will get change notifications to
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // a deleted object if we continue here, so fail now.
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(FATAL) << "~SettingGetterImplGConf: deleting on wrong thread!";
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!client_);
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  virtual bool Init(
2361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      const scoped_refptr<base::SingleThreadTaskRunner>& glib_task_runner,
2371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner)
2381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      OVERRIDE {
2391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DCHECK(glib_task_runner->BelongsToCurrentThread());
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!client_);
241868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    DCHECK(!task_runner_.get());
2421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    task_runner_ = glib_task_runner;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    client_ = gconf_client_get_default();
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!client_) {
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // It's not clear whether/when this can return NULL.
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Unable to create a gconf client";
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      task_runner_ = NULL;
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GError* error = NULL;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool added_system_proxy = false;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We need to add the directories for which we'll be asking
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // for notifications, and we might as well ask to preload them.
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // These need to be removed again in ShutDown(); we are careful
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // here to only leave client_ non-NULL if both have been added.
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gconf_client_add_dir(client_, "/system/proxy",
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         GCONF_CLIENT_PRELOAD_ONELEVEL, &error);
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (error == NULL) {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      added_system_proxy = true;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gconf_client_add_dir(client_, "/system/http_proxy",
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           GCONF_CLIENT_PRELOAD_ONELEVEL, &error);
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (error != NULL) {
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Error requesting gconf directory: " << error->message;
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_error_free(error);
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (added_system_proxy)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        gconf_client_remove_dir(client_, "/system/proxy", NULL);
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_object_unref(client_);
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      client_ = NULL;
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      task_runner_ = NULL;
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void ShutDown() OVERRIDE {
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (client_) {
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(task_runner_->BelongsToCurrentThread());
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We must explicitly disable gconf notifications here, because the gconf
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // client will be shared between all setting getters, and they do not all
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // have the same lifetimes. (For instance, incognito sessions get their
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // own, which is destroyed when the session ends.)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gconf_client_notify_remove(client_, system_http_proxy_id_);
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gconf_client_notify_remove(client_, system_proxy_id_);
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gconf_client_remove_dir(client_, "/system/http_proxy", NULL);
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gconf_client_remove_dir(client_, "/system/proxy", NULL);
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_object_unref(client_);
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      client_ = NULL;
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      task_runner_ = NULL;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool SetUpNotifications(
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ProxyConfigServiceLinux::Delegate* delegate) OVERRIDE {
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(client_);
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(task_runner_->BelongsToCurrentThread());
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GError* error = NULL;
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    notify_delegate_ = delegate;
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We have to keep track of the IDs returned by gconf_client_notify_add() so
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // that we can remove them in ShutDown(). (Otherwise, notifications will be
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // delivered to this object after it is deleted, which is bad, m'kay?)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    system_proxy_id_ = gconf_client_notify_add(
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        client_, "/system/proxy",
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        OnGConfChangeNotification, this,
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NULL, &error);
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (error == NULL) {
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      system_http_proxy_id_ = gconf_client_notify_add(
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          client_, "/system/http_proxy",
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          OnGConfChangeNotification, this,
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          NULL, &error);
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (error != NULL) {
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Error requesting gconf notifications: " << error->message;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_error_free(error);
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ShutDown();
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Simulate a change to avoid possibly losing updates before this point.
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnChangeNotification();
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  virtual const scoped_refptr<base::SingleThreadTaskRunner>&
3241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  GetNotificationTaskRunner() OVERRIDE {
3251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return task_runner_;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ProxyConfigSource GetConfigSource() OVERRIDE {
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PROXY_CONFIG_SOURCE_GCONF;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool GetString(StringSetting key, std::string* result) OVERRIDE {
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (key) {
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PROXY_MODE:
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return GetStringByPath("/system/proxy/mode", result);
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PROXY_AUTOCONF_URL:
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return GetStringByPath("/system/proxy/autoconfig_url", result);
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PROXY_HTTP_HOST:
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return GetStringByPath("/system/http_proxy/host", result);
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PROXY_HTTPS_HOST:
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return GetStringByPath("/system/proxy/secure_host", result);
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PROXY_FTP_HOST:
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return GetStringByPath("/system/proxy/ftp_host", result);
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PROXY_SOCKS_HOST:
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return GetStringByPath("/system/proxy/socks_host", result);
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // Placate compiler.
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool GetBool(BoolSetting key, bool* result) OVERRIDE {
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (key) {
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PROXY_USE_HTTP_PROXY:
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return GetBoolByPath("/system/http_proxy/use_http_proxy", result);
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PROXY_USE_SAME_PROXY:
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return GetBoolByPath("/system/http_proxy/use_same_proxy", result);
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PROXY_USE_AUTHENTICATION:
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return GetBoolByPath("/system/http_proxy/use_authentication", result);
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // Placate compiler.
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool GetInt(IntSetting key, int* result) OVERRIDE {
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (key) {
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PROXY_HTTP_PORT:
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return GetIntByPath("/system/http_proxy/port", result);
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PROXY_HTTPS_PORT:
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return GetIntByPath("/system/proxy/secure_port", result);
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PROXY_FTP_PORT:
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return GetIntByPath("/system/proxy/ftp_port", result);
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PROXY_SOCKS_PORT:
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return GetIntByPath("/system/proxy/socks_port", result);
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // Placate compiler.
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool GetStringList(StringListSetting key,
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             std::vector<std::string>* result) OVERRIDE {
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (key) {
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PROXY_IGNORE_HOSTS:
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return GetStringListByPath("/system/http_proxy/ignore_hosts", result);
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // Placate compiler.
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool BypassListIsReversed() OVERRIDE {
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This is a KDE-specific setting.
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool MatchHostsUsingSuffixMatching() OVERRIDE {
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool GetStringByPath(const char* key, std::string* result) {
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(client_);
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(task_runner_->BelongsToCurrentThread());
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GError* error = NULL;
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gchar* value = gconf_client_get_string(client_, key, &error);
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (HandleGError(error, key))
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!value)
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *result = value;
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_free(value);
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool GetBoolByPath(const char* key, bool* result) {
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(client_);
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(task_runner_->BelongsToCurrentThread());
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GError* error = NULL;
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We want to distinguish unset values from values defaulting to
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // false. For that we need to use the type-generic
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // gconf_client_get() rather than gconf_client_get_bool().
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GConfValue* gconf_value = gconf_client_get(client_, key, &error);
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (HandleGError(error, key))
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!gconf_value) {
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Unset.
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (gconf_value->type != GCONF_VALUE_BOOL) {
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gconf_value_free(gconf_value);
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gboolean bool_value = gconf_value_get_bool(gconf_value);
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *result = static_cast<bool>(bool_value);
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gconf_value_free(gconf_value);
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool GetIntByPath(const char* key, int* result) {
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(client_);
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(task_runner_->BelongsToCurrentThread());
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GError* error = NULL;
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int value = gconf_client_get_int(client_, key, &error);
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (HandleGError(error, key))
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't bother to distinguish an unset value because callers
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // don't care. 0 is returned if unset.
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *result = value;
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool GetStringListByPath(const char* key, std::vector<std::string>* result) {
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(client_);
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(task_runner_->BelongsToCurrentThread());
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GError* error = NULL;
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GSList* list = gconf_client_get_list(client_, key,
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         GCONF_VALUE_STRING, &error);
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (HandleGError(error, key))
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!list)
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (GSList *it = list; it; it = it->next) {
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result->push_back(static_cast<char*>(it->data));
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_free(it->data);
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_slist_free(list);
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Logs and frees a glib error. Returns false if there was no error
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (error is NULL).
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool HandleGError(GError* error, const char* key) {
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (error != NULL) {
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Error getting gconf value for " << key
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << ": " << error->message;
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_error_free(error);
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is the callback from the debounce timer.
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OnDebouncedNotification() {
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(task_runner_->BelongsToCurrentThread());
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK(notify_delegate_);
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Forward to a method on the proxy config service delegate object.
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    notify_delegate_->OnCheckProxyConfigSettings();
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OnChangeNotification() {
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't use Reset() because the timer may not yet be running.
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // (In that case Stop() is a no-op.)
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    debounce_timer_.Stop();
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    debounce_timer_.Start(FROM_HERE,
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::TimeDelta::FromMilliseconds(kDebounceTimeoutMilliseconds),
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this, &SettingGetterImplGConf::OnDebouncedNotification);
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // gconf notification callback, dispatched on the default glib main loop.
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void OnGConfChangeNotification(GConfClient* client, guint cnxn_id,
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        GConfEntry* entry, gpointer user_data) {
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(1) << "gconf change notification for key "
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            << gconf_entry_get_key(entry);
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't track which key has changed, just that something did change.
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SettingGetterImplGConf* setting_getter =
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        reinterpret_cast<SettingGetterImplGConf*>(user_data);
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    setting_getter->OnChangeNotification();
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GConfClient* client_;
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // These ids are the values returned from gconf_client_notify_add(), which we
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will need in order to later call gconf_client_notify_remove().
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  guint system_proxy_id_;
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  guint system_http_proxy_id_;
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProxyConfigServiceLinux::Delegate* notify_delegate_;
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::OneShotTimer<SettingGetterImplGConf> debounce_timer_;
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Task runner for the thread that we make gconf calls on. It should
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // be the UI thread and all our methods should be called on this
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // thread. Only for assertions.
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(SettingGetterImplGConf);
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // defined(USE_GCONF)
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_GIO)
5176d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)const char kProxyGConfSchema[] = "org.gnome.system.proxy";
5186d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This setting getter uses gsettings, as used in most GNOME 3 desktops.
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SettingGetterImplGSettings
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : public ProxyConfigServiceLinux::SettingGetter {
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SettingGetterImplGSettings() :
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    client_(NULL),
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    http_client_(NULL),
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    https_client_(NULL),
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ftp_client_(NULL),
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    socks_client_(NULL),
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    notify_delegate_(NULL) {
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~SettingGetterImplGSettings() {
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // client_ should have been released before now, from
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Delegate::OnDestroy(), while running on the UI thread. However
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // on exiting the process, it may happen that
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Delegate::OnDestroy() task is left pending on the glib loop
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // after the loop was quit, and pending tasks may then be deleted
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // without being run.
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (client_) {
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // gconf client was not cleaned up.
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (task_runner_->BelongsToCurrentThread()) {
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // We are on the UI thread so we can clean it safely. This is
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // the case at least for ui_tests running under Valgrind in
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // bug 16076.
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        VLOG(1) << "~SettingGetterImplGSettings: releasing gsettings client";
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ShutDown();
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(WARNING) << "~SettingGetterImplGSettings: leaking gsettings client";
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        client_ = NULL;
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!client_);
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool SchemaExists(const char* schema_name) {
5562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const gchar* const* schemas = libgio_loader_.g_settings_list_schemas();
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (*schemas) {
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (strcmp(schema_name, static_cast<const char*>(*schemas)) == 0)
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return true;
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      schemas++;
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // LoadAndCheckVersion() must be called *before* Init()!
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool LoadAndCheckVersion(base::Environment* env);
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  virtual bool Init(
5691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      const scoped_refptr<base::SingleThreadTaskRunner>& glib_task_runner,
5701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner)
5711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      OVERRIDE {
5721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DCHECK(glib_task_runner->BelongsToCurrentThread());
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!client_);
574868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    DCHECK(!task_runner_.get());
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
57646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (!SchemaExists(kProxyGConfSchema) ||
57746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        !(client_ = libgio_loader_.g_settings_new(kProxyGConfSchema))) {
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // It's not clear whether/when this can return NULL.
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Unable to create a gsettings client";
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    task_runner_ = glib_task_runner;
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We assume these all work if the above call worked.
5842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    http_client_ = libgio_loader_.g_settings_get_child(client_, "http");
5852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    https_client_ = libgio_loader_.g_settings_get_child(client_, "https");
5862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ftp_client_ = libgio_loader_.g_settings_get_child(client_, "ftp");
5872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    socks_client_ = libgio_loader_.g_settings_get_child(client_, "socks");
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(http_client_ && https_client_ && ftp_client_ && socks_client_);
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void ShutDown() OVERRIDE {
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (client_) {
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(task_runner_->BelongsToCurrentThread());
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This also disables gsettings notifications.
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_object_unref(socks_client_);
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_object_unref(ftp_client_);
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_object_unref(https_client_);
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_object_unref(http_client_);
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_object_unref(client_);
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We only need to null client_ because it's the only one that we check.
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      client_ = NULL;
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      task_runner_ = NULL;
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool SetUpNotifications(
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ProxyConfigServiceLinux::Delegate* delegate) OVERRIDE {
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(client_);
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(task_runner_->BelongsToCurrentThread());
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    notify_delegate_ = delegate;
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We could watch for the change-event signal instead of changed, but
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // since we have to watch more than one object, we'd still have to
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // debounce change notifications. This is conceptually simpler.
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_signal_connect(G_OBJECT(client_), "changed",
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     G_CALLBACK(OnGSettingsChangeNotification), this);
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_signal_connect(G_OBJECT(http_client_), "changed",
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     G_CALLBACK(OnGSettingsChangeNotification), this);
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_signal_connect(G_OBJECT(https_client_), "changed",
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     G_CALLBACK(OnGSettingsChangeNotification), this);
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_signal_connect(G_OBJECT(ftp_client_), "changed",
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     G_CALLBACK(OnGSettingsChangeNotification), this);
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_signal_connect(G_OBJECT(socks_client_), "changed",
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     G_CALLBACK(OnGSettingsChangeNotification), this);
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Simulate a change to avoid possibly losing updates before this point.
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnChangeNotification();
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  virtual const scoped_refptr<base::SingleThreadTaskRunner>&
6311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  GetNotificationTaskRunner() OVERRIDE {
6321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return task_runner_;
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ProxyConfigSource GetConfigSource() OVERRIDE {
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PROXY_CONFIG_SOURCE_GSETTINGS;
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool GetString(StringSetting key, std::string* result) OVERRIDE {
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(client_);
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (key) {
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PROXY_MODE:
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return GetStringByPath(client_, "mode", result);
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PROXY_AUTOCONF_URL:
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return GetStringByPath(client_, "autoconfig-url", result);
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PROXY_HTTP_HOST:
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return GetStringByPath(http_client_, "host", result);
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PROXY_HTTPS_HOST:
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return GetStringByPath(https_client_, "host", result);
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PROXY_FTP_HOST:
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return GetStringByPath(ftp_client_, "host", result);
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PROXY_SOCKS_HOST:
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return GetStringByPath(socks_client_, "host", result);
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // Placate compiler.
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool GetBool(BoolSetting key, bool* result) OVERRIDE {
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(client_);
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (key) {
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PROXY_USE_HTTP_PROXY:
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Although there is an "enabled" boolean in http_client_, it is not set
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // to true by the proxy config utility. We ignore it and return false.
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PROXY_USE_SAME_PROXY:
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Similarly, although there is a "use-same-proxy" boolean in client_,
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // it is never set to false by the proxy config utility. We ignore it.
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PROXY_USE_AUTHENTICATION:
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // There is also no way to set this in the proxy config utility, but it
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // doesn't hurt us to get the actual setting (unlike the two above).
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return GetBoolByPath(http_client_, "use-authentication", result);
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // Placate compiler.
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool GetInt(IntSetting key, int* result) OVERRIDE {
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(client_);
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (key) {
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PROXY_HTTP_PORT:
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return GetIntByPath(http_client_, "port", result);
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PROXY_HTTPS_PORT:
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return GetIntByPath(https_client_, "port", result);
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PROXY_FTP_PORT:
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return GetIntByPath(ftp_client_, "port", result);
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PROXY_SOCKS_PORT:
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return GetIntByPath(socks_client_, "port", result);
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // Placate compiler.
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool GetStringList(StringListSetting key,
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             std::vector<std::string>* result) OVERRIDE {
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(client_);
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (key) {
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case PROXY_IGNORE_HOSTS:
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return GetStringListByPath(client_, "ignore-hosts", result);
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // Placate compiler.
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool BypassListIsReversed() OVERRIDE {
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This is a KDE-specific setting.
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool MatchHostsUsingSuffixMatching() OVERRIDE {
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool GetStringByPath(GSettings* client, const char* key,
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       std::string* result) {
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(task_runner_->BelongsToCurrentThread());
7122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    gchar* value = libgio_loader_.g_settings_get_string(client, key);
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!value)
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *result = value;
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_free(value);
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool GetBoolByPath(GSettings* client, const char* key, bool* result) {
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(task_runner_->BelongsToCurrentThread());
7212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *result = static_cast<bool>(
7222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        libgio_loader_.g_settings_get_boolean(client, key));
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool GetIntByPath(GSettings* client, const char* key, int* result) {
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(task_runner_->BelongsToCurrentThread());
7272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *result = libgio_loader_.g_settings_get_int(client, key);
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool GetStringListByPath(GSettings* client, const char* key,
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           std::vector<std::string>* result) {
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(task_runner_->BelongsToCurrentThread());
7332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    gchar** list = libgio_loader_.g_settings_get_strv(client, key);
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!list)
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; list[i]; ++i) {
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result->push_back(static_cast<char*>(list[i]));
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_free(list[i]);
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_free(list);
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is the callback from the debounce timer.
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OnDebouncedNotification() {
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(task_runner_->BelongsToCurrentThread());
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK(notify_delegate_);
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Forward to a method on the proxy config service delegate object.
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    notify_delegate_->OnCheckProxyConfigSettings();
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OnChangeNotification() {
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't use Reset() because the timer may not yet be running.
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // (In that case Stop() is a no-op.)
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    debounce_timer_.Stop();
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    debounce_timer_.Start(FROM_HERE,
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::TimeDelta::FromMilliseconds(kDebounceTimeoutMilliseconds),
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this, &SettingGetterImplGSettings::OnDebouncedNotification);
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // gsettings notification callback, dispatched on the default glib main loop.
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void OnGSettingsChangeNotification(GSettings* client, gchar* key,
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            gpointer user_data) {
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(1) << "gsettings change notification for key " << key;
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't track which key has changed, just that something did change.
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SettingGetterImplGSettings* setting_getter =
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        reinterpret_cast<SettingGetterImplGSettings*>(user_data);
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    setting_getter->OnChangeNotification();
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GSettings* client_;
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GSettings* http_client_;
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GSettings* https_client_;
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GSettings* ftp_client_;
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GSettings* socks_client_;
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProxyConfigServiceLinux::Delegate* notify_delegate_;
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::OneShotTimer<SettingGetterImplGSettings> debounce_timer_;
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Task runner for the thread that we make gsettings calls on. It should
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // be the UI thread and all our methods should be called on this
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // thread. Only for assertions.
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LibGioLoader libgio_loader_;
7852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(SettingGetterImplGSettings);
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SettingGetterImplGSettings::LoadAndCheckVersion(
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Environment* env) {
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // LoadAndCheckVersion() must be called *before* Init()!
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!client_);
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The APIs to query gsettings were introduced after the minimum glib
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // version we target, so we can't link directly against them. We load them
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // dynamically at runtime, and if they don't exist, return false here. (We
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // support linking directly via gyp flags though.) Additionally, even when
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // they are present, we do two additional checks to make sure we should use
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // them and not gconf. First, we attempt to load the schema for proxy
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // settings. Second, we check for the program that was used in older
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // versions of GNOME to configure proxy settings, and return false if it
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // exists. Some distributions (e.g. Ubuntu 11.04) have the API and schema
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // but don't use gsettings for proxy settings, but they do have the old
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // binary, so we detect these systems that way.
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
8072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // TODO(phajdan.jr): Redesign the code to load library on different thread.
8082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::ThreadRestrictions::ScopedAllowIO allow_io;
8092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Try also without .0 at the end; on some systems this may be required.
8112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!libgio_loader_.Load("libgio-2.0.so.0") &&
8122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        !libgio_loader_.Load("libgio-2.0.so")) {
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VLOG(1) << "Cannot load gio library. Will fall back to gconf.";
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
81846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  GSettings* client = NULL;
81946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (SchemaExists(kProxyGConfSchema)) {
82046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    ANNOTATE_SCOPED_MEMORY_LEAK; // http://crbug.com/380782
82146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    client = libgio_loader_.g_settings_new(kProxyGConfSchema);
82246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
82346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!client) {
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(1) << "Cannot create gsettings client. Will fall back to gconf.";
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_object_unref(client);
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string path;
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!env->GetVar("PATH", &path)) {
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "No $PATH variable. Assuming no gnome-network-properties.";
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Yes, we're on the UI thread. Yes, we're accessing the file system.
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Sadly, we don't have much choice. We need the proxy settings and we
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // need them now, and to figure out where to get them, we have to check
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // for this binary. See http://crbug.com/69057 for additional details.
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::ThreadRestrictions::ScopedAllowIO allow_io;
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<std::string> paths;
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Tokenize(path, ":", &paths);
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < paths.size(); ++i) {
8412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::FilePath file(paths[i]);
8427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      if (base::PathExists(file.Append("gnome-network-properties"))) {
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        VLOG(1) << "Found gnome-network-properties. Will fall back to gconf.";
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "All gsettings tests OK. Will get proxy config from gsettings.";
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // defined(USE_GIO)
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is the KDE version that reads kioslaverc and simulates gconf.
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Doing this allows the main Delegate code, as well as the unit tests
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// for it, to stay the same - and the settings map fairly well besides.
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SettingGetterImplKDE : public ProxyConfigServiceLinux::SettingGetter,
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             public base::MessagePumpLibevent::Watcher {
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit SettingGetterImplKDE(base::Environment* env_var_getter)
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : inotify_fd_(-1), notify_delegate_(NULL), indirect_manual_(false),
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        auto_no_pac_(false), reversed_bypass_list_(false),
8631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        env_var_getter_(env_var_getter), file_task_runner_(NULL) {
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This has to be called on the UI thread (http://crbug.com/69057).
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::ThreadRestrictions::ScopedAllowIO allow_io;
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Derive the location of the kde config dir from the environment.
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string home;
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (env_var_getter->GetVar("KDEHOME", &home) && !home.empty()) {
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // $KDEHOME is set. Use it unconditionally.
8712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      kde_config_dir_ = KDEHomeToConfigPath(base::FilePath(home));
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // $KDEHOME is unset. Try to figure out what to use. This seems to be
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // the common case on most distributions.
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!env_var_getter->GetVar(base::env_vars::kHome, &home))
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // User has no $HOME? Give up. Later we'll report the failure.
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (base::nix::GetDesktopEnvironment(env_var_getter) ==
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::nix::DESKTOP_ENVIRONMENT_KDE3) {
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // KDE3 always uses .kde for its configuration.
8812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::FilePath kde_path = base::FilePath(home).Append(".kde");
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        kde_config_dir_ = KDEHomeToConfigPath(kde_path);
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Some distributions patch KDE4 to use .kde4 instead of .kde, so that
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // both can be installed side-by-side. Sadly they don't all do this, and
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // they don't always do this: some distributions have started switching
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // back as well. So if there is a .kde4 directory, check the timestamps
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // of the config directories within and use the newest one.
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Note that we should currently be running in the UI thread, because in
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // the gconf version, that is the only thread that can access the proxy
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // settings (a gconf restriction). As noted below, the initial read of
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // the proxy settings will be done in this thread anyway, so we check
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // for .kde4 here in this thread as well.
8942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::FilePath kde3_path = base::FilePath(home).Append(".kde");
8952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::FilePath kde3_config = KDEHomeToConfigPath(kde3_path);
8962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::FilePath kde4_path = base::FilePath(home).Append(".kde4");
8972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::FilePath kde4_config = KDEHomeToConfigPath(kde4_path);
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        bool use_kde4 = false;
8997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        if (base::DirectoryExists(kde4_path)) {
9005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          base::File::Info kde3_info;
9015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          base::File::Info kde4_info;
902a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          if (base::GetFileInfo(kde4_config, &kde4_info)) {
903a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            if (base::GetFileInfo(kde3_config, &kde3_info)) {
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              use_kde4 = kde4_info.last_modified >= kde3_info.last_modified;
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            } else {
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              use_kde4 = true;
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (use_kde4) {
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          kde_config_dir_ = KDEHomeToConfigPath(kde4_path);
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else {
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          kde_config_dir_ = KDEHomeToConfigPath(kde3_path);
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~SettingGetterImplKDE() {
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // inotify_fd_ should have been closed before now, from
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Delegate::OnDestroy(), while running on the file thread. However
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // on exiting the process, it may happen that Delegate::OnDestroy()
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // task is left pending on the file loop after the loop was quit,
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // and pending tasks may then be deleted without being run.
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Here in the KDE version, we can safely close the file descriptor
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // anyway. (Not that it really matters; the process is exiting.)
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (inotify_fd_ >= 0)
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ShutDown();
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(inotify_fd_ < 0);
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  virtual bool Init(
9331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      const scoped_refptr<base::SingleThreadTaskRunner>& glib_task_runner,
9341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner)
9351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      OVERRIDE {
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This has to be called on the UI thread (http://crbug.com/69057).
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::ThreadRestrictions::ScopedAllowIO allow_io;
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(inotify_fd_ < 0);
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    inotify_fd_ = inotify_init();
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (inotify_fd_ < 0) {
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PLOG(ERROR) << "inotify_init failed";
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int flags = fcntl(inotify_fd_, F_GETFL);
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (fcntl(inotify_fd_, F_SETFL, flags | O_NONBLOCK) < 0) {
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PLOG(ERROR) << "fcntl failed";
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      close(inotify_fd_);
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      inotify_fd_ = -1;
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    file_task_runner_ = file_task_runner;
9521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // The initial read is done on the current thread, not
9531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // |file_task_runner_|, since we will need to have it for
9541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // SetUpAndFetchInitialConfig().
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateCachedSettings();
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void ShutDown() OVERRIDE {
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (inotify_fd_ >= 0) {
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ResetCachedSettings();
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      inotify_watcher_.StopWatchingFileDescriptor();
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      close(inotify_fd_);
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      inotify_fd_ = -1;
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool SetUpNotifications(
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ProxyConfigServiceLinux::Delegate* delegate) OVERRIDE {
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(inotify_fd_ >= 0);
9711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DCHECK(file_task_runner_->BelongsToCurrentThread());
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We can't just watch the kioslaverc file directly, since KDE will write
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // a new copy of it and then rename it whenever settings are changed and
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // inotify watches inodes (so we'll be watching the old deleted file after
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the first change, and it will never change again). So, we watch the
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // directory instead. We then act only on changes to the kioslaverc entry.
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (inotify_add_watch(inotify_fd_, kde_config_dir_.value().c_str(),
9781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                          IN_MODIFY | IN_MOVED_TO) < 0) {
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
9801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    notify_delegate_ = delegate;
9821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
9831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            inotify_fd_, true, base::MessageLoopForIO::WATCH_READ,
9841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            &inotify_watcher_, this)) {
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
9861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Simulate a change to avoid possibly losing updates before this point.
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnChangeNotification();
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  virtual const scoped_refptr<base::SingleThreadTaskRunner>&
9931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  GetNotificationTaskRunner() OVERRIDE {
9941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return file_task_runner_;
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Implement base::MessagePumpLibevent::Watcher.
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE {
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ(fd, inotify_fd_);
10001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DCHECK(file_task_runner_->BelongsToCurrentThread());
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnChangeNotification();
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ProxyConfigSource GetConfigSource() OVERRIDE {
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PROXY_CONFIG_SOURCE_KDE;
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool GetString(StringSetting key, std::string* result) OVERRIDE {
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    string_map_type::iterator it = string_table_.find(key);
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (it == string_table_.end())
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *result = it->second;
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool GetBool(BoolSetting key, bool* result) OVERRIDE {
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't ever have any booleans.
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool GetInt(IntSetting key, int* result) OVERRIDE {
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't ever have any integers. (See AddProxy() below about ports.)
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool GetStringList(StringListSetting key,
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             std::vector<std::string>* result) OVERRIDE {
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    strings_map_type::iterator it = strings_table_.find(key);
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (it == strings_table_.end())
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *result = it->second;
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool BypassListIsReversed() OVERRIDE {
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return reversed_bypass_list_;
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool MatchHostsUsingSuffixMatching() OVERRIDE {
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ResetCachedSettings() {
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    string_table_.clear();
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    strings_table_.clear();
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    indirect_manual_ = false;
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    auto_no_pac_ = false;
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    reversed_bypass_list_ = false;
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath KDEHomeToConfigPath(const base::FilePath& kde_home) {
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return kde_home.Append("share").Append("config");
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void AddProxy(StringSetting host_key, const std::string& value) {
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (value.empty() || value.substr(0, 3) == "//:")
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // No proxy.
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t space = value.find(' ');
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (space != std::string::npos) {
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Newer versions of KDE use a space rather than a colon to separate the
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // port number from the hostname. If we find this, we need to convert it.
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string fixed = value;
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      fixed[space] = ':';
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      string_table_[host_key] = fixed;
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We don't need to parse the port number out; GetProxyFromSettings()
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // would only append it right back again. So we just leave the port
10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // number right in the host string.
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      string_table_[host_key] = value;
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void AddHostList(StringListSetting key, const std::string& value) {
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<std::string> tokens;
10772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::StringTokenizer tk(value, ", ");
10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (tk.GetNext()) {
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string token = tk.token();
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!token.empty())
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        tokens.push_back(token);
10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    strings_table_[key] = tokens;
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void AddKDESetting(const std::string& key, const std::string& value) {
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (key == "ProxyType") {
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const char* mode = "none";
10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      indirect_manual_ = false;
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      auto_no_pac_ = false;
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int int_value;
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::StringToInt(value, &int_value);
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      switch (int_value) {
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case 0:  // No proxy, or maybe kioslaverc syntax error.
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case 1:  // Manual configuration.
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          mode = "manual";
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case 2:  // PAC URL.
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          mode = "auto";
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case 3:  // WPAD.
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          mode = "auto";
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          auto_no_pac_ = true;
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case 4:  // Indirect manual via environment variables.
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          mode = "manual";
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          indirect_manual_ = true;
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      string_table_[PROXY_MODE] = mode;
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (key == "Proxy Config Script") {
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      string_table_[PROXY_AUTOCONF_URL] = value;
11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (key == "httpProxy") {
11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AddProxy(PROXY_HTTP_HOST, value);
11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (key == "httpsProxy") {
11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AddProxy(PROXY_HTTPS_HOST, value);
11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (key == "ftpProxy") {
11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AddProxy(PROXY_FTP_HOST, value);
11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (key == "socksProxy") {
11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Older versions of KDE configure SOCKS in a weird way involving
11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // LD_PRELOAD and a library that intercepts network calls to SOCKSify
11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // them. We don't support it. KDE 4.8 added a proper SOCKS setting.
11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AddProxy(PROXY_SOCKS_HOST, value);
11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (key == "ReversedException") {
11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We count "true" or any nonzero number as true, otherwise false.
11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Note that if the value is not actually numeric StringToInt()
11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // will return 0, which we count as false.
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int int_value;
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::StringToInt(value, &int_value);
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reversed_bypass_list_ = (value == "true" || int_value);
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (key == "NoProxyFor") {
11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      AddHostList(PROXY_IGNORE_HOSTS, value);
11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (key == "AuthMode") {
11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Check for authentication, just so we can warn.
11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int mode;
11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::StringToInt(value, &mode);
11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (mode) {
11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // ProxyConfig does not support authentication parameters, but
11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Chrome will prompt for the password later. So we ignore this.
11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(WARNING) <<
11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "Proxy authentication parameters ignored, see bug 16709";
11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ResolveIndirect(StringSetting key) {
11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    string_map_type::iterator it = string_table_.find(key);
11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (it != string_table_.end()) {
11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string value;
11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (env_var_getter_->GetVar(it->second.c_str(), &value))
11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        it->second = value;
11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else
11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        string_table_.erase(it);
11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ResolveIndirectList(StringListSetting key) {
11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    strings_map_type::iterator it = strings_table_.find(key);
11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (it != strings_table_.end()) {
11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      std::string value;
11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!it->second.empty() &&
11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          env_var_getter_->GetVar(it->second[0].c_str(), &value))
11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        AddHostList(key, value);
11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else
11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        strings_table_.erase(it);
11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The settings in kioslaverc could occur in any order, but some affect
11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // others. Rather than read the whole file in and then query them in an
11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // order that allows us to handle that, we read the settings in whatever
11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // order they occur and do any necessary tweaking after we finish.
11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ResolveModeEffects() {
11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (indirect_manual_) {
11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ResolveIndirect(PROXY_HTTP_HOST);
11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ResolveIndirect(PROXY_HTTPS_HOST);
11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ResolveIndirect(PROXY_FTP_HOST);
11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ResolveIndirectList(PROXY_IGNORE_HOSTS);
11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (auto_no_pac_) {
11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Remove the PAC URL; we're not supposed to use it.
11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      string_table_.erase(PROXY_AUTOCONF_URL);
11845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Reads kioslaverc one line at a time and calls AddKDESetting() to add
11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // each relevant name-value pair to the appropriate value table.
11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void UpdateCachedSettings() {
11902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath kioslaverc = kde_config_dir_.Append("kioslaverc");
1191a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    base::ScopedFILE input(base::OpenFile(kioslaverc, "r"));
11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!input.get())
11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ResetCachedSettings();
11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool in_proxy_settings = false;
11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool line_too_long = false;
11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char line[BUFFER_SIZE];
11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // fgets() will return NULL on EOF or error.
11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (fgets(line, sizeof(line), input.get())) {
12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // fgets() guarantees the line will be properly terminated.
12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      size_t length = strlen(line);
12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!length)
12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This should be true even with CRLF endings.
12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (line[length - 1] != '\n') {
12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        line_too_long = true;
12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (line_too_long) {
12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // The previous line had no line ending, but this done does. This is
12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // the end of the line that was too long, so warn here and skip it.
12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(WARNING) << "skipped very long line in " << kioslaverc.value();
12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        line_too_long = false;
12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Remove the LF at the end, and the CR if there is one.
12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      line[--length] = '\0';
12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (length && line[length - 1] == '\r')
12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        line[--length] = '\0';
12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Now parse the line.
12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (line[0] == '[') {
12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Switching sections. All we care about is whether this is
12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // the (a?) proxy settings section, for both KDE3 and KDE4.
12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        in_proxy_settings = !strncmp(line, "[Proxy Settings]", 16);
12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else if (in_proxy_settings) {
12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // A regular line, in the (a?) proxy settings section.
12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        char* split = strchr(line, '=');
12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Skip this line if it does not contain an = sign.
12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!split)
12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          continue;
12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Split the line on the = and advance |split|.
12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *(split++) = 0;
12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::string key = line;
12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::string value = split;
1235a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        base::TrimWhitespaceASCII(key, base::TRIM_ALL, &key);
1236a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        base::TrimWhitespaceASCII(value, base::TRIM_ALL, &value);
12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Skip this line if the key name is empty.
12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (key.empty())
12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          continue;
12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Is the value name localized?
12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (key[key.length() - 1] == ']') {
12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Find the matching bracket.
12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          length = key.rfind('[');
12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Skip this line if the localization indicator is malformed.
12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (length == std::string::npos)
12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            continue;
12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Trim the localization indicator off.
12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          key.resize(length);
12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Remove any resulting trailing whitespace.
1250a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          base::TrimWhitespaceASCII(key, base::TRIM_TRAILING, &key);
12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          // Skip this line if the key name is now empty.
12525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (key.empty())
12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            continue;
12545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
12555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Now fill in the tables.
12565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        AddKDESetting(key, value);
12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ferror(input.get()))
12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "error reading " << kioslaverc.value();
12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ResolveModeEffects();
12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is the callback from the debounce timer.
12655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OnDebouncedNotification() {
12661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DCHECK(file_task_runner_->BelongsToCurrentThread());
12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(1) << "inotify change notification for kioslaverc";
12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateCachedSettings();
12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK(notify_delegate_);
12705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Forward to a method on the proxy config service delegate object.
12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    notify_delegate_->OnCheckProxyConfigSettings();
12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Called by OnFileCanReadWithoutBlocking() on the file thread. Reads
12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // from the inotify file descriptor and starts up a debounce timer if
12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // an event for kioslaverc is seen.
12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OnChangeNotification() {
12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_GE(inotify_fd_,  0);
12791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DCHECK(file_task_runner_->BelongsToCurrentThread());
12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char event_buf[(sizeof(inotify_event) + NAME_MAX + 1) * 4];
12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool kioslaverc_touched = false;
12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ssize_t r;
12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while ((r = read(inotify_fd_, event_buf, sizeof(event_buf))) > 0) {
12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // inotify returns variable-length structures, which is why we have
12855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // this strange-looking loop instead of iterating through an array.
12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      char* event_ptr = event_buf;
12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      while (event_ptr < event_buf + r) {
12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        inotify_event* event = reinterpret_cast<inotify_event*>(event_ptr);
12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // The kernel always feeds us whole events.
12905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CHECK_LE(event_ptr + sizeof(inotify_event), event_buf + r);
12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CHECK_LE(event->name + event->len, event_buf + r);
12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!strcmp(event->name, "kioslaverc"))
12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          kioslaverc_touched = true;
12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Advance the pointer just past the end of the filename.
12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        event_ptr = event->name + event->len;
12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We keep reading even if |kioslaverc_touched| is true to drain the
12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // inotify event queue.
12995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!r)
13015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Instead of returning -1 and setting errno to EINVAL if there is not
13025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // enough buffer space, older kernels (< 2.6.21) return 0. Simulate the
13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // new behavior (EINVAL) so we can reuse the code below.
13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      errno = EINVAL;
13055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (errno != EAGAIN) {
13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PLOG(WARNING) << "error reading inotify file descriptor";
13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (errno == EINVAL) {
13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Our buffer is not large enough to read the next event. This should
13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // not happen (because its size is calculated to always be sufficiently
13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // large), but if it does we'd warn continuously since |inotify_fd_|
13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // would be forever ready to read. Close it and stop watching instead.
13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(ERROR) << "inotify failure; no longer watching kioslaverc!";
13135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        inotify_watcher_.StopWatchingFileDescriptor();
13145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        close(inotify_fd_);
13155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        inotify_fd_ = -1;
13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (kioslaverc_touched) {
13195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We don't use Reset() because the timer may not yet be running.
13205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // (In that case Stop() is a no-op.)
13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      debounce_timer_.Stop();
13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      debounce_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(
13235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          kDebounceTimeoutMilliseconds), this,
13245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          &SettingGetterImplKDE::OnDebouncedNotification);
13255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef std::map<StringSetting, std::string> string_map_type;
13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef std::map<StringListSetting,
13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   std::vector<std::string> > strings_map_type;
13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int inotify_fd_;
13335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::MessagePumpLibevent::FileDescriptorWatcher inotify_watcher_;
13345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProxyConfigServiceLinux::Delegate* notify_delegate_;
13355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::OneShotTimer<SettingGetterImplKDE> debounce_timer_;
13362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath kde_config_dir_;
13375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool indirect_manual_;
13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool auto_no_pac_;
13395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool reversed_bypass_list_;
13405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't own |env_var_getter_|.  It's safe to hold a pointer to it, since
13415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // both it and us are owned by ProxyConfigServiceLinux::Delegate, and have the
13425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // same lifetime.
13435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Environment* env_var_getter_;
13445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We cache these settings whenever we re-read the kioslaverc file.
13465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  string_map_type string_table_;
13475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  strings_map_type strings_table_;
13485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Task runner of the file thread, for reading kioslaverc. If NULL,
13505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // just read it directly (for testing). We also handle inotify events
13515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // on this thread.
13521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
13535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(SettingGetterImplKDE);
13555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
13565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
13585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProxyConfigServiceLinux::Delegate::GetProxyFromSettings(
13605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SettingGetter::StringSetting host_key,
13615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProxyServer* result_server) {
13625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string host;
13635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!setting_getter_->GetString(host_key, &host) || host.empty()) {
13645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Unset or empty.
13655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
13665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check for an optional port.
13685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int port = 0;
13695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SettingGetter::IntSetting port_key =
13705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SettingGetter::HostSettingToPortSetting(host_key);
13715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  setting_getter_->GetInt(port_key, &port);
13725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (port != 0) {
13735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If a port is set and non-zero:
13745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    host += ":" + base::IntToString(port);
13755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // gconf settings do not appear to distinguish between SOCKS version. We
13785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // default to version 5. For more information on this policy decision, see:
13795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // http://code.google.com/p/chromium/issues/detail?id=55912#c2
13805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProxyServer::Scheme scheme = (host_key == SettingGetter::PROXY_SOCKS_HOST) ?
13815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ProxyServer::SCHEME_SOCKS5 : ProxyServer::SCHEME_HTTP;
13825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  host = FixupProxyHostScheme(scheme, host);
13835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProxyServer proxy_server = ProxyServer::FromURI(host,
13845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  ProxyServer::SCHEME_HTTP);
13855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (proxy_server.is_valid()) {
13865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *result_server = proxy_server;
13875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
13885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
13905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ProxyConfigServiceLinux::Delegate::GetConfigFromSettings(
13935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProxyConfig* config) {
13945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string mode;
13955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!setting_getter_->GetString(SettingGetter::PROXY_MODE, &mode)) {
13965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We expect this to always be set, so if we don't see it then we
13975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // probably have a gconf/gsettings problem, and so we don't have a valid
13985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // proxy config.
13995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
14005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (mode == "none") {
14025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Specifically specifies no proxy.
14035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
14045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (mode == "auto") {
14075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Automatic proxy config.
14085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string pac_url_str;
14095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (setting_getter_->GetString(SettingGetter::PROXY_AUTOCONF_URL,
14105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   &pac_url_str)) {
14115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!pac_url_str.empty()) {
14125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If the PAC URL is actually a file path, then put file:// in front.
14135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (pac_url_str[0] == '/')
14145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          pac_url_str = "file://" + pac_url_str;
14155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GURL pac_url(pac_url_str);
14165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!pac_url.is_valid())
14175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return false;
14185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        config->set_pac_url(pac_url);
14195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return true;
14205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
14215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
14225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    config->set_auto_detect(true);
14235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
14245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (mode != "manual") {
14275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Mode is unrecognized.
14285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
14295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool use_http_proxy;
14315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (setting_getter_->GetBool(SettingGetter::PROXY_USE_HTTP_PROXY,
14325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               &use_http_proxy)
14335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      && !use_http_proxy) {
14345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Another master switch for some reason. If set to false, then no
14355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // proxy. But we don't panic if the key doesn't exist.
14365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
14375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool same_proxy = false;
14405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Indicates to use the http proxy for all protocols. This one may
14415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // not exist (presumably on older versions); we assume false in that
14425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // case.
14435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  setting_getter_->GetBool(SettingGetter::PROXY_USE_SAME_PROXY,
14445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &same_proxy);
14455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProxyServer proxy_for_http;
14475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProxyServer proxy_for_https;
14485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProxyServer proxy_for_ftp;
14495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProxyServer socks_proxy;  // (socks)
14505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This counts how many of the above ProxyServers were defined and valid.
14525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t num_proxies_specified = 0;
14535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Extract the per-scheme proxies. If we failed to parse it, or no proxy was
14555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // specified for the scheme, then the resulting ProxyServer will be invalid.
14565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GetProxyFromSettings(SettingGetter::PROXY_HTTP_HOST, &proxy_for_http))
14575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    num_proxies_specified++;
14585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GetProxyFromSettings(SettingGetter::PROXY_HTTPS_HOST, &proxy_for_https))
14595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    num_proxies_specified++;
14605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GetProxyFromSettings(SettingGetter::PROXY_FTP_HOST, &proxy_for_ftp))
14615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    num_proxies_specified++;
14625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GetProxyFromSettings(SettingGetter::PROXY_SOCKS_HOST, &socks_proxy))
14635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    num_proxies_specified++;
14645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (same_proxy) {
14665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (proxy_for_http.is_valid()) {
14675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Use the http proxy for all schemes.
14685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      config->proxy_rules().type = ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY;
14692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      config->proxy_rules().single_proxies.SetSingleProxyServer(proxy_for_http);
14705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
14715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (num_proxies_specified > 0) {
14725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (socks_proxy.is_valid() && num_proxies_specified == 1) {
14735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If the only proxy specified was for SOCKS, use it for all schemes.
14745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      config->proxy_rules().type = ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY;
14752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      config->proxy_rules().single_proxies.SetSingleProxyServer(socks_proxy);
14765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
14772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Otherwise use the indicated proxies per-scheme.
14785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      config->proxy_rules().type =
14795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
14802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      config->proxy_rules().proxies_for_http.
14812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          SetSingleProxyServer(proxy_for_http);
14822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      config->proxy_rules().proxies_for_https.
14832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          SetSingleProxyServer(proxy_for_https);
14842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      config->proxy_rules().proxies_for_ftp.SetSingleProxyServer(proxy_for_ftp);
14852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      config->proxy_rules().fallback_proxies.SetSingleProxyServer(socks_proxy);
14865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
14875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (config->proxy_rules().empty()) {
14905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Manual mode but we couldn't parse any rules.
14915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
14925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check for authentication, just so we can warn.
14955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool use_auth = false;
14965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  setting_getter_->GetBool(SettingGetter::PROXY_USE_AUTHENTICATION,
14975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &use_auth);
14985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (use_auth) {
14995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // ProxyConfig does not support authentication parameters, but
15005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Chrome will prompt for the password later. So we ignore
15015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // /system/http_proxy/*auth* settings.
15025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Proxy authentication parameters ignored, see bug 16709";
15035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now the bypass list.
15065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::string> ignore_hosts_list;
15075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  config->proxy_rules().bypass_rules.Clear();
15085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (setting_getter_->GetStringList(SettingGetter::PROXY_IGNORE_HOSTS,
15095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     &ignore_hosts_list)) {
15105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<std::string>::const_iterator it(ignore_hosts_list.begin());
15115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (; it != ignore_hosts_list.end(); ++it) {
15125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (setting_getter_->MatchHostsUsingSuffixMatching()) {
15135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        config->proxy_rules().bypass_rules.
15145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            AddRuleFromStringUsingSuffixMatching(*it);
15155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
15165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        config->proxy_rules().bypass_rules.AddRuleFromString(*it);
15175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
15185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
15195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that there are no settings with semantics corresponding to
15215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // bypass of local names in GNOME. In KDE, "<local>" is supported
15225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // as a hostname rule.
15235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // KDE allows one to reverse the bypass rules.
15255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  config->proxy_rules().reverse_bypass =
15265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      setting_getter_->BypassListIsReversed();
15275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
15295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProxyConfigServiceLinux::Delegate::Delegate(base::Environment* env_var_getter)
15325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : env_var_getter_(env_var_getter) {
15335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Figure out which SettingGetterImpl to use, if any.
15345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (base::nix::GetDesktopEnvironment(env_var_getter)) {
15355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case base::nix::DESKTOP_ENVIRONMENT_GNOME:
15365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case base::nix::DESKTOP_ENVIRONMENT_UNITY:
15375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_GIO)
15385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
15395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        scoped_ptr<SettingGetterImplGSettings> gs_getter(
15405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            new SettingGetterImplGSettings());
15415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // We have to load symbols and check the GNOME version in use to decide
15425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // if we should use the gsettings getter. See LoadAndCheckVersion().
15435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (gs_getter->LoadAndCheckVersion(env_var_getter))
15445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          setting_getter_.reset(gs_getter.release());
15455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
15465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
15475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_GCONF)
15485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Fall back on gconf if gsettings is unavailable or incorrect.
15495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!setting_getter_.get())
15505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        setting_getter_.reset(new SettingGetterImplGConf());
15515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
15525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
15535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case base::nix::DESKTOP_ENVIRONMENT_KDE3:
15545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case base::nix::DESKTOP_ENVIRONMENT_KDE4:
15555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      setting_getter_.reset(new SettingGetterImplKDE(env_var_getter));
15565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
15575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case base::nix::DESKTOP_ENVIRONMENT_XFCE:
15585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case base::nix::DESKTOP_ENVIRONMENT_OTHER:
15595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
15605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
15615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProxyConfigServiceLinux::Delegate::Delegate(
15645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Environment* env_var_getter, SettingGetter* setting_getter)
15655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : env_var_getter_(env_var_getter), setting_getter_(setting_getter) {
15665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProxyConfigServiceLinux::Delegate::SetUpAndFetchInitialConfig(
15691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const scoped_refptr<base::SingleThreadTaskRunner>& glib_task_runner,
15701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
15711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner) {
15725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We should be running on the default glib main loop thread right
15735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // now. gconf can only be accessed from this thread.
15741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(glib_task_runner->BelongsToCurrentThread());
15751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  glib_task_runner_ = glib_task_runner;
15761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  io_task_runner_ = io_task_runner;
15771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
15781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // If we are passed a NULL |io_task_runner| or |file_task_runner|, then we
15791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // don't set up proxy setting change notifications. This should not be the
15801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // usual case but is intended to/ simplify test setups.
15811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!io_task_runner_.get() || !file_task_runner.get())
15825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(1) << "Monitoring of proxy setting changes is disabled";
15835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fetch and cache the current proxy config. The config is left in
15855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // cached_config_, where GetLatestProxyConfig() running on the IO thread
15865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will expect to find it. This is safe to do because we return
15875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // before this ProxyConfigServiceLinux is passed on to
15885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the ProxyService.
15895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note: It would be nice to prioritize environment variables
15915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and only fall back to gconf if env vars were unset. But
15925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // gnome-terminal "helpfully" sets http_proxy and no_proxy, and it
15935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // does so even if the proxy mode is set to auto, which would
15945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // mislead us.
15955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool got_config = false;
15975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (setting_getter_.get() &&
15981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      setting_getter_->Init(glib_task_runner, file_task_runner) &&
15995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetConfigFromSettings(&cached_config_)) {
16005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cached_config_.set_id(1);  // Mark it as valid.
16015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cached_config_.set_source(setting_getter_->GetConfigSource());
16025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(1) << "Obtained proxy settings from "
16035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            << ProxyConfigSourceToString(cached_config_.source());
16045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If gconf proxy mode is "none", meaning direct, then we take
16065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // that to be a valid config and will not check environment
16075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // variables. The alternative would have been to look for a proxy
16085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // whereever we can find one.
16095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    got_config = true;
16105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Keep a copy of the config for use from this thread for
16125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // comparison with updated settings when we get notifications.
16135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    reference_config_ = cached_config_;
16145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    reference_config_.set_id(1);  // Mark it as valid.
16155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We only set up notifications if we have IO and file loops available.
16175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We do this after getting the initial configuration so that we don't have
16185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // to worry about cancelling it if the initial fetch above fails. Note that
16195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // setting up notifications has the side effect of simulating a change, so
16205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // that we won't lose any updates that may have happened after the initial
16215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // fetch and before setting up notifications. We'll detect the common case
16225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // of no changes in OnCheckProxyConfigSettings() (or sooner) and ignore it.
16231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (io_task_runner.get() && file_task_runner.get()) {
16245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scoped_refptr<base::SingleThreadTaskRunner> required_loop =
16255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          setting_getter_->GetNotificationTaskRunner();
1626868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if (!required_loop.get() || required_loop->BelongsToCurrentThread()) {
16275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // In this case we are already on an acceptable thread.
16285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SetUpNotifications();
16295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
16305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Post a task to set up notifications. We don't wait for success.
16315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        required_loop->PostTask(FROM_HERE, base::Bind(
16325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            &ProxyConfigServiceLinux::Delegate::SetUpNotifications, this));
16335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
16345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
16355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
16365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!got_config) {
16385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We fall back on environment variables.
16395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //
16405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Consulting environment variables doesn't need to be done from the
16415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // default glib main loop, but it's a tiny enough amount of work.
16425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (GetConfigFromEnv(&cached_config_)) {
16435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cached_config_.set_source(PROXY_CONFIG_SOURCE_ENV);
16445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cached_config_.set_id(1);  // Mark it as valid.
16455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VLOG(1) << "Obtained proxy settings from environment variables";
16465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
16475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
16485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Depending on the SettingGetter in use, this method will be called
16515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// on either the UI thread (GConf) or the file thread (KDE).
16525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProxyConfigServiceLinux::Delegate::SetUpNotifications() {
16535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<base::SingleThreadTaskRunner> required_loop =
16545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      setting_getter_->GetNotificationTaskRunner();
1655868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!required_loop.get() || required_loop->BelongsToCurrentThread());
16565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!setting_getter_->SetUpNotifications(this))
16575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Unable to set up proxy configuration change notifications";
16585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProxyConfigServiceLinux::Delegate::AddObserver(Observer* observer) {
16615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observers_.AddObserver(observer);
16625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProxyConfigServiceLinux::Delegate::RemoveObserver(Observer* observer) {
16655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observers_.RemoveObserver(observer);
16665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProxyConfigService::ConfigAvailability
16695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProxyConfigServiceLinux::Delegate::GetLatestProxyConfig(
16705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ProxyConfig* config) {
16715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is called from the IO thread.
16721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(!io_task_runner_.get() ||
16731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci         io_task_runner_->BelongsToCurrentThread());
16745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Simply return the last proxy configuration that glib_default_loop
16765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // notified us of.
16775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (cached_config_.is_valid()) {
16785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *config = cached_config_;
16795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
16805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *config = ProxyConfig::CreateDirect();
16815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    config->set_source(PROXY_CONFIG_SOURCE_SYSTEM_FAILED);
16825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
16835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We return CONFIG_VALID to indicate that *config was filled in. It is always
16855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // going to be available since we initialized eagerly on the UI thread.
16865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(eroman): do lazy initialization instead, so we no longer need
16875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //               to construct ProxyConfigServiceLinux on the UI thread.
16885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //               In which case, we may return false here.
16895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return CONFIG_VALID;
16905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
16915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Depending on the SettingGetter in use, this method will be called
16935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// on either the UI thread (GConf) or the file thread (KDE).
16945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProxyConfigServiceLinux::Delegate::OnCheckProxyConfigSettings() {
16955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<base::SingleThreadTaskRunner> required_loop =
16965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      setting_getter_->GetNotificationTaskRunner();
1697868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!required_loop.get() || required_loop->BelongsToCurrentThread());
16985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProxyConfig new_config;
16995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool valid = GetConfigFromSettings(&new_config);
17005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (valid)
17015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_config.set_id(1);  // mark it as valid
17025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // See if it is different from what we had before.
17045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (new_config.is_valid() != reference_config_.is_valid() ||
17055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !new_config.Equals(reference_config_)) {
17065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Post a task to the IO thread with the new configuration, so it can
17075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // update |cached_config_|.
17081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    io_task_runner_->PostTask(FROM_HERE, base::Bind(
17095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        &ProxyConfigServiceLinux::Delegate::SetNewProxyConfig,
17105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this, new_config));
17115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Update the thread-private copy in |reference_config_| as well.
17125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    reference_config_ = new_config;
17135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
17145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VLOG(1) << "Detected no-op change to proxy settings. Doing nothing.";
17155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProxyConfigServiceLinux::Delegate::SetNewProxyConfig(
17195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ProxyConfig& new_config) {
17201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(io_task_runner_->BelongsToCurrentThread());
17215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "Proxy configuration changed";
17225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cached_config_ = new_config;
17235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(
17245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Observer, observers_,
17255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      OnProxyConfigChanged(new_config, ProxyConfigService::CONFIG_VALID));
17265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProxyConfigServiceLinux::Delegate::PostDestroyTask() {
17295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!setting_getter_.get())
17305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
17315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<base::SingleThreadTaskRunner> shutdown_loop =
17325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      setting_getter_->GetNotificationTaskRunner();
1733868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!shutdown_loop.get() || shutdown_loop->BelongsToCurrentThread()) {
17345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Already on the right thread, call directly.
17355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This is the case for the unittests.
17365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnDestroy();
17375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
17385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Post to shutdown thread. Note that on browser shutdown, we may quit
17395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // this MessageLoop and exit the program before ever running this.
17405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shutdown_loop->PostTask(FROM_HERE, base::Bind(
17415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        &ProxyConfigServiceLinux::Delegate::OnDestroy, this));
17425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
17435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProxyConfigServiceLinux::Delegate::OnDestroy() {
17455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<base::SingleThreadTaskRunner> shutdown_loop =
17465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      setting_getter_->GetNotificationTaskRunner();
1747868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(!shutdown_loop.get() || shutdown_loop->BelongsToCurrentThread());
17485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  setting_getter_->ShutDown();
17495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProxyConfigServiceLinux::ProxyConfigServiceLinux()
17525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : delegate_(new Delegate(base::Environment::Create())) {
17535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProxyConfigServiceLinux::~ProxyConfigServiceLinux() {
17565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_->PostDestroyTask();
17575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProxyConfigServiceLinux::ProxyConfigServiceLinux(
17605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Environment* env_var_getter)
17615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : delegate_(new Delegate(env_var_getter)) {
17625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProxyConfigServiceLinux::ProxyConfigServiceLinux(
17655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Environment* env_var_getter, SettingGetter* setting_getter)
17665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : delegate_(new Delegate(env_var_getter, setting_getter)) {
17675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProxyConfigServiceLinux::AddObserver(Observer* observer) {
17705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_->AddObserver(observer);
17715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProxyConfigServiceLinux::RemoveObserver(Observer* observer) {
17745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_->RemoveObserver(observer);
17755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ProxyConfigService::ConfigAvailability
17785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProxyConfigServiceLinux::GetLatestProxyConfig(ProxyConfig* config) {
17795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return delegate_->GetLatestProxyConfig(config);
17805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
17815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
1783