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/. */
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() {
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);
25 Services
.prefs
.setBoolPref(
26 "network.dns.https_rr.check_record_with_cname",
30 registerCleanupFunction(() => {
32 Services
.prefs
.clearUserPref("network.dns.upgrade_with_https_rr");
33 Services
.prefs
.clearUserPref("network.dns.use_https_rr_as_altsvc");
34 Services
.prefs
.clearUserPref(
35 "network.dns.https_rr.check_record_with_cname"
39 if (mozinfo
.socketprocess_networking
) {
40 Services
.dns
; // Needed to trigger socket process.
41 await TestUtils
.waitForCondition(() => Services
.io
.socketProcessLaunched
);
44 Services
.prefs
.setIntPref("network.trr.mode", Ci
.nsIDNSService
.MODE_TRRONLY
);
47 function makeChan(url
) {
48 let chan
= NetUtil
.newChannel({
50 loadUsingSystemPrincipal
: true,
51 contentPolicyType
: Ci
.nsIContentPolicy
.TYPE_DOCUMENT
,
52 }).QueryInterface(Ci
.nsIHttpChannel
);
56 function channelOpenPromise(chan
) {
57 return new Promise(resolve
=> {
58 function finish(req
, buffer
) {
59 resolve([req
, buffer
]);
61 chan
.asyncOpen(new ChannelListener(finish
, null, CL_ALLOW_UNKNOWN_CL
));
65 // This is for testing when the HTTPSSVC record is not available when
66 // the transaction is added in connection manager.
67 add_task(async
function testUseHTTPSSVCForHttpsUpgrade() {
68 // use the h2 server as DOH provider
69 Services
.prefs
.setCharPref(
71 "https://foo.example.com:" + h2Port
+ "/httpssvc_as_altsvc"
73 Services
.dns
.clearCache(true);
75 certOverrideService
.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
79 let chan
= makeChan(`https://test.httpssvc.com:8080/`);
80 let [req
] = await
channelOpenPromise(chan
);
81 Assert
.equal(req
.getResponseHeader("x-connection-http2"), "yes");
83 certOverrideService
.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
88 class EventSinkListener
{
90 if (iid
.equals(Ci
.nsIChannelEventSink
)) {
93 throw Components
.Exception("", Cr
.NS_ERROR_NO_INTERFACE
);
95 asyncOnChannelRedirect(oldChan
, newChan
, flags
, callback
) {
96 Assert
.equal(oldChan
.URI
.hostPort
, newChan
.URI
.hostPort
);
97 Assert
.equal(oldChan
.URI
.scheme
, "http");
98 Assert
.equal(newChan
.URI
.scheme
, "https");
99 callback
.onRedirectVerifyCallback(Cr
.NS_OK
);
103 EventSinkListener
.prototype.QueryInterface
= ChromeUtils
.generateQI([
104 "nsIInterfaceRequestor",
105 "nsIChannelEventSink",
108 // Test if the request is upgraded to https with a HTTPSSVC record.
109 add_task(async
function testUseHTTPSSVCAsHSTS() {
110 // use the h2 server as DOH provider
111 Services
.prefs
.setCharPref(
113 "https://foo.example.com:" + h2Port
+ "/httpssvc_as_altsvc"
115 Services
.dns
.clearCache(true);
117 certOverrideService
.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
121 // At this time, the DataStorage is not ready, so MaybeUseHTTPSRRForUpgrade()
122 // is called from the callback of NS_ShouldSecureUpgrade().
123 let chan
= makeChan(`http://test.httpssvc.com:80/`);
124 let listener
= new EventSinkListener();
125 chan
.notificationCallbacks
= listener
;
127 let [req
] = await
channelOpenPromise(chan
);
129 req
.QueryInterface(Ci
.nsIHttpChannel
);
130 Assert
.equal(req
.getResponseHeader("x-connection-http2"), "yes");
132 // At this time, the DataStorage is ready, so MaybeUseHTTPSRRForUpgrade()
133 // is called from nsHttpChannel::OnBeforeConnect().
134 chan
= makeChan(`http://test.httpssvc.com:80/`);
135 listener
= new EventSinkListener();
136 chan
.notificationCallbacks
= listener
;
138 [req
] = await
channelOpenPromise(chan
);
140 req
.QueryInterface(Ci
.nsIHttpChannel
);
141 Assert
.equal(req
.getResponseHeader("x-connection-http2"), "yes");
143 certOverrideService
.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
148 // This is for testing when the HTTPSSVC record is already available before
149 // the transaction is added in connection manager.
150 add_task(async
function testUseHTTPSSVC() {
151 // use the h2 server as DOH provider
152 Services
.prefs
.setCharPref(
154 "https://foo.example.com:" + h2Port
+ "/httpssvc_as_altsvc"
157 // Do DNS resolution before creating the channel, so the HTTPSSVC record will
158 // be resolved from the cache.
159 await
new TRRDNSListener("test.httpssvc.com", {
160 type
: Ci
.nsIDNSService
.RESOLVE_TYPE_HTTPSSVC
,
163 // We need to skip the security check, since our test cert is signed for
164 // foo.example.com, not test.httpssvc.com.
165 certOverrideService
.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
169 let chan
= makeChan(`https://test.httpssvc.com:8888`);
170 let [req
] = await
channelOpenPromise(chan
);
171 // Test if this request is done by h2.
172 Assert
.equal(req
.getResponseHeader("x-connection-http2"), "yes");
174 certOverrideService
.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
179 // Test if we can successfully fallback to the original host and port.
180 add_task(async
function testFallback() {
181 let trrServer
= new TRRServer();
182 registerCleanupFunction(async () => {
183 await trrServer
.stop();
185 await trrServer
.start();
187 Services
.prefs
.setIntPref("network.trr.mode", Ci
.nsIDNSService
.MODE_TRRONLY
);
188 Services
.prefs
.setCharPref(
190 `https://foo.example.com:${trrServer.port()}/dns-query`
193 await trrServer
.registerDoHAnswers("test.fallback.com", "A", {
196 name
: "test.fallback.com",
204 // Use a wrong port number 8888, so this connection will be refused.
205 await trrServer
.registerDoHAnswers("test.fallback.com", "HTTPS", {
208 name
: "test.fallback.com",
214 name
: "foo.example.com",
215 values
: [{ key
: "port", value
: 8888 }],
221 let { inRecord
} = await
new TRRDNSListener("test.fallback.com", {
222 type
: Ci
.nsIDNSService
.RESOLVE_TYPE_HTTPSSVC
,
225 let record
= inRecord
226 .QueryInterface(Ci
.nsIDNSHTTPSSVCRecord
)
227 .GetServiceModeRecord(false, false);
228 Assert
.equal(record
.priority
, 1);
229 Assert
.equal(record
.name
, "foo.example.com");
231 certOverrideService
.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
235 // When the connection with port 8888 failed, the correct h2Port will be used
237 let chan
= makeChan(`https://test.fallback.com:${h2Port}`);
238 let [req
] = await
channelOpenPromise(chan
);
239 // Test if this request is done by h2.
240 Assert
.equal(req
.getResponseHeader("x-connection-http2"), "yes");
242 certOverrideService
.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(