mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-23 07:37:29 +09:00
[Network, DOM] Align our implementation with the current CORS/Fetch spec.
This commit is contained in:
parent
bf19c2087b
commit
37f0199c79
9 changed files with 366 additions and 31 deletions
|
|
@ -7058,16 +7058,26 @@ nsContentUtils::HasDistributedChildren(nsIContent* aContent)
|
||||||
|
|
||||||
// static
|
// static
|
||||||
bool
|
bool
|
||||||
nsContentUtils::IsForbiddenRequestHeader(const nsACString& aHeader)
|
nsContentUtils::IsForbiddenRequestHeader(const nsACString& aHeader,
|
||||||
|
const nsACString& aValue)
|
||||||
{
|
{
|
||||||
if (IsForbiddenSystemRequestHeader(aHeader)) {
|
if (IsForbiddenSystemRequestHeader(aHeader)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((nsContentUtils::IsOverrideMethodHeader(aHeader) &&
|
||||||
|
nsContentUtils::ContainsForbiddenMethod(aValue))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return StringBeginsWith(aHeader, NS_LITERAL_CSTRING("proxy-"),
|
if (StringBeginsWith(aHeader, NS_LITERAL_CSTRING("proxy-"),
|
||||||
nsCaseInsensitiveCStringComparator()) ||
|
nsCaseInsensitiveCStringComparator()) ||
|
||||||
StringBeginsWith(aHeader, NS_LITERAL_CSTRING("sec-"),
|
StringBeginsWith(aHeader, NS_LITERAL_CSTRING("sec-"),
|
||||||
nsCaseInsensitiveCStringComparator());
|
nsCaseInsensitiveCStringComparator())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
|
@ -7096,6 +7106,64 @@ nsContentUtils::IsForbiddenResponseHeader(const nsACString& aHeader)
|
||||||
aHeader.LowerCaseEqualsASCII("set-cookie2"));
|
aHeader.LowerCaseEqualsASCII("set-cookie2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
bool
|
||||||
|
nsContentUtils::IsOverrideMethodHeader(const nsACString& headerName) {
|
||||||
|
return headerName.LowerCaseEqualsASCII("x-http-method-override") ||
|
||||||
|
headerName.LowerCaseEqualsASCII("x-http-method") ||
|
||||||
|
headerName.LowerCaseEqualsASCII("x-method-override");
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
bool
|
||||||
|
nsContentUtils::ContainsForbiddenMethod(const nsACString& headerValue) {
|
||||||
|
bool hasInsecureMethod = false;
|
||||||
|
nsCCharSeparatedTokenizer tokenizer(headerValue, ',');
|
||||||
|
|
||||||
|
while (tokenizer.hasMoreTokens()) {
|
||||||
|
const nsDependentCSubstring& value = tokenizer.nextToken();
|
||||||
|
|
||||||
|
if (value.LowerCaseEqualsASCII("connect") ||
|
||||||
|
value.LowerCaseEqualsASCII("trace") ||
|
||||||
|
value.LowerCaseEqualsASCII("track")) {
|
||||||
|
hasInsecureMethod = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasInsecureMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
bool nsContentUtils::IsCorsUnsafeRequestHeaderValue(
|
||||||
|
const nsACString& aHeaderValue) {
|
||||||
|
const char* cur = aHeaderValue.BeginReading();
|
||||||
|
const char* end = aHeaderValue.EndReading();
|
||||||
|
|
||||||
|
while (cur != end) {
|
||||||
|
// Implementation of
|
||||||
|
// https://fetch.spec.whatwg.org/#cors-unsafe-request-header-byte Is less
|
||||||
|
// than a space but not a horizontal tab
|
||||||
|
if ((*cur < ' ' && *cur != '\t') || *cur == '"' || *cur == '(' ||
|
||||||
|
*cur == ')' || *cur == ':' || *cur == '<' || *cur == '>' ||
|
||||||
|
*cur == '?' || *cur == '@' || *cur == '[' || *cur == '\\' ||
|
||||||
|
*cur == ']' || *cur == '{' || *cur == '}' ||
|
||||||
|
*cur == 0x7F) { // 0x75 is DEL
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
cur++;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
bool nsContentUtils::IsAllowedNonCorsAccept(const nsACString& aHeaderValue) {
|
||||||
|
if (IsCorsUnsafeRequestHeaderValue(aHeaderValue)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
bool
|
bool
|
||||||
nsContentUtils::IsAllowedNonCorsContentType(const nsACString& aHeaderValue)
|
nsContentUtils::IsAllowedNonCorsContentType(const nsACString& aHeaderValue)
|
||||||
|
|
@ -7103,6 +7171,10 @@ nsContentUtils::IsAllowedNonCorsContentType(const nsACString& aHeaderValue)
|
||||||
nsAutoCString contentType;
|
nsAutoCString contentType;
|
||||||
nsAutoCString unused;
|
nsAutoCString unused;
|
||||||
|
|
||||||
|
if (IsCorsUnsafeRequestHeaderValue(aHeaderValue)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult rv = NS_ParseRequestContentType(aHeaderValue, contentType, unused);
|
nsresult rv = NS_ParseRequestContentType(aHeaderValue, contentType, unused);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -7113,6 +7185,41 @@ nsContentUtils::IsAllowedNonCorsContentType(const nsACString& aHeaderValue)
|
||||||
contentType.LowerCaseEqualsLiteral("multipart/form-data");
|
contentType.LowerCaseEqualsLiteral("multipart/form-data");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
bool nsContentUtils::IsAllowedNonCorsLanguage(const nsACString& aHeaderValue) {
|
||||||
|
const char* cur = aHeaderValue.BeginReading();
|
||||||
|
const char* end = aHeaderValue.EndReading();
|
||||||
|
|
||||||
|
while (cur != end) {
|
||||||
|
if ((*cur >= '0' && *cur <= '9') || (*cur >= 'A' && *cur <= 'Z') ||
|
||||||
|
(*cur >= 'a' && *cur <= 'z') || *cur == ' ' || *cur == '*' ||
|
||||||
|
*cur == ',' || *cur == '-' || *cur == '.' || *cur == ';' ||
|
||||||
|
*cur == '=') {
|
||||||
|
cur++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
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
|
bool
|
||||||
nsContentUtils::DOMWindowDumpEnabled()
|
nsContentUtils::DOMWindowDumpEnabled()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -2425,7 +2425,8 @@ public:
|
||||||
* Returns whether a given header is forbidden for an XHR or fetch
|
* Returns whether a given header is forbidden for an XHR or fetch
|
||||||
* request.
|
* request.
|
||||||
*/
|
*/
|
||||||
static bool IsForbiddenRequestHeader(const nsACString& aHeader);
|
static bool IsForbiddenRequestHeader(const nsACString& aHeader,
|
||||||
|
const nsACString& aValue);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether a given header is forbidden for a system XHR
|
* Returns whether a given header is forbidden for a system XHR
|
||||||
|
|
@ -2433,18 +2434,50 @@ public:
|
||||||
*/
|
*/
|
||||||
static bool IsForbiddenSystemRequestHeader(const nsACString& aHeader);
|
static bool IsForbiddenSystemRequestHeader(const nsACString& aHeader);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether a given header has characters that aren't permitted
|
||||||
|
*/
|
||||||
|
static bool IsCorsUnsafeRequestHeaderValue(const nsACString& aHeaderValue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether a given Accept header value is allowed
|
||||||
|
* for a non-CORS XHR or fetch request.
|
||||||
|
*/
|
||||||
|
static bool IsAllowedNonCorsAccept(const nsACString& aHeaderValue);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether a given Content-Type header value is allowed
|
* Returns whether a given Content-Type header value is allowed
|
||||||
* for a non-CORS XHR or fetch request.
|
* for a non-CORS XHR or fetch request.
|
||||||
*/
|
*/
|
||||||
static bool IsAllowedNonCorsContentType(const nsACString& aHeaderValue);
|
static bool IsAllowedNonCorsContentType(const nsACString& aHeaderValue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether a given Content-Language or accept-language header value is
|
||||||
|
* allowed for a non-CORS XHR or fetch request.
|
||||||
|
*/
|
||||||
|
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
|
* Returns whether a given header is forbidden for an XHR or fetch
|
||||||
* response.
|
* response.
|
||||||
*/
|
*/
|
||||||
static bool IsForbiddenResponseHeader(const nsACString& aHeader);
|
static bool IsForbiddenResponseHeader(const nsACString& aHeader);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the header overrides any http methods
|
||||||
|
*/
|
||||||
|
static bool IsOverrideMethodHeader(const nsACString& headerName);
|
||||||
|
/**
|
||||||
|
* Checks whether the header value contains any forbidden method
|
||||||
|
*/
|
||||||
|
static bool ContainsForbiddenMethod(const nsACString& headerValue);
|
||||||
/**
|
/**
|
||||||
* Returns the inner window ID for the window associated with a request,
|
* Returns the inner window ID for the window associated with a request,
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "mozilla/dom/InternalHeaders.h"
|
#include "mozilla/dom/InternalHeaders.h"
|
||||||
|
|
||||||
|
#include "FetchUtil.h"
|
||||||
#include "mozilla/dom/FetchTypes.h"
|
#include "mozilla/dom/FetchTypes.h"
|
||||||
#include "mozilla/ErrorResult.h"
|
#include "mozilla/ErrorResult.h"
|
||||||
|
|
||||||
|
|
@ -46,20 +47,112 @@ InternalHeaders::ToIPC(nsTArray<HeadersEntry>& aIPCHeaders,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
InternalHeaders::IsValidHeaderValue(const nsCString& aLowerName,
|
||||||
|
const nsCString& aNormalizedValue,
|
||||||
|
ErrorResult& aRv) {
|
||||||
|
// Steps 2 to 6 for ::Set() and ::Append() in the spec.
|
||||||
|
|
||||||
|
// Step 2
|
||||||
|
if (IsInvalidName(aLowerName, aRv) || IsInvalidValue(aNormalizedValue, aRv)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3
|
||||||
|
if (IsImmutable(aRv)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4
|
||||||
|
if (mGuard == HeadersGuardEnum::Request) {
|
||||||
|
if (IsForbiddenRequestHeader(aLowerName, aNormalizedValue)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5
|
||||||
|
if (mGuard == HeadersGuardEnum::Request_no_cors) {
|
||||||
|
nsAutoCString tempValue;
|
||||||
|
Get(aLowerName, tempValue, aRv);
|
||||||
|
|
||||||
|
if (tempValue.IsVoid()) {
|
||||||
|
tempValue = aNormalizedValue;
|
||||||
|
} else {
|
||||||
|
tempValue.Append(", ");
|
||||||
|
tempValue.Append(aNormalizedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nsContentUtils::IsCORSSafelistedRequestHeader(aLowerName, tempValue)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 6
|
||||||
|
else if (IsForbiddenResponseHeader(aLowerName)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
InternalHeaders::Append(const nsACString& aName, const nsACString& aValue,
|
InternalHeaders::Append(const nsACString& aName, const nsACString& aValue,
|
||||||
ErrorResult& aRv)
|
ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
|
// Step 1
|
||||||
|
nsAutoCString trimValue;
|
||||||
|
NS_TrimHTTPWhitespace(aValue, trimValue);
|
||||||
|
|
||||||
|
// Steps 2 to 6
|
||||||
nsAutoCString lowerName;
|
nsAutoCString lowerName;
|
||||||
ToLowerCase(aName, lowerName);
|
ToLowerCase(aName, lowerName);
|
||||||
|
if (!IsValidHeaderValue(lowerName, trimValue, aRv)) {
|
||||||
if (IsInvalidMutableHeader(lowerName, aValue, aRv)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Step 7
|
||||||
SetListDirty();
|
SetListDirty();
|
||||||
|
|
||||||
mList.AppendElement(Entry(lowerName, aValue));
|
mList.AppendElement(Entry(lowerName, aValue));
|
||||||
|
|
||||||
|
// Step 8
|
||||||
|
if (mGuard == HeadersGuardEnum::Request_no_cors) {
|
||||||
|
RemovePrivilegedNoCorsRequestHeaders();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InternalHeaders::RemovePrivilegedNoCorsRequestHeaders() {
|
||||||
|
bool dirty = false;
|
||||||
|
|
||||||
|
// remove in reverse order to minimize copying
|
||||||
|
for (int32_t i = mList.Length() - 1; i >= 0; --i) {
|
||||||
|
if (IsPrivilegedNoCorsRequestHeaderName(mList[i].mName)) {
|
||||||
|
mList.RemoveElementAt(i);
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dirty) {
|
||||||
|
SetListDirty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InternalHeaders::DeleteInternal(const nsCString& aLowerName,
|
||||||
|
ErrorResult& aRv) {
|
||||||
|
bool dirty = false;
|
||||||
|
|
||||||
|
// remove in reverse order to minimize copying
|
||||||
|
for (int32_t i = mList.Length() - 1; i >= 0; --i) {
|
||||||
|
if (mList[i].mName.EqualsIgnoreCase(aLowerName.get())) {
|
||||||
|
mList.RemoveElementAt(i);
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dirty) {
|
||||||
|
SetListDirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
return dirty;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -68,17 +161,43 @@ InternalHeaders::Delete(const nsACString& aName, ErrorResult& aRv)
|
||||||
nsAutoCString lowerName;
|
nsAutoCString lowerName;
|
||||||
ToLowerCase(aName, lowerName);
|
ToLowerCase(aName, lowerName);
|
||||||
|
|
||||||
if (IsInvalidMutableHeader(lowerName, aRv)) {
|
// Step 1
|
||||||
|
if (IsInvalidName(lowerName, aRv)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetListDirty();
|
// Step 2
|
||||||
|
if (IsImmutable(aRv)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// remove in reverse order to minimize copying
|
// Step 3
|
||||||
for (int32_t i = mList.Length() - 1; i >= 0; --i) {
|
nsAutoCString value;
|
||||||
if (lowerName == mList[i].mName) {
|
GetInternal(lowerName, value, aRv);
|
||||||
mList.RemoveElementAt(i);
|
if (IsForbiddenRequestHeader(lowerName, value)) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4
|
||||||
|
if (mGuard == HeadersGuardEnum::Request_no_cors &&
|
||||||
|
!IsNoCorsSafelistedRequestHeaderName(lowerName) &&
|
||||||
|
!IsPrivilegedNoCorsRequestHeaderName(lowerName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5
|
||||||
|
if (IsForbiddenResponseHeader(lowerName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Steps 6 and 7
|
||||||
|
if (!DeleteInternal(lowerName, aRv)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 8
|
||||||
|
if (mGuard == HeadersGuardEnum::Request_no_cors) {
|
||||||
|
RemovePrivilegedNoCorsRequestHeaders();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,12 +210,18 @@ InternalHeaders::Get(const nsACString& aName, nsACString& aValue, ErrorResult& a
|
||||||
if (IsInvalidName(lowerName, aRv)) {
|
if (IsInvalidName(lowerName, aRv)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
GetInternal(lowerName, aValue, aRv);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InternalHeaders::GetInternal(const nsCString& aLowerName,
|
||||||
|
nsACString& aValue,
|
||||||
|
ErrorResult& aRv) const {
|
||||||
const char* delimiter = ",";
|
const char* delimiter = ",";
|
||||||
bool firstValueFound = false;
|
bool firstValueFound = false;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < mList.Length(); ++i) {
|
for (uint32_t i = 0; i < mList.Length(); ++i) {
|
||||||
if (lowerName == mList[i].mName) {
|
if (aLowerName == mList[i].mName) {
|
||||||
if (firstValueFound) {
|
if (firstValueFound) {
|
||||||
aValue += delimiter;
|
aValue += delimiter;
|
||||||
}
|
}
|
||||||
|
|
@ -153,13 +278,18 @@ InternalHeaders::Has(const nsACString& aName, ErrorResult& aRv) const
|
||||||
void
|
void
|
||||||
InternalHeaders::Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv)
|
InternalHeaders::Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
|
// Step 1
|
||||||
|
nsAutoCString trimValue;
|
||||||
|
NS_TrimHTTPWhitespace(aValue, trimValue);
|
||||||
|
|
||||||
|
// Steps 2 to 6
|
||||||
nsAutoCString lowerName;
|
nsAutoCString lowerName;
|
||||||
ToLowerCase(aName, lowerName);
|
ToLowerCase(aName, lowerName);
|
||||||
|
if (!IsValidHeaderValue(lowerName, trimValue, aRv)) {
|
||||||
if (IsInvalidMutableHeader(lowerName, aValue, aRv)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Step 7
|
||||||
SetListDirty();
|
SetListDirty();
|
||||||
|
|
||||||
int32_t firstIndex = INT32_MAX;
|
int32_t firstIndex = INT32_MAX;
|
||||||
|
|
@ -179,6 +309,11 @@ InternalHeaders::Set(const nsACString& aName, const nsACString& aValue, ErrorRes
|
||||||
} else {
|
} else {
|
||||||
mList.AppendElement(Entry(lowerName, aValue));
|
mList.AppendElement(Entry(lowerName, aValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Step 8
|
||||||
|
if (mGuard == HeadersGuardEnum::Request_no_cors) {
|
||||||
|
RemovePrivilegedNoCorsRequestHeaders();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -200,6 +335,22 @@ InternalHeaders::~InternalHeaders()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
bool
|
||||||
|
InternalHeaders::IsNoCorsSafelistedRequestHeaderName(const nsCString& aName) {
|
||||||
|
return aName.EqualsIgnoreCase("accept") ||
|
||||||
|
aName.EqualsIgnoreCase("accept-language") ||
|
||||||
|
aName.EqualsIgnoreCase("content-language") ||
|
||||||
|
aName.EqualsIgnoreCase("content-type");
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
bool
|
||||||
|
InternalHeaders::IsPrivilegedNoCorsRequestHeaderName(
|
||||||
|
const nsCString& aName) {
|
||||||
|
return aName.EqualsIgnoreCase("range");
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
bool
|
bool
|
||||||
InternalHeaders::IsSimpleHeader(const nsACString& aName, const nsACString& aValue)
|
InternalHeaders::IsSimpleHeader(const nsACString& aName, const nsACString& aValue)
|
||||||
|
|
@ -207,9 +358,12 @@ InternalHeaders::IsSimpleHeader(const nsACString& aName, const nsACString& aValu
|
||||||
// Note, we must allow a null content-type value here to support
|
// Note, we must allow a null content-type value here to support
|
||||||
// get("content-type"), but the IsInvalidValue() check will prevent null
|
// get("content-type"), but the IsInvalidValue() check will prevent null
|
||||||
// from being set or appended.
|
// from being set or appended.
|
||||||
return aName.EqualsLiteral("accept") ||
|
return (aName.EqualsLiteral("accept") &&
|
||||||
aName.EqualsLiteral("accept-language") ||
|
nsContentUtils::IsAllowedNonCorsAccept(aValue)) ||
|
||||||
aName.EqualsLiteral("content-language") ||
|
(aName.EqualsLiteral("accept-language") &&
|
||||||
|
nsContentUtils::IsAllowedNonCorsLanguage(aValue))||
|
||||||
|
(aName.EqualsLiteral("content-language") &&
|
||||||
|
nsContentUtils::IsAllowedNonCorsLanguage(aValue))||
|
||||||
(aName.EqualsLiteral("content-type") &&
|
(aName.EqualsLiteral("content-type") &&
|
||||||
nsContentUtils::IsAllowedNonCorsContentType(aValue));
|
nsContentUtils::IsAllowedNonCorsContentType(aValue));
|
||||||
}
|
}
|
||||||
|
|
@ -261,10 +415,11 @@ InternalHeaders::IsImmutable(ErrorResult& aRv) const
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
InternalHeaders::IsForbiddenRequestHeader(const nsACString& aName) const
|
InternalHeaders::IsForbiddenRequestHeader(const nsACString& aName,
|
||||||
|
const nsACString& aValue) const
|
||||||
{
|
{
|
||||||
return mGuard == HeadersGuardEnum::Request &&
|
return mGuard == HeadersGuardEnum::Request &&
|
||||||
nsContentUtils::IsForbiddenRequestHeader(aName);
|
nsContentUtils::IsForbiddenRequestHeader(aName, aValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
@ -370,7 +525,7 @@ InternalHeaders::CORSHeaders(InternalHeaders* aHeaders, RequestCredentials aCred
|
||||||
ErrorResult result;
|
ErrorResult result;
|
||||||
|
|
||||||
nsAutoCString acExposedNames;
|
nsAutoCString acExposedNames;
|
||||||
aHeaders->GetFirst(NS_LITERAL_CSTRING("Access-Control-Expose-Headers"), acExposedNames, result);
|
aHeaders->Get(NS_LITERAL_CSTRING("Access-Control-Expose-Headers"), acExposedNames, result);
|
||||||
MOZ_ASSERT(!result.Failed());
|
MOZ_ASSERT(!result.Failed());
|
||||||
|
|
||||||
bool allowAllHeaders = false;
|
bool allowAllHeaders = false;
|
||||||
|
|
|
||||||
|
|
@ -136,8 +136,11 @@ private:
|
||||||
|
|
||||||
static bool IsInvalidName(const nsACString& aName, ErrorResult& aRv);
|
static bool IsInvalidName(const nsACString& aName, ErrorResult& aRv);
|
||||||
static bool IsInvalidValue(const nsACString& aValue, ErrorResult& aRv);
|
static bool IsInvalidValue(const nsACString& aValue, ErrorResult& aRv);
|
||||||
|
bool IsValidHeaderValue(const nsCString& aLowerName,
|
||||||
|
const nsCString& aNormalizedValue, ErrorResult& aRv);
|
||||||
bool IsImmutable(ErrorResult& aRv) const;
|
bool IsImmutable(ErrorResult& aRv) const;
|
||||||
bool IsForbiddenRequestHeader(const nsACString& aName) const;
|
bool IsForbiddenRequestHeader(const nsACString& aName,
|
||||||
|
const nsACString& aValue) const;
|
||||||
bool IsForbiddenRequestNoCorsHeader(const nsACString& aName) const;
|
bool IsForbiddenRequestNoCorsHeader(const nsACString& aName) const;
|
||||||
bool IsForbiddenRequestNoCorsHeader(const nsACString& aName,
|
bool IsForbiddenRequestNoCorsHeader(const nsACString& aName,
|
||||||
const nsACString& aValue) const;
|
const nsACString& aValue) const;
|
||||||
|
|
@ -156,11 +159,22 @@ private:
|
||||||
return IsInvalidName(aName, aRv) ||
|
return IsInvalidName(aName, aRv) ||
|
||||||
IsInvalidValue(aValue, aRv) ||
|
IsInvalidValue(aValue, aRv) ||
|
||||||
IsImmutable(aRv) ||
|
IsImmutable(aRv) ||
|
||||||
IsForbiddenRequestHeader(aName) ||
|
IsForbiddenRequestHeader(aName, aValue) ||
|
||||||
IsForbiddenRequestNoCorsHeader(aName, aValue) ||
|
IsForbiddenRequestNoCorsHeader(aName, aValue) ||
|
||||||
IsForbiddenResponseHeader(aName);
|
IsForbiddenResponseHeader(aName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RemovePrivilegedNoCorsRequestHeaders();
|
||||||
|
|
||||||
|
void GetInternal(const nsCString& aLowerName, nsACString& aValue,
|
||||||
|
ErrorResult& aRv) const;
|
||||||
|
|
||||||
|
bool DeleteInternal(const nsCString& aLowerName, ErrorResult& aRv);
|
||||||
|
|
||||||
|
static bool IsNoCorsSafelistedRequestHeaderName(const nsCString& aName);
|
||||||
|
|
||||||
|
static bool IsPrivilegedNoCorsRequestHeaderName(const nsCString& aName);
|
||||||
|
|
||||||
static bool IsSimpleHeader(const nsACString& aName,
|
static bool IsSimpleHeader(const nsACString& aName,
|
||||||
const nsACString& aValue);
|
const nsACString& aValue);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3071,9 +3071,8 @@ XMLHttpRequestMainThread::SetRequestHeader(const nsACString& aName,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 3
|
// Step 3
|
||||||
nsAutoCString value(aValue);
|
nsAutoCString value;
|
||||||
static const char kHTTPWhitespace[] = "\n\t\r ";
|
NS_TrimHTTPWhitespace(aValue, value);
|
||||||
value.Trim(kHTTPWhitespace);
|
|
||||||
|
|
||||||
// Step 4
|
// Step 4
|
||||||
if (!NS_IsValidHTTPToken(aName) || !NS_IsReasonableHTTPHeaderValue(value)) {
|
if (!NS_IsValidHTTPToken(aName) || !NS_IsReasonableHTTPHeaderValue(value)) {
|
||||||
|
|
@ -3082,7 +3081,7 @@ XMLHttpRequestMainThread::SetRequestHeader(const nsACString& aName,
|
||||||
|
|
||||||
// Step 5
|
// Step 5
|
||||||
bool isPrivilegedCaller = IsSystemXHR();
|
bool isPrivilegedCaller = IsSystemXHR();
|
||||||
bool isForbiddenHeader = nsContentUtils::IsForbiddenRequestHeader(aName);
|
bool isForbiddenHeader = nsContentUtils::IsForbiddenRequestHeader(aName, aValue);
|
||||||
if (!isPrivilegedCaller && isForbiddenHeader) {
|
if (!isPrivilegedCaller && isForbiddenHeader) {
|
||||||
NS_ConvertUTF8toUTF16 name(aName);
|
NS_ConvertUTF8toUTF16 name(aName);
|
||||||
const char16_t* params[] = { name.get() };
|
const char16_t* params[] = { name.get() };
|
||||||
|
|
|
||||||
|
|
@ -520,6 +520,12 @@ bool NS_IsValidHTTPToken(const nsACString &aToken)
|
||||||
return mozilla::net::nsHttp::IsValidToken(aToken);
|
return mozilla::net::nsHttp::IsValidToken(aToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NS_TrimHTTPWhitespace(const nsACString& aSource, nsACString& aDest)
|
||||||
|
{
|
||||||
|
mozilla::net::nsHttp::TrimHTTPWhitespace(aSource, aDest);
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
NS_NewLoadGroup(nsILoadGroup **aResult, nsIPrincipal *aPrincipal)
|
NS_NewLoadGroup(nsILoadGroup **aResult, nsIPrincipal *aPrincipal)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -959,6 +959,11 @@ bool NS_IsReasonableHTTPHeaderValue(const nsACString &aValue);
|
||||||
*/
|
*/
|
||||||
bool NS_IsValidHTTPToken(const nsACString &aToken);
|
bool NS_IsValidHTTPToken(const nsACString &aToken);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strip the leading or trailing HTTP whitespace per fetch spec section 2.2.
|
||||||
|
*/
|
||||||
|
void NS_TrimHTTPWhitespace(const nsACString& aSource, nsACString& aDest);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if the given request must be upgraded to HTTPS.
|
* Return true if the given request must be upgraded to HTTPS.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -245,6 +245,18 @@ nsHttp::GetProtocolVersion(uint32_t pv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void
|
||||||
|
nsHttp::TrimHTTPWhitespace(const nsACString& aSource, nsACString& aDest)
|
||||||
|
{
|
||||||
|
nsAutoCString str(aSource);
|
||||||
|
|
||||||
|
// HTTP whitespace 0x09: '\t', 0x0A: '\n', 0x0D: '\r', 0x20: ' '
|
||||||
|
static const char kHTTPWhitespace[] = "\t\n\r ";
|
||||||
|
str.Trim(kHTTPWhitespace);
|
||||||
|
aDest.Assign(str);
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
bool
|
bool
|
||||||
nsHttp::IsReasonableHeaderValue(const nsACString &s)
|
nsHttp::IsReasonableHeaderValue(const nsACString &s)
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,10 @@ struct nsHttp
|
||||||
static inline bool IsValidToken(const nsACString &s) {
|
static inline bool IsValidToken(const nsACString &s) {
|
||||||
return IsValidToken(s.BeginReading(), s.EndReading());
|
return IsValidToken(s.BeginReading(), s.EndReading());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Strip the leading or trailing HTTP whitespace per fetch spec section 2.2.
|
||||||
|
static void TrimHTTPWhitespace(const nsACString& aSource,
|
||||||
|
nsACString& aDest);
|
||||||
|
|
||||||
// Returns true if the specified value is reasonable given the defintion
|
// Returns true if the specified value is reasonable given the defintion
|
||||||
// in RFC 2616 section 4.2. Full strict validation is not performed
|
// in RFC 2616 section 4.2. Full strict validation is not performed
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue