mirror of
https://github.com/servo/servo.git
synced 2025-08-05 05:30:08 +01:00
498 lines
21 KiB
HTML
498 lines
21 KiB
HTML
<!doctype html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>Request cache</title>
|
|
<meta name="help" href="https://fetch.spec.whatwg.org/#request">
|
|
<meta name="timeout" content="long">
|
|
<script src="/resources/testharness.js"></script>
|
|
<script src="/resources/testharnessreport.js"></script>
|
|
<script src="/common/utils.js"></script>
|
|
</head>
|
|
<body>
|
|
<script>
|
|
var now = new Date();
|
|
var tests = [
|
|
{
|
|
name: 'RequestCache "default" mode checks the cache for previously cached content and goes to the network for stale responses',
|
|
state: "stale",
|
|
request_cache: ["default", "default"],
|
|
expected_validation_headers: [false, true],
|
|
expected_no_cache_headers: [false, false],
|
|
},
|
|
{
|
|
name: 'RequestCache "default" mode checks the cache for previously cached content and avoids going to the network if a fresh response exists',
|
|
state: "fresh",
|
|
request_cache: ["default", "default"],
|
|
expected_validation_headers: [false],
|
|
expected_no_cache_headers: [false],
|
|
},
|
|
{
|
|
name: 'RequestCache "no-cache" mode revalidates stale responses found in the cache',
|
|
state: "stale",
|
|
request_cache: ["default", "no-cache"],
|
|
expected_validation_headers: [false, true],
|
|
expected_no_cache_headers: [false, false],
|
|
expected_max_age_headers: [false, true],
|
|
},
|
|
{
|
|
name: 'RequestCache "no-cache" mode revalidates fresh responses found in the cache',
|
|
state: "fresh",
|
|
request_cache: ["default", "no-cache"],
|
|
expected_validation_headers: [false, true],
|
|
expected_no_cache_headers: [false, false],
|
|
expected_max_age_headers: [false, true],
|
|
},
|
|
{
|
|
name: 'RequestCache "force-cache" mode checks the cache for previously cached content and avoid revalidation for stale responses',
|
|
state: "stale",
|
|
request_cache: ["default", "force-cache"],
|
|
expected_validation_headers: [false],
|
|
expected_no_cache_headers: [false],
|
|
},
|
|
{
|
|
name: 'RequestCache "force-cache" mode checks the cache for previously cached content and avoid revalidation for fresh responses',
|
|
state: "fresh",
|
|
request_cache: ["default", "force-cache"],
|
|
expected_validation_headers: [false],
|
|
expected_no_cache_headers: [false],
|
|
},
|
|
{
|
|
name: 'RequestCache "force-cache" mode checks the cache for previously cached content and goes to the network if a cached response is not found',
|
|
state: "stale",
|
|
request_cache: ["force-cache"],
|
|
expected_validation_headers: [false],
|
|
expected_no_cache_headers: [false],
|
|
},
|
|
{
|
|
name: 'RequestCache "force-cache" mode checks the cache for previously cached content and goes to the network if a cached response is not found',
|
|
state: "fresh",
|
|
request_cache: ["force-cache"],
|
|
expected_validation_headers: [false],
|
|
expected_no_cache_headers: [false],
|
|
},
|
|
{
|
|
name: 'RequestCache "force-cache" mode checks the cache for previously cached content and goes to the network if a cached response would vary',
|
|
state: "stale",
|
|
vary: "*",
|
|
request_cache: ["default", "force-cache"],
|
|
expected_validation_headers: [false, true],
|
|
expected_no_cache_headers: [false, false],
|
|
},
|
|
{
|
|
name: 'RequestCache "force-cache" mode checks the cache for previously cached content and goes to the network if a cached response would vary',
|
|
state: "fresh",
|
|
vary: "*",
|
|
request_cache: ["default", "force-cache"],
|
|
expected_validation_headers: [false, true],
|
|
expected_no_cache_headers: [false, false],
|
|
},
|
|
{
|
|
name: 'RequestCache "force-cache" stores the response in the cache if it goes to the network',
|
|
state: "stale",
|
|
request_cache: ["force-cache", "default"],
|
|
expected_validation_headers: [false, true],
|
|
expected_no_cache_headers: [false, false],
|
|
},
|
|
{
|
|
name: 'RequestCache "force-cache" stores the response in the cache if it goes to the network',
|
|
state: "fresh",
|
|
request_cache: ["force-cache", "default"],
|
|
expected_validation_headers: [false],
|
|
expected_no_cache_headers: [false],
|
|
},
|
|
{
|
|
name: 'RequestCache "no-store" mode does not check the cache for previously cached content and goes to the network regardless',
|
|
state: "stale",
|
|
request_cache: ["default", "no-store"],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [false, true],
|
|
},
|
|
{
|
|
name: 'RequestCache "no-store" mode does not check the cache for previously cached content and goes to the network regardless',
|
|
state: "fresh",
|
|
request_cache: ["default", "no-store"],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [false, true],
|
|
},
|
|
{
|
|
name: 'RequestCache "no-store" mode does not store the response in the cache',
|
|
state: "stale",
|
|
request_cache: ["no-store", "default"],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [true, false],
|
|
},
|
|
{
|
|
name: 'RequestCache "no-store" mode does not store the response in the cache',
|
|
state: "fresh",
|
|
request_cache: ["no-store", "default"],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [true, false],
|
|
},
|
|
{
|
|
name: 'RequestCache "default" mode with an If-Modified-Since header is treated similarly to "no-store"',
|
|
state: "stale",
|
|
request_cache: ["default", "default"],
|
|
request_headers: [{}, {"If-Modified-Since": now.toGMTString()}],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [false, true],
|
|
},
|
|
{
|
|
name: 'RequestCache "default" mode with an If-Modified-Since header is treated similarly to "no-store"',
|
|
state: "fresh",
|
|
request_cache: ["default", "default"],
|
|
request_headers: [{}, {"If-Modified-Since": now.toGMTString()}],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [false, true],
|
|
},
|
|
{
|
|
name: 'RequestCache "default" mode with an If-Modified-Since header is treated similarly to "no-store"',
|
|
state: "stale",
|
|
request_cache: ["default", "default"],
|
|
request_headers: [{"If-Modified-Since": now.toGMTString()}, {}],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [true, false],
|
|
},
|
|
{
|
|
name: 'RequestCache "default" mode with an If-Modified-Since header is treated similarly to "no-store"',
|
|
state: "fresh",
|
|
request_cache: ["default", "default"],
|
|
request_headers: [{"If-Modified-Since": now.toGMTString()}, {}],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [true, false],
|
|
},
|
|
{
|
|
name: 'RequestCache "default" mode with an If-None-Match header is treated similarly to "no-store"',
|
|
state: "stale",
|
|
request_cache: ["default", "default"],
|
|
request_headers: [{}, {"If-None-Match": '"foo"'}],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [false, true],
|
|
},
|
|
{
|
|
name: 'RequestCache "default" mode with an If-None-Match header is treated similarly to "no-store"',
|
|
state: "fresh",
|
|
request_cache: ["default", "default"],
|
|
request_headers: [{}, {"If-None-Match": '"foo"'}],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [false, true],
|
|
},
|
|
{
|
|
name: 'RequestCache "default" mode with an If-None-Match header is treated similarly to "no-store"',
|
|
state: "stale",
|
|
request_cache: ["default", "default"],
|
|
request_headers: [{"If-None-Match": '"foo"'}, {}],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [true, false],
|
|
},
|
|
{
|
|
name: 'RequestCache "default" mode with an If-None-Match header is treated similarly to "no-store"',
|
|
state: "fresh",
|
|
request_cache: ["default", "default"],
|
|
request_headers: [{"If-None-Match": '"foo"'}, {}],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [true, false],
|
|
},
|
|
{
|
|
name: 'RequestCache "default" mode with an If-Unmodified-Since header is treated similarly to "no-store"',
|
|
state: "stale",
|
|
request_cache: ["default", "default"],
|
|
request_headers: [{}, {"If-Unmodified-Since": now.toGMTString()}],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [false, true],
|
|
},
|
|
{
|
|
name: 'RequestCache "default" mode with an If-Unmodified-Since header is treated similarly to "no-store"',
|
|
state: "fresh",
|
|
request_cache: ["default", "default"],
|
|
request_headers: [{}, {"If-Unmodified-Since": now.toGMTString()}],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [false, true],
|
|
},
|
|
{
|
|
name: 'RequestCache "default" mode with an If-Unmodified-Since header is treated similarly to "no-store"',
|
|
state: "stale",
|
|
request_cache: ["default", "default"],
|
|
request_headers: [{"If-Unmodified-Since": now.toGMTString()}, {}],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [true, false],
|
|
},
|
|
{
|
|
name: 'RequestCache "default" mode with an If-Unmodified-Since header is treated similarly to "no-store"',
|
|
state: "fresh",
|
|
request_cache: ["default", "default"],
|
|
request_headers: [{"If-Unmodified-Since": now.toGMTString()}, {}],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [true, false],
|
|
},
|
|
{
|
|
name: 'RequestCache "default" mode with an If-Match header is treated similarly to "no-store"',
|
|
state: "stale",
|
|
request_cache: ["default", "default"],
|
|
request_headers: [{}, {"If-Match": '"foo"'}],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [false, true],
|
|
},
|
|
{
|
|
name: 'RequestCache "default" mode with an If-Match header is treated similarly to "no-store"',
|
|
state: "fresh",
|
|
request_cache: ["default", "default"],
|
|
request_headers: [{}, {"If-Match": '"foo"'}],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [false, true],
|
|
},
|
|
{
|
|
name: 'RequestCache "default" mode with an If-Match header is treated similarly to "no-store"',
|
|
state: "stale",
|
|
request_cache: ["default", "default"],
|
|
request_headers: [{"If-Match": '"foo"'}, {}],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [true, false],
|
|
},
|
|
{
|
|
name: 'RequestCache "default" mode with an If-Match header is treated similarly to "no-store"',
|
|
state: "fresh",
|
|
request_cache: ["default", "default"],
|
|
request_headers: [{"If-Match": '"foo"'}, {}],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [true, false],
|
|
},
|
|
{
|
|
name: 'RequestCache "default" mode with an If-Range header is treated similarly to "no-store"',
|
|
state: "stale",
|
|
request_cache: ["default", "default"],
|
|
request_headers: [{}, {"If-Range": '"foo"'}],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [false, true],
|
|
},
|
|
{
|
|
name: 'RequestCache "default" mode with an If-Range header is treated similarly to "no-store"',
|
|
state: "fresh",
|
|
request_cache: ["default", "default"],
|
|
request_headers: [{}, {"If-Range": '"foo"'}],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [false, true],
|
|
},
|
|
{
|
|
name: 'RequestCache "default" mode with an If-Range header is treated similarly to "no-store"',
|
|
state: "stale",
|
|
request_cache: ["default", "default"],
|
|
request_headers: [{"If-Range": '"foo"'}, {}],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [true, false],
|
|
},
|
|
{
|
|
name: 'RequestCache "default" mode with an If-Range header is treated similarly to "no-store"',
|
|
state: "fresh",
|
|
request_cache: ["default", "default"],
|
|
request_headers: [{"If-Range": '"foo"'}, {}],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [true, false],
|
|
},
|
|
{
|
|
name: 'Responses with the "Cache-Control: no-store" header are not stored in the cache',
|
|
state: "stale",
|
|
cache_control: "no-store",
|
|
request_cache: ["default", "default"],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [false, false],
|
|
},
|
|
{
|
|
name: 'Responses with the "Cache-Control: no-store" header are not stored in the cache',
|
|
state: "fresh",
|
|
cache_control: "no-store",
|
|
request_cache: ["default", "default"],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [false, false],
|
|
},
|
|
{
|
|
name: 'RequestCache "reload" mode does not check the cache for previously cached content and goes to the network regardless',
|
|
state: "stale",
|
|
request_cache: ["default", "reload"],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [false, true],
|
|
},
|
|
{
|
|
name: 'RequestCache "reload" mode does not check the cache for previously cached content and goes to the network regardless',
|
|
state: "fresh",
|
|
request_cache: ["default", "reload"],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [false, true],
|
|
},
|
|
{
|
|
name: 'RequestCache "reload" mode does store the response in the cache',
|
|
state: "stale",
|
|
request_cache: ["reload", "default"],
|
|
expected_validation_headers: [false, true],
|
|
expected_no_cache_headers: [true, false],
|
|
},
|
|
{
|
|
name: 'RequestCache "reload" mode does store the response in the cache',
|
|
state: "fresh",
|
|
request_cache: ["reload", "default"],
|
|
expected_validation_headers: [false],
|
|
expected_no_cache_headers: [true],
|
|
},
|
|
{
|
|
name: 'RequestCache "reload" mode does store the response in the cache even if a previous response is already stored',
|
|
state: "stale",
|
|
request_cache: ["default", "reload", "default"],
|
|
expected_validation_headers: [false, false, true],
|
|
expected_no_cache_headers: [false, true, false],
|
|
},
|
|
{
|
|
name: 'RequestCache "reload" mode does store the response in the cache even if a previous response is already stored',
|
|
state: "fresh",
|
|
request_cache: ["default", "reload", "default"],
|
|
expected_validation_headers: [false, false],
|
|
expected_no_cache_headers: [false, true],
|
|
},
|
|
];
|
|
function make_url(uuid, id, value, content, info) {
|
|
var dates = {
|
|
fresh: new Date(now.getFullYear() + 1, now.getMonth(), now.getDay()).toGMTString(),
|
|
stale: new Date(now.getFullYear() - 1, now.getMonth(), now.getDay()).toGMTString(),
|
|
};
|
|
var vary = "";
|
|
if ("vary" in info) {
|
|
vary = "&vary=" + info.vary;
|
|
}
|
|
var cache_control = "";
|
|
if ("cache_control" in info) {
|
|
cache_control = "&cache_control=" + info.cache_control;
|
|
}
|
|
var ignore_request_headers = "";
|
|
if ("request_headers" in info) {
|
|
// Ignore the request headers that we send since they may be synthesized by the test.
|
|
ignore_request_headers = "&ignore";
|
|
}
|
|
return "resources/cache.py?token=" + uuid +
|
|
"&content=" + content +
|
|
"&" + id + "=" + value +
|
|
"&expires=" + dates[info.state] +
|
|
vary + cache_control + ignore_request_headers;
|
|
}
|
|
function expected_status(type, identifier, init) {
|
|
if (type == "date" &&
|
|
init.headers &&
|
|
init.headers["If-Modified-Since"] == identifier) {
|
|
// The server will respond with a 304 in this case.
|
|
return [304, "Not Modified"];
|
|
}
|
|
return [200, "OK"];
|
|
}
|
|
function expected_response_text(type, identifier, init, content) {
|
|
if (type == "date" &&
|
|
init.headers &&
|
|
init.headers["If-Modified-Since"] == identifier) {
|
|
// The server will respond with a 304 in this case.
|
|
return "";
|
|
}
|
|
return content;
|
|
}
|
|
function server_state(uuid) {
|
|
return fetch("resources/cache.py?querystate&token=" + uuid)
|
|
.then(function(response) {
|
|
return response.text();
|
|
}).then(function(text) {
|
|
return JSON.parse(text);
|
|
});
|
|
}
|
|
function populate_cache(url, content, info, type, identifier) {
|
|
var init = {cache: info.request_cache[0]};
|
|
if ("request_headers" in info) {
|
|
init.headers = info.request_headers[0];
|
|
}
|
|
return fetch(url, init)
|
|
.then(function(response) {
|
|
assert_array_equals([response.status, response.statusText],
|
|
expected_status(type, identifier, init));
|
|
return response.text();
|
|
}).then(function(text) {
|
|
assert_equals(text, expected_response_text(type, identifier, init, content));
|
|
});
|
|
}
|
|
function make_test(type, info) {
|
|
return function(test) {
|
|
var uuid = token();
|
|
var identifier = (type == "tag" ? Math.random() : now.toGMTString());
|
|
var content = Math.random().toString();
|
|
var url = make_url(uuid, type, identifier, content, info);
|
|
var fetch_functions = [function() {
|
|
return populate_cache(url, content, info, type, identifier);
|
|
}];
|
|
for (var i = 1; i < info.request_cache.length; ++i) {
|
|
fetch_functions.push(function(idx) {
|
|
var init = {cache: info.request_cache[idx]};
|
|
if ("request_headers" in info) {
|
|
init.headers = info.request_headers[idx];
|
|
}
|
|
return fetch(url, init)
|
|
.then(function(response) {
|
|
assert_array_equals([response.status, response.statusText],
|
|
expected_status(type, identifier, init));
|
|
return response.text();
|
|
}).then(function(text) {
|
|
assert_equals(text, expected_response_text(type, identifier, init, content));
|
|
});
|
|
});
|
|
}
|
|
var i = 0;
|
|
function run_next_step() {
|
|
if (fetch_functions.length) {
|
|
return fetch_functions.shift()(i++)
|
|
.then(run_next_step);
|
|
} else {
|
|
return Promise.resolve();
|
|
}
|
|
}
|
|
return run_next_step()
|
|
.then(function() {
|
|
// Now, query the server state
|
|
return server_state(uuid);
|
|
}).then(function(state) {
|
|
var expectedState = [];
|
|
info.expected_validation_headers.forEach(function (validate) {
|
|
if (validate) {
|
|
if (type == "tag") {
|
|
expectedState.push({"If-None-Match": '"' + identifier + '"'});
|
|
} else {
|
|
expectedState.push({"If-Modified-Since": identifier});
|
|
}
|
|
} else {
|
|
expectedState.push({});
|
|
}
|
|
});
|
|
for (var i = 0; i < info.expected_no_cache_headers.length; ++i) {
|
|
if (info.expected_no_cache_headers[i]) {
|
|
expectedState[i]["Pragma"] = "no-cache";
|
|
expectedState[i]["Cache-Control"] = "no-cache";
|
|
}
|
|
}
|
|
if ("expected_max_age_headers" in info) {
|
|
for (var i = 0; i < info.expected_max_age_headers.length; ++i) {
|
|
if (info.expected_max_age_headers[i]) {
|
|
expectedState[i]["Cache-Control"] = "max-age=0";
|
|
}
|
|
}
|
|
}
|
|
assert_equals(state.length, expectedState.length);
|
|
for (var i = 0; i < state.length; ++i) {
|
|
for (var header in state[i]) {
|
|
assert_equals(state[i][header], expectedState[i][header]);
|
|
delete expectedState[i][header];
|
|
}
|
|
for (var header in expectedState[i]) {
|
|
assert_false(header in state[i]);
|
|
}
|
|
}
|
|
});
|
|
};
|
|
}
|
|
tests.forEach(function(info) {
|
|
promise_test(make_test("tag", info), info.name + " with Etag and " + info.state + " response");
|
|
promise_test(make_test("date", info), info.name + " with date and " + info.state + " response");
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|