tor-browser

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

test_transparent_redirect.js (3034B)


      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 const { HttpServer } = ChromeUtils.importESModule(
      8  "resource://testing-common/httpd.sys.mjs"
      9 );
     10 
     11 const SUCCESS_TEXT = "success!";
     12 
     13 function successResponseHandler(req, resp) {
     14  var text = SUCCESS_TEXT;
     15  resp.setHeader("Content-Type", "text/plain", false);
     16  resp.bodyOutputStream.write(text, text.length);
     17 }
     18 
     19 function onBeforeConnect(callback) {
     20  Services.obs.addObserver(
     21    {
     22      observe(subject) {
     23        Services.obs.removeObserver(this, "http-on-before-connect");
     24        callback(subject.QueryInterface(Ci.nsIHttpChannel));
     25      },
     26    },
     27    "http-on-before-connect"
     28  );
     29 }
     30 
     31 function onExamineResponse(callback) {
     32  Services.obs.addObserver(
     33    {
     34      observe(subject) {
     35        Services.obs.removeObserver(this, "http-on-examine-response");
     36        callback(subject.QueryInterface(Ci.nsIHttpChannel));
     37      },
     38    },
     39    "http-on-examine-response"
     40  );
     41 }
     42 
     43 class EventSinkListener {
     44  getInterface(iid) {
     45    if (iid.equals(Ci.nsIChannelEventSink)) {
     46      return this;
     47    }
     48    throw Components.Exception("", Cr.NS_ERROR_NO_INTERFACE);
     49  }
     50  asyncOnChannelRedirect(oldChan, newChan, flags, callback) {
     51    // if transparent, asyncOnChannelRedirect should not be called.
     52    Assert.ok(false);
     53    callback.onRedirectVerifyCallback(Cr.NS_OK);
     54  }
     55 }
     56 
     57 EventSinkListener.prototype.QueryInterface = ChromeUtils.generateQI([
     58  "nsIInterfaceRequestor",
     59  "nsIChannelEventSink",
     60 ]);
     61 
     62 add_task(async function test_transparent_redirect() {
     63  var server = new HttpServer();
     64  await server.start(-1);
     65  registerCleanupFunction(async () => {
     66    await server.stop();
     67  });
     68 
     69  server.registerPathHandler("/success", successResponseHandler);
     70 
     71  const baseUrl = `http://localhost:${server.identity.primaryPort}/`;
     72  const successUrl = baseUrl + "success";
     73 
     74  onBeforeConnect(chan => {
     75    chan.suspend();
     76    Promise.resolve().then(() => {
     77      try {
     78        chan.transparentRedirectTo(Services.io.newURI(successUrl));
     79      } catch (e) {
     80        do_throw(e);
     81      }
     82      chan.resume();
     83    });
     84  });
     85 
     86  onExamineResponse(chan => {
     87    chan.QueryInterface(Ci.nsITimedChannel);
     88    Assert.equal(chan.redirectCount, 0, "redirectCount should be 0");
     89    Assert.equal(
     90      chan.internalRedirectCount,
     91      1,
     92      "internalRedirectCount should be 1"
     93    );
     94  });
     95 
     96  let chan = NetUtil.newChannel({
     97    uri: baseUrl,
     98    loadUsingSystemPrincipal: true,
     99  }).QueryInterface(Ci.nsIHttpChannelInternal);
    100  let listener = new EventSinkListener();
    101  chan.notificationCallbacks = listener;
    102 
    103  await new Promise(resolve => {
    104    chan.asyncOpen(
    105      new ChannelListener(
    106        (req, resp) => {
    107          // Should hit /success for both.
    108          Assert.equal(resp, SUCCESS_TEXT, "Should redirect to success");
    109          resolve();
    110        },
    111        null,
    112        CL_ALLOW_UNKNOWN_CL
    113      )
    114    );
    115  });
    116 });