mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 23:31:56 +00:00
6ff16b6810
Differential Revision: https://phabricator.services.mozilla.com/D146346
659 lines
21 KiB
C++
659 lines
21 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "Cookie.h"
|
|
#include "CookieCommons.h"
|
|
#include "CookieLogging.h"
|
|
#include "CookieService.h"
|
|
#include "mozilla/net/CookieServiceChild.h"
|
|
#include "mozilla/net/NeckoChannelParams.h"
|
|
#include "mozilla/LoadInfo.h"
|
|
#include "mozilla/BasePrincipal.h"
|
|
#include "mozilla/ClearOnShutdown.h"
|
|
#include "mozilla/dom/ContentChild.h"
|
|
#include "mozilla/dom/Document.h"
|
|
#include "mozilla/ipc/URIUtils.h"
|
|
#include "mozilla/net/NeckoChild.h"
|
|
#include "mozilla/StaticPrefs_network.h"
|
|
#include "mozilla/StoragePrincipalHelper.h"
|
|
#include "nsNetCID.h"
|
|
#include "nsNetUtil.h"
|
|
#include "nsICookieJarSettings.h"
|
|
#include "nsIChannel.h"
|
|
#include "nsIClassifiedChannel.h"
|
|
#include "nsIHttpChannel.h"
|
|
#include "nsIEffectiveTLDService.h"
|
|
#include "nsIURI.h"
|
|
#include "nsIPrefBranch.h"
|
|
#include "nsIWebProgressListener.h"
|
|
#include "nsServiceManagerUtils.h"
|
|
#include "mozilla/Telemetry.h"
|
|
#include "mozilla/TimeStamp.h"
|
|
#include "ThirdPartyUtil.h"
|
|
#include "nsIConsoleReportCollector.h"
|
|
|
|
using namespace mozilla::ipc;
|
|
|
|
namespace mozilla {
|
|
namespace net {
|
|
|
|
// Pref string constants
|
|
static const char kCookieMoveIntervalSecs[] =
|
|
"network.cookie.move.interval_sec";
|
|
|
|
static StaticRefPtr<CookieServiceChild> gCookieChildService;
|
|
static uint32_t gMoveCookiesIntervalSeconds = 10;
|
|
|
|
already_AddRefed<CookieServiceChild> CookieServiceChild::GetSingleton() {
|
|
if (!gCookieChildService) {
|
|
gCookieChildService = new CookieServiceChild();
|
|
ClearOnShutdown(&gCookieChildService);
|
|
}
|
|
|
|
return do_AddRef(gCookieChildService);
|
|
}
|
|
|
|
NS_IMPL_ISUPPORTS(CookieServiceChild, nsICookieService, nsIObserver,
|
|
nsITimerCallback, nsINamed, nsISupportsWeakReference)
|
|
|
|
CookieServiceChild::CookieServiceChild() {
|
|
NS_ASSERTION(IsNeckoChild(), "not a child process");
|
|
|
|
auto* cc = static_cast<mozilla::dom::ContentChild*>(gNeckoChild->Manager());
|
|
if (cc->IsShuttingDown()) {
|
|
return;
|
|
}
|
|
|
|
// This corresponds to Release() in DeallocPCookieService.
|
|
NS_ADDREF_THIS();
|
|
|
|
NeckoChild::InitNeckoChild();
|
|
|
|
// Create a child PCookieService actor.
|
|
gNeckoChild->SendPCookieServiceConstructor(this);
|
|
|
|
mThirdPartyUtil = ThirdPartyUtil::GetInstance();
|
|
NS_ASSERTION(mThirdPartyUtil, "couldn't get ThirdPartyUtil service");
|
|
|
|
mTLDService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
|
|
NS_ASSERTION(mTLDService, "couldn't get TLDService");
|
|
|
|
// Init our prefs and observer.
|
|
nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
|
NS_WARNING_ASSERTION(prefBranch, "no prefservice");
|
|
if (prefBranch) {
|
|
prefBranch->AddObserver(kCookieMoveIntervalSecs, this, true);
|
|
PrefChanged(prefBranch);
|
|
}
|
|
|
|
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
|
|
if (observerService) {
|
|
observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
|
|
}
|
|
}
|
|
|
|
void CookieServiceChild::MoveCookies() {
|
|
TimeStamp start = TimeStamp::Now();
|
|
for (const auto& cookiesList : mCookiesMap.Values()) {
|
|
CookiesList newCookiesList;
|
|
for (uint32_t i = 0; i < cookiesList->Length(); ++i) {
|
|
Cookie* cookie = cookiesList->ElementAt(i);
|
|
RefPtr<Cookie> newCookie = cookie->Clone();
|
|
newCookiesList.AppendElement(newCookie);
|
|
}
|
|
*cookiesList = std::move(newCookiesList);
|
|
}
|
|
|
|
Telemetry::AccumulateTimeDelta(Telemetry::COOKIE_TIME_MOVING_MS, start);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
CookieServiceChild::Notify(nsITimer* aTimer) {
|
|
if (aTimer == mCookieTimer) {
|
|
MoveCookies();
|
|
} else {
|
|
MOZ_CRASH("Unknown timer");
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
CookieServiceChild::GetName(nsACString& aName) {
|
|
aName.AssignLiteral("CookieServiceChild");
|
|
return NS_OK;
|
|
}
|
|
|
|
CookieServiceChild::~CookieServiceChild() { gCookieChildService = nullptr; }
|
|
|
|
void CookieServiceChild::TrackCookieLoad(nsIChannel* aChannel) {
|
|
if (!CanSend()) {
|
|
return;
|
|
}
|
|
|
|
uint32_t rejectedReason = 0;
|
|
ThirdPartyAnalysisResult result = mThirdPartyUtil->AnalyzeChannel(
|
|
aChannel, true, nullptr, RequireThirdPartyCheck, &rejectedReason);
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
aChannel->GetURI(getter_AddRefs(uri));
|
|
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
|
|
|
|
OriginAttributes attrs = loadInfo->GetOriginAttributes();
|
|
StoragePrincipalHelper::PrepareEffectiveStoragePrincipalOriginAttributes(
|
|
aChannel, attrs);
|
|
|
|
bool isSafeTopLevelNav = CookieCommons::IsSafeTopLevelNav(aChannel);
|
|
bool hadCrossSiteRedirects = false;
|
|
bool isSameSiteForeign =
|
|
CookieCommons::IsSameSiteForeign(aChannel, uri, &hadCrossSiteRedirects);
|
|
SendPrepareCookieList(
|
|
uri, result.contains(ThirdPartyAnalysis::IsForeign),
|
|
result.contains(ThirdPartyAnalysis::IsThirdPartyTrackingResource),
|
|
result.contains(ThirdPartyAnalysis::IsThirdPartySocialTrackingResource),
|
|
result.contains(ThirdPartyAnalysis::IsStorageAccessPermissionGranted),
|
|
rejectedReason, isSafeTopLevelNav, isSameSiteForeign,
|
|
hadCrossSiteRedirects, attrs);
|
|
}
|
|
|
|
IPCResult CookieServiceChild::RecvRemoveAll() {
|
|
mCookiesMap.Clear();
|
|
return IPC_OK();
|
|
}
|
|
|
|
IPCResult CookieServiceChild::RecvRemoveCookie(const CookieStruct& aCookie,
|
|
const OriginAttributes& aAttrs) {
|
|
nsCString baseDomain;
|
|
CookieCommons::GetBaseDomainFromHost(mTLDService, aCookie.host(), baseDomain);
|
|
CookieKey key(baseDomain, aAttrs);
|
|
CookiesList* cookiesList = nullptr;
|
|
mCookiesMap.Get(key, &cookiesList);
|
|
|
|
if (!cookiesList) {
|
|
return IPC_OK();
|
|
}
|
|
|
|
for (uint32_t i = 0; i < cookiesList->Length(); i++) {
|
|
Cookie* cookie = cookiesList->ElementAt(i);
|
|
if (cookie->Name().Equals(aCookie.name()) &&
|
|
cookie->Host().Equals(aCookie.host()) &&
|
|
cookie->Path().Equals(aCookie.path())) {
|
|
cookiesList->RemoveElementAt(i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return IPC_OK();
|
|
}
|
|
|
|
IPCResult CookieServiceChild::RecvAddCookie(const CookieStruct& aCookie,
|
|
const OriginAttributes& aAttrs) {
|
|
RefPtr<Cookie> cookie = Cookie::Create(aCookie, aAttrs);
|
|
RecordDocumentCookie(cookie, aAttrs);
|
|
|
|
// signal test code to check their cookie list
|
|
nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
|
|
if (obsService) {
|
|
obsService->NotifyObservers(nullptr, "cookie-content-filter-test", nullptr);
|
|
}
|
|
|
|
return IPC_OK();
|
|
}
|
|
|
|
IPCResult CookieServiceChild::RecvRemoveBatchDeletedCookies(
|
|
nsTArray<CookieStruct>&& aCookiesList,
|
|
nsTArray<OriginAttributes>&& aAttrsList) {
|
|
MOZ_ASSERT(aCookiesList.Length() == aAttrsList.Length());
|
|
for (uint32_t i = 0; i < aCookiesList.Length(); i++) {
|
|
CookieStruct cookieStruct = aCookiesList.ElementAt(i);
|
|
RecvRemoveCookie(cookieStruct, aAttrsList.ElementAt(i));
|
|
}
|
|
return IPC_OK();
|
|
}
|
|
|
|
IPCResult CookieServiceChild::RecvTrackCookiesLoad(
|
|
nsTArray<CookieStruct>&& aCookiesList, const OriginAttributes& aAttrs) {
|
|
for (uint32_t i = 0; i < aCookiesList.Length(); i++) {
|
|
RefPtr<Cookie> cookie = Cookie::Create(aCookiesList[i], aAttrs);
|
|
cookie->SetIsHttpOnly(false);
|
|
RecordDocumentCookie(cookie, aAttrs);
|
|
}
|
|
|
|
return IPC_OK();
|
|
}
|
|
|
|
void CookieServiceChild::PrefChanged(nsIPrefBranch* aPrefBranch) {
|
|
int32_t val;
|
|
if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kCookieMoveIntervalSecs, &val))) {
|
|
gMoveCookiesIntervalSeconds = clamped<uint32_t>(val, 0, 3600);
|
|
if (gMoveCookiesIntervalSeconds && !mCookieTimer) {
|
|
NS_NewTimerWithCallback(getter_AddRefs(mCookieTimer), this,
|
|
gMoveCookiesIntervalSeconds * 1000,
|
|
nsITimer::TYPE_REPEATING_SLACK_LOW_PRIORITY);
|
|
}
|
|
if (!gMoveCookiesIntervalSeconds && mCookieTimer) {
|
|
mCookieTimer->Cancel();
|
|
mCookieTimer = nullptr;
|
|
}
|
|
if (mCookieTimer) {
|
|
mCookieTimer->SetDelay(gMoveCookiesIntervalSeconds * 1000);
|
|
}
|
|
}
|
|
}
|
|
|
|
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) {
|
|
return false;
|
|
}
|
|
|
|
nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
|
|
nsresult rv =
|
|
aLoadInfo->GetCookieJarSettings(getter_AddRefs(cookieJarSettings));
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return false;
|
|
}
|
|
|
|
uint32_t cookieBehavior = cookieJarSettings->GetCookieBehavior();
|
|
return cookieBehavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN ||
|
|
cookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN ||
|
|
cookieBehavior == nsICookieService::BEHAVIOR_REJECT_TRACKER ||
|
|
cookieBehavior ==
|
|
nsICookieService::BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN ||
|
|
StaticPrefs::network_cookie_thirdparty_sessionOnly() ||
|
|
StaticPrefs::network_cookie_thirdparty_nonsecureSessionOnly();
|
|
}
|
|
|
|
void CookieServiceChild::RecordDocumentCookie(Cookie* aCookie,
|
|
const OriginAttributes& aAttrs) {
|
|
nsAutoCString baseDomain;
|
|
CookieCommons::GetBaseDomainFromHost(mTLDService, aCookie->Host(),
|
|
baseDomain);
|
|
|
|
CookieKey key(baseDomain, aAttrs);
|
|
CookiesList* cookiesList = nullptr;
|
|
mCookiesMap.Get(key, &cookiesList);
|
|
|
|
if (!cookiesList) {
|
|
cookiesList = mCookiesMap.GetOrInsertNew(key);
|
|
}
|
|
for (uint32_t i = 0; i < cookiesList->Length(); i++) {
|
|
Cookie* cookie = cookiesList->ElementAt(i);
|
|
if (cookie->Name().Equals(aCookie->Name()) &&
|
|
cookie->Host().Equals(aCookie->Host()) &&
|
|
cookie->Path().Equals(aCookie->Path())) {
|
|
if (cookie->Value().Equals(aCookie->Value()) &&
|
|
cookie->Expiry() == aCookie->Expiry() &&
|
|
cookie->IsSecure() == aCookie->IsSecure() &&
|
|
cookie->SameSite() == aCookie->SameSite() &&
|
|
cookie->RawSameSite() == aCookie->RawSameSite() &&
|
|
cookie->IsSession() == aCookie->IsSession() &&
|
|
cookie->IsHttpOnly() == aCookie->IsHttpOnly()) {
|
|
cookie->SetLastAccessed(aCookie->LastAccessed());
|
|
return;
|
|
}
|
|
cookiesList->RemoveElementAt(i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
int64_t currentTime = PR_Now() / PR_USEC_PER_SEC;
|
|
if (aCookie->Expiry() <= currentTime) {
|
|
return;
|
|
}
|
|
|
|
cookiesList->AppendElement(aCookie);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
CookieServiceChild::Observe(nsISupports* aSubject, const char* aTopic,
|
|
const char16_t* /*aData*/) {
|
|
if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
|
|
if (mCookieTimer) {
|
|
mCookieTimer->Cancel();
|
|
mCookieTimer = nullptr;
|
|
}
|
|
nsCOMPtr<nsIObserverService> observerService =
|
|
services::GetObserverService();
|
|
if (observerService) {
|
|
observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
|
|
}
|
|
} else if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
|
|
nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(aSubject);
|
|
if (prefBranch) {
|
|
PrefChanged(prefBranch);
|
|
}
|
|
} else {
|
|
MOZ_ASSERT(false, "unexpected topic!");
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
CookieServiceChild::GetCookieStringFromDocument(dom::Document* aDocument,
|
|
nsACString& aCookieString) {
|
|
NS_ENSURE_ARG(aDocument);
|
|
|
|
aCookieString.Truncate();
|
|
|
|
nsCOMPtr<nsIPrincipal> principal = aDocument->EffectiveCookiePrincipal();
|
|
|
|
if (!CookieCommons::IsSchemeSupported(principal)) {
|
|
return NS_OK;
|
|
}
|
|
|
|
nsAutoCString baseDomain;
|
|
nsresult rv = CookieCommons::GetBaseDomain(principal, baseDomain);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return NS_OK;
|
|
}
|
|
|
|
CookieKey key(baseDomain, principal->OriginAttributesRef());
|
|
CookiesList* cookiesList = nullptr;
|
|
mCookiesMap.Get(key, &cookiesList);
|
|
|
|
if (!cookiesList) {
|
|
return NS_OK;
|
|
}
|
|
|
|
nsAutoCString hostFromURI;
|
|
rv = nsContentUtils::GetHostOrIPv6WithBrackets(principal, hostFromURI);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return NS_OK;
|
|
}
|
|
|
|
nsAutoCString pathFromURI;
|
|
principal->GetFilePath(pathFromURI);
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
bool isPotentiallyTrustworthy =
|
|
principal->GetIsOriginPotentiallyTrustworthy();
|
|
int64_t currentTimeInUsec = PR_Now();
|
|
int64_t currentTime = currentTimeInUsec / PR_USEC_PER_SEC;
|
|
|
|
cookiesList->Sort(CompareCookiesForSending());
|
|
for (uint32_t i = 0; i < cookiesList->Length(); i++) {
|
|
Cookie* cookie = cookiesList->ElementAt(i);
|
|
// check the host, since the base domain lookup is conservative.
|
|
if (!CookieCommons::DomainMatches(cookie, hostFromURI)) {
|
|
continue;
|
|
}
|
|
|
|
// We don't show HttpOnly cookies in content processes.
|
|
if (cookie->IsHttpOnly()) {
|
|
continue;
|
|
}
|
|
|
|
if (thirdParty &&
|
|
!CookieCommons::ShouldIncludeCrossSiteCookieForDocument(cookie)) {
|
|
continue;
|
|
}
|
|
|
|
// if the cookie is secure and the host scheme isn't, we can't send it
|
|
if (cookie->IsSecure() && !isPotentiallyTrustworthy) {
|
|
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;
|
|
}
|
|
|
|
if (!cookie->Name().IsEmpty() || !cookie->Value().IsEmpty()) {
|
|
if (!aCookieString.IsEmpty()) {
|
|
aCookieString.AppendLiteral("; ");
|
|
}
|
|
if (!cookie->Name().IsEmpty()) {
|
|
aCookieString.Append(cookie->Name().get());
|
|
aCookieString.AppendLiteral("=");
|
|
aCookieString.Append(cookie->Value().get());
|
|
} else {
|
|
aCookieString.Append(cookie->Value().get());
|
|
}
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
CookieServiceChild::GetCookieStringFromHttp(nsIURI* /*aHostURI*/,
|
|
nsIChannel* /*aChannel*/,
|
|
nsACString& /*aCookieString*/) {
|
|
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);
|
|
};
|
|
|
|
RefPtr<Cookie> cookie = CookieCommons::CreateCookieFromDocument(
|
|
aDocument, aCookieString, PR_Now(), mTLDService, mThirdPartyUtil,
|
|
hasExistingCookiesLambda, getter_AddRefs(documentURI), 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)) {
|
|
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
|
|
// 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.
|
|
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()) &&
|
|
existingCookie->IsHttpOnly()) {
|
|
// Can't overwrite an httponly cookie from a script context.
|
|
return NS_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
RecordDocumentCookie(cookie, attrs);
|
|
|
|
if (CanSend()) {
|
|
nsTArray<CookieStruct> cookiesToSend;
|
|
cookiesToSend.AppendElement(cookie->ToIPC());
|
|
|
|
// Asynchronously call the parent.
|
|
SendSetCookies(baseDomain, attrs, documentURI, false, cookiesToSend);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
CookieServiceChild::SetCookieStringFromHttp(nsIURI* aHostURI,
|
|
const nsACString& aCookieString,
|
|
nsIChannel* aChannel) {
|
|
NS_ENSURE_ARG(aHostURI);
|
|
NS_ENSURE_ARG(aChannel);
|
|
|
|
if (!CookieCommons::IsSchemeSupported(aHostURI)) {
|
|
return NS_OK;
|
|
}
|
|
|
|
// Fast past: don't bother sending IPC messages about nullprincipal'd
|
|
// documents.
|
|
nsAutoCString scheme;
|
|
aHostURI->GetScheme(scheme);
|
|
if (scheme.EqualsLiteral("moz-nullprincipal")) {
|
|
return NS_OK;
|
|
}
|
|
|
|
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
|
|
|
|
uint32_t rejectedReason = 0;
|
|
ThirdPartyAnalysisResult result = mThirdPartyUtil->AnalyzeChannel(
|
|
aChannel, false, aHostURI, RequireThirdPartyCheck, &rejectedReason);
|
|
|
|
nsCString cookieString(aCookieString);
|
|
|
|
OriginAttributes attrs = loadInfo->GetOriginAttributes();
|
|
StoragePrincipalHelper::PrepareEffectiveStoragePrincipalOriginAttributes(
|
|
aChannel, attrs);
|
|
|
|
bool requireHostMatch;
|
|
nsCString baseDomain;
|
|
CookieCommons::GetBaseDomain(mTLDService, aHostURI, baseDomain,
|
|
requireHostMatch);
|
|
|
|
nsCOMPtr<nsICookieJarSettings> cookieJarSettings =
|
|
CookieCommons::GetCookieJarSettings(aChannel);
|
|
|
|
nsCOMPtr<nsIConsoleReportCollector> crc = do_QueryInterface(aChannel);
|
|
|
|
CookieStatus cookieStatus = CookieService::CheckPrefs(
|
|
crc, cookieJarSettings, aHostURI,
|
|
result.contains(ThirdPartyAnalysis::IsForeign),
|
|
result.contains(ThirdPartyAnalysis::IsThirdPartyTrackingResource),
|
|
result.contains(ThirdPartyAnalysis::IsThirdPartySocialTrackingResource),
|
|
result.contains(ThirdPartyAnalysis::IsStorageAccessPermissionGranted),
|
|
aCookieString, CountCookiesFromHashTable(baseDomain, attrs), attrs,
|
|
&rejectedReason);
|
|
|
|
if (cookieStatus != STATUS_ACCEPTED &&
|
|
cookieStatus != STATUS_ACCEPT_SESSION) {
|
|
return NS_OK;
|
|
}
|
|
|
|
CookieKey key(baseDomain, attrs);
|
|
|
|
nsTArray<CookieStruct> cookiesToSend;
|
|
|
|
int64_t currentTimeInUsec = PR_Now();
|
|
|
|
bool addonAllowsLoad = false;
|
|
nsCOMPtr<nsIURI> finalChannelURI;
|
|
NS_GetFinalChannelURI(aChannel, getter_AddRefs(finalChannelURI));
|
|
addonAllowsLoad = BasePrincipal::Cast(loadInfo->TriggeringPrincipal())
|
|
->AddonAllowsLoad(finalChannelURI);
|
|
|
|
bool isForeignAndNotAddon = false;
|
|
if (!addonAllowsLoad) {
|
|
mThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI,
|
|
&isForeignAndNotAddon);
|
|
}
|
|
|
|
bool moreCookies;
|
|
do {
|
|
CookieStruct cookieData;
|
|
bool canSetCookie = false;
|
|
moreCookies = CookieService::CanSetCookie(
|
|
aHostURI, baseDomain, cookieData, requireHostMatch, cookieStatus,
|
|
cookieString, true, isForeignAndNotAddon, crc, canSetCookie);
|
|
if (!canSetCookie) {
|
|
continue;
|
|
}
|
|
|
|
// check permissions from site permission list.
|
|
if (!CookieCommons::CheckCookiePermission(aChannel, cookieData)) {
|
|
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieString,
|
|
"cookie rejected by permission manager");
|
|
constexpr auto CONSOLE_REJECTION_CATEGORY = "cookiesRejection"_ns;
|
|
CookieLogging::LogMessageToConsole(
|
|
crc, aHostURI, nsIScriptError::warningFlag,
|
|
CONSOLE_REJECTION_CATEGORY, "CookieRejectedByPermissionManager"_ns,
|
|
AutoTArray<nsString, 1>{
|
|
NS_ConvertUTF8toUTF16(cookieData.name()),
|
|
});
|
|
CookieCommons::NotifyRejected(
|
|
aHostURI, aChannel,
|
|
nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION,
|
|
OPERATION_WRITE);
|
|
continue;
|
|
}
|
|
|
|
RefPtr<Cookie> cookie = Cookie::Create(cookieData, attrs);
|
|
MOZ_ASSERT(cookie);
|
|
|
|
cookie->SetLastAccessed(currentTimeInUsec);
|
|
cookie->SetCreationTime(
|
|
Cookie::GenerateUniqueCreationTime(currentTimeInUsec));
|
|
|
|
RecordDocumentCookie(cookie, attrs);
|
|
cookiesToSend.AppendElement(cookieData);
|
|
} while (moreCookies);
|
|
|
|
// Asynchronously call the parent.
|
|
if (CanSend() && !cookiesToSend.IsEmpty()) {
|
|
SendSetCookies(baseDomain, attrs, aHostURI, true, cookiesToSend);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
CookieServiceChild::RunInTransaction(
|
|
nsICookieTransactionCallback* /*aCallback*/) {
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
} // namespace net
|
|
} // namespace mozilla
|