OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |