Bug 971153 - Write a test for bug 751465. r=mcmanus
authorGeorg Koppen <gk@torproject.org>
Tue, 15 Apr 2014 22:13:00 +0200
changeset 198324 d8d1d9108f5617de45888431d458a72b1d635fa1
parent 198323 2c4a02a5c169721615220f666645b4a79b919d4f
child 198325 5d7dd6086a5a78f283cdf7f979395cd5cb357c25
push id486
push userasasaki@mozilla.com
push dateMon, 14 Jul 2014 18:39:42 +0000
treeherdermozilla-release@d33428174ff1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmcmanus
bugs971153, 751465
milestone31.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 971153 - Write a test for bug 751465. r=mcmanus This patch adds a) a test for the fixed proxy bypass in bug 751465 and makes b) some underlying changes to the nsDNSService to be able to write that test in the first place.
netwerk/dns/nsDNSService2.cpp
netwerk/dns/nsDNSService2.h
netwerk/test/unit/test_dns_proxy_bypass.js
netwerk/test/unit/xpcshell.ini
--- a/netwerk/dns/nsDNSService2.cpp
+++ b/netwerk/dns/nsDNSService2.cpp
@@ -25,34 +25,34 @@
 #include "prnetdb.h"
 #include "prmon.h"
 #include "prio.h"
 #include "plstr.h"
 #include "nsIOService.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsNetAddr.h"
 #include "nsProxyRelease.h"
-#include "nsIObserverService.h"
 
 #include "mozilla/Attributes.h"
 #include "mozilla/VisualEventTracer.h"
 #include "mozilla/net/NeckoCommon.h"
 #include "mozilla/net/ChildDNSService.h"
 #include "mozilla/net/DNSListenerProxy.h"
 
 using namespace mozilla;
 using namespace mozilla::net;
 
