Bug 1845311 - [Part 2] Use ChromeUtils.defineLazyGetter in more places r=arai,webcomp...
[gecko.git] / netwerk / test / unit / test_use_httpssvc.js
blob1085ca09597809a8052b430f3484468b0b62fa5e
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 "use strict";
7 let h2Port;
9 const certOverrideService = Cc[
10   "@mozilla.org/security/certoverride;1"
11 ].getService(Ci.nsICertOverrideService);
12 const { TestUtils } = ChromeUtils.importESModule(
13   "resource://testing-common/TestUtils.sys.mjs"
16 add_setup(async function setup() {
17   trr_test_setup();
19   h2Port = Services.env.get("MOZHTTP2_PORT");
20   Assert.notEqual(h2Port, null);
21   Assert.notEqual(h2Port, "");
23   Services.prefs.setBoolPref("network.dns.upgrade_with_https_rr", true);
24   Services.prefs.setBoolPref("network.dns.use_https_rr_as_altsvc", true);
26   registerCleanupFunction(() => {
27     trr_clear_prefs();
28     Services.prefs.clearUserPref("network.dns.upgrade_with_https_rr");
29     Services.prefs.clearUserPref("network.dns.use_https_rr_as_altsvc");
30   });
32   if (mozinfo.socketprocess_networking) {
33     Services.dns; // Needed to trigger socket process.
34     await TestUtils.waitForCondition(() => Services.io.socketProcessLaunched);
35   }
37   Services.prefs.setIntPref("network.trr.mode", 2); // TRR first
38 });
40 function makeChan(url) {
41   let chan = NetUtil.newChannel({
42     uri: url,
43     loadUsingSystemPrincipal: true,
44     contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT,
45   }).QueryInterface(Ci.nsIHttpChannel);
46   return chan;
49 function channelOpenPromise(chan) {
50   return new Promise(resolve => {
51     function finish(req, buffer) {
52       resolve([req, buffer]);
53     }
54     let internal = chan.QueryInterface(Ci.nsIHttpChannelInternal);
55     internal.setWaitForHTTPSSVCRecord();
56     chan.asyncOpen(new ChannelListener(finish, null, CL_ALLOW_UNKNOWN_CL));
57   });
60 // This is for testing when the HTTPSSVC record is not available when
61 // the transaction is added in connection manager.
62 add_task(async function testUseHTTPSSVCForHttpsUpgrade() {
63   // use the h2 server as DOH provider
64   Services.prefs.setCharPref(
65     "network.trr.uri",
66     "https://foo.example.com:" + h2Port + "/httpssvc_as_altsvc"
67   );
68   Services.dns.clearCache(true);
70   certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
71     true
72   );
74   let chan = makeChan(`https://test.httpssvc.com:8080/`);
75   let [req] = await channelOpenPromise(chan);
76   Assert.equal(req.getResponseHeader("x-connection-http2"), "yes");
78   certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
79     false
80   );
81 });
83 class EventSinkListener {
84   getInterface(iid) {
85     if (iid.equals(Ci.nsIChannelEventSink)) {
86       return this;
87     }
88     throw Components.Exception("", Cr.NS_ERROR_NO_INTERFACE);
89   }
90   asyncOnChannelRedirect(oldChan, newChan, flags, callback) {
91     Assert.equal(oldChan.URI.hostPort, newChan.URI.hostPort);
92     Assert.equal(oldChan.URI.scheme, "http");
93     Assert.equal(newChan.URI.scheme, "https");
94     callback.onRedirectVerifyCallback(Cr.NS_OK);
95   }
98 EventSinkListener.prototype.QueryInterface = ChromeUtils.generateQI([
99   "nsIInterfaceRequestor",
100   "nsIChannelEventSink",
103 // Test if the request is upgraded to https with a HTTPSSVC record.
104 add_task(async function testUseHTTPSSVCAsHSTS() {
105   // use the h2 server as DOH provider
106   Services.prefs.setCharPref(
107     "network.trr.uri",
108     "https://foo.example.com:" + h2Port + "/httpssvc_as_altsvc"
109   );
110   Services.dns.clearCache(true);
112   certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
113     true
114   );
116   // At this time, the DataStorage is not ready, so MaybeUseHTTPSRRForUpgrade()
117   // is called from the callback of NS_ShouldSecureUpgrade().
118   let chan = makeChan(`http://test.httpssvc.com:80/`);
119   let listener = new EventSinkListener();
120   chan.notificationCallbacks = listener;
122   let [req] = await channelOpenPromise(chan);
124   req.QueryInterface(Ci.nsIHttpChannel);
125   Assert.equal(req.getResponseHeader("x-connection-http2"), "yes");
127   // At this time, the DataStorage is ready, so MaybeUseHTTPSRRForUpgrade()
128   // is called from nsHttpChannel::OnBeforeConnect().
129   chan = makeChan(`http://test.httpssvc.com:80/`);
130   listener = new EventSinkListener();
131   chan.notificationCallbacks = listener;
133   [req] = await channelOpenPromise(chan);
135   req.QueryInterface(Ci.nsIHttpChannel);
136   Assert.equal(req.getResponseHeader("x-connection-http2"), "yes");
138   certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
139     false
140   );
143 // This is for testing when the HTTPSSVC record is already available before
144 // the transaction is added in connection manager.
145 add_task(async function testUseHTTPSSVC() {
146   // use the h2 server as DOH provider
147   Services.prefs.setCharPref(
148     "network.trr.uri",
149     "https://foo.example.com:" + h2Port + "/httpssvc_as_altsvc"
150   );
152   // Do DNS resolution before creating the channel, so the HTTPSSVC record will
153   // be resolved from the cache.
154   await new TRRDNSListener("test.httpssvc.com", {
155     type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
156   });
158   // We need to skip the security check, since our test cert is signed for
159   // foo.example.com, not test.httpssvc.com.
160   certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
161     true
162   );
164   let chan = makeChan(`https://test.httpssvc.com:8888`);
165   let [req] = await channelOpenPromise(chan);
166   // Test if this request is done by h2.
167   Assert.equal(req.getResponseHeader("x-connection-http2"), "yes");
169   certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
170     false
171   );
174 // Test if we can successfully fallback to the original host and port.
175 add_task(async function testFallback() {
176   let trrServer = new TRRServer();
177   registerCleanupFunction(async () => {
178     await trrServer.stop();
179   });
180   await trrServer.start();
182   Services.prefs.setIntPref("network.trr.mode", 3);
183   Services.prefs.setCharPref(
184     "network.trr.uri",
185     `https://foo.example.com:${trrServer.port}/dns-query`
186   );
188   await trrServer.registerDoHAnswers("test.fallback.com", "A", {
189     answers: [
190       {
191         name: "test.fallback.com",
192         ttl: 55,
193         type: "A",
194         flush: false,
195         data: "127.0.0.1",
196       },
197     ],
198   });
199   // Use a wrong port number 8888, so this connection will be refused.
200   await trrServer.registerDoHAnswers("test.fallback.com", "HTTPS", {
201     answers: [
202       {
203         name: "test.fallback.com",
204         ttl: 55,
205         type: "HTTPS",
206         flush: false,
207         data: {
208           priority: 1,
209           name: "foo.example.com",
210           values: [{ key: "port", value: 8888 }],
211         },
212       },
213     ],
214   });
216   let { inRecord } = await new TRRDNSListener("test.fallback.com", {
217     type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
218   });
220   let record = inRecord
221     .QueryInterface(Ci.nsIDNSHTTPSSVCRecord)
222     .GetServiceModeRecord(false, false);
223   Assert.equal(record.priority, 1);
224   Assert.equal(record.name, "foo.example.com");
226   certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
227     true
228   );
230   // When the connection with port 8888 failed, the correct h2Port will be used
231   // to connect again.
232   let chan = makeChan(`https://test.fallback.com:${h2Port}`);
233   let [req] = await channelOpenPromise(chan);
234   // Test if this request is done by h2.
235   Assert.equal(req.getResponseHeader("x-connection-http2"), "yes");
237   certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
238     false
239   );