diff --git a/dom/base/nsXMLHttpRequest.cpp b/dom/base/nsXMLHttpRequest.cpp index 9d36d6d92..e86063448 100644 --- a/dom/base/nsXMLHttpRequest.cpp +++ b/dom/base/nsXMLHttpRequest.cpp @@ -1317,7 +1317,10 @@ nsXMLHttpRequest::IsSafeHeader(const nsACString& header, nsIHttpChannel* httpCha if (!NS_IsValidHTTPToken(token)) { return false; } - if (header.Equals(token, nsCaseInsensitiveCStringComparator())) { + + if (token.EqualsLiteral("*")) { + isSafe = true; + } else if (header.Equals(token, nsCaseInsensitiveCStringComparator())) { isSafe = true; } } diff --git a/dom/fetch/FetchDriver.cpp b/dom/fetch/FetchDriver.cpp index 96696f059..c08195d73 100644 --- a/dom/fetch/FetchDriver.cpp +++ b/dom/fetch/FetchDriver.cpp @@ -491,7 +491,8 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest, nsAutoCString statusText; httpChannel->GetResponseStatusText(statusText); - response = new InternalResponse(responseStatus, statusText); + response = new InternalResponse(responseStatus, statusText, + mRequest->GetCredentialsMode()); RefPtr visitor = new FillResponseHeaders(response); rv = httpChannel->VisitResponseHeaders(visitor); @@ -511,7 +512,8 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest, result); MOZ_ASSERT(!result.Failed()); } else { - response = new InternalResponse(200, NS_LITERAL_CSTRING("OK")); + response = new InternalResponse(200, NS_LITERAL_CSTRING("OK"), + mRequest->GetCredentialsMode()); ErrorResult result; nsAutoCString contentType; diff --git a/dom/fetch/InternalHeaders.cpp b/dom/fetch/InternalHeaders.cpp index fccc9fc18..ee7977a95 100644 --- a/dom/fetch/InternalHeaders.cpp +++ b/dom/fetch/InternalHeaders.cpp @@ -300,7 +300,8 @@ InternalHeaders::BasicHeaders(InternalHeaders* aHeaders) // static already_AddRefed -InternalHeaders::CORSHeaders(InternalHeaders* aHeaders) +InternalHeaders::CORSHeaders(InternalHeaders* aHeaders, + RequestCredentials aCredentialsMode) { RefPtr cors = new InternalHeaders(aHeaders->mGuard); ErrorResult result; @@ -309,6 +310,7 @@ InternalHeaders::CORSHeaders(InternalHeaders* aHeaders) aHeaders->Get(NS_LITERAL_CSTRING("Access-Control-Expose-Headers"), acExposedNames, result); MOZ_ASSERT(!result.Failed()); + bool allowAllHeaders = false; nsAutoTArray exposeNamesArray; nsCCharSeparatedTokenizer exposeTokens(acExposedNames, ','); while (exposeTokens.hasMoreTokens()) { @@ -324,19 +326,27 @@ InternalHeaders::CORSHeaders(InternalHeaders* aHeaders) break; } + if (token.EqualsLiteral("*") && + aCredentialsMode != RequestCredentials::Include) { + allowAllHeaders = true; + } + exposeNamesArray.AppendElement(token); } nsCaseInsensitiveCStringArrayComparator comp; for (uint32_t i = 0; i < aHeaders->mList.Length(); ++i) { const Entry& entry = aHeaders->mList[i]; - if (entry.mName.EqualsASCII("cache-control") || - entry.mName.EqualsASCII("content-language") || - entry.mName.EqualsASCII("content-type") || - entry.mName.EqualsASCII("expires") || - entry.mName.EqualsASCII("last-modified") || - entry.mName.EqualsASCII("pragma") || - exposeNamesArray.Contains(entry.mName, comp)) { + if (allowAllHeaders) { + cors->Append(entry.mName, entry.mValue, result); + MOZ_ASSERT(!result.Failed()); + } else if (entry.mName.EqualsASCII("cache-control") || + entry.mName.EqualsASCII("content-language") || + entry.mName.EqualsASCII("content-type") || + 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); MOZ_ASSERT(!result.Failed()); } diff --git a/dom/fetch/InternalHeaders.h b/dom/fetch/InternalHeaders.h index 54639cb9a..e86e9cc7e 100644 --- a/dom/fetch/InternalHeaders.h +++ b/dom/fetch/InternalHeaders.h @@ -9,6 +9,7 @@ // needed for HeadersGuardEnum. #include "mozilla/dom/HeadersBinding.h" +#include "mozilla/dom/RequestBinding.h" #include "mozilla/dom/UnionTypes.h" #include "nsClassHashtable.h" @@ -103,7 +104,8 @@ public: BasicHeaders(InternalHeaders* aHeaders); static already_AddRefed - CORSHeaders(InternalHeaders* aHeaders); + CORSHeaders(InternalHeaders* aHeaders, + RequestCredentials mCredentialsMode = RequestCredentials::Omit); void GetEntries(nsTArray& aEntries) const; diff --git a/dom/fetch/InternalResponse.cpp b/dom/fetch/InternalResponse.cpp index 0d90d1365..9dc2c7ed7 100644 --- a/dom/fetch/InternalResponse.cpp +++ b/dom/fetch/InternalResponse.cpp @@ -16,11 +16,14 @@ namespace mozilla { namespace dom { -InternalResponse::InternalResponse(uint16_t aStatus, const nsACString& aStatusText) +InternalResponse::InternalResponse(uint16_t aStatus, + const nsACString& aStatusText, + RequestCredentials aCredentialsMode) : mType(ResponseType::Default) , mStatus(aStatus) , mStatusText(aStatusText) , mHeaders(new InternalHeaders(HeadersGuardEnum::Response)) + , mCredentialsMode(aCredentialsMode) { } @@ -76,7 +79,7 @@ InternalResponse::CORSResponse() MOZ_ASSERT(!mWrappedResponse, "Can't CORSResponse a already wrapped response"); RefPtr cors = CreateIncompleteCopy(); cors->mType = ResponseType::Cors; - cors->mHeaders = InternalHeaders::CORSHeaders(Headers()); + cors->mHeaders = InternalHeaders::CORSHeaders(Headers(), mCredentialsMode); cors->mWrappedResponse = this; return cors.forget(); } diff --git a/dom/fetch/InternalResponse.h b/dom/fetch/InternalResponse.h index 716e8b3f9..db36af96f 100644 --- a/dom/fetch/InternalResponse.h +++ b/dom/fetch/InternalResponse.h @@ -10,7 +10,9 @@ #include "nsIInputStream.h" #include "nsISupportsImpl.h" +#include "mozilla/dom/InternalHeaders.h" #include "mozilla/dom/ResponseBinding.h" +#include "mozilla/dom/RequestBinding.h" #include "mozilla/dom/ChannelInfo.h" #include "mozilla/UniquePtr.h" @@ -30,7 +32,8 @@ class InternalResponse final public: 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 Clone(); @@ -241,6 +244,7 @@ private: nsCOMPtr mBody; ChannelInfo mChannelInfo; UniquePtr mPrincipalInfo; + RequestCredentials mCredentialsMode; // For filtered responses. // Cache, and SW interception should always serialize/access the underlying diff --git a/dom/fetch/Request.cpp b/dom/fetch/Request.cpp index 36eea47ea..36b8821e1 100644 --- a/dom/fetch/Request.cpp +++ b/dom/fetch/Request.cpp @@ -275,7 +275,7 @@ Request::Constructor(const GlobalObject& aGlobal, request->SetURL(NS_ConvertUTF16toUTF8(requestURL)); fallbackMode = RequestMode::Cors; - fallbackCredentials = RequestCredentials::Omit; + fallbackCredentials = RequestCredentials::Same_origin; fallbackCache = RequestCache::Default; } @@ -365,7 +365,8 @@ Request::Constructor(const GlobalObject& aGlobal, 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. nsAutoCString method; request->GetMethod(method); @@ -377,29 +378,34 @@ Request::Constructor(const GlobalObject& aGlobal, } if (aInit.mBody.WasPassed()) { - const OwningArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& bodyInit = aInit.mBody.Value(); - nsCOMPtr stream; - nsAutoCString contentType; - aRv = ExtractByteStreamFromBody(bodyInit, - getter_AddRefs(stream), contentType); - if (NS_WARN_IF(aRv.Failed())) { - return nullptr; + const Nullable& bodyInitNullable = + aInit.mBody.Value(); + if (!bodyInitNullable.IsNull()) { + const OwningArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& bodyInit = + bodyInitNullable.Value(); + nsCOMPtr stream; + 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 domRequest = new Request(global, request); diff --git a/dom/webidl/Request.webidl b/dom/webidl/Request.webidl index 1ab355f3a..3eb9676b4 100644 --- a/dom/webidl/Request.webidl +++ b/dom/webidl/Request.webidl @@ -38,7 +38,7 @@ Request implements Body; dictionary RequestInit { ByteString method; HeadersInit headers; - BodyInit body; + BodyInit? body; RequestMode mode; RequestCredentials credentials; RequestCache cache; diff --git a/netwerk/protocol/http/nsCORSListenerProxy.cpp b/netwerk/protocol/http/nsCORSListenerProxy.cpp index 7a78d7511..2e2e5a24e 100644 --- a/netwerk/protocol/http/nsCORSListenerProxy.cpp +++ b/netwerk/protocol/http/nsCORSListenerProxy.cpp @@ -1272,7 +1272,11 @@ nsCORSPreflightListener::CheckPreflightRequestApproved(nsIRequest* aRequest) NS_ConvertUTF8toUTF16(method).get()); return NS_ERROR_DOM_BAD_URI; } - foundMethod |= mPreflightMethod.Equals(method); + if (method.EqualsLiteral("*") && !mWithCredentials) { + foundMethod = true; + } else { + foundMethod |= mPreflightMethod.Equals(method); + } } if (!foundMethod) { LogBlockedRequest(aRequest, "CORSMethodNotFound", nullptr);