test_connection_coalescing.js (6040B)
1 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 "use strict"; 7 8 const { NodeHTTP2Server } = ChromeUtils.importESModule( 9 "resource://testing-common/NodeServer.sys.mjs" 10 ); 11 12 const { AppConstants } = ChromeUtils.importESModule( 13 "resource://gre/modules/AppConstants.sys.mjs" 14 ); 15 16 const override = Cc["@mozilla.org/network/native-dns-override;1"].getService( 17 Ci.nsINativeDNSResolverOverride 18 ); 19 20 let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService( 21 Ci.nsIX509CertDB 22 ); 23 addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u"); 24 25 async function createServer() { 26 let server = new NodeHTTP2Server(); 27 await server.start(); 28 registerCleanupFunction(async () => { 29 await server.stop(); 30 }); 31 await server.registerPathHandler("/", (req, resp) => { 32 let content = `hello from ${req.authority} | ${req.socket.remotePort}`; 33 resp.writeHead(200, { 34 "Content-Type": "text/plain", 35 "Content-Length": `${content.length}`, 36 }); 37 resp.end(content); 38 }); 39 return server; 40 } 41 42 let IP1 = "127.0.0.1"; 43 let IP2 = "127.0.0.2"; 44 if (AppConstants.platform == "macosx") { 45 // OSX doesn't use 127.0.0.2 as a local interface 46 IP2 = "::1"; 47 } else if (AppConstants.platform == "android") { 48 IP2 = "10.0.2.2"; 49 } 50 51 async function openChan(uri) { 52 let chan = NetUtil.newChannel({ 53 uri, 54 loadUsingSystemPrincipal: true, 55 }).QueryInterface(Ci.nsIHttpChannel); 56 chan.loadFlags = Ci.nsIChannel.LOAD_INITIAL_DOCUMENT_URI; 57 58 let { req, buffer } = await new Promise(resolve => { 59 function finish(r, b) { 60 resolve({ req: r, buffer: b }); 61 } 62 chan.asyncOpen(new ChannelListener(finish, null, CL_ALLOW_UNKNOWN_CL)); 63 }); 64 65 return { 66 buffer, 67 port: buffer.split("|")[1], 68 addr: req.QueryInterface(Ci.nsIHttpChannelInternal).remoteAddress, 69 status: req.QueryInterface(Ci.nsIHttpChannel).responseStatus, 70 }; 71 } 72 73 add_task(async function test_dontCoalesce() { 74 let server = await createServer(); 75 Services.prefs.setBoolPref("network.http.http2.aggressive_coalescing", false); 76 override.clearOverrides(); 77 Services.dns.clearCache(true); 78 79 override.addIPOverride("foo.example.com", IP1); 80 override.addIPOverride("foo.example.com", IP2); 81 override.addIPOverride("alt1.example.com", IP2); 82 83 let { addr: addr1 } = await openChan( 84 `https://foo.example.com:${server.port()}/` 85 ); 86 let { addr: addr2 } = await openChan( 87 `https://alt1.example.com:${server.port()}/` 88 ); 89 90 Assert.notEqual(addr1, addr2); 91 await server.stop(); 92 }); 93 94 add_task(async function test_doCoalesce() { 95 let server = await createServer(); 96 Services.prefs.setBoolPref("network.http.http2.aggressive_coalescing", false); 97 override.clearOverrides(); 98 Services.dns.clearCache(true); 99 100 override.addIPOverride("foo.example.com", IP1); 101 override.addIPOverride("foo.example.com", IP2); 102 override.addIPOverride("alt2.example.com", IP1); 103 override.addIPOverride("alt2.example.com", IP2); 104 105 let { port: port1, addr: addr1 } = await openChan( 106 `https://foo.example.com:${server.port()}/` 107 ); 108 let { port: port2, addr: addr2 } = await openChan( 109 `https://alt2.example.com:${server.port()}/` 110 ); 111 112 Assert.equal(addr1, addr2); 113 Assert.equal(port1, port2); 114 await server.stop(); 115 }); 116 117 add_task(async function test_doCoalesceAggresive() { 118 let server = await createServer(); 119 120 Services.prefs.setBoolPref("network.http.http2.aggressive_coalescing", true); 121 override.clearOverrides(); 122 Services.dns.clearCache(true); 123 124 override.addIPOverride("foo.example.com", IP1); 125 override.addIPOverride("foo.example.com", IP2); 126 override.addIPOverride("alt1.example.com", IP2); 127 128 let { port: port1, addr: addr1 } = await openChan( 129 `https://foo.example.com:${server.port()}/` 130 ); 131 let { port: port2, addr: addr2 } = await openChan( 132 `https://alt1.example.com:${server.port()}/` 133 ); 134 135 Assert.equal(addr1, addr2); 136 Assert.equal(port1, port2); 137 await server.stop(); 138 }); 139 140 // On android because of the way networking is set up the 141 // localAddress is always ::ffff:127.0.0.1 so it can't be 142 // used to make a decision. 143 add_task( 144 { skip_if: () => AppConstants.platform == "android" }, 145 async function test_doCoalesceAggresive421() { 146 let server = await createServer(); 147 148 await server.execute(`global.rightIP = "${IP2}"`); 149 150 await server.registerPathHandler("/", (req, resp) => { 151 let content = `hello from ${req.authority} | ${req.socket.remotePort}`; 152 // Check that returning 421 when aggresively coalescing 153 // makes Firefox not coalesce the connections. 154 if ( 155 req.authority.startsWith("alt1.example.com") && 156 req.socket.localAddress != global.rightIP && 157 req.socket.localAddress != `::ffff:${global.rightIP}` 158 ) { 159 resp.writeHead(421, { 160 "Content-Type": "text/plain", 161 "Content-Length": `${content.length}`, 162 }); 163 resp.end(content); 164 return; 165 } 166 resp.writeHead(200, { 167 "Content-Type": "text/plain", 168 "Content-Length": `${content.length}`, 169 }); 170 resp.end(content); 171 }); 172 173 Services.prefs.setBoolPref( 174 "network.http.http2.aggressive_coalescing", 175 true 176 ); 177 override.clearOverrides(); 178 Services.dns.clearCache(true); 179 180 override.addIPOverride("foo.example.com", IP1); 181 override.addIPOverride("foo.example.com", IP2); 182 override.addIPOverride("alt1.example.com", IP2); 183 184 let { 185 addr: addr1, 186 status: status1, 187 port: port1, 188 } = await openChan(`https://foo.example.com:${server.port()}/`); 189 Assert.equal(status1, 200); 190 Assert.equal(addr1, IP1); 191 let { 192 addr: addr2, 193 status: status2, 194 port: port2, 195 } = await openChan(`https://alt1.example.com:${server.port()}/`); 196 197 Assert.equal(status2, 200); 198 Assert.equal(addr2, IP2); 199 Assert.notEqual(port1, port2); 200 await server.stop(); 201 } 202 );