From 73e28830abd52806d597988e63ace05ee6a32c31 Mon Sep 17 00:00:00 2001 From: Riccardo Mottola Date: Thu, 15 Aug 2019 10:01:03 +0200 Subject: [PATCH] bug 967792 - make localhost resolve offline r=dragana --- dom/base/test/unit/test_error_codes.js | 5 ++ modules/libpref/init/all.js | 3 + netwerk/dns/nsDNSService2.cpp | 22 ++++-- netwerk/dns/nsDNSService2.h | 1 + netwerk/test/unit/test_dns_offline.js | 74 +++++++++++++++++++ netwerk/test/unit/xpcshell.ini | 1 + ...test_errorhandler_sync_checkServerError.js | 2 + 7 files changed, 101 insertions(+), 7 deletions(-) create mode 100644 netwerk/test/unit/test_dns_offline.js diff --git a/dom/base/test/unit/test_error_codes.js b/dom/base/test/unit/test_error_codes.js index 737241a7517..c4f488f1892 100755 --- a/dom/base/test/unit/test_error_codes.js +++ b/dom/base/test/unit/test_error_codes.js @@ -6,6 +6,9 @@ var gExpectedStatus = null; var gNextTestFunc = null; +var prefs = Components.classes["@mozilla.org/preferences-service;1"]. + getService(Components.interfaces.nsIPrefBranch); + var asyncXHR = { load: function() { var request = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"] @@ -39,6 +42,7 @@ function run_test_pt1() { catch (e) { } ioService.offline = true; + prefs.setBoolPref("network.dns.offline-localhost", false); gExpectedStatus = Components.results.NS_ERROR_OFFLINE; gNextTestFunc = run_test_pt2; @@ -51,6 +55,7 @@ function run_test_pt2() { var ioService = Components.classes["@mozilla.org/network/io-service;1"] .getService(Components.interfaces.nsIIOService); ioService.offline = false; + prefs.clearUserPref("network.dns.offline-localhost"); gExpectedStatus = Components.results.NS_ERROR_CONNECTION_REFUSED; gNextTestFunc = end_test; diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 9308afe89fa..d33a9b45cf6 100755 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -1897,6 +1897,9 @@ pref("network.dnsCacheExpirationGracePeriod", 300); // This preference can be used to turn off DNS prefetch. pref("network.dns.disablePrefetch", true); +// Contols whether or not "localhost" should resolve when offline +pref("network.dns.offline-localhost", true); + // 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); diff --git a/netwerk/dns/nsDNSService2.cpp b/netwerk/dns/nsDNSService2.cpp index 393bb388b3b..19ad8298917 100755 --- a/netwerk/dns/nsDNSService2.cpp +++ b/netwerk/dns/nsDNSService2.cpp @@ -50,6 +50,7 @@ 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 kPrefDnsOfflineLocalhost[] = "network.dns.offline-localhost"; static const char kPrefDnsNotifyResolution[] = "network.dns.notifyResolution"; //----------------------------------------------------------------------------- @@ -535,12 +536,12 @@ nsDNSService::Init() if (mResolver) return NS_OK; NS_ENSURE_TRUE(!mResolver, NS_ERROR_ALREADY_INITIALIZED); - // prefs uint32_t maxCacheEntries = 400; uint32_t defaultCacheLifetime = 120; // seconds uint32_t defaultGracePeriod = 60; // seconds bool disableIPv6 = false; + bool offlineLocalhost = true; bool disablePrefetch = false; int proxyType = nsIProtocolProxyService::PROXYCONFIG_DIRECT; bool notifyResolution = false; @@ -563,6 +564,7 @@ nsDNSService::Init() prefs->GetBoolPref(kPrefDisableIPv6, &disableIPv6); prefs->GetCharPref(kPrefIPv4OnlyDomains, getter_Copies(ipv4OnlyDomains)); prefs->GetCharPref(kPrefDnsLocalDomains, getter_Copies(localDomains)); + prefs->GetBoolPref(kPrefDnsOfflineLocalhost, &offlineLocalhost); prefs->GetBoolPref(kPrefDisablePrefetch, &disablePrefetch); // If a manual proxy is in use, disable prefetch implicitly @@ -581,6 +583,7 @@ nsDNSService::Init() prefs->AddObserver(kPrefIPv4OnlyDomains, this, false); prefs->AddObserver(kPrefDnsLocalDomains, this, false); prefs->AddObserver(kPrefDisableIPv6, this, false); + prefs->AddObserver(kPrefDnsOfflineLocalhost, this, false); prefs->AddObserver(kPrefDisablePrefetch, this, false); prefs->AddObserver(kPrefDnsNotifyResolution, this, false); @@ -621,6 +624,7 @@ nsDNSService::Init() mResolver = res; mIDN = idn; mIPv4OnlyDomains = ipv4OnlyDomains; // exchanges buffer ownership + mOfflineLocalhost = offlineLocalhost; mDisableIPv6 = disableIPv6; // Disable prefetching either by explicit preference or if a manual proxy is configured @@ -753,13 +757,15 @@ nsDNSService::AsyncResolveExtended(const nsACString &aHostname, if (!res) return NS_ERROR_OFFLINE; - if (mOffline) - flags |= RESOLVE_OFFLINE; - nsCString hostname; if (!PreprocessHostname(localDomain, aHostname, idn, hostname)) return NS_ERROR_FAILURE; + if (mOffline && + (!mOfflineLocalhost || !hostname.LowerCaseEqualsASCII("localhost"))) { + flags |= RESOLVE_OFFLINE; + } + // make sure JS callers get notification on the main thread nsCOMPtr wrappedListener = do_QueryInterface(listener); if (wrappedListener && !target) { @@ -867,13 +873,15 @@ nsDNSService::Resolve(const nsACString &aHostname, NS_ENSURE_TRUE(res, NS_ERROR_OFFLINE); - if (mOffline) - flags |= RESOLVE_OFFLINE; - nsCString hostname; if (!PreprocessHostname(localDomain, aHostname, idn, hostname)) return NS_ERROR_FAILURE; + if (mOffline && + (!mOfflineLocalhost || !hostname.LowerCaseEqualsASCII("localhost"))) { + flags |= RESOLVE_OFFLINE; + } + // // sync resolve: since the host resolver only works asynchronously, we need // to use a mutex and a condvar to wait for the result. however, since the diff --git a/netwerk/dns/nsDNSService2.h b/netwerk/dns/nsDNSService2.h index b5c4f5d8c9b..39add3d4e50 100755 --- a/netwerk/dns/nsDNSService2.h +++ b/netwerk/dns/nsDNSService2.h @@ -60,6 +60,7 @@ class nsDNSService final : public nsPIDNSService bool mFirstTime; bool mOffline; bool mNotifyResolution; + bool mOfflineLocalhost; nsMainThreadPtrHandle mObserverService; nsTHashtable mLocalDomains; }; diff --git a/netwerk/test/unit/test_dns_offline.js b/netwerk/test/unit/test_dns_offline.js new file mode 100644 index 00000000000..87a9ad8b1e3 --- /dev/null +++ b/netwerk/test/unit/test_dns_offline.js @@ -0,0 +1,74 @@ +var dns = Cc["@mozilla.org/network/dns-service;1"].getService(Ci.nsIDNSService); +var ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); +var prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch); +var threadManager = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager); +var mainThread = threadManager.currentThread; + +var listener1 = { + onLookupComplete: function(inRequest, inRecord, inStatus) { + do_check_eq(inStatus, Cr.NS_ERROR_OFFLINE); + test2(); + do_test_finished(); + } +}; + +var listener2 = { + onLookupComplete: function(inRequest, inRecord, inStatus) { + do_check_eq(inStatus, Cr.NS_OK); + var answer = inRecord.getNextAddrAsString(); + do_check_true(answer == "127.0.0.1" || answer == "::1"); + test3(); + do_test_finished(); + } +}; + +var listener3 = { + onLookupComplete: function(inRequest, inRecord, inStatus) { + do_check_eq(inStatus, Cr.NS_OK); + var answer = inRecord.getNextAddrAsString(); + do_check_true(answer == "127.0.0.1" || answer == "::1"); + cleanup(); + do_test_finished(); + } +}; + +function run_test() { + do_test_pending(); + prefs.setBoolPref("network.dns.offline-localhost", false); + ioService.offline = true; + try { + dns.asyncResolve("localhost", 0, listener1, mainThread); + } catch (e) { + do_check_eq(e.result, Cr.NS_ERROR_OFFLINE); + test2(); + do_test_finished(); + } +} + +function test2() { + do_test_pending(); + prefs.setBoolPref("network.dns.offline-localhost", true); + ioService.offline = false; + ioService.offline = true; + // we need to let the main thread run and apply the changes + do_timeout(0, test2Continued); +} + +function test2Continued() { + dns.asyncResolve("localhost", 0, listener2, mainThread); +} + +function test3() { + do_test_pending(); + ioService.offline = false; + // we need to let the main thread run and apply the changes + do_timeout(0, test3Continued); +} + +function test3Continued() { + dns.asyncResolve("localhost", 0, listener3, mainThread); +} + +function cleanup() { + prefs.clearUserPref("network.dns.offline-localhost"); +} diff --git a/netwerk/test/unit/xpcshell.ini b/netwerk/test/unit/xpcshell.ini index b1182f3ea95..8fbba9f629c 100755 --- a/netwerk/test/unit/xpcshell.ini +++ b/netwerk/test/unit/xpcshell.ini @@ -177,6 +177,7 @@ skip-if = bits != 32 [test_dns_per_interface.js] [test_data_protocol.js] [test_dns_service.js] +[test_dns_offline.js] [test_dns_localredirect.js] [test_dns_proxy_bypass.js] [test_duplicate_headers.js] diff --git a/services/sync/tests/unit/test_errorhandler_sync_checkServerError.js b/services/sync/tests/unit/test_errorhandler_sync_checkServerError.js index 18cea2ccee9..6a3882b5cb7 100755 --- a/services/sync/tests/unit/test_errorhandler_sync_checkServerError.js +++ b/services/sync/tests/unit/test_errorhandler_sync_checkServerError.js @@ -200,6 +200,7 @@ add_identity_test(this, function test_service_offline() { let deferred = Promise.defer(); server.stop(() => { Services.io.offline = true; + Services.prefs.setBoolPref("network.dns.offline-localhost", false); try { do_check_eq(Status.sync, SYNC_SUCCEEDED); @@ -214,6 +215,7 @@ add_identity_test(this, function test_service_offline() { Service.startOver(); } Services.io.offline = false; + Services.prefs.clearUserPref("network.dns.offline-localhost"); deferred.resolve(); }); yield deferred.promise;