Backed out changeset b71c8c052463 (bug 1943846) for causing mass failures. CLOSED...
[gecko.git] / netwerk / test / unit / test_ech_grease.js
blob7505985ef8478b0972dff220d5de5c4cc0858a96
1 // -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
2 // Any copyright is dedicated to the Public Domain.
3 // http://creativecommons.org/publicdomain/zero/1.0/
5 "use strict";
7 // Allow telemetry probes which may otherwise be disabled for some
8 // applications (e.g. Thunderbird).
9 Services.prefs.setBoolPref(
10 "toolkit.telemetry.testing.overrideProductsCheck",
11 true
14 // Get a profile directory and ensure PSM initializes NSS.
15 do_get_profile();
16 Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports);
18 class InputStreamCallback {
19 constructor(output) {
20 this.output = output;
21 this.stopped = false;
24 onInputStreamReady(stream) {
25 info("input stream ready");
26 if (this.stopped) {
27 info("input stream callback stopped - bailing");
28 return;
30 let available = 0;
31 try {
32 available = stream.available();
33 } catch (e) {
34 // onInputStreamReady may fire when the stream has been closed.
35 equal(
36 e.result,
37 Cr.NS_BASE_STREAM_CLOSED,
38 "error should be NS_BASE_STREAM_CLOSED"
41 if (available > 0) {
42 let request = NetUtil.readInputStreamToString(stream, available, {
43 charset: "utf8",
44 });
45 ok(
46 request.startsWith("GET / HTTP/1.1\r\n"),
47 "Should get a simple GET / HTTP/1.1 request"
49 let response =
50 "HTTP/1.1 200 OK\r\n" +
51 "Content-Length: 2\r\n" +
52 "Content-Type: text/plain\r\n" +
53 "\r\nOK";
54 let written = this.output.write(response, response.length);
55 equal(
56 written,
57 response.length,
58 "should have been able to write entire response"
61 this.output.close();
62 info("done with input stream ready");
65 stop() {
66 this.stopped = true;
67 this.output.close();
71 class TLSServerSecurityObserver {
72 constructor(input, output) {
73 this.input = input;
74 this.output = output;
75 this.callbacks = [];
76 this.stopped = false;
79 onHandshakeDone(socket, status) {
80 info("TLS handshake done");
81 info(`TLS version used: ${status.tlsVersionUsed}`);
83 if (this.stopped) {
84 info("handshake done callback stopped - bailing");
85 return;
88 let callback = new InputStreamCallback(this.output);
89 this.callbacks.push(callback);
90 this.input.asyncWait(callback, 0, 0, Services.tm.currentThread);
93 stop() {
94 this.stopped = true;
95 this.input.close();
96 this.output.close();
97 this.callbacks.forEach(callback => {
98 callback.stop();
99 });
103 class ServerSocketListener {
104 constructor() {
105 this.securityObservers = [];
108 onSocketAccepted(socket, transport) {
109 info("accepted TLS client connection");
110 let connectionInfo = transport.securityCallbacks.getInterface(
111 Ci.nsITLSServerConnectionInfo
113 let input = transport.openInputStream(0, 0, 0);
114 let output = transport.openOutputStream(0, 0, 0);
115 let securityObserver = new TLSServerSecurityObserver(input, output);
116 this.securityObservers.push(securityObserver);
117 connectionInfo.setSecurityObserver(securityObserver);
120 // For some reason we get input stream callback events after we've stopped
121 // listening, so this ensures we just drop those events.
122 onStopListening() {
123 info("onStopListening");
124 this.securityObservers.forEach(observer => {
125 observer.stop();
130 function startServer(
131 minServerVersion = Ci.nsITLSClientStatus.TLS_VERSION_1_2,
132 maxServerVersion = Ci.nsITLSClientStatus.TLS_VERSION_1_3
134 let tlsServer = Cc["@mozilla.org/network/tls-server-socket;1"].createInstance(
135 Ci.nsITLSServerSocket
137 tlsServer.init(-1, true, -1);
138 tlsServer.serverCert = getTestServerCertificate();
139 tlsServer.setVersionRange(minServerVersion, maxServerVersion);
140 tlsServer.setSessionTickets(false);
141 tlsServer.asyncListen(new ServerSocketListener());
142 storeCertOverride(tlsServer.port, tlsServer.serverCert);
143 return tlsServer;
146 const hostname = "example.com";
148 function storeCertOverride(port, cert) {
149 let certOverrideService = Cc[
150 "@mozilla.org/security/certoverride;1"
151 ].getService(Ci.nsICertOverrideService);
152 certOverrideService.rememberValidityOverride(hostname, port, {}, cert, true);
155 function startClient(port, useGREASE, beConservative) {
156 HandshakeTelemetryHelpers.resetHistograms();
157 let flavors = ["", "_FIRST_TRY"];
158 let nonflavors = ["_ECH"];
160 if (useGREASE) {
161 Services.prefs.setIntPref("security.tls.ech.grease_probability", 100);
162 } else {
163 Services.prefs.setIntPref("security.tls.ech.grease_probability", 0);
166 let req = new XMLHttpRequest();
167 req.open("GET", `https://${hostname}:${port}`);
169 if (beConservative) {
170 // We don't have a way to set DONT_TRY_ECH at the moment.
171 let internalChannel = req.channel.QueryInterface(Ci.nsIHttpChannelInternal);
172 internalChannel.beConservative = beConservative;
173 flavors.push("_CONSERVATIVE");
174 } else {
175 nonflavors.push("_CONSERVATIVE");
178 //GREASE is only used if enabled and not in conservative mode.
179 if (useGREASE && !beConservative) {
180 flavors.push("_ECH_GREASE");
181 } else {
182 nonflavors.push("_ECH_GREASE");
185 return new Promise(resolve => {
186 req.onload = () => {
187 equal(req.responseText, "OK", "response text should be 'OK'");
189 // Only check telemetry if network process is disabled.
190 if (!mozinfo.socketprocess_networking) {
191 HandshakeTelemetryHelpers.checkSuccess(flavors);
192 HandshakeTelemetryHelpers.checkEmpty(nonflavors);
195 resolve();
197 req.onerror = () => {
198 ok(false, `should not have gotten an error`);
199 resolve();
202 req.send();
206 function setup() {
207 Services.prefs.setIntPref("security.tls.version.max", 4);
208 Services.prefs.setCharPref("network.dns.localDomains", hostname);
209 Services.prefs.setIntPref("network.http.speculative-parallel-limit", 0);
211 setup();
213 add_task(async function GreaseYConservativeN() {
214 // First run a server that accepts TLS 1.2 and 1.3. A conservative client
215 // should succeed in connecting.
216 let server = startServer();
218 await startClient(
219 server.port,
220 true /*be conservative*/,
221 false /*should succeed*/
223 server.close();
226 add_task(async function GreaseNConservativeY() {
227 // First run a server that accepts TLS 1.2 and 1.3. A conservative client
228 // should succeed in connecting.
229 let server = startServer();
231 await startClient(
232 server.port,
233 false /*be conservative*/,
234 true /*should succeed*/
236 server.close();
239 add_task(async function GreaseYConservativeY() {
240 // First run a server that accepts TLS 1.2 and 1.3. A conservative client
241 // should succeed in connecting.
242 let server = startServer();
244 await startClient(
245 server.port,
246 true /*be conservative*/,
247 true /*should succeed*/
249 server.close();
252 add_task(async function GreaseNConservativeN() {
253 // First run a server that accepts TLS 1.2 and 1.3. A conservative client
254 // should succeed in connecting.
255 let server = startServer();
257 await startClient(
258 server.port,
259 false /*be conservative*/,
260 false /*should succeed*/
262 server.close();
265 registerCleanupFunction(function () {
266 Services.prefs.clearUserPref("security.tls.version.max");
267 Services.prefs.clearUserPref("network.dns.localDomains");
268 Services.prefs.clearUserPref("security.tls.ech.grease_probability");
269 Services.prefs.clearUserPref("network.http.speculative-parallel-limit");