test_transparent_redirect.js (3034B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 const { HttpServer } = ChromeUtils.importESModule( 8 "resource://testing-common/httpd.sys.mjs" 9 ); 10 11 const SUCCESS_TEXT = "success!"; 12 13 function successResponseHandler(req, resp) { 14 var text = SUCCESS_TEXT; 15 resp.setHeader("Content-Type", "text/plain", false); 16 resp.bodyOutputStream.write(text, text.length); 17 } 18 19 function onBeforeConnect(callback) { 20 Services.obs.addObserver( 21 { 22 observe(subject) { 23 Services.obs.removeObserver(this, "http-on-before-connect"); 24 callback(subject.QueryInterface(Ci.nsIHttpChannel)); 25 }, 26 }, 27 "http-on-before-connect" 28 ); 29 } 30 31 function onExamineResponse(callback) { 32 Services.obs.addObserver( 33 { 34 observe(subject) { 35 Services.obs.removeObserver(this, "http-on-examine-response"); 36 callback(subject.QueryInterface(Ci.nsIHttpChannel)); 37 }, 38 }, 39 "http-on-examine-response" 40 ); 41 } 42 43 class EventSinkListener { 44 getInterface(iid) { 45 if (iid.equals(Ci.nsIChannelEventSink)) { 46 return this; 47 } 48 throw Components.Exception("", Cr.NS_ERROR_NO_INTERFACE); 49 } 50 asyncOnChannelRedirect(oldChan, newChan, flags, callback) { 51 // if transparent, asyncOnChannelRedirect should not be called. 52 Assert.ok(false); 53 callback.onRedirectVerifyCallback(Cr.NS_OK); 54 } 55 } 56 57 EventSinkListener.prototype.QueryInterface = ChromeUtils.generateQI([ 58 "nsIInterfaceRequestor", 59 "nsIChannelEventSink", 60 ]); 61 62 add_task(async function test_transparent_redirect() { 63 var server = new HttpServer(); 64 await server.start(-1); 65 registerCleanupFunction(async () => { 66 await server.stop(); 67 }); 68 69 server.registerPathHandler("/success", successResponseHandler); 70 71 const baseUrl = `http://localhost:${server.identity.primaryPort}/`; 72 const successUrl = baseUrl + "success"; 73 74 onBeforeConnect(chan => { 75 chan.suspend(); 76 Promise.resolve().then(() => { 77 try { 78 chan.transparentRedirectTo(Services.io.newURI(successUrl)); 79 } catch (e) { 80 do_throw(e); 81 } 82 chan.resume(); 83 }); 84 }); 85 86 onExamineResponse(chan => { 87 chan.QueryInterface(Ci.nsITimedChannel); 88 Assert.equal(chan.redirectCount, 0, "redirectCount should be 0"); 89 Assert.equal( 90 chan.internalRedirectCount, 91 1, 92 "internalRedirectCount should be 1" 93 ); 94 }); 95 96 let chan = NetUtil.newChannel({ 97 uri: baseUrl, 98 loadUsingSystemPrincipal: true, 99 }).QueryInterface(Ci.nsIHttpChannelInternal); 100 let listener = new EventSinkListener(); 101 chan.notificationCallbacks = listener; 102 103 await new Promise(resolve => { 104 chan.asyncOpen( 105 new ChannelListener( 106 (req, resp) => { 107 // Should hit /success for both. 108 Assert.equal(resp, SUCCESS_TEXT, "Should redirect to success"); 109 resolve(); 110 }, 111 null, 112 CL_ALLOW_UNKNOWN_CL 113 ) 114 ); 115 }); 116 });