tor-browser

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

test_cors_preflight_dns_cache.js (5835B)


      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 var { setTimeout } = ChromeUtils.importESModule(
      8  "resource://gre/modules/Timer.sys.mjs"
      9 );
     10 
     11 const { NodeHTTP2Server } = ChromeUtils.importESModule(
     12  "resource://testing-common/NodeServer.sys.mjs"
     13 );
     14 
     15 /* import-globals-from head_cache.js */
     16 /* import-globals-from head_cookies.js */
     17 /* import-globals-from head_channels.js */
     18 
     19 function channelOpenPromise(chan, flags) {
     20  return new Promise(resolve => {
     21    function finish(req, buffer) {
     22      resolve([req, buffer]);
     23    }
     24    chan.asyncOpen(new ChannelListener(finish, null, flags));
     25  });
     26 }
     27 
     28 let trrServer;
     29 let server;
     30 let preflightCache;
     31 
     32 add_setup(async function () {
     33  trr_test_setup();
     34 
     35  trrServer = new TRRServer();
     36  await trrServer.start();
     37 
     38  await trrServer.registerDoHAnswers("alt1.example.com", "A", {
     39    answers: [
     40      {
     41        name: "alt1.example.com",
     42        ttl: 55,
     43        type: "A",
     44        flush: false,
     45        data: "127.0.0.1",
     46      },
     47    ],
     48  });
     49  await trrServer.registerDoHAnswers("alt2.example.com", "A", {
     50    answers: [
     51      {
     52        name: "alt2.example.com",
     53        ttl: 55,
     54        type: "A",
     55        flush: false,
     56        data: "127.0.0.1",
     57      },
     58    ],
     59  });
     60 
     61  Services.prefs.setIntPref("network.trr.mode", 3);
     62  Services.prefs.setCharPref(
     63    "network.trr.uri",
     64    `https://foo.example.com:${trrServer.port()}/dns-query`
     65  );
     66 
     67  preflightCache = Cc["@mozilla.org/network/cors-preflight-cache;1"].getService(
     68    Ci.nsICORSPreflightCache
     69  );
     70 
     71  server = new NodeHTTP2Server();
     72  await server.start();
     73  await server.registerPathHandler("/", (req, resp) => {
     74    resp.setHeader("Access-Control-Allow-Methods", "PUT");
     75    resp.setHeader("Access-Control-Allow-Origin", "https://example.org");
     76    resp.writeHead(200);
     77    resp.end(global.server_name);
     78  });
     79 
     80  registerCleanupFunction(async () => {
     81    trr_clear_prefs();
     82    if (trrServer) {
     83      await trrServer.stop();
     84    }
     85    await server.stop();
     86  });
     87 });
     88 
     89 function createCORSRequest(corsURI) {
     90  let uri = NetUtil.newURI(corsURI);
     91  let principal = Services.scriptSecurityManager.createContentPrincipal(uri, {
     92    firstPartyDomain: "https://example.org",
     93  });
     94  let channel = NetUtil.newChannel({
     95    uri,
     96    loadingPrincipal: principal,
     97    securityFlags: Ci.nsILoadInfo.SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT,
     98    contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER,
     99  }).QueryInterface(Ci.nsIHttpChannel);
    100  channel.requestMethod = "PUT";
    101  let triggeringPrincipal =
    102    Services.scriptSecurityManager.createContentPrincipal(
    103      NetUtil.newURI("https://example.org/"),
    104      {
    105        firstPartyDomain: "https://example.org",
    106      }
    107    );
    108 
    109  channel.loadInfo.setTriggeringPrincipalForTesting(triggeringPrincipal);
    110  return [channel, principal];
    111 }
    112 
    113 async function runCORSTest({
    114  uri,
    115  expectedPreflightCount,
    116  beforeSecondRequest = () => {},
    117 }) {
    118  let preflightRequestCount = 0;
    119 
    120  const observer = {
    121    QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
    122    observe(aSubject, aTopic) {
    123      aSubject = aSubject.QueryInterface(Ci.nsIHttpChannel);
    124      if (aTopic === "http-on-before-connect" && aSubject.URI.spec === uri) {
    125        dump("aSubject.requestMethod:" + aSubject.requestMethod + "\n");
    126        if (aSubject.requestMethod === "OPTIONS") {
    127          preflightRequestCount++;
    128        }
    129      }
    130    },
    131  };
    132 
    133  Services.obs.addObserver(observer, "http-on-before-connect");
    134 
    135  // First request
    136  let [channel, principal] = createCORSRequest(uri);
    137  await channelOpenPromise(channel, CL_ALLOW_UNKNOWN_CL);
    138 
    139  let entries = preflightCache.getEntries(principal);
    140  Assert.equal(entries.length, 1);
    141  Assert.equal(entries[0].URI.asciiSpec, uri);
    142 
    143  await beforeSecondRequest();
    144 
    145  // Second request
    146  let [secondChannel] = createCORSRequest(uri);
    147  await channelOpenPromise(secondChannel, CL_ALLOW_UNKNOWN_CL);
    148 
    149  Assert.equal(preflightRequestCount, expectedPreflightCount);
    150 
    151  Services.obs.removeObserver(observer, "http-on-before-connect");
    152 }
    153 
    154 add_task(async function test_cors_with_valid_dns_cache() {
    155  const corsURI = `https://alt1.example.com:${server.port()}/`;
    156  await runCORSTest({
    157    uri: corsURI,
    158    expectedPreflightCount: 1,
    159  });
    160 });
    161 
    162 add_task(async function test_cors_without_valid_dns_cache() {
    163  const corsURI = `https://alt2.example.com:${server.port()}/`;
    164  Services.dns.clearCache(true); // clear before first request
    165  await runCORSTest({
    166    uri: corsURI,
    167    expectedPreflightCount: 2,
    168    beforeSecondRequest: async () => {
    169      Services.dns.clearCache(true);
    170    },
    171  });
    172 });
    173 
    174 add_task(async function test_cors_with_dns_cache_changed() {
    175  const corsURI = `https://alt2.example.com:${server.port()}/`;
    176  Services.dns.clearCache(true); // clear before first request
    177  await runCORSTest({
    178    uri: corsURI,
    179    expectedPreflightCount: 2,
    180    beforeSecondRequest: async () => {
    181      Services.dns.clearCache(true);
    182      // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
    183      await new Promise(resolve => setTimeout(resolve, 500));
    184 
    185      await trrServer.registerDoHAnswers("alt2.example.com", "A", {
    186        answers: [
    187          {
    188            name: "alt2.example.com",
    189            ttl: 55,
    190            type: "A",
    191            flush: false,
    192            data: "127.0.0.1",
    193          },
    194          {
    195            name: "alt2.example.com",
    196            ttl: 55,
    197            type: "A",
    198            flush: false,
    199            data: "127.0.0.3",
    200          },
    201        ],
    202      });
    203 
    204      const oa = {
    205        firstPartyDomain: "https://example.org",
    206      };
    207      await new TRRDNSListener("alt2.example.com", {
    208        expectedAnswer: "127.0.0.1",
    209        originAttributes: oa,
    210      });
    211    },
    212  });
    213 });