tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 );