Backed out changeset b71c8c052463 (bug 1943846) for causing mass failures. CLOSED...
[gecko.git] / netwerk / test / unit / http2_test_common.js
blob71532cd1189dc745d482958b3d7b26a0be2f55dd
1 // test HTTP/2
3 "use strict";
5 /* import-globals-from head_channels.js */
7 // Generate a small and a large post with known pre-calculated md5 sums
8 function generateContent(size) {
9 var content = "";
10 for (var i = 0; i < size; i++) {
11 content += "0";
13 return content;
16 var posts = [];
17 posts.push(generateContent(10));
18 posts.push(generateContent(250000));
19 posts.push(generateContent(128000));
21 // pre-calculated md5sums (in hex) of the above posts
22 var md5s = [
23 "f1b708bba17f1ce948dc979f4d7092bc",
24 "2ef8d3b6c8f329318eb1a119b12622b6",
27 var bigListenerData = generateContent(128 * 1024);
28 var bigListenerMD5 = "8f607cfdd2c87d6a7eedb657dafbd836";
30 function checkIsHttp2(request) {
31 try {
32 if (request.getResponseHeader("X-Firefox-Spdy") == "h2") {
33 if (request.getResponseHeader("X-Connection-Http2") == "yes") {
34 return true;
36 return false; // Weird case, but the server disagrees with us
38 } catch (e) {
39 // Nothing to do here
41 return false;
44 var Http2CheckListener = function () {};
46 Http2CheckListener.prototype = {
47 onStartRequestFired: false,
48 onDataAvailableFired: false,
49 isHttp2Connection: false,
50 shouldBeHttp2: true,
51 accum: 0,
52 expected: -1,
53 shouldSucceed: true,
55 onStartRequest: function testOnStartRequest(request) {
56 this.onStartRequestFired = true;
57 if (this.shouldSucceed && !Components.isSuccessCode(request.status)) {
58 do_throw("Channel should have a success code! (" + request.status + ")");
59 } else if (
60 !this.shouldSucceed &&
61 Components.isSuccessCode(request.status)
62 ) {
63 do_throw("Channel succeeded unexpectedly!");
66 Assert.ok(request instanceof Ci.nsIHttpChannel);
67 Assert.equal(request.requestSucceeded, this.shouldSucceed);
68 if (this.shouldSucceed) {
69 Assert.equal(request.responseStatus, 200);
73 onDataAvailable: function testOnDataAvailable(request, stream, off, cnt) {
74 this.onDataAvailableFired = true;
75 this.isHttp2Connection = checkIsHttp2(request);
76 this.accum += cnt;
77 read_stream(stream, cnt);
80 onStopRequest: function testOnStopRequest(request, status) {
81 Assert.ok(this.onStartRequestFired);
82 if (this.expected != -1) {
83 Assert.equal(this.accum, this.expected);
86 if (this.shouldSucceed) {
87 Assert.ok(Components.isSuccessCode(status));
88 Assert.ok(this.onDataAvailableFired);
89 Assert.ok(this.isHttp2Connection == this.shouldBeHttp2);
90 } else {
91 Assert.ok(!Components.isSuccessCode(status));
93 request.QueryInterface(Ci.nsIProxiedChannel);
94 var httpProxyConnectResponseCode = request.httpProxyConnectResponseCode;
95 this.finish({ httpProxyConnectResponseCode });
100 * Support for testing valid multiplexing of streams
103 var multiplexContent = generateContent(30 * 1024);
105 /* Listener class to control the testing of multiplexing */
106 var Http2MultiplexListener = function () {};
108 Http2MultiplexListener.prototype = new Http2CheckListener();
110 Http2MultiplexListener.prototype.streamID = 0;
111 Http2MultiplexListener.prototype.buffer = "";
113 Http2MultiplexListener.prototype.onDataAvailable = function (
114 request,
115 stream,
116 off,
119 this.onDataAvailableFired = true;
120 this.isHttp2Connection = checkIsHttp2(request);
121 this.streamID = parseInt(request.getResponseHeader("X-Http2-StreamID"));
122 var data = read_stream(stream, cnt);
123 this.buffer = this.buffer.concat(data);
126 Http2MultiplexListener.prototype.onStopRequest = function (request) {
127 Assert.ok(this.onStartRequestFired);
128 Assert.ok(this.onDataAvailableFired);
129 Assert.ok(this.isHttp2Connection);
130 Assert.ok(this.buffer == multiplexContent);
132 request.QueryInterface(Ci.nsIProxiedChannel);
133 // This is what does most of the hard work for us
134 var httpProxyConnectResponseCode = request.httpProxyConnectResponseCode;
135 var streamID = this.streamID;
136 this.finish({ httpProxyConnectResponseCode, streamID });
139 // Does the appropriate checks for header gatewaying
140 var Http2HeaderListener = function (name, callback) {
141 this.name = name;
142 this.callback = callback;
145 Http2HeaderListener.prototype = new Http2CheckListener();
146 Http2HeaderListener.prototype.value = "";
148 Http2HeaderListener.prototype.onDataAvailable = function (
149 request,
150 stream,
151 off,
154 this.onDataAvailableFired = true;
155 this.isHttp2Connection = checkIsHttp2(request);
156 var hvalue = request.getResponseHeader(this.name);
157 Assert.notEqual(hvalue, "");
158 this.callback(hvalue);
159 read_stream(stream, cnt);
162 var Http2PushListener = function (shouldBePushed) {
163 this.shouldBePushed = shouldBePushed;
166 Http2PushListener.prototype = new Http2CheckListener();
168 Http2PushListener.prototype.onDataAvailable = function (
169 request,
170 stream,
171 off,
174 this.onDataAvailableFired = true;
175 this.isHttp2Connection = checkIsHttp2(request);
176 if (
177 request.originalURI.spec ==
178 `https://localhost:${this.serverPort}/push.js` ||
179 request.originalURI.spec ==
180 `https://localhost:${this.serverPort}/push2.js` ||
181 request.originalURI.spec == `https://localhost:${this.serverPort}/push5.js`
183 Assert.equal(
184 request.getResponseHeader("pushed"),
185 this.shouldBePushed ? "yes" : "no"
188 read_stream(stream, cnt);
191 const pushHdrTxt =
192 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
193 const pullHdrTxt = pushHdrTxt.split("").reverse().join("");
195 function checkContinuedHeaders(getHeader, headerPrefix, headerText) {
196 for (var i = 0; i < 265; i++) {
197 Assert.equal(getHeader(headerPrefix + 1), headerText);
201 var Http2ContinuedHeaderListener = function () {};
203 Http2ContinuedHeaderListener.prototype = new Http2CheckListener();
205 Http2ContinuedHeaderListener.prototype.onStopsLeft = 2;
207 Http2ContinuedHeaderListener.prototype.QueryInterface = ChromeUtils.generateQI([
208 "nsIHttpPushListener",
209 "nsIStreamListener",
212 Http2ContinuedHeaderListener.prototype.getInterface = function (aIID) {
213 return this.QueryInterface(aIID);
216 Http2ContinuedHeaderListener.prototype.onDataAvailable = function (
217 request,
218 stream,
219 off,
222 this.onDataAvailableFired = true;
223 this.isHttp2Connection = checkIsHttp2(request);
224 if (
225 request.originalURI.spec ==
226 `https://localhost:${this.serverPort}/continuedheaders`
228 // This is the original request, so the only one where we'll have continued response headers
229 checkContinuedHeaders(
230 request.getResponseHeader,
231 "X-Pull-Test-Header-",
232 pullHdrTxt
235 read_stream(stream, cnt);
238 Http2ContinuedHeaderListener.prototype.onStopRequest = function (
239 request,
240 status
242 Assert.ok(this.onStartRequestFired);
243 Assert.ok(Components.isSuccessCode(status));
244 Assert.ok(this.onDataAvailableFired);
245 Assert.ok(this.isHttp2Connection);
247 --this.onStopsLeft;
248 if (this.onStopsLeft === 0) {
249 request.QueryInterface(Ci.nsIProxiedChannel);
250 var httpProxyConnectResponseCode = request.httpProxyConnectResponseCode;
251 this.finish({ httpProxyConnectResponseCode });
255 Http2ContinuedHeaderListener.prototype.onPush = function (
256 associatedChannel,
257 pushChannel
259 Assert.equal(
260 associatedChannel.originalURI.spec,
261 "https://localhost:" + this.serverPort + "/continuedheaders"
263 Assert.equal(pushChannel.getRequestHeader("x-pushed-request"), "true");
264 checkContinuedHeaders(
265 pushChannel.getRequestHeader,
266 "X-Push-Test-Header-",
267 pushHdrTxt
270 pushChannel.asyncOpen(this);
273 // Does the appropriate checks for a large GET response
274 var Http2BigListener = function () {};
276 Http2BigListener.prototype = new Http2CheckListener();
277 Http2BigListener.prototype.buffer = "";
279 Http2BigListener.prototype.onDataAvailable = function (
280 request,
281 stream,
282 off,
285 this.onDataAvailableFired = true;
286 this.isHttp2Connection = checkIsHttp2(request);
287 this.buffer = this.buffer.concat(read_stream(stream, cnt));
288 // We know the server should send us the same data as our big post will be,
289 // so the md5 should be the same
290 Assert.equal(bigListenerMD5, request.getResponseHeader("X-Expected-MD5"));
293 Http2BigListener.prototype.onStopRequest = function (request) {
294 Assert.ok(this.onStartRequestFired);
295 Assert.ok(this.onDataAvailableFired);
296 Assert.ok(this.isHttp2Connection);
298 // Don't want to flood output, so don't use do_check_eq
299 Assert.ok(this.buffer == bigListenerData);
301 request.QueryInterface(Ci.nsIProxiedChannel);
302 var httpProxyConnectResponseCode = request.httpProxyConnectResponseCode;
303 this.finish({ httpProxyConnectResponseCode });
306 var Http2HugeSuspendedListener = function () {};
308 Http2HugeSuspendedListener.prototype = new Http2CheckListener();
309 Http2HugeSuspendedListener.prototype.count = 0;
311 Http2HugeSuspendedListener.prototype.onDataAvailable = function (
312 request,
313 stream,
314 off,
317 this.onDataAvailableFired = true;
318 this.isHttp2Connection = checkIsHttp2(request);
319 this.count += cnt;
320 read_stream(stream, cnt);
323 Http2HugeSuspendedListener.prototype.onStopRequest = function (request) {
324 Assert.ok(this.onStartRequestFired);
325 Assert.ok(this.onDataAvailableFired);
326 Assert.ok(this.isHttp2Connection);
327 Assert.equal(this.count, 1024 * 1024 * 1); // 1mb of data expected
328 request.QueryInterface(Ci.nsIProxiedChannel);
329 var httpProxyConnectResponseCode = request.httpProxyConnectResponseCode;
330 this.finish({ httpProxyConnectResponseCode });
333 // Does the appropriate checks for POSTs
334 var Http2PostListener = function (expected_md5) {
335 this.expected_md5 = expected_md5;
338 Http2PostListener.prototype = new Http2CheckListener();
339 Http2PostListener.prototype.expected_md5 = "";
341 Http2PostListener.prototype.onDataAvailable = function (
342 request,
343 stream,
344 off,
347 this.onDataAvailableFired = true;
348 this.isHttp2Connection = checkIsHttp2(request);
349 read_stream(stream, cnt);
350 Assert.equal(
351 this.expected_md5,
352 request.getResponseHeader("X-Calculated-MD5")
356 var ResumeStalledChannelListener = function () {};
358 ResumeStalledChannelListener.prototype = {
359 onStartRequestFired: false,
360 onDataAvailableFired: false,
361 isHttp2Connection: false,
362 shouldBeHttp2: true,
363 resumable: null,
365 onStartRequest: function testOnStartRequest(request) {
366 this.onStartRequestFired = true;
367 if (!Components.isSuccessCode(request.status)) {
368 do_throw("Channel should have a success code! (" + request.status + ")");
371 Assert.ok(request instanceof Ci.nsIHttpChannel);
372 Assert.equal(request.responseStatus, 200);
373 Assert.equal(request.requestSucceeded, true);
376 onDataAvailable: function testOnDataAvailable(request, stream, off, cnt) {
377 this.onDataAvailableFired = true;
378 this.isHttp2Connection = checkIsHttp2(request);
379 read_stream(stream, cnt);
382 onStopRequest: function testOnStopRequest(request, status) {
383 Assert.ok(this.onStartRequestFired);
384 Assert.ok(Components.isSuccessCode(status));
385 Assert.ok(this.onDataAvailableFired);
386 Assert.ok(this.isHttp2Connection == this.shouldBeHttp2);
387 this.resumable.resume();
391 // test a large download that creates stream flow control and
392 // confirm we can do another independent stream while the download
393 // stream is stuck
394 async function test_http2_blocking_download(serverPort) {
395 var chan = makeHTTPChannel(`https://localhost:${serverPort}/bigdownload`);
396 var internalChannel = chan.QueryInterface(Ci.nsIHttpChannelInternal);
397 internalChannel.initialRwin = 500000; // make the stream.suspend push back in h2
398 var p = new Promise(resolve => {
399 var listener = new Http2CheckListener();
400 listener.finish = resolve;
401 listener.expected = 3 * 1024 * 1024;
402 chan.asyncOpen(listener);
403 chan.suspend();
405 // wait 5 seconds so that stream flow control kicks in and then see if we
406 // can do a basic transaction (i.e. session not blocked). afterwards resume
407 // channel
408 do_timeout(5000, function () {
409 var simpleChannel = makeHTTPChannel(`https://localhost:${serverPort}/`);
410 var sl = new ResumeStalledChannelListener();
411 sl.resumable = chan;
412 simpleChannel.asyncOpen(sl);
414 return p;
417 // Make sure we make a HTTP2 connection and both us and the server mark it as such
418 async function test_http2_basic(serverPort) {
419 var chan = makeHTTPChannel(`https://localhost:${serverPort}/`);
420 var p = new Promise(resolve => {
421 var listener = new Http2CheckListener();
422 listener.finish = resolve;
423 chan.asyncOpen(listener);
425 return p;
428 async function test_http2_basic_unblocked_dep(serverPort) {
429 var chan = makeHTTPChannel(
430 `https://localhost:${serverPort}/basic_unblocked_dep`
432 var cos = chan.QueryInterface(Ci.nsIClassOfService);
433 cos.addClassFlags(Ci.nsIClassOfService.Unblocked);
434 return new Promise(resolve => {
435 var listener = new Http2CheckListener();
436 listener.finish = resolve;
437 chan.asyncOpen(listener);
441 // make sure we don't use h2 when disallowed
442 async function test_http2_nospdy(serverPort) {
443 var chan = makeHTTPChannel(`https://localhost:${serverPort}/`);
444 return new Promise(resolve => {
445 var listener = new Http2CheckListener();
446 listener.finish = resolve;
447 var internalChannel = chan.QueryInterface(Ci.nsIHttpChannelInternal);
448 internalChannel.allowSpdy = false;
449 listener.shouldBeHttp2 = false;
450 chan.asyncOpen(listener);
454 // Support for making sure XHR works over SPDY
455 function checkXhr(xhr, finish) {
456 if (xhr.readyState != 4) {
457 return;
460 Assert.equal(xhr.status, 200);
461 Assert.equal(checkIsHttp2(xhr), true);
462 finish();
465 // Fires off an XHR request over h2
466 async function test_http2_xhr(serverPort) {
467 return new Promise(resolve => {
468 var req = new XMLHttpRequest();
469 req.open("GET", `https://localhost:${serverPort}/`, true);
470 req.addEventListener("readystatechange", function () {
471 checkXhr(req, resolve);
473 req.send(null);
477 var Http2ConcurrentListener = function () {};
479 Http2ConcurrentListener.prototype = new Http2CheckListener();
480 Http2ConcurrentListener.prototype.count = 0;
481 Http2ConcurrentListener.prototype.target = 0;
482 Http2ConcurrentListener.prototype.reset = 0;
483 Http2ConcurrentListener.prototype.recvdHdr = 0;
485 Http2ConcurrentListener.prototype.onStopRequest = function (request) {
486 this.count++;
487 Assert.ok(this.isHttp2Connection);
488 if (this.recvdHdr > 0) {
489 Assert.equal(request.getResponseHeader("X-Recvd"), this.recvdHdr);
492 if (this.count == this.target) {
493 if (this.reset > 0) {
494 Services.prefs.setIntPref(
495 "network.http.http2.default-concurrent",
496 this.reset
499 request.QueryInterface(Ci.nsIProxiedChannel);
500 var httpProxyConnectResponseCode = request.httpProxyConnectResponseCode;
501 this.finish({ httpProxyConnectResponseCode });
505 async function test_http2_concurrent(concurrent_channels, serverPort) {
506 var p = new Promise(resolve => {
507 var concurrent_listener = new Http2ConcurrentListener();
508 concurrent_listener.finish = resolve;
509 concurrent_listener.target = 201;
510 concurrent_listener.reset = Services.prefs.getIntPref(
511 "network.http.http2.default-concurrent"
513 Services.prefs.setIntPref("network.http.http2.default-concurrent", 100);
515 for (var i = 0; i < concurrent_listener.target; i++) {
516 concurrent_channels[i] = makeHTTPChannel(
517 `https://localhost:${serverPort}/750ms`
519 concurrent_channels[i].loadFlags = Ci.nsIRequest.LOAD_BYPASS_CACHE;
520 concurrent_channels[i].asyncOpen(concurrent_listener);
523 return p;
526 async function test_http2_concurrent_post(concurrent_channels, serverPort) {
527 return new Promise(resolve => {
528 var concurrent_listener = new Http2ConcurrentListener();
529 concurrent_listener.finish = resolve;
530 concurrent_listener.target = 8;
531 concurrent_listener.recvdHdr = posts[2].length;
532 concurrent_listener.reset = Services.prefs.getIntPref(
533 "network.http.http2.default-concurrent"
535 Services.prefs.setIntPref("network.http.http2.default-concurrent", 3);
537 for (var i = 0; i < concurrent_listener.target; i++) {
538 concurrent_channels[i] = makeHTTPChannel(
539 `https://localhost:${serverPort}/750msPost`
541 concurrent_channels[i].loadFlags = Ci.nsIRequest.LOAD_BYPASS_CACHE;
542 var stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(
543 Ci.nsIStringInputStream
545 stream.setByteStringData(posts[2]);
546 var uchan = concurrent_channels[i].QueryInterface(Ci.nsIUploadChannel);
547 uchan.setUploadStream(stream, "text/plain", stream.available());
548 concurrent_channels[i].requestMethod = "POST";
549 concurrent_channels[i].asyncOpen(concurrent_listener);
554 // Test to make sure we get multiplexing right
555 async function test_http2_multiplex(serverPort) {
556 let chan1 = makeHTTPChannel(`https://localhost:${serverPort}/multiplex1`);
557 let chan2 = makeHTTPChannel(`https://localhost:${serverPort}/multiplex2`);
558 let listener1 = new Http2MultiplexListener();
559 let listener2 = new Http2MultiplexListener();
561 let promises = [];
562 let p1 = new Promise(resolve => {
563 listener1.finish = resolve;
565 promises.push(p1);
566 let p2 = new Promise(resolve => {
567 listener2.finish = resolve;
569 promises.push(p2);
571 chan1.asyncOpen(listener1);
572 chan2.asyncOpen(listener2);
573 return Promise.all(promises);
576 // Test to make sure we gateway non-standard headers properly
577 async function test_http2_header(serverPort) {
578 let chan = makeHTTPChannel(`https://localhost:${serverPort}/header`);
579 let hvalue = "Headers are fun";
580 chan.setRequestHeader("X-Test-Header", hvalue, false);
581 return new Promise(resolve => {
582 let listener = new Http2HeaderListener("X-Received-Test-Header", function (
583 received_hvalue
585 Assert.equal(received_hvalue, hvalue);
587 listener.finish = resolve;
588 chan.asyncOpen(listener);
592 // Test to make sure headers with invalid characters in the name are rejected
593 async function test_http2_invalid_response_header(serverPort, invalid_kind) {
594 return new Promise(resolve => {
595 var listener = new Http2CheckListener();
596 listener.finish = resolve;
597 listener.shouldSucceed = false;
598 var chan = makeHTTPChannel(
599 `https://localhost:${serverPort}/invalid_response_header/${invalid_kind}`
601 chan.asyncOpen(listener);
605 // Test to make sure cookies are split into separate fields before compression
606 async function test_http2_cookie_crumbling(serverPort) {
607 var chan = makeHTTPChannel(
608 `https://localhost:${serverPort}/cookie_crumbling`
610 var cookiesSent = ["a=b", "c=d01234567890123456789", "e=f"].sort();
611 chan.setRequestHeader("Cookie", cookiesSent.join("; "), false);
612 return new Promise(resolve => {
613 var listener = new Http2HeaderListener("X-Received-Header-Pairs", function (
614 pairsReceived
616 var cookiesReceived = JSON.parse(pairsReceived)
617 .filter(function (pair) {
618 return pair[0] == "cookie";
620 .map(function (pair) {
621 return pair[1];
623 .sort();
624 Assert.equal(cookiesReceived.length, cookiesSent.length);
625 cookiesReceived.forEach(function (cookieReceived, index) {
626 Assert.equal(cookiesSent[index], cookieReceived);
629 listener.finish = resolve;
630 chan.asyncOpen(listener);
634 async function test_http2_push1(loadGroup, serverPort) {
635 var chan = makeHTTPChannel(`https://localhost:${serverPort}/push`);
636 chan.loadGroup = loadGroup;
637 return new Promise(resolve => {
638 var listener = new Http2PushListener(true);
639 listener.finish = resolve;
640 listener.serverPort = serverPort;
641 chan.asyncOpen(listener);
645 async function test_http2_push2(loadGroup, serverPort) {
646 var chan = makeHTTPChannel(`https://localhost:${serverPort}/push.js`);
647 chan.loadGroup = loadGroup;
648 return new Promise(resolve => {
649 var listener = new Http2PushListener(true);
650 listener.finish = resolve;
651 listener.serverPort = serverPort;
652 chan.asyncOpen(listener);
656 async function test_http2_push3(loadGroup, serverPort) {
657 var chan = makeHTTPChannel(`https://localhost:${serverPort}/push2`);
658 chan.loadGroup = loadGroup;
659 return new Promise(resolve => {
660 var listener = new Http2PushListener(true);
661 listener.finish = resolve;
662 listener.serverPort = serverPort;
663 chan.asyncOpen(listener);
667 async function test_http2_push4(loadGroup, serverPort) {
668 var chan = makeHTTPChannel(`https://localhost:${serverPort}/push2.js`);
669 chan.loadGroup = loadGroup;
670 return new Promise(resolve => {
671 var listener = new Http2PushListener(true);
672 listener.finish = resolve;
673 listener.serverPort = serverPort;
674 chan.asyncOpen(listener);
678 async function test_http2_push5(loadGroup, serverPort) {
679 var chan = makeHTTPChannel(`https://localhost:${serverPort}/push5`);
680 chan.loadGroup = loadGroup;
681 return new Promise(resolve => {
682 var listener = new Http2PushListener(true);
683 listener.finish = resolve;
684 listener.serverPort = serverPort;
685 chan.asyncOpen(listener);
689 async function test_http2_push6(loadGroup, serverPort) {
690 var chan = makeHTTPChannel(`https://localhost:${serverPort}/push5.js`);
691 chan.loadGroup = loadGroup;
692 return new Promise(resolve => {
693 var listener = new Http2PushListener(true);
694 listener.finish = resolve;
695 listener.serverPort = serverPort;
696 chan.asyncOpen(listener);
700 // this is a basic test where the server sends a simple document with 2 header
701 // blocks. bug 1027364
702 async function test_http2_doubleheader(serverPort) {
703 var chan = makeHTTPChannel(`https://localhost:${serverPort}/doubleheader`);
704 return new Promise(resolve => {
705 var listener = new Http2CheckListener();
706 listener.finish = resolve;
707 chan.asyncOpen(listener);
711 // Make sure we handle GETs that cover more than 2 frames properly
712 async function test_http2_big(serverPort) {
713 var chan = makeHTTPChannel(`https://localhost:${serverPort}/big`);
714 return new Promise(resolve => {
715 var listener = new Http2BigListener();
716 listener.finish = resolve;
717 chan.asyncOpen(listener);
721 async function test_http2_huge_suspended(serverPort) {
722 var chan = makeHTTPChannel(`https://localhost:${serverPort}/huge`);
723 return new Promise(resolve => {
724 var listener = new Http2HugeSuspendedListener();
725 listener.finish = resolve;
726 chan.asyncOpen(listener);
727 chan.suspend();
728 do_timeout(500, chan.resume);
732 // Support for doing a POST
733 function do_post(content, chan, listener, method) {
734 var stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(
735 Ci.nsIStringInputStream
737 stream.setByteStringData(content);
739 var uchan = chan.QueryInterface(Ci.nsIUploadChannel);
740 uchan.setUploadStream(stream, "text/plain", stream.available());
742 chan.requestMethod = method;
744 chan.asyncOpen(listener);
747 // Make sure we can do a simple POST
748 async function test_http2_post(serverPort) {
749 var chan = makeHTTPChannel(`https://localhost:${serverPort}/post`);
750 var p = new Promise(resolve => {
751 var listener = new Http2PostListener(md5s[0]);
752 listener.finish = resolve;
753 do_post(posts[0], chan, listener, "POST");
755 return p;
758 async function test_http2_empty_post(serverPort) {
759 var chan = makeHTTPChannel(`https://localhost:${serverPort}/post`);
760 var p = new Promise(resolve => {
761 var listener = new Http2PostListener("0");
762 listener.finish = resolve;
763 do_post("", chan, listener, "POST");
765 return p;
768 // Make sure we can do a simple PATCH
769 async function test_http2_patch(serverPort) {
770 var chan = makeHTTPChannel(`https://localhost:${serverPort}/patch`);
771 return new Promise(resolve => {
772 var listener = new Http2PostListener(md5s[0]);
773 listener.finish = resolve;
774 do_post(posts[0], chan, listener, "PATCH");
778 // Make sure we can do a POST that covers more than 2 frames
779 async function test_http2_post_big(serverPort) {
780 var chan = makeHTTPChannel(`https://localhost:${serverPort}/post`);
781 return new Promise(resolve => {
782 var listener = new Http2PostListener(md5s[1]);
783 listener.finish = resolve;
784 do_post(posts[1], chan, listener, "POST");
788 // When a http proxy is used alt-svc is disable. Therefore if withProxy is true,
789 // try numberOfTries times to connect and make sure that alt-svc is not use and we never
790 // connect to the HTTP/2 server.
791 var altsvcClientListener = function (
792 finish,
793 httpserv,
794 httpserv2,
795 withProxy,
796 numberOfTries
798 this.finish = finish;
799 this.httpserv = httpserv;
800 this.httpserv2 = httpserv2;
801 this.withProxy = withProxy;
802 this.numberOfTries = numberOfTries;
805 altsvcClientListener.prototype = {
806 onStartRequest: function test_onStartR(request) {
807 Assert.equal(request.status, Cr.NS_OK);
810 onDataAvailable: function test_ODA(request, stream, offset, cnt) {
811 read_stream(stream, cnt);
814 onStopRequest: function test_onStopR(request) {
815 var isHttp2Connection = checkIsHttp2(
816 request.QueryInterface(Ci.nsIHttpChannel)
818 if (!isHttp2Connection) {
819 dump("/altsvc1 not over h2 yet - retry\n");
820 if (this.withProxy && this.numberOfTries == 0) {
821 request.QueryInterface(Ci.nsIProxiedChannel);
822 var httpProxyConnectResponseCode = request.httpProxyConnectResponseCode;
823 this.finish({ httpProxyConnectResponseCode });
824 return;
826 let chan = makeHTTPChannel(
827 `http://foo.example.com:${this.httpserv}/altsvc1`,
828 this.withProxy
829 ).QueryInterface(Ci.nsIHttpChannel);
830 // we use this header to tell the server to issue a altsvc frame for the
831 // speficied origin we will use in the next part of the test
832 chan.setRequestHeader(
833 "x-redirect-origin",
834 `http://foo.example.com:${this.httpserv2}`,
835 false
837 chan.loadFlags = Ci.nsIRequest.LOAD_BYPASS_CACHE;
838 chan.asyncOpen(
839 new altsvcClientListener(
840 this.finish,
841 this.httpserv,
842 this.httpserv2,
843 this.withProxy,
844 this.numberOfTries - 1
847 } else {
848 Assert.ok(isHttp2Connection);
849 let chan = makeHTTPChannel(
850 `http://foo.example.com:${this.httpserv2}/altsvc2`
851 ).QueryInterface(Ci.nsIHttpChannel);
852 chan.loadFlags = Ci.nsIRequest.LOAD_BYPASS_CACHE;
853 chan.asyncOpen(
854 new altsvcClientListener2(this.finish, this.httpserv, this.httpserv2)
860 var altsvcClientListener2 = function (finish, httpserv, httpserv2) {
861 this.finish = finish;
862 this.httpserv = httpserv;
863 this.httpserv2 = httpserv2;
866 altsvcClientListener2.prototype = {
867 onStartRequest: function test_onStartR(request) {
868 Assert.equal(request.status, Cr.NS_OK);
871 onDataAvailable: function test_ODA(request, stream, offset, cnt) {
872 read_stream(stream, cnt);
875 onStopRequest: function test_onStopR(request) {
876 var isHttp2Connection = checkIsHttp2(
877 request.QueryInterface(Ci.nsIHttpChannel)
879 if (!isHttp2Connection) {
880 dump("/altsvc2 not over h2 yet - retry\n");
881 var chan = makeHTTPChannel(
882 `http://foo.example.com:${this.httpserv2}/altsvc2`
883 ).QueryInterface(Ci.nsIHttpChannel);
884 chan.loadFlags = Ci.nsIRequest.LOAD_BYPASS_CACHE;
885 chan.asyncOpen(
886 new altsvcClientListener2(this.finish, this.httpserv, this.httpserv2)
888 } else {
889 Assert.ok(isHttp2Connection);
890 request.QueryInterface(Ci.nsIProxiedChannel);
891 var httpProxyConnectResponseCode = request.httpProxyConnectResponseCode;
892 this.finish({ httpProxyConnectResponseCode });
897 async function test_http2_altsvc(httpserv, httpserv2, withProxy) {
898 var chan = makeHTTPChannel(
899 `http://foo.example.com:${httpserv}/altsvc1`,
900 withProxy
901 ).QueryInterface(Ci.nsIHttpChannel);
902 return new Promise(resolve => {
903 var numberOfTries = 0;
904 if (withProxy) {
905 numberOfTries = 20;
907 chan.asyncOpen(
908 new altsvcClientListener(
909 resolve,
910 httpserv,
911 httpserv2,
912 withProxy,
913 numberOfTries
919 var Http2PushApiListener = function (finish, serverPort) {
920 this.finish = finish;
921 this.serverPort = serverPort;
924 Http2PushApiListener.prototype = {
925 checksPending: 9, // 4 onDataAvailable and 5 onStop
927 getInterface(aIID) {
928 return this.QueryInterface(aIID);
931 QueryInterface: ChromeUtils.generateQI([
932 "nsIHttpPushListener",
933 "nsIStreamListener",
936 // nsIHttpPushListener
937 onPush: function onPush(associatedChannel, pushChannel) {
938 Assert.equal(
939 associatedChannel.originalURI.spec,
940 "https://localhost:" + this.serverPort + "/pushapi1"
942 Assert.equal(pushChannel.getRequestHeader("x-pushed-request"), "true");
944 pushChannel.asyncOpen(this);
945 if (
946 pushChannel.originalURI.spec ==
947 "https://localhost:" + this.serverPort + "/pushapi1/2"
949 pushChannel.cancel(Cr.NS_ERROR_ABORT);
950 } else if (
951 pushChannel.originalURI.spec ==
952 "https://localhost:" + this.serverPort + "/pushapi1/3"
954 Assert.ok(pushChannel.getRequestHeader("Accept-Encoding").includes("br"));
958 // normal Channel listeners
959 onStartRequest: function pushAPIOnStart() {},
961 onDataAvailable: function pushAPIOnDataAvailable(
962 request,
963 stream,
964 offset,
967 Assert.notEqual(
968 request.originalURI.spec,
969 `https://localhost:${this.serverPort}/pushapi1/2`
972 var data = read_stream(stream, cnt);
974 if (
975 request.originalURI.spec ==
976 `https://localhost:${this.serverPort}/pushapi1`
978 Assert.equal(data[0], "0");
979 --this.checksPending;
980 } else if (
981 request.originalURI.spec ==
982 `https://localhost:${this.serverPort}/pushapi1/1`
984 Assert.equal(data[0], "1");
985 --this.checksPending; // twice
986 } else if (
987 request.originalURI.spec ==
988 `https://localhost:${this.serverPort}/pushapi1/3`
990 Assert.equal(data[0], "3");
991 --this.checksPending;
992 } else {
993 Assert.equal(true, false);
997 onStopRequest: function test_onStopR(request) {
998 if (
999 request.originalURI.spec ==
1000 `https://localhost:${this.serverPort}/pushapi1/2`
1002 Assert.equal(request.status, Cr.NS_ERROR_ABORT);
1003 } else {
1004 Assert.equal(request.status, Cr.NS_OK);
1007 --this.checksPending; // 5 times - one for each push plus the pull
1008 if (!this.checksPending) {
1009 request.QueryInterface(Ci.nsIProxiedChannel);
1010 var httpProxyConnectResponseCode = request.httpProxyConnectResponseCode;
1011 this.finish({ httpProxyConnectResponseCode });
1016 // pushAPI testcase 1 expects
1017 // 1 to pull /pushapi1 with 0
1018 // 2 to see /pushapi1/1 with 1
1019 // 3 to see /pushapi1/1 with 1 (again)
1020 // 4 to see /pushapi1/2 that it will cancel
1021 // 5 to see /pushapi1/3 with 3 with brotli
1023 async function test_http2_pushapi_1(loadGroup, serverPort) {
1024 var chan = makeHTTPChannel(`https://localhost:${serverPort}/pushapi1`);
1025 chan.loadGroup = loadGroup;
1026 return new Promise(resolve => {
1027 var listener = new Http2PushApiListener(resolve, serverPort);
1028 chan.notificationCallbacks = listener;
1029 chan.asyncOpen(listener);
1033 var WrongSuiteListener = function () {};
1035 WrongSuiteListener.prototype = new Http2CheckListener();
1036 WrongSuiteListener.prototype.shouldBeHttp2 = false;
1037 WrongSuiteListener.prototype.onStopRequest = function (request, status) {
1038 Services.prefs.setBoolPref(
1039 "security.ssl3.ecdhe_rsa_aes_128_gcm_sha256",
1040 true
1042 Services.prefs.clearUserPref("security.tls.version.max");
1043 Http2CheckListener.prototype.onStopRequest.call(this, request, status);
1046 // test that we use h1 without the mandatory cipher suite available when
1047 // offering at most tls1.2
1048 async function test_http2_wrongsuite_tls12(serverPort) {
1049 Services.prefs.setBoolPref(
1050 "security.ssl3.ecdhe_rsa_aes_128_gcm_sha256",
1051 false
1053 Services.prefs.setIntPref("security.tls.version.max", 3);
1054 var chan = makeHTTPChannel(`https://localhost:${serverPort}/wrongsuite`);
1055 chan.loadFlags =
1056 Ci.nsIRequest.LOAD_FRESH_CONNECTION |
1057 Ci.nsIChannel.LOAD_INITIAL_DOCUMENT_URI;
1058 return new Promise(resolve => {
1059 var listener = new WrongSuiteListener();
1060 listener.finish = resolve;
1061 chan.asyncOpen(listener);
1065 // test that we use h2 when offering tls1.3 or higher regardless of if the
1066 // mandatory cipher suite is available
1067 async function test_http2_wrongsuite_tls13(serverPort) {
1068 Services.prefs.setBoolPref(
1069 "security.ssl3.ecdhe_rsa_aes_128_gcm_sha256",
1070 false
1072 var chan = makeHTTPChannel(`https://localhost:${serverPort}/wrongsuite`);
1073 chan.loadFlags =
1074 Ci.nsIRequest.LOAD_FRESH_CONNECTION |
1075 Ci.nsIChannel.LOAD_INITIAL_DOCUMENT_URI;
1076 return new Promise(resolve => {
1077 var listener = new WrongSuiteListener();
1078 listener.finish = resolve;
1079 listener.shouldBeHttp2 = true;
1080 chan.asyncOpen(listener);
1084 async function test_http2_h11required_stream(serverPort) {
1085 var chan = makeHTTPChannel(
1086 `https://localhost:${serverPort}/h11required_stream`
1088 return new Promise(resolve => {
1089 var listener = new Http2CheckListener();
1090 listener.finish = resolve;
1091 listener.shouldBeHttp2 = false;
1092 chan.asyncOpen(listener);
1096 function H11RequiredSessionListener() {}
1098 H11RequiredSessionListener.prototype = new Http2CheckListener();
1100 H11RequiredSessionListener.prototype.onStopRequest = function (request) {
1101 var streamReused = request.getResponseHeader("X-H11Required-Stream-Ok");
1102 Assert.equal(streamReused, "yes");
1104 Assert.ok(this.onStartRequestFired);
1105 Assert.ok(this.onDataAvailableFired);
1106 Assert.ok(this.isHttp2Connection == this.shouldBeHttp2);
1108 request.QueryInterface(Ci.nsIProxiedChannel);
1109 var httpProxyConnectResponseCode = request.httpProxyConnectResponseCode;
1110 this.finish({ httpProxyConnectResponseCode });
1113 async function test_http2_h11required_session(serverPort) {
1114 var chan = makeHTTPChannel(
1115 `https://localhost:${serverPort}/h11required_session`
1117 return new Promise(resolve => {
1118 var listener = new H11RequiredSessionListener();
1119 listener.finish = resolve;
1120 listener.shouldBeHttp2 = false;
1121 chan.asyncOpen(listener);
1125 async function test_http2_retry_rst(serverPort) {
1126 var chan = makeHTTPChannel(`https://localhost:${serverPort}/rstonce`);
1127 return new Promise(resolve => {
1128 var listener = new Http2CheckListener();
1129 listener.finish = resolve;
1130 chan.asyncOpen(listener);
1134 async function test_http2_continuations(loadGroup, serverPort) {
1135 var chan = makeHTTPChannel(
1136 `https://localhost:${serverPort}/continuedheaders`
1138 chan.loadGroup = loadGroup;
1139 return new Promise(resolve => {
1140 var listener = new Http2ContinuedHeaderListener();
1141 listener.finish = resolve;
1142 listener.serverPort = serverPort;
1143 chan.notificationCallbacks = listener;
1144 chan.asyncOpen(listener);
1148 async function test_http2_continuations_over_max_response_limit(
1149 loadGroup,
1150 serverPort
1152 var chan = makeHTTPChannel(
1153 `https://localhost:${serverPort}/hugecontinuedheaders?size=385`
1155 chan.loadGroup = loadGroup;
1156 return new Promise(resolve => {
1157 var listener = new Http2CheckListener();
1158 listener.finish = resolve;
1159 listener.shouldSucceed = false;
1160 chan.asyncOpen(listener);
1164 function Http2IllegalHpackValidationListener() {}
1166 Http2IllegalHpackValidationListener.prototype = new Http2CheckListener();
1167 Http2IllegalHpackValidationListener.prototype.shouldGoAway = false;
1169 Http2IllegalHpackValidationListener.prototype.onStopRequest = function (
1170 request
1172 var wentAway = request.getResponseHeader("X-Did-Goaway") === "yes";
1173 Assert.equal(wentAway, this.shouldGoAway);
1175 Assert.ok(this.onStartRequestFired);
1176 Assert.ok(this.onDataAvailableFired);
1177 Assert.ok(this.isHttp2Connection == this.shouldBeHttp2);
1179 request.QueryInterface(Ci.nsIProxiedChannel);
1180 var httpProxyConnectResponseCode = request.httpProxyConnectResponseCode;
1181 this.finish({ httpProxyConnectResponseCode });
1184 function Http2IllegalHpackListener() {}
1185 Http2IllegalHpackListener.prototype = new Http2CheckListener();
1186 Http2IllegalHpackListener.prototype.shouldGoAway = false;
1188 Http2IllegalHpackListener.prototype.onStopRequest = function () {
1189 var chan = makeHTTPChannel(
1190 `https://localhost:${this.serverPort}/illegalhpack_validate`
1192 var listener = new Http2IllegalHpackValidationListener();
1193 listener.finish = this.finish;
1194 listener.shouldGoAway = this.shouldGoAway;
1195 chan.asyncOpen(listener);
1198 async function test_http2_illegalhpacksoft(serverPort) {
1199 var chan = makeHTTPChannel(
1200 `https://localhost:${serverPort}/illegalhpacksoft`
1202 return new Promise(resolve => {
1203 var listener = new Http2IllegalHpackListener();
1204 listener.finish = resolve;
1205 listener.serverPort = serverPort;
1206 listener.shouldGoAway = false;
1207 listener.shouldSucceed = false;
1208 chan.asyncOpen(listener);
1212 async function test_http2_illegalhpackhard(serverPort) {
1213 var chan = makeHTTPChannel(
1214 `https://localhost:${serverPort}/illegalhpackhard`
1216 return new Promise(resolve => {
1217 var listener = new Http2IllegalHpackListener();
1218 listener.finish = resolve;
1219 listener.serverPort = serverPort;
1220 listener.shouldGoAway = true;
1221 listener.shouldSucceed = false;
1222 chan.asyncOpen(listener);
1226 async function test_http2_folded_header(loadGroup, serverPort) {
1227 var chan = makeHTTPChannel(`https://localhost:${serverPort}/foldedheader`);
1228 chan.loadGroup = loadGroup;
1229 return new Promise(resolve => {
1230 var listener = new Http2CheckListener();
1231 listener.finish = resolve;
1232 listener.shouldSucceed = false;
1233 chan.asyncOpen(listener);
1237 async function test_http2_empty_data(serverPort) {
1238 var chan = makeHTTPChannel(`https://localhost:${serverPort}/emptydata`);
1239 return new Promise(resolve => {
1240 var listener = new Http2CheckListener();
1241 listener.finish = resolve;
1242 chan.asyncOpen(listener);
1246 async function test_http2_push_firstparty1(loadGroup, serverPort) {
1247 var chan = makeHTTPChannel(`https://localhost:${serverPort}/push`);
1248 chan.loadGroup = loadGroup;
1249 chan.loadInfo.originAttributes = { firstPartyDomain: "foo.com" };
1250 return new Promise(resolve => {
1251 var listener = new Http2PushListener(true);
1252 listener.finish = resolve;
1253 listener.serverPort = serverPort;
1254 chan.asyncOpen(listener);
1258 async function test_http2_push_firstparty2(loadGroup, serverPort) {
1259 var chan = makeHTTPChannel(`https://localhost:${serverPort}/push.js`);
1260 chan.loadGroup = loadGroup;
1261 chan.loadInfo.originAttributes = { firstPartyDomain: "bar.com" };
1262 return new Promise(resolve => {
1263 var listener = new Http2PushListener(false);
1264 listener.finish = resolve;
1265 listener.serverPort = serverPort;
1266 chan.asyncOpen(listener);
1270 async function test_http2_push_firstparty3(loadGroup, serverPort) {
1271 var chan = makeHTTPChannel(`https://localhost:${serverPort}/push.js`);
1272 chan.loadGroup = loadGroup;
1273 chan.loadInfo.originAttributes = { firstPartyDomain: "foo.com" };
1274 return new Promise(resolve => {
1275 var listener = new Http2PushListener(true);
1276 listener.finish = resolve;
1277 listener.serverPort = serverPort;
1278 chan.asyncOpen(listener);
1282 async function test_http2_push_userContext1(loadGroup, serverPort) {
1283 var chan = makeHTTPChannel(`https://localhost:${serverPort}/push`);
1284 chan.loadGroup = loadGroup;
1285 chan.loadInfo.originAttributes = { userContextId: 1 };
1286 return new Promise(resolve => {
1287 var listener = new Http2PushListener(true);
1288 listener.finish = resolve;
1289 listener.serverPort = serverPort;
1290 chan.asyncOpen(listener);
1294 async function test_http2_push_userContext2(loadGroup, serverPort) {
1295 var chan = makeHTTPChannel(`https://localhost:${serverPort}/push.js`);
1296 chan.loadGroup = loadGroup;
1297 chan.loadInfo.originAttributes = { userContextId: 2 };
1298 return new Promise(resolve => {
1299 var listener = new Http2PushListener(false);
1300 listener.finish = resolve;
1301 listener.serverPort = serverPort;
1302 chan.asyncOpen(listener);
1306 async function test_http2_push_userContext3(loadGroup, serverPort) {
1307 var chan = makeHTTPChannel(`https://localhost:${serverPort}/push.js`);
1308 chan.loadGroup = loadGroup;
1309 chan.loadInfo.originAttributes = { userContextId: 1 };
1310 return new Promise(resolve => {
1311 var listener = new Http2PushListener(true);
1312 listener.finish = resolve;
1313 listener.serverPort = serverPort;
1314 chan.asyncOpen(listener);
1318 async function test_http2_status_phrase(serverPort) {
1319 var chan = makeHTTPChannel(`https://localhost:${serverPort}/statusphrase`);
1320 return new Promise(resolve => {
1321 var listener = new Http2CheckListener();
1322 listener.finish = resolve;
1323 listener.shouldSucceed = false;
1324 chan.asyncOpen(listener);
1328 var PulledDiskCacheListener = function () {};
1329 PulledDiskCacheListener.prototype = new Http2CheckListener();
1330 PulledDiskCacheListener.prototype.EXPECTED_DATA = "this was pulled via h2";
1331 PulledDiskCacheListener.prototype.readData = "";
1332 PulledDiskCacheListener.prototype.onDataAvailable =
1333 function testOnDataAvailable(request, stream, off, cnt) {
1334 this.onDataAvailableFired = true;
1335 this.isHttp2Connection = checkIsHttp2(request);
1336 this.accum += cnt;
1337 this.readData += read_stream(stream, cnt);
1339 PulledDiskCacheListener.prototype.onStopRequest = function testOnStopRequest(
1340 request,
1341 status
1343 Assert.equal(this.EXPECTED_DATA, this.readData);
1344 Http2CheckListener.prorotype.onStopRequest.call(this, request, status);
1347 const DISK_CACHE_DATA = "this is from disk cache";
1349 var FromDiskCacheListener = function (finish, loadGroup, serverPort) {
1350 this.finish = finish;
1351 this.loadGroup = loadGroup;
1352 this.serverPort = serverPort;
1354 FromDiskCacheListener.prototype = {
1355 onStartRequestFired: false,
1356 onDataAvailableFired: false,
1357 readData: "",
1359 onStartRequest: function testOnStartRequest(request) {
1360 this.onStartRequestFired = true;
1361 if (!Components.isSuccessCode(request.status)) {
1362 do_throw("Channel should have a success code! (" + request.status + ")");
1365 Assert.ok(request instanceof Ci.nsIHttpChannel);
1366 Assert.ok(request.requestSucceeded);
1367 Assert.equal(request.responseStatus, 200);
1370 onDataAvailable: function testOnDataAvailable(request, stream, off, cnt) {
1371 this.onDataAvailableFired = true;
1372 this.readData += read_stream(stream, cnt);
1375 onStopRequest: function testOnStopRequest(request, status) {
1376 Assert.ok(this.onStartRequestFired);
1377 Assert.ok(Components.isSuccessCode(status));
1378 Assert.ok(this.onDataAvailableFired);
1379 Assert.equal(this.readData, DISK_CACHE_DATA);
1381 evict_cache_entries("disk");
1382 syncWithCacheIOThread(() => {
1383 // Now that we know the entry is out of the disk cache, check to make sure
1384 // we don't have this hiding in the push cache somewhere - if we do, it
1385 // didn't get cancelled, and we have a bug.
1386 var chan = makeHTTPChannel(
1387 `https://localhost:${this.serverPort}/diskcache`
1389 var listener = new PulledDiskCacheListener();
1390 listener.finish = this.finish;
1391 chan.loadGroup = this.loadGroup;
1392 chan.asyncOpen(listener);
1397 var Http2DiskCachePushListener = function () {};
1398 Http2DiskCachePushListener.prototype = new Http2CheckListener();
1400 Http2DiskCachePushListener.onStopRequest = function (request, status) {
1401 Assert.ok(this.onStartRequestFired);
1402 Assert.ok(Components.isSuccessCode(status));
1403 Assert.ok(this.onDataAvailableFired);
1404 Assert.ok(this.isHttp2Connection == this.shouldBeHttp2);
1406 // Now we need to open a channel to ensure we get data from the disk cache
1407 // for the pushed item, instead of from the push cache.
1408 var chan = makeHTTPChannel(`https://localhost:${this.serverPort}/diskcache`);
1409 var listener = new FromDiskCacheListener(
1410 this.finish,
1411 this.loadGroup,
1412 this.serverPort
1414 chan.loadGroup = this.loadGroup;
1415 chan.asyncOpen(listener);
1418 function continue_test_http2_disk_cache_push(
1419 status,
1420 entry,
1421 finish,
1422 loadGroup,
1423 serverPort
1425 // TODO - store stuff in cache entry, then open an h2 channel that will push
1426 // this, once that completes, open a channel for the cache entry we made and
1427 // ensure it came from disk cache, not the push cache.
1428 var outputStream = entry.openOutputStream(0, -1);
1429 outputStream.write(DISK_CACHE_DATA, DISK_CACHE_DATA.length);
1431 // Now we open our URL that will push data for the URL above
1432 var chan = makeHTTPChannel(`https://localhost:${serverPort}/pushindisk`);
1433 var listener = new Http2DiskCachePushListener();
1434 listener.finish = finish;
1435 listener.loadGroup = loadGroup;
1436 listener.serverPort = serverPort;
1437 chan.loadGroup = loadGroup;
1438 chan.asyncOpen(listener);
1441 async function test_http2_disk_cache_push(loadGroup, serverPort) {
1442 return new Promise(resolve => {
1443 asyncOpenCacheEntry(
1444 `https://localhost:${serverPort}/diskcache`,
1445 "disk",
1446 Ci.nsICacheStorage.OPEN_NORMALLY,
1447 null,
1448 function (status, entry) {
1449 continue_test_http2_disk_cache_push(
1450 status,
1451 entry,
1452 resolve,
1453 loadGroup,
1454 serverPort
1457 false
1462 var Http2DoublepushListener = function () {};
1463 Http2DoublepushListener.prototype = new Http2CheckListener();
1464 Http2DoublepushListener.prototype.onStopRequest = function (request, status) {
1465 Assert.ok(this.onStartRequestFired);
1466 Assert.ok(Components.isSuccessCode(status));
1467 Assert.ok(this.onDataAvailableFired);
1468 Assert.ok(this.isHttp2Connection == this.shouldBeHttp2);
1470 var chan = makeHTTPChannel(
1471 `https://localhost:${this.serverPort}/doublypushed`
1473 var listener = new Http2DoublypushedListener();
1474 listener.finish = this.finish;
1475 chan.loadGroup = this.loadGroup;
1476 chan.asyncOpen(listener);
1479 var Http2DoublypushedListener = function () {};
1480 Http2DoublypushedListener.prototype = new Http2CheckListener();
1481 Http2DoublypushedListener.prototype.readData = "";
1482 Http2DoublypushedListener.prototype.onDataAvailable = function (
1483 request,
1484 stream,
1485 off,
1488 this.onDataAvailableFired = true;
1489 this.accum += cnt;
1490 this.readData += read_stream(stream, cnt);
1492 Http2DoublypushedListener.prototype.onStopRequest = function (request, status) {
1493 Assert.ok(this.onStartRequestFired);
1494 Assert.ok(Components.isSuccessCode(status));
1495 Assert.ok(this.onDataAvailableFired);
1496 Assert.equal(this.readData, "pushed");
1498 request.QueryInterface(Ci.nsIProxiedChannel);
1499 let httpProxyConnectResponseCode = request.httpProxyConnectResponseCode;
1500 this.finish({ httpProxyConnectResponseCode });
1503 function test_http2_doublepush(loadGroup, serverPort) {
1504 var chan = makeHTTPChannel(`https://localhost:${serverPort}/doublepush`);
1505 return new Promise(resolve => {
1506 var listener = new Http2DoublepushListener();
1507 listener.finish = resolve;
1508 listener.loadGroup = loadGroup;
1509 listener.serverPort = serverPort;
1510 chan.loadGroup = loadGroup;
1511 chan.asyncOpen(listener);