// This file tests channel event sinks (bug 315598 et al) "use strict"; const { HttpServer } = ChromeUtils.importESModule( "resource://testing-common/httpd.sys.mjs" ); ChromeUtils.defineLazyGetter(this, "URL", function () { return "http://localhost:" + httpserv.identity.primaryPort; }); const sinkCID = Components.ID("{14aa4b81-e266-45cb-88f8-89595dece114}"); const sinkContract = "@mozilla.org/network/unittest/channeleventsink;1"; const categoryName = "net-channel-event-sinks"; /** * This object is both a factory and an nsIChannelEventSink implementation (so, it * is de-facto a service). It's also an interface requestor that gives out * itself when asked for nsIChannelEventSink. */ var eventsink = { QueryInterface: ChromeUtils.generateQI(["nsIFactory", "nsIChannelEventSink"]), createInstance: function eventsink_ci(iid) { return this.QueryInterface(iid); }, asyncOnChannelRedirect: function eventsink_onredir() { // veto this.called = true; throw Components.Exception("", Cr.NS_BINDING_ABORTED); }, getInterface: function eventsink_gi(iid) { if (iid.equals(Ci.nsIChannelEventSink)) { return this; } throw Components.Exception("", Cr.NS_ERROR_NO_INTERFACE); }, called: false, }; var listener = { expectSinkCall: true, onStartRequest: function test_onStartR(request) { try { // Commenting out this check pending resolution of bug 255119 //if (Components.isSuccessCode(request.status)) // do_throw("Channel should have a failure code!"); // The current URI must be the original URI, as all redirects have been // cancelled if ( !(request instanceof Ci.nsIChannel) || !request.URI.equals(request.originalURI) ) { do_throw( "Wrong URI: Is <" + request.URI.spec + ">, should be <" + request.originalURI.spec + ">" ); } if (request instanceof Ci.nsIHttpChannel) { // As we expect a blocked redirect, verify that we have a 3xx status Assert.equal(Math.floor(request.responseStatus / 100), 3); Assert.equal(request.requestSucceeded, false); } Assert.equal(eventsink.called, this.expectSinkCall); } catch (e) { do_throw("Unexpected exception: " + e); } throw Components.Exception("", Cr.NS_ERROR_ABORT); }, onDataAvailable: function test_ODA() { do_throw("Should not get any data!"); }, onStopRequest: function test_onStopR() { if (this._iteration <= 2) { run_test_continued(); } else { do_test_pending(); httpserv.stop(do_test_finished); } do_test_finished(); }, _iteration: 1, }; function makeChan(url) { return NetUtil.newChannel({ uri: url, loadUsingSystemPrincipal: true }); } var httpserv = null; function run_test() { httpserv = new HttpServer(); httpserv.registerPathHandler("/redirect", redirect); httpserv.registerPathHandler("/redirectfile", redirectfile); httpserv.start(-1); Components.manager.nsIComponentRegistrar.registerFactory( sinkCID, "Unit test Event sink", sinkContract, eventsink ); // Step 1: Set the callbacks on the listener itself var chan = makeChan(URL + "/redirect"); chan.notificationCallbacks = eventsink; chan.asyncOpen(listener); do_test_pending(); } function run_test_continued() { eventsink.called = false; var chan; if (listener._iteration == 1) { // Step 2: Category entry Services.catMan.addCategoryEntry( categoryName, "unit test", sinkContract, false, true ); chan = makeChan(URL + "/redirect"); } else { // Step 3: Global contract id Services.catMan.deleteCategoryEntry(categoryName, "unit test", false); listener.expectSinkCall = false; chan = makeChan(URL + "/redirectfile"); } listener._iteration++; chan.asyncOpen(listener); do_test_pending(); } // PATHS // /redirect function redirect(metadata, response) { response.setStatusLine(metadata.httpVersion, 301, "Moved Permanently"); response.setHeader( "Location", "http://localhost:" + metadata.port + "/", false ); var body = "Moved\n"; response.bodyOutputStream.write(body, body.length); } // /redirectfile function redirectfile(metadata, response) { response.setStatusLine(metadata.httpVersion, 301, "Moved Permanently"); response.setHeader("Content-Type", "text/plain", false); response.setHeader("Location", "file:///etc/", false); var body = "Attempted to move to a file URI, but failed.\n"; response.bodyOutputStream.write(body, body.length); }