OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 <errno.h> | 7 #include <errno.h> |
8 #include <fcntl.h> | 8 #include <fcntl.h> |
9 #if defined(USE_GCONF) | 9 #if defined(USE_GCONF) |
10 #include <gconf/gconf-client.h> | 10 #include <gconf/gconf-client.h> |
11 #endif // defined(USE_GCONF) | 11 #endif // defined(USE_GCONF) |
12 #if defined(USE_GIO) | |
13 #include <gio/gio.h> | |
14 #if defined(DLOPEN_GSETTINGS) | |
15 #include <dlfcn.h> | |
16 #endif // defined(DLOPEN_GSETTINGS) | |
17 #endif // defined(USE_GIO) | |
18 #include <limits.h> | 12 #include <limits.h> |
19 #include <stdio.h> | 13 #include <stdio.h> |
20 #include <stdlib.h> | 14 #include <stdlib.h> |
21 #include <sys/inotify.h> | 15 #include <sys/inotify.h> |
22 #include <unistd.h> | 16 #include <unistd.h> |
23 | 17 |
24 #include <map> | 18 #include <map> |
25 | 19 |
26 #include "base/bind.h" | 20 #include "base/bind.h" |
27 #include "base/compiler_specific.h" | 21 #include "base/compiler_specific.h" |
28 #include "base/environment.h" | 22 #include "base/environment.h" |
29 #include "base/file_path.h" | 23 #include "base/file_path.h" |
30 #include "base/file_util.h" | 24 #include "base/file_util.h" |
31 #include "base/logging.h" | 25 #include "base/logging.h" |
32 #include "base/message_loop.h" | 26 #include "base/message_loop.h" |
33 #include "base/nix/xdg_util.h" | 27 #include "base/nix/xdg_util.h" |
34 #include "base/single_thread_task_runner.h" | 28 #include "base/single_thread_task_runner.h" |
35 #include "base/string_number_conversions.h" | 29 #include "base/string_number_conversions.h" |
36 #include "base/string_tokenizer.h" | 30 #include "base/string_tokenizer.h" |
37 #include "base/string_util.h" | 31 #include "base/string_util.h" |
38 #include "base/threading/thread_restrictions.h" | 32 #include "base/threading/thread_restrictions.h" |
39 #include "base/timer.h" | 33 #include "base/timer.h" |
40 #include "googleurl/src/url_canon.h" | 34 #include "googleurl/src/url_canon.h" |
41 #include "net/base/net_errors.h" | 35 #include "net/base/net_errors.h" |
42 #include "net/http/http_util.h" | 36 #include "net/http/http_util.h" |
43 #include "net/proxy/proxy_config.h" | 37 #include "net/proxy/proxy_config.h" |
44 #include "net/proxy/proxy_server.h" | 38 #include "net/proxy/proxy_server.h" |
45 | 39 |
40 #if defined(USE_GIO) | |
41 #include "library_loaders/libgio.h" | |
42 #endif // defined(USE_GIO) | |
43 | |
46 namespace net { | 44 namespace net { |
47 | 45 |
48 namespace { | 46 namespace { |
49 | 47 |
50 // Given a proxy hostname from a setting, returns that hostname with | 48 // Given a proxy hostname from a setting, returns that hostname with |
51 // an appropriate proxy server scheme prefix. | 49 // an appropriate proxy server scheme prefix. |
52 // scheme indicates the desired proxy scheme: usually http, with | 50 // scheme indicates the desired proxy scheme: usually http, with |
53 // socks 4 or 5 as special cases. | 51 // socks 4 or 5 as special cases. |
54 // TODO(arindam): Remove URI string manipulation by using MapUrlSchemeToProxy. | 52 // TODO(arindam): Remove URI string manipulation by using MapUrlSchemeToProxy. |
55 std::string FixupProxyHostScheme(ProxyServer::Scheme scheme, | 53 std::string FixupProxyHostScheme(ProxyServer::Scheme scheme, |
(...skipping 452 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
508 DISALLOW_COPY_AND_ASSIGN(SettingGetterImplGConf); | 506 DISALLOW_COPY_AND_ASSIGN(SettingGetterImplGConf); |
509 }; | 507 }; |
510 #endif // defined(USE_GCONF) | 508 #endif // defined(USE_GCONF) |
511 | 509 |
512 #if defined(USE_GIO) | 510 #if defined(USE_GIO) |
513 // This setting getter uses gsettings, as used in most GNOME 3 desktops. | 511 // This setting getter uses gsettings, as used in most GNOME 3 desktops. |
514 class SettingGetterImplGSettings | 512 class SettingGetterImplGSettings |
515 : public ProxyConfigServiceLinux::SettingGetter { | 513 : public ProxyConfigServiceLinux::SettingGetter { |
516 public: | 514 public: |
517 SettingGetterImplGSettings() : | 515 SettingGetterImplGSettings() : |
518 #if defined(DLOPEN_GSETTINGS) | |
519 g_settings_new(NULL), | |
520 g_settings_get_child(NULL), | |
521 g_settings_get_boolean(NULL), | |
522 g_settings_get_string(NULL), | |
523 g_settings_get_int(NULL), | |
524 g_settings_get_strv(NULL), | |
525 g_settings_list_schemas(NULL), | |
526 gio_handle_(NULL), | |
527 #endif | |
528 client_(NULL), | 516 client_(NULL), |
529 http_client_(NULL), | 517 http_client_(NULL), |
530 https_client_(NULL), | 518 https_client_(NULL), |
531 ftp_client_(NULL), | 519 ftp_client_(NULL), |
532 socks_client_(NULL), | 520 socks_client_(NULL), |
533 notify_delegate_(NULL) { | 521 notify_delegate_(NULL) { |
534 } | 522 } |
535 | 523 |
536 virtual ~SettingGetterImplGSettings() { | 524 virtual ~SettingGetterImplGSettings() { |
537 // client_ should have been released before now, from | 525 // client_ should have been released before now, from |
538 // Delegate::OnDestroy(), while running on the UI thread. However | 526 // Delegate::OnDestroy(), while running on the UI thread. However |
539 // on exiting the process, it may happen that | 527 // on exiting the process, it may happen that |
540 // Delegate::OnDestroy() task is left pending on the glib loop | 528 // Delegate::OnDestroy() task is left pending on the glib loop |
541 // after the loop was quit, and pending tasks may then be deleted | 529 // after the loop was quit, and pending tasks may then be deleted |
542 // without being run. | 530 // without being run. |
543 if (client_) { | 531 if (client_) { |
544 // gconf client was not cleaned up. | 532 // gconf client was not cleaned up. |
545 if (task_runner_->BelongsToCurrentThread()) { | 533 if (task_runner_->BelongsToCurrentThread()) { |
546 // We are on the UI thread so we can clean it safely. This is | 534 // We are on the UI thread so we can clean it safely. This is |
547 // the case at least for ui_tests running under Valgrind in | 535 // the case at least for ui_tests running under Valgrind in |
548 // bug 16076. | 536 // bug 16076. |
549 VLOG(1) << "~SettingGetterImplGSettings: releasing gsettings client"; | 537 VLOG(1) << "~SettingGetterImplGSettings: releasing gsettings client"; |
550 ShutDown(); | 538 ShutDown(); |
551 } else { | 539 } else { |
552 LOG(WARNING) << "~SettingGetterImplGSettings: leaking gsettings client"; | 540 LOG(WARNING) << "~SettingGetterImplGSettings: leaking gsettings client"; |
553 client_ = NULL; | 541 client_ = NULL; |
554 } | 542 } |
555 } | 543 } |
556 DCHECK(!client_); | 544 DCHECK(!client_); |
557 #if defined(DLOPEN_GSETTINGS) | |
558 if (gio_handle_) { | |
559 dlclose(gio_handle_); | |
560 gio_handle_ = NULL; | |
561 } | |
562 #endif | |
563 } | 545 } |
564 | 546 |
565 bool SchemaExists(const char* schema_name) { | 547 bool SchemaExists(const char* schema_name) { |
566 const gchar* const* schemas = g_settings_list_schemas(); | 548 const gchar* const* schemas = libgio_loader_.g_settings_list_schemas(); |
567 while (*schemas) { | 549 while (*schemas) { |
568 if (strcmp(schema_name, static_cast<const char*>(*schemas)) == 0) | 550 if (strcmp(schema_name, static_cast<const char*>(*schemas)) == 0) |
569 return true; | 551 return true; |
570 schemas++; | 552 schemas++; |
571 } | 553 } |
572 return false; | 554 return false; |
573 } | 555 } |
574 | 556 |
575 // LoadAndCheckVersion() must be called *before* Init()! | 557 // LoadAndCheckVersion() must be called *before* Init()! |
576 bool LoadAndCheckVersion(base::Environment* env); | 558 bool LoadAndCheckVersion(base::Environment* env); |
577 | 559 |
578 virtual bool Init(base::SingleThreadTaskRunner* glib_thread_task_runner, | 560 virtual bool Init(base::SingleThreadTaskRunner* glib_thread_task_runner, |
579 MessageLoopForIO* file_loop) OVERRIDE { | 561 MessageLoopForIO* file_loop) OVERRIDE { |
580 DCHECK(glib_thread_task_runner->BelongsToCurrentThread()); | 562 DCHECK(glib_thread_task_runner->BelongsToCurrentThread()); |
581 DCHECK(!client_); | 563 DCHECK(!client_); |
582 DCHECK(!task_runner_); | 564 DCHECK(!task_runner_); |
583 | 565 |
584 if (!SchemaExists("org.gnome.system.proxy") || | 566 if (!SchemaExists("org.gnome.system.proxy") || |
585 !(client_ = g_settings_new("org.gnome.system.proxy"))) { | 567 !(client_ = libgio_loader_.g_settings_new("org.gnome.system.proxy"))) { |
586 // It's not clear whether/when this can return NULL. | 568 // It's not clear whether/when this can return NULL. |
587 LOG(ERROR) << "Unable to create a gsettings client"; | 569 LOG(ERROR) << "Unable to create a gsettings client"; |
588 return false; | 570 return false; |
589 } | 571 } |
590 task_runner_ = glib_thread_task_runner; | 572 task_runner_ = glib_thread_task_runner; |
591 // We assume these all work if the above call worked. | 573 // We assume these all work if the above call worked. |
592 http_client_ = g_settings_get_child(client_, "http"); | 574 http_client_ = libgio_loader_.g_settings_get_child(client_, "http"); |
593 https_client_ = g_settings_get_child(client_, "https"); | 575 https_client_ = libgio_loader_.g_settings_get_child(client_, "https"); |
594 ftp_client_ = g_settings_get_child(client_, "ftp"); | 576 ftp_client_ = libgio_loader_.g_settings_get_child(client_, "ftp"); |
595 socks_client_ = g_settings_get_child(client_, "socks"); | 577 socks_client_ = libgio_loader_.g_settings_get_child(client_, "socks"); |
596 DCHECK(http_client_ && https_client_ && ftp_client_ && socks_client_); | 578 DCHECK(http_client_ && https_client_ && ftp_client_ && socks_client_); |
597 return true; | 579 return true; |
598 } | 580 } |
599 | 581 |
600 virtual void ShutDown() OVERRIDE { | 582 virtual void ShutDown() OVERRIDE { |
601 if (client_) { | 583 if (client_) { |
602 DCHECK(task_runner_->BelongsToCurrentThread()); | 584 DCHECK(task_runner_->BelongsToCurrentThread()); |
603 // This also disables gsettings notifications. | 585 // This also disables gsettings notifications. |
604 g_object_unref(socks_client_); | 586 g_object_unref(socks_client_); |
605 g_object_unref(ftp_client_); | 587 g_object_unref(ftp_client_); |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
706 virtual bool BypassListIsReversed() OVERRIDE { | 688 virtual bool BypassListIsReversed() OVERRIDE { |
707 // This is a KDE-specific setting. | 689 // This is a KDE-specific setting. |
708 return false; | 690 return false; |
709 } | 691 } |
710 | 692 |
711 virtual bool MatchHostsUsingSuffixMatching() OVERRIDE { | 693 virtual bool MatchHostsUsingSuffixMatching() OVERRIDE { |
712 return false; | 694 return false; |
713 } | 695 } |
714 | 696 |
715 private: | 697 private: |
716 #if defined(DLOPEN_GSETTINGS) | |
717 // We replicate the prototypes for the g_settings APIs we need. We may not | |
718 // even be compiling on a system that has them. If we are, these won't | |
719 // conflict both because they are identical and also due to scoping. The | |
720 // scoping will also ensure that these get used instead of the global ones. | |
721 struct _GSettings; | |
722 typedef struct _GSettings GSettings; | |
Ryan Sleevi
2012/11/28 20:38:33
It's not clear to me whether this removal is safe
Paweł Hajdan Jr.
2012/11/28 21:19:46
It will fail compile. We have trybots for that. We
Ryan Sleevi
2012/11/28 22:29:42
Considering how often you're adding flags that try
| |
723 GSettings* (*g_settings_new)(const gchar* schema); | |
724 GSettings* (*g_settings_get_child)(GSettings* settings, const gchar* name); | |
725 gboolean (*g_settings_get_boolean)(GSettings* settings, const gchar* key); | |
726 gchar* (*g_settings_get_string)(GSettings* settings, const gchar* key); | |
727 gint (*g_settings_get_int)(GSettings* settings, const gchar* key); | |
728 gchar** (*g_settings_get_strv)(GSettings* settings, const gchar* key); | |
729 const gchar* const* (*g_settings_list_schemas)(); | |
730 | |
731 // The library handle. | |
732 void* gio_handle_; | |
733 | |
734 // Load a symbol from |gio_handle_| and store it into |*func_ptr|. | |
735 bool LoadSymbol(const char* name, void** func_ptr) { | |
736 dlerror(); | |
737 *func_ptr = dlsym(gio_handle_, name); | |
738 const char* error = dlerror(); | |
739 if (error) { | |
740 VLOG(1) << "Unable to load symbol " << name << ": " << error; | |
741 return false; | |
742 } | |
743 return true; | |
744 } | |
745 #endif // defined(DLOPEN_GSETTINGS) | |
746 | |
747 bool GetStringByPath(GSettings* client, const char* key, | 698 bool GetStringByPath(GSettings* client, const char* key, |
748 std::string* result) { | 699 std::string* result) { |
749 DCHECK(task_runner_->BelongsToCurrentThread()); | 700 DCHECK(task_runner_->BelongsToCurrentThread()); |
750 gchar* value = g_settings_get_string(client, key); | 701 gchar* value = libgio_loader_.g_settings_get_string(client, key); |
751 if (!value) | 702 if (!value) |
752 return false; | 703 return false; |
753 *result = value; | 704 *result = value; |
754 g_free(value); | 705 g_free(value); |
755 return true; | 706 return true; |
756 } | 707 } |
757 bool GetBoolByPath(GSettings* client, const char* key, bool* result) { | 708 bool GetBoolByPath(GSettings* client, const char* key, bool* result) { |
758 DCHECK(task_runner_->BelongsToCurrentThread()); | 709 DCHECK(task_runner_->BelongsToCurrentThread()); |
759 *result = static_cast<bool>(g_settings_get_boolean(client, key)); | 710 *result = static_cast<bool>( |
711 libgio_loader_.g_settings_get_boolean(client, key)); | |
760 return true; | 712 return true; |
761 } | 713 } |
762 bool GetIntByPath(GSettings* client, const char* key, int* result) { | 714 bool GetIntByPath(GSettings* client, const char* key, int* result) { |
763 DCHECK(task_runner_->BelongsToCurrentThread()); | 715 DCHECK(task_runner_->BelongsToCurrentThread()); |
764 *result = g_settings_get_int(client, key); | 716 *result = libgio_loader_.g_settings_get_int(client, key); |
765 return true; | 717 return true; |
766 } | 718 } |
767 bool GetStringListByPath(GSettings* client, const char* key, | 719 bool GetStringListByPath(GSettings* client, const char* key, |
768 std::vector<std::string>* result) { | 720 std::vector<std::string>* result) { |
769 DCHECK(task_runner_->BelongsToCurrentThread()); | 721 DCHECK(task_runner_->BelongsToCurrentThread()); |
770 gchar** list = g_settings_get_strv(client, key); | 722 gchar** list = libgio_loader_.g_settings_get_strv(client, key); |
771 if (!list) | 723 if (!list) |
772 return false; | 724 return false; |
773 for (size_t i = 0; list[i]; ++i) { | 725 for (size_t i = 0; list[i]; ++i) { |
774 result->push_back(static_cast<char*>(list[i])); | 726 result->push_back(static_cast<char*>(list[i])); |
775 g_free(list[i]); | 727 g_free(list[i]); |
776 } | 728 } |
777 g_free(list); | 729 g_free(list); |
778 return true; | 730 return true; |
779 } | 731 } |
780 | 732 |
(...skipping 30 matching lines...) Expand all Loading... | |
811 GSettings* ftp_client_; | 763 GSettings* ftp_client_; |
812 GSettings* socks_client_; | 764 GSettings* socks_client_; |
813 ProxyConfigServiceLinux::Delegate* notify_delegate_; | 765 ProxyConfigServiceLinux::Delegate* notify_delegate_; |
814 base::OneShotTimer<SettingGetterImplGSettings> debounce_timer_; | 766 base::OneShotTimer<SettingGetterImplGSettings> debounce_timer_; |
815 | 767 |
816 // Task runner for the thread that we make gsettings calls on. It should | 768 // Task runner for the thread that we make gsettings calls on. It should |
817 // be the UI thread and all our methods should be called on this | 769 // be the UI thread and all our methods should be called on this |
818 // thread. Only for assertions. | 770 // thread. Only for assertions. |
819 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | 771 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
820 | 772 |
773 LibGioLoader libgio_loader_; | |
774 | |
821 DISALLOW_COPY_AND_ASSIGN(SettingGetterImplGSettings); | 775 DISALLOW_COPY_AND_ASSIGN(SettingGetterImplGSettings); |
822 }; | 776 }; |
823 | 777 |
824 bool SettingGetterImplGSettings::LoadAndCheckVersion( | 778 bool SettingGetterImplGSettings::LoadAndCheckVersion( |
825 base::Environment* env) { | 779 base::Environment* env) { |
826 // LoadAndCheckVersion() must be called *before* Init()! | 780 // LoadAndCheckVersion() must be called *before* Init()! |
827 DCHECK(!client_); | 781 DCHECK(!client_); |
828 | 782 |
829 // The APIs to query gsettings were introduced after the minimum glib | 783 // The APIs to query gsettings were introduced after the minimum glib |
830 // version we target, so we can't link directly against them. We load them | 784 // version we target, so we can't link directly against them. We load them |
831 // dynamically at runtime, and if they don't exist, return false here. (We | 785 // dynamically at runtime, and if they don't exist, return false here. (We |
832 // support linking directly via gyp flags though.) Additionally, even when | 786 // support linking directly via gyp flags though.) Additionally, even when |
833 // they are present, we do two additional checks to make sure we should use | 787 // they are present, we do two additional checks to make sure we should use |
834 // them and not gconf. First, we attempt to load the schema for proxy | 788 // them and not gconf. First, we attempt to load the schema for proxy |
835 // settings. Second, we check for the program that was used in older | 789 // settings. Second, we check for the program that was used in older |
836 // versions of GNOME to configure proxy settings, and return false if it | 790 // versions of GNOME to configure proxy settings, and return false if it |
837 // exists. Some distributions (e.g. Ubuntu 11.04) have the API and schema | 791 // exists. Some distributions (e.g. Ubuntu 11.04) have the API and schema |
838 // but don't use gsettings for proxy settings, but they do have the old | 792 // but don't use gsettings for proxy settings, but they do have the old |
839 // binary, so we detect these systems that way. | 793 // binary, so we detect these systems that way. |
840 | 794 |
841 #ifdef DLOPEN_GSETTINGS | 795 // Try also without .0 at the end; on some systems this may be required. |
842 gio_handle_ = dlopen("libgio-2.0.so.0", RTLD_NOW | RTLD_GLOBAL); | 796 if (!libgio_loader_.Load("libgio-2.0.so.0") && |
843 if (!gio_handle_) { | 797 !libgio_loader_.Load("libgio-2.0.so")) { |
844 // Try again without .0 at the end; on some systems this may be required. | 798 VLOG(1) << "Cannot load gio library. Will fall back to gconf."; |
845 gio_handle_ = dlopen("libgio-2.0.so", RTLD_NOW | RTLD_GLOBAL); | |
846 if (!gio_handle_) { | |
847 VLOG(1) << "Cannot load gio library. Will fall back to gconf."; | |
848 return false; | |
849 } | |
850 } | |
851 if (!LoadSymbol("g_settings_new", | |
852 reinterpret_cast<void**>(&g_settings_new)) || | |
853 !LoadSymbol("g_settings_get_child", | |
854 reinterpret_cast<void**>(&g_settings_get_child)) || | |
855 !LoadSymbol("g_settings_get_string", | |
856 reinterpret_cast<void**>(&g_settings_get_string)) || | |
857 !LoadSymbol("g_settings_get_boolean", | |
858 reinterpret_cast<void**>(&g_settings_get_boolean)) || | |
859 !LoadSymbol("g_settings_get_int", | |
860 reinterpret_cast<void**>(&g_settings_get_int)) || | |
861 !LoadSymbol("g_settings_get_strv", | |
862 reinterpret_cast<void**>(&g_settings_get_strv)) || | |
863 !LoadSymbol("g_settings_list_schemas", | |
864 reinterpret_cast<void**>(&g_settings_list_schemas))) { | |
865 VLOG(1) << "Cannot load gsettings API. Will fall back to gconf."; | |
866 dlclose(gio_handle_); | |
867 gio_handle_ = NULL; | |
868 return false; | 799 return false; |
869 } | 800 } |
870 #endif | |
871 | 801 |
872 GSettings* client; | 802 GSettings* client; |
873 if (!SchemaExists("org.gnome.system.proxy") || | 803 if (!SchemaExists("org.gnome.system.proxy") || |
874 !(client = g_settings_new("org.gnome.system.proxy"))) { | 804 !(client = libgio_loader_.g_settings_new("org.gnome.system.proxy"))) { |
875 VLOG(1) << "Cannot create gsettings client. Will fall back to gconf."; | 805 VLOG(1) << "Cannot create gsettings client. Will fall back to gconf."; |
876 return false; | 806 return false; |
877 } | 807 } |
878 g_object_unref(client); | 808 g_object_unref(client); |
879 | 809 |
880 std::string path; | 810 std::string path; |
881 if (!env->GetVar("PATH", &path)) { | 811 if (!env->GetVar("PATH", &path)) { |
882 LOG(ERROR) << "No $PATH variable. Assuming no gnome-network-properties."; | 812 LOG(ERROR) << "No $PATH variable. Assuming no gnome-network-properties."; |
883 } else { | 813 } else { |
884 // Yes, we're on the UI thread. Yes, we're accessing the file system. | 814 // Yes, we're on the UI thread. Yes, we're accessing the file system. |
(...skipping 931 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1816 void ProxyConfigServiceLinux::RemoveObserver(Observer* observer) { | 1746 void ProxyConfigServiceLinux::RemoveObserver(Observer* observer) { |
1817 delegate_->RemoveObserver(observer); | 1747 delegate_->RemoveObserver(observer); |
1818 } | 1748 } |
1819 | 1749 |
1820 ProxyConfigService::ConfigAvailability | 1750 ProxyConfigService::ConfigAvailability |
1821 ProxyConfigServiceLinux::GetLatestProxyConfig(ProxyConfig* config) { | 1751 ProxyConfigServiceLinux::GetLatestProxyConfig(ProxyConfig* config) { |
1822 return delegate_->GetLatestProxyConfig(config); | 1752 return delegate_->GetLatestProxyConfig(config); |
1823 } | 1753 } |
1824 | 1754 |
1825 } // namespace net | 1755 } // namespace net |
OLD | NEW |