bug 507578 - disable dns prefetch in presence of active proxy r=jduell
authorPatrick McManus <mcmanus@ducksong.com>
Fri, 14 Sep 2012 16:27:46 -0400
changeset 108322 a41f9fff4cd15649b4d7254c6559373ac74d15e8
parent 108321 dcae72a1333c8dec3f61f1287f4bcd0127279c04
child 108323 345ebb6f3f3e30e965c608e1e504317c929a1ca8
push id23552
push userryanvm@gmail.com
push dateFri, 28 Sep 2012 03:05:08 +0000
treeherdermozilla-central@2d96ee8d9dd4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjduell
bugs507578
milestone18.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 507578 - disable dns prefetch in presence of active proxy r=jduell
modules/libpref/src/init/all.js
netwerk/base/src/nsProtocolProxyService.cpp
netwerk/base/src/nsProtocolProxyService.h
netwerk/dns/nsDNSService2.cpp
netwerk/dns/nsPIDNSService.idl
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -1116,16 +1116,19 @@ pref("network.dns.ipv4OnlyDomains", "");
 // This preference can be used to turn off IPv6 name lookups. See bug 68796.
 pref("network.dns.disableIPv6", false);
 
 // The grace period allows the DNS cache to use expired entries, while kicking off
 // a revalidation in the background. In seconds, but rounded to minutes in gecko.
 // Default to 30 days. (basically forever)
 pref("network.dnsCacheExpirationGracePeriod", 2592000);
 
+// This preference can be used to turn off DNS prefetch.
+pref("network.dns.disablePrefetch", false);
+
 // This preference controls whether or not URLs with UTF-8 characters are
 // escaped.  Set this preference to TRUE for strict RFC2396 conformance.
 pref("network.standard-url.escape-utf8", true);
 
 // This preference controls whether or not URLs are always encoded and sent as
 // UTF-8.
 pref("network.standard-url.encode-utf8", true);
 
--- a/netwerk/base/src/nsProtocolProxyService.cpp
+++ b/netwerk/base/src/nsProtocolProxyService.cpp
@@ -13,16 +13,17 @@
 #include "nsIServiceManager.h"
 #include "nsXPIDLString.h"
 #include "nsIIOService.h"
 #include "nsIObserverService.h"
 #include "nsIProtocolHandler.h"
 #include "nsIProtocolProxyCallback.h"
 #include "nsICancelable.h"
 #include "nsIDNSService.h"
+#include "nsPIDNSService.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 #include "nsReadableUtils.h"
 #include "nsThreadUtils.h"
 #include "nsString.h"
 #include "nsNetUtil.h"
 #include "nsNetCID.h"
 #include "nsCRT.h"
@@ -195,16 +196,18 @@ private:
             nsProtocolInfo info;
             mStatus = mPPS->GetProtocolInfo(mURI, &info);
             if (NS_SUCCEEDED(mStatus))
                 mPPS->ApplyFilters(mURI, info, mProxyInfo);
             else
                 mProxyInfo = nullptr;
 
             LOG(("pac thread callback %s\n", mPACString.get()));
+            if (NS_SUCCEEDED(mStatus))
+                mPPS->MaybeDisableDNSPrefetch(mProxyInfo);
             mCallback->OnProxyAvailable(this, mURI, mProxyInfo, mStatus);
         }
         else if (NS_SUCCEEDED(mStatus) && !mPACURL.IsEmpty()) {
             LOG(("pac thread callback indicates new pac file load\n"));
 
             // trigger load of new pac url
             nsresult rv = mPPS->ConfigureFromPAC(mPACURL, false);
             if (NS_SUCCEEDED(rv)) {
@@ -217,16 +220,18 @@ private:
             if (NS_FAILED(rv))
                 mCallback->OnProxyAvailable(this, mURI, nullptr, rv);
 
             // do not call onproxyavailable() in SUCCESS case - the newRequest will
             // take care of that
         }
         else {
             LOG(("pac thread callback did not provide information %X\n", mStatus));
+            if (NS_SUCCEEDED(mStatus))
+                mPPS->MaybeDisableDNSPrefetch(mProxyInfo);
             mCallback->OnProxyAvailable(this, mURI, mProxyInfo, mStatus);
         }
 
         // We are on the main thread now and don't need these any more so
         // release them to avoid having to proxy them back to the main thread
         // in the dtor
         mCallback = nullptr;  // in case the callback holds an owning ref to us
         mPPS = nullptr;
@@ -1600,16 +1605,40 @@ nsProtocolProxyService::Resolve_Internal
         if (NS_FAILED(rv))
             return rv;
     }
 
     return NS_OK;
 }
 
 void
