const { HttpServer } = ChromeUtils.importESModule( "resource://testing-common/httpd.sys.mjs" ); /* * Test that when doing HTTP requests, the nsIHttpChannel is detected in * both parent and child and shares the same channelId across processes. */ let httpserver; let port; function startHttpServer() { httpserver = new HttpServer(); httpserver.registerPathHandler("/resource", (metadata, response) => { response.setStatusLine(metadata.httpVersion, 200, "OK"); response.setHeader("Content-Type", "text/plain", false); response.setHeader("Cache-Control", "no-cache", false); response.bodyOutputStream.write("data", 4); }); httpserver.registerPathHandler("/redirect", (metadata, response) => { response.setStatusLine(metadata.httpVersion, 302, "Redirect"); response.setHeader("Location", "/resource", false); response.setHeader("Cache-Control", "no-cache", false); }); httpserver.start(-1); port = httpserver.identity.primaryPort; } function stopHttpServer(next) { httpserver.stop(next); } let expectedParentChannels = []; let expectedChildMessages = []; let maybeFinishWaitForParentChannels; let parentChannelsDone = new Promise(resolve => { maybeFinishWaitForParentChannels = () => { if (!expectedParentChannels.length) { dump("All expected parent channels were detected\n"); resolve(); } }; }); function observer(subject) { let channel = subject.QueryInterface(Ci.nsIHttpChannel); let uri = channel.URI.spec; let origUri = channel.originalURI.spec; let id = channel.channelId; dump(`Parent detected channel: ${uri} (orig=${origUri}): channelId=${id}\n`); // did we expect a new channel? let expected = expectedParentChannels.shift(); Assert.ok(!!expected); // Start waiting for the messages about request/response from child for (let event of expected) { let message = `${event}:${id}`; dump(`Expecting message from child: ${message}\n`); let messagePromise = do_await_remote_message(message).then(() => { dump(`Expected message from child arrived: ${message}\n`); }); expectedChildMessages.push(messagePromise); } // If we don't expect any further parent channels, finish the parent wait maybeFinishWaitForParentChannels(); } function run_test() { startHttpServer(); Services.obs.addObserver(observer, "http-on-modify-request"); run_test_in_child("child_channel_id.js", makeRequests); } function makeRequests() { // First, a normal request without any redirect. Expect one channel detected // in parent, used by both request and response. expectedParentChannels.push(["request", "response"]); sendCommand(`makeRequest("http://localhost:${port}/resource");`); // Second request will be redirected. Expect two channels, one with the // original request, then the redirected one which gets the final response. expectedParentChannels.push(["request"], ["response"]); sendCommand(`makeRequest("http://localhost:${port}/redirect");`); waitForParentChannels(); } function waitForParentChannels() { parentChannelsDone.then(waitForChildMessages); } function waitForChildMessages() { dump(`Waiting for ${expectedChildMessages.length} child messages\n`); Promise.all(expectedChildMessages).then(finish); } function finish() { Services.obs.removeObserver(observer, "http-on-modify-request"); sendCommand("finish();", () => stopHttpServer(do_test_finished)); }