From 8b870c3847ef0c44a12fcb8ddc0e2e47bc5753b0 Mon Sep 17 00:00:00 2001 From: Sean Feng Date: Mon, 27 Jun 2022 17:07:15 +0000 Subject: [PATCH] Bug 1731778 - Implement COEP: credentialless for cache storage r=edenchuang MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Spec: https://fetch.spec.whatwg.org/#ref-for-cross-origin-resource-policy-internal-check This purpose of this patch is just to implement the spec. One noticeable thing I did in the patch is I made `CacheResponse` to include the `credentials mode` of the initial request. Consider the below scenario: 1. Create a fetch request with a URL and a specific credential_mode, and put it into cache 2. Call cache.match by using a URL, but without credential_mode 3. cache.match() result should be filtered according to the initial request's credential_mode When applying the `response’s request-includes-credentials is true` check, the initial request's `credential_mode` is needed because `request-includes-credentials` is judged by the `credential_mode`. The rest of the changes are just normal spec alignments. Differential Revision: https://phabricator.services.mozilla.com/D147803 --- dom/cache/CacheOpParent.cpp | 34 +++++++++++++++++++++------------- dom/cache/CacheTypes.ipdlh | 1 + dom/cache/DBSchema.cpp | 8 +++++++- dom/fetch/InternalResponse.cpp | 1 + 4 files changed, 30 insertions(+), 14 deletions(-) diff --git a/dom/cache/CacheOpParent.cpp b/dom/cache/CacheOpParent.cpp index 2621540d0afa..288eb5618bbb 100644 --- a/dom/cache/CacheOpParent.cpp +++ b/dom/cache/CacheOpParent.cpp @@ -226,21 +226,17 @@ void CacheOpParent::ProcessCrossOriginResourcePolicyHeader( Maybe principalInfo; switch (mOpArgs.type()) { case CacheOpArgs::TCacheMatchArgs: { - loadingCOEP = - mOpArgs.get_CacheMatchArgs().request().loadingEmbedderPolicy(); - principalInfo = mOpArgs.get_CacheMatchArgs().request().principalInfo(); + const auto& request = mOpArgs.get_CacheMatchArgs().request(); + loadingCOEP = request.loadingEmbedderPolicy(); + principalInfo = request.principalInfo(); break; } case CacheOpArgs::TCacheMatchAllArgs: { if (mOpArgs.get_CacheMatchAllArgs().maybeRequest().isSome()) { - loadingCOEP = mOpArgs.get_CacheMatchAllArgs() - .maybeRequest() - .ref() - .loadingEmbedderPolicy(); - principalInfo = mOpArgs.get_CacheMatchAllArgs() - .maybeRequest() - .ref() - .principalInfo(); + const auto& request = + mOpArgs.get_CacheMatchAllArgs().maybeRequest().ref(); + loadingCOEP = request.loadingEmbedderPolicy(); + principalInfo = request.principalInfo(); } break; } @@ -266,6 +262,7 @@ void CacheOpParent::ProcessCrossOriginResourcePolicyHeader( } const auto& headers = it->mValue.headers(); + const RequestCredentials credentials = it->mValue.credentials(); const auto corpHeaderIt = std::find_if(headers.cbegin(), headers.cend(), [](const auto& header) { return header.name().EqualsLiteral("Cross-Origin-Resource-Policy"); @@ -294,11 +291,22 @@ void CacheOpParent::ProcessCrossOriginResourcePolicyHeader( const mozilla::ipc::ContentPrincipalInfo& responseContentPrincipalInfo = it->mValue.principalInfo().ref().get_ContentPrincipalInfo(); - const auto& corp = + nsCString corp = corpHeaderIt == headers.cend() ? EmptyCString() : corpHeaderIt->value(); + if (corp.IsEmpty()) { + if (loadingCOEP == nsILoadInfo::EMBEDDER_POLICY_CREDENTIALLESS) { + // This means the request of this request doesn't have + // credentials, so it's safe for us to return. + if (credentials == RequestCredentials::Omit) { + return; + } + corp = "same-origin"; + } + } + if (corp.EqualsLiteral("same-origin")) { - if (responseContentPrincipalInfo == contentPrincipalInfo) { + if (responseContentPrincipalInfo != contentPrincipalInfo) { aRv.ThrowTypeError("Response is expected from same origin."); return; } diff --git a/dom/cache/CacheTypes.ipdlh b/dom/cache/CacheTypes.ipdlh index 2539116a275c..86b0b9de284f 100644 --- a/dom/cache/CacheTypes.ipdlh +++ b/dom/cache/CacheTypes.ipdlh @@ -84,6 +84,7 @@ struct CacheResponse PrincipalInfo? principalInfo; uint32_t paddingInfo; int64_t paddingSize; + RequestCredentials credentials; }; struct CacheRequestResponse diff --git a/dom/cache/DBSchema.cpp b/dom/cache/DBSchema.cpp index 0464a3226447..09bec128eb68 100644 --- a/dom/cache/DBSchema.cpp +++ b/dom/cache/DBSchema.cpp @@ -1794,7 +1794,8 @@ Result ReadResponse(mozIStorageConnection& aConn, "entries.response_body_id, " "entries.response_principal_info, " "entries.response_padding_size, " - "security_info.data " + "security_info.data, " + "entries.request_credentials " "FROM entries " "LEFT OUTER JOIN security_info " "ON entries.response_security_info_id=security_info.id " @@ -1896,6 +1897,11 @@ Result ReadResponse(mozIStorageConnection& aConn, QM_TRY(MOZ_TO_RESULT(state->GetBlobAsUTF8String( 7, savedResponse.mValue.channelInfo().securityInfo()))); + QM_TRY_INSPECT(const int32_t& credentials, + MOZ_TO_RESULT_INVOKE_MEMBER(*state, GetInt32, 8)); + savedResponse.mValue.credentials() = + static_cast(credentials); + { QM_TRY_INSPECT(const auto& state, MOZ_TO_RESULT_INVOKE_MEMBER_TYPED( diff --git a/dom/fetch/InternalResponse.cpp b/dom/fetch/InternalResponse.cpp index 0eeac35337d2..e6847e74b898 100644 --- a/dom/fetch/InternalResponse.cpp +++ b/dom/fetch/InternalResponse.cpp @@ -196,6 +196,7 @@ SafeRefPtr InternalResponse::Clone(CloneType aCloneType) { clone->mPaddingSize = mPaddingSize; clone->mCacheInfoChannel = mCacheInfoChannel; + clone->mCredentialsMode = mCredentialsMode; if (mWrappedResponse) { clone->mWrappedResponse = mWrappedResponse->Clone(aCloneType);