michael@0: // Test nsITraceableChannel interface. michael@0: // Replace original listener with TracingListener that modifies body of HTTP michael@0: // response. Make sure that body received by original channel's listener michael@0: // is correctly modified. michael@0: michael@0: Cu.import("resource://testing-common/httpd.js"); michael@0: michael@0: var httpserver = new HttpServer(); michael@0: httpserver.start(-1); michael@0: const PORT = httpserver.identity.primaryPort; michael@0: michael@0: var pipe = null; michael@0: var streamSink = null; michael@0: michael@0: var originalBody = "original http response body"; michael@0: var gotOnStartRequest = false; michael@0: michael@0: function TracingListener() {} michael@0: michael@0: TracingListener.prototype = { michael@0: onStartRequest: function(request, context) { michael@0: dump("*** tracing listener onStartRequest\n"); michael@0: michael@0: gotOnStartRequest = true; michael@0: michael@0: request.QueryInterface(Components.interfaces.nsIHttpChannelInternal); michael@0: michael@0: // local/remote addresses broken in e10s: disable for now michael@0: /* michael@0: do_check_eq(request.localAddress, "127.0.0.1"); michael@0: do_check_eq(request.localPort > 0, true); michael@0: do_check_neq(request.localPort, PORT); michael@0: do_check_eq(request.remoteAddress, "127.0.0.1"); michael@0: do_check_eq(request.remotePort, PORT); michael@0: */ michael@0: michael@0: // Make sure listener can't be replaced after OnStartRequest was called. michael@0: request.QueryInterface(Components.interfaces.nsITraceableChannel); michael@0: try { michael@0: var newListener = new TracingListener(); michael@0: newListener.listener = request.setNewListener(newListener); michael@0: } catch(e) { michael@0: dump("TracingListener.onStartRequest swallowing exception: " + e + "\n"); michael@0: return; // OK michael@0: } michael@0: do_throw("replaced channel's listener during onStartRequest."); michael@0: }, michael@0: michael@0: onStopRequest: function(request, context, statusCode) { michael@0: dump("*** tracing listener onStopRequest\n"); michael@0: michael@0: do_check_eq(gotOnStartRequest, true); michael@0: michael@0: try { michael@0: var sin = Components.classes["@mozilla.org/scriptableinputstream;1"]. michael@0: createInstance(Ci.nsIScriptableInputStream); michael@0: michael@0: streamSink.close(); michael@0: var input = pipe.inputStream; michael@0: sin.init(input); michael@0: do_check_eq(sin.available(), originalBody.length); michael@0: michael@0: var result = sin.read(originalBody.length); michael@0: do_check_eq(result, originalBody); michael@0: michael@0: input.close(); michael@0: } catch (e) { michael@0: dump("TracingListener.onStopRequest swallowing exception: " + e + "\n"); michael@0: } finally { michael@0: httpserver.stop(do_test_finished); michael@0: } michael@0: }, michael@0: michael@0: QueryInterface: function(iid) { michael@0: if (iid.equals(Components.interfaces.nsIRequestObserver) || michael@0: iid.equals(Components.interfaces.nsISupports) michael@0: ) michael@0: return this; michael@0: throw Components.results.NS_NOINTERFACE; michael@0: }, michael@0: michael@0: listener: null michael@0: } michael@0: michael@0: michael@0: function HttpResponseExaminer() {} michael@0: michael@0: HttpResponseExaminer.prototype = { michael@0: register: function() { michael@0: Cc["@mozilla.org/observer-service;1"]. michael@0: getService(Components.interfaces.nsIObserverService). michael@0: addObserver(this, "http-on-examine-response", true); michael@0: dump("Did HttpResponseExaminer.register\n"); michael@0: }, michael@0: michael@0: // Replace channel's listener. michael@0: observe: function(subject, topic, data) { michael@0: dump("In HttpResponseExaminer.observe\n"); michael@0: try { michael@0: subject.QueryInterface(Components.interfaces.nsITraceableChannel); michael@0: michael@0: var tee = Cc["@mozilla.org/network/stream-listener-tee;1"]. michael@0: createInstance(Ci.nsIStreamListenerTee); michael@0: var newListener = new TracingListener(); michael@0: pipe = Cc["@mozilla.org/pipe;1"].createInstance(Ci.nsIPipe); michael@0: pipe.init(false, false, 0, 0xffffffff, null); michael@0: streamSink = pipe.outputStream; michael@0: michael@0: var originalListener = subject.setNewListener(tee); michael@0: tee.init(originalListener, streamSink, newListener); michael@0: } catch(e) { michael@0: do_throw("can't replace listener " + e); michael@0: } michael@0: dump("Did HttpResponseExaminer.observe\n"); michael@0: }, michael@0: michael@0: QueryInterface: function(iid) { michael@0: if (iid.equals(Components.interfaces.nsIObserver) || michael@0: iid.equals(Components.interfaces.nsISupportsWeakReference) || michael@0: iid.equals(Components.interfaces.nsISupports)) michael@0: return this; michael@0: throw Components.results.NS_NOINTERFACE; michael@0: } michael@0: } michael@0: michael@0: function test_handler(metadata, response) { michael@0: response.setHeader("Content-Type", "text/html", false); michael@0: response.setStatusLine(metadata.httpVersion, 200, "OK"); michael@0: response.bodyOutputStream.write(originalBody, originalBody.length); michael@0: } michael@0: michael@0: function make_channel(url) { michael@0: var ios = Cc["@mozilla.org/network/io-service;1"]. michael@0: getService(Ci.nsIIOService); michael@0: return ios.newChannel(url, null, null). michael@0: QueryInterface(Components.interfaces.nsIHttpChannel); michael@0: } michael@0: michael@0: // Check if received body is correctly modified. michael@0: function channel_finished(request, input, ctx) { michael@0: httpserver.stop(do_test_finished); michael@0: } michael@0: michael@0: function run_test() { michael@0: var observer = new HttpResponseExaminer(); michael@0: observer.register(); michael@0: michael@0: httpserver.registerPathHandler("/testdir", test_handler); michael@0: michael@0: var channel = make_channel("http://localhost:" + PORT + "/testdir"); michael@0: channel.asyncOpen(new ChannelListener(channel_finished), null); michael@0: do_test_pending(); michael@0: }