-static const char kPrefDnsCacheEntries[]    = "network.dnsCacheEntries";
-static const char kPrefDnsCacheExpiration[] = "network.dnsCacheExpiration";
-static const char kPrefDnsCacheGrace[]      = "network.dnsCacheExpirationGracePeriod";
-static const char kPrefIPv4OnlyDomains[]    = "network.dns.ipv4OnlyDomains";
-static const char kPrefDisableIPv6[]        = "network.dns.disableIPv6";
-static const char kPrefDisablePrefetch[]    = "network.dns.disablePrefetch";
-static const char kPrefDnsLocalDomains[]    = "network.dns.localDomains";
+static const char kPrefDnsCacheEntries[]     = "network.dnsCacheEntries";
+static const char kPrefDnsCacheExpiration[]  = "network.dnsCacheExpiration";
+static const char kPrefDnsCacheGrace[]       = "network.dnsCacheExpirationGracePeriod";
+static const char kPrefIPv4OnlyDomains[]     = "network.dns.ipv4OnlyDomains";
+static const char kPrefDisableIPv6[]         = "network.dns.disableIPv6";
+static const char kPrefDisablePrefetch[]     = "network.dns.disablePrefetch";
+static const char kPrefDnsLocalDomains[]     = "network.dns.localDomains";
+static const char kPrefDnsNotifyResolution[] = "network.dns.notifyResolution";
 
 //-----------------------------------------------------------------------------
 
 class nsDNSRecord : public nsIDNSRecord
 {
 public:
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSIDNSRECORD
@@ -390,16 +390,41 @@ nsDNSSyncRequest::SizeOfIncludingThis(Ma
 
     // Measurement of the following members may be added later if DMD finds it
     // is worthwhile:
     // - mMonitor
 
     return n;
 }
 
+class NotifyDNSResolution: public nsRunnable
+{
+public:
+    NotifyDNSResolution(nsMainThreadPtrHandle<nsIObserverService> &aObs,
+                        const nsACString &aHostname)
+        : mObs(aObs)
+        , mHostname(aHostname)
+    {
+        MOZ_ASSERT(mObs);
+    }
+
+    NS_IMETHOD Run()
+    {
+        MOZ_ASSERT(NS_IsMainThread());
+        mObs->NotifyObservers(nullptr,
+                              "dns-resolution-request",
+                              NS_ConvertUTF8toUTF16(mHostname).get());
+        return NS_OK;
+    }
+
+private:
+    nsMainThreadPtrHandle<nsIObserverService> mObs;
+    nsCString                                 mHostname;
+};
+
 //-----------------------------------------------------------------------------
 
 nsDNSService::nsDNSService()
     : mLock("nsDNSServer.mLock")
     , mFirstTime(true)
     , mOffline(false)
 {
 }
@@ -457,16 +482,17 @@ nsDNSService::Init()
 
     // prefs
     uint32_t maxCacheEntries  = 400;
     uint32_t maxCacheLifetime = 120; // seconds
     uint32_t lifetimeGracePeriod = 60; // seconds
     bool     disableIPv6      = false;
     bool     disablePrefetch  = false;
     int      proxyType        = nsIProtocolProxyService::PROXYCONFIG_DIRECT;
+    bool     notifyResolution = false;
 
     nsAdoptingCString ipv4OnlyDomains;
     nsAdoptingCString localDomains;
 
     // read prefs
     nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
     if (prefs) {
         int32_t val;
@@ -480,30 +506,32 @@ nsDNSService::Init()
         // ASSUMPTION: pref branch does not modify out params on failure
         prefs->GetBoolPref(kPrefDisableIPv6, &disableIPv6);
         prefs->GetCharPref(kPrefIPv4OnlyDomains, getter_Copies(ipv4OnlyDomains));
         prefs->GetCharPref(kPrefDnsLocalDomains, getter_Copies(localDomains));
         prefs->GetBoolPref(kPrefDisablePrefetch, &disablePrefetch);
 
         // If a manual proxy is in use, disable prefetch implicitly
         prefs->GetIntPref("network.proxy.type", &proxyType);
+        prefs->GetBoolPref(kPrefDnsNotifyResolution, &notifyResolution);
     }
 
     if (mFirstTime) {
         mFirstTime = false;
 
         // register as prefs observer
         if (prefs) {
             prefs->AddObserver(kPrefDnsCacheEntries, this, false);
             prefs->AddObserver(kPrefDnsCacheExpiration, this, false);
             prefs->AddObserver(kPrefDnsCacheGrace, this, false);
             prefs->AddObserver(kPrefIPv4OnlyDomains, this, false);
             prefs->AddObserver(kPrefDnsLocalDomains, this, false);
             prefs->AddObserver(kPrefDisableIPv6, this, false);
             prefs->AddObserver(kPrefDisablePrefetch, this, false);
+            prefs->AddObserver(kPrefDnsNotifyResolution, this, false);
 
             // Monitor these to see if there is a change in proxy configuration
             // If a manual proxy is in use, disable prefetch implicitly
             prefs->AddObserver("network.proxy.type", this, false);
         }
 
         nsresult rv;
         nsCOMPtr<nsIObserverService> observerService =
@@ -517,16 +545,19 @@ nsDNSService::Init()
 
     // Don't initialize the resolver if we're in offline mode.
     // Later on, the IO service will reinitialize us when going online.
     if (gIOService->IsOffline() && !gIOService->IsComingOnline())
         return NS_OK;
 
     nsCOMPtr<nsIIDNService> idn = do_GetService(NS_IDNSERVICE_CONTRACTID);
 
+    nsCOMPtr<nsIObserverService> obs =
+        do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
+
     nsRefPtr<nsHostResolver> res;
     nsresult rv = nsHostResolver::Create(maxCacheEntries,
                                          maxCacheLifetime,
                                          lifetimeGracePeriod,
                                          getter_AddRefs(res));
     if (NS_SUCCEEDED(rv)) {
         // now, set all of our member variables while holding the lock
         MutexAutoLock lock(mLock);
@@ -545,16 +576,21 @@ nsDNSService::Init()
             nsCharSeparatedTokenizer tokenizer(domains, ',',
                                                nsCharSeparatedTokenizerTemplate<>::SEPARATOR_OPTIONAL);
 
             while (tokenizer.hasMoreTokens()) {
                 const nsSubstring& domain = tokenizer.nextToken();
                 mLocalDomains.PutEntry(nsDependentCString(NS_ConvertUTF16toUTF8(domain).get()));
             }
         }
+        mNotifyResolution = notifyResolution;
+        if (mNotifyResolution) {
+            mObserverService =
+              new nsMainThreadPtrHolder<nsIObserverService>(obs);
+        }
     }
 
     RegisterWeakMemoryReporter(this);
 
     return rv;
 }
 
 NS_IMETHODIMP
