/**
* Test for the "CacheEntryId" under several cases.
*/
"use strict";
const { HttpServer } = ChromeUtils.importESModule(
"resource://testing-common/httpd.sys.mjs"
);
ChromeUtils.defineLazyGetter(
this,
"URL",
function () {
return "http://localhost:" + httpServer.identity.primaryPort + "/content";
});
var httpServer =
null;
const responseContent =
"response body";
const responseContent2 =
"response body 2";
const altContent =
"!@#$%^&*()";
const altContentType =
"text/binary";
function isParentProcess() {
let appInfo = Cc[
"@mozilla.org/xre/app-info;1"];
return (
!appInfo ||
Services.appinfo.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT
);
}
var handlers = [
(m, r) => {
r.bodyOutputStream.write(responseContent, responseContent.length);
},
(m, r) => {
r.setStatusLine(m.httpVersion, 304,
"Not Modified");
},
(m, r) => {
r.setStatusLine(m.httpVersion, 304,
"Not Modified");
},
(m, r) => {
r.setStatusLine(m.httpVersion, 304,
"Not Modified");
},
(m, r) => {
r.setStatusLine(m.httpVersion, 304,
"Not Modified");
},
(m, r) => {
r.bodyOutputStream.write(responseContent2, responseContent2.length);
},
(m, r) => {
r.setStatusLine(m.httpVersion, 304,
"Not Modified");
},
];
function contentHandler(metadata, response) {
response.setHeader(
"Content-Type",
"text/plain");
response.setHeader(
"Cache-Control",
"no-cache");
var handler = handlers.shift();
if (handler) {
handler(metadata, response);
return;
}
Assert.ok(
false,
"Should not reach here.");
}
function fetch(preferredDataType =
null) {
return new Promise(resolve => {
var chan = NetUtil.newChannel({ uri: URL, loadUsingSystemPrincipal:
true });
if (preferredDataType) {
var cc = chan.QueryInterface(Ci.nsICacheInfoChannel);
cc.preferAlternativeDataType(
altContentType,
"",
Ci.nsICacheInfoChannel.ASYNC
);
}
chan.asyncOpen(
new ChannelListener((request, buffer, ctx, isFromCache, cacheEntryId) => {
resolve({ request, buffer, isFromCache, cacheEntryId });
},
null)
);
});
}
function check(
response,
content,
preferredDataType,
isFromCache,
cacheEntryIdChecker
) {
var cc = response.request.QueryInterface(Ci.nsICacheInfoChannel);
Assert.equal(response.buffer, content);
Assert.equal(cc.alternativeDataType, preferredDataType);
Assert.equal(response.isFromCache, isFromCache);
Assert.ok(!cacheEntryIdChecker || cacheEntryIdChecker(response.cacheEntryId));
return response;
}
function writeAltData(request) {
var cc = request.QueryInterface(Ci.nsICacheInfoChannel);
var os = cc.openAlternativeOutputStream(altContentType, altContent.length);
os.write(altContent, altContent.length);
os.close();
gc();
// We need to do a GC pass to ensure the cache entry has been freed.
return new Promise(resolve => {
if (isParentProcess()) {
Services.cache2.QueryInterface(Ci.nsICacheTesting).flush(resolve);
}
else {
do_send_remote_message(
"flush");
do_await_remote_message(
"flushed").then(resolve);
}
});
}
function run_test() {
do_get_profile();
httpServer =
new HttpServer();
httpServer.registerPathHandler(
"/content", contentHandler);
httpServer.start(-1);
do_test_pending();
var targetCacheEntryId =
null;
return (
Promise.resolve()
// Setup testing environment: Placing alternative data into HTTP cache.
.then(_ => fetch(altContentType))
.then(r =>
check(
r,
responseContent,
"",
false,
cacheEntryId => cacheEntryId === undefined
)
)
.then(r => writeAltData(r.request))
// Start testing.
.then(_ => fetch(altContentType))
.then(r =>
check(
r,
altContent,
altContentType,
true,
cacheEntryId => cacheEntryId !== undefined
)
)
.then(r => (targetCacheEntryId = r.cacheEntryId))
.then(_ => fetch())
.then(r =>
check(
r,
responseContent,
"",
true,
cacheEntryId => cacheEntryId === targetCacheEntryId
)
)
.then(_ => fetch(altContentType))
.then(r =>
check(
r,
altContent,
altContentType,
true,
cacheEntryId => cacheEntryId === targetCacheEntryId
)
)
.then(_ => fetch())
.then(r =>
check(
r,
responseContent,
"",
true,
cacheEntryId => cacheEntryId === targetCacheEntryId
)
)
.then(_ => fetch())
// The response is changed here.
.then(r =>
check(
r,
responseContent2,
"",
false,
cacheEntryId => cacheEntryId === undefined
)
)
.then(_ => fetch())
.then(r =>
check(
r,
responseContent2,
"",
true,
cacheEntryId =>
cacheEntryId !== undefined && cacheEntryId !== targetCacheEntryId
)
)
// Tear down.
.
catch(e =>
Assert.ok(
false,
"Unexpected exception: " + e))
.then(_ =>
Assert.equal(handlers.length, 0))
.then(_ => httpServer.stop(do_test_finished))
);
}