2 * Test for the "alternative data stream" stored withing a cache entry.
4 * - we load a URL with preference for an alt data (check what we get is the raw data,
5 * since there was nothing previously cached)
6 * - we store the alt data along the channel (to the cache entry)
7 * - we flush the HTTP cache
8 * - we reload the same URL using a new channel, again prefering the alt data be loaded
9 * - this time the alt data must arive
14 const { HttpServer } = ChromeUtils.importESModule(
15 "resource://testing-common/httpd.sys.mjs"
18 ChromeUtils.defineLazyGetter(this, "URL", function () {
19 return "http://localhost:" + httpServer.identity.primaryPort + "/content";
22 var httpServer = null;
24 function make_channel(url, callback, ctx) {
25 return NetUtil.newChannel({ uri: url, loadUsingSystemPrincipal: true });
28 function inChildProcess() {
29 return Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
32 const responseContent = "response body";
33 const responseContent2 = "response body 2";
34 const altContent = "!@#$%^&*()";
35 const altContentType = "text/binary";
37 var servedNotModified = false;
38 var shouldPassRevalidation = true;
40 var cache_storage = null;
42 function contentHandler(metadata, response) {
43 response.setHeader("Content-Type", "text/plain");
44 response.setHeader("Cache-Control", "no-cache");
45 response.setHeader("ETag", "test-etag1");
49 etag = metadata.getHeader("If-None-Match");
54 if (etag == "test-etag1" && shouldPassRevalidation) {
55 response.setStatusLine(metadata.httpVersion, 304, "Not Modified");
56 servedNotModified = true;
58 var content = shouldPassRevalidation ? responseContent : responseContent2;
59 response.bodyOutputStream.write(content, content.length);
63 function check_has_alt_data_in_index(aHasAltData, callback) {
64 if (inChildProcess()) {
69 syncWithCacheIOThread(() => {
71 cache_storage.getCacheIndexEntryAttrs(createURI(URL), "", hasAltData, {});
72 Assert.equal(hasAltData.value, aHasAltData);
79 httpServer = new HttpServer();
80 httpServer.registerPathHandler("/content", contentHandler);
84 if (!inChildProcess()) {
85 cache_storage = getCacheStorage("disk");
86 wait_for_cache_index(asyncOpen);
92 function asyncOpen() {
93 var chan = make_channel(URL);
95 var cc = chan.QueryInterface(Ci.nsICacheInfoChannel);
96 cc.preferAlternativeDataType(
99 Ci.nsICacheInfoChannel.ASYNC
102 chan.asyncOpen(new ChannelListener(readServerContent, null));
105 function readServerContent(request, buffer) {
106 var cc = request.QueryInterface(Ci.nsICacheInfoChannel);
108 Assert.equal(buffer, responseContent);
109 Assert.equal(cc.alternativeDataType, "");
110 check_has_alt_data_in_index(false, () => {
112 var os = cc.openAlternativeOutputStream(
116 os.write(altContent, altContent.length);
119 executeSoon(flushAndOpenAltChannel);
124 // needs to be rooted
125 var cacheFlushObserver = (cacheFlushObserver = {
127 cacheFlushObserver = null;
132 function flushAndOpenAltChannel() {
133 // We need to do a GC pass to ensure the cache entry has been freed.
135 if (!inChildProcess()) {
137 .QueryInterface(Ci.nsICacheTesting)
138 .flush(cacheFlushObserver);
140 do_send_remote_message("flush");
141 do_await_remote_message("flushed").then(() => {
147 function openAltChannel() {
148 var chan = make_channel(URL);
149 var cc = chan.QueryInterface(Ci.nsICacheInfoChannel);
150 cc.preferAlternativeDataType(
153 Ci.nsICacheInfoChannel.ASYNC
155 cc.preferAlternativeDataType(
158 Ci.nsICacheInfoChannel.ASYNC
160 cc.preferAlternativeDataType("dummy2", "", Ci.nsICacheInfoChannel.ASYNC);
162 chan.asyncOpen(new ChannelListener(readAltContent, null));
165 function readAltContent(request, buffer) {
166 var cc = request.QueryInterface(Ci.nsICacheInfoChannel);
168 Assert.equal(servedNotModified, true);
169 Assert.equal(cc.alternativeDataType, altContentType);
170 Assert.equal(buffer, altContent);
171 check_has_alt_data_in_index(true, () => {
172 cc.getOriginalInputStream({
173 onInputStreamReady(aInputStream) {
174 executeSoon(() => readOriginalInputStream(aInputStream));
180 function readOriginalInputStream(aInputStream) {
181 // We expect the async stream length to match the expected content.
182 // If the test times out, it's probably because of this.
184 let originalData = read_stream(aInputStream, responseContent.length);
185 Assert.equal(originalData, responseContent);
188 equal(e.result, Cr.NS_BASE_STREAM_WOULD_BLOCK);
189 executeSoon(() => readOriginalInputStream(aInputStream));
193 function requestAgain() {
194 shouldPassRevalidation = false;
195 var chan = make_channel(URL);
196 var cc = chan.QueryInterface(Ci.nsICacheInfoChannel);
197 cc.preferAlternativeDataType(
200 Ci.nsICacheInfoChannel.ASYNC
202 chan.asyncOpen(new ChannelListener(readEmptyAltContent, null));
205 function readEmptyAltContent(request, buffer) {
206 var cc = request.QueryInterface(Ci.nsICacheInfoChannel);
208 // the cache is overwrite and the alt-data is reset
209 Assert.equal(cc.alternativeDataType, "");
210 Assert.equal(buffer, responseContent2);
211 check_has_alt_data_in_index(false, () => httpServer.stop(do_test_finished));