+nsProtocolProxyService::MaybeDisableDNSPrefetch(nsIProxyInfo *aProxy)
+{
+    // Disable Prefetch in the DNS service if a proxy is in use.
+    if (!aProxy)
+        return;
+
+    nsCOMPtr<nsProxyInfo> pi = do_QueryInterface(aProxy);
+    if (!pi ||
+        !pi->mType ||
+        pi->mType == kProxyType_DIRECT)
+        return;
+
+    nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
+    if (!dns)
+        return;
+    nsCOMPtr<nsPIDNSService> pdns = do_QueryInterface(dns);
+    if (!pdns)
+        return;
+
+    // We lose the prefetch optimization for the life of the dns service.
+    pdns->SetPrefetchEnabled(false);
+}
+
+void
 nsProtocolProxyService::ApplyFilters(nsIURI *uri, const nsProtocolInfo &info,
                                      nsIProxyInfo **list)
 {
     if (!(info.flags & nsIProtocolHandler::ALLOWS_PROXY))
         return;
 
     // We prune the proxy list prior to invoking each filter.  This may be
     // somewhat inefficient, but it seems like a good idea since we want each
--- a/netwerk/base/src/nsProtocolProxyService.h
+++ b/netwerk/base/src/nsProtocolProxyService.h
@@ -266,16 +266,24 @@ protected:
      *        The URI to test.
      * @param defaultPort
      *        The default port for the given URI.
      *
      * @return True if the URI can use the specified proxy.
      */
     NS_HIDDEN_(bool) CanUseProxy(nsIURI *uri, int32_t defaultPort);
 
+    /**
+     * Disable Prefetch in the DNS service if a proxy is in use.
+     *
+     * @param aProxy
+     *        The proxy information
+     */
+    NS_HIDDEN_(void) MaybeDisableDNSPrefetch(nsIProxyInfo *aProxy);
+
 private:
     nsresult SetupPACThread();
     nsresult ResetPACThread();
 
 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.
--- a/netwerk/dns/nsDNSService2.cpp
+++ b/netwerk/dns/nsDNSService2.cpp
@@ -491,16 +491,30 @@ nsDNSService::GetOffline(bool *offline)
 
 NS_IMETHODIMP
 nsDNSService::SetOffline(bool offline)
 {
     mOffline = offline;
     return NS_OK;
 }
 
+NS_IMETHODIMP
+nsDNSService::GetPrefetchEnabled(bool *outVal)
+{
+    *outVal = !mDisablePrefetch;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDNSService::SetPrefetchEnabled(bool inVal)
+{
+    mDisablePrefetch = !inVal;
+    return NS_OK;
+}
+
 namespace {
 
 class DNSListenerProxy MOZ_FINAL : public nsIDNSListener
 {
 public:
   DNSListenerProxy(nsIDNSListener* aListener, nsIEventTarget* aTargetThread)
     : mListener(aListener)
     , mTargetThread(aTargetThread)
--- a/netwerk/dns/nsPIDNSService.idl
+++ b/netwerk/dns/nsPIDNSService.idl
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIDNSService.idl"
 
 /**
  * This is a private interface used by the internals of the networking library.
  * It will never be frozen.  Do not use it in external code.
  */
-[scriptable, uuid(26bd9b9e-90c3-11e1-981c-001fbc092072)]
+[scriptable, uuid(6b16fb1f-5709-4c94-a89f-a22be873c54d)]
 interface nsPIDNSService : nsIDNSService
 {
     /**
      * called to initialize the DNS service.
      */
     void init();
 
     /**
@@ -23,12 +23,17 @@ interface nsPIDNSService : nsIDNSService
      * requests will be canceled, and the local cache of DNS records
      * will be cleared.  NOTE: the operating system may still have
      * its own cache of DNS records, which would be unaffected by
      * this method.
      */
     void shutdown();
 
     /**
+     * Whether or not DNS prefetching (aka RESOLVE_SPECULATE) is enabled
+     */
+    attribute boolean prefetchEnabled;
+
+    /**
      * @return whether the DNS service is offline.
      */
     attribute boolean offline;
 };