3 const { HttpServer
} = ChromeUtils
.importESModule(
4 "resource://testing-common/httpd.sys.mjs"
9 // https://foo.example.com:(h3Port)
10 // https://bar.example.com:(h3Port) <- invalid for bar, but ok for foo
11 var h1Foo
; // server http://foo.example.com:(h1Foo.identity.primaryPort)
12 var h1Bar
; // server http://bar.example.com:(h1bar.identity.primaryPort)
14 var otherServer
; // server socket listening for other connection.
16 var h3FooRoute
; // foo.example.com:H3PORT
17 var h3BarRoute
; // bar.example.com:H3PORT
18 var h3Route
; // :H3PORT
19 var httpFooOrigin
; // http://foo.exmaple.com:PORT/
20 var httpsFooOrigin
; // https://foo.exmaple.com:PORT/
21 var httpBarOrigin
; // http://bar.example.com:PORT/
22 var httpsBarOrigin
; // https://bar.example.com:PORT/
25 h3Port
= Services
.env
.get("MOZHTTP3_PORT");
26 Assert
.notEqual(h3Port
, null);
27 Assert
.notEqual(h3Port
, "");
29 // Set to allow the cert presented by our H3 server
32 Services
.prefs
.setBoolPref("network.http.http3.enable", true);
33 Services
.prefs
.setBoolPref("network.http.altsvc.enabled", true);
34 Services
.prefs
.setBoolPref("network.http.altsvc.oe", true);
35 Services
.prefs
.setCharPref(
36 "network.dns.localDomains",
37 "foo.example.com, bar.example.com"
40 // The moz-http2 cert is for foo.example.com and is signed by http2-ca.pem
41 // so add that cert to the trust list as a signing cert. The same cert is used
42 // for both h3FooRoute and h3BarRoute though it is only valid for
43 // the foo.example.com domain name.
44 let certdb
= Cc
["@mozilla.org/security/x509certdb;1"].getService(
47 addCertFromFile(certdb
, "http2-ca.pem", "CTu,u,u");
49 h1Foo
= new HttpServer();
50 h1Foo
.registerPathHandler("/altsvc-test", h1Server
);
51 h1Foo
.registerPathHandler("/.well-known/http-opportunistic", h1ServerWK
);
53 h1Foo
.identity
.setPrimary(
56 h1Foo
.identity
.primaryPort
59 h1Bar
= new HttpServer();
60 h1Bar
.registerPathHandler("/altsvc-test", h1Server
);
62 h1Bar
.identity
.setPrimary(
65 h1Bar
.identity
.primaryPort
68 h3FooRoute
= "foo.example.com:" + h3Port
;
69 h3BarRoute
= "bar.example.com:" + h3Port
;
70 h3Route
= ":" + h3Port
;
72 httpFooOrigin
= "http://foo.example.com:" + h1Foo
.identity
.primaryPort
+ "/";
73 httpsFooOrigin
= "https://" + h3FooRoute
+ "/";
74 httpBarOrigin
= "http://bar.example.com:" + h1Bar
.identity
.primaryPort
+ "/";
75 httpsBarOrigin
= "https://" + h3BarRoute
+ "/";
94 function h1Server(metadata
, response
) {
95 response
.setStatusLine(metadata
.httpVersion
, 200, "OK");
96 response
.setHeader("Content-Type", "text/plain", false);
97 response
.setHeader("Connection", "close", false);
98 response
.setHeader("Cache-Control", "no-cache", false);
99 response
.setHeader("Access-Control-Allow-Origin", "*", false);
100 response
.setHeader("Access-Control-Allow-Method", "GET", false);
101 response
.setHeader("Access-Control-Allow-Headers", "x-altsvc", false);
104 var hval
= "h3-29=" + metadata
.getHeader("x-altsvc");
105 response
.setHeader("Alt-Svc", hval
, false);
108 var body
= "Q: What did 0 say to 8? A: Nice Belt!\n";
109 response
.bodyOutputStream
.write(body
, body
.length
);
112 function h1ServerWK(metadata
, response
) {
113 response
.setStatusLine(metadata
.httpVersion
, 200, "OK");
114 response
.setHeader("Content-Type", "application/json", false);
115 response
.setHeader("Connection", "close", false);
116 response
.setHeader("Cache-Control", "no-cache", false);
117 response
.setHeader("Access-Control-Allow-Origin", "*", false);
118 response
.setHeader("Access-Control-Allow-Method", "GET", false);
119 response
.setHeader("Access-Control-Allow-Headers", "x-altsvc", false);
121 var body
= '["http://foo.example.com:' + h1Foo
.identity
.primaryPort
+ '"]';
122 response
.bodyOutputStream
.write(body
, body
.length
);
125 function resetPrefs() {
126 Services
.prefs
.clearUserPref("network.http.http3.enable");
127 Services
.prefs
.clearUserPref("network.dns.localDomains");
128 Services
.prefs
.clearUserPref("network.http.altsvc.enabled");
129 Services
.prefs
.clearUserPref("network.http.altsvc.oe");
130 Services
.prefs
.clearUserPref("network.dns.localDomains");
131 Services
.prefs
.clearUserPref("network.security.ports.banned");
134 function makeChan(origin
) {
135 return NetUtil
.newChannel({
136 uri
: origin
+ "altsvc-test",
137 loadUsingSystemPrincipal
: true,
138 }).QueryInterface(Ci
.nsIHttpChannel
);
143 var loadWithoutClearingMappings
= false;
144 var disallowH3
= false;
145 var disallowH2
= false;
146 var testKeepAliveNotSet
= false;
148 var expectPass
= true;
150 var originAttributes
= {};
152 var Listener = function () {};
153 Listener
.prototype = {
154 onStartRequest
: function testOnStartRequest(request
) {
155 Assert
.ok(request
instanceof Ci
.nsIHttpChannel
);
158 if (!Components
.isSuccessCode(request
.status
)) {
160 "Channel should have a success code! (" + request
.status
+ ")"
163 Assert
.equal(request
.responseStatus
, 200);
165 Assert
.equal(Components
.isSuccessCode(request
.status
), false);
169 onDataAvailable
: function testOnDataAvailable(request
, stream
, off
, cnt
) {
170 read_stream(stream
, cnt
);
173 onStopRequest
: function testOnStopRequest(request
, status
) {
176 routed
= request
.getRequestHeader("Alt-Used");
178 dump("routed is " + routed
+ "\n");
179 Assert
.equal(Components
.isSuccessCode(status
), expectPass
);
182 Assert
.equal(routed
, "");
184 loadWithoutClearingMappings
= true;
185 do_timeout(waitFor
, doTest
);
188 } else if (xaltsvc
== "NA") {
189 Assert
.equal(routed
, "");
191 } else if (routed
== xaltsvc
) {
192 Assert
.equal(routed
, xaltsvc
); // always true, but a useful log
195 dump("poll later for alt svc mapping\n");
197 loadWithoutClearingMappings
= true;
198 do_timeout(500, doTest
);
205 function testsDone() {
211 h1Foo
.stop(do_test_finished
);
213 h1Bar
.stop(do_test_finished
);
217 dump("execute doTest " + origin
+ "\n");
218 var chan
= makeChan(origin
);
219 var listener
= new Listener();
220 if (xaltsvc
!= "NA") {
221 chan
.setRequestHeader("x-altsvc", xaltsvc
, false);
223 if (testKeepAliveNotSet
) {
224 chan
.setRequestHeader("Connection", "close", false);
225 testKeepAliveNotSet
= false;
227 if (loadWithoutClearingMappings
) {
228 chan
.loadFlags
= Ci
.nsIChannel
.LOAD_INITIAL_DOCUMENT_URI
;
231 Ci
.nsIRequest
.LOAD_FRESH_CONNECTION
|
232 Ci
.nsIChannel
.LOAD_INITIAL_DOCUMENT_URI
;
235 let internalChannel
= chan
.QueryInterface(Ci
.nsIHttpChannelInternal
);
236 internalChannel
.allowHttp3
= false;
240 let internalChannel
= chan
.QueryInterface(Ci
.nsIHttpChannelInternal
);
241 internalChannel
.allowSpdy
= false;
244 loadWithoutClearingMappings
= false;
245 chan
.loadInfo
.originAttributes
= originAttributes
;
246 chan
.asyncOpen(listener
);
249 // xaltsvc is overloaded to do two things..
250 // 1] it is sent in the x-altsvc request header, and the response uses the value in the Alt-Svc response header
251 // 2] the test polls until necko sets Alt-Used to that value (i.e. it uses that route)
253 // When xaltsvc is set to h3Route (i.e. :port with the implied hostname) it doesn't match the alt-used,
254 // which is always explicit, so it needs to be changed after the channel is created but before the
255 // listener is invoked
257 // http://foo served from h3-29=:port
260 origin
= httpFooOrigin
;
265 xaltsvc
= h3FooRoute
;
268 // http://foo served from h3-29=foo:port
271 origin
= httpFooOrigin
;
272 xaltsvc
= h3FooRoute
;
278 // http://foo served from h3-29=bar:port
279 // requires cert for foo
282 origin
= httpFooOrigin
;
283 xaltsvc
= h3BarRoute
;
289 // https://bar should fail because host bar has cert for foo
292 origin
= httpsBarOrigin
;
300 // http://bar via h3 on bar
301 // should not use TLS/h3 because h3BarRoute is not auth'd for bar
302 // however the test ought to PASS (i.e. get a 200) because fallback
303 // to plaintext happens.. thus the timeout
306 origin
= httpBarOrigin
;
307 xaltsvc
= h3BarRoute
;
315 // http://bar served from h3-29=:port, which is like the bar route in 8
318 origin
= httpBarOrigin
;
325 xaltsvc
= h3BarRoute
;
328 // check again https://bar should fail because host bar has cert for foo
331 origin
= httpsBarOrigin
;
339 // http://bar served from h3-29=foo, should fail because host foo only has
340 // cert for foo. Fail in this case means alt-svc is not used, but content
344 origin
= httpBarOrigin
;
345 xaltsvc
= h3FooRoute
;
354 // Insert a cache of http://foo served from h3-29=:port with origin attributes.
357 origin
= httpFooOrigin
;
361 firstPartyDomain
: "a.com",
366 xaltsvc
= h3FooRoute
;
369 // Make sure we get a cache miss with a different userContextId.
370 function doTest10() {
371 dump("doTest10()\n");
372 origin
= httpFooOrigin
;
376 firstPartyDomain
: "a.com",
378 loadWithoutClearingMappings
= true;
384 // Make sure we get a cache miss with a different firstPartyDomain.
385 function doTest11() {
386 dump("doTest11()\n");
387 origin
= httpFooOrigin
;
391 firstPartyDomain
: "b.com",
393 loadWithoutClearingMappings
= true;
399 // Make sure we get a cache hit with the same origin attributes.
400 function doTest12() {
401 dump("doTest12()\n");
402 origin
= httpFooOrigin
;
406 firstPartyDomain
: "a.com",
408 loadWithoutClearingMappings
= true;
412 // This ensures a cache hit.
413 xaltsvc
= h3FooRoute
;
416 // Make sure we do not use H3 if it is disabled on a channel.
417 function doTest13() {
418 dump("doTest13()\n");
419 origin
= httpFooOrigin
;
424 firstPartyDomain
: "a.com",
426 loadWithoutClearingMappings
= true;
432 // Make sure we use H3 if only Http2 is disabled on a channel.
433 function doTest14() {
434 dump("doTest14()\n");
435 origin
= httpFooOrigin
;
440 firstPartyDomain
: "a.com",
442 loadWithoutClearingMappings
= true;
446 // This should ensures a cache hit.
447 xaltsvc
= h3FooRoute
;
450 // Make sure we do not use H3 if NS_HTTP_ALLOW_KEEPALIVE is not set.
451 function doTest15() {
452 dump("doTest15()\n");
453 origin
= httpFooOrigin
;
455 testKeepAliveNotSet
= true;
458 firstPartyDomain
: "a.com",
460 loadWithoutClearingMappings
= true;
466 // Check we don't connect to blocked ports
467 function doTest16() {
468 dump("doTest16()\n");
469 origin
= httpFooOrigin
;
470 nextTest
= testsDone
;
471 otherServer
= Cc
["@mozilla.org/network/server-socket;1"].createInstance(
474 otherServer
.init(-1, true, -1);
475 xaltsvc
= "localhost:" + otherServer
.port
;
476 Services
.prefs
.setCharPref(
477 "network.security.ports.banned",
478 "" + otherServer
.port
480 dump("Blocked port: " + otherServer
.port
);
482 otherServer
.asyncListen({
484 Assert
.ok(false, "Got connection to socket when we didn't expect it!");
487 // We get closed when the entire file is done, which guarantees we get the socket accept
488 // if we do connect to the alt-svc header