3 const { HttpServer } = ChromeUtils.importESModule(
4 "resource://testing-common/httpd.sys.mjs"
7 let httpServerIPv4 = new HttpServer();
8 let httpServerIPv6 = new HttpServer();
10 let testpath = "/simple";
11 let httpbody = "0123456789";
12 let CC_IPV4 = "example_cc_ipv4.com";
13 let CC_IPV6 = "example_cc_ipv6.com";
14 Services.prefs.clearUserPref("network.dns.native-is-localhost");
16 ChromeUtils.defineLazyGetter(this, "URL_CC_IPV4", function () {
17 return `http://${CC_IPV4}:${httpServerIPv4.identity.primaryPort}${testpath}`;
19 ChromeUtils.defineLazyGetter(this, "URL_CC_IPV6", function () {
20 return `http://${CC_IPV6}:${httpServerIPv6.identity.primaryPort}${testpath}`;
22 ChromeUtils.defineLazyGetter(this, "URL6a", function () {
23 return `http://example6a.com:${httpServerIPv6.identity.primaryPort}${testpath}`;
25 ChromeUtils.defineLazyGetter(this, "URL6b", function () {
26 return `http://example6b.com:${httpServerIPv6.identity.primaryPort}${testpath}`;
30 "@mozilla.org/network/network-connectivity-service;1"
31 ].getService(Ci.nsINetworkConnectivityService);
32 const { TestUtils } = ChromeUtils.importESModule(
33 "resource://testing-common/TestUtils.sys.mjs"
36 registerCleanupFunction(async () => {
37 Services.prefs.clearUserPref("network.http.speculative-parallel-limit");
38 Services.prefs.clearUserPref("network.captive-portal-service.testMode");
39 Services.prefs.clearUserPref("network.connectivity-service.IPv6.url");
40 Services.prefs.clearUserPref("network.connectivity-service.IPv4.url");
41 Services.prefs.clearUserPref("network.dns.localDomains");
44 await httpServerIPv4.stop();
45 await httpServerIPv6.stop();
46 await trrServer.stop();
49 function makeChan(url) {
50 let chan = NetUtil.newChannel({
52 loadUsingSystemPrincipal: true,
53 }).QueryInterface(Ci.nsIHttpChannel);
54 chan.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
55 chan.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
56 chan.setTRRMode(Ci.nsIRequest.TRR_DEFAULT_MODE);
60 function serverHandler(metadata, response) {
61 response.setHeader("Content-Type", "text/plain", false);
62 response.bodyOutputStream.write(httpbody, httpbody.length);
65 add_task(async function test_setup() {
66 httpServerIPv4.registerPathHandler(testpath, serverHandler);
67 httpServerIPv4.start(-1);
68 httpServerIPv6.registerPathHandler(testpath, serverHandler);
69 httpServerIPv6.start_ipv6(-1);
70 Services.prefs.setCharPref(
71 "network.dns.localDomains",
72 `foo.example.com, ${CC_IPV4}, ${CC_IPV6}`
75 trrServer = new TRRServer();
76 await trrServer.start();
78 if (mozinfo.socketprocess_networking) {
79 Services.dns; // Needed to trigger socket process.
80 await TestUtils.waitForCondition(() => Services.io.socketProcessLaunched);
83 Services.prefs.setIntPref("network.trr.mode", 3);
84 Services.prefs.setCharPref(
86 `https://foo.example.com:${trrServer.port()}/dns-query`
89 await registerDoHAnswers(true, true);
92 async function registerDoHAnswers(ipv4, ipv6) {
93 let hosts = ["example6a.com", "example6b.com"];
94 for (const host of hosts) {
107 await trrServer.registerDoHAnswers(host, "A", {
108 answers: ipv4answers,
111 let ipv6answers = [];
124 await trrServer.registerDoHAnswers(host, "AAAA", {
125 answers: ipv6answers,
129 Services.dns.clearCache(true);
132 let StatusCounter = function () {
133 this._statusCount = {};
135 StatusCounter.prototype = {
136 QueryInterface: ChromeUtils.generateQI([
137 "nsIInterfaceRequestor",
138 "nsIProgressEventSink",
142 return this.QueryInterface(iid);
146 onStatus(request, status) {
147 this._statusCount[status] = 1 + (this._statusCount[status] || 0);
151 let HttpListener = function (finish, succeeded) {
152 this.finish = finish;
153 this.succeeded = succeeded;
156 HttpListener.prototype = {
157 onStartRequest: function testOnStartRequest() {},
159 onDataAvailable: function testOnDataAvailable(request, stream, off, cnt) {
160 read_stream(stream, cnt);
163 onStopRequest: function testOnStopRequest(request, status) {
164 equal(this.succeeded, status == Cr.NS_OK);
169 function promiseObserverNotification(aTopic, matchFunc) {
170 return new Promise(resolve => {
171 Services.obs.addObserver(function observe(subject, topic, data) {
172 let matches = typeof matchFunc != "function" || matchFunc(subject, data);
176 Services.obs.removeObserver(observe, topic);
177 resolve({ subject, data });
182 async function make_request(uri, check_events, succeeded) {
183 let chan = makeChan(uri);
184 let statusCounter = new StatusCounter();
185 chan.notificationCallbacks = statusCounter;
186 await new Promise(resolve =>
187 chan.asyncOpen(new HttpListener(resolve, succeeded))
192 statusCounter._statusCount[0x4b000b] || 0,
194 "Expecting only one instance of NS_NET_STATUS_RESOLVED_HOST"
197 statusCounter._statusCount[0x4b0007] || 0,
199 "Expecting only one instance of NS_NET_STATUS_CONNECTING_TO"
204 async function setup_connectivity(ipv6, ipv4) {
205 Services.prefs.setBoolPref("network.captive-portal-service.testMode", true);
208 Services.prefs.setCharPref(
209 "network.connectivity-service.IPv6.url",
210 URL_CC_IPV6 + testpath
213 Services.prefs.setCharPref(
214 "network.connectivity-service.IPv6.url",
215 "http://donotexist.example.com"
220 Services.prefs.setCharPref(
221 "network.connectivity-service.IPv4.url",
222 URL_CC_IPV4 + testpath
225 Services.prefs.setCharPref(
226 "network.connectivity-service.IPv4.url",
227 "http://donotexist.example.com"
231 let topic = "network:connectivity-service:ip-checks-complete";
232 if (mozinfo.socketprocess_networking) {
233 topic += "-from-socket-process";
235 let observerNotification = promiseObserverNotification(topic);
236 ncs.recheckIPConnectivity();
237 await observerNotification;
242 Ci.nsINetworkConnectivityService.NOT_AVAILABLE,
246 equal(ncs.IPv6, Ci.nsINetworkConnectivityService.OK, "Check IPv6 support");
252 Ci.nsINetworkConnectivityService.NOT_AVAILABLE,
256 equal(ncs.IPv4, Ci.nsINetworkConnectivityService.OK, "Check IPv4 support");
260 // This test that we retry to connect using IPv4 when IPv6 connecivity is not
261 // present, but a ConnectionEntry have IPv6 prefered set.
262 // Speculative connections are disabled.
263 add_task(async function test_prefer_address_version_fail_trr3_1() {
264 Services.prefs.setIntPref("network.http.speculative-parallel-limit", 0);
265 await registerDoHAnswers(true, true);
267 // Make a request to setup the address version preference to a ConnectionEntry.
268 await make_request(URL6a, true, true);
270 // connect again using the address version preference from the ConnectionEntry.
271 await make_request(URL6a, true, true);
273 // Make IPv6 connectivity check fail
274 await setup_connectivity(false, true);
276 Services.dns.clearCache(true);
278 // This will succeed as we query both DNS records
279 await make_request(URL6a, true, true);
281 // Now make the DNS server only return IPv4 records
282 await registerDoHAnswers(true, false);
283 // This will fail, because the server is not lisenting to IPv4 address as well,
284 // We should still get NS_NET_STATUS_RESOLVED_HOST and
285 // NS_NET_STATUS_CONNECTING_TO notification.
286 await make_request(URL6a, true, false);
288 // Make IPv6 connectivity check succeed again
289 await setup_connectivity(true, true);
292 // This test that we retry to connect using IPv4 when IPv6 connecivity is not
293 // present, but a ConnectionEntry have IPv6 prefered set.
294 // Speculative connections are enabled.
295 add_task(async function test_prefer_address_version_fail_trr3_2() {
296 Services.prefs.setIntPref("network.http.speculative-parallel-limit", 6);
297 await registerDoHAnswers(true, true);
299 // Make a request to setup the address version preference to a ConnectionEntry.
300 await make_request(URL6b, false, true);
302 // connect again using the address version preference from the ConnectionEntry.
303 await make_request(URL6b, false, true);
305 // Make IPv6 connectivity check fail
306 await setup_connectivity(false, true);
308 Services.dns.clearCache(true);
310 // This will succeed as we query both DNS records
311 await make_request(URL6b, false, true);
313 // Now make the DNS server only return IPv4 records
314 await registerDoHAnswers(true, false);
315 // This will fail, because the server is not lisenting to IPv4 address as well,
316 // We should still get NS_NET_STATUS_RESOLVED_HOST and
317 // NS_NET_STATUS_CONNECTING_TO notification.
318 await make_request(URL6b, true, false);