Home | History | Annotate | Download | only in proxy
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "net/proxy/proxy_config_service_linux.h"
      6 
      7 #include <errno.h>
      8 #include <fcntl.h>
      9 #if defined(USE_GCONF)
     10 #include <gconf/gconf-client.h>
     11 #endif  // defined(USE_GCONF)
     12 #include <limits.h>
     13 #include <stdio.h>
     14 #include <stdlib.h>
     15 #include <sys/inotify.h>
     16 #include <unistd.h>
     17 
     18 #include <map>
     19 
     20 #include "base/bind.h"
     21 #include "base/compiler_specific.h"
     22 #include "base/debug/leak_annotations.h"
     23 #include "base/environment.h"
     24 #include "base/files/file_path.h"
     25 #include "base/files/file_util.h"
     26 #include "base/files/scoped_file.h"
     27 #include "base/logging.h"
     28 #include "base/message_loop/message_loop.h"
     29 #include "base/nix/xdg_util.h"
     30 #include "base/single_thread_task_runner.h"
     31 #include "base/strings/string_number_conversions.h"
     32 #include "base/strings/string_tokenizer.h"
     33 #include "base/strings/string_util.h"
     34 #include "base/threading/thread_restrictions.h"
     35 #include "base/timer/timer.h"
     36 #include "net/base/net_errors.h"
     37 #include "net/http/http_util.h"
     38 #include "net/proxy/proxy_config.h"
     39 #include "net/proxy/proxy_server.h"
     40 #include "url/url_canon.h"
     41 
     42 #if defined(USE_GIO)
     43 #include "library_loaders/libgio.h"
     44 #endif  // defined(USE_GIO)
     45 
     46 namespace net {
     47 
     48 namespace {
     49 
     50 // Given a proxy hostname from a setting, returns that hostname with
     51 // an appropriate proxy server scheme prefix.
     52 // scheme indicates the desired proxy scheme: usually http, with
     53 // socks 4 or 5 as special cases.
     54 // TODO(arindam): Remove URI string manipulation by using MapUrlSchemeToProxy.
     55 std::string FixupProxyHostScheme(ProxyServer::Scheme scheme,
     56                                  std::string host) {
     57   if (scheme == ProxyServer::SCHEME_SOCKS5 &&
     58       StartsWithASCII(host, "socks4://", false)) {
     59     // We default to socks 5, but if the user specifically set it to
     60     // socks4://, then use that.
     61     scheme = ProxyServer::SCHEME_SOCKS4;
     62   }
     63   // Strip the scheme if any.
     64   std::string::size_type colon = host.find("://");
     65   if (colon != std::string::npos)
     66     host = host.substr(colon + 3);
     67   // If a username and perhaps password are specified, give a warning.
     68   std::string::size_type at_sign = host.find("@");
     69   // Should this be supported?
     70   if (at_sign != std::string::npos) {
     71     // ProxyConfig does not support authentication parameters, but Chrome
     72     // will prompt for the password later. Disregard the
     73     // authentication parameters and continue with this hostname.
     74     LOG(WARNING) << "Proxy authentication parameters ignored, see bug 16709";
     75     host = host.substr(at_sign + 1);
     76   }
     77   // If this is a socks proxy, prepend a scheme so as to tell
     78   // ProxyServer. This also allows ProxyServer to choose the right
     79   // default port.
     80   if (scheme == ProxyServer::SCHEME_SOCKS4)
     81     host = "socks4://" + host;
     82   else if (scheme == ProxyServer::SCHEME_SOCKS5)
     83     host = "socks5://" + host;
     84   // If there is a trailing slash, remove it so |host| will parse correctly
     85   // even if it includes a port number (since the slash is not numeric).
     86   if (host.length() && host[host.length() - 1] == '/')
     87     host.resize(host.length() - 1);
     88   return host;
     89 }
     90 
     91 }  // namespace
     92 
     93 ProxyConfigServiceLinux::Delegate::~Delegate() {
     94 }
     95 
     96 bool ProxyConfigServiceLinux::Delegate::GetProxyFromEnvVarForScheme(
     97     const char* variable, ProxyServer::Scheme scheme,
     98     ProxyServer* result_server) {
     99   std::string env_value;
    100   if (env_var_getter_->GetVar(variable, &env_value)) {
    101     if (!env_value.empty()) {
    102       env_value = FixupProxyHostScheme(scheme, env_value);
    103       ProxyServer proxy_server =
    104           ProxyServer::FromURI(env_value, ProxyServer::SCHEME_HTTP);
    105       if (proxy_server.is_valid() && !proxy_server.is_direct()) {
    106         *result_server = proxy_server;
    107         return true;
    108       } else {
    109         LOG(ERROR) << "Failed to parse environment variable " << variable;
    110       }
    111     }
    112   }
    113   return false;
    114 }
    115 
    116 bool ProxyConfigServiceLinux::Delegate::GetProxyFromEnvVar(
    117     const char* variable, ProxyServer* result_server) {
    118   return GetProxyFromEnvVarForScheme(variable, ProxyServer::SCHEME_HTTP,
    119                                      result_server);
    120 }
    121 
    122 bool ProxyConfigServiceLinux::Delegate::GetConfigFromEnv(ProxyConfig* config) {
    123   // Check for automatic configuration first, in
    124   // "auto_proxy". Possibly only the "environment_proxy" firefox
    125   // extension has ever used this, but it still sounds like a good
    126   // idea.
    127   std::string auto_proxy;
    128   if (env_var_getter_->GetVar("auto_proxy", &auto_proxy)) {
    129     if (auto_proxy.empty()) {
    130       // Defined and empty => autodetect
    131       config->set_auto_detect(true);
    132     } else {
    133       // specified autoconfig URL
    134       config->set_pac_url(GURL(auto_proxy));
    135     }
    136     return true;
    137   }
    138   // "all_proxy" is a shortcut to avoid defining {http,https,ftp}_proxy.
    139   ProxyServer proxy_server;
    140   if (GetProxyFromEnvVar("all_proxy", &proxy_server)) {
    141     config->proxy_rules().type = ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY;
    142     config->proxy_rules().single_proxies.SetSingleProxyServer(proxy_server);
    143   } else {
    144     bool have_http = GetProxyFromEnvVar("http_proxy", &proxy_server);
    145     if (have_http)
    146       config->proxy_rules().proxies_for_http.SetSingleProxyServer(proxy_server);
    147     // It would be tempting to let http_proxy apply for all protocols
    148     // if https_proxy and ftp_proxy are not defined. Googling turns up
    149     // several documents that mention only http_proxy. But then the
    150     // user really might not want to proxy https. And it doesn't seem
    151     // like other apps do this. So we will refrain.
    152     bool have_https = GetProxyFromEnvVar("https_proxy", &proxy_server);
    153     if (have_https)
    154       config->proxy_rules().proxies_for_https.
    155           SetSingleProxyServer(proxy_server);
    156     bool have_ftp = GetProxyFromEnvVar("ftp_proxy", &proxy_server);
    157     if (have_ftp)
    158       config->proxy_rules().proxies_for_ftp.SetSingleProxyServer(proxy_server);
    159     if (have_http || have_https || have_ftp) {
    160       // mustn't change type unless some rules are actually set.
    161       config->proxy_rules().type =
    162           ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
    163     }
    164   }
    165   if (config->proxy_rules().empty()) {
    166     // If the above were not defined, try for socks.
    167     // For environment variables, we default to version 5, per the gnome
    168     // documentation: http://library.gnome.org/devel/gnet/stable/gnet-socks.html
    169     ProxyServer::Scheme scheme = ProxyServer::SCHEME_SOCKS5;
    170     std::string env_version;
    171     if (env_var_getter_->GetVar("SOCKS_VERSION", &env_version)
    172         && env_version == "4")
    173       scheme = ProxyServer::SCHEME_SOCKS4;
    174     if (GetProxyFromEnvVarForScheme("SOCKS_SERVER", scheme, &proxy_server)) {
    175       config->proxy_rules().type = ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY;
    176       config->proxy_rules().single_proxies.SetSingleProxyServer(proxy_server);
    177     }
    178   }
    179   // Look for the proxy bypass list.
    180   std::string no_proxy;
    181   env_var_getter_->GetVar("no_proxy", &no_proxy);
    182   if (config->proxy_rules().empty()) {
    183     // Having only "no_proxy" set, presumably to "*", makes it
    184     // explicit that env vars do specify a configuration: having no
    185     // rules specified only means the user explicitly asks for direct
    186     // connections.
    187     return !no_proxy.empty();
    188   }
    189   // Note that this uses "suffix" matching. So a bypass of "google.com"
    190   // is understood to mean a bypass of "*google.com".
    191   config->proxy_rules().bypass_rules.ParseFromStringUsingSuffixMatching(
    192       no_proxy);
    193   return true;
    194 }
    195 
    196 namespace {
    197 
    198 const int kDebounceTimeoutMilliseconds = 250;
    199 
    200 #if defined(USE_GCONF)
    201 // This setting getter uses gconf, as used in GNOME 2 and some GNOME 3 desktops.
    202 class SettingGetterImplGConf : public ProxyConfigServiceLinux::SettingGetter {
    203  public:
    204   SettingGetterImplGConf()
    205       : client_(NULL), system_proxy_id_(0), system_http_proxy_id_(0),
    206         notify_delegate_(NULL) {
    207   }
    208 
    209   virtual ~SettingGetterImplGConf() {
    210     // client_ should have been released before now, from
    211     // Delegate::OnDestroy(), while running on the UI thread. However
    212     // on exiting the process, it may happen that Delegate::OnDestroy()
    213     // task is left pending on the glib loop after the loop was quit,
    214     // and pending tasks may then be deleted without being run.
    215     if (client_) {
    216       // gconf client was not cleaned up.
    217       if (task_runner_->BelongsToCurrentThread()) {
    218         // We are on the UI thread so we can clean it safely. This is
    219         // the case at least for ui_tests running under Valgrind in
    220         // bug 16076.
    221         VLOG(1) << "~SettingGetterImplGConf: releasing gconf client";
    222         ShutDown();
    223       } else {
    224         // This is very bad! We are deleting the setting getter but we're not on
    225         // the UI thread. This is not supposed to happen: the setting getter is
    226         // owned by the proxy config service's delegate, which is supposed to be
    227         // destroyed on the UI thread only. We will get change notifications to
    228         // a deleted object if we continue here, so fail now.
    229         LOG(FATAL) << "~SettingGetterImplGConf: deleting on wrong thread!";
    230       }
    231     }
    232     DCHECK(!client_);
    233   }
    234 
    235   virtual bool Init(
    236       const scoped_refptr<base::SingleThreadTaskRunner>& glib_task_runner,
    237       const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner)
    238       OVERRIDE {
    239     DCHECK(glib_task_runner->BelongsToCurrentThread());
    240     DCHECK(!client_);
    241     DCHECK(!task_runner_.get());
    242     task_runner_ = glib_task_runner;
    243     client_ = gconf_client_get_default();
    244     if (!client_) {
    245       // It's not clear whether/when this can return NULL.
    246       LOG(ERROR) << "Unable to create a gconf client";
    247       task_runner_ = NULL;
    248       return false;
    249     }
    250     GError* error = NULL;
    251     bool added_system_proxy = false;
    252     // We need to add the directories for which we'll be asking
    253     // for notifications, and we might as well ask to preload them.
    254     // These need to be removed again in ShutDown(); we are careful
    255     // here to only leave client_ non-NULL if both have been added.
    256     gconf_client_add_dir(client_, "/system/proxy",
    257                          GCONF_CLIENT_PRELOAD_ONELEVEL, &error);
    258     if (error == NULL) {
    259       added_system_proxy = true;
    260       gconf_client_add_dir(client_, "/system/http_proxy",
    261                            GCONF_CLIENT_PRELOAD_ONELEVEL, &error);
    262     }
    263     if (error != NULL) {
    264       LOG(ERROR) << "Error requesting gconf directory: " << error->message;
    265       g_error_free(error);
    266       if (added_system_proxy)
    267         gconf_client_remove_dir(client_, "/system/proxy", NULL);
    268       g_object_unref(client_);
    269       client_ = NULL;
    270       task_runner_ = NULL;
    271       return false;
    272     }
    273     return true;
    274   }
    275 
    276   virtual void ShutDown() OVERRIDE {
    277     if (client_) {
    278       DCHECK(task_runner_->BelongsToCurrentThread());
    279       // We must explicitly disable gconf notifications here, because the gconf
    280       // client will be shared between all setting getters, and they do not all
    281       // have the same lifetimes. (For instance, incognito sessions get their
    282       // own, which is destroyed when the session ends.)
    283       gconf_client_notify_remove(client_, system_http_proxy_id_);
    284       gconf_client_notify_remove(client_, system_proxy_id_);
    285       gconf_client_remove_dir(client_, "/system/http_proxy", NULL);
    286       gconf_client_remove_dir(client_, "/system/proxy", NULL);
    287       g_object_unref(client_);
    288       client_ = NULL;
    289       task_runner_ = NULL;
    290     }
    291   }
    292 
    293   virtual bool SetUpNotifications(
    294       ProxyConfigServiceLinux::Delegate* delegate) OVERRIDE {
    295     DCHECK(client_);
    296     DCHECK(task_runner_->BelongsToCurrentThread());
    297     GError* error = NULL;
    298     notify_delegate_ = delegate;
    299     // We have to keep track of the IDs returned by gconf_client_notify_add() so
    300     // that we can remove them in ShutDown(). (Otherwise, notifications will be
    301     // delivered to this object after it is deleted, which is bad, m'kay?)
    302     system_proxy_id_ = gconf_client_notify_add(
    303         client_, "/system/proxy",
    304         OnGConfChangeNotification, this,
    305         NULL, &error);
    306     if (error == NULL) {
    307       system_http_proxy_id_ = gconf_client_notify_add(
    308           client_, "/system/http_proxy",
    309           OnGConfChangeNotification, this,
    310           NULL, &error);
    311     }
    312     if (error != NULL) {
    313       LOG(ERROR) << "Error requesting gconf notifications: " << error->message;
    314       g_error_free(error);
    315       ShutDown();
    316       return false;
    317     }
    318     // Simulate a change to avoid possibly losing updates before this point.
    319     OnChangeNotification();
    320     return true;
    321   }
    322 
    323   virtual const scoped_refptr<base::SingleThreadTaskRunner>&
    324   GetNotificationTaskRunner() OVERRIDE {
    325     return task_runner_;
    326   }
    327 
    328   virtual ProxyConfigSource GetConfigSource() OVERRIDE {
    329     return PROXY_CONFIG_SOURCE_GCONF;
    330   }
    331 
    332   virtual bool GetString(StringSetting key, std::string* result) OVERRIDE {
    333     switch (key) {
    334       case PROXY_MODE:
    335         return GetStringByPath("/system/proxy/mode", result);
    336       case PROXY_AUTOCONF_URL:
    337         return GetStringByPath("/system/proxy/autoconfig_url", result);
    338       case PROXY_HTTP_HOST:
    339         return GetStringByPath("/system/http_proxy/host", result);
    340       case PROXY_HTTPS_HOST:
    341         return GetStringByPath("/system/proxy/secure_host", result);
    342       case PROXY_FTP_HOST:
    343         return GetStringByPath("/system/proxy/ftp_host", result);
    344       case PROXY_SOCKS_HOST:
    345         return GetStringByPath("/system/proxy/socks_host", result);
    346     }
    347     return false;  // Placate compiler.
    348   }
    349   virtual bool GetBool(BoolSetting key, bool* result) OVERRIDE {
    350     switch (key) {
    351       case PROXY_USE_HTTP_PROXY:
    352         return GetBoolByPath("/system/http_proxy/use_http_proxy", result);
    353       case PROXY_USE_SAME_PROXY:
    354         return GetBoolByPath("/system/http_proxy/use_same_proxy", result);
    355       case PROXY_USE_AUTHENTICATION:
    356         return GetBoolByPath("/system/http_proxy/use_authentication", result);
    357     }
    358     return false;  // Placate compiler.
    359   }
    360   virtual bool GetInt(IntSetting key, int* result) OVERRIDE {
    361     switch (key) {
    362       case PROXY_HTTP_PORT:
    363         return GetIntByPath("/system/http_proxy/port", result);
    364       case PROXY_HTTPS_PORT:
    365         return GetIntByPath("/system/proxy/secure_port", result);
    366       case PROXY_FTP_PORT:
    367         return GetIntByPath("/system/proxy/ftp_port", result);
    368       case PROXY_SOCKS_PORT:
    369         return GetIntByPath("/system/proxy/socks_port", result);
    370     }
    371     return false;  // Placate compiler.
    372   }
    373   virtual bool GetStringList(StringListSetting key,
    374                              std::vector<std::string>* result) OVERRIDE {
    375     switch (key) {
    376       case PROXY_IGNORE_HOSTS:
    377         return GetStringListByPath("/system/http_proxy/ignore_hosts", result);
    378     }
    379     return false;  // Placate compiler.
    380   }
    381 
    382   virtual bool BypassListIsReversed() OVERRIDE {
    383     // This is a KDE-specific setting.
    384     return false;
    385   }
    386 
    387   virtual bool MatchHostsUsingSuffixMatching() OVERRIDE {
    388     return false;
    389   }
    390 
    391  private:
    392   bool GetStringByPath(const char* key, std::string* result) {
    393     DCHECK(client_);
    394     DCHECK(task_runner_->BelongsToCurrentThread());
    395     GError* error = NULL;
    396     gchar* value = gconf_client_get_string(client_, key, &error);
    397     if (HandleGError(error, key))
    398       return false;
    399     if (!value)
    400       return false;
    401     *result = value;
    402     g_free(value);
    403     return true;
    404   }
    405   bool GetBoolByPath(const char* key, bool* result) {
    406     DCHECK(client_);
    407     DCHECK(task_runner_->BelongsToCurrentThread());
    408     GError* error = NULL;
    409     // We want to distinguish unset values from values defaulting to
    410     // false. For that we need to use the type-generic
    411     // gconf_client_get() rather than gconf_client_get_bool().
    412     GConfValue* gconf_value = gconf_client_get(client_, key, &error);
    413     if (HandleGError(error, key))
    414       return false;
    415     if (!gconf_value) {
    416       // Unset.
    417       return false;
    418     }
    419     if (gconf_value->type != GCONF_VALUE_BOOL) {
    420       gconf_value_free(gconf_value);
    421       return false;
    422     }
    423     gboolean bool_value = gconf_value_get_bool(gconf_value);
    424     *result = static_cast<bool>(bool_value);
    425     gconf_value_free(gconf_value);
    426     return true;
    427   }
    428   bool GetIntByPath(const char* key, int* result) {
    429     DCHECK(client_);
    430     DCHECK(task_runner_->BelongsToCurrentThread());
    431     GError* error = NULL;
    432     int value = gconf_client_get_int(client_, key, &error);
    433     if (HandleGError(error, key))
    434       return false;
    435     // We don't bother to distinguish an unset value because callers
    436     // don't care. 0 is returned if unset.
    437     *result = value;
    438     return true;
    439   }
    440   bool GetStringListByPath(const char* key, std::vector<std::string>* result) {
    441     DCHECK(client_);
    442     DCHECK(task_runner_->BelongsToCurrentThread());
    443     GError* error = NULL;
    444     GSList* list = gconf_client_get_list(client_, key,
    445                                          GCONF_VALUE_STRING, &error);
    446     if (HandleGError(error, key))
    447       return false;
    448     if (!list)
    449       return false;
    450     for (GSList *it = list; it; it = it->next) {
    451       result->push_back(static_cast<char*>(it->data));
    452       g_free(it->data);
    453     }
    454     g_slist_free(list);
    455     return true;
    456   }
    457 
    458   // Logs and frees a glib error. Returns false if there was no error
    459   // (error is NULL).
    460   bool HandleGError(GError* error, const char* key) {
    461     if (error != NULL) {
    462       LOG(ERROR) << "Error getting gconf value for " << key
    463                  << ": " << error->message;
    464       g_error_free(error);
    465       return true;
    466     }
    467     return false;
    468   }
    469 
    470   // This is the callback from the debounce timer.
    471   void OnDebouncedNotification() {
    472     DCHECK(task_runner_->BelongsToCurrentThread());
    473     CHECK(notify_delegate_);
    474     // Forward to a method on the proxy config service delegate object.
    475     notify_delegate_->OnCheckProxyConfigSettings();
    476   }
    477 
    478   void OnChangeNotification() {
    479     // We don't use Reset() because the timer may not yet be running.
    480     // (In that case Stop() is a no-op.)
    481     debounce_timer_.Stop();
    482     debounce_timer_.Start(FROM_HERE,
    483         base::TimeDelta::FromMilliseconds(kDebounceTimeoutMilliseconds),
    484         this, &SettingGetterImplGConf::OnDebouncedNotification);
    485   }
    486 
    487   // gconf notification callback, dispatched on the default glib main loop.
    488   static void OnGConfChangeNotification(GConfClient* client, guint cnxn_id,
    489                                         GConfEntry* entry, gpointer user_data) {
    490     VLOG(1) << "gconf change notification for key "
    491             << gconf_entry_get_key(entry);
    492     // We don't track which key has changed, just that something did change.
    493     SettingGetterImplGConf* setting_getter =
    494         reinterpret_cast<SettingGetterImplGConf*>(user_data);
    495     setting_getter->OnChangeNotification();
    496   }
    497 
    498   GConfClient* client_;
    499   // These ids are the values returned from gconf_client_notify_add(), which we
    500   // will need in order to later call gconf_client_notify_remove().
    501   guint system_proxy_id_;
    502   guint system_http_proxy_id_;
    503 
    504   ProxyConfigServiceLinux::Delegate* notify_delegate_;
    505   base::OneShotTimer<SettingGetterImplGConf> debounce_timer_;
    506 
    507   // Task runner for the thread that we make gconf calls on. It should
    508   // be the UI thread and all our methods should be called on this
    509   // thread. Only for assertions.
    510   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
    511 
    512   DISALLOW_COPY_AND_ASSIGN(SettingGetterImplGConf);
    513 };
    514 #endif  // defined(USE_GCONF)
    515 
    516 #if defined(USE_GIO)
    517 const char kProxyGConfSchema[] = "org.gnome.system.proxy";
    518 
    519 // This setting getter uses gsettings, as used in most GNOME 3 desktops.
    520 class SettingGetterImplGSettings
    521     : public ProxyConfigServiceLinux::SettingGetter {
    522  public:
    523   SettingGetterImplGSettings() :
    524     client_(NULL),
    525     http_client_(NULL),
    526     https_client_(NULL),
    527     ftp_client_(NULL),
    528     socks_client_(NULL),
    529     notify_delegate_(NULL) {
    530   }
    531 
    532   virtual ~SettingGetterImplGSettings() {
    533     // client_ should have been released before now, from
    534     // Delegate::OnDestroy(), while running on the UI thread. However
    535     // on exiting the process, it may happen that
    536     // Delegate::OnDestroy() task is left pending on the glib loop
    537     // after the loop was quit, and pending tasks may then be deleted
    538     // without being run.
    539     if (client_) {
    540       // gconf client was not cleaned up.
    541       if (task_runner_->BelongsToCurrentThread()) {
    542         // We are on the UI thread so we can clean it safely. This is
    543         // the case at least for ui_tests running under Valgrind in
    544         // bug 16076.
    545         VLOG(1) << "~SettingGetterImplGSettings: releasing gsettings client";
    546         ShutDown();
    547       } else {
    548         LOG(WARNING) << "~SettingGetterImplGSettings: leaking gsettings client";
    549         client_ = NULL;
    550       }
    551     }
    552     DCHECK(!client_);
    553   }
    554 
    555   bool SchemaExists(const char* schema_name) {
    556     const gchar* const* schemas = libgio_loader_.g_settings_list_schemas();
    557     while (*schemas) {
    558       if (strcmp(schema_name, static_cast<const char*>(*schemas)) == 0)
    559         return true;
    560       schemas++;
    561     }
    562     return false;
    563   }
    564 
    565   // LoadAndCheckVersion() must be called *before* Init()!
    566   bool LoadAndCheckVersion(base::Environment* env);
    567 
    568   virtual bool Init(
    569       const scoped_refptr<base::SingleThreadTaskRunner>& glib_task_runner,
    570       const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner)
    571       OVERRIDE {
    572     DCHECK(glib_task_runner->BelongsToCurrentThread());
    573     DCHECK(!client_);
    574     DCHECK(!task_runner_.get());
    575 
    576     if (!SchemaExists(kProxyGConfSchema) ||
    577         !(client_ = libgio_loader_.g_settings_new(kProxyGConfSchema))) {
    578       // It's not clear whether/when this can return NULL.
    579       LOG(ERROR) << "Unable to create a gsettings client";
    580       return false;
    581     }
    582     task_runner_ = glib_task_runner;
    583     // We assume these all work if the above call worked.
    584     http_client_ = libgio_loader_.g_settings_get_child(client_, "http");
    585     https_client_ = libgio_loader_.g_settings_get_child(client_, "https");
    586     ftp_client_ = libgio_loader_.g_settings_get_child(client_, "ftp");
    587     socks_client_ = libgio_loader_.g_settings_get_child(client_, "socks");
    588     DCHECK(http_client_ && https_client_ && ftp_client_ && socks_client_);
    589     return true;
    590   }
    591 
    592   virtual void ShutDown() OVERRIDE {
    593     if (client_) {
    594       DCHECK(task_runner_->BelongsToCurrentThread());
    595       // This also disables gsettings notifications.
    596       g_object_unref(socks_client_);
    597       g_object_unref(ftp_client_);
    598       g_object_unref(https_client_);
    599       g_object_unref(http_client_);
    600       g_object_unref(client_);
    601       // We only need to null client_ because it's the only one that we check.
    602       client_ = NULL;
    603       task_runner_ = NULL;
    604     }
    605   }
    606 
    607   virtual bool SetUpNotifications(
    608       ProxyConfigServiceLinux::Delegate* delegate) OVERRIDE {
    609     DCHECK(client_);
    610     DCHECK(task_runner_->BelongsToCurrentThread());
    611     notify_delegate_ = delegate;
    612     // We could watch for the change-event signal instead of changed, but
    613     // since we have to watch more than one object, we'd still have to
    614     // debounce change notifications. This is conceptually simpler.
    615     g_signal_connect(G_OBJECT(client_), "changed",
    616                      G_CALLBACK(OnGSettingsChangeNotification), this);
    617     g_signal_connect(G_OBJECT(http_client_), "changed",
    618                      G_CALLBACK(OnGSettingsChangeNotification), this);
    619     g_signal_connect(G_OBJECT(https_client_), "changed",
    620                      G_CALLBACK(OnGSettingsChangeNotification), this);
    621     g_signal_connect(G_OBJECT(ftp_client_), "changed",
    622                      G_CALLBACK(OnGSettingsChangeNotification), this);
    623     g_signal_connect(G_OBJECT(socks_client_), "changed",
    624                      G_CALLBACK(OnGSettingsChangeNotification), this);
    625     // Simulate a change to avoid possibly losing updates before this point.
    626     OnChangeNotification();
    627     return true;
    628   }
    629 
    630   virtual const scoped_refptr<base::SingleThreadTaskRunner>&
    631   GetNotificationTaskRunner() OVERRIDE {
    632     return task_runner_;
    633   }
    634 
    635   virtual ProxyConfigSource GetConfigSource() OVERRIDE {
    636     return PROXY_CONFIG_SOURCE_GSETTINGS;
    637   }
    638 
    639   virtual bool GetString(StringSetting key, std::string* result) OVERRIDE {
    640     DCHECK(client_);
    641     switch (key) {
    642       case PROXY_MODE:
    643         return GetStringByPath(client_, "mode", result);
    644       case PROXY_AUTOCONF_URL:
    645         return GetStringByPath(client_, "autoconfig-url", result);
    646       case PROXY_HTTP_HOST:
    647         return GetStringByPath(http_client_, "host", result);
    648       case PROXY_HTTPS_HOST:
    649         return GetStringByPath(https_client_, "host", result);
    650       case PROXY_FTP_HOST:
    651         return GetStringByPath(ftp_client_, "host", result);
    652       case PROXY_SOCKS_HOST:
    653         return GetStringByPath(socks_client_, "host", result);
    654     }
    655     return false;  // Placate compiler.
    656   }
    657   virtual bool GetBool(BoolSetting key, bool* result) OVERRIDE {
    658     DCHECK(client_);
    659     switch (key) {
    660       case PROXY_USE_HTTP_PROXY:
    661         // Although there is an "enabled" boolean in http_client_, it is not set
    662         // to true by the proxy config utility. We ignore it and return false.
    663         return false;
    664       case PROXY_USE_SAME_PROXY:
    665         // Similarly, although there is a "use-same-proxy" boolean in client_,
    666         // it is never set to false by the proxy config utility. We ignore it.
    667         return false;
    668       case PROXY_USE_AUTHENTICATION:
    669         // There is also no way to set this in the proxy config utility, but it
    670         // doesn't hurt us to get the actual setting (unlike the two above).
    671         return GetBoolByPath(http_client_, "use-authentication", result);
    672     }
    673     return false;  // Placate compiler.
    674   }
    675   virtual bool GetInt(IntSetting key, int* result) OVERRIDE {
    676     DCHECK(client_);
    677     switch (key) {
    678       case PROXY_HTTP_PORT:
    679         return GetIntByPath(http_client_, "port", result);
    680       case PROXY_HTTPS_PORT:
    681         return GetIntByPath(https_client_, "port", result);
    682       case PROXY_FTP_PORT:
    683         return GetIntByPath(ftp_client_, "port", result);
    684       case PROXY_SOCKS_PORT:
    685         return GetIntByPath(socks_client_, "port", result);
    686     }
    687     return false;  // Placate compiler.
    688   }
    689   virtual bool GetStringList(StringListSetting key,
    690                              std::vector<std::string>* result) OVERRIDE {
    691     DCHECK(client_);
    692     switch (key) {
    693       case PROXY_IGNORE_HOSTS:
    694         return GetStringListByPath(client_, "ignore-hosts", result);
    695     }
    696     return false;  // Placate compiler.
    697   }
    698 
    699   virtual bool BypassListIsReversed() OVERRIDE {
    700     // This is a KDE-specific setting.
    701     return false;
    702   }
    703 
    704   virtual bool MatchHostsUsingSuffixMatching() OVERRIDE {
    705     return false;
    706   }
    707 
    708  private:
    709   bool GetStringByPath(GSettings* client, const char* key,
    710                        std::string* result) {
    711     DCHECK(task_runner_->BelongsToCurrentThread());
    712     gchar* value = libgio_loader_.g_settings_get_string(client, key);
    713     if (!value)
    714       return false;
    715     *result = value;
    716     g_free(value);
    717     return true;
    718   }
    719   bool GetBoolByPath(GSettings* client, const char* key, bool* result) {
    720     DCHECK(task_runner_->BelongsToCurrentThread());
    721     *result = static_cast<bool>(
    722         libgio_loader_.g_settings_get_boolean(client, key));
    723     return true;
    724   }
    725   bool GetIntByPath(GSettings* client, const char* key, int* result) {
    726     DCHECK(task_runner_->BelongsToCurrentThread());
    727     *result = libgio_loader_.g_settings_get_int(client, key);
    728     return true;
    729   }
    730   bool GetStringListByPath(GSettings* client, const char* key,
    731                            std::vector<std::string>* result) {
    732     DCHECK(task_runner_->BelongsToCurrentThread());
    733     gchar** list = libgio_loader_.g_settings_get_strv(client, key);
    734     if (!list)
    735       return false;
    736     for (size_t i = 0; list[i]; ++i) {
    737       result->push_back(static_cast<char*>(list[i]));
    738       g_free(list[i]);
    739     }
    740     g_free(list);
    741     return true;
    742   }
    743 
    744   // This is the callback from the debounce timer.
    745   void OnDebouncedNotification() {
    746     DCHECK(task_runner_->BelongsToCurrentThread());
    747     CHECK(notify_delegate_);
    748     // Forward to a method on the proxy config service delegate object.
    749     notify_delegate_->OnCheckProxyConfigSettings();
    750   }
    751 
    752   void OnChangeNotification() {
    753     // We don't use Reset() because the timer may not yet be running.
    754     // (In that case Stop() is a no-op.)
    755     debounce_timer_.Stop();
    756     debounce_timer_.Start(FROM_HERE,
    757         base::TimeDelta::FromMilliseconds(kDebounceTimeoutMilliseconds),
    758         this, &SettingGetterImplGSettings::OnDebouncedNotification);
    759   }
    760 
    761   // gsettings notification callback, dispatched on the default glib main loop.
    762   static void OnGSettingsChangeNotification(GSettings* client, gchar* key,
    763                                             gpointer user_data) {
    764     VLOG(1) << "gsettings change notification for key " << key;
    765     // We don't track which key has changed, just that something did change.
    766     SettingGetterImplGSettings* setting_getter =
    767         reinterpret_cast<SettingGetterImplGSettings*>(user_data);
    768     setting_getter->OnChangeNotification();
    769   }
    770 
    771   GSettings* client_;
    772   GSettings* http_client_;
    773   GSettings* https_client_;
    774   GSettings* ftp_client_;
    775   GSettings* socks_client_;
    776   ProxyConfigServiceLinux::Delegate* notify_delegate_;
    777   base::OneShotTimer<SettingGetterImplGSettings> debounce_timer_;
    778 
    779   // Task runner for the thread that we make gsettings calls on. It should
    780   // be the UI thread and all our methods should be called on this
    781   // thread. Only for assertions.
    782   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
    783 
    784   LibGioLoader libgio_loader_;
    785 
    786   DISALLOW_COPY_AND_ASSIGN(SettingGetterImplGSettings);
    787 };
    788 
    789 bool SettingGetterImplGSettings::LoadAndCheckVersion(
    790     base::Environment* env) {
    791   // LoadAndCheckVersion() must be called *before* Init()!
    792   DCHECK(!client_);
    793 
    794   // The APIs to query gsettings were introduced after the minimum glib
    795   // version we target, so we can't link directly against them. We load them
    796   // dynamically at runtime, and if they don't exist, return false here. (We
    797   // support linking directly via gyp flags though.) Additionally, even when
    798   // they are present, we do two additional checks to make sure we should use
    799   // them and not gconf. First, we attempt to load the schema for proxy
    800   // settings. Second, we check for the program that was used in older
    801   // versions of GNOME to configure proxy settings, and return false if it
    802   // exists. Some distributions (e.g. Ubuntu 11.04) have the API and schema
    803   // but don't use gsettings for proxy settings, but they do have the old
    804   // binary, so we detect these systems that way.
    805 
    806   {
    807     // TODO(phajdan.jr): Redesign the code to load library on different thread.
    808     base::ThreadRestrictions::ScopedAllowIO allow_io;
    809 
    810     // Try also without .0 at the end; on some systems this may be required.
    811     if (!libgio_loader_.Load("libgio-2.0.so.0") &&
    812         !libgio_loader_.Load("libgio-2.0.so")) {
    813       VLOG(1) << "Cannot load gio library. Will fall back to gconf.";
    814       return false;
    815     }
    816   }
    817 
    818   GSettings* client = NULL;
    819   if (SchemaExists(kProxyGConfSchema)) {
    820     ANNOTATE_SCOPED_MEMORY_LEAK; // http://crbug.com/380782
    821     client = libgio_loader_.g_settings_new(kProxyGConfSchema);
    822   }
    823   if (!client) {
    824     VLOG(1) << "Cannot create gsettings client. Will fall back to gconf.";
    825     return false;
    826   }
    827   g_object_unref(client);
    828 
    829   std::string path;
    830   if (!env->GetVar("PATH", &path)) {
    831     LOG(ERROR) << "No $PATH variable. Assuming no gnome-network-properties.";
    832   } else {
    833     // Yes, we're on the UI thread. Yes, we're accessing the file system.
    834     // Sadly, we don't have much choice. We need the proxy settings and we
    835     // need them now, and to figure out where to get them, we have to check
    836     // for this binary. See http://crbug.com/69057 for additional details.
    837     base::ThreadRestrictions::ScopedAllowIO allow_io;
    838     std::vector<std::string> paths;
    839     Tokenize(path, ":", &paths);
    840     for (size_t i = 0; i < paths.size(); ++i) {
    841       base::FilePath file(paths[i]);
    842       if (base::PathExists(file.Append("gnome-network-properties"))) {
    843         VLOG(1) << "Found gnome-network-properties. Will fall back to gconf.";
    844         return false;
    845       }
    846     }
    847   }
    848 
    849   VLOG(1) << "All gsettings tests OK. Will get proxy config from gsettings.";
    850   return true;
    851 }
    852 #endif  // defined(USE_GIO)
    853 
    854 // This is the KDE version that reads kioslaverc and simulates gconf.
    855 // Doing this allows the main Delegate code, as well as the unit tests
    856 // for it, to stay the same - and the settings map fairly well besides.
    857 class SettingGetterImplKDE : public ProxyConfigServiceLinux::SettingGetter,
    858                              public base::MessagePumpLibevent::Watcher {
    859  public:
    860   explicit SettingGetterImplKDE(base::Environment* env_var_getter)
    861       : inotify_fd_(-1), notify_delegate_(NULL), indirect_manual_(false),
    862         auto_no_pac_(false), reversed_bypass_list_(false),
    863         env_var_getter_(env_var_getter), file_task_runner_(NULL) {
    864     // This has to be called on the UI thread (http://crbug.com/69057).
    865     base::ThreadRestrictions::ScopedAllowIO allow_io;
    866 
    867     // Derive the location of the kde config dir from the environment.
    868     std::string home;
    869     if (env_var_getter->GetVar("KDEHOME", &home) && !home.empty()) {
    870       // $KDEHOME is set. Use it unconditionally.
    871       kde_config_dir_ = KDEHomeToConfigPath(base::FilePath(home));
    872     } else {
    873       // $KDEHOME is unset. Try to figure out what to use. This seems to be
    874       // the common case on most distributions.
    875       if (!env_var_getter->GetVar(base::env_vars::kHome, &home))
    876         // User has no $HOME? Give up. Later we'll report the failure.
    877         return;
    878       if (base::nix::GetDesktopEnvironment(env_var_getter) ==
    879           base::nix::DESKTOP_ENVIRONMENT_KDE3) {
    880         // KDE3 always uses .kde for its configuration.
    881         base::FilePath kde_path = base::FilePath(home).Append(".kde");
    882         kde_config_dir_ = KDEHomeToConfigPath(kde_path);
    883       } else {
    884         // Some distributions patch KDE4 to use .kde4 instead of .kde, so that
    885         // both can be installed side-by-side. Sadly they don't all do this, and
    886         // they don't always do this: some distributions have started switching
    887         // back as well. So if there is a .kde4 directory, check the timestamps
    888         // of the config directories within and use the newest one.
    889         // Note that we should currently be running in the UI thread, because in
    890         // the gconf version, that is the only thread that can access the proxy
    891         // settings (a gconf restriction). As noted below, the initial read of
    892         // the proxy settings will be done in this thread anyway, so we check
    893         // for .kde4 here in this thread as well.
    894         base::FilePath kde3_path = base::FilePath(home).Append(".kde");
    895         base::FilePath kde3_config = KDEHomeToConfigPath(kde3_path);
    896         base::FilePath kde4_path = base::FilePath(home).Append(".kde4");
    897         base::FilePath kde4_config = KDEHomeToConfigPath(kde4_path);
    898         bool use_kde4 = false;
    899         if (base::DirectoryExists(kde4_path)) {
    900           base::File::Info kde3_info;
    901           base::File::Info kde4_info;
    902           if (base::GetFileInfo(kde4_config, &kde4_info)) {
    903             if (base::GetFileInfo(kde3_config, &kde3_info)) {
    904               use_kde4 = kde4_info.last_modified >= kde3_info.last_modified;
    905             } else {
    906               use_kde4 = true;
    907             }
    908           }
    909         }
    910         if (use_kde4) {
    911           kde_config_dir_ = KDEHomeToConfigPath(kde4_path);
    912         } else {
    913           kde_config_dir_ = KDEHomeToConfigPath(kde3_path);
    914         }
    915       }
    916     }
    917   }
    918 
    919   virtual ~SettingGetterImplKDE() {
    920     // inotify_fd_ should have been closed before now, from
    921     // Delegate::OnDestroy(), while running on the file thread. However
    922     // on exiting the process, it may happen that Delegate::OnDestroy()
    923     // task is left pending on the file loop after the loop was quit,
    924     // and pending tasks may then be deleted without being run.
    925     // Here in the KDE version, we can safely close the file descriptor
    926     // anyway. (Not that it really matters; the process is exiting.)
    927     if (inotify_fd_ >= 0)
    928       ShutDown();
    929     DCHECK(inotify_fd_ < 0);
    930   }
    931 
    932   virtual bool Init(
    933       const scoped_refptr<base::SingleThreadTaskRunner>& glib_task_runner,
    934       const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner)
    935       OVERRIDE {
    936     // This has to be called on the UI thread (http://crbug.com/69057).
    937     base::ThreadRestrictions::ScopedAllowIO allow_io;
    938     DCHECK(inotify_fd_ < 0);
    939     inotify_fd_ = inotify_init();
    940     if (inotify_fd_ < 0) {
    941       PLOG(ERROR) << "inotify_init failed";
    942       return false;
    943     }
    944     int flags = fcntl(inotify_fd_, F_GETFL);
    945     if (fcntl(inotify_fd_, F_SETFL, flags | O_NONBLOCK) < 0) {
    946       PLOG(ERROR) << "fcntl failed";
    947       close(inotify_fd_);
    948       inotify_fd_ = -1;
    949       return false;
    950     }
    951     file_task_runner_ = file_task_runner;
    952     // The initial read is done on the current thread, not
    953     // |file_task_runner_|, since we will need to have it for
    954     // SetUpAndFetchInitialConfig().
    955     UpdateCachedSettings();
    956     return true;
    957   }
    958 
    959   virtual void ShutDown() OVERRIDE {
    960     if (inotify_fd_ >= 0) {
    961       ResetCachedSettings();
    962       inotify_watcher_.StopWatchingFileDescriptor();
    963       close(inotify_fd_);
    964       inotify_fd_ = -1;
    965     }
    966   }
    967 
    968   virtual bool SetUpNotifications(
    969       ProxyConfigServiceLinux::Delegate* delegate) OVERRIDE {
    970     DCHECK(inotify_fd_ >= 0);
    971     DCHECK(file_task_runner_->BelongsToCurrentThread());
    972     // We can't just watch the kioslaverc file directly, since KDE will write
    973     // a new copy of it and then rename it whenever settings are changed and
    974     // inotify watches inodes (so we'll be watching the old deleted file after
    975     // the first change, and it will never change again). So, we watch the
    976     // directory instead. We then act only on changes to the kioslaverc entry.
    977     if (inotify_add_watch(inotify_fd_, kde_config_dir_.value().c_str(),
    978                           IN_MODIFY | IN_MOVED_TO) < 0) {
    979       return false;
    980     }
    981     notify_delegate_ = delegate;
    982     if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
    983             inotify_fd_, true, base::MessageLoopForIO::WATCH_READ,
    984             &inotify_watcher_, this)) {
    985       return false;
    986     }
    987     // Simulate a change to avoid possibly losing updates before this point.
    988     OnChangeNotification();
    989     return true;
    990   }
    991 
    992   virtual const scoped_refptr<base::SingleThreadTaskRunner>&
    993   GetNotificationTaskRunner() OVERRIDE {
    994     return file_task_runner_;
    995   }
    996 
    997   // Implement base::MessagePumpLibevent::Watcher.
    998   virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE {
    999     DCHECK_EQ(fd, inotify_fd_);
   1000     DCHECK(file_task_runner_->BelongsToCurrentThread());
   1001     OnChangeNotification();
   1002   }
   1003   virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {
   1004     NOTREACHED();
   1005   }
   1006 
   1007   virtual ProxyConfigSource GetConfigSource() OVERRIDE {
   1008     return PROXY_CONFIG_SOURCE_KDE;
   1009   }
   1010 
   1011   virtual bool GetString(StringSetting key, std::string* result) OVERRIDE {
   1012     string_map_type::iterator it = string_table_.find(key);
   1013     if (it == string_table_.end())
   1014       return false;
   1015     *result = it->second;
   1016     return true;
   1017   }
   1018   virtual bool GetBool(BoolSetting key, bool* result) OVERRIDE {
   1019     // We don't ever have any booleans.
   1020     return false;
   1021   }
   1022   virtual bool GetInt(IntSetting key, int* result) OVERRIDE {
   1023     // We don't ever have any integers. (See AddProxy() below about ports.)
   1024     return false;
   1025   }
   1026   virtual bool GetStringList(StringListSetting key,
   1027                              std::vector<std::string>* result) OVERRIDE {
   1028     strings_map_type::iterator it = strings_table_.find(key);
   1029     if (it == strings_table_.end())
   1030       return false;
   1031     *result = it->second;
   1032     return true;
   1033   }
   1034 
   1035   virtual bool BypassListIsReversed() OVERRIDE {
   1036     return reversed_bypass_list_;
   1037   }
   1038 
   1039   virtual bool MatchHostsUsingSuffixMatching() OVERRIDE {
   1040     return true;
   1041   }
   1042 
   1043  private:
   1044   void ResetCachedSettings() {
   1045     string_table_.clear();
   1046     strings_table_.clear();
   1047     indirect_manual_ = false;
   1048     auto_no_pac_ = false;
   1049     reversed_bypass_list_ = false;
   1050   }
   1051 
   1052   base::FilePath KDEHomeToConfigPath(const base::FilePath& kde_home) {
   1053     return kde_home.Append("share").Append("config");
   1054   }
   1055 
   1056   void AddProxy(StringSetting host_key, const std::string& value) {
   1057     if (value.empty() || value.substr(0, 3) == "//:")
   1058       // No proxy.
   1059       return;
   1060     size_t space = value.find(' ');
   1061     if (space != std::string::npos) {
   1062       // Newer versions of KDE use a space rather than a colon to separate the
   1063       // port number from the hostname. If we find this, we need to convert it.
   1064       std::string fixed = value;
   1065       fixed[space] = ':';
   1066       string_table_[host_key] = fixed;
   1067     } else {
   1068       // We don't need to parse the port number out; GetProxyFromSettings()
   1069       // would only append it right back again. So we just leave the port
   1070       // number right in the host string.
   1071       string_table_[host_key] = value;
   1072     }
   1073   }
   1074 
   1075   void AddHostList(StringListSetting key, const std::string& value) {
   1076     std::vector<std::string> tokens;
   1077     base::StringTokenizer tk(value, ", ");
   1078     while (tk.GetNext()) {
   1079       std::string token = tk.token();
   1080       if (!token.empty())
   1081         tokens.push_back(token);
   1082     }
   1083     strings_table_[key] = tokens;
   1084   }
   1085 
   1086   void AddKDESetting(const std::string& key, const std::string& value) {
   1087     if (key == "ProxyType") {
   1088       const char* mode = "none";
   1089       indirect_manual_ = false;
   1090       auto_no_pac_ = false;
   1091       int int_value;
   1092       base::StringToInt(value, &int_value);
   1093       switch (int_value) {
   1094         case 0:  // No proxy, or maybe kioslaverc syntax error.
   1095           break;
   1096         case 1:  // Manual configuration.
   1097           mode = "manual";
   1098           break;
   1099         case 2:  // PAC URL.
   1100           mode = "auto";
   1101           break;
   1102         case 3:  // WPAD.
   1103           mode = "auto";
   1104           auto_no_pac_ = true;
   1105           break;
   1106         case 4:  // Indirect manual via environment variables.
   1107           mode = "manual";
   1108           indirect_manual_ = true;
   1109           break;
   1110       }
   1111       string_table_[PROXY_MODE] = mode;
   1112     } else if (key == "Proxy Config Script") {
   1113       string_table_[PROXY_AUTOCONF_URL] = value;
   1114     } else if (key == "httpProxy") {
   1115       AddProxy(PROXY_HTTP_HOST, value);
   1116     } else if (key == "httpsProxy") {
   1117       AddProxy(PROXY_HTTPS_HOST, value);
   1118     } else if (key == "ftpProxy") {
   1119       AddProxy(PROXY_FTP_HOST, value);
   1120     } else if (key == "socksProxy") {
   1121       // Older versions of KDE configure SOCKS in a weird way involving
   1122       // LD_PRELOAD and a library that intercepts network calls to SOCKSify
   1123       // them. We don't support it. KDE 4.8 added a proper SOCKS setting.
   1124       AddProxy(PROXY_SOCKS_HOST, value);
   1125     } else if (key == "ReversedException") {
   1126       // We count "true" or any nonzero number as true, otherwise false.
   1127       // Note that if the value is not actually numeric StringToInt()
   1128       // will return 0, which we count as false.
   1129       int int_value;
   1130       base::StringToInt(value, &int_value);
   1131       reversed_bypass_list_ = (value == "true" || int_value);
   1132     } else if (key == "NoProxyFor") {
   1133       AddHostList(PROXY_IGNORE_HOSTS, value);
   1134     } else if (key == "AuthMode") {
   1135       // Check for authentication, just so we can warn.
   1136       int mode;
   1137       base::StringToInt(value, &mode);
   1138       if (mode) {
   1139         // ProxyConfig does not support authentication parameters, but
   1140         // Chrome will prompt for the password later. So we ignore this.
   1141         LOG(WARNING) <<
   1142             "Proxy authentication parameters ignored, see bug 16709";
   1143       }
   1144     }
   1145   }
   1146 
   1147   void ResolveIndirect(StringSetting key) {
   1148     string_map_type::iterator it = string_table_.find(key);
   1149     if (it != string_table_.end()) {
   1150       std::string value;
   1151       if (env_var_getter_->GetVar(it->second.c_str(), &value))
   1152         it->second = value;
   1153       else
   1154         string_table_.erase(it);
   1155     }
   1156   }
   1157 
   1158   void ResolveIndirectList(StringListSetting key) {
   1159     strings_map_type::iterator it = strings_table_.find(key);
   1160     if (it != strings_table_.end()) {
   1161       std::string value;
   1162       if (!it->second.empty() &&
   1163           env_var_getter_->GetVar(it->second[0].c_str(), &value))
   1164         AddHostList(key, value);
   1165       else
   1166         strings_table_.erase(it);
   1167     }
   1168   }
   1169 
   1170   // The settings in kioslaverc could occur in any order, but some affect
   1171   // others. Rather than read the whole file in and then query them in an
   1172   // order that allows us to handle that, we read the settings in whatever
   1173   // order they occur and do any necessary tweaking after we finish.
   1174   void ResolveModeEffects() {
   1175     if (indirect_manual_) {
   1176       ResolveIndirect(PROXY_HTTP_HOST);
   1177       ResolveIndirect(PROXY_HTTPS_HOST);
   1178       ResolveIndirect(PROXY_FTP_HOST);
   1179       ResolveIndirectList(PROXY_IGNORE_HOSTS);
   1180     }
   1181     if (auto_no_pac_) {
   1182       // Remove the PAC URL; we're not supposed to use it.
   1183       string_table_.erase(PROXY_AUTOCONF_URL);
   1184     }
   1185   }
   1186 
   1187   // Reads kioslaverc one line at a time and calls AddKDESetting() to add
   1188   // each relevant name-value pair to the appropriate value table.
   1189   void UpdateCachedSettings() {
   1190     base::FilePath kioslaverc = kde_config_dir_.Append("kioslaverc");
   1191     base::ScopedFILE input(base::OpenFile(kioslaverc, "r"));
   1192     if (!input.get())
   1193       return;
   1194     ResetCachedSettings();
   1195     bool in_proxy_settings = false;
   1196     bool line_too_long = false;
   1197     char line[BUFFER_SIZE];
   1198     // fgets() will return NULL on EOF or error.
   1199     while (fgets(line, sizeof(line), input.get())) {
   1200       // fgets() guarantees the line will be properly terminated.
   1201       size_t length = strlen(line);
   1202       if (!length)
   1203         continue;
   1204       // This should be true even with CRLF endings.
   1205       if (line[length - 1] != '\n') {
   1206         line_too_long = true;
   1207         continue;
   1208       }
   1209       if (line_too_long) {
   1210         // The previous line had no line ending, but this done does. This is
   1211         // the end of the line that was too long, so warn here and skip it.
   1212         LOG(WARNING) << "skipped very long line in " << kioslaverc.value();
   1213         line_too_long = false;
   1214         continue;
   1215       }
   1216       // Remove the LF at the end, and the CR if there is one.
   1217       line[--length] = '\0';
   1218       if (length && line[length - 1] == '\r')
   1219         line[--length] = '\0';
   1220       // Now parse the line.
   1221       if (line[0] == '[') {
   1222         // Switching sections. All we care about is whether this is
   1223         // the (a?) proxy settings section, for both KDE3 and KDE4.
   1224         in_proxy_settings = !strncmp(line, "[Proxy Settings]", 16);
   1225       } else if (in_proxy_settings) {
   1226         // A regular line, in the (a?) proxy settings section.
   1227         char* split = strchr(line, '=');
   1228         // Skip this line if it does not contain an = sign.
   1229         if (!split)
   1230           continue;
   1231         // Split the line on the = and advance |split|.
   1232         *(split++) = 0;
   1233         std::string key = line;
   1234         std::string value = split;
   1235         base::TrimWhitespaceASCII(key, base::TRIM_ALL, &key);
   1236         base::TrimWhitespaceASCII(value, base::TRIM_ALL, &value);
   1237         // Skip this line if the key name is empty.
   1238         if (key.empty())
   1239           continue;
   1240         // Is the value name localized?
   1241         if (key[key.length() - 1] == ']') {
   1242           // Find the matching bracket.
   1243           length = key.rfind('[');
   1244           // Skip this line if the localization indicator is malformed.
   1245           if (length == std::string::npos)
   1246             continue;
   1247           // Trim the localization indicator off.
   1248           key.resize(length);
   1249           // Remove any resulting trailing whitespace.
   1250           base::TrimWhitespaceASCII(key, base::TRIM_TRAILING, &key);
   1251           // Skip this line if the key name is now empty.
   1252           if (key.empty())
   1253             continue;
   1254         }
   1255         // Now fill in the tables.
   1256         AddKDESetting(key, value);
   1257       }
   1258     }
   1259     if (ferror(input.get()))
   1260       LOG(ERROR) << "error reading " << kioslaverc.value();
   1261     ResolveModeEffects();
   1262   }
   1263 
   1264   // This is the callback from the debounce timer.
   1265   void OnDebouncedNotification() {
   1266     DCHECK(file_task_runner_->BelongsToCurrentThread());
   1267     VLOG(1) << "inotify change notification for kioslaverc";
   1268     UpdateCachedSettings();
   1269     CHECK(notify_delegate_);
   1270     // Forward to a method on the proxy config service delegate object.
   1271     notify_delegate_->OnCheckProxyConfigSettings();
   1272   }
   1273 
   1274   // Called by OnFileCanReadWithoutBlocking() on the file thread. Reads
   1275   // from the inotify file descriptor and starts up a debounce timer if
   1276   // an event for kioslaverc is seen.
   1277   void OnChangeNotification() {
   1278     DCHECK_GE(inotify_fd_,  0);
   1279     DCHECK(file_task_runner_->BelongsToCurrentThread());
   1280     char event_buf[(sizeof(inotify_event) + NAME_MAX + 1) * 4];
   1281     bool kioslaverc_touched = false;
   1282     ssize_t r;
   1283     while ((r = read(inotify_fd_, event_buf, sizeof(event_buf))) > 0) {
   1284       // inotify returns variable-length structures, which is why we have
   1285       // this strange-looking loop instead of iterating through an array.
   1286       char* event_ptr = event_buf;
   1287       while (event_ptr < event_buf + r) {
   1288         inotify_event* event = reinterpret_cast<inotify_event*>(event_ptr);
   1289         // The kernel always feeds us whole events.
   1290         CHECK_LE(event_ptr + sizeof(inotify_event), event_buf + r);
   1291         CHECK_LE(event->name + event->len, event_buf + r);
   1292         if (!strcmp(event->name, "kioslaverc"))
   1293           kioslaverc_touched = true;
   1294         // Advance the pointer just past the end of the filename.
   1295         event_ptr = event->name + event->len;
   1296       }
   1297       // We keep reading even if |kioslaverc_touched| is true to drain the
   1298       // inotify event queue.
   1299     }
   1300     if (!r)
   1301       // Instead of returning -1 and setting errno to EINVAL if there is not
   1302       // enough buffer space, older kernels (< 2.6.21) return 0. Simulate the
   1303       // new behavior (EINVAL) so we can reuse the code below.
   1304       errno = EINVAL;
   1305     if (errno != EAGAIN) {
   1306       PLOG(WARNING) << "error reading inotify file descriptor";
   1307       if (errno == EINVAL) {
   1308         // Our buffer is not large enough to read the next event. This should
   1309         // not happen (because its size is calculated to always be sufficiently
   1310         // large), but if it does we'd warn continuously since |inotify_fd_|
   1311         // would be forever ready to read. Close it and stop watching instead.
   1312         LOG(ERROR) << "inotify failure; no longer watching kioslaverc!";
   1313         inotify_watcher_.StopWatchingFileDescriptor();
   1314         close(inotify_fd_);
   1315         inotify_fd_ = -1;
   1316       }
   1317     }
   1318     if (kioslaverc_touched) {
   1319       // We don't use Reset() because the timer may not yet be running.
   1320       // (In that case Stop() is a no-op.)
   1321       debounce_timer_.Stop();
   1322       debounce_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(
   1323           kDebounceTimeoutMilliseconds), this,
   1324           &SettingGetterImplKDE::OnDebouncedNotification);
   1325     }
   1326   }
   1327 
   1328   typedef std::map<StringSetting, std::string> string_map_type;
   1329   typedef std::map<StringListSetting,
   1330                    std::vector<std::string> > strings_map_type;
   1331 
   1332   int inotify_fd_;
   1333   base::MessagePumpLibevent::FileDescriptorWatcher inotify_watcher_;
   1334   ProxyConfigServiceLinux::Delegate* notify_delegate_;
   1335   base::OneShotTimer<SettingGetterImplKDE> debounce_timer_;
   1336   base::FilePath kde_config_dir_;
   1337   bool indirect_manual_;
   1338   bool auto_no_pac_;
   1339   bool reversed_bypass_list_;
   1340   // We don't own |env_var_getter_|.  It's safe to hold a pointer to it, since
   1341   // both it and us are owned by ProxyConfigServiceLinux::Delegate, and have the
   1342   // same lifetime.
   1343   base::Environment* env_var_getter_;
   1344 
   1345   // We cache these settings whenever we re-read the kioslaverc file.
   1346   string_map_type string_table_;
   1347   strings_map_type strings_table_;
   1348 
   1349   // Task runner of the file thread, for reading kioslaverc. If NULL,
   1350   // just read it directly (for testing). We also handle inotify events
   1351   // on this thread.
   1352   scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
   1353 
   1354   DISALLOW_COPY_AND_ASSIGN(SettingGetterImplKDE);
   1355 };
   1356 
   1357 }  // namespace
   1358 
   1359 bool ProxyConfigServiceLinux::Delegate::GetProxyFromSettings(
   1360     SettingGetter::StringSetting host_key,
   1361     ProxyServer* result_server) {
   1362   std::string host;
   1363   if (!setting_getter_->GetString(host_key, &host) || host.empty()) {
   1364     // Unset or empty.
   1365     return false;
   1366   }
   1367   // Check for an optional port.
   1368   int port = 0;
   1369   SettingGetter::IntSetting port_key =
   1370       SettingGetter::HostSettingToPortSetting(host_key);
   1371   setting_getter_->GetInt(port_key, &port);
   1372   if (port != 0) {
   1373     // If a port is set and non-zero:
   1374     host += ":" + base::IntToString(port);
   1375   }
   1376 
   1377   // gconf settings do not appear to distinguish between SOCKS version. We
   1378   // default to version 5. For more information on this policy decision, see:
   1379   // http://code.google.com/p/chromium/issues/detail?id=55912#c2
   1380   ProxyServer::Scheme scheme = (host_key == SettingGetter::PROXY_SOCKS_HOST) ?
   1381       ProxyServer::SCHEME_SOCKS5 : ProxyServer::SCHEME_HTTP;
   1382   host = FixupProxyHostScheme(scheme, host);
   1383   ProxyServer proxy_server = ProxyServer::FromURI(host,
   1384                                                   ProxyServer::SCHEME_HTTP);
   1385   if (proxy_server.is_valid()) {
   1386     *result_server = proxy_server;
   1387     return true;
   1388   }
   1389   return false;
   1390 }
   1391 
   1392 bool ProxyConfigServiceLinux::Delegate::GetConfigFromSettings(
   1393     ProxyConfig* config) {
   1394   std::string mode;
   1395   if (!setting_getter_->GetString(SettingGetter::PROXY_MODE, &mode)) {
   1396     // We expect this to always be set, so if we don't see it then we
   1397     // probably have a gconf/gsettings problem, and so we don't have a valid
   1398     // proxy config.
   1399     return false;
   1400   }
   1401   if (mode == "none") {
   1402     // Specifically specifies no proxy.
   1403     return true;
   1404   }
   1405 
   1406   if (mode == "auto") {
   1407     // Automatic proxy config.
   1408     std::string pac_url_str;
   1409     if (setting_getter_->GetString(SettingGetter::PROXY_AUTOCONF_URL,
   1410                                    &pac_url_str)) {
   1411       if (!pac_url_str.empty()) {
   1412         // If the PAC URL is actually a file path, then put file:// in front.
   1413         if (pac_url_str[0] == '/')
   1414           pac_url_str = "file://" + pac_url_str;
   1415         GURL pac_url(pac_url_str);
   1416         if (!pac_url.is_valid())
   1417           return false;
   1418         config->set_pac_url(pac_url);
   1419         return true;
   1420       }
   1421     }
   1422     config->set_auto_detect(true);
   1423     return true;
   1424   }
   1425 
   1426   if (mode != "manual") {
   1427     // Mode is unrecognized.
   1428     return false;
   1429   }
   1430   bool use_http_proxy;
   1431   if (setting_getter_->GetBool(SettingGetter::PROXY_USE_HTTP_PROXY,
   1432                                &use_http_proxy)
   1433       && !use_http_proxy) {
   1434     // Another master switch for some reason. If set to false, then no
   1435     // proxy. But we don't panic if the key doesn't exist.
   1436     return true;
   1437   }
   1438 
   1439   bool same_proxy = false;
   1440   // Indicates to use the http proxy for all protocols. This one may
   1441   // not exist (presumably on older versions); we assume false in that
   1442   // case.
   1443   setting_getter_->GetBool(SettingGetter::PROXY_USE_SAME_PROXY,
   1444                            &same_proxy);
   1445 
   1446   ProxyServer proxy_for_http;
   1447   ProxyServer proxy_for_https;
   1448   ProxyServer proxy_for_ftp;
   1449   ProxyServer socks_proxy;  // (socks)
   1450 
   1451   // This counts how many of the above ProxyServers were defined and valid.
   1452   size_t num_proxies_specified = 0;
   1453 
   1454   // Extract the per-scheme proxies. If we failed to parse it, or no proxy was
   1455   // specified for the scheme, then the resulting ProxyServer will be invalid.
   1456   if (GetProxyFromSettings(SettingGetter::PROXY_HTTP_HOST, &proxy_for_http))
   1457     num_proxies_specified++;
   1458   if (GetProxyFromSettings(SettingGetter::PROXY_HTTPS_HOST, &proxy_for_https))
   1459     num_proxies_specified++;
   1460   if (GetProxyFromSettings(SettingGetter::PROXY_FTP_HOST, &proxy_for_ftp))
   1461     num_proxies_specified++;
   1462   if (GetProxyFromSettings(SettingGetter::PROXY_SOCKS_HOST, &socks_proxy))
   1463     num_proxies_specified++;
   1464 
   1465   if (same_proxy) {
   1466     if (proxy_for_http.is_valid()) {
   1467       // Use the http proxy for all schemes.
   1468       config->proxy_rules().type = ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY;
   1469       config->proxy_rules().single_proxies.SetSingleProxyServer(proxy_for_http);
   1470     }
   1471   } else if (num_proxies_specified > 0) {
   1472     if (socks_proxy.is_valid() && num_proxies_specified == 1) {
   1473       // If the only proxy specified was for SOCKS, use it for all schemes.
   1474       config->proxy_rules().type = ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY;
   1475       config->proxy_rules().single_proxies.SetSingleProxyServer(socks_proxy);
   1476     } else {
   1477       // Otherwise use the indicated proxies per-scheme.
   1478       config->proxy_rules().type =
   1479           ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
   1480       config->proxy_rules().proxies_for_http.
   1481           SetSingleProxyServer(proxy_for_http);
   1482       config->proxy_rules().proxies_for_https.
   1483           SetSingleProxyServer(proxy_for_https);
   1484       config->proxy_rules().proxies_for_ftp.SetSingleProxyServer(proxy_for_ftp);
   1485       config->proxy_rules().fallback_proxies.SetSingleProxyServer(socks_proxy);
   1486     }
   1487   }
   1488 
   1489   if (config->proxy_rules().empty()) {
   1490     // Manual mode but we couldn't parse any rules.
   1491     return false;
   1492   }
   1493 
   1494   // Check for authentication, just so we can warn.
   1495   bool use_auth = false;
   1496   setting_getter_->GetBool(SettingGetter::PROXY_USE_AUTHENTICATION,
   1497                            &use_auth);
   1498   if (use_auth) {
   1499     // ProxyConfig does not support authentication parameters, but
   1500     // Chrome will prompt for the password later. So we ignore
   1501     // /system/http_proxy/*auth* settings.
   1502     LOG(WARNING) << "Proxy authentication parameters ignored, see bug 16709";
   1503   }
   1504 
   1505   // Now the bypass list.
   1506   std::vector<std::string> ignore_hosts_list;
   1507   config->proxy_rules().bypass_rules.Clear();
   1508   if (setting_getter_->GetStringList(SettingGetter::PROXY_IGNORE_HOSTS,
   1509                                      &ignore_hosts_list)) {
   1510     std::vector<std::string>::const_iterator it(ignore_hosts_list.begin());
   1511     for (; it != ignore_hosts_list.end(); ++it) {
   1512       if (setting_getter_->MatchHostsUsingSuffixMatching()) {
   1513         config->proxy_rules().bypass_rules.
   1514             AddRuleFromStringUsingSuffixMatching(*it);
   1515       } else {
   1516         config->proxy_rules().bypass_rules.AddRuleFromString(*it);
   1517       }
   1518     }
   1519   }
   1520   // Note that there are no settings with semantics corresponding to
   1521   // bypass of local names in GNOME. In KDE, "<local>" is supported
   1522   // as a hostname rule.
   1523 
   1524   // KDE allows one to reverse the bypass rules.
   1525   config->proxy_rules().reverse_bypass =
   1526       setting_getter_->BypassListIsReversed();
   1527 
   1528   return true;
   1529 }
   1530 
   1531 ProxyConfigServiceLinux::Delegate::Delegate(base::Environment* env_var_getter)
   1532     : env_var_getter_(env_var_getter) {
   1533   // Figure out which SettingGetterImpl to use, if any.
   1534   switch (base::nix::GetDesktopEnvironment(env_var_getter)) {
   1535     case base::nix::DESKTOP_ENVIRONMENT_GNOME:
   1536     case base::nix::DESKTOP_ENVIRONMENT_UNITY:
   1537 #if defined(USE_GIO)
   1538       {
   1539         scoped_ptr<SettingGetterImplGSettings> gs_getter(
   1540             new SettingGetterImplGSettings());
   1541         // We have to load symbols and check the GNOME version in use to decide
   1542         // if we should use the gsettings getter. See LoadAndCheckVersion().
   1543         if (gs_getter->LoadAndCheckVersion(env_var_getter))
   1544           setting_getter_.reset(gs_getter.release());
   1545       }
   1546 #endif
   1547 #if defined(USE_GCONF)
   1548       // Fall back on gconf if gsettings is unavailable or incorrect.
   1549       if (!setting_getter_.get())
   1550         setting_getter_.reset(new SettingGetterImplGConf());
   1551 #endif
   1552       break;
   1553     case base::nix::DESKTOP_ENVIRONMENT_KDE3:
   1554     case base::nix::DESKTOP_ENVIRONMENT_KDE4:
   1555       setting_getter_.reset(new SettingGetterImplKDE(env_var_getter));
   1556       break;
   1557     case base::nix::DESKTOP_ENVIRONMENT_XFCE:
   1558     case base::nix::DESKTOP_ENVIRONMENT_OTHER:
   1559       break;
   1560   }
   1561 }
   1562 
   1563 ProxyConfigServiceLinux::Delegate::Delegate(
   1564     base::Environment* env_var_getter, SettingGetter* setting_getter)
   1565     : env_var_getter_(env_var_getter), setting_getter_(setting_getter) {
   1566 }
   1567 
   1568 void ProxyConfigServiceLinux::Delegate::SetUpAndFetchInitialConfig(
   1569     const scoped_refptr<base::SingleThreadTaskRunner>& glib_task_runner,
   1570     const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
   1571     const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner) {
   1572   // We should be running on the default glib main loop thread right
   1573   // now. gconf can only be accessed from this thread.
   1574   DCHECK(glib_task_runner->BelongsToCurrentThread());
   1575   glib_task_runner_ = glib_task_runner;
   1576   io_task_runner_ = io_task_runner;
   1577 
   1578   // If we are passed a NULL |io_task_runner| or |file_task_runner|, then we
   1579   // don't set up proxy setting change notifications. This should not be the
   1580   // usual case but is intended to/ simplify test setups.
   1581   if (!io_task_runner_.get() || !file_task_runner.get())
   1582     VLOG(1) << "Monitoring of proxy setting changes is disabled";
   1583 
   1584   // Fetch and cache the current proxy config. The config is left in
   1585   // cached_config_, where GetLatestProxyConfig() running on the IO thread
   1586   // will expect to find it. This is safe to do because we return
   1587   // before this ProxyConfigServiceLinux is passed on to
   1588   // the ProxyService.
   1589 
   1590   // Note: It would be nice to prioritize environment variables
   1591   // and only fall back to gconf if env vars were unset. But
   1592   // gnome-terminal "helpfully" sets http_proxy and no_proxy, and it
   1593   // does so even if the proxy mode is set to auto, which would
   1594   // mislead us.
   1595 
   1596   bool got_config = false;
   1597   if (setting_getter_.get() &&
   1598       setting_getter_->Init(glib_task_runner, file_task_runner) &&
   1599       GetConfigFromSettings(&cached_config_)) {
   1600     cached_config_.set_id(1);  // Mark it as valid.
   1601     cached_config_.set_source(setting_getter_->GetConfigSource());
   1602     VLOG(1) << "Obtained proxy settings from "
   1603             << ProxyConfigSourceToString(cached_config_.source());
   1604 
   1605     // If gconf proxy mode is "none", meaning direct, then we take
   1606     // that to be a valid config and will not check environment
   1607     // variables. The alternative would have been to look for a proxy
   1608     // whereever we can find one.
   1609     got_config = true;
   1610 
   1611     // Keep a copy of the config for use from this thread for
   1612     // comparison with updated settings when we get notifications.
   1613     reference_config_ = cached_config_;
   1614     reference_config_.set_id(1);  // Mark it as valid.
   1615 
   1616     // We only set up notifications if we have IO and file loops available.
   1617     // We do this after getting the initial configuration so that we don't have
   1618     // to worry about cancelling it if the initial fetch above fails. Note that
   1619     // setting up notifications has the side effect of simulating a change, so
   1620     // that we won't lose any updates that may have happened after the initial
   1621     // fetch and before setting up notifications. We'll detect the common case
   1622     // of no changes in OnCheckProxyConfigSettings() (or sooner) and ignore it.
   1623     if (io_task_runner.get() && file_task_runner.get()) {
   1624       scoped_refptr<base::SingleThreadTaskRunner> required_loop =
   1625           setting_getter_->GetNotificationTaskRunner();
   1626       if (!required_loop.get() || required_loop->BelongsToCurrentThread()) {
   1627         // In this case we are already on an acceptable thread.
   1628         SetUpNotifications();
   1629       } else {
   1630         // Post a task to set up notifications. We don't wait for success.
   1631         required_loop->PostTask(FROM_HERE, base::Bind(
   1632             &ProxyConfigServiceLinux::Delegate::SetUpNotifications, this));
   1633       }
   1634     }
   1635   }
   1636 
   1637   if (!got_config) {
   1638     // We fall back on environment variables.
   1639     //
   1640     // Consulting environment variables doesn't need to be done from the
   1641     // default glib main loop, but it's a tiny enough amount of work.
   1642     if (GetConfigFromEnv(&cached_config_)) {
   1643       cached_config_.set_source(PROXY_CONFIG_SOURCE_ENV);
   1644       cached_config_.set_id(1);  // Mark it as valid.
   1645       VLOG(1) << "Obtained proxy settings from environment variables";
   1646     }
   1647   }
   1648 }
   1649 
   1650 // Depending on the SettingGetter in use, this method will be called
   1651 // on either the UI thread (GConf) or the file thread (KDE).
   1652 void ProxyConfigServiceLinux::Delegate::SetUpNotifications() {
   1653   scoped_refptr<base::SingleThreadTaskRunner> required_loop =
   1654       setting_getter_->GetNotificationTaskRunner();
   1655   DCHECK(!required_loop.get() || required_loop->BelongsToCurrentThread());
   1656   if (!setting_getter_->SetUpNotifications(this))
   1657     LOG(ERROR) << "Unable to set up proxy configuration change notifications";
   1658 }
   1659 
   1660 void ProxyConfigServiceLinux::Delegate::AddObserver(Observer* observer) {
   1661   observers_.AddObserver(observer);
   1662 }
   1663 
   1664 void ProxyConfigServiceLinux::Delegate::RemoveObserver(Observer* observer) {
   1665   observers_.RemoveObserver(observer);
   1666 }
   1667 
   1668 ProxyConfigService::ConfigAvailability
   1669     ProxyConfigServiceLinux::Delegate::GetLatestProxyConfig(
   1670         ProxyConfig* config) {
   1671   // This is called from the IO thread.
   1672   DCHECK(!io_task_runner_.get() ||
   1673          io_task_runner_->BelongsToCurrentThread());
   1674 
   1675   // Simply return the last proxy configuration that glib_default_loop
   1676   // notified us of.
   1677   if (cached_config_.is_valid()) {
   1678     *config = cached_config_;
   1679   } else {
   1680     *config = ProxyConfig::CreateDirect();
   1681     config->set_source(PROXY_CONFIG_SOURCE_SYSTEM_FAILED);
   1682   }
   1683 
   1684   // We return CONFIG_VALID to indicate that *config was filled in. It is always
   1685   // going to be available since we initialized eagerly on the UI thread.
   1686   // TODO(eroman): do lazy initialization instead, so we no longer need
   1687   //               to construct ProxyConfigServiceLinux on the UI thread.
   1688   //               In which case, we may return false here.
   1689   return CONFIG_VALID;
   1690 }
   1691 
   1692 // Depending on the SettingGetter in use, this method will be called
   1693 // on either the UI thread (GConf) or the file thread (KDE).
   1694 void ProxyConfigServiceLinux::Delegate::OnCheckProxyConfigSettings() {
   1695   scoped_refptr<base::SingleThreadTaskRunner> required_loop =
   1696       setting_getter_->GetNotificationTaskRunner();
   1697   DCHECK(!required_loop.get() || required_loop->BelongsToCurrentThread());
   1698   ProxyConfig new_config;
   1699   bool valid = GetConfigFromSettings(&new_config);
   1700   if (valid)
   1701     new_config.set_id(1);  // mark it as valid
   1702 
   1703   // See if it is different from what we had before.
   1704   if (new_config.is_valid() != reference_config_.is_valid() ||
   1705       !new_config.Equals(reference_config_)) {
   1706     // Post a task to the IO thread with the new configuration, so it can
   1707     // update |cached_config_|.
   1708     io_task_runner_->PostTask(FROM_HERE, base::Bind(
   1709         &ProxyConfigServiceLinux::Delegate::SetNewProxyConfig,
   1710         this, new_config));
   1711     // Update the thread-private copy in |reference_config_| as well.
   1712     reference_config_ = new_config;
   1713   } else {
   1714     VLOG(1) << "Detected no-op change to proxy settings. Doing nothing.";
   1715   }
   1716 }
   1717 
   1718 void ProxyConfigServiceLinux::Delegate::SetNewProxyConfig(
   1719     const ProxyConfig& new_config) {
   1720   DCHECK(io_task_runner_->BelongsToCurrentThread());
   1721   VLOG(1) << "Proxy configuration changed";
   1722   cached_config_ = new_config;
   1723   FOR_EACH_OBSERVER(
   1724       Observer, observers_,
   1725       OnProxyConfigChanged(new_config, ProxyConfigService::CONFIG_VALID));
   1726 }
   1727 
   1728 void ProxyConfigServiceLinux::Delegate::PostDestroyTask() {
   1729   if (!setting_getter_.get())
   1730     return;
   1731   scoped_refptr<base::SingleThreadTaskRunner> shutdown_loop =
   1732       setting_getter_->GetNotificationTaskRunner();
   1733   if (!shutdown_loop.get() || shutdown_loop->BelongsToCurrentThread()) {
   1734     // Already on the right thread, call directly.
   1735     // This is the case for the unittests.
   1736     OnDestroy();
   1737   } else {
   1738     // Post to shutdown thread. Note that on browser shutdown, we may quit
   1739     // this MessageLoop and exit the program before ever running this.
   1740     shutdown_loop->PostTask(FROM_HERE, base::Bind(
   1741         &ProxyConfigServiceLinux::Delegate::OnDestroy, this));
   1742   }
   1743 }
   1744 void ProxyConfigServiceLinux::Delegate::OnDestroy() {
   1745   scoped_refptr<base::SingleThreadTaskRunner> shutdown_loop =
   1746       setting_getter_->GetNotificationTaskRunner();
   1747   DCHECK(!shutdown_loop.get() || shutdown_loop->BelongsToCurrentThread());
   1748   setting_getter_->ShutDown();
   1749 }
   1750 
   1751 ProxyConfigServiceLinux::ProxyConfigServiceLinux()
   1752     : delegate_(new Delegate(base::Environment::Create())) {
   1753 }
   1754 
   1755 ProxyConfigServiceLinux::~ProxyConfigServiceLinux() {
   1756   delegate_->PostDestroyTask();
   1757 }
   1758 
   1759 ProxyConfigServiceLinux::ProxyConfigServiceLinux(
   1760     base::Environment* env_var_getter)
   1761     : delegate_(new Delegate(env_var_getter)) {
   1762 }
   1763 
   1764 ProxyConfigServiceLinux::ProxyConfigServiceLinux(
   1765     base::Environment* env_var_getter, SettingGetter* setting_getter)
   1766     : delegate_(new Delegate(env_var_getter, setting_getter)) {
   1767 }
   1768 
   1769 void ProxyConfigServiceLinux::AddObserver(Observer* observer) {
   1770   delegate_->AddObserver(observer);
   1771 }
   1772 
   1773 void ProxyConfigServiceLinux::RemoveObserver(Observer* observer) {
   1774   delegate_->RemoveObserver(observer);
   1775 }
   1776 
   1777 ProxyConfigService::ConfigAvailability
   1778     ProxyConfigServiceLinux::GetLatestProxyConfig(ProxyConfig* config) {
   1779   return delegate_->GetLatestProxyConfig(config);
   1780 }
   1781 
   1782 }  // namespace net
   1783