Bug 1931425 - Limit how often moz-label's #setStyles runs r=reusable-components-revie...
[gecko.git] / netwerk / test / unit / test_proxy_cancel.js
blob6374a162c970a8e9b35d744657f4a2c5b79aef13
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 /* globals setTimeout */
9 const { TestUtils } = ChromeUtils.importESModule(
10 "resource://testing-common/TestUtils.sys.mjs"
13 function makeChan(uri) {
14 let chan = NetUtil.newChannel({
15 uri,
16 loadUsingSystemPrincipal: true,
17 }).QueryInterface(Ci.nsIHttpChannel);
18 chan.loadFlags = Ci.nsIChannel.LOAD_INITIAL_DOCUMENT_URI;
19 return chan;
22 add_setup(async function setup() {
23 // See Bug 1878505
24 Services.prefs.setIntPref("network.http.speculative-parallel-limit", 0);
25 registerCleanupFunction(async () => {
26 Services.prefs.clearUserPref("network.http.speculative-parallel-limit");
27 });
28 });
30 add_task(async function test_cancel_after_asyncOpen() {
31 let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
32 Ci.nsIX509CertDB
34 addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u");
35 addCertFromFile(certdb, "proxy-ca.pem", "CTu,u,u");
37 let proxies = [
38 NodeHTTPProxyServer,
39 NodeHTTPSProxyServer,
40 NodeHTTP2ProxyServer,
42 for (let p of proxies) {
43 let proxy = new p();
44 await proxy.start();
45 registerCleanupFunction(async () => {
46 await proxy.stop();
47 });
48 await with_node_servers(
49 [NodeHTTPServer, NodeHTTPSServer, NodeHTTP2Server],
50 async server => {
51 info(`Testing ${p.name} with ${server.constructor.name}`);
52 await server.execute(
53 `global.server_name = "${server.constructor.name}";`
56 await server.registerPathHandler("/test", (req, resp) => {
57 resp.writeHead(200);
58 resp.end(global.server_name);
59 });
61 let chan = makeChan(`${server.origin()}/test`);
62 let openPromise = new Promise(resolve => {
63 chan.asyncOpen(
64 new ChannelListener(
65 (req, buff) => resolve({ req, buff }),
66 null,
67 CL_EXPECT_FAILURE
70 });
71 chan.cancel(Cr.NS_ERROR_ABORT);
72 let { req } = await openPromise;
73 Assert.equal(req.status, Cr.NS_ERROR_ABORT);
76 await proxy.stop();
78 });
80 // const NS_NET_STATUS_CONNECTING_TO = 0x4b0007;
81 // const NS_NET_STATUS_CONNECTED_TO = 0x4b0004;
82 // const NS_NET_STATUS_SENDING_TO = 0x4b0005;
83 const NS_NET_STATUS_WAITING_FOR = 0x4b000a; // 2152398858
84 const NS_NET_STATUS_RECEIVING_FROM = 0x4b0006;
85 // const NS_NET_STATUS_TLS_HANDSHAKE_STARTING = 0x4b000c; // 2152398860
86 // const NS_NET_STATUS_TLS_HANDSHAKE_ENDED = 0x4b000d; // 2152398861
88 add_task(async function test_cancel_after_connect_http2proxy() {
89 let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
90 Ci.nsIX509CertDB
92 addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u");
93 addCertFromFile(certdb, "proxy-ca.pem", "CTu,u,u");
95 await with_node_servers(
96 [NodeHTTPServer, NodeHTTPSServer, NodeHTTP2Server],
97 async server => {
98 // Set up a proxy for each server to make sure proxy state is clean
99 // for each test.
100 let proxy = new NodeHTTP2ProxyServer();
101 await proxy.start();
102 registerCleanupFunction(async () => {
103 await proxy.stop();
105 await proxy.execute(`
106 global.session_counter = 0;
107 global.proxy.on("session", () => {
108 global.session_counter++;
112 info(`Testing ${proxy.constructor.name} with ${server.constructor.name}`);
113 await server.execute(
114 `global.server_name = "${server.constructor.name}";`
117 await server.registerPathHandler("/test", (req, resp) => {
118 global.reqCount = (global.reqCount || 0) + 1;
119 resp.writeHead(200);
120 resp.end(global.server_name);
123 let chan = makeChan(`${server.origin()}/test`);
124 chan.notificationCallbacks = {
125 QueryInterface: ChromeUtils.generateQI([
126 "nsIInterfaceRequestor",
127 "nsIProgressEventSink",
130 getInterface(iid) {
131 return this.QueryInterface(iid);
134 onProgress() {},
135 onStatus(request, status) {
136 info(`status = ${status}`);
137 // XXX(valentin): Is this the best status to be cancelling?
138 if (status == NS_NET_STATUS_WAITING_FOR) {
139 info("cancelling connected channel");
140 chan.cancel(Cr.NS_ERROR_ABORT);
144 let openPromise = new Promise(resolve => {
145 chan.asyncOpen(
146 new ChannelListener(
147 (req, buff) => resolve({ req, buff }),
148 null,
149 CL_EXPECT_FAILURE
153 let { req } = await openPromise;
154 Assert.equal(req.status, Cr.NS_ERROR_ABORT);
156 // Since we're cancelling just after connect, we'd expect that no
157 // requests are actually registered. But because we're cancelling on the
158 // main thread, and the request is being performed on the socket thread,
159 // it might actually reach the server, especially in chaos test mode.
160 // Assert.equal(
161 // await server.execute(`global.reqCount || 0`),
162 // 0,
163 // `No requests should have been made at this point`
164 // );
165 Assert.equal(await proxy.execute(`global.session_counter`), 1);
167 chan = makeChan(`${server.origin()}/test`);
168 await new Promise(resolve => {
169 chan.asyncOpen(
170 new ChannelListener(
171 // eslint-disable-next-line no-shadow
172 (req, buff) => resolve({ req, buff }),
173 null,
174 CL_ALLOW_UNKNOWN_CL
179 // Check that there's still only one session.
180 Assert.equal(await proxy.execute(`global.session_counter`), 1);
181 await proxy.stop();
186 add_task(async function test_cancel_after_sending_request() {
187 let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
188 Ci.nsIX509CertDB
190 addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u");
191 addCertFromFile(certdb, "proxy-ca.pem", "CTu,u,u");
193 await with_node_servers(
194 [NodeHTTPServer, NodeHTTPSServer, NodeHTTP2Server],
195 async server => {
196 let proxies = [
197 NodeHTTPProxyServer,
198 NodeHTTPSProxyServer,
199 NodeHTTP2ProxyServer,
201 for (let p of proxies) {
202 let proxy = new p();
203 await proxy.start();
204 registerCleanupFunction(async () => {
205 await proxy.stop();
208 await proxy.execute(`
209 global.session_counter = 0;
210 global.proxy.on("session", () => {
211 global.session_counter++;
214 info(`Testing ${p.name} with ${server.constructor.name}`);
215 await server.execute(
216 `global.server_name = "${server.constructor.name}";`
219 await server.registerPathHandler("/test", (req, resp) => {
220 // Here we simmulate a slow response to give the test time to
221 // cancel the channel before receiving the response.
222 global.request_count = (global.request_count || 0) + 1;
223 // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
224 setTimeout(() => {
225 resp.writeHead(200);
226 resp.end(global.server_name);
227 }, 2000);
229 await server.registerPathHandler("/instant", (req, resp) => {
230 resp.writeHead(200);
231 resp.end(global.server_name);
234 // It seems proxy.on("session") only gets emitted after a full request.
235 // So we first load a simple request, then the long lasting request
236 // that we then cancel before it has the chance to complete.
237 let chan = makeChan(`${server.origin()}/instant`);
238 await new Promise(resolve => {
239 chan.asyncOpen(
240 new ChannelListener(resolve, null, CL_ALLOW_UNKNOWN_CL)
244 chan = makeChan(`${server.origin()}/test`);
245 let openPromise = new Promise(resolve => {
246 chan.asyncOpen(
247 new ChannelListener(
248 (req, buff) => resolve({ req, buff }),
249 null,
250 CL_EXPECT_FAILURE
254 // XXX(valentin) This might be a little racy
255 await TestUtils.waitForCondition(async () => {
256 return (await server.execute("global.request_count")) > 0;
259 chan.cancel(Cr.NS_ERROR_ABORT);
261 let { req } = await openPromise;
262 Assert.equal(req.status, Cr.NS_ERROR_ABORT);
264 async function checkSessionCounter() {
265 if (p.name == "NodeHTTP2ProxyServer") {
266 Assert.equal(await proxy.execute(`global.session_counter`), 1);
270 await checkSessionCounter();
272 chan = makeChan(`${server.origin()}/instant`);
273 await new Promise(resolve => {
274 chan.asyncOpen(
275 new ChannelListener(
276 // eslint-disable-next-line no-shadow
277 (req, buff) => resolve({ req, buff }),
278 null,
279 CL_ALLOW_UNKNOWN_CL
283 await checkSessionCounter();
285 await proxy.stop();
291 add_task(async function test_cancel_during_response() {
292 let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
293 Ci.nsIX509CertDB
295 addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u");
296 addCertFromFile(certdb, "proxy-ca.pem", "CTu,u,u");
298 await with_node_servers(
299 [NodeHTTPServer, NodeHTTPSServer, NodeHTTP2Server],
300 async server => {
301 let proxies = [
302 NodeHTTPProxyServer,
303 NodeHTTPSProxyServer,
304 NodeHTTP2ProxyServer,
306 for (let p of proxies) {
307 let proxy = new p();
308 await proxy.start();
309 registerCleanupFunction(async () => {
310 await proxy.stop();
313 await proxy.execute(`
314 global.session_counter = 0;
315 global.proxy.on("session", () => {
316 global.session_counter++;
320 info(`Testing ${p.name} with ${server.constructor.name}`);
321 await server.execute(
322 `global.server_name = "${server.constructor.name}";`
325 await server.registerPathHandler("/test", (req, resp) => {
326 resp.writeHead(200);
327 resp.write("a".repeat(1000));
328 // Here we send the response back in two chunks.
329 // The channel should be cancelled after the first one.
330 // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
331 setTimeout(() => {
332 resp.write("a".repeat(1000));
333 resp.end(global.server_name);
334 }, 2000);
336 await server.registerPathHandler("/instant", (req, resp) => {
337 resp.writeHead(200);
338 resp.end(global.server_name);
341 let chan = makeChan(`${server.origin()}/test`);
343 chan.notificationCallbacks = {
344 QueryInterface: ChromeUtils.generateQI([
345 "nsIInterfaceRequestor",
346 "nsIProgressEventSink",
349 getInterface(iid) {
350 return this.QueryInterface(iid);
353 onProgress(request, progress, progressMax) {
354 info(`progress: ${progress}/${progressMax}`);
355 // Check that we never get more than 1000 bytes.
356 Assert.equal(progress, 1000);
358 onStatus(request, status) {
359 if (status == NS_NET_STATUS_RECEIVING_FROM) {
360 info("cancelling when receiving request");
361 chan.cancel(Cr.NS_ERROR_ABORT);
366 let openPromise = new Promise(resolve => {
367 chan.asyncOpen(
368 new ChannelListener(
369 (req, buff) => resolve({ req, buff }),
370 null,
371 CL_EXPECT_FAILURE
376 let { req } = await openPromise;
377 Assert.equal(req.status, Cr.NS_ERROR_ABORT);
379 async function checkSessionCounter() {
380 if (p.name == "NodeHTTP2ProxyServer") {
381 Assert.equal(await proxy.execute(`global.session_counter`), 1);
385 await checkSessionCounter();
387 chan = makeChan(`${server.origin()}/instant`);
388 await new Promise(resolve => {
389 chan.asyncOpen(
390 new ChannelListener(
391 // eslint-disable-next-line no-shadow
392 (req, buff) => resolve({ req, buff }),
393 null,
394 CL_ALLOW_UNKNOWN_CL
399 await checkSessionCounter();
401 await proxy.stop();