Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
- Manifest: netwerk/test/unit/xpcshell.toml
/*
* Tests for cache2 Compression Dictionary support (draft-ietf-httpbis-compression-dictionary-19)
* - Storing dictionaries via Use-As-Dictionary
* - Using Available-Dictionary for decompression
*/
"use strict";
// Load cache helpers
const { NodeHTTPSServer } = ChromeUtils.importESModule(
);
var server = null;
// Keep these in sync with duplicates below!
const dictContent = "DICTIONARY_DATA";
const decompressedContent = "COMPRESSED_DATA";
const resourcePath = "/resource";
const dictPath = "/dict";
function makeChan(url) {
let chan = NetUtil.newChannel({
uri: url,
loadUsingSystemPrincipal: true,
contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT,
}).QueryInterface(Ci.nsIHttpChannel);
return chan;
}
function channelOpenPromise(chan) {
return new Promise(resolve => {
function finish(req, buffer) {
resolve([req, buffer]);
}
chan.asyncOpen(new ChannelListener(finish, null, CL_ALLOW_UNKNOWN_CL));
});
}
// Serve a dictionary with Use-As-Dictionary header
function serveDictionary(request, response) {
// the server can't see the global versions of these.
// Note: keep in sync with above!
let dict = "dict1";
const dictContent = "DICTIONARY_DATA";
response.writeHead(200, {
"Content-Type": "application/octet-stream",
"Use-As-Dictionary": `match=\"*\", id=\"${dict}\", type=raw`,
"Cache-Control": "max-age=3600",
});
response.end(dictContent, "binary");
}
// Serve a resource with Available-Dictionary header
function serveCompressedResource(request, response) {
// brotli compressed data is 4 byte magic + 32-byte SHA-256 hash (which we
// don't check)
const compressedContent =
"\xff\x44\x43\x42" +
"12345678901234567890123456789012" +
"\x21\x38\x00\x04COMPRESSED_DATA\x03";
let availDict = request.headers["available-dictionary"];
if (availDict != undefined) {
response.writeHead(200, {
"Content-Type": "application/octet-stream",
"Content-Encoding": "dcb",
});
response.end(compressedContent, "binary");
} else {
response.writeHead(200, {
"Content-Type": "application/octet-stream",
});
response.end("UNCOMPRESSED_DATA", "binary");
}
}
add_setup(async function () {
if (!server) {
server = new NodeHTTPSServer();
await server.start();
registerCleanupFunction(async () => {
await server.stop();
});
await server.registerPathHandler(dictPath, serveDictionary);
await server.registerPathHandler(resourcePath, serveCompressedResource);
}
});
add_task(async function test_resource_without_dictionary() {
let uri = `${server.origin()}${resourcePath}`;
let chan = makeChan(uri);
let [, data] = await channelOpenPromise(chan);
Assert.equal(data, "UNCOMPRESSED_DATA", "Received uncompressed data");
});
add_task(async function test_store_dictionary() {
let uri = `${server.origin()}${dictPath}`;
let chan = makeChan(uri);
let [, data] = await channelOpenPromise(chan);
Assert.equal(data, dictContent, "Dictionary body matches");
await new Promise(resolve => {
// Check that dictionary is stored in cache (disk)
let lci = Services.loadContextInfo.custom(false, {
partitionKey: `(https,localhost)`,
});
asyncCheckCacheEntryPresence(uri, "disk", true, lci, resolve);
});
});
add_task(async function test_use_dictionary_for_resource() {
let uri = `${server.origin()}${resourcePath}`;
let chan = makeChan(uri);
let [req, data] = await channelOpenPromise(chan);
// Check for expected uncompressed content
Assert.strictEqual(
data,
decompressedContent,
"Received compressed data (decompression not supported in test)"
);
// Check response headers
Assert.equal(
req.getResponseHeader("Content-Encoding"),
"",
"Content-Encoding dcb was removed"
);
let availdict = req.getRequestHeader("available-dictionary");
Assert.equal(availdict, ":iFRBfhN7ePMquH3Lmw/oL4xRkaa8QjW43JQO+04KA7I=:");
});