Bug 1495880 - update our cors/no-cors header safelisting to match the Fetch spec; r=hsivonen,ckerschb
update XHR cors/no-cors header safelisting to match the Fetch spec Differential Revision: https://phabricator.services.mozilla.com/D7771
This commit is contained in:
@@ -6942,6 +6942,23 @@ bool nsContentUtils::IsAllowedNonCorsLanguage(const nsACString& aHeaderValue) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
bool nsContentUtils::IsCORSSafelistedRequestHeader(const nsACString& aName,
|
||||
const nsACString& aValue) {
|
||||
// see https://fetch.spec.whatwg.org/#cors-safelisted-request-header
|
||||
if (aValue.Length() > 128) {
|
||||
return false;
|
||||
}
|
||||
return (aName.LowerCaseEqualsLiteral("accept") &&
|
||||
nsContentUtils::IsAllowedNonCorsAccept(aValue)) ||
|
||||
(aName.LowerCaseEqualsLiteral("accept-language") &&
|
||||
nsContentUtils::IsAllowedNonCorsLanguage(aValue)) ||
|
||||
(aName.LowerCaseEqualsLiteral("content-language") &&
|
||||
nsContentUtils::IsAllowedNonCorsLanguage(aValue)) ||
|
||||
(aName.LowerCaseEqualsLiteral("content-type") &&
|
||||
nsContentUtils::IsAllowedNonCorsContentType(aValue));
|
||||
}
|
||||
|
||||
bool nsContentUtils::DoNotTrackEnabled() {
|
||||
return nsContentUtils::sDoNotTrackEnabled;
|
||||
}
|
||||
|
||||
@@ -2759,6 +2759,13 @@ class nsContentUtils {
|
||||
*/
|
||||
static bool IsAllowedNonCorsLanguage(const nsACString& aHeaderValue);
|
||||
|
||||
/**
|
||||
* Returns whether a given header and value is a CORS-safelisted request
|
||||
* header per https://fetch.spec.whatwg.org/#cors-safelisted-request-header
|
||||
*/
|
||||
static bool IsCORSSafelistedRequestHeader(const nsACString& aName,
|
||||
const nsACString& aValue);
|
||||
|
||||
/**
|
||||
* Returns whether a given header is forbidden for an XHR or fetch
|
||||
* response.
|
||||
|
||||
@@ -3931,20 +3931,9 @@ void RequestHeaders::ApplyToChannel(nsIHttpChannel* aHttpChannel) const {
|
||||
}
|
||||
|
||||
void RequestHeaders::GetCORSUnsafeHeaders(nsTArray<nsCString>& aArray) const {
|
||||
static const char* kCrossOriginSafeHeaders[] = {
|
||||
"accept", "accept-language", "content-language", "content-type",
|
||||
"last-event-id"};
|
||||
const uint32_t kCrossOriginSafeHeadersLength =
|
||||
ArrayLength(kCrossOriginSafeHeaders);
|
||||
for (const RequestHeader& header : mHeaders) {
|
||||
bool safe = false;
|
||||
for (uint32_t i = 0; i < kCrossOriginSafeHeadersLength; ++i) {
|
||||
if (header.mName.LowerCaseEqualsASCII(kCrossOriginSafeHeaders[i])) {
|
||||
safe = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!safe) {
|
||||
if (!nsContentUtils::IsCORSSafelistedRequestHeader(header.mName,
|
||||
header.mValue)) {
|
||||
aArray.AppendElement(header.mName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[client-hint-request-headers.htm]
|
||||
[client-hint-request-headers-2.tentative.htm]
|
||||
[Client hint headers are simple headers]
|
||||
expected: FAIL
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[simple-requests.htm]
|
||||
[simple-requests-ch.tentative.htm]
|
||||
[No preflight GET and {"save-data":"on","device-memory":"2.0","dpr":"3.0","width":"1200","viewport-width":"1300"}]
|
||||
expected: FAIL
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
[access-control-basic-cors-safelisted-request-headers.htm]
|
||||
[Request with CORS-safelisted headers]
|
||||
expected: FAIL
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
[send-redirect-to-cors.htm]
|
||||
[XMLHttpRequest: send() - Redirect to CORS-enabled resource (301 GET with explicit Content-Type)]
|
||||
expected: FAIL
|
||||
|
||||
[XMLHttpRequest: send() - Redirect to CORS-enabled resource (301 POST with string and explicit Content-Type)]
|
||||
expected: FAIL
|
||||
|
||||
[XMLHttpRequest: send() - Redirect to CORS-enabled resource (302 POST with string and explicit Content-Type)]
|
||||
expected: FAIL
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>CORS and Client Hints, potentially</title>
|
||||
|
||||
<script src=/resources/testharness.js></script>
|
||||
<script src=/resources/testharnessreport.js></script>
|
||||
<script src=support.js?pipe=sub></script>
|
||||
|
||||
<h1>Request headers</h1>
|
||||
<div id=log></div>
|
||||
<script>
|
||||
test(function() {
|
||||
var client = new XMLHttpRequest()
|
||||
client.open('GET', CROSSDOMAIN + 'resources/cors-makeheader.py?headers=x-print,', false)
|
||||
client.setRequestHeader('x-print', 'unicorn')
|
||||
client.setRequestHeader('content-type', 'text/plain')
|
||||
client.setRequestHeader('accept', 'test')
|
||||
client.setRequestHeader('accept-language', 'nn')
|
||||
client.setRequestHeader('content-language', 'nn')
|
||||
client.setRequestHeader('save-data', 'on')
|
||||
client.setRequestHeader('device-memory', '1.0')
|
||||
client.setRequestHeader('dpr', '2.0')
|
||||
client.setRequestHeader('width', '35')
|
||||
client.setRequestHeader('viewport-width', '42')
|
||||
client.send(null)
|
||||
const res = JSON.parse(client.response)
|
||||
assert_equals(res['x-print'], 'unicorn')
|
||||
assert_equals(res['content-type'], 'text/plain')
|
||||
assert_equals(res['accept'], 'test')
|
||||
assert_equals(res['accept-language'], 'nn')
|
||||
assert_equals(res['content-language'], 'nn')
|
||||
assert_equals(res['save-data'], 'on')
|
||||
assert_equals(res['device-memory'], '1.0')
|
||||
assert_equals(res['dpr'], '2.0')
|
||||
assert_equals(res['width'], '35')
|
||||
assert_equals(res['viewport-width'], '42')
|
||||
}, 'Client hint headers are simple headers')
|
||||
</script>
|
||||
@@ -1,6 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>CORS - client hint request headers - Access-Control-Allow-Headers</title>
|
||||
<title>CORS and Client Hints</title>
|
||||
|
||||
<script src=/resources/testharness.js></script>
|
||||
<script src=/resources/testharnessreport.js></script>
|
||||
@@ -10,34 +10,6 @@
|
||||
<div id=log></div>
|
||||
<script>
|
||||
|
||||
test(function() {
|
||||
var client = new XMLHttpRequest()
|
||||
client.open('GET', CROSSDOMAIN + 'resources/cors-makeheader.py?headers=x-print,', false)
|
||||
client.setRequestHeader('x-print', 'unicorn')
|
||||
client.setRequestHeader('content-type', 'text/plain')
|
||||
client.setRequestHeader('accept', 'test')
|
||||
client.setRequestHeader('accept-language', 'nn')
|
||||
client.setRequestHeader('content-language', 'nn')
|
||||
client.setRequestHeader('save-data', 'on')
|
||||
client.setRequestHeader('device-memory', '1.0')
|
||||
client.setRequestHeader('dpr', '2.0')
|
||||
client.setRequestHeader('width', '35')
|
||||
client.setRequestHeader('viewport-width', '42')
|
||||
client.send(null)
|
||||
|
||||
const res = JSON.parse(client.response)
|
||||
assert_equals(res['x-print'], 'unicorn')
|
||||
assert_equals(res['content-type'], 'text/plain')
|
||||
assert_equals(res['accept'], 'test')
|
||||
assert_equals(res['accept-language'], 'nn')
|
||||
assert_equals(res['content-language'], 'nn')
|
||||
assert_equals(res['save-data'], 'on')
|
||||
assert_equals(res['device-memory'], '1.0')
|
||||
assert_equals(res['dpr'], '2.0')
|
||||
assert_equals(res['width'], '35')
|
||||
assert_equals(res['viewport-width'], '42')
|
||||
}, 'Client hint headers are simple headers')
|
||||
|
||||
test(function() {
|
||||
var client = new XMLHttpRequest()
|
||||
client.open('GET', CROSSDOMAIN + 'resources/cors-makeheader.py?headers=x-print', false)
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>CORS - simple requests</title>
|
||||
<meta name=author title="Odin Hørthe Omdal" href="mailto:odiho@opera.com">
|
||||
|
||||
<script src=/resources/testharness.js></script>
|
||||
<script src=/resources/testharnessreport.js></script>
|
||||
<script src=support.js?pipe=sub></script>
|
||||
<script src=/common/utils.js></script>
|
||||
|
||||
<h1>Simple requests</h1>
|
||||
<p>Simple requests shouldn't trigger preflight</p>
|
||||
|
||||
<div id=log></div>
|
||||
<script>
|
||||
var test_c = 0;
|
||||
function check_simple(method, headers)
|
||||
{
|
||||
test(function() {
|
||||
var client = new XMLHttpRequest()
|
||||
var uuid_token = token();
|
||||
client.open(method, CROSSDOMAIN + 'resources/preflight.py?token='
|
||||
+ uuid_token, false)
|
||||
for (head in headers)
|
||||
client.setRequestHeader(head, headers[head])
|
||||
client.send("data")
|
||||
assert_equals(client.getResponseHeader('content-type'), "text/plain")
|
||||
if (method == 'HEAD')
|
||||
assert_equals(client.response, '', 'response')
|
||||
else
|
||||
assert_equals(client.response, 'NO', 'response')
|
||||
client.open('GET', 'resources/preflight.py?check&token='
|
||||
+ uuid_token, false)
|
||||
client.send("data")
|
||||
assert_equals(client.response, "0", "Found preflight log")
|
||||
},
|
||||
'No preflight ' + method + ' and ' + JSON.stringify(headers))
|
||||
}
|
||||
function check_simple_headers(headers) {
|
||||
check_simple('GET', headers)
|
||||
check_simple('HEAD', headers)
|
||||
check_simple('POST', headers)
|
||||
}
|
||||
check_simple_headers({
|
||||
'save-data': 'on',
|
||||
'device-memory': '2.0',
|
||||
'dpr': '3.0',
|
||||
'width': '1200',
|
||||
'viewport-width': '1300'
|
||||
})
|
||||
</script>
|
||||
@@ -61,14 +61,6 @@ check_simple_headers({
|
||||
'content-type': 'text/plain; parameter=whatever'
|
||||
})
|
||||
|
||||
check_simple_headers({
|
||||
'save-data': 'on',
|
||||
'device-memory': '2.0',
|
||||
'dpr': '3.0',
|
||||
'width': '1200',
|
||||
'viewport-width': '1300'
|
||||
})
|
||||
|
||||
check_simple('Get', {'content-type': 'text/plain; parameter=extra_bonus'})
|
||||
check_simple('post', {'content-type': 'text/plain'})
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
xhr.setRequestHeader("Accept-Language", "ru");
|
||||
xhr.setRequestHeader("Content-Language", "ru");
|
||||
xhr.setRequestHeader("Content-Type", "text/plain");
|
||||
xhr.setRequestHeader("Save-Data", "on");
|
||||
|
||||
xhr.send();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user