tor-browser

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

browser_set_response_override.js (6768B)


      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 // Test for the nsIHttpChannelInternal helper setResponseOverride.
      8 // which allows to bypass the network for a request before connect, and
      9 // reply with a mocked response instead.
     10 add_task(async function test_set_response_override() {
     11  let observer = {
     12    QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
     13    observe(aSubject, aTopic) {
     14      aSubject = aSubject.QueryInterface(Ci.nsIHttpChannelInternal);
     15      if (
     16        aTopic == "http-on-before-connect" &&
     17        aSubject.URI.spec ==
     18          "https://example.com/browser/netwerk/test/browser/dummy.html"
     19      ) {
     20        const replacedHttpResponse = Cc[
     21          "@mozilla.org/network/replaced-http-response;1"
     22        ].createInstance(Ci.nsIReplacedHttpResponse);
     23        replacedHttpResponse.responseStatus = 200;
     24        replacedHttpResponse.responseStatusText = "Och Aye";
     25        replacedHttpResponse.responseBody =
     26          "<div id=from-response-override>From setResponseOverride";
     27        replacedHttpResponse.setResponseHeader(
     28          "some-header",
     29          "some-value",
     30          false
     31        );
     32        replacedHttpResponse.setResponseHeader(
     33          "Set-Cookie",
     34          "foo=bar;Path=/",
     35          false
     36        );
     37        aSubject.setResponseOverride(replacedHttpResponse);
     38      }
     39    },
     40  };
     41  Services.obs.addObserver(observer, "http-on-before-connect");
     42 
     43  const onTabLoaded = BrowserTestUtils.withNewTab(
     44    {
     45      gBrowser,
     46      url: "https://example.com/browser/netwerk/test/browser/dummy.html",
     47      waitForLoad: true,
     48    },
     49    async function (browser) {
     50      await ContentTask.spawn(browser, [], async function () {
     51        Assert.ok(
     52          !!content.document.getElementById("from-response-override"),
     53          "Page was loaded using the response override"
     54        );
     55        Assert.equal(
     56          content.document.cookie,
     57          "foo=bar",
     58          "Cookie was set from the response override headers"
     59        );
     60 
     61        // Perform another request to the same URL to check status and headers override.
     62        const response = await content.fetch(
     63          "https://example.com/browser/netwerk/test/browser/dummy.html"
     64        );
     65        Assert.equal(
     66          response.status,
     67          200,
     68          "Status was set from the response override"
     69        );
     70        Assert.equal(
     71          response.statusText,
     72          "Och Aye",
     73          "Status text was set from the response override"
     74        );
     75        Assert.equal(
     76          response.headers.get("some-header"),
     77          "some-value",
     78          "same-header header was set from the response override"
     79        );
     80      });
     81    }
     82  );
     83  await onTabLoaded;
     84 
     85  Services.obs.removeObserver(observer, "http-on-before-connect");
     86 });
     87 
     88 // Test that a response override with 302 Found status + Location header
     89 // redirects to the URL specified in the Location header.
     90 add_task(async function test_set_response_override_redirects() {
     91  let observer = {
     92    QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
     93    observe(aSubject, aTopic) {
     94      aSubject = aSubject.QueryInterface(Ci.nsIHttpChannelInternal);
     95      if (
     96        aTopic == "http-on-before-connect" &&
     97        aSubject.URI.spec ==
     98          "https://example.com/browser/netwerk/test/browser/dummy.html"
     99      ) {
    100        const replacedHttpResponse = Cc[
    101          "@mozilla.org/network/replaced-http-response;1"
    102        ].createInstance(Ci.nsIReplacedHttpResponse);
    103        replacedHttpResponse.responseStatus = 302;
    104        replacedHttpResponse.responseStatusText = "Found";
    105        replacedHttpResponse.setResponseHeader(
    106          "Location",
    107          "https://example.com/browser/netwerk/test/browser/dummy.html?redirected=true",
    108          false
    109        );
    110        aSubject.setResponseOverride(replacedHttpResponse);
    111      }
    112    },
    113  };
    114  Services.obs.addObserver(observer, "http-on-before-connect");
    115 
    116  const onTabLoaded = BrowserTestUtils.withNewTab(
    117    {
    118      gBrowser,
    119      url: "https://example.com/browser/netwerk/test/browser/dummy.html",
    120      waitForLoad: true,
    121    },
    122    async function (browser) {
    123      await ContentTask.spawn(browser, [], async function () {
    124        Assert.equal(
    125          content.location.href,
    126          "https://example.com/browser/netwerk/test/browser/dummy.html?redirected=true",
    127          "Navigation was redirected based on the overridden response"
    128        );
    129      });
    130    }
    131  );
    132  await onTabLoaded;
    133 
    134  Services.obs.removeObserver(observer, "http-on-before-connect");
    135 });
    136 
    137 // Test that a response override for a requst with CORS preflight succeeds without
    138 // crashing Firefox.
    139 add_task(async function test_set_response_override_cors_preflight() {
    140  let observer = {
    141    QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
    142    observe(aSubject, aTopic) {
    143      aSubject = aSubject.QueryInterface(Ci.nsIHttpChannelInternal);
    144      if (
    145        aTopic == "http-on-before-connect" &&
    146        aSubject.URI.spec == "https://example.org/cors"
    147      ) {
    148        const replacedHttpResponse = Cc[
    149          "@mozilla.org/network/replaced-http-response;1"
    150        ].createInstance(Ci.nsIReplacedHttpResponse);
    151        replacedHttpResponse.responseStatus = 200;
    152        replacedHttpResponse.responseStatusText = "OK";
    153        replacedHttpResponse.responseBody = "From setResponseOverride";
    154        replacedHttpResponse.setResponseHeader(
    155          "Access-Control-Allow-Origin",
    156          "*",
    157          false
    158        );
    159 
    160        aSubject.setResponseOverride(replacedHttpResponse);
    161      }
    162    },
    163  };
    164  Services.obs.addObserver(observer, "http-on-before-connect");
    165 
    166  await BrowserTestUtils.withNewTab(
    167    {
    168      gBrowser,
    169      url: "https://example.com/browser/netwerk/test/browser/dummy.html",
    170      waitForLoad: true,
    171    },
    172    async function (browser) {
    173      await ContentTask.spawn(browser, [], async function () {
    174        const response = await content.fetch("https://example.org/cors", {
    175          // extra header to force a CORS preflight request.
    176          headers: { "X-PINGOTHER": "pingpong" },
    177        });
    178        // Note: https://example.org/cors does not exist, so simply receiving
    179        // a response here already means the override was successful.
    180        Assert.equal(
    181          response.status,
    182          200,
    183          "Status was set from the response override"
    184        );
    185        Assert.equal(
    186          await response.text(),
    187          "From setResponseOverride",
    188          "Text content was set from the response override"
    189        );
    190      });
    191    }
    192  );
    193 
    194  Services.obs.removeObserver(observer, "http-on-before-connect");
    195 });