Bug 939318 - Have protocolproxy service act on network change. r=mcmanus
authorDaniel Stenberg <daniel@haxx.se>
Fri, 05 Sep 2014 09:29:00 -0400
changeset 230476 832f7125551e46f18bd51c7e57ad47fb85445b43
parent 230475 f83f8caccaf64dbaa7a6e08befd41675fab39625
child 230477 f4a3943388e15e43793365683c81c7008293c4da
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmcmanus
bugs939318
milestone35.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 939318 - Have protocolproxy service act on network change. r=mcmanus Reloads the PAC on network change, but avoids the reload if the specified PAC URL is a file: or a data: one - as those are not likely to have changed just because the network changed.
netwerk/base/src/nsProtocolProxyService.cpp
netwerk/base/src/nsProtocolProxyService.h
--- a/netwerk/base/src/nsProtocolProxyService.cpp
+++ b/netwerk/base/src/nsProtocolProxyService.cpp
@@ -24,16 +24,17 @@
 #include "nsNetUtil.h"
 #include "nsNetCID.h"
 #include "prnetdb.h"
 #include "nsPACMan.h"
 #include "nsProxyRelease.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/CondVar.h"
 #include "nsISystemProxySettings.h"
+#include "nsINetworkLinkService.h"
 
 //----------------------------------------------------------------------------
 
 namespace mozilla {
   extern const char kProxyType_HTTP[];
   extern const char kProxyType_HTTPS[];
   extern const char kProxyType_SOCKS[];
   extern const char kProxyType_SOCKS4[];
@@ -334,30 +335,30 @@ proxy_GetStringPref(nsIPrefBranch *aPref
 
 static void
 proxy_GetIntPref(nsIPrefBranch *aPrefBranch,
                  const char    *aPref,
                  int32_t       &aResult)
 {
     int32_t temp;
     nsresult rv = aPrefBranch->GetIntPref(aPref, &temp);
-    if (NS_FAILED(rv)) 
+    if (NS_FAILED(rv))
         aResult = -1;
     else
         aResult = temp;
 }
 
 static void
 proxy_GetBoolPref(nsIPrefBranch *aPrefBranch,
                  const char    *aPref,
                  bool          &aResult)
 {
     bool temp;
     nsresult rv = aPrefBranch->GetBoolPref(aPref, &temp);
-    if (NS_FAILED(rv)) 
+    if (NS_FAILED(rv))
         aResult = false;
     else
         aResult = temp;
 }
 
 //----------------------------------------------------------------------------
 
 static const int32_t PROXYCONFIG_DIRECT4X = 3;
@@ -409,24 +410,76 @@ nsProtocolProxyService::Init()
     if (prefBranch) {
         // monitor proxy prefs
         prefBranch->AddObserver(PROXY_PREF_BRANCH, this, false);
 
         // read all prefs
         PrefsChanged(prefBranch, nullptr);
     }
 
-    // register for shutdown notification so we can clean ourselves up properly.
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
-    if (obs)
+    if (obs) {
+        // register for shutdown notification so we can clean ourselves up
+        // properly.
         obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
 
+        obs->AddObserver(this, NS_NETWORK_LINK_TOPIC, false);
+    }
+
     return NS_OK;
 }
 
+// ReloadNetworkPAC() checks if there's a non-networked PAC in use then avoids
+// to call ReloadPAC()
+nsresult
+nsProtocolProxyService::ReloadNetworkPAC()
+{
+    nsCOMPtr<nsIPrefBranch> prefs =
+        do_GetService(NS_PREFSERVICE_CONTRACTID);
+    if (!prefs) {
+        return NS_OK;
+    }
+
+    int32_t type;
+    nsresult rv = prefs->GetIntPref(PROXY_PREF("type"), &type);
+    if (NS_FAILED(rv)) {
+        return NS_OK;
+    }
+
+    if (type == PROXYCONFIG_PAC) {
+        nsXPIDLCString pacSpec;
+        prefs->GetCharPref(PROXY_PREF("autoconfig_url"),
+                           getter_Copies(pacSpec));
+        if (!pacSpec.IsEmpty()) {
+            nsCOMPtr<nsIURI> pacURI;
+            rv = NS_NewURI(getter_AddRefs(pacURI), pacSpec);
+            if(!NS_SUCCEEDED(rv)) {
+                return rv;
+            }
+
+            nsProtocolInfo pac;
+            rv = GetProtocolInfo(pacURI, &pac);
+            if(!NS_SUCCEEDED(rv)) {
+                return rv;
+            }
+
+            if (!pac.scheme.EqualsLiteral("file") &&
+                !pac.scheme.EqualsLiteral("data")) {
+                LOG((": received network changed event, reload PAC"));
+                ReloadPAC();
+            }
+        }
+    } else if ((type == PROXYCONFIG_WPAD) || (type == PROXYCONFIG_SYSTEM)) {
+        ReloadPAC();
+    }
+
+    return NS_OK;
+}
+
+
 NS_IMETHODIMP
 nsProtocolProxyService::Observe(nsISupports     *aSubject,
                                 const char      *aTopic,
                                 const char16_t *aData)
 {
     if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
         // cleanup
         if (mHostFiltersArray.Length() > 0) {
@@ -435,16 +488,22 @@ nsProtocolProxyService::Observe(nsISuppo
         if (mFilters) {
             delete mFilters;
             mFilters = nullptr;
         }
         if (mPACMan) {
             mPACMan->Shutdown();
             mPACMan = nullptr;
         }
+    } else if (strcmp(aTopic, NS_NETWORK_LINK_TOPIC) == 0) {
+        nsCString converted = NS_ConvertUTF16toUTF8(aData);
+        const char *state = converted.get();
+        if (!strcmp(state, NS_NETWORK_LINK_DATA_CHANGED)) {
+            ReloadNetworkPAC();
+        }
     }
     else {
         NS_ASSERTION(strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0,
                      "what is this random observer event?");
         nsCOMPtr<nsIPrefBranch> prefs = do_QueryInterface(aSubject);
         if (prefs)
             PrefsChanged(prefs, NS_LossyConvertUTF16toASCII(aData).get());
     }
@@ -508,17 +567,17 @@ nsProtocolProxyService::PrefsChanged(nsI
     if (!pref || !strcmp(pref, PROXY_PREF("ftp")))
         proxy_GetStringPref(prefBranch, PROXY_PREF("ftp"), mFTPProxyHost);
 
     if (!pref || !strcmp(pref, PROXY_PREF("ftp_port")))
         proxy_GetIntPref(prefBranch, PROXY_PREF("ftp_port"), mFTPProxyPort);
 
     if (!pref || !strcmp(pref, PROXY_PREF("socks")))
         proxy_GetStringPref(prefBranch, PROXY_PREF("socks"), mSOCKSProxyHost);
-    
+
     if (!pref || !strcmp(pref, PROXY_PREF("socks_port")))
         proxy_GetIntPref(prefBranch, PROXY_PREF("socks_port"), mSOCKSProxyPort);
 
     if (!pref || !strcmp(pref, PROXY_PREF("socks_version"))) {
         int32_t version;
         proxy_GetIntPref(prefBranch, PROXY_PREF("socks_version"), version);
         // make sure this preference value remains sane
         if (version == 5)
@@ -582,24 +641,24 @@ nsProtocolProxyService::PrefsChanged(nsI
             mSystemProxySettings->GetPACURI(tempString);
         }
         if (!tempString.IsEmpty())
             ConfigureFromPAC(tempString, false);
     }
 }
 
 bool
-nsProtocolProxyService::CanUseProxy(nsIURI *aURI, int32_t defaultPort) 
+nsProtocolProxyService::CanUseProxy(nsIURI *aURI, int32_t defaultPort)
 {
     if (mHostFiltersArray.Length() == 0)
         return true;
 
     int32_t port;
     nsAutoCString host;
- 
+
     nsresult rv = aURI->GetAsciiHost(host);
     if (NS_FAILED(rv) || host.IsEmpty())
         return false;
 
     rv = aURI->GetPort(&port);
     if (NS_FAILED(rv))
         return false;
     if (port == -1)
@@ -619,17 +678,17 @@ nsProtocolProxyService::CanUseProxy(nsIU
             // copy the address
             memcpy(&ipv6, &addr.ipv6.ip, sizeof(PRIPv6Addr));
         }
         else {
             NS_WARNING("unknown address family");
             return true; // allow proxying
         }
     }
-    
+
     // Don't use proxy for local hosts (plain hostname, no dots)
     if (!is_ipaddr && mFilterLocalHosts && (kNotFound == host.FindChar('.'))) {
         LOG(("Not using proxy for this local host [%s]!\n", host.get()));
         return false; // don't allow proxying
     }
 
     int32_t index = -1;
     while (++index < int32_t(mHostFiltersArray.Length())) {
@@ -805,17 +864,17 @@ nsProtocolProxyService::GetProxyKey(nsPr
 {
     key.AssignASCII(pi->mType);
     if (!pi->mHost.IsEmpty()) {
         key.Append(' ');
         key.Append(pi->mHost);
         key.Append(':');
         key.AppendInt(pi->mPort);
     }
-} 
+}
 
 uint32_t
 nsProtocolProxyService::SecondsSinceSessionStart()
 {
     PRTime now = PR_Now();
 
     // get time elapsed since session start
     int64_t diff = now - mSessionStart;
@@ -1326,29 +1385,29 @@ nsProtocolProxyService::LoadHostFilters(
     if (mHostFiltersArray.Length() > 0) {
         mHostFiltersArray.Clear();
     }
 
     if (!filters)
         return; // fail silently...
 
     //
-    // filter  = ( host | domain | ipaddr ["/" mask] ) [":" port] 
+    // filter  = ( host | domain | ipaddr ["/" mask] ) [":" port]
     // filters = filter *( "," LWS filter)
     //
     // Reset mFilterLocalHosts - will be set to true if "<local>" is in pref string
     mFilterLocalHosts = false;
     while (*filters) {
         // skip over spaces and ,
         while (*filters && (*filters == ',' || IS_ASCII_SPACE(*filters)))
             filters++;
 
         const char *starthost = filters;
         const char *endhost = filters + 1; // at least that...
-        const char *portLocation = 0; 
+        const char *portLocation = 0;
         const char *maskLocation = 0;
 
         while (*endhost && (*endhost != ',' && !IS_ASCII_SPACE(*endhost))) {
             if (*endhost == ':')
                 portLocation = endhost;
             else if (*endhost == '/')
                 maskLocation = endhost;
             else if (*endhost == ']') // IPv6 address literals
--- a/netwerk/base/src/nsProtocolProxyService.h
+++ b/netwerk/base/src/nsProtocolProxyService.h
@@ -275,16 +275,17 @@ protected:
      * @param aProxy
      *        The proxy information
      */
     void MaybeDisableDNSPrefetch(nsIProxyInfo *aProxy);
 
 private:
     nsresult SetupPACThread();
     nsresult ResetPACThread();
+    nsresult ReloadNetworkPAC();
 
 public:
     // The Sun Forte compiler and others implement older versions of the
     // C++ standard's rules on access and nested classes.  These structs
     // need to be public in order to deal with those compilers.
 
     struct HostInfoIP {
         uint16_t   family;