Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(147)

Side by Side Diff: net/proxy/proxy_config_service_linux.cc

Issue 113043: Fix gconf for the linux proxy config service.... (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: '' Created 11 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/proxy/proxy_config_service_linux.h" 5 #include "net/proxy/proxy_config_service_linux.h"
6 6
7 #include <gconf/gconf-client.h> 7 #include <gconf/gconf-client.h>
8 #include <gdk/gdk.h>
9 #include <stdlib.h> 8 #include <stdlib.h>
10 9
11 #include "base/logging.h" 10 #include "base/logging.h"
12 #include "base/string_tokenizer.h" 11 #include "base/string_tokenizer.h"
13 #include "base/string_util.h" 12 #include "base/string_util.h"
13 #include "base/task.h"
14 #include "googleurl/src/url_canon.h" 14 #include "googleurl/src/url_canon.h"
15 #include "net/base/net_errors.h" 15 #include "net/base/net_errors.h"
16 #include "net/http/http_util.h" 16 #include "net/http/http_util.h"
17 #include "net/proxy/proxy_config.h" 17 #include "net/proxy/proxy_config.h"
18 #include "net/proxy/proxy_server.h" 18 #include "net/proxy/proxy_server.h"
19 19
20 namespace net { 20 namespace net {
21 21
22 namespace { 22 namespace {
23 23
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
64 scheme = ProxyServer::SCHEME_SOCKS5; 64 scheme = ProxyServer::SCHEME_SOCKS5;
65 } 65 }
66 // Strip the scheme if any. 66 // Strip the scheme if any.
67 std::string::size_type colon = host.find("://"); 67 std::string::size_type colon = host.find("://");
68 if (colon != std::string::npos) 68 if (colon != std::string::npos)
69 host = host.substr(colon + 3); 69 host = host.substr(colon + 3);
70 // If a username and perhaps password are specified, give a warning. 70 // If a username and perhaps password are specified, give a warning.
71 std::string::size_type at_sign = host.find("@"); 71 std::string::size_type at_sign = host.find("@");
72 // Should this be supported? 72 // Should this be supported?
73 if (at_sign != std::string::npos) { 73 if (at_sign != std::string::npos) {
74 LOG(ERROR) << "ProxyConfigServiceLinux: proxy authentication " 74 LOG(ERROR) << "Proxy authentication not supported";
75 "not supported";
76 // Disregard the authentication parameters and continue with this hostname. 75 // Disregard the authentication parameters and continue with this hostname.
77 host = host.substr(at_sign + 1); 76 host = host.substr(at_sign + 1);
78 } 77 }
79 // If this is a socks proxy, prepend a scheme so as to tell 78 // If this is a socks proxy, prepend a scheme so as to tell
80 // ProxyServer. This also allows ProxyServer to choose the right 79 // ProxyServer. This also allows ProxyServer to choose the right
81 // default port. 80 // default port.
82 if (scheme == ProxyServer::SCHEME_SOCKS4) 81 if (scheme == ProxyServer::SCHEME_SOCKS4)
83 host = "socks4://" + host; 82 host = "socks4://" + host;
84 else if (scheme == ProxyServer::SCHEME_SOCKS5) 83 else if (scheme == ProxyServer::SCHEME_SOCKS5)
85 host = "socks5://" + host; 84 host = "socks5://" + host;
86 return host; 85 return host;
87 } 86 }
88 87
89 } // namespace 88 } // namespace
90 89
91 bool ProxyConfigServiceLinux::GetProxyFromEnvVarForScheme( 90 bool ProxyConfigServiceLinux::Delegate::GetProxyFromEnvVarForScheme(
92 const char* variable, ProxyServer::Scheme scheme, 91 const char* variable, ProxyServer::Scheme scheme,
93 ProxyServer* result_server) { 92 ProxyServer* result_server) {
94 std::string env_value; 93 std::string env_value;
95 if (env_var_getter_->Getenv(variable, &env_value)) { 94 if (env_var_getter_->Getenv(variable, &env_value)) {
96 if (!env_value.empty()) { 95 if (!env_value.empty()) {
97 env_value = FixupProxyHostScheme(scheme, env_value); 96 env_value = FixupProxyHostScheme(scheme, env_value);
98 ProxyServer proxy_server = ProxyServer::FromURI(env_value); 97 ProxyServer proxy_server = ProxyServer::FromURI(env_value);
99 if (proxy_server.is_valid() && !proxy_server.is_direct()) { 98 if (proxy_server.is_valid() && !proxy_server.is_direct()) {
100 *result_server = proxy_server; 99 *result_server = proxy_server;
101 return true; 100 return true;
102 } else { 101 } else {
103 LOG(ERROR) << "ProxyConfigServiceLinux: failed to parse " 102 LOG(ERROR) << "Failed to parse environment variable " << variable;
104 << "environment variable " << variable;
105 } 103 }
106 } 104 }
107 } 105 }
108 return false; 106 return false;
109 } 107 }
110 108
111 bool ProxyConfigServiceLinux::GetProxyFromEnvVar( 109 bool ProxyConfigServiceLinux::Delegate::GetProxyFromEnvVar(
112 const char* variable, ProxyServer* result_server) { 110 const char* variable, ProxyServer* result_server) {
113 return GetProxyFromEnvVarForScheme(variable, ProxyServer::SCHEME_HTTP, 111 return GetProxyFromEnvVarForScheme(variable, ProxyServer::SCHEME_HTTP,
114 result_server); 112 result_server);
115 } 113 }
116 114
117 bool ProxyConfigServiceLinux::GetConfigFromEnv(ProxyConfig* config) { 115 bool ProxyConfigServiceLinux::Delegate::GetConfigFromEnv(ProxyConfig* config) {
118 // Check for automatic configuration first, in 116 // Check for automatic configuration first, in
119 // "auto_proxy". Possibly only the "environment_proxy" firefox 117 // "auto_proxy". Possibly only the "environment_proxy" firefox
120 // extension has ever used this, but it still sounds like a good 118 // extension has ever used this, but it still sounds like a good
121 // idea. 119 // idea.
122 std::string auto_proxy; 120 std::string auto_proxy;
123 if (env_var_getter_->Getenv("auto_proxy", &auto_proxy)) { 121 if (env_var_getter_->Getenv("auto_proxy", &auto_proxy)) {
124 if (auto_proxy.empty()) { 122 if (auto_proxy.empty()) {
125 // Defined and empty => autodetect 123 // Defined and empty => autodetect
126 config->auto_detect = true; 124 config->auto_detect = true;
127 } else { 125 } else {
(...skipping 25 matching lines...) Expand all
153 if (have_http || have_https || have_ftp) { 151 if (have_http || have_https || have_ftp) {
154 // mustn't change type unless some rules are actually set. 152 // mustn't change type unless some rules are actually set.
155 config->proxy_rules.type = ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME; 153 config->proxy_rules.type = ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
156 } 154 }
157 } 155 }
158 if (config->proxy_rules.empty()) { 156 if (config->proxy_rules.empty()) {
159 // If the above were not defined, try for socks. 157 // If the above were not defined, try for socks.
160 ProxyServer::Scheme scheme = ProxyServer::SCHEME_SOCKS4; 158 ProxyServer::Scheme scheme = ProxyServer::SCHEME_SOCKS4;
161 std::string env_version; 159 std::string env_version;
162 if (env_var_getter_->Getenv("SOCKS_VERSION", &env_version) 160 if (env_var_getter_->Getenv("SOCKS_VERSION", &env_version)
163 && env_version.compare("5") == 0) 161 && env_version == "5")
164 scheme = ProxyServer::SCHEME_SOCKS5; 162 scheme = ProxyServer::SCHEME_SOCKS5;
165 if (GetProxyFromEnvVarForScheme("SOCKS_SERVER", scheme, &proxy_server)) { 163 if (GetProxyFromEnvVarForScheme("SOCKS_SERVER", scheme, &proxy_server)) {
166 config->proxy_rules.type = ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY; 164 config->proxy_rules.type = ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY;
167 config->proxy_rules.single_proxy = proxy_server; 165 config->proxy_rules.single_proxy = proxy_server;
168 } 166 }
169 } 167 }
170 // Look for the proxy bypass list. 168 // Look for the proxy bypass list.
171 std::string no_proxy; 169 std::string no_proxy;
172 env_var_getter_->Getenv("no_proxy", &no_proxy); 170 env_var_getter_->Getenv("no_proxy", &no_proxy);
173 if (config->proxy_rules.empty()) { 171 if (config->proxy_rules.empty()) {
174 // Having only "no_proxy" set, presumably to "*", makes it 172 // Having only "no_proxy" set, presumably to "*", makes it
175 // explicit that env vars do specify a configuration: having no 173 // explicit that env vars do specify a configuration: having no
176 // rules specified only means the user explicitly asks for direct 174 // rules specified only means the user explicitly asks for direct
177 // connections. 175 // connections.
178 return !no_proxy.empty(); 176 return !no_proxy.empty();
179 } 177 }
180 config->ParseNoProxyList(no_proxy); 178 config->ParseNoProxyList(no_proxy);
181 return true; 179 return true;
182 } 180 }
183 181
184 namespace { 182 namespace {
185 183
184 // static
185 // gconf notification callback, dispatched from the default
186 // glib main loop.
187 void OnGConfChangeNotification(
188 GConfClient* client, guint cnxn_id,
189 GConfEntry* entry, gpointer user_data) {
190 // It would be nice to debounce multiple callbacks in quick
191 // succession, since I guess we'll get one for each changed key. As
192 // it is we will read settings from gconf once for each callback.
193 LOG(INFO) << "gconf change notification for key "
194 << gconf_entry_get_key(entry);
195 // We don't track which key has changed, just that something did change.
196 // Forward to a method on the proxy config service delegate object.
197 ProxyConfigServiceLinux::Delegate* config_service_delegate =
198 reinterpret_cast<ProxyConfigServiceLinux::Delegate*>(user_data);
199 config_service_delegate->OnCheckProxyConfigSettings();
200 }
201
186 class GConfSettingGetterImpl 202 class GConfSettingGetterImpl
187 : public ProxyConfigServiceLinux::GConfSettingGetter { 203 : public ProxyConfigServiceLinux::GConfSettingGetter {
188 public: 204 public:
189 GConfSettingGetterImpl() : client_(NULL) {} 205 GConfSettingGetterImpl() : client_(NULL), loop_(NULL) {}
206
190 virtual ~GConfSettingGetterImpl() { 207 virtual ~GConfSettingGetterImpl() {
191 if (client_) 208 LOG(INFO) << "~GConfSettingGetterImpl called";
192 g_object_unref(client_); 209 // client_ should have been released before now, from
210 // Delegate::OnDestroy(), while running on the UI thread.
211 DCHECK(!client_);
193 } 212 }
194 213
195 virtual void Enter() { 214 virtual bool Init() {
196 gdk_threads_enter(); 215 DCHECK(!client_);
197 } 216 DCHECK(!loop_);
198 virtual void Leave() { 217 loop_ = MessageLoopForUI::current();
199 gdk_threads_leave(); 218 client_ = gconf_client_get_default();
219 if (!client_) {
220 // It's not clear whether/when this can return NULL.
221 LOG(ERROR) << "Unable to create a gconf client";
222 loop_ = NULL;
223 return false;
224 }
225 GError* error = NULL;
226 // We need to add the directories for which we'll be asking
227 // notifications, and we might as well ask to preload them.
228 gconf_client_add_dir(client_, "/system/proxy",
229 GCONF_CLIENT_PRELOAD_ONELEVEL, &error);
230 if (error == NULL) {
231 gconf_client_add_dir(client_, "/system/http_proxy",
232 GCONF_CLIENT_PRELOAD_ONELEVEL, &error);
233 }
234 if (error != NULL) {
235 LOG(ERROR) << "Error requesting gconf directory: " << error->message;
236 g_error_free(error);
237 Release();
238 return false;
239 }
240 return true;
200 } 241 }
201 242
202 virtual bool InitIfNeeded() { 243 void Release() {
203 if (!client_) { 244 if (client_) {
204 Enter(); 245 DCHECK(MessageLoop::current() == loop_);
205 client_ = gconf_client_get_default(); 246 // This also disables gconf notifications.
206 Leave(); 247 g_object_unref(client_);
207 // It's not clear whether/when this can return NULL. 248 client_ = NULL;
208 if (!client_) 249 loop_ = NULL;
209 LOG(ERROR) << "ProxyConfigServiceLinux: Unable to create "
210 "a gconf client";
211 } 250 }
212 return client_ != NULL; 251 }
252
253 bool SetupNotification(void* callback_user_data) {
254 DCHECK(client_);
255 DCHECK(MessageLoop::current() == loop_);
256 GError* error = NULL;
257 gconf_client_notify_add(
258 client_, "/system/proxy",
259 OnGConfChangeNotification, callback_user_data,
260 NULL, &error);
261 if (error == NULL) {
262 gconf_client_notify_add(
263 client_, "/system/http_proxy",
264 OnGConfChangeNotification, callback_user_data,
265 NULL, &error);
266 }
267 if (error != NULL) {
268 LOG(ERROR) << "Error requesting gconf notifications: " << error->message;
269 g_error_free(error);
270 Release();
271 return false;
272 }
273 return true;
213 } 274 }
214 275
215 virtual bool GetString(const char* key, std::string* result) { 276 virtual bool GetString(const char* key, std::string* result) {
216 CHECK(client_); 277 DCHECK(client_);
278 DCHECK(MessageLoop::current() == loop_);
217 GError* error = NULL; 279 GError* error = NULL;
218 gchar* value = gconf_client_get_string(client_, key, &error); 280 gchar* value = gconf_client_get_string(client_, key, &error);
219 if (HandleGError(error, key)) 281 if (HandleGError(error, key))
220 return false; 282 return false;
221 if (!value) 283 if (!value)
222 return false; 284 return false;
223 *result = value; 285 *result = value;
224 g_free(value); 286 g_free(value);
225 return true; 287 return true;
226 } 288 }
227 virtual bool GetBoolean(const char* key, bool* result) { 289 virtual bool GetBoolean(const char* key, bool* result) {
228 CHECK(client_); 290 DCHECK(client_);
291 DCHECK(MessageLoop::current() == loop_);
229 GError* error = NULL; 292 GError* error = NULL;
230 // We want to distinguish unset values from values defaulting to 293 // We want to distinguish unset values from values defaulting to
231 // false. For that we need to use the type-generic 294 // false. For that we need to use the type-generic
232 // gconf_client_get() rather than gconf_client_get_bool(). 295 // gconf_client_get() rather than gconf_client_get_bool().
233 GConfValue* gconf_value = gconf_client_get(client_, key, &error); 296 GConfValue* gconf_value = gconf_client_get(client_, key, &error);
234 if (HandleGError(error, key)) 297 if (HandleGError(error, key))
235 return false; 298 return false;
236 if (!gconf_value) { 299 if (!gconf_value) {
237 // Unset. 300 // Unset.
238 return false; 301 return false;
239 } 302 }
240 if (gconf_value->type != GCONF_VALUE_BOOL) { 303 if (gconf_value->type != GCONF_VALUE_BOOL) {
241 gconf_value_free(gconf_value); 304 gconf_value_free(gconf_value);
242 return false; 305 return false;
243 } 306 }
244 gboolean bool_value = gconf_value_get_bool(gconf_value); 307 gboolean bool_value = gconf_value_get_bool(gconf_value);
245 *result = static_cast<bool>(bool_value); 308 *result = static_cast<bool>(bool_value);
246 gconf_value_free(gconf_value); 309 gconf_value_free(gconf_value);
247 return true; 310 return true;
248 } 311 }
249 virtual bool GetInt(const char* key, int* result) { 312 virtual bool GetInt(const char* key, int* result) {
250 CHECK(client_); 313 DCHECK(client_);
314 DCHECK(MessageLoop::current() == loop_);
251 GError* error = NULL; 315 GError* error = NULL;
252 int value = gconf_client_get_int(client_, key, &error); 316 int value = gconf_client_get_int(client_, key, &error);
253 if (HandleGError(error, key)) 317 if (HandleGError(error, key))
254 return false; 318 return false;
255 // We don't bother to distinguish an unset value because callers 319 // We don't bother to distinguish an unset value because callers
256 // don't care. 0 is returned if unset. 320 // don't care. 0 is returned if unset.
257 *result = value; 321 *result = value;
258 return true; 322 return true;
259 } 323 }
260 virtual bool GetStringList(const char* key, 324 virtual bool GetStringList(const char* key,
261 std::vector<std::string>* result) { 325 std::vector<std::string>* result) {
262 CHECK(client_); 326 DCHECK(client_);
327 DCHECK(MessageLoop::current() == loop_);
263 GError* error = NULL; 328 GError* error = NULL;
264 GSList* list = gconf_client_get_list(client_, key, 329 GSList* list = gconf_client_get_list(client_, key,
265 GCONF_VALUE_STRING, &error); 330 GCONF_VALUE_STRING, &error);
266 if (HandleGError(error, key)) 331 if (HandleGError(error, key))
267 return false; 332 return false;
268 if (!list) { 333 if (!list) {
269 // unset 334 // unset
270 return false; 335 return false;
271 } 336 }
272 for (GSList *it = list; it; it = it->next) { 337 for (GSList *it = list; it; it = it->next) {
273 result->push_back(static_cast<char*>(it->data)); 338 result->push_back(static_cast<char*>(it->data));
274 g_free(it->data); 339 g_free(it->data);
275 } 340 }
276 g_slist_free(list); 341 g_slist_free(list);
277 return true; 342 return true;
278 } 343 }
279 344
280 private: 345 private:
281 // Logs and frees a glib error. Returns false if there was no error 346 // Logs and frees a glib error. Returns false if there was no error
282 // (error is NULL). 347 // (error is NULL).
283 bool HandleGError(GError* error, const char* key) { 348 bool HandleGError(GError* error, const char* key) {
284 if (error != NULL) { 349 if (error != NULL) {
285 LOG(ERROR) << "ProxyConfigServiceLinux: error getting gconf value for " 350 LOG(ERROR) << "Error getting gconf value for " << key
286 << key << ": " << error->message; 351 << ": " << error->message;
287 g_error_free(error); 352 g_error_free(error);
288 return true; 353 return true;
289 } 354 }
290 return false; 355 return false;
291 } 356 }
292 357
293 GConfClient* client_; 358 GConfClient* client_;
294 359
360 // Message loop of the thread that we make gconf calls on. It should
361 // be the UI thread and all our methods should be called on this
362 // thread. Only for assertions.
363 MessageLoop* loop_;
364
295 DISALLOW_COPY_AND_ASSIGN(GConfSettingGetterImpl); 365 DISALLOW_COPY_AND_ASSIGN(GConfSettingGetterImpl);
296 }; 366 };
297 367
298 } // namespace 368 } // namespace
299 369
300 bool ProxyConfigServiceLinux::GetProxyFromGConf( 370 bool ProxyConfigServiceLinux::Delegate::GetProxyFromGConf(
301 const char* key_prefix, bool is_socks, ProxyServer* result_server) { 371 const char* key_prefix, bool is_socks, ProxyServer* result_server) {
302 std::string key(key_prefix); 372 std::string key(key_prefix);
303 std::string host; 373 std::string host;
304 if (!gconf_getter_->GetString((key + "host").c_str(), &host) 374 if (!gconf_getter_->GetString((key + "host").c_str(), &host)
305 || host.empty()) { 375 || host.empty()) {
306 // Unset or empty. 376 // Unset or empty.
307 return false; 377 return false;
308 } 378 }
309 // Check for an optional port. 379 // Check for an optional port.
310 int port; 380 int port;
311 gconf_getter_->GetInt((key + "port").c_str(), &port); 381 gconf_getter_->GetInt((key + "port").c_str(), &port);
312 if (port != 0) { 382 if (port != 0) {
313 // If a port is set and non-zero: 383 // If a port is set and non-zero:
314 host += ":" + IntToString(port); 384 host += ":" + IntToString(port);
315 } 385 }
316 host = FixupProxyHostScheme( 386 host = FixupProxyHostScheme(
317 is_socks ? ProxyServer::SCHEME_SOCKS4 : ProxyServer::SCHEME_HTTP, 387 is_socks ? ProxyServer::SCHEME_SOCKS4 : ProxyServer::SCHEME_HTTP,
318 host); 388 host);
319 ProxyServer proxy_server = ProxyServer::FromURI(host); 389 ProxyServer proxy_server = ProxyServer::FromURI(host);
320 if (proxy_server.is_valid()) { 390 if (proxy_server.is_valid()) {
321 *result_server = proxy_server; 391 *result_server = proxy_server;
322 return true; 392 return true;
323 } 393 }
324 return false; 394 return false;
325 } 395 }
326 396
327 bool ProxyConfigServiceLinux::GetConfigFromGConf(ProxyConfig* config) { 397 bool ProxyConfigServiceLinux::Delegate::GetConfigFromGConf(
398 ProxyConfig* config) {
328 std::string mode; 399 std::string mode;
329 if (!gconf_getter_->GetString("/system/proxy/mode", &mode)) { 400 if (!gconf_getter_->GetString("/system/proxy/mode", &mode)) {
330 // We expect this to always be set, so if we don't see it then we 401 // We expect this to always be set, so if we don't see it then we
331 // probably have a gconf problem, and so we don't have a valid 402 // probably have a gconf problem, and so we don't have a valid
332 // proxy config. 403 // proxy config.
333 return false; 404 return false;
334 } 405 }
335 if (mode.compare("none") == 0) 406 if (mode == "none") {
336 // Specifically specifies no proxy. 407 // Specifically specifies no proxy.
337 return true; 408 return true;
409 }
338 410
339 if (mode.compare("auto") == 0) { 411 if (mode == "auto") {
340 // automatic proxy config 412 // automatic proxy config
341 std::string pac_url_str; 413 std::string pac_url_str;
342 if (gconf_getter_->GetString("/system/proxy/autoconfig_url", 414 if (gconf_getter_->GetString("/system/proxy/autoconfig_url",
343 &pac_url_str)) { 415 &pac_url_str)) {
344 if (!pac_url_str.empty()) { 416 if (!pac_url_str.empty()) {
345 GURL pac_url(pac_url_str); 417 GURL pac_url(pac_url_str);
346 if (!pac_url.is_valid()) 418 if (!pac_url.is_valid())
347 return false; 419 return false;
348 config->pac_url = pac_url; 420 config->pac_url = pac_url;
349 return true; 421 return true;
350 } 422 }
351 } 423 }
352 config->auto_detect = true; 424 config->auto_detect = true;
353 return true; 425 return true;
354 } 426 }
355 427
356 if (mode.compare("manual") != 0) { 428 if (mode != "manual") {
357 // Mode is unrecognized. 429 // Mode is unrecognized.
358 return false; 430 return false;
359 } 431 }
360 bool use_http_proxy; 432 bool use_http_proxy;
361 if (gconf_getter_->GetBoolean("/system/http_proxy/use_http_proxy", 433 if (gconf_getter_->GetBoolean("/system/http_proxy/use_http_proxy",
362 &use_http_proxy) 434 &use_http_proxy)
363 && !use_http_proxy) { 435 && !use_http_proxy) {
364 // Another master switch for some reason. If set to false, then no 436 // Another master switch for some reason. If set to false, then no
365 // proxy. But we don't panic if the key doesn't exist. 437 // proxy. But we don't panic if the key doesn't exist.
366 return true; 438 return true;
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
412 if (config->proxy_rules.empty()) { 484 if (config->proxy_rules.empty()) {
413 // Manual mode but we couldn't parse any rules. 485 // Manual mode but we couldn't parse any rules.
414 return false; 486 return false;
415 } 487 }
416 488
417 // Check for authentication, just so we can warn. 489 // Check for authentication, just so we can warn.
418 bool use_auth; 490 bool use_auth;
419 gconf_getter_->GetBoolean("/system/http_proxy/use_authentication", 491 gconf_getter_->GetBoolean("/system/http_proxy/use_authentication",
420 &use_auth); 492 &use_auth);
421 if (use_auth) 493 if (use_auth)
422 LOG(ERROR) << "ProxyConfigServiceLinux: proxy authentication " 494 LOG(ERROR) << "Proxy authentication not supported";
423 "not supported";
424 495
425 // Now the bypass list. 496 // Now the bypass list.
426 gconf_getter_->GetStringList("/system/http_proxy/ignore_hosts", 497 gconf_getter_->GetStringList("/system/http_proxy/ignore_hosts",
427 &config->proxy_bypass); 498 &config->proxy_bypass);
428 // Note that there are no settings with semantics corresponding to 499 // Note that there are no settings with semantics corresponding to
429 // config->proxy_bypass_local_names. 500 // config->proxy_bypass_local_names.
430 501
431 return true; 502 return true;
432 } 503 }
433 504
505 ProxyConfigServiceLinux::Delegate::Delegate(
506 EnvironmentVariableGetter* env_var_getter,
507 GConfSettingGetter* gconf_getter)
508 : env_var_getter_(env_var_getter), gconf_getter_(gconf_getter),
509 glib_default_loop_(NULL), io_loop_(NULL) {
510 }
511
512 bool ProxyConfigServiceLinux::Delegate::ShouldTryGConf() {
513 // GNOME_DESKTOP_SESSION_ID being defined is a good indication that
514 // we are probably running under GNOME.
515 // Note: KDE_FULL_SESSION is a corresponding env var to recognize KDE.
516 std::string dummy, desktop_session;
517 return env_var_getter_->Getenv("GNOME_DESKTOP_SESSION_ID", &dummy)
518 || (env_var_getter_->Getenv("DESKTOP_SESSION", &desktop_session)
519 && desktop_session == "gnome");
520 // I (sdoyon) would have liked to prioritize environment variables
521 // and only fallback to gconf if env vars were unset. But
522 // gnome-terminal "helpfully" sets http_proxy and no_proxy, and it
523 // does so even if the proxy mode is set to auto, which would
524 // mislead us.
525 //
526 // We could introduce a CHROME_PROXY_OBEY_ENV_VARS variable...??
527 }
528
529 void ProxyConfigServiceLinux::Delegate::SetupAndFetchInitialConfig(
530 MessageLoop* glib_default_loop, MessageLoop* io_loop) {
531 // We should be running on the default glib main loop thread right
532 // now. gconf can only be accessed from this thread.
533 DCHECK(MessageLoop::current() == glib_default_loop);
534 glib_default_loop_ = glib_default_loop;
535 io_loop_ = io_loop;
536
537 // If we are passed a NULL io_loop, then we don't setup gconf
538 // notifications. This should not be the usual case but is intended
539 // to simplify test setups.
540 if (!io_loop_)
541 LOG(INFO) << "Monitoring of gconf setting changes is disabled";
542
543 // Fetch and cache the current proxy config. The config is left in
544 // cached_config_, where GetProxyConfig() running on the IO thread
545 // will expect to find it. This is safe to do because we return
546 // before this ProxyConfigServiceLinux is passed on to
547 // the ProxyService.
548 bool got_config = false;
549 if (ShouldTryGConf() &&
550 gconf_getter_->Init() &&
551 (!io_loop || gconf_getter_->SetupNotification(this))) {
552 if (GetConfigFromGConf(&cached_config_)) {
553 cached_config_.set_id(1); // mark it as valid
554 got_config = true;
555 LOG(INFO) << "Obtained proxy setting from gconf";
556 // If gconf proxy mode is "none", meaning direct, then we take
557 // that to be a valid config and will not check environment
558 // variables. The alternative would have been to look for a proxy
559 // where ever we can find one.
560 //
561 // Keep a copy of the config for use from this thread for
562 // comparison with updated settings when we get notifications.
563 reference_config_ = cached_config_;
564 reference_config_.set_id(1); // mark it as valid
565 } else {
566 gconf_getter_->Release(); // Stop notifications
567 }
568 }
569 if (!got_config) {
570 // An implementation for KDE settings would be welcome here.
571 //
572 // Consulting environment variables doesn't need to be done from
573 // the default glib main loop, but it's a tiny enough amount of
574 // work.
575 if (GetConfigFromEnv(&cached_config_)) {
576 cached_config_.set_id(1); // mark it as valid
577 LOG(INFO) << "Obtained proxy setting from environment variables";
578 }
579 }
580 }
581
582 void ProxyConfigServiceLinux::Delegate::Reset() {
583 DCHECK(!glib_default_loop_ || MessageLoop::current() == glib_default_loop_);
584 gconf_getter_->Release();
585 cached_config_ = ProxyConfig();
586 }
587
588 int ProxyConfigServiceLinux::Delegate::GetProxyConfig(ProxyConfig* config) {
589 // This is called from the IO thread.
590 DCHECK(!io_loop_ || MessageLoop::current() == io_loop_);
591
592 // Simply return the last proxy configuration that glib_default_loop
593 // notified us of.
594 *config = cached_config_;
595 return cached_config_.is_valid() ? OK : ERR_FAILED;
596 }
597
598 void ProxyConfigServiceLinux::Delegate::OnCheckProxyConfigSettings() {
599 // This should be dispatched from the thread with the default glib
600 // main loop, which allows us to access gconf.
601 DCHECK(MessageLoop::current() == glib_default_loop_);
602
603 ProxyConfig new_config;
604 bool valid = GetConfigFromGConf(&new_config);
605 if (valid)
606 new_config.set_id(1); // mark it as valid
607
608 // See if it is different than what we had before.
609 if (new_config.is_valid() != reference_config_.is_valid() ||
610 !new_config.Equals(reference_config_)) {
611 // Post a task to |io_loop| with the new configuration, so it can
612 // update |cached_config_|.
613 io_loop_->PostTask(
614 FROM_HERE,
615 NewRunnableMethod(
616 this,
617 &ProxyConfigServiceLinux::Delegate::SetNewProxyConfig,
618 new_config));
619 }
620 }
621
622 void ProxyConfigServiceLinux::Delegate::SetNewProxyConfig(
623 const ProxyConfig& new_config) {
624 DCHECK(MessageLoop::current() == io_loop_);
625 LOG(INFO) << "Proxy configuration changed";
626 cached_config_ = new_config;
627 }
628
629 void ProxyConfigServiceLinux::Delegate::PostDestroyTask() {
630 if (MessageLoop::current() == glib_default_loop_) {
631 // Already on the right thread, call directly.
632 // This is the case for the unittests.
633 OnDestroy();
634 } else {
635 // Post to UI thread. Note that on browser shutdown, we may quit
636 // the UI MessageLoop and exit the program before ever running
637 // this.
638 glib_default_loop_->PostTask(
639 FROM_HERE,
640 NewRunnableMethod(
641 this,
642 &ProxyConfigServiceLinux::Delegate::OnDestroy));
643 }
644 }
645 void ProxyConfigServiceLinux::Delegate::OnDestroy() {
646 DCHECK(!glib_default_loop_ || MessageLoop::current() == glib_default_loop_);
647 gconf_getter_->Release();
648 }
649
650 ProxyConfigServiceLinux::ProxyConfigServiceLinux()
651 : delegate_(new Delegate(new EnvironmentVariableGetterImpl(),
652 new GConfSettingGetterImpl())) {
653 }
654
434 ProxyConfigServiceLinux::ProxyConfigServiceLinux( 655 ProxyConfigServiceLinux::ProxyConfigServiceLinux(
435 EnvironmentVariableGetter* env_var_getter, 656 EnvironmentVariableGetter* env_var_getter,
436 GConfSettingGetter* gconf_getter) 657 GConfSettingGetter* gconf_getter)
437 : env_var_getter_(env_var_getter), gconf_getter_(gconf_getter) { 658 : delegate_(new Delegate(env_var_getter, gconf_getter)) {
438 }
439
440 ProxyConfigServiceLinux::ProxyConfigServiceLinux()
441 : env_var_getter_(new EnvironmentVariableGetterImpl()),
442 gconf_getter_(new GConfSettingGetterImpl()) {
443 }
444
445 int ProxyConfigServiceLinux::GetProxyConfig(ProxyConfig* config) {
446 // GNOME_DESKTOP_SESSION_ID being defined is a good indication that
447 // we are probably running under GNOME.
448 // Note: KDE_FULL_SESSION is a corresponding env var to recognize KDE.
449 std::string dummy, desktop_session;
450 bool ok = false;
451 #if 0 // gconf temporarily disabled because of races.
452 // See http://crbug.com/11442.
453 if (env_var_getter_->Getenv("GNOME_DESKTOP_SESSION_ID", &dummy)
454 || (env_var_getter_->Getenv("DESKTOP_SESSION", &desktop_session)
455 && desktop_session.compare("gnome") == 0)) {
456 // Get settings from gconf.
457 //
458 // I (sdoyon) would have liked to prioritize environment variables
459 // and only fallback to gconf if env vars were unset. But
460 // gnome-terminal "helpfully" sets http_proxy and no_proxy, and it
461 // does so even if the proxy mode is set to auto, which would
462 // mislead us.
463 //
464 // We could introduce a CHROME_PROXY_OBEY_ENV_VARS variable...??
465 if (gconf_getter_->InitIfNeeded()) {
466 gconf_getter_->Enter();
467 ok = GetConfigFromGConf(config);
468 gconf_getter_->Leave();
469 if (ok)
470 LOG(INFO) << "ProxyConfigServiceLinux: obtained proxy setting "
471 "from gconf";
472 // If gconf proxy mode is "none", meaning direct, then we take
473 // that to be a valid config and will not check environment variables.
474 // The alternative would have been to look for a proxy whereever
475 // we can find one.
476 //
477 // TODO(sdoyon): Consider wiring in the gconf notification
478 // system. Cache this result config to return on subsequent calls,
479 // and only call GetConfigFromGConf() when we know things have
480 // actually changed.
481 }
482 }
483 #endif // 0 (gconf disabled)
484 // An implementation for KDE settings would be welcome here.
485 if (!ok) {
486 ok = GetConfigFromEnv(config);
487 if (ok)
488 LOG(INFO) << "ProxyConfigServiceLinux: obtained proxy setting "
489 "from environment variables";
490 }
491 return ok ? OK : ERR_FAILED;
492 } 659 }
493 660
494 } // namespace net 661 } // namespace net
OLDNEW
« no previous file with comments | « net/proxy/proxy_config_service_linux.h ('k') | net/proxy/proxy_config_service_linux_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698