Bug 1931425 - Limit how often moz-label's #setStyles runs r=reusable-components-revie...
[gecko.git] / netwerk / test / unit / test_http2-proxy.js
blobd8aa0019fef182c6ecbf5ba3cc06334158b5a89c
1 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /**
8 * This test checks following expectations when using HTTP/2 proxy:
10 * - when we request https access, we don't create different sessions for
11 * different origins, only new tunnels inside a single session
12 * - when the isolation key (`proxy_isolation`) is changed, new single session
13 * is created for new requests to same origins as before
14 * - error code returned from the tunnel (a proxy error - not end-server
15 * error!) doesn't kill the existing session
16 * - check we are seeing expected nsresult error codes on channels
17 * (nsIChannel.status) corresponding to different proxy status code
18 * responses (502, 504, 407, ...)
19 * - check we don't try to ask for credentials or otherwise authenticate to
20 * the proxy when 407 is returned and there is no Proxy-Authenticate
21 * response header sent
22 * - a stream reset for a connect stream to the proxy does not cause session to
23 * be closed and the request through the proxy will failed.
24 * - a "soft" stream error on a connection to the origin server will close the
25 * stream, but it will not close niether the HTTP/2 session to the proxy nor
26 * to the origin server.
27 * - a "hard" stream error on a connection to the origin server will close the
28 * HTTP/2 session to the origin server, but it will not close the HTTP/2
29 * session to the proxy.
32 /* eslint-env node */
33 /* global serverPort */
35 "use strict";
37 const pps = Cc["@mozilla.org/network/protocol-proxy-service;1"].getService();
39 let proxy_port;
40 let filter;
41 let proxy;
43 // See moz-http2
44 const proxy_auth = "authorization-token";
45 let proxy_isolation;
47 class ProxyFilter {
48 constructor(type, host, port, flags) {
49 this._type = type;
50 this._host = host;
51 this._port = port;
52 this._flags = flags;
53 this.QueryInterface = ChromeUtils.generateQI(["nsIProtocolProxyFilter"]);
55 applyFilter(uri, pi, cb) {
56 cb.onProxyFilterResult(
57 pps.newProxyInfo(
58 this._type,
59 this._host,
60 this._port,
61 proxy_auth,
62 proxy_isolation,
63 this._flags,
64 1000,
65 null
71 class UnxpectedAuthPrompt2 {
72 constructor(signal) {
73 this.signal = signal;
74 this.QueryInterface = ChromeUtils.generateQI(["nsIAuthPrompt2"]);
76 asyncPromptAuth() {
77 this.signal.triggered = true;
78 throw Components.Exception("", Cr.ERROR_UNEXPECTED);
82 class SimpleAuthPrompt2 {
83 constructor(signal) {
84 this.signal = signal;
85 this.QueryInterface = ChromeUtils.generateQI(["nsIAuthPrompt2"]);
87 asyncPromptAuth(channel, callback, context, encryptionLevel, authInfo) {
88 this.signal.triggered = true;
89 executeSoon(function () {
90 authInfo.username = "user";
91 authInfo.password = "pass";
92 callback.onAuthAvailable(context, authInfo);
93 });
97 class AuthRequestor {
98 constructor(prompt) {
99 this.prompt = prompt;
100 this.QueryInterface = ChromeUtils.generateQI(["nsIInterfaceRequestor"]);
102 getInterface(iid) {
103 if (iid.equals(Ci.nsIAuthPrompt2)) {
104 return this.prompt();
106 throw Components.Exception("", Cr.NS_ERROR_NO_INTERFACE);
110 function createPrincipal(url) {
111 var ssm = Services.scriptSecurityManager;
112 try {
113 return ssm.createContentPrincipal(Services.io.newURI(url), {});
114 } catch (e) {
115 return null;
119 function make_channel(url) {
120 return NetUtil.newChannel({
121 uri: url,
122 loadingPrincipal: createPrincipal(url),
123 securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT,
124 // Using TYPE_DOCUMENT for the authentication dialog test, it'd be blocked for other types
125 contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT,
129 function get_response(channel, flags = CL_ALLOW_UNKNOWN_CL, delay = 0) {
130 return new Promise(resolve => {
131 var listener = new ChannelListener(
132 (request, data) => {
133 request.QueryInterface(Ci.nsIHttpChannel);
134 const status = request.status;
135 const http_code = status ? undefined : request.responseStatus;
136 request.QueryInterface(Ci.nsIProxiedChannel);
137 const proxy_connect_response_code =
138 request.httpProxyConnectResponseCode;
139 resolve({ status, http_code, data, proxy_connect_response_code });
141 null,
142 flags
144 if (delay > 0) {
145 do_timeout(delay, function () {
146 channel.asyncOpen(listener);
148 } else {
149 channel.asyncOpen(listener);
154 let initial_session_count = 0;
156 class http2ProxyCode {
157 static listen(server, envport) {
158 if (!server) {
159 return Promise.resolve(0);
162 let portSelection = 0;
163 if (envport !== undefined) {
164 try {
165 portSelection = parseInt(envport, 10);
166 } catch (e) {
167 portSelection = -1;
170 return new Promise(resolve => {
171 server.listen(portSelection, "0.0.0.0", 2000, () => {
172 resolve(server.address().port);
177 static startNewProxy() {
178 const fs = require("fs");
179 const options = {
180 key: fs.readFileSync(__dirname + "/http2-cert.key"),
181 cert: fs.readFileSync(__dirname + "/http2-cert.pem"),
183 const http2 = require("http2");
184 global.proxy = http2.createSecureServer(options);
185 this.setupProxy();
186 return http2ProxyCode.listen(proxy).then(port => {
187 return { port, success: true };
191 static closeProxy() {
192 proxy.closeSockets();
193 return new Promise(resolve => {
194 proxy.close(resolve);
198 static proxySessionCount() {
199 if (!proxy) {
200 return 0;
202 return proxy.proxy_session_count;
205 static proxySessionToOriginServersCount() {
206 if (!proxy) {
207 return 0;
209 return proxy.sessionToOriginServersCount;
212 static setupProxy() {
213 if (!proxy) {
214 throw new Error("proxy is null");
216 proxy.proxy_session_count = 0;
217 proxy.sessionToOriginServersCount = 0;
218 proxy.on("session", () => {
219 ++proxy.proxy_session_count;
222 // We need to track active connections so we can forcefully close keep-alive
223 // connections when shutting down the proxy.
224 proxy.socketIndex = 0;
225 proxy.socketMap = {};
226 proxy.on("connection", function (socket) {
227 let index = proxy.socketIndex++;
228 proxy.socketMap[index] = socket;
229 socket.on("close", function () {
230 delete proxy.socketMap[index];
233 proxy.closeSockets = function () {
234 for (let i in proxy.socketMap) {
235 proxy.socketMap[i].destroy();
239 proxy.on("stream", (stream, headers) => {
240 if (headers[":method"] !== "CONNECT") {
241 // Only accept CONNECT requests
242 stream.respond({ ":status": 405 });
243 stream.end();
244 return;
247 const target = headers[":authority"];
249 const authorization_token = headers["proxy-authorization"];
250 if (target == "407.example.com:443") {
251 stream.respond({ ":status": 407 });
252 // Deliberately send no Proxy-Authenticate header
253 stream.end();
254 return;
256 if (target == "407.basic.example.com:443") {
257 // we want to return a different response than 407 to not re-request
258 // credentials (and thus loop) but also not 200 to not let the channel
259 // attempt to waste time connecting a non-existing https server - hence
260 // 418 I'm a teapot :)
261 if ("Basic dXNlcjpwYXNz" == authorization_token) {
262 stream.respond({ ":status": 418 });
263 stream.end();
264 return;
266 stream.respond({
267 ":status": 407,
268 "proxy-authenticate": "Basic realm='foo'",
270 stream.end();
271 return;
273 if (target == "404.example.com:443") {
274 // 404 Not Found, a response code that a proxy should return when the host can't be found
275 stream.respond({ ":status": 404 });
276 stream.end();
277 return;
279 if (target == "429.example.com:443") {
280 // 429 Too Many Requests, a response code that a proxy should return when receiving too many requests
281 stream.respond({ ":status": 429 });
282 stream.end();
283 return;
285 if (target == "502.example.com:443") {
286 // 502 Bad Gateway, a response code mostly resembling immediate connection error
287 stream.respond({ ":status": 502 });
288 stream.end();
289 return;
291 if (target == "504.example.com:443") {
292 // 504 Gateway Timeout, did not receive a timely response from an upstream server
293 stream.respond({ ":status": 504 });
294 stream.end();
295 return;
297 if (target == "reset.example.com:443") {
298 // always reset the stream.
299 stream.close(0x0);
300 return;
303 ++proxy.sessionToOriginServersCount;
304 const net = require("net");
305 const socket = net.connect(serverPort, "127.0.0.1", () => {
306 try {
307 stream.respond({ ":status": 200 });
308 socket.pipe(stream);
309 stream.pipe(socket);
310 } catch (exception) {
311 console.log(exception);
312 stream.close();
315 socket.on("error", error => {
316 throw new Error(
317 `Unexpected error when conneting the HTTP/2 server from the HTTP/2 proxy during CONNECT handling: '${error}'`
324 async function proxy_session_counter() {
325 let data = await NodeServer.execute(
326 processId,
327 `http2ProxyCode.proxySessionCount()`
329 return parseInt(data) - initial_session_count;
331 async function proxy_session_to_origin_server_counter() {
332 let data = await NodeServer.execute(
333 processId,
334 `http2ProxyCode.proxySessionToOriginServersCount()`
336 return parseInt(data) - initial_session_count;
338 let processId;
339 add_task(async function setup() {
340 // Set to allow the cert presented by our H2 server
341 do_get_profile();
343 // The moz-http2 cert is for foo.example.com and is signed by http2-ca.pem
344 // so add that cert to the trust list as a signing cert.
345 let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
346 Ci.nsIX509CertDB
348 addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u");
350 let server_port = Services.env.get("MOZHTTP2_PORT");
351 Assert.notEqual(server_port, null);
352 processId = await NodeServer.fork();
353 await NodeServer.execute(processId, `serverPort = ${server_port}`);
354 await NodeServer.execute(processId, http2ProxyCode);
355 let newProxy = await NodeServer.execute(
356 processId,
357 `http2ProxyCode.startNewProxy()`
359 proxy_port = newProxy.port;
360 Assert.notEqual(proxy_port, null);
362 Services.prefs.setStringPref(
363 "services.settings.server",
364 `data:,#remote-settings-dummy/v1`
367 Services.prefs.setBoolPref("network.http.http2.enabled", true);
369 // Even with network state isolation active, we don't end up using the
370 // partitioned principal.
371 Services.prefs.setBoolPref("privacy.partition.network_state", true);
373 // make all native resolve calls "secretly" resolve localhost instead
374 Services.prefs.setBoolPref("network.dns.native-is-localhost", true);
376 filter = new ProxyFilter("https", "localhost", proxy_port, 0);
377 pps.registerFilter(filter, 10);
379 initial_session_count = await proxy_session_counter();
380 info(`Initial proxy session count = ${initial_session_count}`);
383 registerCleanupFunction(async () => {
384 Services.prefs.clearUserPref("services.settings.server");
385 Services.prefs.clearUserPref("network.http.http2.enabled");
386 Services.prefs.clearUserPref("network.dns.native-is-localhost");
388 pps.unregisterFilter(filter);
390 await NodeServer.execute(processId, `http2ProxyCode.closeProxy()`);
391 await NodeServer.kill(processId);
395 * Test series beginning.
398 // Check we reach the h2 end server and keep only one session with the proxy for two different origin.
399 // Here we use the first isolation token.
400 add_task(async function proxy_success_one_session() {
401 proxy_isolation = "TOKEN1";
403 const foo = await get_response(
404 make_channel(`https://foo.example.com/random-request-1`)
406 const alt1 = await get_response(
407 make_channel(`https://alt1.example.com/random-request-2`)
410 Assert.equal(foo.status, Cr.NS_OK);
411 Assert.equal(foo.proxy_connect_response_code, 200);
412 Assert.equal(foo.http_code, 200);
413 Assert.ok(foo.data.match("random-request-1"));
414 Assert.ok(foo.data.match("You Win!"));
415 Assert.equal(alt1.status, Cr.NS_OK);
416 Assert.equal(alt1.proxy_connect_response_code, 200);
417 Assert.equal(alt1.http_code, 200);
418 Assert.ok(alt1.data.match("random-request-2"));
419 Assert.ok(alt1.data.match("You Win!"));
420 Assert.equal(
421 await proxy_session_counter(),
423 "Created just one session with the proxy"
427 // The proxy responses with 407 instead of 200 Connected, make sure we get a proper error
428 // code from the channel and not try to ask for any credentials.
429 add_task(async function proxy_auth_failure() {
430 const chan = make_channel(`https://407.example.com/`);
431 const auth_prompt = { triggered: false };
432 chan.notificationCallbacks = new AuthRequestor(
433 () => new UnxpectedAuthPrompt2(auth_prompt)
435 const { status, http_code, proxy_connect_response_code } = await get_response(
436 chan,
437 CL_EXPECT_FAILURE
440 Assert.equal(status, Cr.NS_ERROR_PROXY_AUTHENTICATION_FAILED);
441 Assert.equal(proxy_connect_response_code, 407);
442 Assert.equal(http_code, undefined);
443 Assert.equal(auth_prompt.triggered, false, "Auth prompt didn't trigger");
444 Assert.equal(
445 await proxy_session_counter(),
447 "No new session created by 407"
451 // The proxy responses with 407 with Proxy-Authenticate header presence. Make
452 // sure that we prompt the auth prompt to ask for credentials.
453 add_task(async function proxy_auth_basic() {
454 const chan = make_channel(`https://407.basic.example.com/`);
455 const auth_prompt = { triggered: false };
456 chan.notificationCallbacks = new AuthRequestor(
457 () => new SimpleAuthPrompt2(auth_prompt)
459 const { status, http_code, proxy_connect_response_code } = await get_response(
460 chan,
461 CL_EXPECT_FAILURE
464 // 418 indicates we pass the basic authentication.
465 Assert.equal(status, Cr.NS_ERROR_PROXY_CONNECTION_REFUSED);
466 Assert.equal(proxy_connect_response_code, 418);
467 Assert.equal(http_code, undefined);
468 Assert.equal(auth_prompt.triggered, true, "Auth prompt should trigger");
469 Assert.equal(
470 await proxy_session_counter(),
472 "No new session created by 407"
476 // 502 Bad gateway code returned by the proxy, still one session only, proper different code
477 // from the channel.
478 add_task(async function proxy_bad_gateway_failure() {
479 const { status, http_code, proxy_connect_response_code } = await get_response(
480 make_channel(`https://502.example.com/`),
481 CL_EXPECT_FAILURE
484 Assert.equal(status, Cr.NS_ERROR_PROXY_BAD_GATEWAY);
485 Assert.equal(proxy_connect_response_code, 502);
486 Assert.equal(http_code, undefined);
487 Assert.equal(
488 await proxy_session_counter(),
490 "No new session created by 502 after 407"
494 // Second 502 Bad gateway code returned by the proxy, still one session only with the proxy.
495 add_task(async function proxy_bad_gateway_failure_two() {
496 const { status, http_code, proxy_connect_response_code } = await get_response(
497 make_channel(`https://502.example.com/`),
498 CL_EXPECT_FAILURE
501 Assert.equal(status, Cr.NS_ERROR_PROXY_BAD_GATEWAY);
502 Assert.equal(proxy_connect_response_code, 502);
503 Assert.equal(http_code, undefined);
504 Assert.equal(
505 await proxy_session_counter(),
507 "No new session created by second 502"
511 // 504 Gateway timeout code returned by the proxy, still one session only, proper different code
512 // from the channel.
513 add_task(async function proxy_gateway_timeout_failure() {
514 const { status, http_code, proxy_connect_response_code } = await get_response(
515 make_channel(`https://504.example.com/`),
516 CL_EXPECT_FAILURE
519 Assert.equal(status, Cr.NS_ERROR_PROXY_GATEWAY_TIMEOUT);
520 Assert.equal(proxy_connect_response_code, 504);
521 Assert.equal(http_code, undefined);
522 Assert.equal(
523 await proxy_session_counter(),
525 "No new session created by 504 after 502"
529 // 404 Not Found means the proxy could not resolve the host. As for other error responses
530 // we still expect this not to close the existing session.
531 add_task(async function proxy_host_not_found_failure() {
532 const { status, http_code, proxy_connect_response_code } = await get_response(
533 make_channel(`https://404.example.com/`),
534 CL_EXPECT_FAILURE
537 Assert.equal(status, Cr.NS_ERROR_UNKNOWN_HOST);
538 Assert.equal(proxy_connect_response_code, 404);
539 Assert.equal(http_code, undefined);
540 Assert.equal(
541 await proxy_session_counter(),
543 "No new session created by 404 after 504"
547 add_task(async function proxy_too_many_requests_failure() {
548 const { status, http_code, proxy_connect_response_code } = await get_response(
549 make_channel(`https://429.example.com/`),
550 CL_EXPECT_FAILURE
553 Assert.equal(status, Cr.NS_ERROR_PROXY_TOO_MANY_REQUESTS);
554 Assert.equal(proxy_connect_response_code, 429);
555 Assert.equal(http_code, undefined);
556 Assert.equal(
557 await proxy_session_counter(),
559 "No new session created by 429 after 504"
563 add_task(async function proxy_stream_reset_failure() {
564 const { status, http_code, proxy_connect_response_code } = await get_response(
565 make_channel(`https://reset.example.com/`),
566 CL_EXPECT_FAILURE
569 Assert.equal(status, Cr.NS_ERROR_NET_INTERRUPT);
570 Assert.equal(proxy_connect_response_code, 0);
571 Assert.equal(http_code, undefined);
572 Assert.equal(
573 await proxy_session_counter(),
575 "No new session created by 429 after 504"
579 // The soft errors are not closing the session.
580 add_task(async function origin_server_stream_soft_failure() {
581 var current_num_sessions_to_origin_server =
582 await proxy_session_to_origin_server_counter();
584 const { status, http_code, proxy_connect_response_code } = await get_response(
585 make_channel(`https://foo.example.com/illegalhpacksoft`),
586 CL_EXPECT_FAILURE
589 Assert.equal(status, Cr.NS_ERROR_ILLEGAL_VALUE);
590 Assert.equal(proxy_connect_response_code, 200);
591 Assert.equal(http_code, undefined);
592 Assert.equal(
593 await proxy_session_counter(),
595 "No session to the proxy closed by soft stream errors"
597 Assert.equal(
598 await proxy_session_to_origin_server_counter(),
599 current_num_sessions_to_origin_server,
600 "No session to the origin server closed by soft stream errors"
604 // The soft errors are not closing the session.
605 add_task(
606 async function origin_server_stream_soft_failure_multiple_streams_not_affected() {
607 var current_num_sessions_to_origin_server =
608 await proxy_session_to_origin_server_counter();
610 let should_succeed = get_response(
611 make_channel(`https://foo.example.com/750ms`)
614 const failed = await get_response(
615 make_channel(`https://foo.example.com/illegalhpacksoft`),
616 CL_EXPECT_FAILURE,
620 const succeeded = await should_succeed;
622 Assert.equal(failed.status, Cr.NS_ERROR_ILLEGAL_VALUE);
623 Assert.equal(failed.proxy_connect_response_code, 200);
624 Assert.equal(failed.http_code, undefined);
625 Assert.equal(succeeded.status, Cr.NS_OK);
626 Assert.equal(succeeded.proxy_connect_response_code, 200);
627 Assert.equal(succeeded.http_code, 200);
628 Assert.equal(
629 await proxy_session_counter(),
631 "No session to the proxy closed by soft stream errors"
633 Assert.equal(
634 await proxy_session_to_origin_server_counter(),
635 current_num_sessions_to_origin_server,
636 "No session to the origin server closed by soft stream errors"
641 // Make sure that the above error codes don't kill the session to the proxy.
642 add_task(async function proxy_success_still_one_session() {
643 const foo = await get_response(
644 make_channel(`https://foo.example.com/random-request-1`)
646 const alt1 = await get_response(
647 make_channel(`https://alt1.example.com/random-request-2`)
650 Assert.equal(foo.status, Cr.NS_OK);
651 Assert.equal(foo.http_code, 200);
652 Assert.equal(foo.proxy_connect_response_code, 200);
653 Assert.ok(foo.data.match("random-request-1"));
654 Assert.equal(alt1.status, Cr.NS_OK);
655 Assert.equal(alt1.proxy_connect_response_code, 200);
656 Assert.equal(alt1.http_code, 200);
657 Assert.ok(alt1.data.match("random-request-2"));
658 Assert.equal(
659 await proxy_session_counter(),
661 "No new session to the proxy created after stream error codes"
665 // Have a new isolation key, this means we are expected to create a new, and again one only,
666 // session with the proxy to reach the end server.
667 add_task(async function proxy_success_isolated_session() {
668 Assert.notEqual(proxy_isolation, "TOKEN2");
669 proxy_isolation = "TOKEN2";
671 const foo = await get_response(
672 make_channel(`https://foo.example.com/random-request-1`)
674 const alt1 = await get_response(
675 make_channel(`https://alt1.example.com/random-request-2`)
677 const lh = await get_response(
678 make_channel(`https://localhost/random-request-3`)
681 Assert.equal(foo.status, Cr.NS_OK);
682 Assert.equal(foo.proxy_connect_response_code, 200);
683 Assert.equal(foo.http_code, 200);
684 Assert.ok(foo.data.match("random-request-1"));
685 Assert.ok(foo.data.match("You Win!"));
686 Assert.equal(alt1.status, Cr.NS_OK);
687 Assert.equal(alt1.proxy_connect_response_code, 200);
688 Assert.equal(alt1.http_code, 200);
689 Assert.ok(alt1.data.match("random-request-2"));
690 Assert.ok(alt1.data.match("You Win!"));
691 Assert.equal(lh.status, Cr.NS_OK);
692 Assert.equal(lh.proxy_connect_response_code, 200);
693 Assert.equal(lh.http_code, 200);
694 Assert.ok(lh.data.match("random-request-3"));
695 Assert.ok(lh.data.match("You Win!"));
696 Assert.equal(
697 await proxy_session_counter(),
699 "Just one new session seen after changing the isolation key"
703 // Check that error codes are still handled the same way with new isolation, just in case.
704 add_task(async function proxy_bad_gateway_failure_isolated() {
705 const failure1 = await get_response(
706 make_channel(`https://502.example.com/`),
707 CL_EXPECT_FAILURE
709 const failure2 = await get_response(
710 make_channel(`https://502.example.com/`),
711 CL_EXPECT_FAILURE
714 Assert.equal(failure1.status, Cr.NS_ERROR_PROXY_BAD_GATEWAY);
715 Assert.equal(failure1.proxy_connect_response_code, 502);
716 Assert.equal(failure1.http_code, undefined);
717 Assert.equal(failure2.status, Cr.NS_ERROR_PROXY_BAD_GATEWAY);
718 Assert.equal(failure2.proxy_connect_response_code, 502);
719 Assert.equal(failure2.http_code, undefined);
720 Assert.equal(
721 await proxy_session_counter(),
723 "No new session created by 502"
727 add_task(async function proxy_success_check_number_of_session() {
728 const foo = await get_response(
729 make_channel(`https://foo.example.com/random-request-1`)
731 const alt1 = await get_response(
732 make_channel(`https://alt1.example.com/random-request-2`)
734 const lh = await get_response(
735 make_channel(`https://localhost/random-request-3`)
738 Assert.equal(foo.status, Cr.NS_OK);
739 Assert.equal(foo.proxy_connect_response_code, 200);
740 Assert.equal(foo.http_code, 200);
741 Assert.ok(foo.data.match("random-request-1"));
742 Assert.ok(foo.data.match("You Win!"));
743 Assert.equal(alt1.status, Cr.NS_OK);
744 Assert.equal(alt1.proxy_connect_response_code, 200);
745 Assert.equal(alt1.http_code, 200);
746 Assert.ok(alt1.data.match("random-request-2"));
747 Assert.ok(alt1.data.match("You Win!"));
748 Assert.equal(lh.status, Cr.NS_OK);
749 Assert.equal(lh.proxy_connect_response_code, 200);
750 Assert.equal(lh.http_code, 200);
751 Assert.ok(lh.data.match("random-request-3"));
752 Assert.ok(lh.data.match("You Win!"));
753 Assert.equal(
754 await proxy_session_counter(),
756 "The number of sessions has not changed"
760 // The hard errors are closing the session.
761 add_task(async function origin_server_stream_hard_failure() {
762 var current_num_sessions_to_origin_server =
763 await proxy_session_to_origin_server_counter();
764 const { status, http_code, proxy_connect_response_code } = await get_response(
765 make_channel(`https://foo.example.com/illegalhpackhard`),
766 CL_EXPECT_FAILURE
769 Assert.equal(status, 0x804b0053);
770 Assert.equal(proxy_connect_response_code, 200);
771 Assert.equal(http_code, undefined);
772 Assert.equal(
773 await proxy_session_counter(),
775 "No new session to the proxy."
777 Assert.equal(
778 await proxy_session_to_origin_server_counter(),
779 current_num_sessions_to_origin_server,
780 "No new session to the origin server yet."
783 // Check the a new session ill be opened.
784 const foo = await get_response(
785 make_channel(`https://foo.example.com/random-request-1`)
788 Assert.equal(foo.status, Cr.NS_OK);
789 Assert.equal(foo.proxy_connect_response_code, 200);
790 Assert.equal(foo.http_code, 200);
791 Assert.ok(foo.data.match("random-request-1"));
792 Assert.ok(foo.data.match("You Win!"));
794 Assert.equal(
795 await proxy_session_counter(),
797 "No new session to the proxy is created after a hard stream failure on the session to the origin server."
799 Assert.equal(
800 await proxy_session_to_origin_server_counter(),
801 current_num_sessions_to_origin_server + 1,
802 "A new session to the origin server after a hard stream error"
806 // The hard errors are closing the session.
807 add_task(
808 async function origin_server_stream_hard_failure_multiple_streams_affected() {
809 var current_num_sessions_to_origin_server =
810 await proxy_session_to_origin_server_counter();
811 let should_fail = get_response(
812 make_channel(`https://foo.example.com/750msNoData`),
813 CL_EXPECT_FAILURE
815 const failed1 = await get_response(
816 make_channel(`https://foo.example.com/illegalhpackhard`),
817 CL_EXPECT_FAILURE,
821 const failed2 = await should_fail;
823 Assert.equal(failed1.status, 0x804b0053);
824 Assert.equal(failed1.proxy_connect_response_code, 200);
825 Assert.equal(failed1.http_code, undefined);
826 Assert.equal(failed2.status, 0x804b0053);
827 Assert.equal(failed2.proxy_connect_response_code, 200);
828 Assert.equal(failed2.http_code, undefined);
829 Assert.equal(
830 await proxy_session_counter(),
832 "No new session to the proxy"
834 Assert.equal(
835 await proxy_session_to_origin_server_counter(),
836 current_num_sessions_to_origin_server,
837 "No session to the origin server yet."
839 // Check the a new session ill be opened.
840 const foo = await get_response(
841 make_channel(`https://foo.example.com/random-request-1`)
844 Assert.equal(foo.status, Cr.NS_OK);
845 Assert.equal(foo.proxy_connect_response_code, 200);
846 Assert.equal(foo.http_code, 200);
847 Assert.ok(foo.data.match("random-request-1"));
848 Assert.ok(foo.data.match("You Win!"));
850 Assert.equal(
851 await proxy_session_counter(),
853 "No new session to the proxy is created after a hard stream failure on the session to the origin server."
856 Assert.equal(
857 await proxy_session_to_origin_server_counter(),
858 current_num_sessions_to_origin_server + 1,
859 "A new session to the origin server after a hard stream error"