test_suspend_channel_on_modified.js (4933B)
1 // This file tests async handling of a channel suspended in http-on-modify-request. 2 "use strict"; 3 4 const { HttpServer } = ChromeUtils.importESModule( 5 "resource://testing-common/httpd.sys.mjs" 6 ); 7 8 var obs = Services.obs; 9 10 var ios = Services.io; 11 12 // baseUrl is always the initial connection attempt and is handled by 13 // failResponseHandler since every test expects that request will either be 14 // redirected or cancelled. 15 var baseUrl; 16 17 function failResponseHandler(metadata, response) { 18 var text = "failure response"; 19 response.setHeader("Content-Type", "text/plain", false); 20 response.bodyOutputStream.write(text, text.length); 21 Assert.ok(false, "Received request when we shouldn't."); 22 } 23 24 function successResponseHandler(metadata, response) { 25 var text = "success response"; 26 response.setHeader("Content-Type", "text/plain", false); 27 response.bodyOutputStream.write(text, text.length); 28 Assert.ok(true, "Received expected request."); 29 } 30 31 function onModifyListener(callback) { 32 obs.addObserver( 33 { 34 observe(subject) { 35 obs.removeObserver(this, "http-on-modify-request"); 36 callback(subject.QueryInterface(Ci.nsIHttpChannel)); 37 }, 38 }, 39 "http-on-modify-request" 40 ); 41 } 42 43 function startChannelRequest(uri, flags, expectedResponse = null) { 44 var chan = NetUtil.newChannel({ 45 uri, 46 loadUsingSystemPrincipal: true, 47 }); 48 chan.asyncOpen( 49 new ChannelListener( 50 (request, data) => { 51 if (expectedResponse) { 52 Assert.equal(data, expectedResponse); 53 } else { 54 Assert.ok(!data, "no response"); 55 } 56 executeSoon(run_next_test); 57 }, 58 null, 59 flags 60 ) 61 ); 62 } 63 64 add_test(function testSimpleRedirect() { 65 onModifyListener(chan => { 66 chan.redirectTo(ios.newURI(`${baseUrl}/success`)); 67 }); 68 startChannelRequest(baseUrl, undefined, "success response"); 69 }); 70 71 add_test(function testSimpleCancel() { 72 onModifyListener(chan => { 73 chan.cancel(Cr.NS_BINDING_ABORTED); 74 }); 75 startChannelRequest(baseUrl, CL_EXPECT_FAILURE); 76 }); 77 78 add_test(function testSimpleCancelRedirect() { 79 onModifyListener(chan => { 80 chan.redirectTo(ios.newURI(`${baseUrl}/fail`)); 81 chan.cancel(Cr.NS_BINDING_ABORTED); 82 }); 83 startChannelRequest(baseUrl, CL_EXPECT_FAILURE); 84 }); 85 86 // Test a request that will get redirected asynchronously. baseUrl should 87 // not be requested, we should receive the request for the redirectedUrl. 88 add_test(function testAsyncRedirect() { 89 onModifyListener(chan => { 90 // Suspend the channel then yield to make this async. 91 chan.suspend(); 92 Promise.resolve().then(() => { 93 chan.redirectTo(ios.newURI(`${baseUrl}/success`)); 94 chan.resume(); 95 }); 96 }); 97 startChannelRequest(baseUrl, undefined, "success response"); 98 }); 99 100 add_test(function testSyncRedirect() { 101 onModifyListener(chan => { 102 chan.suspend(); 103 chan.redirectTo(ios.newURI(`${baseUrl}/success`)); 104 Promise.resolve().then(() => { 105 chan.resume(); 106 }); 107 }); 108 startChannelRequest(baseUrl, undefined, "success response"); 109 }); 110 111 add_test(function testAsyncCancel() { 112 onModifyListener(chan => { 113 // Suspend the channel then yield to make this async. 114 chan.suspend(); 115 Promise.resolve().then(() => { 116 chan.cancel(Cr.NS_BINDING_ABORTED); 117 chan.resume(); 118 }); 119 }); 120 startChannelRequest(baseUrl, CL_EXPECT_FAILURE); 121 }); 122 123 add_test(function testSyncCancel() { 124 onModifyListener(chan => { 125 chan.suspend(); 126 chan.cancel(Cr.NS_BINDING_ABORTED); 127 Promise.resolve().then(() => { 128 chan.resume(); 129 }); 130 }); 131 startChannelRequest(baseUrl, CL_EXPECT_FAILURE); 132 }); 133 134 // Test request that will get redirected and cancelled asynchronously, 135 // ensure no connection is made. 136 add_test(function testAsyncCancelRedirect() { 137 onModifyListener(chan => { 138 // Suspend the channel then yield to make this async. 139 chan.suspend(); 140 Promise.resolve().then(() => { 141 chan.cancel(Cr.NS_BINDING_ABORTED); 142 chan.redirectTo(ios.newURI(`${baseUrl}/fail`)); 143 chan.resume(); 144 }); 145 }); 146 startChannelRequest(baseUrl, CL_EXPECT_FAILURE); 147 }); 148 149 // Test a request that will get cancelled synchronously, ensure async redirect 150 // is not made. 151 add_test(function testSyncCancelRedirect() { 152 onModifyListener(chan => { 153 chan.suspend(); 154 chan.cancel(Cr.NS_BINDING_ABORTED); 155 Promise.resolve().then(() => { 156 chan.redirectTo(ios.newURI(`${baseUrl}/fail`)); 157 chan.resume(); 158 }); 159 }); 160 startChannelRequest(baseUrl, CL_EXPECT_FAILURE); 161 }); 162 163 function run_test() { 164 var httpServer = new HttpServer(); 165 httpServer.registerPathHandler("/", failResponseHandler); 166 httpServer.registerPathHandler("/fail", failResponseHandler); 167 httpServer.registerPathHandler("/success", successResponseHandler); 168 httpServer.start(-1); 169 170 baseUrl = `http://localhost:${httpServer.identity.primaryPort}`; 171 172 run_next_test(); 173 174 registerCleanupFunction(function () { 175 httpServer.stop(() => {}); 176 }); 177 }