зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1910886 - Reduce duplicated code between CookieService and CookieServiceChild - part 2 - Unify nsICookieService.setCookieStringFromDocument implementations, r=edgul,cookie-reviewers
Differential Revision: https://phabricator.services.mozilla.com/D218313
This commit is contained in:
Родитель
f2b80c9707
Коммит
64d766f610
|
@ -269,6 +269,7 @@
|
|||
#include "mozilla/net/Cookie.h"
|
||||
#include "mozilla/net/CookieCommons.h"
|
||||
#include "mozilla/net/CookieJarSettings.h"
|
||||
#include "mozilla/net/CookieParser.h"
|
||||
#include "mozilla/net/NeckoChannelParams.h"
|
||||
#include "mozilla/net/RequestContextService.h"
|
||||
#include "nsAboutProtocolUtils.h"
|
||||
|
@ -6787,7 +6788,7 @@ void Document::GetCookie(nsAString& aCookie, ErrorResult& aRv) {
|
|||
UTF_8_ENCODING->DecodeWithoutBOMHandling(cookieString, aCookie);
|
||||
}
|
||||
|
||||
void Document::SetCookie(const nsAString& aCookie, ErrorResult& aRv) {
|
||||
void Document::SetCookie(const nsAString& aCookieString, ErrorResult& aRv) {
|
||||
if (mDisableCookieAccess) {
|
||||
return;
|
||||
}
|
||||
|
@ -6827,19 +6828,71 @@ void Document::SetCookie(const nsAString& aCookie, ErrorResult& aRv) {
|
|||
return;
|
||||
}
|
||||
|
||||
NS_ConvertUTF16toUTF8 cookie(aCookie);
|
||||
nsresult rv = service->SetCookieStringFromDocument(this, cookie);
|
||||
NS_ConvertUTF16toUTF8 cookieString(aCookieString);
|
||||
|
||||
// No warning messages here.
|
||||
if (NS_FAILED(rv)) {
|
||||
nsCOMPtr<nsIURI> documentURI;
|
||||
nsAutoCString baseDomain;
|
||||
OriginAttributes attrs;
|
||||
|
||||
int64_t currentTimeInUsec = PR_Now();
|
||||
|
||||
auto* basePrincipal = BasePrincipal::Cast(NodePrincipal());
|
||||
basePrincipal->GetURI(getter_AddRefs(documentURI));
|
||||
if (NS_WARN_IF(!documentURI)) {
|
||||
// Document's principal is not a content or null (may be system), so
|
||||
// can't set cookies
|
||||
return;
|
||||
}
|
||||
|
||||
// Console report takes care of the correct reporting at the exit of this
|
||||
// method.
|
||||
RefPtr<ConsoleReportCollector> crc = new ConsoleReportCollector();
|
||||
auto scopeExit = MakeScopeExit([&] { crc->FlushConsoleReports(this); });
|
||||
|
||||
CookieParser cookieParser(crc, documentURI);
|
||||
|
||||
ThirdPartyUtil* thirdPartyUtil = ThirdPartyUtil::GetInstance();
|
||||
if (!thirdPartyUtil) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIEffectiveTLDService> tldService =
|
||||
do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
|
||||
if (!tldService) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<Cookie> cookie = CookieCommons::CreateCookieFromDocument(
|
||||
cookieParser, this, cookieString, currentTimeInUsec, tldService,
|
||||
thirdPartyUtil, baseDomain, attrs);
|
||||
if (!cookie) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool thirdParty = true;
|
||||
nsPIDOMWindowInner* innerWindow = GetInnerWindow();
|
||||
// in gtests we don't have a window, let's consider those requests as 3rd
|
||||
// party.
|
||||
if (innerWindow) {
|
||||
Unused << thirdPartyUtil->IsThirdPartyWindow(innerWindow->GetOuterWindow(),
|
||||
nullptr, &thirdParty);
|
||||
}
|
||||
|
||||
if (thirdParty &&
|
||||
!CookieCommons::ShouldIncludeCrossSiteCookieForDocument(cookie, this)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// add the cookie to the list. AddCookieFromDocument() takes care of logging.
|
||||
service->AddCookieFromDocument(cookieParser, baseDomain, attrs, *cookie,
|
||||
currentTimeInUsec, documentURI, thirdParty,
|
||||
this);
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
if (observerService) {
|
||||
observerService->NotifyObservers(ToSupports(this), "document-set-cookie",
|
||||
nsString(aCookie).get());
|
||||
nsString(aCookieString).get());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -368,8 +368,6 @@ already_AddRefed<Cookie> CookieCommons::CreateCookieFromDocument(
|
|||
CookieParser& aCookieParser, Document* aDocument,
|
||||
const nsACString& aCookieString, int64_t currentTimeInUsec,
|
||||
nsIEffectiveTLDService* aTLDService, mozIThirdPartyUtil* aThirdPartyUtil,
|
||||
std::function<bool(const nsACString&, const OriginAttributes&)>&&
|
||||
aHasExistingCookiesLambda,
|
||||
nsACString& aBaseDomain, OriginAttributes& aAttrs) {
|
||||
if (!CookieCommons::IsSchemeSupported(aCookieParser.HostURI())) {
|
||||
return nullptr;
|
||||
|
@ -447,11 +445,17 @@ already_AddRefed<Cookie> CookieCommons::CreateCookieFromDocument(
|
|||
: aDocument->EffectiveCookiePrincipal();
|
||||
MOZ_ASSERT(cookiePrincipal);
|
||||
|
||||
nsCOMPtr<nsICookieService> service =
|
||||
do_GetService(NS_COOKIESERVICE_CONTRACTID);
|
||||
if (!service) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Check if limit-foreign is required.
|
||||
uint32_t dummyRejectedReason = 0;
|
||||
if (aDocument->CookieJarSettings()->GetLimitForeignContexts() &&
|
||||
!aHasExistingCookiesLambda(baseDomain,
|
||||
cookiePrincipal->OriginAttributesRef()) &&
|
||||
!service->HasExistingCookies(baseDomain,
|
||||
cookiePrincipal->OriginAttributesRef()) &&
|
||||
!ShouldAllowAccessFor(innerWindow, aCookieParser.HostURI(),
|
||||
&dummyRejectedReason)) {
|
||||
return nullptr;
|
||||
|
|
|
@ -107,8 +107,6 @@ class CookieCommons final {
|
|||
CookieParser& aCookieParser, dom::Document* aDocument,
|
||||
const nsACString& aCookieString, int64_t aCurrentTimeInUsec,
|
||||
nsIEffectiveTLDService* aTLDService, mozIThirdPartyUtil* aThirdPartyUtil,
|
||||
std::function<bool(const nsACString&, const OriginAttributes&)>&&
|
||||
aHasExistingCookiesLambda,
|
||||
nsACString& aBaseDomain, OriginAttributes& aAttrs);
|
||||
|
||||
static already_AddRefed<nsICookieJarSettings> GetCookieJarSettings(
|
||||
|
|
|
@ -860,7 +860,7 @@ bool CookieParser::Parse(const nsACString& aBaseDomain, bool aRequireHostMatch,
|
|||
|
||||
// aCookieHeader is an in/out param to point to the next cookie, if
|
||||
// there is one. Save the present value for logging purposes
|
||||
nsCString savedCookieHeader(aCookieHeader);
|
||||
mCookieString.Assign(aCookieHeader);
|
||||
|
||||
// newCookie says whether there are multiple cookies in the header;
|
||||
// so we can handle them separately.
|
||||
|
@ -897,7 +897,7 @@ bool CookieParser::Parse(const nsACString& aBaseDomain, bool aRequireHostMatch,
|
|||
|
||||
// reject cookie if name and value are empty, per RFC6265bis
|
||||
if (mCookieData.name().IsEmpty() && mCookieData.value().IsEmpty()) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, mHostURI, savedCookieHeader,
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, mHostURI, mCookieString,
|
||||
"cookie name and value are empty");
|
||||
|
||||
RejectCookie(RejectedEmptyNameAndValue);
|
||||
|
@ -906,7 +906,7 @@ bool CookieParser::Parse(const nsACString& aBaseDomain, bool aRequireHostMatch,
|
|||
|
||||
// reject cookie if it's over the size limit, per RFC2109
|
||||
if (!CookieCommons::CheckNameAndValueSize(mCookieData)) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, mHostURI, savedCookieHeader,
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, mHostURI, mCookieString,
|
||||
"cookie too big (> 4kb)");
|
||||
RejectCookie(RejectedNameValueOversize);
|
||||
return newCookie;
|
||||
|
@ -921,7 +921,7 @@ bool CookieParser::Parse(const nsACString& aBaseDomain, bool aRequireHostMatch,
|
|||
}
|
||||
|
||||
if (!CookieCommons::CheckName(mCookieData)) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, mHostURI, savedCookieHeader,
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, mHostURI, mCookieString,
|
||||
"invalid name character");
|
||||
RejectCookie(RejectedInvalidCharName);
|
||||
return newCookie;
|
||||
|
@ -929,14 +929,14 @@ bool CookieParser::Parse(const nsACString& aBaseDomain, bool aRequireHostMatch,
|
|||
|
||||
// domain & path checks
|
||||
if (!CheckDomain(mCookieData, mHostURI, aBaseDomain, aRequireHostMatch)) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, mHostURI, savedCookieHeader,
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, mHostURI, mCookieString,
|
||||
"failed the domain tests");
|
||||
RejectCookie(RejectedInvalidDomain);
|
||||
return newCookie;
|
||||
}
|
||||
|
||||
if (!CheckPath()) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, mHostURI, savedCookieHeader,
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, mHostURI, mCookieString,
|
||||
"failed the path tests");
|
||||
return newCookie;
|
||||
}
|
||||
|
@ -945,7 +945,7 @@ bool CookieParser::Parse(const nsACString& aBaseDomain, bool aRequireHostMatch,
|
|||
// `__Host-` or `__Secure-`
|
||||
if (mCookieData.name().IsEmpty() && (HasSecurePrefix(mCookieData.value()) ||
|
||||
HasHostPrefix(mCookieData.value()))) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, mHostURI, savedCookieHeader,
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, mHostURI, mCookieString,
|
||||
"failed hidden prefix tests");
|
||||
RejectCookie(RejectedInvalidPrefix);
|
||||
return newCookie;
|
||||
|
@ -953,14 +953,14 @@ bool CookieParser::Parse(const nsACString& aBaseDomain, bool aRequireHostMatch,
|
|||
|
||||
// magic prefix checks. MUST be run after CheckDomain() and CheckPath()
|
||||
if (!CheckPrefixes(mCookieData, potentiallyTrustworthy)) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, mHostURI, savedCookieHeader,
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, mHostURI, mCookieString,
|
||||
"failed the prefix tests");
|
||||
RejectCookie(RejectedInvalidPrefix);
|
||||
return newCookie;
|
||||
}
|
||||
|
||||
if (!CookieCommons::CheckValue(mCookieData)) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, mHostURI, savedCookieHeader,
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, mHostURI, mCookieString,
|
||||
"invalid value character");
|
||||
RejectCookie(RejectedInvalidCharValue);
|
||||
return newCookie;
|
||||
|
@ -968,7 +968,7 @@ bool CookieParser::Parse(const nsACString& aBaseDomain, bool aRequireHostMatch,
|
|||
|
||||
// if the new cookie is httponly, make sure we're not coming from script
|
||||
if (!aFromHttp && mCookieData.isHttpOnly()) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, mHostURI, savedCookieHeader,
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, mHostURI, mCookieString,
|
||||
"cookie is httponly; coming from script");
|
||||
RejectCookie(RejectedHttpOnlyButFromScript);
|
||||
return newCookie;
|
||||
|
@ -994,7 +994,7 @@ bool CookieParser::Parse(const nsACString& aBaseDomain, bool aRequireHostMatch,
|
|||
laxByDefault ? mCookieData.sameSite() : mCookieData.rawSameSite();
|
||||
if ((effectiveSameSite != nsICookie::SAMESITE_NONE) &&
|
||||
aIsForeignAndNotAddon) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, mHostURI, savedCookieHeader,
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, mHostURI, mCookieString,
|
||||
"failed the samesite tests");
|
||||
RejectCookie(RejectedForNonSameSiteness);
|
||||
return newCookie;
|
||||
|
@ -1010,7 +1010,7 @@ bool CookieParser::Parse(const nsACString& aBaseDomain, bool aRequireHostMatch,
|
|||
(aIsInPrivateBrowsing &&
|
||||
StaticPrefs::
|
||||
network_cookie_cookieBehavior_optInPartitioning_pbmode())) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, mHostURI, savedCookieHeader,
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, mHostURI, mCookieString,
|
||||
"foreign cookies must be partitioned");
|
||||
RejectCookie(RejectedForeignNoPartitionedError);
|
||||
return newCookie;
|
||||
|
@ -1028,5 +1028,9 @@ void CookieParser::RejectCookie(Rejection aRejection) {
|
|||
mRejection = aRejection;
|
||||
}
|
||||
|
||||
void CookieParser::GetCookieString(nsACString& aCookieString) const {
|
||||
aCookieString.Assign(mCookieString);
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -63,6 +63,8 @@ class CookieParser final {
|
|||
return mCookieData;
|
||||
}
|
||||
|
||||
void GetCookieString(nsACString& aCookieString) const;
|
||||
|
||||
// Public for testing
|
||||
bool ParseMaxAgeAttribute(const nsACString& aMaxage, int64_t* aValue);
|
||||
|
||||
|
@ -112,6 +114,7 @@ class CookieParser final {
|
|||
} mWarnings;
|
||||
|
||||
CookieStruct mCookieData;
|
||||
nsCString mCookieString;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
|
|
|
@ -419,77 +419,6 @@ CookieService::GetCookieStringFromHttp(nsIURI* aHostURI, nsIChannel* aChannel,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
CookieService::SetCookieStringFromDocument(Document* aDocument,
|
||||
const nsACString& aCookieString) {
|
||||
NS_ENSURE_ARG(aDocument);
|
||||
|
||||
if (!IsInitialized()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> documentURI;
|
||||
nsAutoCString baseDomain;
|
||||
OriginAttributes attrs;
|
||||
|
||||
int64_t currentTimeInUsec = PR_Now();
|
||||
|
||||
// This function is executed in this context, I don't need to keep objects
|
||||
// alive.
|
||||
auto hasExistingCookiesLambda = [&](const nsACString& aBaseDomain,
|
||||
const OriginAttributes& aAttrs) {
|
||||
CookieStorage* storage = PickStorage(aAttrs);
|
||||
return !!storage->CountCookiesFromHost(aBaseDomain,
|
||||
aAttrs.mPrivateBrowsingId);
|
||||
};
|
||||
|
||||
auto* basePrincipal = BasePrincipal::Cast(aDocument->NodePrincipal());
|
||||
basePrincipal->GetURI(getter_AddRefs(documentURI));
|
||||
if (NS_WARN_IF(!documentURI)) {
|
||||
// Document's principal is not a content or null (may be system), so
|
||||
// can't set cookies
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Console report takes care of the correct reporting at the exit of this
|
||||
// method.
|
||||
RefPtr<ConsoleReportCollector> crc = new ConsoleReportCollector();
|
||||
auto scopeExit = MakeScopeExit([&] { crc->FlushConsoleReports(aDocument); });
|
||||
|
||||
CookieParser cookieParser(crc, documentURI);
|
||||
|
||||
RefPtr<Cookie> cookie = CookieCommons::CreateCookieFromDocument(
|
||||
cookieParser, aDocument, aCookieString, currentTimeInUsec, mTLDService,
|
||||
mThirdPartyUtil, hasExistingCookiesLambda, baseDomain, attrs);
|
||||
if (!cookie) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool thirdParty = true;
|
||||
nsPIDOMWindowInner* innerWindow = aDocument->GetInnerWindow();
|
||||
// in gtests we don't have a window, let's consider those requests as 3rd
|
||||
// party.
|
||||
if (innerWindow) {
|
||||
ThirdPartyUtil* thirdPartyUtil = ThirdPartyUtil::GetInstance();
|
||||
|
||||
if (thirdPartyUtil) {
|
||||
Unused << thirdPartyUtil->IsThirdPartyWindow(
|
||||
innerWindow->GetOuterWindow(), nullptr, &thirdParty);
|
||||
}
|
||||
}
|
||||
|
||||
if (thirdParty && !CookieCommons::ShouldIncludeCrossSiteCookieForDocument(
|
||||
cookie, aDocument)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// add the cookie to the list. AddCookie() takes care of logging.
|
||||
PickStorage(attrs)->AddCookie(
|
||||
&cookieParser, baseDomain, attrs, cookie, currentTimeInUsec, documentURI,
|
||||
aCookieString, false, thirdParty, aDocument->GetBrowsingContext());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
CookieService::SetCookieStringFromHttp(nsIURI* aHostURI,
|
||||
const nsACString& aCookieHeader,
|
||||
|
@ -1694,9 +1623,8 @@ bool CookieService::SetCookiesFromIPC(const nsACString& aBaseDomain,
|
|||
}
|
||||
|
||||
void CookieService::GetCookiesFromHost(
|
||||
const nsACString& aBaseDomain,
|
||||
const mozilla::OriginAttributes& aOriginAttributes,
|
||||
nsTArray<RefPtr<mozilla::net::Cookie>>& aCookies) {
|
||||
const nsACString& aBaseDomain, const OriginAttributes& aOriginAttributes,
|
||||
nsTArray<RefPtr<Cookie>>& aCookies) {
|
||||
if (!IsInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
@ -1705,9 +1633,8 @@ void CookieService::GetCookiesFromHost(
|
|||
storage->GetCookiesFromHost(aBaseDomain, aOriginAttributes, aCookies);
|
||||
}
|
||||
|
||||
void CookieService::StaleCookies(
|
||||
const nsTArray<RefPtr<mozilla::net::Cookie>>& aCookies,
|
||||
int64_t aCurrentTimeInUsec) {
|
||||
void CookieService::StaleCookies(const nsTArray<RefPtr<Cookie>>& aCookies,
|
||||
int64_t aCurrentTimeInUsec) {
|
||||
if (!IsInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
@ -1727,5 +1654,37 @@ void CookieService::StaleCookies(
|
|||
storage->StaleCookies(aCookies, aCurrentTimeInUsec);
|
||||
}
|
||||
|
||||
bool CookieService::HasExistingCookies(
|
||||
const nsACString& aBaseDomain, const OriginAttributes& aOriginAttributes) {
|
||||
if (!IsInitialized()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CookieStorage* storage = PickStorage(aOriginAttributes);
|
||||
return !!storage->CountCookiesFromHost(aBaseDomain,
|
||||
aOriginAttributes.mPrivateBrowsingId);
|
||||
}
|
||||
|
||||
void CookieService::AddCookieFromDocument(
|
||||
CookieParser& aCookieParser, const nsACString& aBaseDomain,
|
||||
const OriginAttributes& aOriginAttributes, Cookie& aCookie,
|
||||
int64_t aCurrentTimeInUsec, nsIURI* aDocumentURI, bool aThirdParty,
|
||||
Document* aDocument) {
|
||||
MOZ_ASSERT(aDocumentURI);
|
||||
MOZ_ASSERT(aDocument);
|
||||
|
||||
if (!IsInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoCString cookieString;
|
||||
aCookieParser.GetCookieString(cookieString);
|
||||
|
||||
PickStorage(aOriginAttributes)
|
||||
->AddCookie(&aCookieParser, aBaseDomain, aOriginAttributes, &aCookie,
|
||||
aCurrentTimeInUsec, aDocumentURI, cookieString, false,
|
||||
aThirdParty, aDocument->GetBrowsingContext());
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -272,17 +272,6 @@ IPCResult CookieServiceChild::RecvTrackCookiesLoad(
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
uint32_t CookieServiceChild::CountCookiesFromHashTable(
|
||||
const nsACString& aBaseDomain, const OriginAttributes& aOriginAttrs) {
|
||||
CookiesList* cookiesList = nullptr;
|
||||
|
||||
nsCString baseDomain;
|
||||
CookieKey key(aBaseDomain, aOriginAttrs);
|
||||
mCookiesMap.Get(key, &cookiesList);
|
||||
|
||||
return cookiesList ? cookiesList->Length() : 0;
|
||||
}
|
||||
|
||||
/* static */ bool CookieServiceChild::RequireThirdPartyCheck(
|
||||
nsILoadInfo* aLoadInfo) {
|
||||
if (!aLoadInfo) {
|
||||
|
@ -352,123 +341,6 @@ CookieServiceChild::GetCookieStringFromHttp(nsIURI* /*aHostURI*/,
|
|||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
CookieServiceChild::SetCookieStringFromDocument(
|
||||
dom::Document* aDocument, const nsACString& aCookieString) {
|
||||
NS_ENSURE_ARG(aDocument);
|
||||
|
||||
nsCOMPtr<nsIURI> documentURI;
|
||||
nsAutoCString baseDomain;
|
||||
OriginAttributes attrs;
|
||||
|
||||
// This function is executed in this context, I don't need to keep objects
|
||||
// alive.
|
||||
auto hasExistingCookiesLambda = [&](const nsACString& aBaseDomain,
|
||||
const OriginAttributes& aAttrs) {
|
||||
return !!CountCookiesFromHashTable(aBaseDomain, aAttrs);
|
||||
};
|
||||
|
||||
auto* basePrincipal = BasePrincipal::Cast(aDocument->NodePrincipal());
|
||||
basePrincipal->GetURI(getter_AddRefs(documentURI));
|
||||
if (NS_WARN_IF(!documentURI)) {
|
||||
// Document's principal is not a content or null (may be system), so
|
||||
// can't set cookies
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Console report takes care of the correct reporting at the exit of this
|
||||
// method.
|
||||
RefPtr<ConsoleReportCollector> crc = new ConsoleReportCollector();
|
||||
auto scopeExit = MakeScopeExit([&] { crc->FlushConsoleReports(aDocument); });
|
||||
|
||||
CookieParser cookieParser(crc, documentURI);
|
||||
|
||||
RefPtr<Cookie> cookie = CookieCommons::CreateCookieFromDocument(
|
||||
cookieParser, aDocument, aCookieString, PR_Now(), mTLDService,
|
||||
mThirdPartyUtil, hasExistingCookiesLambda, baseDomain, attrs);
|
||||
if (!cookie) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool thirdParty = true;
|
||||
nsPIDOMWindowInner* innerWindow = aDocument->GetInnerWindow();
|
||||
// in gtests we don't have a window, let's consider those requests as 3rd
|
||||
// party.
|
||||
if (innerWindow) {
|
||||
ThirdPartyUtil* thirdPartyUtil = ThirdPartyUtil::GetInstance();
|
||||
|
||||
if (thirdPartyUtil) {
|
||||
Unused << thirdPartyUtil->IsThirdPartyWindow(
|
||||
innerWindow->GetOuterWindow(), nullptr, &thirdParty);
|
||||
}
|
||||
}
|
||||
|
||||
if (thirdParty && !CookieCommons::ShouldIncludeCrossSiteCookieForDocument(
|
||||
cookie, aDocument)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
CookieKey key(baseDomain, attrs);
|
||||
CookiesList* cookies = mCookiesMap.Get(key);
|
||||
|
||||
if (cookies) {
|
||||
// We need to see if the cookie we're setting would overwrite an httponly
|
||||
// or a secure one. This would not affect anything we send over the net
|
||||
// (those come from the parent, which already checks this),
|
||||
// but script could see an inconsistent view of things.
|
||||
|
||||
// CHIPS - If the cookie has the "Partitioned" attribute set it will be
|
||||
// stored in the partitioned cookie jar.
|
||||
bool needPartitioned = StaticPrefs::network_cookie_CHIPS_enabled() &&
|
||||
cookie->RawIsPartitioned();
|
||||
nsCOMPtr<nsIPrincipal> principal =
|
||||
needPartitioned ? aDocument->PartitionedPrincipal()
|
||||
: aDocument->EffectiveCookiePrincipal();
|
||||
bool isPotentiallyTrustworthy =
|
||||
principal->GetIsOriginPotentiallyTrustworthy();
|
||||
|
||||
for (uint32_t i = 0; i < cookies->Length(); ++i) {
|
||||
RefPtr<Cookie> existingCookie = cookies->ElementAt(i);
|
||||
if (existingCookie->Name().Equals(cookie->Name()) &&
|
||||
existingCookie->Host().Equals(cookie->Host()) &&
|
||||
existingCookie->Path().Equals(cookie->Path())) {
|
||||
// Can't overwrite an httponly cookie from a script context.
|
||||
if (existingCookie->IsHttpOnly()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// prevent insecure cookie from overwriting a secure one in insecure
|
||||
// context.
|
||||
if (existingCookie->IsSecure() && !isPotentiallyTrustworthy) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RecordDocumentCookie(cookie, attrs);
|
||||
|
||||
if (CanSend()) {
|
||||
nsTArray<CookieStruct> cookiesToSend;
|
||||
cookiesToSend.AppendElement(cookie->ToIPC());
|
||||
|
||||
// Asynchronously call the parent.
|
||||
dom::WindowGlobalChild* windowGlobalChild =
|
||||
aDocument->GetWindowGlobalChild();
|
||||
|
||||
// If there is no WindowGlobalChild fall back to PCookieService SetCookies.
|
||||
if (NS_WARN_IF(!windowGlobalChild)) {
|
||||
SendSetCookies(baseDomain, attrs, documentURI, false, thirdParty,
|
||||
cookiesToSend);
|
||||
return NS_OK;
|
||||
}
|
||||
windowGlobalChild->SendSetCookies(baseDomain, attrs, documentURI, false,
|
||||
thirdParty, cookiesToSend);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
CookieServiceChild::SetCookieStringFromHttp(nsIURI* aHostURI,
|
||||
const nsACString& aCookieString,
|
||||
|
@ -518,7 +390,7 @@ CookieServiceChild::SetCookieStringFromHttp(nsIURI* aHostURI,
|
|||
result.contains(ThirdPartyAnalysis::IsThirdPartySocialTrackingResource),
|
||||
result.contains(ThirdPartyAnalysis::IsStorageAccessPermissionGranted),
|
||||
aCookieString,
|
||||
CountCookiesFromHashTable(baseDomain, storagePrincipalOriginAttributes),
|
||||
HasExistingCookies(baseDomain, storagePrincipalOriginAttributes),
|
||||
storagePrincipalOriginAttributes, &rejectedReason);
|
||||
|
||||
if (cookieStatus != STATUS_ACCEPTED &&
|
||||
|
@ -653,9 +525,8 @@ CookieServiceChild::RunInTransaction(
|
|||
}
|
||||
|
||||
void CookieServiceChild::GetCookiesFromHost(
|
||||
const nsACString& aBaseDomain,
|
||||
const mozilla::OriginAttributes& aOriginAttributes,
|
||||
nsTArray<RefPtr<mozilla::net::Cookie>>& aCookies) {
|
||||
const nsACString& aBaseDomain, const OriginAttributes& aOriginAttributes,
|
||||
nsTArray<RefPtr<Cookie>>& aCookies) {
|
||||
CookieKey key(aBaseDomain, aOriginAttributes);
|
||||
|
||||
CookiesList* cookiesList = nullptr;
|
||||
|
@ -666,11 +537,89 @@ void CookieServiceChild::GetCookiesFromHost(
|
|||
}
|
||||
}
|
||||
|
||||
void CookieServiceChild::StaleCookies(
|
||||
const nsTArray<RefPtr<mozilla::net::Cookie>>& aCookies,
|
||||
int64_t aCurrentTimeInUsec) {
|
||||
void CookieServiceChild::StaleCookies(const nsTArray<RefPtr<Cookie>>& aCookies,
|
||||
int64_t aCurrentTimeInUsec) {
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
bool CookieServiceChild::HasExistingCookies(
|
||||
const nsACString& aBaseDomain, const OriginAttributes& aOriginAttributes) {
|
||||
CookiesList* cookiesList = nullptr;
|
||||
|
||||
CookieKey key(aBaseDomain, aOriginAttributes);
|
||||
mCookiesMap.Get(key, &cookiesList);
|
||||
|
||||
return cookiesList ? cookiesList->Length() : 0;
|
||||
}
|
||||
|
||||
void CookieServiceChild::AddCookieFromDocument(
|
||||
CookieParser& aCookieParser, const nsACString& aBaseDomain,
|
||||
const OriginAttributes& aOriginAttributes, Cookie& aCookie,
|
||||
int64_t aCurrentTimeInUsec, nsIURI* aDocumentURI, bool aThirdParty,
|
||||
dom::Document* aDocument) {
|
||||
MOZ_ASSERT(aDocumentURI);
|
||||
MOZ_ASSERT(aDocument);
|
||||
|
||||
CookieKey key(aBaseDomain, aOriginAttributes);
|
||||
CookiesList* cookies = mCookiesMap.Get(key);
|
||||
|
||||
if (cookies) {
|
||||
// We need to see if the cookie we're setting would overwrite an httponly
|
||||
// or a secure one. This would not affect anything we send over the net
|
||||
// (those come from the parent, which already checks this),
|
||||
// but script could see an inconsistent view of things.
|
||||
|
||||
// CHIPS - If the cookie has the "Partitioned" attribute set it will be
|
||||
// stored in the partitioned cookie jar.
|
||||
bool needPartitioned = StaticPrefs::network_cookie_CHIPS_enabled() &&
|
||||
aCookie.RawIsPartitioned();
|
||||
nsCOMPtr<nsIPrincipal> principal =
|
||||
needPartitioned ? aDocument->PartitionedPrincipal()
|
||||
: aDocument->EffectiveCookiePrincipal();
|
||||
bool isPotentiallyTrustworthy =
|
||||
principal->GetIsOriginPotentiallyTrustworthy();
|
||||
|
||||
for (uint32_t i = 0; i < cookies->Length(); ++i) {
|
||||
RefPtr<Cookie> existingCookie = cookies->ElementAt(i);
|
||||
if (existingCookie->Name().Equals(aCookie.Name()) &&
|
||||
existingCookie->Host().Equals(aCookie.Host()) &&
|
||||
existingCookie->Path().Equals(aCookie.Path())) {
|
||||
// Can't overwrite an httponly cookie from a script context.
|
||||
if (existingCookie->IsHttpOnly()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// prevent insecure cookie from overwriting a secure one in insecure
|
||||
// context.
|
||||
if (existingCookie->IsSecure() && !isPotentiallyTrustworthy) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RecordDocumentCookie(&aCookie, aOriginAttributes);
|
||||
|
||||
if (CanSend()) {
|
||||
nsTArray<CookieStruct> cookiesToSend;
|
||||
cookiesToSend.AppendElement(aCookie.ToIPC());
|
||||
|
||||
// Asynchronously call the parent.
|
||||
dom::WindowGlobalChild* windowGlobalChild =
|
||||
aDocument->GetWindowGlobalChild();
|
||||
|
||||
// If there is no WindowGlobalChild fall back to PCookieService SetCookies.
|
||||
if (NS_WARN_IF(!windowGlobalChild)) {
|
||||
SendSetCookies(aBaseDomain, aOriginAttributes, aDocumentURI, false,
|
||||
aThirdParty, cookiesToSend);
|
||||
return;
|
||||
}
|
||||
|
||||
windowGlobalChild->SendSetCookies(aBaseDomain, aOriginAttributes,
|
||||
aDocumentURI, false, aThirdParty,
|
||||
cookiesToSend);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -48,9 +48,6 @@ class CookieServiceChild final : public PCookieServiceChild,
|
|||
|
||||
void RecordDocumentCookie(Cookie* aCookie, const OriginAttributes& aAttrs);
|
||||
|
||||
uint32_t CountCookiesFromHashTable(const nsACString& aBaseDomain,
|
||||
const OriginAttributes& aOriginAttrs);
|
||||
|
||||
static bool RequireThirdPartyCheck(nsILoadInfo* aLoadInfo);
|
||||
|
||||
mozilla::ipc::IPCResult RecvTrackCookiesLoad(
|
||||
|
|
|
@ -16,12 +16,15 @@ namespace mozilla {
|
|||
|
||||
namespace net {
|
||||
class Cookie;
|
||||
class CookieParser;
|
||||
}
|
||||
}
|
||||
%}
|
||||
|
||||
[ref] native const_OriginAttributes(const mozilla::OriginAttributes);
|
||||
native CookiePtr(RefPtr<mozilla::net::Cookie>);
|
||||
native CookieRefPtr(RefPtr<mozilla::net::Cookie>);
|
||||
[ref] native CookiePtr(mozilla::net::Cookie);
|
||||
[ref] native CookieParserPtr(mozilla::net::CookieParser);
|
||||
|
||||
/**
|
||||
* @see nsICookieService::runInTransaction
|
||||
|
@ -88,12 +91,26 @@ interface nsICookieService : nsISupports
|
|||
*/
|
||||
[noscript, notxpcom, nostdcall] void getCookiesFromHost(in ACString aBaseDomain,
|
||||
in const_OriginAttributes aOriginAttributes,
|
||||
out Array<CookiePtr> aCookies);
|
||||
out Array<CookieRefPtr> aCookies);
|
||||
|
||||
/* Update the last access to stale cookies */
|
||||
[noscript, notxpcom, nostdcall] void staleCookies(in Array<CookiePtr> aCookies,
|
||||
[noscript, notxpcom, nostdcall] void staleCookies(in Array<CookieRefPtr> aCookies,
|
||||
in int64_t aCurrentTimeInUsec);
|
||||
|
||||
/* Return true if there are existing cookies for the host and OriginAttributes. */
|
||||
[noscript, notxpcom, nostdcall] boolean hasExistingCookies(in ACString aBaseDomain,
|
||||
in const_OriginAttributes aOriginAttributes);
|
||||
|
||||
/* Return true if there are existing cookies for the host and OriginAttributes. */
|
||||
[noscript, notxpcom, nostdcall] void addCookieFromDocument(in CookieParserPtr aCookieParser,
|
||||
in ACString aBaseDomain,
|
||||
in const_OriginAttributes aOriginAttributes,
|
||||
in CookiePtr aCookie,
|
||||
in int64_t aCurrentTimeInUsec,
|
||||
in nsIURI aDocumentURI,
|
||||
in boolean aThirdParty,
|
||||
in Document document);
|
||||
|
||||
/*
|
||||
* Get the complete cookie string associated with the URI.
|
||||
*
|
||||
|
@ -112,18 +129,6 @@ interface nsICookieService : nsISupports
|
|||
*/
|
||||
ACString getCookieStringFromHttp(in nsIURI aURI, in nsIChannel aChannel);
|
||||
|
||||
/*
|
||||
* Set the cookie string associated with a Document. This method is meant to
|
||||
* be used for `document.cookie` only. Any security check about
|
||||
* storage-access permission and cookie behavior must be done by the caller.
|
||||
*
|
||||
* @param aDocument
|
||||
* The document.
|
||||
* @param aCookie
|
||||
* the cookie string to set.
|
||||
*/
|
||||
void setCookieStringFromDocument(in Document aDocument, in ACString aCookie);
|
||||
|
||||
/*
|
||||
* Set the cookie string and expires associated with the URI.
|
||||
*
|
||||
|
|
|
@ -82,9 +82,9 @@ const unpartitionedOAs = createOriginAttributes("");
|
|||
|
||||
// Set partitioned and unpartitioned cookie from first-party document.
|
||||
// CHIPS "Partitioned" cookie MUST always be stored in partitioned jar.
|
||||
// This calls CookieServiceChild::SetCookieStringFromDocument() internally.
|
||||
// CookieService::SetCookieStringFromDocument() is not explicitly tested since
|
||||
// CHIPS are in the common function CookieCommons::CreateCookieFromDocument().
|
||||
// This uses CookieServiceChild internally. CookieService is not explicitly
|
||||
// tested since CHIPS are in the common function
|
||||
// CookieCommons::CreateCookieFromDocument().
|
||||
add_task(
|
||||
async function test_chips_store_partitioned_document_first_party_child() {
|
||||
const tab = BrowserTestUtils.addTab(gBrowser, URL_DOCUMENT_FIRSTPARTY);
|
||||
|
@ -126,9 +126,9 @@ add_task(
|
|||
|
||||
// Set partitioned and unpartitioned cookie from third-party document with storage
|
||||
// access. CHIPS "Partitioned" cookie MUST always be stored in partitioned jar.
|
||||
// This calls CookieServiceChild::SetCookieStringFromDocument() internally.
|
||||
// CookieService::SetCookieStringFromDocument() is not explicitly tested since
|
||||
// CHIPS are in the common function CookieCommons::CreateCookieFromDocument().
|
||||
// This uses CookieServiceChild internally. CookieService is not explicitly
|
||||
// tested since CHIPS are in the common function
|
||||
// CookieCommons::CreateCookieFromDocument().
|
||||
add_task(
|
||||
async function test_chips_store_partitioned_document_third_party_storage_access_child() {
|
||||
const tab = BrowserTestUtils.addTab(gBrowser, URL_DOCUMENT_FIRSTPARTY);
|
||||
|
|
|
@ -157,7 +157,7 @@ void GetACookieNoHttp(nsICookieService* aCookieService, const char* aSpec,
|
|||
nsAutoString cookie;
|
||||
ErrorResult err;
|
||||
document->GetCookie(cookie, err);
|
||||
MOZ_ASSERT(!err.Failed());
|
||||
EXPECT_TRUE(!err.Failed());
|
||||
|
||||
CopyUTF16toUTF8(cookie, aCookie);
|
||||
}
|
||||
|
@ -213,6 +213,9 @@ void InitPrefs(nsIPrefBranch* aPrefBranch) {
|
|||
Preferences::SetBool("network.cookieJarSettings.unblocked_for_testing", true);
|
||||
Preferences::SetBool("dom.securecontext.allowlist_onions", false);
|
||||
Preferences::SetBool("network.cookie.sameSite.schemeful", false);
|
||||
|
||||
// Disable a few security checks for document.cookie
|
||||
Preferences::SetBool("dom.cookie.testing.enabled", true);
|
||||
}
|
||||
|
||||
TEST(TestCookie, TestCookieMain)
|
||||
|
|
|
@ -234,7 +234,7 @@ add_task(async () => {
|
|||
await testDomainCookie("http://co.uk/", "co.uk");
|
||||
|
||||
// Test that trailing dots are treated differently for purposes of the
|
||||
// 'domain' attribute when using setCookieStringFromDocument.
|
||||
// 'domain' attribute.
|
||||
await testTrailingDotCookie("http://localhost/", "localhost");
|
||||
await testTrailingDotCookie("http://foo.com/", "foo.com");
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
// Note that E2E test doesn't seem possible via setting a cookie
|
||||
// from xpcshell (main process) since:
|
||||
// 1. setCookieStringFromHttp requires a valid URL
|
||||
// 2. setCookieStringFromDocument requires access to the document
|
||||
// 2. document.cookie requires access to the document
|
||||
// 3. Services.cookies.add() is just a backdoor that will bypass
|
||||
// Similarly, even with a browser test, in order to call
|
||||
// content.document.cookie we would need to SpecialPowers.spawn
|
||||
|
|
|
@ -7708,7 +7708,6 @@ interface nsICookieService extends nsISupports {
|
|||
readonly BEHAVIOR_LAST: 5;
|
||||
|
||||
getCookieStringFromHttp(aURI: nsIURI, aChannel: nsIChannel): string;
|
||||
setCookieStringFromDocument(aDocument: Document, aCookie: string): void;
|
||||
setCookieStringFromHttp(aURI: nsIURI, aCookie: string, aChannel: nsIChannel): void;
|
||||
runInTransaction(aCallback: nsICookieTransactionCallback): void;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче