test_traceable_channel.js (4162B)
1 "use strict"; 2 3 // Test nsITraceableChannel interface. 4 // Replace original listener with TracingListener that modifies body of HTTP 5 // response. Make sure that body received by original channel's listener 6 // is correctly modified. 7 8 const { HttpServer } = ChromeUtils.importESModule( 9 "resource://testing-common/httpd.sys.mjs" 10 ); 11 12 var httpserver = new HttpServer(); 13 httpserver.start(-1); 14 const PORT = httpserver.identity.primaryPort; 15 16 var pipe = null; 17 var streamSink = null; 18 19 var originalBody = "original http response body"; 20 var gotOnStartRequest = false; 21 22 function TracingListener() {} 23 24 TracingListener.prototype = { 25 onStartRequest(request) { 26 dump("*** tracing listener onStartRequest\n"); 27 28 gotOnStartRequest = true; 29 30 request.QueryInterface(Ci.nsIHttpChannelInternal); 31 32 // local/remote addresses broken in e10s: disable for now 33 Assert.equal(request.localAddress, "127.0.0.1"); 34 Assert.equal(request.localPort > 0, true); 35 Assert.notEqual(request.localPort, PORT); 36 Assert.equal(request.remoteAddress, "127.0.0.1"); 37 Assert.equal(request.remotePort, PORT); 38 39 // Make sure listener can't be replaced after OnStartRequest was called. 40 request.QueryInterface(Ci.nsITraceableChannel); 41 try { 42 var newListener = new TracingListener(); 43 newListener.listener = request.setNewListener(newListener); 44 } catch (e) { 45 dump("TracingListener.onStartRequest swallowing exception: " + e + "\n"); 46 return; // OK 47 } 48 do_throw("replaced channel's listener during onStartRequest."); 49 }, 50 51 onStopRequest() { 52 dump("*** tracing listener onStopRequest\n"); 53 54 Assert.equal(gotOnStartRequest, true); 55 56 try { 57 var sin = Cc["@mozilla.org/scriptableinputstream;1"].createInstance( 58 Ci.nsIScriptableInputStream 59 ); 60 61 streamSink.close(); 62 var input = pipe.inputStream; 63 sin.init(input); 64 Assert.equal(sin.available(), originalBody.length); 65 66 var result = sin.read(originalBody.length); 67 Assert.equal(result, originalBody); 68 69 input.close(); 70 } catch (e) { 71 dump("TracingListener.onStopRequest swallowing exception: " + e + "\n"); 72 } finally { 73 httpserver.stop(do_test_finished); 74 } 75 }, 76 77 QueryInterface: ChromeUtils.generateQI(["nsIRequestObserver"]), 78 79 listener: null, 80 }; 81 82 function HttpResponseExaminer() {} 83 84 HttpResponseExaminer.prototype = { 85 register() { 86 Services.obs.addObserver(this, "http-on-examine-response", true); 87 dump("Did HttpResponseExaminer.register\n"); 88 }, 89 90 // Replace channel's listener. 91 observe(subject) { 92 dump("In HttpResponseExaminer.observe\n"); 93 try { 94 subject.QueryInterface(Ci.nsITraceableChannel); 95 96 var tee = Cc["@mozilla.org/network/stream-listener-tee;1"].createInstance( 97 Ci.nsIStreamListenerTee 98 ); 99 var newListener = new TracingListener(); 100 pipe = Cc["@mozilla.org/pipe;1"].createInstance(Ci.nsIPipe); 101 pipe.init(false, false, 0, 0xffffffff, null); 102 streamSink = pipe.outputStream; 103 104 var originalListener = subject.setNewListener(tee); 105 tee.init(originalListener, streamSink, newListener); 106 } catch (e) { 107 do_throw("can't replace listener " + e); 108 } 109 dump("Did HttpResponseExaminer.observe\n"); 110 }, 111 112 QueryInterface: ChromeUtils.generateQI([ 113 "nsIObserver", 114 "nsISupportsWeakReference", 115 ]), 116 }; 117 118 function test_handler(metadata, response) { 119 response.setHeader("Content-Type", "text/html", false); 120 response.setStatusLine(metadata.httpVersion, 200, "OK"); 121 response.bodyOutputStream.write(originalBody, originalBody.length); 122 } 123 124 function make_channel(url) { 125 return NetUtil.newChannel({ 126 uri: url, 127 loadUsingSystemPrincipal: true, 128 }).QueryInterface(Ci.nsIHttpChannel); 129 } 130 131 // Check if received body is correctly modified. 132 function channel_finished() { 133 httpserver.stop(do_test_finished); 134 } 135 136 function run_test() { 137 var observer = new HttpResponseExaminer(); 138 observer.register(); 139 140 httpserver.registerPathHandler("/testdir", test_handler); 141 142 var channel = make_channel("http://localhost:" + PORT + "/testdir"); 143 channel.asyncOpen(new ChannelListener(channel_finished)); 144 do_test_pending(); 145 }