Initialize all data members in HTTPResponseInfo's new ctor and remove the related...
[chromium-blink-merge.git] / chrome_frame / np_proxy_service.cc
blobb1eadde81f241e0c5748b47e0276404345343bab
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/string_number_conversions.h"
6 #include "chrome/common/automation_constants.h"
7 #include "chrome/common/json_value_serializer.h"
8 #include "chrome_frame/np_proxy_service.h"
9 #include "chrome_frame/np_browser_functions.h"
11 #include "net/proxy/proxy_config.h"
13 #include "third_party/xulrunner-sdk/win/include/xpcom/nsXPCOM.h"
14 #include "third_party/xulrunner-sdk/win/include/xpcom/nsIObserverService.h"
15 #include "third_party/xulrunner-sdk/win/include/xpcom/nsISupportsUtils.h"
16 #include "third_party/xulrunner-sdk/win/include/xpcom/nsStringAPI.h"
18 ASSOCIATE_IID(NS_IOBSERVERSERVICE_IID_STR, nsIObserverService);
19 ASSOCIATE_IID(NS_IPREFBRANCH_IID_STR, nsIPrefBranch);
21 // Firefox preference names.
22 const char* kProxyObserverRoot = "network.";
23 const char* kProxyObserverBranch = "proxy.";
24 const char* kProxyType = "proxy.type";
25 const char* kProxyAutoconfigUrl = "proxy.autoconfig_url";
26 const char* kProxyBypassList = "proxy.no_proxies_on";
28 const int kInvalidIntPref = -1;
30 // These are the proxy schemes that Chrome knows about at the moment.
31 // SOCKS is a notable ommission here, this will need to be updated when
32 // Chrome supports SOCKS proxies.
33 const NpProxyService::ProxyNames NpProxyService::kProxyInfo[] = {
34 {"http", "proxy.http", "proxy.http_port"},
35 {"https", "proxy.ssl", "proxy.ssl_port"},
36 {"ftp", "proxy.ftp", "proxy.ftp_port"} };
38 NpProxyService::NpProxyService(void)
39 : type_(PROXY_CONFIG_LAST), auto_detect_(false), no_proxy_(false),
40 system_config_(false), automation_client_(NULL) {
43 NpProxyService::~NpProxyService(void) {
46 bool NpProxyService::Initialize(NPP instance,
47 ChromeFrameAutomationClient* automation_client) {
48 DCHECK(automation_client);
49 automation_client_ = automation_client;
51 // Get the pref service
52 bool result = false;
53 ScopedNsPtr<nsISupports> service_manager_base;
54 npapi::GetValue(instance, NPNVserviceManager, service_manager_base.Receive());
55 if (service_manager_base != NULL) {
56 service_manager_.QueryFrom(service_manager_base);
57 if (service_manager_.get() == NULL) {
58 DLOG(ERROR) << "Failed to create ServiceManager. This only works in FF.";
59 } else {
60 service_manager_->GetServiceByContractID(
61 NS_PREFSERVICE_CONTRACTID, NS_GET_IID(nsIPrefService),
62 reinterpret_cast<void**>(pref_service_.Receive()));
63 if (!pref_service_) {
64 DLOG(ERROR) << "Failed to create PreferencesService";
65 } else {
66 result = InitializePrefBranch(pref_service_);
70 return result;
73 bool NpProxyService::InitializePrefBranch(nsIPrefService* pref_service) {
74 DCHECK(pref_service);
75 // Note that we cannot persist a reference to the pref branch because we
76 // also act as an observer of changes to the branch. As per
77 // nsIPrefBranch2.h, this would result in a circular reference between us
78 // and the pref branch, which can impede cleanup. There are workarounds,
79 // but let's try just not caching the branch reference for now.
80 bool result = false;
81 ScopedNsPtr<nsIPrefBranch> pref_branch;
83 pref_service->GetBranch(kProxyObserverRoot, pref_branch.Receive());
85 if (!pref_branch) {
86 DLOG(ERROR) << "Failed to get nsIPrefBranch";
87 } else {
88 if (!ReadProxySettings(pref_branch.get())) {
89 DLOG(ERROR) << "Could not read proxy settings.";
90 } else {
91 observer_pref_branch_.QueryFrom(pref_branch);
92 if (!observer_pref_branch_) {
93 DLOG(ERROR) << "Failed to get observer nsIPrefBranch2";
94 } else {
95 nsresult res = observer_pref_branch_->AddObserver(kProxyObserverBranch,
96 this, PR_FALSE);
97 result = NS_SUCCEEDED(res);
101 return result;
104 bool NpProxyService::UnInitialize() {
105 // Fail early if this was never created - we may not be running on FF.
106 if (!pref_service_)
107 return false;
109 // Unhook ourselves as an observer.
110 nsresult res = NS_ERROR_FAILURE;
111 if (observer_pref_branch_)
112 res = observer_pref_branch_->RemoveObserver(kProxyObserverBranch, this);
114 return NS_SUCCEEDED(res);
117 NS_IMETHODIMP NpProxyService::Observe(nsISupports* subject, const char* topic,
118 const PRUnichar* data) {
119 if (!subject || !topic) {
120 NOTREACHED();
121 return NS_ERROR_UNEXPECTED;
124 std::string topic_str(topic);
125 nsresult res = NS_OK;
126 if (topic_str == NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) {
127 // Looks like our proxy settings changed. We need to reload!
128 // I have observed some extremely strange behaviour here. Specifically,
129 // we are supposed to be able to QI |subject| and get from it an
130 // nsIPrefBranch from which we can query new values. This has erratic
131 // behaviour, specifically subject starts returning null on all member
132 // queries. So I am using the cached nsIPrefBranch2 (that we used to add
133 // the observer) to do the querying.
134 if (NS_SUCCEEDED(res)) {
135 if (!ReadProxySettings(observer_pref_branch_)) {
136 res = NS_ERROR_UNEXPECTED;
137 } else {
138 std::string proxy_settings;
139 if (GetProxyValueJSONString(&proxy_settings))
140 automation_client_->SetProxySettings(proxy_settings);
143 } else {
144 NOTREACHED();
147 return res;
150 std::string NpProxyService::GetStringPref(nsIPrefBranch* pref_branch,
151 const char* pref_name) {
152 nsCString pref_string;
153 std::string result;
154 nsresult rv = pref_branch->GetCharPref(pref_name, getter_Copies(pref_string));
155 if (SUCCEEDED(rv) && pref_string.get()) {
156 result = pref_string.get();
158 return result;
161 int NpProxyService::GetIntPref(nsIPrefBranch* pref_branch,
162 const char* pref_name) {
163 PRInt32 pref_int;
164 int result = kInvalidIntPref;
165 nsresult rv = pref_branch->GetIntPref(pref_name, &pref_int);
166 if (SUCCEEDED(rv)) {
167 result = pref_int;
169 return result;
172 bool NpProxyService::GetBoolPref(nsIPrefBranch* pref_branch,
173 const char* pref_name) {
174 PRBool pref_bool;
175 bool result = false;
176 nsresult rv = pref_branch->GetBoolPref(pref_name, &pref_bool);
177 if (SUCCEEDED(rv)) {
178 result = pref_bool == PR_TRUE;
180 return result;
183 void NpProxyService::Reset() {
184 type_ = PROXY_CONFIG_LAST;
185 auto_detect_ = false;
186 no_proxy_ = false;
187 system_config_ = false;
188 manual_proxies_.clear();
189 pac_url_.clear();
190 proxy_bypass_list_.clear();
193 bool NpProxyService::ReadProxySettings(nsIPrefBranch* pref_branch) {
194 DCHECK(pref_branch);
196 // Clear our current settings.
197 Reset();
198 type_ = GetIntPref(pref_branch, kProxyType);
199 if (type_ == kInvalidIntPref) {
200 NOTREACHED();
201 return false;
204 switch (type_) {
205 case PROXY_CONFIG_DIRECT:
206 case PROXY_CONFIG_DIRECT4X:
207 no_proxy_ = true;
208 break;
209 case PROXY_CONFIG_SYSTEM:
210 // _SYSTEM is documented as "Use system settings if available, otherwise
211 // DIRECT". It isn't clear under what circumstances system settings would
212 // be unavailable, but I'll special-case this nonetheless and have
213 // GetProxyValueJSONString() return empty if we get this proxy type.
214 DLOG(WARNING) << "Received PROXY_CONFIG_SYSTEM proxy type.";
215 system_config_ = true;
216 break;
217 case PROXY_CONFIG_WPAD:
218 auto_detect_ = true;
219 break;
220 case PROXY_CONFIG_PAC:
221 pac_url_ = GetStringPref(pref_branch, kProxyAutoconfigUrl);
222 break;
223 case PROXY_CONFIG_MANUAL:
224 // Read in the values for each of the known schemes.
225 for (int i = 0; i < arraysize(kProxyInfo); i++) {
226 ManualProxyEntry entry;
227 entry.url = GetStringPref(pref_branch, kProxyInfo[i].pref_name);
228 entry.port = GetIntPref(pref_branch, kProxyInfo[i].port_pref_name);
229 if (!entry.url.empty() && entry.port != kInvalidIntPref) {
230 entry.scheme = kProxyInfo[i].chrome_scheme;
231 manual_proxies_.push_back(entry);
235 // Also pick up the list of URLs we bypass proxies for.
236 proxy_bypass_list_ = GetStringPref(pref_branch, kProxyBypassList);
237 break;
238 default:
239 NOTREACHED();
240 return false;
242 return true;
245 DictionaryValue* NpProxyService::BuildProxyValueSet() {
246 scoped_ptr<DictionaryValue> proxy_settings_value(new DictionaryValue);
248 if (auto_detect_) {
249 proxy_settings_value->SetBoolean(automation::kJSONProxyAutoconfig,
250 auto_detect_);
253 if (no_proxy_) {
254 proxy_settings_value->SetBoolean(automation::kJSONProxyNoProxy, no_proxy_);
257 if (!pac_url_.empty()) {
258 proxy_settings_value->SetString(automation::kJSONProxyPacUrl, pac_url_);
261 if (!proxy_bypass_list_.empty()) {
262 proxy_settings_value->SetString(automation::kJSONProxyBypassList,
263 proxy_bypass_list_);
266 // Fill in the manual proxy settings. Build a string representation that
267 // corresponds to the format of the input parameter to
268 // ProxyConfig::ProxyRules::ParseFromString.
269 std::string manual_proxy_settings;
270 ManualProxyList::const_iterator iter(manual_proxies_.begin());
271 for (; iter != manual_proxies_.end(); iter++) {
272 DCHECK(!iter->scheme.empty());
273 DCHECK(!iter->url.empty());
274 DCHECK(iter->port != kInvalidIntPref);
275 manual_proxy_settings += iter->scheme;
276 manual_proxy_settings += "=";
277 manual_proxy_settings += iter->url;
278 manual_proxy_settings += ":";
279 manual_proxy_settings += base::IntToString(iter->port);
280 manual_proxy_settings += ";";
283 if (!manual_proxy_settings.empty()) {
284 proxy_settings_value->SetString(automation::kJSONProxyServer,
285 manual_proxy_settings);
288 return proxy_settings_value.release();
291 bool NpProxyService::GetProxyValueJSONString(std::string* output) {
292 DCHECK(output);
293 output->empty();
295 // If we detected a PROXY_CONFIG_SYSTEM config type or failed to obtain the
296 // pref service then return false here to make Chrome continue using its
297 // default proxy settings.
298 if (system_config_ || !pref_service_)
299 return false;
301 scoped_ptr<DictionaryValue> proxy_settings_value(BuildProxyValueSet());
303 JSONStringValueSerializer serializer(output);
304 return serializer.Serialize(*static_cast<Value*>(proxy_settings_value.get()));