tor-browser

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

browser_essential_domain_fallbacks.js (5587B)


      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 ChromeUtils.defineESModuleGetters(this, {
      8  RemoteSettings: "resource://services-settings/remote-settings.sys.mjs",
      9  EssentialDomainsRemoteSettings:
     10    "resource://gre/modules/EssentialDomainsRemoteSettings.sys.mjs",
     11  ESSENTIAL_DOMAINS_REMOTE_BUCKET:
     12    "resource://gre/modules/EssentialDomainsRemoteSettings.sys.mjs",
     13 });
     14 
     15 const lazy = {};
     16 ChromeUtils.defineESModuleGetters(lazy, {
     17  AddonSettings: "resource://gre/modules/addons/AddonSettings.sys.mjs",
     18  CertUtils: "resource://gre/modules/CertUtils.sys.mjs",
     19  ServiceRequest: "resource://gre/modules/ServiceRequest.sys.mjs",
     20 });
     21 
     22 const { sinon } = ChromeUtils.importESModule(
     23  "resource://testing-common/Sinon.sys.mjs"
     24 );
     25 
     26 const override = Cc["@mozilla.org/network/native-dns-override;1"].getService(
     27  Ci.nsINativeDNSResolverOverride
     28 );
     29 
     30 const EXPECTED_RESPONSE = "<html><body>\n</body></html>\n";
     31 
     32 add_setup(async function () {
     33  await SpecialPowers.pushPrefEnv({
     34    set: [
     35      ["network.essential_domains_fallback", true],
     36      ["network.proxy.no_proxies_on", "aus5.mozilla.org"],
     37    ],
     38  });
     39 
     40  // Pretend this domain blocked at the DNS layer.
     41  override.addIPOverride("aus5.mozilla.org", "N/A");
     42  registerCleanupFunction(async () => {
     43    override.clearOverrides();
     44  });
     45 
     46  let ncs = Cc[
     47    "@mozilla.org/network/network-connectivity-service;1"
     48  ].getService(Ci.nsINetworkConnectivityService);
     49  ncs.IPv4 = Ci.nsINetworkConnectivityService.OK;
     50 
     51  const settings = await RemoteSettings(ESSENTIAL_DOMAINS_REMOTE_BUCKET);
     52  let stub = sinon.stub(settings, "get").returns(newData);
     53  registerCleanupFunction(async function () {
     54    stub.restore();
     55  });
     56 
     57  await RemoteSettings(ESSENTIAL_DOMAINS_REMOTE_BUCKET).emit("sync", {});
     58 });
     59 
     60 let newData = [
     61  {
     62    id: "111",
     63    from: "aus5.mozilla.org",
     64    to: "test1.example.com",
     65  },
     66 ];
     67 
     68 function read_stream(stream, count) {
     69  /* assume stream has non-ASCII data */
     70  var wrapper = Cc["@mozilla.org/binaryinputstream;1"].createInstance(
     71    Ci.nsIBinaryInputStream
     72  );
     73  wrapper.setInputStream(stream);
     74  /* JS methods can be called with a maximum of 65535 arguments, and input
     75     streams don't have to return all the data they make .available() when
     76     asked to .read() that number of bytes. */
     77  var data = [];
     78  while (count > 0) {
     79    var bytes = wrapper.readByteArray(Math.min(65535, count));
     80    data.push(String.fromCharCode.apply(null, bytes));
     81    count -= bytes.length;
     82    if (!bytes.length) {
     83      throw new Error("Nothing read from input stream!");
     84    }
     85  }
     86  return data.join("");
     87 }
     88 
     89 class SimpleChannelListener {
     90  constructor(callback) {
     91    this._onStopCallback = callback;
     92    this._buffer = "";
     93  }
     94  get QueryInterface() {
     95    return ChromeUtils.generateQI(["nsIStreamListener", "nsIRequestObserver"]);
     96  }
     97 
     98  onStartRequest() {}
     99 
    100  onDataAvailable(request, stream, offset, count) {
    101    this._buffer = this._buffer.concat(read_stream(stream, count));
    102  }
    103 
    104  onStopRequest(request) {
    105    if (this._onStopCallback) {
    106      this._onStopCallback(request, this._buffer);
    107    }
    108  }
    109 }
    110 
    111 function openChannelPromise(url, options = { loadUsingSystemPrincipal: true }) {
    112  let uri = Services.io.newURI(url);
    113  options.uri = uri;
    114  let chan = NetUtil.newChannel(options);
    115  return new Promise(resolve => {
    116    chan.asyncOpen(
    117      new SimpleChannelListener((req, buf) => resolve({ req, buf }))
    118    );
    119  });
    120 }
    121 
    122 add_task(async function test_channel_fallback_on_dns() {
    123  // The host should be replaced with test1.example.com
    124  // if the original channel fails and it's in the remote settings payload.
    125  let { req, buf } = await openChannelPromise(
    126    "https://aus5.mozilla.org/browser/netwerk/cookie/test/browser/file_empty.html"
    127  );
    128  Assert.equal(buf, EXPECTED_RESPONSE);
    129  Assert.equal(req.URI.host, "test1.example.com");
    130 });
    131 
    132 add_task(async function test_service_request_fallback() {
    133  let request = await new Promise((resolve, reject) => {
    134    let request = new lazy.ServiceRequest({ mozAnon: true });
    135    request.open(
    136      "GET",
    137      `https://aus5.mozilla.org/browser/netwerk/cookie/test/browser/file_empty.html`,
    138      true
    139    );
    140    request.channel.notificationCallbacks = new lazy.CertUtils.BadCertHandler(
    141      !lazy.AddonSettings.UPDATE_REQUIREBUILTINCERTS
    142    );
    143    request.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
    144    // Prevent the request from writing to cache.
    145    request.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
    146    request.overrideMimeType("text/plain");
    147    request.timeout = 5000;
    148    request.addEventListener("load", () => resolve(request));
    149    request.addEventListener("error", reject);
    150    request.addEventListener("timeout", reject);
    151    request.send(null);
    152  });
    153  Assert.equal(request.responseText, "<html><body>\n</body></html>\n");
    154  Assert.equal(
    155    request.responseURL,
    156    "https://test1.example.com/browser/netwerk/cookie/test/browser/file_empty.html"
    157  );
    158 });
    159 
    160 add_task(async function test_fetch_request_fallback() {
    161  let response = await fetch(
    162    "https://aus5.mozilla.org/browser/netwerk/cookie/test/browser/file_empty.html",
    163    {
    164      method: "GET",
    165      cache: "no-store", // prevent caching, similar to LOAD_BYPASS_CACHE
    166    }
    167  );
    168 
    169  let text = await response.text();
    170 
    171  Assert.equal(text, "<html><body>\n</body></html>\n");
    172  Assert.equal(
    173    response.url,
    174    "https://test1.example.com/browser/netwerk/cookie/test/browser/file_empty.html"
    175  );
    176 });