Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { HttpServer } = ChromeUtils.importESModule(
);
const SUCCESS_TEXT = "success!";
function successResponseHandler(req, resp) {
var text = SUCCESS_TEXT;
resp.setHeader("Content-Type", "text/plain", false);
resp.bodyOutputStream.write(text, text.length);
}
function onBeforeConnect(callback) {
Services.obs.addObserver(
{
observe(subject) {
Services.obs.removeObserver(this, "http-on-before-connect");
callback(subject.QueryInterface(Ci.nsIHttpChannel));
},
},
"http-on-before-connect"
);
}
function onExamineResponse(callback) {
Services.obs.addObserver(
{
observe(subject) {
Services.obs.removeObserver(this, "http-on-examine-response");
callback(subject.QueryInterface(Ci.nsIHttpChannel));
},
},
"http-on-examine-response"
);
}
class EventSinkListener {
getInterface(iid) {
if (iid.equals(Ci.nsIChannelEventSink)) {
return this;
}
throw Components.Exception("", Cr.NS_ERROR_NO_INTERFACE);
}
asyncOnChannelRedirect(oldChan, newChan, flags, callback) {
// if transparent, asyncOnChannelRedirect should not be called.
Assert.ok(false);
callback.onRedirectVerifyCallback(Cr.NS_OK);
}
}
EventSinkListener.prototype.QueryInterface = ChromeUtils.generateQI([
"nsIInterfaceRequestor",
"nsIChannelEventSink",
]);
add_task(async function test_transparent_redirect() {
var server = new HttpServer();
await server.start(-1);
registerCleanupFunction(async () => {
await server.stop();
});
server.registerPathHandler("/success", successResponseHandler);
const baseUrl = `http://localhost:${server.identity.primaryPort}/`;
const successUrl = baseUrl + "success";
onBeforeConnect(chan => {
chan.suspend();
Promise.resolve().then(() => {
try {
chan.transparentRedirectTo(Services.io.newURI(successUrl));
} catch (e) {
do_throw(e);
}
chan.resume();
});
});
onExamineResponse(chan => {
chan.QueryInterface(Ci.nsITimedChannel);
Assert.equal(chan.redirectCount, 0, "redirectCount should be 0");
Assert.equal(
chan.internalRedirectCount,
1,
"internalRedirectCount should be 1"
);
});
let chan = NetUtil.newChannel({
uri: baseUrl,
loadUsingSystemPrincipal: true,
}).QueryInterface(Ci.nsIHttpChannelInternal);
let listener = new EventSinkListener();
chan.notificationCallbacks = listener;
await new Promise(resolve => {
chan.asyncOpen(
new ChannelListener(
(req, resp) => {
// Should hit /success for both.
Assert.equal(resp, SUCCESS_TEXT, "Should redirect to success");
resolve();
},
null,
CL_ALLOW_UNKNOWN_CL
)
);
});
});