summaryrefslogtreecommitdiffstats
path: root/chrome_frame/np_proxy_service.cc
diff options
context:
space:
mode:
authorslightlyoff@chromium.org <slightlyoff@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-24 05:11:58 +0000
committerslightlyoff@chromium.org <slightlyoff@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-24 05:11:58 +0000
commitf781782dd67077478e117c61dca4ea5eefce3544 (patch)
tree4801f724123cfdcbb69c4e7fe40a565b331723ae /chrome_frame/np_proxy_service.cc
parent63cf4759efa2373e33436fb5df6849f930081226 (diff)
downloadchromium_src-f781782dd67077478e117c61dca4ea5eefce3544.zip
chromium_src-f781782dd67077478e117c61dca4ea5eefce3544.tar.gz
chromium_src-f781782dd67077478e117c61dca4ea5eefce3544.tar.bz2
Initial import of the Chrome Frame codebase. Integration in chrome.gyp coming in a separate CL.
BUG=None TEST=None Review URL: http://codereview.chromium.org/218019 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@27042 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome_frame/np_proxy_service.cc')
-rw-r--r--chrome_frame/np_proxy_service.cc306
1 files changed, 306 insertions, 0 deletions
diff --git a/chrome_frame/np_proxy_service.cc b/chrome_frame/np_proxy_service.cc
new file mode 100644
index 0000000..cb26dac
--- /dev/null
+++ b/chrome_frame/np_proxy_service.cc
@@ -0,0 +1,306 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/string_util.h"
+#include "chrome/common/automation_constants.h"
+#include "chrome/common/json_value_serializer.h"
+#include "chrome_frame/np_proxy_service.h"
+#include "chrome_frame/np_browser_functions.h"
+
+#include "net/proxy/proxy_config.h"
+
+#include "third_party/xulrunner-sdk/win/include/xpcom/nsXPCOM.h"
+#include "third_party/xulrunner-sdk/win/include/xpcom/nsIObserverService.h"
+#include "third_party/xulrunner-sdk/win/include/xpcom/nsISupportsUtils.h"
+#include "third_party/xulrunner-sdk/win/include/xpcom/nsStringAPI.h"
+
+ASSOCIATE_IID(NS_IOBSERVERSERVICE_IID_STR, nsIObserverService);
+ASSOCIATE_IID(NS_IPREFBRANCH_IID_STR, nsIPrefBranch);
+
+// Firefox preference names.
+const char* kProxyObserverRoot = "network.";
+const char* kProxyObserverBranch = "proxy.";
+const char* kProxyType = "proxy.type";
+const char* kProxyAutoconfigUrl = "proxy.autoconfig_url";
+const char* kProxyBypassList = "proxy.no_proxies_on";
+
+const int kInvalidIntPref = -1;
+
+// These are the proxy schemes that Chrome knows about at the moment.
+// SOCKS is a notable ommission here, this will need to be updated when
+// Chrome supports SOCKS proxies.
+const NpProxyService::ProxyNames NpProxyService::kProxyInfo[] = {
+ {"http", "proxy.http", "proxy.http_port"},
+ {"https", "proxy.ssl", "proxy.ssl_port"},
+ {"ftp", "proxy.ftp", "proxy.ftp_port"} };
+
+NpProxyService::NpProxyService(void)
+ : type_(PROXY_CONFIG_LAST), auto_detect_(false), no_proxy_(false),
+ system_config_(false), automation_client_(NULL) {
+}
+
+NpProxyService::~NpProxyService(void) {
+}
+
+bool NpProxyService::Initialize(NPP instance,
+ ChromeFrameAutomationClient* automation_client) {
+ DCHECK(automation_client);
+ automation_client_ = automation_client;
+
+ // Get the pref service
+ bool result = false;
+ ScopedNsPtr<nsISupports> service_manager_base;
+ npapi::GetValue(instance, NPNVserviceManager, service_manager_base.Receive());
+ if (service_manager_base != NULL) {
+ service_manager_.QueryFrom(service_manager_base);
+ if (service_manager_.get() == NULL) {
+ DLOG(ERROR) << "Failed to create ServiceManager. This only works in FF.";
+ } else {
+ service_manager_->GetServiceByContractID(
+ NS_PREFSERVICE_CONTRACTID, NS_GET_IID(nsIPrefService),
+ reinterpret_cast<void**>(pref_service_.Receive()));
+ if (!pref_service_) {
+ DLOG(ERROR) << "Failed to create PreferencesService";
+ } else {
+ result = InitializePrefBranch(pref_service_);
+ }
+ }
+ }
+ return result;
+}
+
+bool NpProxyService::InitializePrefBranch(nsIPrefService* pref_service) {
+ DCHECK(pref_service);
+ // Note that we cannot persist a reference to the pref branch because we
+ // also act as an observer of changes to the branch. As per
+ // nsIPrefBranch2.h, this would result in a circular reference between us
+ // and the pref branch, which can impede cleanup. There are workarounds,
+ // but let's try just not caching the branch reference for now.
+ bool result = false;
+ ScopedNsPtr<nsIPrefBranch> pref_branch;
+
+ pref_service->ReadUserPrefs(nsnull);
+ pref_service->GetBranch(kProxyObserverRoot, pref_branch.Receive());
+
+ if (!pref_branch) {
+ DLOG(ERROR) << "Failed to get nsIPrefBranch";
+ } else {
+ if (!ReadProxySettings(pref_branch.get())) {
+ DLOG(ERROR) << "Could not read proxy settings.";
+ } else {
+ observer_pref_branch_.QueryFrom(pref_branch);
+ if (!observer_pref_branch_) {
+ DLOG(ERROR) << "Failed to get observer nsIPrefBranch2";
+ } else {
+ nsresult res = observer_pref_branch_->AddObserver(kProxyObserverBranch,
+ this, PR_FALSE);
+ result = NS_SUCCEEDED(res);
+ }
+ }
+ }
+ return result;
+}
+
+bool NpProxyService::UnInitialize() {
+ // Fail early if this was never created - we may not be running on FF.
+ if (!pref_service_)
+ return false;
+
+ // Unhook ourselves as an observer.
+ nsresult res = NS_ERROR_FAILURE;
+ if (observer_pref_branch_)
+ res = observer_pref_branch_->RemoveObserver(kProxyObserverBranch, this);
+
+ return NS_SUCCEEDED(res);
+}
+
+NS_IMETHODIMP NpProxyService::Observe(nsISupports* subject, const char* topic,
+ const PRUnichar* data) {
+ if (!subject || !topic) {
+ NOTREACHED();
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ std::string topic_str(topic);
+ nsresult res = NS_OK;
+ if (topic_str == NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) {
+ // Looks like our proxy settings changed. We need to reload!
+ // I have observed some extremely strange behaviour here. Specifically,
+ // we are supposed to be able to QI |subject| and get from it an
+ // nsIPrefBranch from which we can query new values. This has erratic
+ // behaviour, specifically subject starts returning null on all member
+ // queries. So I am using the cached nsIPrefBranch2 (that we used to add
+ // the observer) to do the querying.
+ if (NS_SUCCEEDED(res)) {
+ if (!ReadProxySettings(observer_pref_branch_)) {
+ res = NS_ERROR_UNEXPECTED;
+ } else {
+ std::string proxy_settings;
+ if (GetProxyValueJSONString(&proxy_settings))
+ automation_client_->SetProxySettings(proxy_settings);
+ }
+ }
+ } else {
+ NOTREACHED();
+ }
+
+ return res;
+}
+
+std::string NpProxyService::GetStringPref(nsIPrefBranch* pref_branch,
+ const char* pref_name) {
+ nsCString pref_string;
+ std::string result;
+ nsresult rv = pref_branch->GetCharPref(pref_name, getter_Copies(pref_string));
+ if (SUCCEEDED(rv) && pref_string.get()) {
+ result = pref_string.get();
+ }
+ return result;
+}
+
+int NpProxyService::GetIntPref(nsIPrefBranch* pref_branch,
+ const char* pref_name) {
+ PRInt32 pref_int;
+ int result = kInvalidIntPref;
+ nsresult rv = pref_branch->GetIntPref(pref_name, &pref_int);
+ if (SUCCEEDED(rv)) {
+ result = pref_int;
+ }
+ return result;
+}
+
+bool NpProxyService::GetBoolPref(nsIPrefBranch* pref_branch,
+ const char* pref_name) {
+ PRBool pref_bool;
+ bool result = false;
+ nsresult rv = pref_branch->GetBoolPref(pref_name, &pref_bool);
+ if (SUCCEEDED(rv)) {
+ result = pref_bool == PR_TRUE;
+ }
+ return result;
+}
+
+void NpProxyService::Reset() {
+ type_ = PROXY_CONFIG_LAST;
+ auto_detect_ = false;
+ no_proxy_ = false;
+ system_config_ = false;
+ manual_proxies_.clear();
+ pac_url_.clear();
+ proxy_bypass_list_.clear();
+}
+
+bool NpProxyService::ReadProxySettings(nsIPrefBranch* pref_branch) {
+ DCHECK(pref_branch);
+
+ // Clear our current settings.
+ Reset();
+ type_ = GetIntPref(pref_branch, kProxyType);
+ if (type_ == kInvalidIntPref) {
+ NOTREACHED();
+ return false;
+ }
+
+ switch (type_) {
+ case PROXY_CONFIG_DIRECT:
+ case PROXY_CONFIG_DIRECT4X:
+ no_proxy_ = true;
+ break;
+ case PROXY_CONFIG_SYSTEM:
+ // _SYSTEM is documented as "Use system settings if available, otherwise
+ // DIRECT". It isn't clear under what circumstances system settings would
+ // be unavailable, but I'll special-case this nonetheless and have
+ // GetProxyValueJSONString() return empty if we get this proxy type.
+ DLOG(WARNING) << "Received PROXY_CONFIG_SYSTEM proxy type.";
+ system_config_ = true;
+ break;
+ case PROXY_CONFIG_WPAD:
+ auto_detect_ = true;
+ break;
+ case PROXY_CONFIG_PAC:
+ pac_url_ = GetStringPref(pref_branch, kProxyAutoconfigUrl);
+ break;
+ case PROXY_CONFIG_MANUAL:
+ // Read in the values for each of the known schemes.
+ for (int i = 0; i < arraysize(kProxyInfo); i++) {
+ ManualProxyEntry entry;
+ entry.url = GetStringPref(pref_branch, kProxyInfo[i].pref_name);
+ entry.port = GetIntPref(pref_branch, kProxyInfo[i].port_pref_name);
+ if (!entry.url.empty() && entry.port != kInvalidIntPref) {
+ entry.scheme = kProxyInfo[i].chrome_scheme;
+ manual_proxies_.push_back(entry);
+ }
+ }
+
+ // Also pick up the list of URLs we bypass proxies for.
+ proxy_bypass_list_ = GetStringPref(pref_branch, kProxyBypassList);
+ break;
+ default:
+ NOTREACHED();
+ return false;
+ }
+ return true;
+}
+
+DictionaryValue* NpProxyService::BuildProxyValueSet() {
+ scoped_ptr<DictionaryValue> proxy_settings_value(new DictionaryValue);
+
+ if (auto_detect_) {
+ proxy_settings_value->SetBoolean(automation::kJSONProxyAutoconfig,
+ auto_detect_);
+ }
+
+ if (no_proxy_) {
+ proxy_settings_value->SetBoolean(automation::kJSONProxyNoProxy, no_proxy_);
+ }
+
+ if (!pac_url_.empty()) {
+ proxy_settings_value->SetString(automation::kJSONProxyPacUrl, pac_url_);
+ }
+
+ if (!proxy_bypass_list_.empty()) {
+ proxy_settings_value->SetString(automation::kJSONProxyBypassList,
+ proxy_bypass_list_);
+ }
+
+ // Fill in the manual proxy settings. Build a string representation that
+ // corresponds to the format of the input parameter to
+ // ProxyConfig::ProxyRules::ParseFromString.
+ std::string manual_proxy_settings;
+ ManualProxyList::const_iterator iter(manual_proxies_.begin());
+ for (; iter != manual_proxies_.end(); iter++) {
+ DCHECK(!iter->scheme.empty());
+ DCHECK(!iter->url.empty());
+ DCHECK(iter->port != kInvalidIntPref);
+ manual_proxy_settings += iter->scheme;
+ manual_proxy_settings += "=";
+ manual_proxy_settings += iter->url;
+ manual_proxy_settings += ":";
+ manual_proxy_settings += IntToString(iter->port);
+ manual_proxy_settings += ";";
+ }
+
+ if (!manual_proxy_settings.empty()) {
+ proxy_settings_value->SetString(automation::kJSONProxyServer,
+ manual_proxy_settings);
+ }
+
+ return proxy_settings_value.release();
+}
+
+bool NpProxyService::GetProxyValueJSONString(std::string* output) {
+ DCHECK(output);
+ output->empty();
+
+ // If we detected a PROXY_CONFIG_SYSTEM config type or failed to obtain the
+ // pref service then return false here to make Chrome continue using its
+ // default proxy settings.
+ if (system_config_ || !pref_service_)
+ return false;
+
+ scoped_ptr<DictionaryValue> proxy_settings_value(BuildProxyValueSet());
+
+ JSONStringValueSerializer serializer(output);
+ return serializer.Serialize(*static_cast<Value*>(proxy_settings_value.get()));
+}