test_verify_traffic.js (4797B)
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/. */ 4 5 "use strict"; 6 7 /* import-globals-from head_cache.js */ 8 /* import-globals-from head_cookies.js */ 9 /* import-globals-from head_channels.js */ 10 11 const gDashboard = Cc["@mozilla.org/network/dashboard;1"].getService( 12 Ci.nsIDashboard 13 ); 14 15 const { NodeHTTP2Server } = ChromeUtils.importESModule( 16 "resource://testing-common/NodeServer.sys.mjs" 17 ); 18 19 const { TestUtils } = ChromeUtils.importESModule( 20 "resource://testing-common/TestUtils.sys.mjs" 21 ); 22 23 function makeChan(uri) { 24 let chan = NetUtil.newChannel({ 25 uri, 26 loadUsingSystemPrincipal: true, 27 }).QueryInterface(Ci.nsIHttpChannel); 28 chan.loadFlags = Ci.nsIChannel.LOAD_INITIAL_DOCUMENT_URI; 29 return chan; 30 } 31 32 function channelOpenPromise(chan, flags) { 33 return new Promise(resolve => { 34 function finish(req, buffer) { 35 resolve([req, buffer]); 36 } 37 chan.asyncOpen(new ChannelListener(finish, null, flags)); 38 }); 39 } 40 41 async function registerSimplePathHandler(server, path) { 42 return server.registerPathHandler(path, (req, resp) => { 43 resp.writeHead(200); 44 resp.end("done"); 45 }); 46 } 47 48 add_task(async function test_verify_traffic_for_http2() { 49 Services.prefs.setBoolPref( 50 "network.http.http2.move_to_pending_list_after_network_change", 51 true 52 ); 53 54 // Bug 1878505: It seems when HTTPS RR is enabled, a speculative 55 // connection that waits to receive a HTTPS response will receive it 56 // after the actual connection is established, leading to an extra 57 // connection being established. 58 Services.prefs.setIntPref("network.http.speculative-parallel-limit", 0); 59 60 let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService( 61 Ci.nsIX509CertDB 62 ); 63 addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u"); 64 65 let server = new NodeHTTP2Server(); 66 await server.start(); 67 registerCleanupFunction(async () => { 68 Services.prefs.clearUserPref( 69 "network.http.http2.move_to_pending_list_after_network_change" 70 ); 71 await server.stop(); 72 }); 73 74 try { 75 await server.registerPathHandler("/longDelay", (req, resp) => { 76 // eslint-disable-next-line mozilla/no-arbitrary-setTimeout, no-undef 77 setTimeout(function () { 78 resp.writeHead(200); 79 resp.end("done"); 80 }, 8000); 81 }); 82 } catch (e) {} 83 84 await registerSimplePathHandler(server, "/test"); 85 86 // Send some requests and check if we have only one h2 session. 87 for (let i = 0; i < 2; i++) { 88 let chan = makeChan(`https://localhost:${server.port()}/test`); 89 await channelOpenPromise(chan, CL_ALLOW_UNKNOWN_CL); 90 } 91 let sessionCount = await server.sessionCount(); 92 Assert.equal(sessionCount, 1); 93 94 let res = await new Promise(resolve => { 95 // Create a request that takes 8s to finish. 96 let chan = makeChan(`https://localhost:${server.port()}/longDelay`); 97 chan.asyncOpen(new ChannelListener(resolve, null, CL_ALLOW_UNKNOWN_CL)); 98 99 // Send a network change event to trigger VerifyTraffic(). After this, 100 // the connnection will be put in the pending list. 101 // We'll crate a new connection for the new request. 102 Services.obs.notifyObservers( 103 null, 104 "network:link-status-changed", 105 "changed" 106 ); 107 108 // This request will use the new connection. 109 let chan1 = makeChan(`https://localhost:${server.port()}/test`); 110 chan1.asyncOpen(new ChannelListener(() => {}, null, CL_ALLOW_UNKNOWN_CL)); 111 }); 112 113 // The connection in the pending list should be still working. 114 Assert.equal(res.status, Cr.NS_OK); 115 Assert.equal(res.QueryInterface(Ci.nsIHttpChannel).responseStatus, 200); 116 117 sessionCount = await server.sessionCount(); 118 Assert.equal(sessionCount, 2); 119 120 // Create another request and trigger the network change event again. 121 // The second network change event is to put the second connection into the 122 // pending list. 123 res = await new Promise(resolve => { 124 // Create a request that takes 8s to finish. 125 let chan = makeChan(`https://localhost:${server.port()}/longDelay`); 126 chan.asyncOpen(new ChannelListener(resolve, null, CL_ALLOW_UNKNOWN_CL)); 127 128 Services.obs.notifyObservers( 129 null, 130 "network:link-status-changed", 131 "changed" 132 ); 133 }); 134 135 Assert.equal(res.status, Cr.NS_OK); 136 Assert.equal(res.QueryInterface(Ci.nsIHttpChannel).responseStatus, 200); 137 138 async function getSocketCount() { 139 return new Promise(resolve => { 140 gDashboard.requestSockets(function (data) { 141 resolve(data.sockets.length); 142 }); 143 }); 144 } 145 146 await TestUtils.waitForCondition(async () => { 147 const socketCount = await getSocketCount(); 148 return socketCount === 0; 149 }, "Socket count should be 0"); 150 151 await server.stop(); 152 });