summaryrefslogtreecommitdiffstats
path: root/netwerk/cookie/CookieService.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/cookie/CookieService.cpp')
-rw-r--r--netwerk/cookie/CookieService.cpp431
1 files changed, 231 insertions, 200 deletions
diff --git a/netwerk/cookie/CookieService.cpp b/netwerk/cookie/CookieService.cpp
index d306203c2f..0e90b8cbae 100644
--- a/netwerk/cookie/CookieService.cpp
+++ b/netwerk/cookie/CookieService.cpp
@@ -13,6 +13,7 @@
#include "mozilla/dom/Document.h"
#include "mozilla/dom/nsMixedContentBlocker.h"
#include "mozilla/dom/Promise.h"
+#include "mozilla/glean/GleanMetrics.h"
#include "mozilla/net/CookieJarSettings.h"
#include "mozilla/net/CookiePersistentStorage.h"
#include "mozilla/net/CookiePrivateStorage.h"
@@ -372,44 +373,14 @@ CookieService::GetCookieStringFromDocument(Document* aDocument,
return NS_OK;
}
- nsCOMPtr<nsIPrincipal> principal = aDocument->EffectiveCookiePrincipal();
+ nsCOMPtr<nsIPrincipal> cookiePrincipal =
+ aDocument->EffectiveCookiePrincipal();
- if (!CookieCommons::IsSchemeSupported(principal)) {
- return NS_OK;
- }
-
- CookieStorage* storage = PickStorage(principal->OriginAttributesRef());
-
- nsAutoCString baseDomain;
- rv = CookieCommons::GetBaseDomain(principal, baseDomain);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return NS_OK;
- }
-
- nsAutoCString hostFromURI;
- rv = nsContentUtils::GetHostOrIPv6WithBrackets(principal, hostFromURI);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return NS_OK;
- }
-
- nsAutoCString pathFromURI;
- rv = principal->GetFilePath(pathFromURI);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return NS_OK;
- }
-
- int64_t currentTimeInUsec = PR_Now();
- int64_t currentTime = currentTimeInUsec / PR_USEC_PER_SEC;
-
- const nsTArray<RefPtr<Cookie>>* cookies =
- storage->GetCookiesFromHost(baseDomain, principal->OriginAttributesRef());
- if (!cookies) {
- return NS_OK;
- }
-
- // check if the nsIPrincipal is using an https secure protocol.
- // if it isn't, then we can't send a secure cookie over the connection.
- bool potentiallyTrustworthy = principal->GetIsOriginPotentiallyTrustworthy();
+ // TODO (Bug 1874174): A document could access both unpartitioned and
+ // partitioned cookie jars. We will need to prepare partitioned and
+ // unpartitioned principals for access both cookie jars.
+ nsTArray<nsCOMPtr<nsIPrincipal>> principals;
+ principals.AppendElement(cookiePrincipal);
bool thirdParty = true;
nsPIDOMWindowInner* innerWindow = aDocument->GetInnerWindow();
@@ -424,47 +395,98 @@ CookieService::GetCookieStringFromDocument(Document* aDocument,
}
}
- bool stale = false;
nsTArray<Cookie*> cookieList;
- // iterate the cookies!
- for (Cookie* cookie : *cookies) {
- // check the host, since the base domain lookup is conservative.
- if (!CookieCommons::DomainMatches(cookie, hostFromURI)) {
- continue;
+ for (auto& principal : principals) {
+ if (!CookieCommons::IsSchemeSupported(principal)) {
+ return NS_OK;
}
- // if the cookie is httpOnly and it's not going directly to the HTTP
- // connection, don't send it
- if (cookie->IsHttpOnly()) {
- continue;
+ CookieStorage* storage = PickStorage(principal->OriginAttributesRef());
+
+ nsAutoCString baseDomain;
+ rv = CookieCommons::GetBaseDomain(principal, baseDomain);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return NS_OK;
}
- if (thirdParty && !CookieCommons::ShouldIncludeCrossSiteCookieForDocument(
- cookie, aDocument)) {
- continue;
+ nsAutoCString hostFromURI;
+ rv = nsContentUtils::GetHostOrIPv6WithBrackets(principal, hostFromURI);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return NS_OK;
}
- // if the cookie is secure and the host scheme isn't, we can't send it
- if (cookie->IsSecure() && !potentiallyTrustworthy) {
- continue;
+ nsAutoCString pathFromURI;
+ rv = principal->GetFilePath(pathFromURI);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return NS_OK;
}
- // if the nsIURI path doesn't match the cookie path, don't send it back
- if (!CookieCommons::PathMatches(cookie, pathFromURI)) {
+ int64_t currentTimeInUsec = PR_Now();
+ int64_t currentTime = currentTimeInUsec / PR_USEC_PER_SEC;
+
+ const nsTArray<RefPtr<Cookie>>* cookies = storage->GetCookiesFromHost(
+ baseDomain, principal->OriginAttributesRef());
+ if (!cookies) {
continue;
}
- // check if the cookie has expired
- if (cookie->Expiry() <= currentTime) {
+ // check if the nsIPrincipal is using an https secure protocol.
+ // if it isn't, then we can't send a secure cookie over the connection.
+ bool potentiallyTrustworthy =
+ principal->GetIsOriginPotentiallyTrustworthy();
+
+ bool stale = false;
+
+ // iterate the cookies!
+ for (Cookie* cookie : *cookies) {
+ // check the host, since the base domain lookup is conservative.
+ if (!CookieCommons::DomainMatches(cookie, hostFromURI)) {
+ continue;
+ }
+
+ // if the cookie is httpOnly and it's not going directly to the HTTP
+ // connection, don't send it
+ if (cookie->IsHttpOnly()) {
+ continue;
+ }
+
+ if (thirdParty && !CookieCommons::ShouldIncludeCrossSiteCookieForDocument(
+ cookie, aDocument)) {
+ continue;
+ }
+
+ // if the cookie is secure and the host scheme isn't, we can't send it
+ if (cookie->IsSecure() && !potentiallyTrustworthy) {
+ continue;
+ }
+
+ // if the nsIURI path doesn't match the cookie path, don't send it back
+ if (!CookieCommons::PathMatches(cookie, pathFromURI)) {
+ continue;
+ }
+
+ // check if the cookie has expired
+ if (cookie->Expiry() <= currentTime) {
+ continue;
+ }
+
+ // all checks passed - add to list and check if lastAccessed stamp needs
+ // updating
+ cookieList.AppendElement(cookie);
+ if (cookie->IsStale()) {
+ stale = true;
+ }
+ }
+
+ if (cookieList.IsEmpty()) {
continue;
}
- // all checks passed - add to list and check if lastAccessed stamp needs
- // updating
- cookieList.AppendElement(cookie);
- if (cookie->IsStale()) {
- stale = true;
+ // update lastAccessed timestamps. we only do this if the timestamp is stale
+ // by a certain amount, to avoid thrashing the db during pageload.
+ if (stale) {
+ storage->StaleCookies(cookieList, currentTimeInUsec);
}
}
@@ -472,12 +494,6 @@ CookieService::GetCookieStringFromDocument(Document* aDocument,
return NS_OK;
}
- // update lastAccessed timestamps. we only do this if the timestamp is stale
- // by a certain amount, to avoid thrashing the db during pageload.
- if (stale) {
- storage->StaleCookies(cookieList, currentTimeInUsec);
- }
-
// return cookies in order of path length; longest to shortest.
// this is required per RFC2109. if cookies match in length,
// then sort by creation time (see bug 236772).
@@ -512,6 +528,12 @@ CookieService::GetCookieStringFromHttp(nsIURI* aHostURI, nsIChannel* aChannel,
bool isSameSiteForeign = CookieCommons::IsSameSiteForeign(
aChannel, aHostURI, &hadCrossSiteRedirects);
+ // TODO (Bug 1874174): A channel could load both unpartitioned and partitioned
+ // cookie jars together. We will need to get cookies from both unpartitioned
+ // and partitioned cookie jars according to storage access.
+ nsTArray<OriginAttributes> originAttributesList;
+ originAttributesList.AppendElement(attrs);
+
AutoTArray<Cookie*, 8> foundCookieList;
GetCookiesForURI(
aHostURI, aChannel, result.contains(ThirdPartyAnalysis::IsForeign),
@@ -519,7 +541,8 @@ CookieService::GetCookieStringFromHttp(nsIURI* aHostURI, nsIChannel* aChannel,
result.contains(ThirdPartyAnalysis::IsThirdPartySocialTrackingResource),
result.contains(ThirdPartyAnalysis::IsStorageAccessPermissionGranted),
rejectedReason, isSafeTopLevelNav, isSameSiteForeign,
- hadCrossSiteRedirects, true, false, attrs, foundCookieList);
+ hadCrossSiteRedirects, true, false, originAttributesList,
+ foundCookieList);
ComposeCookieString(foundCookieList, aCookieString);
@@ -936,7 +959,8 @@ void CookieService::GetCookiesForURI(
bool aIsSafeTopLevelNav, bool aIsSameSiteForeign,
bool aHadCrossSiteRedirects, bool aHttpBound,
bool aAllowSecureCookiesToInsecureOrigin,
- const OriginAttributes& aOriginAttrs, nsTArray<Cookie*>& aCookieList) {
+ const nsTArray<OriginAttributes>& aOriginAttrsList,
+ nsTArray<Cookie*>& aCookieList) {
NS_ASSERTION(aHostURI, "null host!");
if (!CookieCommons::IsSchemeSupported(aHostURI)) {
@@ -947,152 +971,165 @@ void CookieService::GetCookiesForURI(
return;
}
- CookieStorage* storage = PickStorage(aOriginAttrs);
-
- // get the base domain, host, and path from the URI.
- // e.g. for "www.bbc.co.uk", the base domain would be "bbc.co.uk".
- // file:// URI's (i.e. with an empty host) are allowed, but any other
- // scheme must have a non-empty host. A trailing dot in the host
- // is acceptable.
- bool requireHostMatch;
- nsAutoCString baseDomain;
- nsAutoCString hostFromURI;
- nsAutoCString pathFromURI;
- nsresult rv = CookieCommons::GetBaseDomain(mTLDService, aHostURI, baseDomain,
- requireHostMatch);
- if (NS_SUCCEEDED(rv)) {
- rv = nsContentUtils::GetHostOrIPv6WithBrackets(aHostURI, hostFromURI);
- }
- if (NS_SUCCEEDED(rv)) {
- rv = aHostURI->GetFilePath(pathFromURI);
- }
- if (NS_FAILED(rv)) {
- COOKIE_LOGFAILURE(GET_COOKIE, aHostURI, VoidCString(),
- "invalid host/path from URI");
- return;
- }
-
nsCOMPtr<nsICookieJarSettings> cookieJarSettings =
CookieCommons::GetCookieJarSettings(aChannel);
- nsAutoCString normalizedHostFromURI(hostFromURI);
- rv = NormalizeHost(normalizedHostFromURI);
- NS_ENSURE_SUCCESS_VOID(rv);
-
- nsAutoCString baseDomainFromURI;
- rv = CookieCommons::GetBaseDomainFromHost(mTLDService, normalizedHostFromURI,
- baseDomainFromURI);
- NS_ENSURE_SUCCESS_VOID(rv);
-
- // check default prefs
- uint32_t rejectedReason = aRejectedReason;
- uint32_t priorCookieCount = storage->CountCookiesFromHost(
- baseDomainFromURI, aOriginAttrs.mPrivateBrowsingId);
-
nsCOMPtr<nsIConsoleReportCollector> crc = do_QueryInterface(aChannel);
- CookieStatus cookieStatus = CheckPrefs(
- crc, cookieJarSettings, aHostURI, aIsForeign,
- aIsThirdPartyTrackingResource, aIsThirdPartySocialTrackingResource,
- aStorageAccessPermissionGranted, VoidCString(), priorCookieCount,
- aOriginAttrs, &rejectedReason);
-
- MOZ_ASSERT_IF(rejectedReason, cookieStatus == STATUS_REJECTED);
- // for GetCookie(), we only fire acceptance/rejection notifications
- // (but not if there was an error)
- switch (cookieStatus) {
- case STATUS_REJECTED:
- // If we don't have any cookies from this host, fail silently.
- if (priorCookieCount) {
- CookieCommons::NotifyRejected(aHostURI, aChannel, rejectedReason,
- OPERATION_READ);
- }
+ for (const auto& attrs : aOriginAttrsList) {
+ CookieStorage* storage = PickStorage(attrs);
+
+ // get the base domain, host, and path from the URI.
+ // e.g. for "www.bbc.co.uk", the base domain would be "bbc.co.uk".
+ // file:// URI's (i.e. with an empty host) are allowed, but any other
+ // scheme must have a non-empty host. A trailing dot in the host
+ // is acceptable.
+ bool requireHostMatch;
+ nsAutoCString baseDomain;
+ nsAutoCString hostFromURI;
+ nsAutoCString pathFromURI;
+ nsresult rv = CookieCommons::GetBaseDomain(mTLDService, aHostURI,
+ baseDomain, requireHostMatch);
+ if (NS_SUCCEEDED(rv)) {
+ rv = nsContentUtils::GetHostOrIPv6WithBrackets(aHostURI, hostFromURI);
+ }
+ if (NS_SUCCEEDED(rv)) {
+ rv = aHostURI->GetFilePath(pathFromURI);
+ }
+ if (NS_FAILED(rv)) {
+ COOKIE_LOGFAILURE(GET_COOKIE, aHostURI, VoidCString(),
+ "invalid host/path from URI");
return;
- default:
- break;
- }
-
- // Note: The following permissions logic is mirrored in
- // extensions::MatchPattern::MatchesCookie.
- // If it changes, please update that function, or file a bug for someone
- // else to do so.
+ }
- // check if aHostURI is using an https secure protocol.
- // if it isn't, then we can't send a secure cookie over the connection.
- // if SchemeIs fails, assume an insecure connection, to be on the safe side
- bool potentiallyTrustworthy =
- nsMixedContentBlocker::IsPotentiallyTrustworthyOrigin(aHostURI);
+ nsAutoCString normalizedHostFromURI(hostFromURI);
+ rv = NormalizeHost(normalizedHostFromURI);
+ NS_ENSURE_SUCCESS_VOID(rv);
+
+ nsAutoCString baseDomainFromURI;
+ rv = CookieCommons::GetBaseDomainFromHost(
+ mTLDService, normalizedHostFromURI, baseDomainFromURI);
+ NS_ENSURE_SUCCESS_VOID(rv);
+
+ // check default prefs
+ uint32_t rejectedReason = aRejectedReason;
+ uint32_t priorCookieCount = storage->CountCookiesFromHost(
+ baseDomainFromURI, attrs.mPrivateBrowsingId);
+
+ CookieStatus cookieStatus = CheckPrefs(
+ crc, cookieJarSettings, aHostURI, aIsForeign,
+ aIsThirdPartyTrackingResource, aIsThirdPartySocialTrackingResource,
+ aStorageAccessPermissionGranted, VoidCString(), priorCookieCount, attrs,
+ &rejectedReason);
+
+ MOZ_ASSERT_IF(rejectedReason, cookieStatus == STATUS_REJECTED);
+
+ // for GetCookie(), we only fire acceptance/rejection notifications
+ // (but not if there was an error)
+ switch (cookieStatus) {
+ case STATUS_REJECTED:
+ // If we don't have any cookies from this host, fail silently.
+ if (priorCookieCount) {
+ CookieCommons::NotifyRejected(aHostURI, aChannel, rejectedReason,
+ OPERATION_READ);
+ }
+ return;
+ default:
+ break;
+ }
- int64_t currentTimeInUsec = PR_Now();
- int64_t currentTime = currentTimeInUsec / PR_USEC_PER_SEC;
- bool stale = false;
+ // Note: The following permissions logic is mirrored in
+ // extensions::MatchPattern::MatchesCookie.
+ // If it changes, please update that function, or file a bug for someone
+ // else to do so.
- const nsTArray<RefPtr<Cookie>>* cookies =
- storage->GetCookiesFromHost(baseDomain, aOriginAttrs);
- if (!cookies) {
- return;
- }
+ // check if aHostURI is using an https secure protocol.
+ // if it isn't, then we can't send a secure cookie over the connection.
+ // if SchemeIs fails, assume an insecure connection, to be on the safe side
+ bool potentiallyTrustworthy =
+ nsMixedContentBlocker::IsPotentiallyTrustworthyOrigin(aHostURI);
- bool laxByDefault =
- StaticPrefs::network_cookie_sameSite_laxByDefault() &&
- !nsContentUtils::IsURIInPrefList(
- aHostURI, "network.cookie.sameSite.laxByDefault.disabledHosts");
+ int64_t currentTimeInUsec = PR_Now();
+ int64_t currentTime = currentTimeInUsec / PR_USEC_PER_SEC;
+ bool stale = false;
- // iterate the cookies!
- for (Cookie* cookie : *cookies) {
- // check the host, since the base domain lookup is conservative.
- if (!CookieCommons::DomainMatches(cookie, hostFromURI)) {
+ const nsTArray<RefPtr<Cookie>>* cookies =
+ storage->GetCookiesFromHost(baseDomain, attrs);
+ if (!cookies) {
continue;
}
- // if the cookie is secure and the host scheme isn't, we avoid sending
- // cookie if possible. But for process synchronization purposes, we may want
- // the content process to know about the cookie (without it's value). In
- // which case we will wipe the value before sending
- if (cookie->IsSecure() && !potentiallyTrustworthy &&
- !aAllowSecureCookiesToInsecureOrigin) {
- continue;
- }
+ bool laxByDefault =
+ StaticPrefs::network_cookie_sameSite_laxByDefault() &&
+ !nsContentUtils::IsURIInPrefList(
+ aHostURI, "network.cookie.sameSite.laxByDefault.disabledHosts");
- // if the cookie is httpOnly and it's not going directly to the HTTP
- // connection, don't send it
- if (cookie->IsHttpOnly() && !aHttpBound) {
- continue;
- }
+ // iterate the cookies!
+ for (Cookie* cookie : *cookies) {
+ // check the host, since the base domain lookup is conservative.
+ if (!CookieCommons::DomainMatches(cookie, hostFromURI)) {
+ continue;
+ }
- // if the nsIURI path doesn't match the cookie path, don't send it back
- if (!CookieCommons::PathMatches(cookie, pathFromURI)) {
- continue;
- }
+ // if the cookie is secure and the host scheme isn't, we avoid sending
+ // cookie if possible. But for process synchronization purposes, we may
+ // want the content process to know about the cookie (without it's value).
+ // In which case we will wipe the value before sending
+ if (cookie->IsSecure() && !potentiallyTrustworthy &&
+ !aAllowSecureCookiesToInsecureOrigin) {
+ continue;
+ }
- // check if the cookie has expired
- if (cookie->Expiry() <= currentTime) {
- continue;
- }
+ // if the cookie is httpOnly and it's not going directly to the HTTP
+ // connection, don't send it
+ if (cookie->IsHttpOnly() && !aHttpBound) {
+ continue;
+ }
- if (aHttpBound && aIsSameSiteForeign) {
- bool blockCookie = !ProcessSameSiteCookieForForeignRequest(
- aChannel, cookie, aIsSafeTopLevelNav, aHadCrossSiteRedirects,
- laxByDefault);
-
- if (blockCookie) {
- if (aHadCrossSiteRedirects) {
- CookieLogging::LogMessageToConsole(
- crc, aHostURI, nsIScriptError::warningFlag,
- CONSOLE_REJECTION_CATEGORY, "CookieBlockedCrossSiteRedirect"_ns,
- AutoTArray<nsString, 1>{
- NS_ConvertUTF8toUTF16(cookie->Name()),
- });
- }
+ // if the nsIURI path doesn't match the cookie path, don't send it back
+ if (!CookieCommons::PathMatches(cookie, pathFromURI)) {
continue;
}
+
+ // check if the cookie has expired
+ if (cookie->Expiry() <= currentTime) {
+ continue;
+ }
+
+ if (aHttpBound && aIsSameSiteForeign) {
+ bool blockCookie = !ProcessSameSiteCookieForForeignRequest(
+ aChannel, cookie, aIsSafeTopLevelNav, aHadCrossSiteRedirects,
+ laxByDefault);
+
+ if (blockCookie) {
+ if (aHadCrossSiteRedirects) {
+ CookieLogging::LogMessageToConsole(
+ crc, aHostURI, nsIScriptError::warningFlag,
+ CONSOLE_REJECTION_CATEGORY, "CookieBlockedCrossSiteRedirect"_ns,
+ AutoTArray<nsString, 1>{
+ NS_ConvertUTF8toUTF16(cookie->Name()),
+ });
+ }
+ continue;
+ }
+ }
+
+ // all checks passed - add to list and check if lastAccessed stamp needs
+ // updating
+ aCookieList.AppendElement(cookie);
+ if (cookie->IsStale()) {
+ stale = true;
+ }
}
- // all checks passed - add to list and check if lastAccessed stamp needs
- // updating
- aCookieList.AppendElement(cookie);
- if (cookie->IsStale()) {
- stale = true;
+ if (aCookieList.IsEmpty()) {
+ continue;
+ }
+
+ // update lastAccessed timestamps. we only do this if the timestamp is stale
+ // by a certain amount, to avoid thrashing the db during pageload.
+ if (stale) {
+ storage->StaleCookies(aCookieList, currentTimeInUsec);
}
}
@@ -1104,12 +1141,6 @@ void CookieService::GetCookiesForURI(
// some.
NotifyAccepted(aChannel);
- // update lastAccessed timestamps. we only do this if the timestamp is stale
- // by a certain amount, to avoid thrashing the db during pageload.
- if (stale) {
- storage->StaleCookies(aCookieList, currentTimeInUsec);
- }
-
// return cookies in order of path length; longest to shortest.
// this is required per RFC2109. if cookies match in length,
// then sort by creation time (see bug 236772).