Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

/* Any copyright is dedicated to the Public Domain.
"use strict";
// A LOAD_FRESH_CONNECTION | LOAD_INITIAL_DOCUMENT_URI load must only reset
// the connections and Alt-Svc cache entries that share its origin attributes.
const { NodeHTTPServer } = ChromeUtils.importESModule(
);
const { TestUtils } = ChromeUtils.importESModule(
);
let server;
let h2Port;
const ORIGIN_HOST = "foo.example.com";
const ALT_HOST = "alt1.example.com";
add_setup(async function setup() {
do_get_profile();
h2Port = Services.env.get("MOZHTTP2_PORT");
Assert.notEqual(h2Port, null);
Assert.notEqual(h2Port, "");
Services.prefs.setBoolPref("network.http.altsvc.enabled", true);
Services.prefs.setCharPref(
"network.dns.localDomains",
`${ORIGIN_HOST},${ALT_HOST}`
);
registerCleanupFunction(() => {
Services.prefs.clearUserPref("network.http.altsvc.enabled");
Services.prefs.clearUserPref("network.dns.localDomains");
});
let certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
Ci.nsIX509CertDB
);
addCertFromFile(certdb, "http2-ca.pem", "CTu,u,u");
server = new NodeHTTPServer();
await server.start();
registerCleanupFunction(async () => {
await server.stop();
});
await server.registerPathHandler("/", (req, resp) => {
resp.setHeader("x-client-port", req.socket.remotePort);
resp.writeHead(200, { "Content-Type": "text/plain" });
resp.end("ok");
});
});
const FRESH_FLAGS =
Ci.nsIRequest.LOAD_FRESH_CONNECTION | Ci.nsIChannel.LOAD_INITIAL_DOCUMENT_URI;
function makeChan(uri, originAttributes) {
let chan = NetUtil.newChannel({
uri,
loadUsingSystemPrincipal: true,
}).QueryInterface(Ci.nsIHttpChannel);
chan.loadInfo.originAttributes = originAttributes;
return chan;
}
async function getClientPort(originAttributes, loadFlags = 0) {
let chan = makeChan(`http://localhost:${server.port()}/`, originAttributes);
chan.loadFlags = loadFlags;
let [req] = await new Promise(resolve => {
chan.asyncOpen(
new ChannelListener(
(request, buffer) => resolve([request, buffer]),
null,
CL_ALLOW_UNKNOWN_CL
)
);
});
Assert.equal(req.responseStatus, 200);
return parseInt(req.getResponseHeader("x-client-port"));
}
async function testFreshConnectionScoping(oa1, oa2) {
let port1 = await getClientPort(oa1);
Assert.equal(await getClientPort(oa1), port1, "Connection is reused");
let port2 = await getClientPort(oa2, FRESH_FLAGS);
Assert.notEqual(port2, port1, "Different OA uses a new connection");
Assert.equal(
await getClientPort(oa1),
port1,
"Fresh load with another OA keeps this OA's connection"
);
let port1Fresh = await getClientPort(oa1, FRESH_FLAGS);
Assert.notEqual(port1Fresh, port1, "Fresh load opens a new connection");
Assert.notEqual(
await getClientPort(oa1),
port1,
"Fresh load closed the old connection with the same OA"
);
}
add_task(async function test_fresh_connection_scoped_to_user_context_id() {
await testFreshConnectionScoping({ userContextId: 1 }, { userContextId: 2 });
});
add_task(async function test_fresh_connection_scoped_to_partition_key() {
await testFreshConnectionScoping(
{ partitionKey: "(https,example.com)" },
{ partitionKey: "(https,example.org)" }
);
});
async function loadAltSvcOrigin(originAttributes, path, loadFlags = 0) {
let chan = makeChan(
`https://${ORIGIN_HOST}:${h2Port}${path}`,
originAttributes
);
chan.loadFlags = loadFlags;
chan.setRequestHeader("x-altsvc", `${ALT_HOST}:${h2Port}`, false);
let [req] = await new Promise(resolve => {
chan.asyncOpen(
new ChannelListener(
(request, buffer) => resolve([request, buffer]),
null,
CL_ALLOW_UNKNOWN_CL
)
);
});
Assert.equal(req.responseStatus, 200);
}
function hasAltSvcMapping(originAttributes) {
let suffix = ChromeUtils.originAttributesToSuffix(originAttributes);
return Services.io
.getProtocolHandler("http")
.QueryInterface(Ci.nsIHttpProtocolHandler)
.altSvcCacheKeys.some(key =>
key.startsWith(`https:${ORIGIN_HOST}:${h2Port}:.:${suffix}:`)
);
}
async function testFreshConnectionScopingAltSvc(oa1, oa2) {
await loadAltSvcOrigin(oa1, "/altsvc-test");
await TestUtils.waitForCondition(
() => hasAltSvcMapping(oa1),
"Alt-Svc mapping was stored"
);
await loadAltSvcOrigin(oa2, "/altsvc-test", FRESH_FLAGS);
Assert.ok(
hasAltSvcMapping(oa1),
"Fresh load with different OA keeps first OA's Alt-Svc mapping"
);
await loadAltSvcOrigin(oa1, "/", FRESH_FLAGS);
Assert.ok(!hasAltSvcMapping(oa1), "Fresh load should remove Alt-Svc mapping");
}
add_task(
async function test_fresh_connection_altsvc_scoped_to_user_context_id() {
await testFreshConnectionScopingAltSvc(
{ userContextId: 1 },
{ userContextId: 2 }
);
}
);
add_task(async function test_fresh_connection_altsvc_scoped_to_partition_key() {
await testFreshConnectionScopingAltSvc(
{ partitionKey: "(https,example.com)" },
{ partitionKey: "(https,example.org)" }
);
});