Skip to content

Commit

Permalink
Fetch: tests for further CORS restrictions
Browse files Browse the repository at this point in the history
  • Loading branch information
annevk authored Aug 16, 2018
1 parent 2eaab82 commit a70e655
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 59 deletions.
19 changes: 19 additions & 0 deletions fetch/api/cors/cors-preflight-not-cors-safelisted.any.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// META: script=/common/utils.js
// META: script=../resources/utils.js
// META: script=/common/get-host-info.sub.js
// META: script=resources/corspreflight.js

const corsURL = get_host_info().HTTP_REMOTE_ORIGIN + dirname(location.pathname) + RESOURCES_DIR + "preflight.py";

promise_test(() => fetch("resources/not-cors-safelisted.json").then(res => res.json().then(runTests)), "Loading data…");

function runTests(testArray) {
testArray.forEach(testItem => {
const [headerName, headerValue] = testItem;
corsPreflight("Need CORS-preflight for " + headerName + "/" + headerValue + " header",
corsURL,
"GET",
true,
[[headerName, headerValue]]);
});
}
60 changes: 1 addition & 59 deletions fetch/api/cors/cors-preflight.any.js
Original file line number Diff line number Diff line change
@@ -1,65 +1,7 @@
// META: script=/common/utils.js
// META: script=../resources/utils.js
// META: script=/common/get-host-info.sub.js

function headerNames(headers)
{
let names = [];
for (let header of headers)
names.push(header[0].toLowerCase());
return names
}

/*
Check preflight is done
Control if server allows method and headers and check accordingly
Check control access headers added by UA (for method and headers)
*/
function corsPreflight(desc, corsUrl, method, allowed, headers, safeHeaders) {
return promise_test(function(test) {
var uuid_token = token();
return fetch(RESOURCES_DIR + "clean-stash.py?token=" + uuid_token).then(function(response) {
var url = corsUrl + (corsUrl.indexOf("?") === -1 ? "?" : "&");
var urlParameters = "token=" + uuid_token + "&max_age=0";
var requestInit = {"mode": "cors", "method": method};
var requestHeaders = [];
if (headers)
requestHeaders.push.apply(requestHeaders, headers);
if (safeHeaders)
requestHeaders.push.apply(requestHeaders, safeHeaders);
requestInit["headers"] = requestHeaders;

if (allowed) {
urlParameters += "&allow_methods=" + method + "&control_request_headers";
if (headers) {
//Make the server allow the headers
urlParameters += "&allow_headers=" + headerNames(headers).join("%20%2C");
}
return fetch(url + urlParameters, requestInit).then(function(resp) {
assert_equals(resp.status, 200, "Response's status is 200");
assert_equals(resp.headers.get("x-did-preflight"), "1", "Preflight request has been made");
if (headers) {
var actualHeaders = resp.headers.get("x-control-request-headers").toLowerCase().split(",");
for (var i in actualHeaders)
actualHeaders[i] = actualHeaders[i].trim();
for (var header of headers)
assert_in_array(header[0].toLowerCase(), actualHeaders, "Preflight asked permission for header: " + header);

let accessControlAllowHeaders = headerNames(headers).sort().join(",");
assert_equals(resp.headers.get("x-control-request-headers"), accessControlAllowHeaders, "Access-Control-Allow-Headers value");
return fetch(RESOURCES_DIR + "clean-stash.py?token=" + uuid_token);
} else {
assert_equals(resp.headers.get("x-control-request-headers"), null, "Access-Control-Request-Headers should be omitted")
}
});
} else {
return promise_rejects(test, new TypeError(), fetch(url + urlParameters, requestInit)).then(function(){
return fetch(RESOURCES_DIR + "clean-stash.py?token=" + uuid_token);
});
}
});
}, desc);
}
// META: script=resources/corspreflight.js

