gecko-dev/netwerk/cookie/CookieServiceChild.cpp
arthur.iakab 944263f18a Backed out 5 changesets (bug 1551798) for multiple build bustages on StaticPrefList.h CLOSED TREE
Backed out changeset c89daff34d97 (bug 1551798)
Backed out changeset bbc3f88b8c03 (bug 1551798)
Backed out changeset b87996b8a411 (bug 1551798)
Backed out changeset d88b0002d736 (bug 1551798)
Backed out changeset 0fe740c90e2b (bug 1551798)
2019-05-29 18:07:26 +03:00

718 lines
25 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 "mozilla/net/CookieServiceChild.h"
#include "mozilla/net/NeckoChannelParams.h"
#include "mozilla/AntiTrackingCommon.h"
#include "mozilla/LoadInfo.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/ipc/URIUtils.h"
#include "mozilla/net/NeckoChild.h"
#include "mozilla/SystemGroup.h"
#include "mozilla/StoragePrincipalHelper.h"
#include "nsCookie.h"
#include "nsCookieService.h"
#include "nsContentUtils.h"
#include "nsNetCID.h"
#include "nsNetUtil.h"
#include "nsIChannel.h"
#include "nsCookiePermission.h"
#include "nsIEffectiveTLDService.h"
#include "nsIURI.h"
#include "nsIPrefService.h"
#include "nsIPrefBranch.h"
#include "nsServiceManagerUtils.h"
#include "mozilla/Telemetry.h"
#include "mozilla/TimeStamp.h"
#include "ThirdPartyUtil.h"
using namespace mozilla::ipc;
using mozilla::OriginAttributes;
namespace mozilla {
namespace net {
// Pref string constants
static const char kPrefThirdPartySession[] =
"network.cookie.thirdparty.sessionOnly";
static const char kPrefThirdPartyNonsecureSession[] =
"network.cookie.thirdparty.nonsecureSessionOnly";
static const char kCookieMoveIntervalSecs[] =
"network.cookie.move.interval_sec";
static StaticRefPtr<CookieServiceChild> gCookieService;
static uint32_t gMoveCookiesIntervalSeconds = 10;
already_AddRefed<CookieServiceChild> CookieServiceChild::GetSingleton() {
if (!gCookieService) {
gCookieService = new CookieServiceChild();
ClearOnShutdown(&gCookieService);
}
return do_AddRef(gCookieService);
}
NS_IMPL_ISUPPORTS(CookieServiceChild, nsICookieService, nsIObserver,
nsITimerCallback, nsISupportsWeakReference)
CookieServiceChild::CookieServiceChild()
: mThirdPartySession(false),
mThirdPartyNonsecureSession(false),
mIPCOpen(false) {
NS_ASSERTION(IsNeckoChild(), "not a child process");
mozilla::dom::ContentChild* 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);
mIPCOpen = true;
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(kPrefThirdPartySession, this, true);
prefBranch->AddObserver(kPrefThirdPartyNonsecureSession, this, true);
prefBranch->AddObserver(kCookieMoveIntervalSecs, this, true);
PrefChanged(prefBranch);
}
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (observerService) {
observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
}
}
void CookieServiceChild::MoveCookies() {
TimeStamp start = TimeStamp::Now();
for (auto iter = mCookiesMap.Iter(); !iter.Done(); iter.Next()) {
CookiesList* cookiesList = iter.UserData();
CookiesList newCookiesList;
for (uint32_t i = 0; i < cookiesList->Length(); ++i) {
nsCookie* cookie = cookiesList->ElementAt(i);
RefPtr<nsCookie> newCookie = nsCookie::Create(
cookie->Name(), cookie->Value(), cookie->Host(), cookie->Path(),
cookie->Expiry(), cookie->LastAccessed(), cookie->CreationTime(),
cookie->IsSession(), cookie->IsSecure(), cookie->IsHttpOnly(),
cookie->OriginAttributesRef(), cookie->SameSite());
newCookiesList.AppendElement(newCookie);
}
cookiesList->SwapElements(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;
}
CookieServiceChild::~CookieServiceChild() { gCookieService = nullptr; }
void CookieServiceChild::ActorDestroy(ActorDestroyReason why) {
mIPCOpen = false;
}
void CookieServiceChild::TrackCookieLoad(nsIChannel* aChannel) {
if (!mIPCOpen) {
return;
}
bool isForeign = false;
bool isTrackingResource = false;
bool firstPartyStorageAccessGranted = false;
uint32_t rejectedReason = 0;
nsCOMPtr<nsIURI> uri;
aChannel->GetURI(getter_AddRefs(uri));
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
if (RequireThirdPartyCheck(loadInfo)) {
mThirdPartyUtil->IsThirdPartyChannel(aChannel, uri, &isForeign);
}
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
if (httpChannel) {
isTrackingResource = httpChannel->IsTrackingResource();
// Check first-party storage access even for non-tracking resources, since
// we will need the result when computing the access rights for the reject
// foreign cookie behavior mode.
if (isForeign && AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(
httpChannel, uri, &rejectedReason)) {
firstPartyStorageAccessGranted = true;
}
// We need to notify about the outcome of the content blocking check here
// since the parent process can't do it for us as it won't have a channel
// object handy.
if (!firstPartyStorageAccessGranted) {
AntiTrackingCommon::NotifyBlockingDecision(
aChannel, AntiTrackingCommon::BlockingDecision::eBlock,
rejectedReason);
}
}
mozilla::OriginAttributes attrs = loadInfo->GetOriginAttributes();
StoragePrincipalHelper::PrepareOriginAttributes(aChannel, attrs);
URIParams uriParams;
SerializeURI(uri, uriParams);
bool isSafeTopLevelNav = NS_IsSafeTopLevelNav(aChannel);
bool isSameSiteForeign = NS_IsSameSiteForeign(aChannel, uri);
SendPrepareCookieList(uriParams, isForeign, isTrackingResource,
firstPartyStorageAccessGranted, rejectedReason,
isSafeTopLevelNav, isSameSiteForeign, attrs);
}
mozilla::ipc::IPCResult CookieServiceChild::RecvRemoveAll() {
mCookiesMap.Clear();
return IPC_OK();
}
mozilla::ipc::IPCResult CookieServiceChild::RecvRemoveCookie(
const CookieStruct& aCookie, const OriginAttributes& aAttrs) {
nsCString baseDomain;
nsCookieService::GetBaseDomainFromHost(mTLDService, aCookie.host(),
baseDomain);
nsCookieKey key(baseDomain, aAttrs);
CookiesList* cookiesList = nullptr;
mCookiesMap.Get(key, &cookiesList);
if (!cookiesList) {
return IPC_OK();
}
for (uint32_t i = 0; i < cookiesList->Length(); i++) {
nsCookie* 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();
}
mozilla::ipc::IPCResult CookieServiceChild::RecvAddCookie(
const CookieStruct& aCookie, const OriginAttributes& aAttrs) {
RefPtr<nsCookie> cookie = nsCookie::Create(
aCookie.name(), aCookie.value(), aCookie.host(), aCookie.path(),
aCookie.expiry(), aCookie.lastAccessed(), aCookie.creationTime(),
aCookie.isSession(), aCookie.isSecure(), aCookie.isHttpOnly(), aAttrs,
aCookie.sameSite());
RecordDocumentCookie(cookie, aAttrs);
return IPC_OK();
}
mozilla::ipc::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();
}
mozilla::ipc::IPCResult CookieServiceChild::RecvTrackCookiesLoad(
nsTArray<CookieStruct>&& aCookiesList, const OriginAttributes& aAttrs) {
for (uint32_t i = 0; i < aCookiesList.Length(); i++) {
RefPtr<nsCookie> cookie = nsCookie::Create(
aCookiesList[i].name(), aCookiesList[i].value(), aCookiesList[i].host(),
aCookiesList[i].path(), aCookiesList[i].expiry(),
aCookiesList[i].lastAccessed(), aCookiesList[i].creationTime(),
aCookiesList[i].isSession(), aCookiesList[i].isSecure(), false, aAttrs,
aCookiesList[i].sameSite());
RecordDocumentCookie(cookie, aAttrs);
}
return IPC_OK();
}
void CookieServiceChild::PrefChanged(nsIPrefBranch* aPrefBranch) {
bool boolval;
if (NS_SUCCEEDED(aPrefBranch->GetBoolPref(kPrefThirdPartySession, &boolval)))
mThirdPartySession = !!boolval;
if (NS_SUCCEEDED(
aPrefBranch->GetBoolPref(kPrefThirdPartyNonsecureSession, &boolval)))
mThirdPartyNonsecureSession = boolval;
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);
}
}
}
void CookieServiceChild::GetCookieStringFromCookieHashTable(
nsIURI* aHostURI, bool aIsForeign, bool aIsTrackingResource,
bool aFirstPartyStorageAccessGranted, uint32_t aRejectedReason,
bool aIsSafeTopLevelNav, bool aIsSameSiteForeign, nsIChannel* aChannel,
nsCString& aCookieString) {
nsCOMPtr<nsIEffectiveTLDService> TLDService =
do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
NS_ASSERTION(TLDService, "Can't get TLDService");
bool requireHostMatch;
nsAutoCString baseDomain;
nsCOMPtr<nsILoadInfo> loadInfo;
mozilla::OriginAttributes attrs;
if (aChannel) {
loadInfo = aChannel->LoadInfo();
attrs = loadInfo->GetOriginAttributes();
StoragePrincipalHelper::PrepareOriginAttributes(aChannel, attrs);
}
nsCookieService::GetBaseDomain(TLDService, aHostURI, baseDomain,
requireHostMatch);
nsCookieKey key(baseDomain, attrs);
CookiesList* cookiesList = nullptr;
mCookiesMap.Get(key, &cookiesList);
if (!cookiesList) {
return;
}
nsAutoCString hostFromURI, pathFromURI;
bool isSecure;
aHostURI->GetAsciiHost(hostFromURI);
aHostURI->GetPathQueryRef(pathFromURI);
aHostURI->SchemeIs("https", &isSecure);
int64_t currentTimeInUsec = PR_Now();
int64_t currentTime = currentTimeInUsec / PR_USEC_PER_SEC;
nsCOMPtr<nsICookieSettings> cookieSettings =
nsCookieService::GetCookieSettings(aChannel);
CookieStatus cookieStatus = nsCookieService::CheckPrefs(
cookieSettings, mThirdPartySession, mThirdPartyNonsecureSession, aHostURI,
aIsForeign, aIsTrackingResource, aFirstPartyStorageAccessGranted, nullptr,
CountCookiesFromHashTable(baseDomain, attrs), attrs, &aRejectedReason);
if (cookieStatus != STATUS_ACCEPTED &&
cookieStatus != STATUS_ACCEPT_SESSION) {
return;
}
cookiesList->Sort(CompareCookiesForSending());
for (uint32_t i = 0; i < cookiesList->Length(); i++) {
nsCookie* cookie = cookiesList->ElementAt(i);
// check the host, since the base domain lookup is conservative.
if (!nsCookieService::DomainMatches(cookie, hostFromURI)) continue;
// We don't show HttpOnly cookies in content processes.
if (cookie->IsHttpOnly()) {
continue;
}
// if the cookie is secure and the host scheme isn't, we can't send it
if (cookie->IsSecure() && !isSecure) continue;
int32_t sameSiteAttr = 0;
cookie->GetSameSite(&sameSiteAttr);
if (aIsSameSiteForeign) {
// it if's a cross origin request and the cookie is same site only
// (strict) don't send it
if (sameSiteAttr == nsICookie2::SAMESITE_STRICT) {
continue;
}
// if it's a cross origin request, the cookie is same site lax, but it's
// not a top-level navigation, don't send it
if (sameSiteAttr == nsICookie2::SAMESITE_LAX && !aIsSafeTopLevelNav) {
continue;
}
}
// if the nsIURI path doesn't match the cookie path, don't send it back
if (!nsCookieService::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());
}
}
}
}
uint32_t CookieServiceChild::CountCookiesFromHashTable(
const nsCString& aBaseDomain, const OriginAttributes& aOriginAttrs) {
CookiesList* cookiesList = nullptr;
nsCString baseDomain;
nsCookieKey key(aBaseDomain, aOriginAttrs);
mCookiesMap.Get(key, &cookiesList);
return cookiesList ? cookiesList->Length() : 0;
}
void CookieServiceChild::SetCookieInternal(
nsCookieAttributes& aCookieAttributes,
const mozilla::OriginAttributes& aAttrs, nsIChannel* aChannel,
bool aFromHttp, nsICookiePermission* aPermissionService) {
int64_t currentTimeInUsec = PR_Now();
RefPtr<nsCookie> cookie = nsCookie::Create(
aCookieAttributes.name, aCookieAttributes.value, aCookieAttributes.host,
aCookieAttributes.path, aCookieAttributes.expiryTime, currentTimeInUsec,
nsCookie::GenerateUniqueCreationTime(currentTimeInUsec),
aCookieAttributes.isSession, aCookieAttributes.isSecure,
aCookieAttributes.isHttpOnly, aAttrs, aCookieAttributes.sameSite);
RecordDocumentCookie(cookie, aAttrs);
}
bool CookieServiceChild::RequireThirdPartyCheck(nsILoadInfo* aLoadInfo) {
if (!aLoadInfo) {
return false;
}
nsCOMPtr<nsICookieSettings> cookieSettings;
nsresult rv = aLoadInfo->GetCookieSettings(getter_AddRefs(cookieSettings));
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
uint32_t cookieBehavior = cookieSettings->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 ||
mThirdPartySession || mThirdPartyNonsecureSession;
}
void CookieServiceChild::RecordDocumentCookie(nsCookie* aCookie,
const OriginAttributes& aAttrs) {
nsAutoCString baseDomain;
nsCookieService::GetBaseDomainFromHost(mTLDService, aCookie->Host(),
baseDomain);
nsCookieKey key(baseDomain, aAttrs);
CookiesList* cookiesList = nullptr;
mCookiesMap.Get(key, &cookiesList);
if (!cookiesList) {
cookiesList = mCookiesMap.LookupOrAdd(key);
}
for (uint32_t i = 0; i < cookiesList->Length(); i++) {
nsCookie* 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->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);
}
nsresult CookieServiceChild::GetCookieStringInternal(nsIURI* aHostURI,
nsIChannel* aChannel,
char** aCookieString) {
NS_ENSURE_ARG(aHostURI);
NS_ENSURE_ARG_POINTER(aCookieString);
*aCookieString = nullptr;
// 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;
// Asynchronously call the parent.
bool isForeign = true;
nsCOMPtr<nsILoadInfo> loadInfo = aChannel ? aChannel->LoadInfo() : nullptr;
if (RequireThirdPartyCheck(loadInfo)) {
mThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI, &isForeign);
}
bool isTrackingResource = false;
bool firstPartyStorageAccessGranted = false;
uint32_t rejectedReason = 0;
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
if (httpChannel) {
isTrackingResource = httpChannel->IsTrackingResource();
// Check first-party storage access even for non-tracking resources, since
// we will need the result when computing the access rights for the reject
// foreign cookie behavior mode.
if (isForeign && AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(
httpChannel, aHostURI, &rejectedReason)) {
firstPartyStorageAccessGranted = true;
}
}
bool isSafeTopLevelNav = NS_IsSafeTopLevelNav(aChannel);
bool isSameSiteForeign = NS_IsSameSiteForeign(aChannel, aHostURI);
nsAutoCString result;
GetCookieStringFromCookieHashTable(
aHostURI, isForeign, isTrackingResource, firstPartyStorageAccessGranted,
rejectedReason, isSafeTopLevelNav, isSameSiteForeign, aChannel, result);
if (!result.IsEmpty()) *aCookieString = ToNewCString(result);
return NS_OK;
}
nsresult CookieServiceChild::SetCookieStringInternal(nsIURI* aHostURI,
nsIChannel* aChannel,
const char* aCookieString,
const char* aServerTime,
bool aFromHttp) {
NS_ENSURE_ARG(aHostURI);
NS_ENSURE_ARG_POINTER(aCookieString);
// 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;
// Determine whether the request is foreign. Failure is acceptable.
bool isForeign = true;
nsCOMPtr<nsILoadInfo> loadInfo = aChannel ? aChannel->LoadInfo() : nullptr;
if (RequireThirdPartyCheck(loadInfo)) {
mThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI, &isForeign);
}
bool isTrackingResource = false;
bool firstPartyStorageAccessGranted = false;
uint32_t rejectedReason = 0;
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
if (httpChannel) {
isTrackingResource = httpChannel->IsTrackingResource();
// Check first-party storage access even for non-tracking resources, since
// we will need the result when computing the access rights for the reject
// foreign cookie behavior mode.
if (isForeign && AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(
httpChannel, aHostURI, &rejectedReason)) {
firstPartyStorageAccessGranted = true;
}
}
nsDependentCString cookieString(aCookieString);
nsDependentCString stringServerTime;
if (aServerTime) stringServerTime.Rebind(aServerTime);
URIParams hostURIParams;
SerializeURI(aHostURI, hostURIParams);
Maybe<URIParams> channelURIParams;
mozilla::OriginAttributes attrs;
if (aChannel) {
nsCOMPtr<nsIURI> channelURI;
aChannel->GetURI(getter_AddRefs(channelURI));
SerializeURI(channelURI, channelURIParams);
MOZ_ASSERT(loadInfo);
attrs = loadInfo->GetOriginAttributes();
StoragePrincipalHelper::PrepareOriginAttributes(aChannel, attrs);
} else {
SerializeURI(nullptr, channelURIParams);
}
Maybe<LoadInfoArgs> optionalLoadInfoArgs;
LoadInfoToLoadInfoArgs(loadInfo, &optionalLoadInfoArgs);
// Asynchronously call the parent.
if (mIPCOpen) {
SendSetCookieString(hostURIParams, channelURIParams, optionalLoadInfoArgs,
isForeign, isTrackingResource,
firstPartyStorageAccessGranted, rejectedReason, attrs,
cookieString, stringServerTime, aFromHttp);
}
bool requireHostMatch;
nsCString baseDomain;
nsCookieService::GetBaseDomain(mTLDService, aHostURI, baseDomain,
requireHostMatch);
nsCOMPtr<nsICookieSettings> cookieSettings =
nsCookieService::GetCookieSettings(aChannel);
CookieStatus cookieStatus = nsCookieService::CheckPrefs(
cookieSettings, mThirdPartySession, mThirdPartyNonsecureSession, aHostURI,
isForeign, isTrackingResource, firstPartyStorageAccessGranted,
aCookieString, CountCookiesFromHashTable(baseDomain, attrs), attrs,
&rejectedReason);
if (cookieStatus != STATUS_ACCEPTED &&
cookieStatus != STATUS_ACCEPT_SESSION) {
return NS_OK;
}
nsCookieKey key(baseDomain, attrs);
CookiesList* cookies = mCookiesMap.Get(key);
nsCString serverTimeString(aServerTime);
int64_t serverTime = nsCookieService::ParseServerTime(serverTimeString);
bool moreCookies;
do {
nsCookieAttributes cookieAttributes;
bool canSetCookie = false;
moreCookies = nsCookieService::CanSetCookie(
aHostURI, key, cookieAttributes, requireHostMatch, cookieStatus,
cookieString, serverTime, aFromHttp, aChannel, canSetCookie,
mThirdPartyUtil);
// 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.
if (cookies && canSetCookie && !aFromHttp) {
for (uint32_t i = 0; i < cookies->Length(); ++i) {
RefPtr<nsCookie> cookie = cookies->ElementAt(i);
if (cookie->Name().Equals(cookieAttributes.name) &&
cookie->Host().Equals(cookieAttributes.host) &&
cookie->Path().Equals(cookieAttributes.path) &&
cookie->IsHttpOnly()) {
// Can't overwrite an httponly cookie from a script context.
canSetCookie = false;
}
}
}
if (canSetCookie) {
nsCOMPtr<nsICookiePermission> permissionService =
nsCookiePermission::GetOrCreate();
SetCookieInternal(cookieAttributes, attrs, aChannel, aFromHttp,
permissionService);
}
// document.cookie can only set one cookie at a time.
if (!aFromHttp) {
break;
}
} while (moreCookies);
return NS_OK;
}
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 =
mozilla::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::GetCookieString(nsIURI* aHostURI, nsIChannel* aChannel,
char** aCookieString) {
return GetCookieStringInternal(aHostURI, aChannel, aCookieString);
}
NS_IMETHODIMP
CookieServiceChild::GetCookieStringFromHttp(nsIURI* aHostURI, nsIURI* aFirstURI,
nsIChannel* aChannel,
char** aCookieString) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
CookieServiceChild::SetCookieString(nsIURI* aHostURI, nsIPrompt* aPrompt,
const char* aCookieString,
nsIChannel* aChannel) {
return SetCookieStringInternal(aHostURI, aChannel, aCookieString, nullptr,
false);
}
NS_IMETHODIMP
CookieServiceChild::SetCookieStringFromHttp(nsIURI* aHostURI, nsIURI* aFirstURI,
nsIPrompt* aPrompt,
const char* aCookieString,
const char* aServerTime,
nsIChannel* aChannel) {
return SetCookieStringInternal(aHostURI, aChannel, aCookieString, aServerTime,
true);
}
NS_IMETHODIMP
CookieServiceChild::RunInTransaction(nsICookieTransactionCallback* aCallback) {
return NS_ERROR_NOT_IMPLEMENTED;
}
} // namespace net
} // namespace mozilla