Bug 1807268 - Re-enable verifyShowClipboardSuggestionsToggleTest UI test r=jajohnson
[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;
22   }
24   onInputStreamReady(stream) {
25     info("input stream ready");
26     if (this.stopped) {
27       info("input stream callback stopped - bailing");
28       return;
29     }
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"
39       );
40     }
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"
48       );
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"
59       );
60     }
61     this.output.close();
62     info("done with input stream ready");
63   }
65   stop() {
66     this.stopped = true;
67     this.output.close();
68   }
71 class TLSServerSecurityObserver {
72   constructor(input, output) {
73     this.input = input;
74     this.output = output;
75     this.callbacks = [];
76     this.stopped = false;
77   }
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;
86     }
88     let callback = new InputStreamCallback(this.output);
89     this.callbacks.push(callback);
90     this.input.asyncWait(callback, 0, 0, Services.tm.currentThread);
91   }
93   stop() {
94     this.stopped = true;
95     this.input.close();
96     this.output.close();
97     this.callbacks.forEach(callback => {
98       callback.stop();
99     });
100   }
103 class ServerSocketListener {
104   constructor() {
105     this.securityObservers = [];
106   }
108   onSocketAccepted(socket, transport) {
109     info("accepted TLS client connection");
110     let connectionInfo = transport.securityCallbacks.getInterface(
111       Ci.nsITLSServerConnectionInfo
112     );
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);
118   }
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();
126     });
127   }
130 function startServer(
131   minServerVersion = Ci.nsITLSClientStatus.TLS_VERSION_1_2,
132   maxServerVersion = Ci.nsITLSClientStatus.TLS_VERSION_1_3
133 ) {
134   let tlsServer = Cc["@mozilla.org/network/tls-server-socket;1"].createInstance(
135     Ci.nsITLSServerSocket
136   );
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);
164   }
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");
176   }
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");
183   }
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);
193       }
195       resolve();
196     };
197     req.onerror = () => {
198       ok(false, `should not have gotten an error`);
199       resolve();
200     };
202     req.send();
203   });
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*/
222   );
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*/
235   );
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*/
248   );
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*/
261   );
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");