// This file tests async handling of a channel suspended in http-on-modify-request. var CC = Components.Constructor; Cu.import("resource://testing-common/httpd.js"); Cu.import("resource://gre/modules/NetUtil.jsm"); var obs = Cc["@mozilla.org/observer-service;1"] .getService(Ci.nsIObserverService); var ios = Cc["@mozilla.org/network/io-service;1"] .getService(Components.interfaces.nsIIOService); // baseUrl is always the initial connection attempt and is handled by // failResponseHandler since every test expects that request will either be // redirected or cancelled. var baseUrl; function failResponseHandler(metadata, response) { var text = "failure response"; response.setHeader("Content-Type", "text/plain", false); response.bodyOutputStream.write(text, text.length); do_check_true(false, "Received request when we shouldn't."); } function successResponseHandler(metadata, response) { var text = "success response"; response.setHeader("Content-Type", "text/plain", false); response.bodyOutputStream.write(text, text.length); do_check_true(true, "Received expected request."); } function onModifyListener(callback) { obs.addObserver({ observe: function(subject, topic, data) { var obs = Cc["@mozilla.org/observer-service;1"].getService(); obs = obs.QueryInterface(Ci.nsIObserverService); obs.removeObserver(this, "http-on-modify-request"); callback(subject.QueryInterface(Ci.nsIHttpChannel)); } }, "http-on-modify-request", false); } function startChannelRequest(baseUrl, flags, expectedResponse=null) { var chan = NetUtil.newChannel({ uri: baseUrl, loadUsingSystemPrincipal: true }); chan.asyncOpen2(new ChannelListener((request, data, context) => { if (expectedResponse) { do_check_eq(data, expectedResponse); } else { do_check_true(!!!data, "no response"); } do_execute_soon(run_next_test) }, null, flags)); } add_test(function testSimpleRedirect() { onModifyListener(chan => { chan.redirectTo(ios.newURI(`${baseUrl}/success`)); }); startChannelRequest(baseUrl, undefined, "success response"); }); add_test(function testSimpleCancel() { onModifyListener(chan => { chan.cancel(Cr.NS_BINDING_ABORTED); }); startChannelRequest(baseUrl, CL_EXPECT_FAILURE); }); add_test(function testSimpleCancelRedirect() { onModifyListener(chan => { chan.redirectTo(ios.newURI(`${baseUrl}/fail`)); chan.cancel(Cr.NS_BINDING_ABORTED); }); startChannelRequest(baseUrl, CL_EXPECT_FAILURE); }); // Test a request that will get redirected asynchronously. baseUrl should // not be requested, we should receive the request for the redirectedUrl. add_test(function testAsyncRedirect() { onModifyListener(chan => { // Suspend the channel then yield to make this async. chan.suspend(); Promise.resolve().then(() => { chan.redirectTo(ios.newURI(`${baseUrl}/success`)); chan.resume(); }); }); startChannelRequest(baseUrl, undefined, "success response"); }); add_test(function testSyncRedirect() { onModifyListener(chan => { chan.suspend(); chan.redirectTo(ios.newURI(`${baseUrl}/success`)); Promise.resolve().then(() => { chan.resume(); }); }); startChannelRequest(baseUrl, undefined, "success response"); }); add_test(function testAsyncCancel() { onModifyListener(chan => { // Suspend the channel then yield to make this async. chan.suspend(); Promise.resolve().then(() => { chan.cancel(Cr.NS_BINDING_ABORTED); chan.resume(); }); }); startChannelRequest(baseUrl, CL_EXPECT_FAILURE); }); add_test(function testSyncCancel() { onModifyListener(chan => { chan.suspend(); chan.cancel(Cr.NS_BINDING_ABORTED); Promise.resolve().then(() => { chan.resume(); }); }); startChannelRequest(baseUrl, CL_EXPECT_FAILURE); }); // Test request that will get redirected and cancelled asynchronously, // ensure no connection is made. add_test(function testAsyncCancelRedirect() { onModifyListener(chan => { // Suspend the channel then yield to make this async. chan.suspend(); Promise.resolve().then(() => { chan.cancel(Cr.NS_BINDING_ABORTED); chan.redirectTo(ios.newURI(`${baseUrl}/fail`)); chan.resume(); }); }); startChannelRequest(baseUrl, CL_EXPECT_FAILURE); }); // Test a request that will get cancelled synchronously, ensure async redirect // is not made. add_test(function testSyncCancelRedirect() { onModifyListener(chan => { chan.suspend(); chan.cancel(Cr.NS_BINDING_ABORTED); Promise.resolve().then(() => { chan.redirectTo(ios.newURI(`${baseUrl}/fail`)); chan.resume(); }); }); startChannelRequest(baseUrl, CL_EXPECT_FAILURE); }); function run_test() { var httpServer = new HttpServer(); httpServer.registerPathHandler("/", failResponseHandler); httpServer.registerPathHandler("/fail", failResponseHandler); httpServer.registerPathHandler("/success", successResponseHandler); httpServer.start(-1); baseUrl = `http://localhost:${httpServer.identity.primaryPort}`; run_next_test(); do_register_cleanup(function(){ httpServer.stop(() => {}); }); }