#612 (from OlgaTPark/14) M1250987 M1309358 M1394399

This commit is contained in:
Cameron Kaiser
2020-10-25 14:27:50 -07:00
parent 81c8a93b94
commit 06bbc2e34c
9 changed files with 75 additions and 41 deletions

View File

@@ -1317,7 +1317,10 @@ nsXMLHttpRequest::IsSafeHeader(const nsACString& header, nsIHttpChannel* httpCha
if (!NS_IsValidHTTPToken(token)) { if (!NS_IsValidHTTPToken(token)) {
return false; return false;
} }
if (header.Equals(token, nsCaseInsensitiveCStringComparator())) {
if (token.EqualsLiteral("*")) {
isSafe = true;
} else if (header.Equals(token, nsCaseInsensitiveCStringComparator())) {
isSafe = true; isSafe = true;
} }
} }

View File

@@ -491,7 +491,8 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest,
nsAutoCString statusText; nsAutoCString statusText;
httpChannel->GetResponseStatusText(statusText); httpChannel->GetResponseStatusText(statusText);
response = new InternalResponse(responseStatus, statusText); response = new InternalResponse(responseStatus, statusText,
mRequest->GetCredentialsMode());
RefPtr<FillResponseHeaders> visitor = new FillResponseHeaders(response); RefPtr<FillResponseHeaders> visitor = new FillResponseHeaders(response);
rv = httpChannel->VisitResponseHeaders(visitor); rv = httpChannel->VisitResponseHeaders(visitor);
@@ -511,7 +512,8 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest,
result); result);
MOZ_ASSERT(!result.Failed()); MOZ_ASSERT(!result.Failed());
} else { } else {
response = new InternalResponse(200, NS_LITERAL_CSTRING("OK")); response = new InternalResponse(200, NS_LITERAL_CSTRING("OK"),
mRequest->GetCredentialsMode());
ErrorResult result; ErrorResult result;
nsAutoCString contentType; nsAutoCString contentType;

View File

@@ -300,7 +300,8 @@ InternalHeaders::BasicHeaders(InternalHeaders* aHeaders)
// static // static
already_AddRefed<InternalHeaders> already_AddRefed<InternalHeaders>
InternalHeaders::CORSHeaders(InternalHeaders* aHeaders) InternalHeaders::CORSHeaders(InternalHeaders* aHeaders,
RequestCredentials aCredentialsMode)
{ {
RefPtr<InternalHeaders> cors = new InternalHeaders(aHeaders->mGuard); RefPtr<InternalHeaders> cors = new InternalHeaders(aHeaders->mGuard);
ErrorResult result; ErrorResult result;
@@ -309,6 +310,7 @@ InternalHeaders::CORSHeaders(InternalHeaders* aHeaders)
aHeaders->Get(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;
nsAutoTArray<nsCString, 5> exposeNamesArray; nsAutoTArray<nsCString, 5> exposeNamesArray;
nsCCharSeparatedTokenizer exposeTokens(acExposedNames, ','); nsCCharSeparatedTokenizer exposeTokens(acExposedNames, ',');
while (exposeTokens.hasMoreTokens()) { while (exposeTokens.hasMoreTokens()) {
@@ -324,19 +326,27 @@ InternalHeaders::CORSHeaders(InternalHeaders* aHeaders)
break; break;
} }
if (token.EqualsLiteral("*") &&
aCredentialsMode != RequestCredentials::Include) {
allowAllHeaders = true;
}
exposeNamesArray.AppendElement(token); exposeNamesArray.AppendElement(token);
} }
nsCaseInsensitiveCStringArrayComparator comp; nsCaseInsensitiveCStringArrayComparator comp;
for (uint32_t i = 0; i < aHeaders->mList.Length(); ++i) { for (uint32_t i = 0; i < aHeaders->mList.Length(); ++i) {
const Entry& entry = aHeaders->mList[i]; const Entry& entry = aHeaders->mList[i];
if (entry.mName.EqualsASCII("cache-control") || if (allowAllHeaders) {
entry.mName.EqualsASCII("content-language") || cors->Append(entry.mName, entry.mValue, result);
entry.mName.EqualsASCII("content-type") || MOZ_ASSERT(!result.Failed());
entry.mName.EqualsASCII("expires") || } else if (entry.mName.EqualsASCII("cache-control") ||
entry.mName.EqualsASCII("last-modified") || entry.mName.EqualsASCII("content-language") ||
entry.mName.EqualsASCII("pragma") || entry.mName.EqualsASCII("content-type") ||
exposeNamesArray.Contains(entry.mName, comp)) { entry.mName.EqualsASCII("expires") ||
entry.mName.EqualsASCII("last-modified") ||
entry.mName.EqualsASCII("pragma") ||
exposeNamesArray.Contains(entry.mName, comp)) {
cors->Append(entry.mName, entry.mValue, result); cors->Append(entry.mName, entry.mValue, result);
MOZ_ASSERT(!result.Failed()); MOZ_ASSERT(!result.Failed());
} }

View File

@@ -9,6 +9,7 @@
// needed for HeadersGuardEnum. // needed for HeadersGuardEnum.
#include "mozilla/dom/HeadersBinding.h" #include "mozilla/dom/HeadersBinding.h"
#include "mozilla/dom/RequestBinding.h"
#include "mozilla/dom/UnionTypes.h" #include "mozilla/dom/UnionTypes.h"
#include "nsClassHashtable.h" #include "nsClassHashtable.h"
@@ -103,7 +104,8 @@ public:
BasicHeaders(InternalHeaders* aHeaders); BasicHeaders(InternalHeaders* aHeaders);
static already_AddRefed<InternalHeaders> static already_AddRefed<InternalHeaders>
CORSHeaders(InternalHeaders* aHeaders); CORSHeaders(InternalHeaders* aHeaders,
RequestCredentials mCredentialsMode = RequestCredentials::Omit);
void void
GetEntries(nsTArray<InternalHeaders::Entry>& aEntries) const; GetEntries(nsTArray<InternalHeaders::Entry>& aEntries) const;

View File

@@ -16,11 +16,14 @@
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
InternalResponse::InternalResponse(uint16_t aStatus, const nsACString& aStatusText) InternalResponse::InternalResponse(uint16_t aStatus,
const nsACString& aStatusText,
RequestCredentials aCredentialsMode)
: mType(ResponseType::Default) : mType(ResponseType::Default)
, mStatus(aStatus) , mStatus(aStatus)
, mStatusText(aStatusText) , mStatusText(aStatusText)
, mHeaders(new InternalHeaders(HeadersGuardEnum::Response)) , mHeaders(new InternalHeaders(HeadersGuardEnum::Response))
, mCredentialsMode(aCredentialsMode)
{ {
} }
@@ -76,7 +79,7 @@ InternalResponse::CORSResponse()
MOZ_ASSERT(!mWrappedResponse, "Can't CORSResponse a already wrapped response"); MOZ_ASSERT(!mWrappedResponse, "Can't CORSResponse a already wrapped response");
RefPtr<InternalResponse> cors = CreateIncompleteCopy(); RefPtr<InternalResponse> cors = CreateIncompleteCopy();
cors->mType = ResponseType::Cors; cors->mType = ResponseType::Cors;
cors->mHeaders = InternalHeaders::CORSHeaders(Headers()); cors->mHeaders = InternalHeaders::CORSHeaders(Headers(), mCredentialsMode);
cors->mWrappedResponse = this; cors->mWrappedResponse = this;
return cors.forget(); return cors.forget();
} }

View File

@@ -10,7 +10,9 @@
#include "nsIInputStream.h" #include "nsIInputStream.h"
#include "nsISupportsImpl.h" #include "nsISupportsImpl.h"
#include "mozilla/dom/InternalHeaders.h"
#include "mozilla/dom/ResponseBinding.h" #include "mozilla/dom/ResponseBinding.h"
#include "mozilla/dom/RequestBinding.h"
#include "mozilla/dom/ChannelInfo.h" #include "mozilla/dom/ChannelInfo.h"
#include "mozilla/UniquePtr.h" #include "mozilla/UniquePtr.h"
@@ -30,7 +32,8 @@ class InternalResponse final
public: public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(InternalResponse) NS_INLINE_DECL_THREADSAFE_REFCOUNTING(InternalResponse)
InternalResponse(uint16_t aStatus, const nsACString& aStatusText); InternalResponse(uint16_t aStatus, const nsACString& aStatusText,
RequestCredentials aCredentialsMode = RequestCredentials::Omit);
already_AddRefed<InternalResponse> Clone(); already_AddRefed<InternalResponse> Clone();
@@ -241,6 +244,7 @@ private:
nsCOMPtr<nsIInputStream> mBody; nsCOMPtr<nsIInputStream> mBody;
ChannelInfo mChannelInfo; ChannelInfo mChannelInfo;
UniquePtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo; UniquePtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo;
RequestCredentials mCredentialsMode;
// For filtered responses. // For filtered responses.
// Cache, and SW interception should always serialize/access the underlying // Cache, and SW interception should always serialize/access the underlying

View File

@@ -275,7 +275,7 @@ Request::Constructor(const GlobalObject& aGlobal,
request->SetURL(NS_ConvertUTF16toUTF8(requestURL)); request->SetURL(NS_ConvertUTF16toUTF8(requestURL));
fallbackMode = RequestMode::Cors; fallbackMode = RequestMode::Cors;
fallbackCredentials = RequestCredentials::Omit; fallbackCredentials = RequestCredentials::Same_origin;
fallbackCache = RequestCache::Default; fallbackCache = RequestCache::Default;
} }
@@ -365,7 +365,8 @@ Request::Constructor(const GlobalObject& aGlobal,
return nullptr; return nullptr;
} }
if (aInit.mBody.WasPassed() || temporaryBody) { if ((aInit.mBody.WasPassed() && !aInit.mBody.Value().IsNull()) ||
temporaryBody) {
// HEAD and GET are not allowed to have a body. // HEAD and GET are not allowed to have a body.
nsAutoCString method; nsAutoCString method;
request->GetMethod(method); request->GetMethod(method);
@@ -377,29 +378,34 @@ Request::Constructor(const GlobalObject& aGlobal,
} }
if (aInit.mBody.WasPassed()) { if (aInit.mBody.WasPassed()) {
const OwningArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& bodyInit = aInit.mBody.Value(); const Nullable<OwningArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>& bodyInitNullable =
nsCOMPtr<nsIInputStream> stream; aInit.mBody.Value();
nsAutoCString contentType; if (!bodyInitNullable.IsNull()) {
aRv = ExtractByteStreamFromBody(bodyInit, const OwningArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& bodyInit =
getter_AddRefs(stream), contentType); bodyInitNullable.Value();
if (NS_WARN_IF(aRv.Failed())) { nsCOMPtr<nsIInputStream> stream;
return nullptr; nsAutoCString contentType;
aRv = ExtractByteStreamFromBody(bodyInit,
getter_AddRefs(stream), contentType);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
temporaryBody = stream;
if (!contentType.IsVoid() &&
!requestHeaders->Has(NS_LITERAL_CSTRING("Content-Type"), aRv)) {
requestHeaders->Append(NS_LITERAL_CSTRING("Content-Type"),
contentType, aRv);
}
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
request->ClearCreatedByFetchEvent();
request->SetBody(temporaryBody);
} }
temporaryBody = stream;
if (!contentType.IsVoid() &&
!requestHeaders->Has(NS_LITERAL_CSTRING("Content-Type"), aRv)) {
requestHeaders->Append(NS_LITERAL_CSTRING("Content-Type"),
contentType, aRv);
}
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
request->ClearCreatedByFetchEvent();
request->SetBody(temporaryBody);
} }
RefPtr<Request> domRequest = new Request(global, request); RefPtr<Request> domRequest = new Request(global, request);

View File

@@ -38,7 +38,7 @@ Request implements Body;
dictionary RequestInit { dictionary RequestInit {
ByteString method; ByteString method;
HeadersInit headers; HeadersInit headers;
BodyInit body; BodyInit? body;
RequestMode mode; RequestMode mode;
RequestCredentials credentials; RequestCredentials credentials;
RequestCache cache; RequestCache cache;

View File

@@ -1272,7 +1272,11 @@ nsCORSPreflightListener::CheckPreflightRequestApproved(nsIRequest* aRequest)
NS_ConvertUTF8toUTF16(method).get()); NS_ConvertUTF8toUTF16(method).get());
return NS_ERROR_DOM_BAD_URI; return NS_ERROR_DOM_BAD_URI;
} }
foundMethod |= mPreflightMethod.Equals(method); if (method.EqualsLiteral("*") && !mWithCredentials) {
foundMethod = true;
} else {
foundMethod |= mPreflightMethod.Equals(method);
}
} }
if (!foundMethod) { if (!foundMethod) {
LogBlockedRequest(aRequest, "CORSMethodNotFound", nullptr); LogBlockedRequest(aRequest, "CORSMethodNotFound", nullptr);