test_cache2_compression_dictionary.js (4157B)
1 /* 2 * Tests for cache2 Compression Dictionary support (draft-ietf-httpbis-compression-dictionary-19) 3 * - Storing dictionaries via Use-As-Dictionary 4 * - Using Available-Dictionary for decompression 5 */ 6 7 "use strict"; 8 9 // Load cache helpers 10 Services.scriptloader.loadSubScript("resource://test/head_cache.js", this); 11 12 const { NodeHTTPSServer } = ChromeUtils.importESModule( 13 "resource://testing-common/NodeServer.sys.mjs" 14 ); 15 16 var server = null; 17 // Keep these in sync with duplicates below! 18 const dictContent = "DICTIONARY_DATA"; 19 const decompressedContent = "COMPRESSED_DATA"; 20 const resourcePath = "/resource"; 21 const dictPath = "/dict"; 22 23 function makeChan(url) { 24 let chan = NetUtil.newChannel({ 25 uri: url, 26 loadUsingSystemPrincipal: true, 27 contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT, 28 }).QueryInterface(Ci.nsIHttpChannel); 29 return chan; 30 } 31 32 function channelOpenPromise(chan) { 33 return new Promise(resolve => { 34 function finish(req, buffer) { 35 resolve([req, buffer]); 36 } 37 chan.asyncOpen(new ChannelListener(finish, null, CL_ALLOW_UNKNOWN_CL)); 38 }); 39 } 40 41 // Serve a dictionary with Use-As-Dictionary header 42 function serveDictionary(request, response) { 43 // the server can't see the global versions of these. 44 // Note: keep in sync with above! 45 let dict = "dict1"; 46 const dictContent = "DICTIONARY_DATA"; 47 response.writeHead(200, { 48 "Content-Type": "application/octet-stream", 49 "Use-As-Dictionary": `match=\"*\", id=\"${dict}\", type=raw`, 50 "Cache-Control": "max-age=3600", 51 }); 52 response.end(dictContent, "binary"); 53 } 54 55 // Serve a resource with Available-Dictionary header 56 function serveCompressedResource(request, response) { 57 // brotli compressed data is 4 byte magic + 32-byte SHA-256 hash (which we 58 // don't check) 59 const compressedContent = 60 "\xff\x44\x43\x42" + 61 "12345678901234567890123456789012" + 62 "\x21\x38\x00\x04COMPRESSED_DATA\x03"; 63 let availDict = request.headers["available-dictionary"]; 64 if (availDict != undefined) { 65 response.writeHead(200, { 66 "Content-Type": "application/octet-stream", 67 "Content-Encoding": "dcb", 68 }); 69 response.end(compressedContent, "binary"); 70 } else { 71 response.writeHead(200, { 72 "Content-Type": "application/octet-stream", 73 }); 74 response.end("UNCOMPRESSED_DATA", "binary"); 75 } 76 } 77 78 add_setup(async function () { 79 Services.prefs.setBoolPref("network.http.dictionaries.enable", true); 80 if (!server) { 81 server = new NodeHTTPSServer(); 82 await server.start(); 83 registerCleanupFunction(async () => { 84 await server.stop(); 85 }); 86 87 await server.registerPathHandler(dictPath, serveDictionary); 88 await server.registerPathHandler(resourcePath, serveCompressedResource); 89 } 90 }); 91 92 add_task(async function test_resource_without_dictionary() { 93 let uri = `${server.origin()}${resourcePath}`; 94 let chan = makeChan(uri); 95 let [, data] = await channelOpenPromise(chan); 96 Assert.equal(data, "UNCOMPRESSED_DATA", "Received uncompressed data"); 97 }); 98 99 add_task(async function test_store_dictionary() { 100 let uri = `${server.origin()}${dictPath}`; 101 let chan = makeChan(uri); 102 let [, data] = await channelOpenPromise(chan); 103 Assert.equal(data, dictContent, "Dictionary body matches"); 104 105 await new Promise(resolve => { 106 // Check that dictionary is stored in cache (disk) 107 let lci = Services.loadContextInfo.custom(false, { 108 partitionKey: `(https,localhost)`, 109 }); 110 asyncCheckCacheEntryPresence(uri, "disk", true, lci, resolve); 111 }); 112 }); 113 114 add_task(async function test_use_dictionary_for_resource() { 115 let uri = `${server.origin()}${resourcePath}`; 116 117 let chan = makeChan(uri); 118 let [req, data] = await channelOpenPromise(chan); 119 // Check for expected uncompressed content 120 Assert.strictEqual( 121 data, 122 decompressedContent, 123 "Received compressed data (decompression not supported in test)" 124 ); 125 // Check response headers 126 Assert.equal( 127 req.getResponseHeader("Content-Encoding"), 128 "", 129 "Content-Encoding dcb was removed" 130 ); 131 let availdict = req.getRequestHeader("available-dictionary"); 132 Assert.equal(availdict, ":iFRBfhN7ePMquH3Lmw/oL4xRkaa8QjW43JQO+04KA7I=:"); 133 });