Bug 939318 - Have protocolproxy service act on network change. r=mcmanus
☠☠ backed out by 74b6974b351c ☠ ☠
authorDaniel Stenberg <daniel@haxx.se>
Fri, 05 Sep 2014 09:29:00 -0400
changeset 207036 20ae968df114a6891e3af1456937efd68515222a
parent 207035 0a066b7ffa46c292ab161949d2c647a659d6070c
child 207037 a7f522902e40ad9f6bdd809067e6091b5937491c
push id27544
push userryanvm@gmail.com
push dateWed, 24 Sep 2014 21:10:36 +0000
treeherdermozilla-central@1735ff2bb23e [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;