| Index: chrome_frame/np_proxy_service.cc
|
| ===================================================================
|
| --- chrome_frame/np_proxy_service.cc (revision 0)
|
| +++ chrome_frame/np_proxy_service.cc (revision 0)
|
| @@ -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()));
|
| +}
|
|
|