@@ -620,16 +656,22 @@ nsDNSService::AsyncResolve(const nsACStr
 
         if (mDisablePrefetch && (flags & RESOLVE_SPECULATE))
             return NS_ERROR_DNS_LOOKUP_QUEUE_FULL;
 
         res = mResolver;
         idn = mIDN;
         localDomain = mLocalDomains.GetEntry(hostname);
     }
+
+    if (mNotifyResolution) {
+        NS_DispatchToMainThread(new NotifyDNSResolution(mObserverService,
+                                                        hostname));
+    }
+
     if (!res)
         return NS_ERROR_OFFLINE;
 
     if (mOffline)
         flags |= RESOLVE_OFFLINE;
 
     const nsACString *hostPtr = &hostname;
 
@@ -724,16 +766,22 @@ nsDNSService::Resolve(const nsACString &
     nsCOMPtr<nsIIDNService> idn;
     bool localDomain = false;
     {
         MutexAutoLock lock(mLock);
         res = mResolver;
         idn = mIDN;
         localDomain = mLocalDomains.GetEntry(hostname);
     }
+
+    if (mNotifyResolution) {
+        NS_DispatchToMainThread(new NotifyDNSResolution(mObserverService,
+                                                        hostname));
+    }
+
     NS_ENSURE_TRUE(res, NS_ERROR_OFFLINE);
 
     if (mOffline)
         flags |= RESOLVE_OFFLINE;
 
     const nsACString *hostPtr = &hostname;
 
     if (localDomain) {
--- a/netwerk/dns/nsDNSService2.h
+++ b/netwerk/dns/nsDNSService2.h
@@ -11,16 +11,18 @@
 #include "nsIIDNService.h"
 #include "nsIMemoryReporter.h"
 #include "nsIObserver.h"
 #include "nsHostResolver.h"
 #include "nsAutoPtr.h"
 #include "nsString.h"
 #include "nsTHashtable.h"
 #include "nsHashKeys.h"
+#include "nsIObserverService.h"
+#include "nsProxyRelease.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/Attributes.h"
 
 class nsDNSService MOZ_FINAL : public nsPIDNSService
                              , public nsIObserver
                              , public nsIMemoryReporter
 {
 public:
@@ -46,17 +48,19 @@ private:
     nsCOMPtr<nsIIDNService>   mIDN;
 
     // mLock protects access to mResolver and mIPv4OnlyDomains
     mozilla::Mutex            mLock;
 
     // mIPv4OnlyDomains is a comma-separated list of domains for which only
     // IPv4 DNS lookups are performed. This allows the user to disable IPv6 on
     // a per-domain basis and work around broken DNS servers. See bug 68796.
-    nsAdoptingCString         mIPv4OnlyDomains;
-    bool                      mDisableIPv6;
-    bool                      mDisablePrefetch;
-    bool                      mFirstTime;
-    bool                      mOffline;
-    nsTHashtable<nsCStringHashKey> mLocalDomains;
+    nsAdoptingCString                         mIPv4OnlyDomains;
+    bool                                      mDisableIPv6;
+    bool                                      mDisablePrefetch;
+    bool                                      mFirstTime;
+    bool                                      mOffline;
+    bool                                      mNotifyResolution;
+    nsMainThreadPtrHandle<nsIObserverService> mObserverService;
+    nsTHashtable<nsCStringHashKey>            mLocalDomains;
 };
 
 #endif //nsDNSService2_h__
new file mode 100644
--- /dev/null
+++ b/netwerk/test/unit/test_dns_proxy_bypass.js
@@ -0,0 +1,68 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+var ioService = Cc["@mozilla.org/network/io-service;1"].
+  getService(Ci.nsIIOService);
+
+var prefs = Cc["@mozilla.org/preferences-service;1"].
+  getService(Ci.nsIPrefBranch);
+
+var url = "ws://dnsleak.example.com";
+
+var dnsRequestObserver = {
+  register: function() {
+    this.obs = Cc["@mozilla.org/observer-service;1"].
+      getService(Ci.nsIObserverService);
+    this.obs.addObserver(this, "dns-resolution-request", false);
+  },
+
+  unregister: function() {
+    if (this.obs) {
+      this.obs.removeObserver(this, "dns-resolution-request");
+    }
+  },
+
+  observe: function(subject, topic, data) {
+    if (topic == "dns-resolution-request") {
+      do_print(data);
+      if (data.indexOf("dnsleak.example.com") > -1) {
+        try {
+          do_check_true(false);
+        } catch (e) {}
+      }
+    }
+  }
+};
+
+var listener = {
+  onAcknowledge: function(aContext, aSize) {},
+  onBinaryMessageAvailable: function(aContext, aMsg) {},
+  onMessageAvailable: function(aContext, aMsg) {},
+  onServerClose: function(aContext, aCode, aReason) {},
+  onStart: function(aContext) {},
+  onStop: function(aContext, aStatusCode) {
+    prefs.clearUserPref("network.proxy.socks");
+    prefs.clearUserPref("network.proxy.socks_port");
+    prefs.clearUserPref("network.proxy.type");
+    prefs.clearUserPref("network.proxy.socks_remote_dns");
+    prefs.clearUserPref("network.dns.notifyResolution");
+    dnsRequestObserver.unregister();
+    do_test_finished();
+  }
+};
+
+function run_test() {
+  dnsRequestObserver.register();
+  prefs.setBoolPref("network.dns.notifyResolution", true);
+  prefs.setCharPref("network.proxy.socks", "127.0.0.1");
+  prefs.setIntPref("network.proxy.socks_port", 9000);
+  prefs.setIntPref("network.proxy.type", 1);
+  prefs.setBoolPref("network.proxy.socks_remote_dns", true);
+  var chan = Cc["@mozilla.org/network/protocol;1?name=ws"].
+    createInstance(Components.interfaces.nsIWebSocketChannel);
+  var uri = ioService.newURI(url, null, null);
+  chan.asyncOpen(uri, url, listener, null);
+  do_test_pending();
+}
+
--- a/netwerk/test/unit/xpcshell.ini
+++ b/netwerk/test/unit/xpcshell.ini
@@ -186,16 +186,17 @@ skip-if = os == "android"
 [test_content_encoding_gzip.js]
 [test_content_sniffer.js]
 [test_cookie_header.js]
 [test_cookiejars.js]
 [test_cookiejars_safebrowsing.js]
 [test_data_protocol.js]
 [test_dns_service.js]
 [test_dns_localredirect.js]
+[test_dns_proxy_bypass.js]
 [test_duplicate_headers.js]
 [test_chunked_responses.js]
 [test_event_sink.js]
 [test_extract_charset_from_content_type.js]
 [test_force_sniffing.js]
 [test_fallback_no-cache-entry_canceled.js]
 [test_fallback_no-cache-entry_passing.js]
 [test_fallback_redirect-to-different-origin_canceled.js]