var corsUrl = get_host_info().HTTP_REMOTE_ORIGIN + dirname(location.pathname) + RESOURCES_DIR + "preflight.py";

Expand Down
58 changes: 58 additions & 0 deletions fetch/api/cors/resources/corspreflight.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
function headerNames(headers) {
let names = [];
for (let header of headers) {
names.push(header[0].toLowerCase());
}
return names;
}

/*
Check preflight is done
Control if server allows method and headers and check accordingly
Check control access headers added by UA (for method and headers)
*/
function corsPreflight(desc, corsUrl, method, allowed, headers, safeHeaders) {
return promise_test(function(test) {
var uuid_token = token();
return fetch(RESOURCES_DIR + "clean-stash.py?token=" + uuid_token).then(function(response) {
var url = corsUrl + (corsUrl.indexOf("?") === -1 ? "?" : "&");
var urlParameters = "token=" + uuid_token + "&max_age=0";
var requestInit = {"mode": "cors", "method": method};
var requestHeaders = [];
if (headers)
requestHeaders.push.apply(requestHeaders, headers);
if (safeHeaders)
requestHeaders.push.apply(requestHeaders, safeHeaders);
requestInit["headers"] = requestHeaders;

if (allowed) {
urlParameters += "&allow_methods=" + method + "&control_request_headers";
if (headers) {
//Make the server allow the headers
urlParameters += "&allow_headers=" + headerNames(headers).join("%20%2C");
}
return fetch(url + urlParameters, requestInit).then(function(resp) {
assert_equals(resp.status, 200, "Response's status is 200");
assert_equals(resp.headers.get("x-did-preflight"), "1", "Preflight request has been made");
if (headers) {
var actualHeaders = resp.headers.get("x-control-request-headers").toLowerCase().split(",");
for (var i in actualHeaders)
actualHeaders[i] = actualHeaders[i].trim();
for (var header of headers)
assert_in_array(header[0].toLowerCase(), actualHeaders, "Preflight asked permission for header: " + header);

let accessControlAllowHeaders = headerNames(headers).sort().join(",");
assert_equals(resp.headers.get("x-control-request-headers"), accessControlAllowHeaders, "Access-Control-Allow-Headers value");
return fetch(RESOURCES_DIR + "clean-stash.py?token=" + uuid_token);
} else {
assert_equals(resp.headers.get("x-control-request-headers"), null, "Access-Control-Request-Headers should be omitted")
}
});
} else {
return promise_rejects(test, new TypeError(), fetch(url + urlParameters, requestInit)).then(function(){
return fetch(RESOURCES_DIR + "clean-stash.py?token=" + uuid_token);
});
}
});
}, desc);
}
11 changes: 11 additions & 0 deletions fetch/api/cors/resources/not-cors-safelisted.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[
["accept", "\""],
["accept", "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678"],
["accept-language", "\u0001"],
["accept-language", "@"],
["content-language", "\u0001"],
["content-language", "@"],
["content-type", "text/html"],
["content-type", "text/plain; long=0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901"],
["test", "hi"]
]
19 changes: 19 additions & 0 deletions fetch/api/headers/headers-no-cors.window.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
promise_test(() => fetch("../cors/resources/not-cors-safelisted.json").then(res => res.json().then(runTests)), "Loading data…");

function runTests(testArray) {
testArray = testArray.concat([
["dpr", "2"],
["downlink", "1"], // https://wicg.github.io/netinfo/
["save-data", "on"],
["viewport-width", "100"],
["width", "100"]
]);
testArray.forEach(testItem => {
const [headerName, headerValue] = testItem;
test(() => {
const noCorsHeaders = new Request("about:blank", { mode: "no-cors" }).headers;
noCorsHeaders.append(headerName, headerValue);
assert_false(noCorsHeaders.has(headerName));
}, "\"no-cors\" Headers object cannot have " + headerName + "/" + headerValue + " as header");
});
}

0 comments on commit a70e655

Please sign in to comment.