diff options
author | slightlyoff@chromium.org <slightlyoff@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-24 05:11:58 +0000 |
---|---|---|
committer | slightlyoff@chromium.org <slightlyoff@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-24 05:11:58 +0000 |
commit | f781782dd67077478e117c61dca4ea5eefce3544 (patch) | |
tree | 4801f724123cfdcbb69c4e7fe40a565b331723ae /chrome_frame/np_proxy_service.cc | |
parent | 63cf4759efa2373e33436fb5df6849f930081226 (diff) | |
download | chromium_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.cc | 306 |
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())); +} |