| OLD | NEW | 
| (Empty) |  | 
 |    1 // Copyright (c) 2009 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. | 
 |    4  | 
 |    5 #include "base/string_util.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" | 
 |   10  | 
 |   11 #include "net/proxy/proxy_config.h" | 
 |   12  | 
 |   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" | 
 |   17  | 
 |   18 ASSOCIATE_IID(NS_IOBSERVERSERVICE_IID_STR, nsIObserverService); | 
 |   19 ASSOCIATE_IID(NS_IPREFBRANCH_IID_STR, nsIPrefBranch); | 
 |   20  | 
 |   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"; | 
 |   27  | 
 |   28 const int kInvalidIntPref = -1; | 
 |   29  | 
 |   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"} }; | 
 |   37  | 
 |   38 NpProxyService::NpProxyService(void) | 
 |   39     : type_(PROXY_CONFIG_LAST), auto_detect_(false), no_proxy_(false), | 
 |   40       system_config_(false), automation_client_(NULL) { | 
 |   41 } | 
 |   42  | 
 |   43 NpProxyService::~NpProxyService(void) { | 
 |   44 } | 
 |   45  | 
 |   46 bool NpProxyService::Initialize(NPP instance, | 
 |   47     ChromeFrameAutomationClient* automation_client) { | 
 |   48   DCHECK(automation_client); | 
 |   49   automation_client_ = automation_client; | 
 |   50  | 
 |   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_); | 
 |   67       } | 
 |   68     } | 
 |   69   } | 
 |   70   return result; | 
 |   71 } | 
 |   72  | 
 |   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; | 
 |   82  | 
 |   83   pref_service->ReadUserPrefs(nsnull); | 
 |   84   pref_service->GetBranch(kProxyObserverRoot, pref_branch.Receive()); | 
 |   85  | 
 |   86   if (!pref_branch) { | 
 |   87     DLOG(ERROR) << "Failed to get nsIPrefBranch"; | 
 |   88   } else { | 
 |   89     if (!ReadProxySettings(pref_branch.get())) { | 
 |   90       DLOG(ERROR) << "Could not read proxy settings."; | 
 |   91     } else { | 
 |   92       observer_pref_branch_.QueryFrom(pref_branch); | 
 |   93       if (!observer_pref_branch_) { | 
 |   94         DLOG(ERROR) << "Failed to get observer nsIPrefBranch2"; | 
 |   95       } else { | 
 |   96         nsresult res = observer_pref_branch_->AddObserver(kProxyObserverBranch, | 
 |   97                                                           this, PR_FALSE); | 
 |   98         result = NS_SUCCEEDED(res); | 
 |   99       } | 
 |  100     } | 
 |  101   } | 
 |  102   return result; | 
 |  103 } | 
 |  104  | 
 |  105 bool NpProxyService::UnInitialize() { | 
 |  106   // Fail early if this was never created - we may not be running on FF. | 
 |  107   if (!pref_service_) | 
 |  108     return false; | 
 |  109  | 
 |  110   // Unhook ourselves as an observer. | 
 |  111   nsresult res = NS_ERROR_FAILURE; | 
 |  112   if (observer_pref_branch_) | 
 |  113     res = observer_pref_branch_->RemoveObserver(kProxyObserverBranch, this); | 
 |  114  | 
 |  115   return NS_SUCCEEDED(res); | 
 |  116 } | 
 |  117  | 
 |  118 NS_IMETHODIMP NpProxyService::Observe(nsISupports* subject, const char* topic, | 
 |  119                                      const PRUnichar* data) { | 
 |  120   if (!subject || !topic) { | 
 |  121     NOTREACHED(); | 
 |  122     return NS_ERROR_UNEXPECTED; | 
 |  123   } | 
 |  124  | 
 |  125   std::string topic_str(topic); | 
 |  126   nsresult res = NS_OK; | 
 |  127   if (topic_str == NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) { | 
 |  128     // Looks like our proxy settings changed. We need to reload! | 
 |  129     // I have observed some extremely strange behaviour here. Specifically, | 
 |  130     // we are supposed to be able to QI |subject| and get from it an | 
 |  131     // nsIPrefBranch from which we can query new values. This has erratic | 
 |  132     // behaviour, specifically subject starts returning null on all member | 
 |  133     // queries. So I am using the cached nsIPrefBranch2 (that we used to add | 
 |  134     // the observer) to do the querying. | 
 |  135     if (NS_SUCCEEDED(res)) { | 
 |  136       if (!ReadProxySettings(observer_pref_branch_)) { | 
 |  137         res = NS_ERROR_UNEXPECTED; | 
 |  138       } else { | 
 |  139         std::string proxy_settings; | 
 |  140         if (GetProxyValueJSONString(&proxy_settings)) | 
 |  141           automation_client_->SetProxySettings(proxy_settings); | 
 |  142       } | 
 |  143     } | 
 |  144   } else { | 
 |  145     NOTREACHED(); | 
 |  146   } | 
 |  147  | 
 |  148   return res; | 
 |  149 } | 
 |  150  | 
 |  151 std::string NpProxyService::GetStringPref(nsIPrefBranch* pref_branch, | 
 |  152                                          const char* pref_name) { | 
 |  153   nsCString pref_string; | 
 |  154   std::string result; | 
 |  155   nsresult rv = pref_branch->GetCharPref(pref_name, getter_Copies(pref_string)); | 
 |  156   if (SUCCEEDED(rv) && pref_string.get()) { | 
 |  157     result = pref_string.get(); | 
 |  158   } | 
 |  159   return result; | 
 |  160 } | 
 |  161  | 
 |  162 int NpProxyService::GetIntPref(nsIPrefBranch* pref_branch, | 
 |  163                               const char* pref_name) { | 
 |  164   PRInt32 pref_int; | 
 |  165   int result = kInvalidIntPref; | 
 |  166   nsresult rv = pref_branch->GetIntPref(pref_name, &pref_int); | 
 |  167   if (SUCCEEDED(rv)) { | 
 |  168     result = pref_int; | 
 |  169   } | 
 |  170   return result; | 
 |  171 } | 
 |  172  | 
 |  173 bool NpProxyService::GetBoolPref(nsIPrefBranch* pref_branch, | 
 |  174                                 const char* pref_name) { | 
 |  175   PRBool pref_bool; | 
 |  176   bool result = false; | 
 |  177   nsresult rv = pref_branch->GetBoolPref(pref_name, &pref_bool); | 
 |  178   if (SUCCEEDED(rv)) { | 
 |  179     result = pref_bool == PR_TRUE; | 
 |  180   } | 
 |  181   return result; | 
 |  182 } | 
 |  183  | 
 |  184 void NpProxyService::Reset() { | 
 |  185   type_ = PROXY_CONFIG_LAST; | 
 |  186   auto_detect_ = false; | 
 |  187   no_proxy_ = false; | 
 |  188   system_config_ = false; | 
 |  189   manual_proxies_.clear(); | 
 |  190   pac_url_.clear(); | 
 |  191   proxy_bypass_list_.clear(); | 
 |  192 } | 
 |  193  | 
 |  194 bool NpProxyService::ReadProxySettings(nsIPrefBranch* pref_branch) { | 
 |  195   DCHECK(pref_branch); | 
 |  196  | 
 |  197   // Clear our current settings. | 
 |  198   Reset(); | 
 |  199   type_ = GetIntPref(pref_branch, kProxyType); | 
 |  200   if (type_ == kInvalidIntPref) { | 
 |  201     NOTREACHED(); | 
 |  202     return false; | 
 |  203   } | 
 |  204  | 
 |  205   switch (type_) { | 
 |  206     case PROXY_CONFIG_DIRECT: | 
 |  207     case PROXY_CONFIG_DIRECT4X: | 
 |  208       no_proxy_ = true; | 
 |  209       break; | 
 |  210     case PROXY_CONFIG_SYSTEM: | 
 |  211       // _SYSTEM is documented as "Use system settings if available, otherwise | 
 |  212       // DIRECT". It isn't clear under what circumstances system settings would | 
 |  213       // be unavailable, but I'll special-case this nonetheless and have | 
 |  214       // GetProxyValueJSONString() return empty if we get this proxy type. | 
 |  215       DLOG(WARNING) << "Received PROXY_CONFIG_SYSTEM proxy type."; | 
 |  216       system_config_ = true; | 
 |  217       break; | 
 |  218     case PROXY_CONFIG_WPAD: | 
 |  219       auto_detect_ = true; | 
 |  220       break; | 
 |  221     case PROXY_CONFIG_PAC: | 
 |  222       pac_url_ = GetStringPref(pref_branch, kProxyAutoconfigUrl); | 
 |  223       break; | 
 |  224     case PROXY_CONFIG_MANUAL: | 
 |  225       // Read in the values for each of the known schemes. | 
 |  226       for (int i = 0; i < arraysize(kProxyInfo); i++) { | 
 |  227         ManualProxyEntry entry; | 
 |  228         entry.url = GetStringPref(pref_branch, kProxyInfo[i].pref_name); | 
 |  229         entry.port = GetIntPref(pref_branch, kProxyInfo[i].port_pref_name); | 
 |  230         if (!entry.url.empty() && entry.port != kInvalidIntPref) { | 
 |  231           entry.scheme = kProxyInfo[i].chrome_scheme; | 
 |  232           manual_proxies_.push_back(entry); | 
 |  233         } | 
 |  234       } | 
 |  235  | 
 |  236       // Also pick up the list of URLs we bypass proxies for. | 
 |  237       proxy_bypass_list_ = GetStringPref(pref_branch, kProxyBypassList); | 
 |  238       break; | 
 |  239     default: | 
 |  240       NOTREACHED(); | 
 |  241       return false; | 
 |  242   } | 
 |  243   return true; | 
 |  244 } | 
 |  245  | 
 |  246 DictionaryValue* NpProxyService::BuildProxyValueSet() { | 
 |  247   scoped_ptr<DictionaryValue> proxy_settings_value(new DictionaryValue); | 
 |  248  | 
 |  249   if (auto_detect_) { | 
 |  250     proxy_settings_value->SetBoolean(automation::kJSONProxyAutoconfig, | 
 |  251                                      auto_detect_); | 
 |  252   } | 
 |  253  | 
 |  254   if (no_proxy_) { | 
 |  255     proxy_settings_value->SetBoolean(automation::kJSONProxyNoProxy, no_proxy_); | 
 |  256   } | 
 |  257  | 
 |  258   if (!pac_url_.empty()) { | 
 |  259     proxy_settings_value->SetString(automation::kJSONProxyPacUrl, pac_url_); | 
 |  260   } | 
 |  261  | 
 |  262   if (!proxy_bypass_list_.empty()) { | 
 |  263     proxy_settings_value->SetString(automation::kJSONProxyBypassList, | 
 |  264                                     proxy_bypass_list_); | 
 |  265   } | 
 |  266  | 
 |  267   // Fill in the manual proxy settings. Build a string representation that | 
 |  268   // corresponds to the format of the input parameter to | 
 |  269   // ProxyConfig::ProxyRules::ParseFromString. | 
 |  270   std::string manual_proxy_settings; | 
 |  271   ManualProxyList::const_iterator iter(manual_proxies_.begin()); | 
 |  272   for (; iter != manual_proxies_.end(); iter++) { | 
 |  273     DCHECK(!iter->scheme.empty()); | 
 |  274     DCHECK(!iter->url.empty()); | 
 |  275     DCHECK(iter->port != kInvalidIntPref); | 
 |  276     manual_proxy_settings += iter->scheme; | 
 |  277     manual_proxy_settings += "="; | 
 |  278     manual_proxy_settings += iter->url; | 
 |  279     manual_proxy_settings += ":"; | 
 |  280     manual_proxy_settings += IntToString(iter->port); | 
 |  281     manual_proxy_settings += ";"; | 
 |  282   } | 
 |  283  | 
 |  284   if (!manual_proxy_settings.empty()) { | 
 |  285     proxy_settings_value->SetString(automation::kJSONProxyServer, | 
 |  286                                     manual_proxy_settings); | 
 |  287   } | 
 |  288  | 
 |  289   return proxy_settings_value.release(); | 
 |  290 } | 
 |  291  | 
 |  292 bool NpProxyService::GetProxyValueJSONString(std::string* output) { | 
 |  293   DCHECK(output); | 
 |  294   output->empty(); | 
 |  295  | 
 |  296   // If we detected a PROXY_CONFIG_SYSTEM config type or failed to obtain the | 
 |  297   // pref service then return false here to make Chrome continue using its | 
 |  298   // default proxy settings. | 
 |  299   if (system_config_ || !pref_service_) | 
 |  300     return false; | 
 |  301  | 
 |  302   scoped_ptr<DictionaryValue> proxy_settings_value(BuildProxyValueSet()); | 
 |  303  | 
 |  304   JSONStringValueSerializer serializer(output); | 
 |  305   return serializer.Serialize(*static_cast<Value*>(proxy_settings_value.get())); | 
 |  306 } | 
| OLD | NEW |