Skip to content

Commit

Permalink
bug 967792 - make localhost resolve offline r=dragana
Browse files Browse the repository at this point in the history
  • Loading branch information
rmottola committed Aug 15, 2019
1 parent 1cc8627 commit 73e2883
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 7 deletions.
5 changes: 5 additions & 0 deletions dom/base/test/unit/test_error_codes.js
Expand Up @@ -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"]
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions modules/libpref/init/all.js
Expand Up @@ -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);
Expand Down
22 changes: 15 additions & 7 deletions netwerk/dns/nsDNSService2.cpp
Expand Up @@ -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";

//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand All @@ -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);

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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<nsIXPConnectWrappedJS> wrappedListener = do_QueryInterface(listener);
if (wrappedListener && !target) {
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions netwerk/dns/nsDNSService2.h
Expand Up @@ -60,6 +60,7 @@ class nsDNSService final : public nsPIDNSService
bool mFirstTime;
bool mOffline;
bool mNotifyResolution;
bool mOfflineLocalhost;
nsMainThreadPtrHandle<nsIObserverService> mObserverService;
nsTHashtable<nsCStringHashKey> mLocalDomains;
};
Expand Down
74 changes: 74 additions & 0 deletions 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");
}
1 change: 1 addition & 0 deletions netwerk/test/unit/xpcshell.ini
Expand Up @@ -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]
Expand Down
Expand Up @@ -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);
Expand All @@ -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;
Expand Down

0 comments on commit 73e2883

Please sign in to comment.