tor-browser

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

test_http3_alt_svc.js (5852B)


      1 "use strict";
      2 
      3 const { HTTP3Server } = ChromeUtils.importESModule(
      4  "resource://testing-common/NodeServer.sys.mjs"
      5 );
      6 
      7 let httpsOrigin;
      8 let h3AltSvc;
      9 let h3Route;
     10 let h3Port;
     11 let h3ServerPath;
     12 let h3DBPath;
     13 let prefs;
     14 
     15 let tests = [
     16  test_https_alt_svc,
     17  test_https_alt_svc_1,
     18  test_https_speculativeConnect_alt_svc,
     19  testsDone,
     20 ];
     21 
     22 let current_test = 0;
     23 
     24 function run_next_test() {
     25  if (current_test < tests.length) {
     26    dump("starting test number " + current_test + "\n");
     27    tests[current_test]();
     28    current_test++;
     29  }
     30 }
     31 
     32 function setupAltSvc() {
     33  h3AltSvc = ":" + h3Port;
     34  h3Route = "foo.example.com:" + h3Port;
     35 }
     36 
     37 function run_test() {
     38  let h2Port = Services.env.get("MOZHTTP2_PORT");
     39  Assert.notEqual(h2Port, null);
     40  Assert.notEqual(h2Port, "");
     41 
     42  h3ServerPath = Services.env.get("MOZ_HTTP3_SERVER_PATH");
     43  h3DBPath = Services.env.get("MOZ_HTTP3_CERT_DB_PATH");
     44 
     45  do_get_profile();
     46  prefs = Services.prefs;
     47 
     48  prefs.setBoolPref("network.http.http3.enable", true);
     49  prefs.setCharPref("network.dns.localDomains", "foo.example.com");
     50  // We always resolve elements of localDomains as it's hardcoded without the
     51  // following pref:
     52  prefs.setBoolPref("network.proxy.allow_hijacking_localhost", true);
     53 
     54  // The certificate for the http3server server is for foo.example.com and
     55  // is signed by http2-ca.pem so add that cert to the trust list as a
     56  // signing cert.
     57  let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
     58    Ci.nsIX509CertDB
     59  );
     60  addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u");
     61  httpsOrigin = "https://foo.example.com:" + h2Port + "/";
     62 
     63  run_next_test();
     64 }
     65 
     66 function createPrincipal(url) {
     67  var ssm = Services.scriptSecurityManager;
     68  try {
     69    return ssm.createContentPrincipal(Services.io.newURI(url), {});
     70  } catch (e) {
     71    return null;
     72  }
     73 }
     74 
     75 function makeChan(uri) {
     76  let chan = NetUtil.newChannel({
     77    uri,
     78    loadingPrincipal: createPrincipal(uri),
     79    securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT,
     80    contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT,
     81  }).QueryInterface(Ci.nsIHttpChannel);
     82  chan.loadFlags = Ci.nsIChannel.LOAD_INITIAL_DOCUMENT_URI;
     83  return chan;
     84 }
     85 
     86 let WaitForHttp3Listener = function (expectedH3Version) {
     87  this._expectedH3Version = expectedH3Version;
     88 };
     89 
     90 WaitForHttp3Listener.prototype = {
     91  onDataAvailableFired: false,
     92  expectedRoute: "",
     93 
     94  onStartRequest: function testOnStartRequest(request) {
     95    Assert.ok(request instanceof Ci.nsIHttpChannel);
     96    Assert.equal(request.responseStatus, 200);
     97  },
     98 
     99  onDataAvailable: function testOnDataAvailable(request, stream, off, cnt) {
    100    this.onDataAvailableFired = true;
    101    read_stream(stream, cnt);
    102  },
    103 
    104  onStopRequest: function testOnStopRequest(request) {
    105    let routed = "NA";
    106    try {
    107      routed = request.getRequestHeader("Alt-Used");
    108    } catch (e) {}
    109    dump("routed is " + routed + "\n");
    110 
    111    if (routed == this.expectedRoute) {
    112      let httpVersion = "";
    113      try {
    114        httpVersion = request.protocolVersion;
    115      } catch (e) {}
    116      Assert.equal(httpVersion, this._expectedH3Version);
    117      run_next_test();
    118    } else {
    119      dump("poll later for alt svc mapping\n");
    120      do_test_pending();
    121      do_timeout(500, () => {
    122        doTest(
    123          this.uri,
    124          this.expectedRoute,
    125          this.h3AltSvc,
    126          this._expectedH3Version
    127        );
    128      });
    129    }
    130 
    131    do_test_finished();
    132  },
    133 };
    134 
    135 function doTest(uri, expectedRoute, altSvc, expectedH3Version) {
    136  let chan = makeChan(uri);
    137  let listener = new WaitForHttp3Listener(expectedH3Version);
    138  listener.uri = uri;
    139  listener.expectedRoute = expectedRoute;
    140  listener.h3AltSvc = altSvc;
    141  chan.setRequestHeader("x-altsvc", altSvc, false);
    142  chan.asyncOpen(listener);
    143 }
    144 
    145 // Test Alt-Svc for http3.
    146 // H2 server returns alt-svc=h2=foo2.example.com:8000,h3=:h3port
    147 function test_https_alt_svc() {
    148  dump("test_https_alt_svc()\n");
    149 
    150  do_test_pending();
    151 
    152  let server = new HTTP3Server();
    153  server
    154    .start(h3ServerPath, h3DBPath)
    155    .then(() => {
    156      h3Port = server.port();
    157      setupAltSvc();
    158      doTest(httpsOrigin + "http3-test2", h3Route, h3AltSvc, "h3");
    159    })
    160    .catch(_ => {});
    161 }
    162 
    163 // Test if we use the latest version of HTTP/3.
    164 // H2 server returns alt-svc=h3=:h3port,h3=:h3port
    165 function test_https_alt_svc_1() {
    166  dump("test_https_alt_svc_1()\n");
    167  Services.obs.notifyObservers(null, "last-pb-context-exited");
    168  Services.obs.notifyObservers(null, "net:cancel-all-connections");
    169 
    170  do_test_pending();
    171 
    172  let server = new HTTP3Server();
    173  server
    174    .start(h3ServerPath, h3DBPath)
    175    .then(() => {
    176      h3Port = server.port();
    177      setupAltSvc();
    178      doTest(httpsOrigin + "http3-test3", h3Route, h3AltSvc, "h3");
    179    })
    180    .catch(_ => {});
    181 }
    182 
    183 function test_https_speculativeConnect_alt_svc() {
    184  dump("test_https_speculativeConnect_alt_svc()\n");
    185 
    186  do_test_pending();
    187 
    188  let observer = {
    189    QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
    190    observe(aSubject, aTopic, aData) {
    191      if (aTopic == "speculative-connect-request") {
    192        Services.obs.removeObserver(observer, "speculative-connect-request");
    193        info("h3Route=" + h3Route + "\n");
    194        info("aData=" + aData + "\n");
    195        Assert.ok(aData.includes(`<ROUTE-via ${h3Route}`));
    196        do_test_finished();
    197      }
    198    },
    199  };
    200  Services.obs.addObserver(observer, "speculative-connect-request");
    201 
    202  Services.prefs.setBoolPref("network.http.debug-observations", true);
    203 
    204  let uri = Services.io.newURI(httpsOrigin);
    205  Services.io.speculativeConnect(
    206    uri,
    207    Services.scriptSecurityManager.getSystemPrincipal(),
    208    null,
    209    false
    210  );
    211 }
    212 
    213 function testsDone() {
    214  prefs.clearUserPref("network.http.http3.enable");
    215  prefs.clearUserPref("network.dns.localDomains");
    216  prefs.clearUserPref("network.proxy.allow_hijacking_localhost");
    217  dump("testDone\n");
    218 }