3 const { HttpServer
} = ChromeUtils
.importESModule(
4 "resource://testing-common/httpd.sys.mjs"
7 ChromeUtils
.defineLazyGetter(this, "URL", function () {
8 return "http://localhost:" + httpServer
.identity
.primaryPort
;
11 var httpServer
= null;
13 function isParentProcess() {
14 let appInfo
= Cc
["@mozilla.org/xre/app-info;1"];
17 Services
.appinfo
.processType
== Ci
.nsIXULRuntime
.PROCESS_TYPE_DEFAULT
21 if (isParentProcess()) {
22 // ensure the cache service is prepped when running the test
23 // We only do this in the main process, as the cache storage service leaks
24 // when instantiated in the content process.
31 function make_channel(url
, body
, cb
) {
32 gotOnProgress
= false;
34 var chan
= NetUtil
.newChannel({
36 loadUsingSystemPrincipal
: true,
37 }).QueryInterface(Ci
.nsIHttpChannel
);
38 chan
.notificationCallbacks
= {
40 QueryInterface
: ChromeUtils
.generateQI([
41 "nsINetworkInterceptController",
42 "nsIInterfaceRequestor",
43 "nsIProgressEventSink",
46 return this.QueryInterface(iid
);
54 shouldPrepareForIntercept() {
55 Assert
.equal(this.numChecks
, 0);
59 channelIntercepted(channel
) {
60 channel
.QueryInterface(Ci
.nsIInterceptedChannel
);
63 "@mozilla.org/io/string-input-stream;1"
64 ].createInstance(Ci
.nsIStringInputStream
);
65 synthesized
.setByteStringData(body
);
67 channel
.startSynthesizedResponse(synthesized
, null, null, "", false);
68 channel
.finishSynthesizedResponse();
81 const REMOTE_BODY
= "http handler body";
82 const NON_REMOTE_BODY
= "synthesized body";
83 const NON_REMOTE_BODY_2
= "synthesized body #2";
85 function bodyHandler(metadata
, response
) {
86 response
.setHeader("Content-Type", "text/plain");
87 response
.write(REMOTE_BODY
);
91 httpServer
= new HttpServer();
92 httpServer
.registerPathHandler("/body", bodyHandler
);
98 function handle_synthesized_response(request
, buffer
) {
99 Assert
.equal(buffer
, NON_REMOTE_BODY
);
100 Assert
.ok(gotOnStatus
);
101 Assert
.ok(gotOnProgress
);
105 function handle_synthesized_response_2(request
, buffer
) {
106 Assert
.equal(buffer
, NON_REMOTE_BODY_2
);
107 Assert
.ok(gotOnStatus
);
108 Assert
.ok(gotOnProgress
);
112 function handle_remote_response(request
, buffer
) {
113 Assert
.equal(buffer
, REMOTE_BODY
);
114 Assert
.ok(gotOnStatus
);
115 Assert
.ok(gotOnProgress
);
119 // hit the network instead of synthesizing
120 add_test(function () {
121 var chan
= make_channel(URL
+ "/body", null, function (channel
) {
122 channel
.resetInterception(false);
124 chan
.asyncOpen(new ChannelListener(handle_remote_response
, null));
127 // synthesize a response
128 add_test(function () {
129 var chan
= make_channel(URL
+ "/body", NON_REMOTE_BODY
);
131 new ChannelListener(handle_synthesized_response
, null, CL_ALLOW_UNKNOWN_CL
)
135 // hit the network instead of synthesizing, to test that no previous synthesized
136 // cache entry is used.
137 add_test(function () {
138 var chan
= make_channel(URL
+ "/body", null, function (channel
) {
139 channel
.resetInterception(false);
141 chan
.asyncOpen(new ChannelListener(handle_remote_response
, null));
144 // synthesize a different response to ensure no previous response is cached
145 add_test(function () {
146 var chan
= make_channel(URL
+ "/body", NON_REMOTE_BODY_2
);
149 handle_synthesized_response_2
,
156 // ensure that the channel waits for a decision and synthesizes headers correctly
157 add_test(function () {
158 var chan
= make_channel(URL
+ "/body", null, function (channel
) {
159 do_timeout(100, function () {
160 var synthesized
= Cc
[
161 "@mozilla.org/io/string-input-stream;1"
162 ].createInstance(Ci
.nsIStringInputStream
);
163 synthesized
.setByteStringData(NON_REMOTE_BODY
);
164 channel
.synthesizeHeader("Content-Length", NON_REMOTE_BODY
.length
);
165 channel
.startSynthesizedResponse(synthesized
, null, null, "", false);
166 channel
.finishSynthesizedResponse();
169 chan
.asyncOpen(new ChannelListener(handle_synthesized_response
, null));
172 // ensure that the channel waits for a decision
173 add_test(function () {
174 var chan
= make_channel(URL
+ "/body", null, function (channel
) {
175 do_timeout(100, function () {
176 channel
.resetInterception(false);
179 chan
.asyncOpen(new ChannelListener(handle_remote_response
, null));
182 // ensure that the intercepted channel supports suspend/resume
183 add_test(function () {
184 var chan
= make_channel(URL
+ "/body", null, function (intercepted
) {
185 var synthesized
= Cc
[
186 "@mozilla.org/io/string-input-stream;1"
187 ].createInstance(Ci
.nsIStringInputStream
);
188 synthesized
.setByteStringData(NON_REMOTE_BODY
);
190 // set the content-type to ensure that the stream converter doesn't hold up notifications
191 // and cause the test to fail
192 intercepted
.synthesizeHeader("Content-Type", "text/plain");
193 intercepted
.startSynthesizedResponse(synthesized
, null, null, "", false);
194 intercepted
.finishSynthesizedResponse();
198 handle_synthesized_response
,
200 CL_ALLOW_UNKNOWN_CL
| CL_SUSPEND
| CL_EXPECT_3S_DELAY
205 // ensure that the intercepted channel can be cancelled
206 add_test(function () {
207 var chan
= make_channel(URL
+ "/body", null, function (intercepted
) {
208 intercepted
.cancelInterception(Cr
.NS_BINDING_ABORTED
);
210 chan
.asyncOpen(new ChannelListener(run_next_test
, null, CL_EXPECT_FAILURE
));
213 // ensure that the channel can't be cancelled via nsIInterceptedChannel after making a decision
214 add_test(function () {
215 var chan
= make_channel(URL
+ "/body", null, function (channel
) {
216 channel
.resetInterception(false);
217 do_timeout(0, function () {
218 var gotexception
= false;
220 channel
.cancelInterception();
224 Assert
.ok(gotexception
);
227 chan
.asyncOpen(new ChannelListener(handle_remote_response
, null));
230 // ensure that the intercepted channel can be canceled during the response
231 add_test(function () {
232 var chan
= make_channel(URL
+ "/body", null, function (intercepted
) {
233 var synthesized
= Cc
[
234 "@mozilla.org/io/string-input-stream;1"
235 ].createInstance(Ci
.nsIStringInputStream
);
236 synthesized
.setByteStringData(NON_REMOTE_BODY
);
238 let channel
= intercepted
.channel
;
239 intercepted
.startSynthesizedResponse(synthesized
, null, null, "", false);
240 intercepted
.finishSynthesizedResponse();
241 channel
.cancel(Cr
.NS_BINDING_ABORTED
);
247 CL_EXPECT_FAILURE
| CL_ALLOW_UNKNOWN_CL
252 // ensure that the intercepted channel can be canceled before the response
253 add_test(function () {
254 var chan
= make_channel(URL
+ "/body", null, function (intercepted
) {
255 var synthesized
= Cc
[
256 "@mozilla.org/io/string-input-stream;1"
257 ].createInstance(Ci
.nsIStringInputStream
);
258 synthesized
.setByteStringData(NON_REMOTE_BODY
);
260 intercepted
.channel
.cancel(Cr
.NS_BINDING_ABORTED
);
262 // This should not throw, but result in the channel firing callbacks
263 // with an error status.
264 intercepted
.startSynthesizedResponse(synthesized
, null, null, "", false);
265 intercepted
.finishSynthesizedResponse();
271 CL_EXPECT_FAILURE
| CL_ALLOW_UNKNOWN_CL
276 // Ensure that nsIInterceptedChannel.channelIntercepted() can return an error.
277 // In this case we should automatically ResetInterception() and complete the
279 add_test(function () {
280 var chan
= make_channel(URL
+ "/body", null, function () {
281 throw new Error("boom");
283 chan
.asyncOpen(new ChannelListener(handle_remote_response
, null));
286 add_test(function () {
287 httpServer
.stop(run_next_test
);