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

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

Issue 11348279: Linux: use generated library loader for gsettings. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years 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) 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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698