зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1632187 - Introduce nsICookieService::setCookieStringFromDocument - part 2 - implementation, r=mayhemer
Differential Revision: https://phabricator.services.mozilla.com/D71974
This commit is contained in:
Родитель
14236dd004
Коммит
871dd4ea6a
|
@ -5720,26 +5720,6 @@ void Document::SetCookie(const nsAString& aCookie, ErrorResult& aRv) {
|
|||
return;
|
||||
}
|
||||
|
||||
// The code for getting the URI matches Navigator::CookieEnabled
|
||||
nsCOMPtr<nsIURI> principalURI;
|
||||
auto* basePrin = BasePrincipal::Cast(NodePrincipal());
|
||||
basePrin->GetURI(getter_AddRefs(principalURI));
|
||||
|
||||
if (!principalURI) {
|
||||
// Document's principal is not a content or null (may be system), so
|
||||
// can't set cookies
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIChannel> channel(mChannel);
|
||||
if (!channel) {
|
||||
channel = CreateDummyChannelForCookies(principalURI);
|
||||
if (!channel) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// not having a cookie service isn't an error
|
||||
nsCOMPtr<nsICookieService> service =
|
||||
do_GetService(NS_COOKIESERVICE_CONTRACTID);
|
||||
|
@ -5748,7 +5728,7 @@ void Document::SetCookie(const nsAString& aCookie, ErrorResult& aRv) {
|
|||
}
|
||||
|
||||
NS_ConvertUTF16toUTF8 cookie(aCookie);
|
||||
nsresult rv = service->SetCookieString(principalURI, cookie, channel);
|
||||
nsresult rv = service->SetCookieStringFromDocument(this, cookie);
|
||||
|
||||
// No warning messages here.
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -5763,45 +5743,6 @@ void Document::SetCookie(const nsAString& aCookie, ErrorResult& aRv) {
|
|||
}
|
||||
}
|
||||
|
||||
already_AddRefed<nsIChannel> Document::CreateDummyChannelForCookies(
|
||||
nsIURI* aContentURI) {
|
||||
// The cookie service reads the privacy status of the channel we pass to it in
|
||||
// order to determine which cookie database to query. In some cases we don't
|
||||
// have a proper channel to hand it to the cookie service though. This
|
||||
// function creates a dummy channel that is not used to load anything, for the
|
||||
// sole purpose of handing it to the cookie service. DO NOT USE THIS CHANNEL
|
||||
// FOR ANY OTHER PURPOSE.
|
||||
MOZ_ASSERT(!mChannel);
|
||||
|
||||
// The following channel is never openend, so it does not matter what
|
||||
// securityFlags we pass; let's follow the principle of least privilege.
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
NS_NewChannel(getter_AddRefs(channel), aContentURI, this,
|
||||
nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED,
|
||||
nsIContentPolicy::TYPE_INVALID);
|
||||
nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel = do_QueryInterface(channel);
|
||||
nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
|
||||
nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
|
||||
if (!pbChannel || !loadContext) {
|
||||
return nullptr;
|
||||
}
|
||||
pbChannel->SetPrivate(loadContext->UsePrivateBrowsing());
|
||||
|
||||
// We need to set the hasStoragePermission for the dummy channel because we
|
||||
// will use this channel to do a content blocking check. The channel URI
|
||||
// is from the NodePrincipal of this document which is the inital document for
|
||||
// the 'about:blank' content viewer. In this case, the NodePrincipal is the
|
||||
// same as the parent document if the parent exists. So, we can copy the flag
|
||||
// from the parent document directly.
|
||||
bool parentDocHasStoragePermissin =
|
||||
mParentDocument ? mParentDocument->HasStoragePermission() : false;
|
||||
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
|
||||
Unused << loadInfo->SetHasStoragePermission(parentDocHasStoragePermissin);
|
||||
|
||||
return channel.forget();
|
||||
}
|
||||
|
||||
ReferrerPolicy Document::GetReferrerPolicy() const {
|
||||
return mReferrerInfo ? mReferrerInfo->ReferrerPolicy()
|
||||
: ReferrerPolicy::_empty;
|
||||
|
|
|
@ -4202,10 +4202,6 @@ class Document : public nsINode,
|
|||
MOZ_MUST_USE RefPtr<AutomaticStorageAccessGrantPromise>
|
||||
AutomaticStorageAccessCanBeGranted();
|
||||
|
||||
// This should *ONLY* be used in GetCookie/SetCookie.
|
||||
already_AddRefed<nsIChannel> CreateDummyChannelForCookies(
|
||||
nsIURI* aContentURI);
|
||||
|
||||
static void AddToplevelLoadingDocument(Document* aDoc);
|
||||
static void RemoveToplevelLoadingDocument(Document* aDoc);
|
||||
static AutoTArray<Document*, 8>* sLoadingForegroundTopLevelContentDocument;
|
||||
|
|
|
@ -5,13 +5,23 @@
|
|||
|
||||
#include "Cookie.h"
|
||||
#include "CookieCommons.h"
|
||||
#include "CookieService.h"
|
||||
#include "mozilla/ContentBlocking.h"
|
||||
#include "mozilla/ConsoleReportCollector.h"
|
||||
#include "mozilla/ContentBlockingNotifier.h"
|
||||
#include "mozilla/dom/nsMixedContentBlocker.h"
|
||||
#include "mozIThirdPartyUtil.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsICookieJarSettings.h"
|
||||
#include "nsICookiePermission.h"
|
||||
#include "nsICookieService.h"
|
||||
#include "nsIEffectiveTLDService.h"
|
||||
#include "nsScriptSecurityManager.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using dom::Document;
|
||||
|
||||
namespace net {
|
||||
|
||||
// static
|
||||
|
@ -64,7 +74,7 @@ bool CookieCommons::PathMatches(Cookie* aCookie, const nsACString& aPath) {
|
|||
// be the exact host, and aRequireHostMatch will be true to indicate that
|
||||
// substring matches should not be performed.
|
||||
nsresult CookieCommons::GetBaseDomain(nsIEffectiveTLDService* aTLDService,
|
||||
nsIURI* aHostURI, nsCString& aBaseDomain,
|
||||
nsIURI* aHostURI, nsACString& aBaseDomain,
|
||||
bool& aRequireHostMatch) {
|
||||
// get the base domain. this will fail if the host contains a leading dot,
|
||||
// more than one trailing dot, or is otherwise malformed.
|
||||
|
@ -92,6 +102,18 @@ nsresult CookieCommons::GetBaseDomain(nsIEffectiveTLDService* aTLDService,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult CookieCommons::GetBaseDomain(nsIPrincipal* aPrincipal,
|
||||
nsACString& aBaseDomain) {
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
|
||||
// for historical reasons we use ascii host for file:// URLs.
|
||||
if (aPrincipal->SchemeIs("file")) {
|
||||
return aPrincipal->GetAsciiHost(aBaseDomain);
|
||||
}
|
||||
|
||||
return aPrincipal->GetBaseDomain(aBaseDomain);
|
||||
}
|
||||
|
||||
// Get the base domain for aHost; e.g. for "www.bbc.co.uk", this would be
|
||||
// "bbc.co.uk". This is done differently than GetBaseDomain(mTLDService, ): it
|
||||
// is assumed that aHost is already normalized, and it may contain a leading dot
|
||||
|
@ -130,10 +152,9 @@ nsresult CookieCommons::GetBaseDomainFromHost(
|
|||
return rv;
|
||||
}
|
||||
|
||||
// Notify observers that a cookie was rejected due to the users' prefs.
|
||||
void CookieCommons::NotifyRejected(nsIURI* aHostURI, nsIChannel* aChannel,
|
||||
uint32_t aRejectedReason,
|
||||
CookieOperation aOperation) {
|
||||
namespace {
|
||||
|
||||
void NotifyRejectionToObservers(nsIURI* aHostURI, CookieOperation aOperation) {
|
||||
if (aOperation == OPERATION_WRITE) {
|
||||
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
||||
if (os) {
|
||||
|
@ -142,6 +163,15 @@ void CookieCommons::NotifyRejected(nsIURI* aHostURI, nsIChannel* aChannel,
|
|||
} else {
|
||||
MOZ_ASSERT(aOperation == OPERATION_READ);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Notify observers that a cookie was rejected due to the users' prefs.
|
||||
void CookieCommons::NotifyRejected(nsIURI* aHostURI, nsIChannel* aChannel,
|
||||
uint32_t aRejectedReason,
|
||||
CookieOperation aOperation) {
|
||||
NotifyRejectionToObservers(aHostURI, aOperation);
|
||||
|
||||
ContentBlockingNotifier::OnDecision(
|
||||
aChannel, ContentBlockingNotifier::BlockingDecision::eBlock,
|
||||
|
@ -208,12 +238,24 @@ bool CookieCommons::CheckCookiePermission(nsIChannel* aChannel,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!channelPrincipal->GetIsContentPrincipal()) {
|
||||
return CheckCookiePermission(channelPrincipal, cookieJarSettings,
|
||||
aCookieData);
|
||||
}
|
||||
|
||||
// static
|
||||
bool CookieCommons::CheckCookiePermission(
|
||||
nsIPrincipal* aPrincipal, nsICookieJarSettings* aCookieJarSettings,
|
||||
CookieStruct& aCookieData) {
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
MOZ_ASSERT(aCookieJarSettings);
|
||||
|
||||
if (!aPrincipal->GetIsContentPrincipal()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t cookiePermission = nsICookiePermission::ACCESS_DEFAULT;
|
||||
rv = cookieJarSettings->CookiePermission(channelPrincipal, &cookiePermission);
|
||||
nsresult rv =
|
||||
aCookieJarSettings->CookiePermission(aPrincipal, &cookiePermission);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return true;
|
||||
}
|
||||
|
@ -257,5 +299,133 @@ bool CookieCommons::CheckCookiePermission(nsIChannel* aChannel,
|
|||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
CookieStatus CookieStatusForWindow(nsPIDOMWindowInner* aWindow,
|
||||
nsIURI* aDocumentURI) {
|
||||
MOZ_ASSERT(aWindow);
|
||||
MOZ_ASSERT(aDocumentURI);
|
||||
|
||||
if (!nsContentUtils::IsThirdPartyWindowOrChannel(aWindow, nullptr,
|
||||
aDocumentURI)) {
|
||||
return STATUS_ACCEPTED;
|
||||
}
|
||||
|
||||
if (StaticPrefs::network_cookie_thirdparty_sessionOnly()) {
|
||||
return STATUS_ACCEPT_SESSION;
|
||||
}
|
||||
|
||||
if (StaticPrefs::network_cookie_thirdparty_nonsecureSessionOnly() &&
|
||||
!nsMixedContentBlocker::IsPotentiallyTrustworthyOrigin(aDocumentURI)) {
|
||||
return STATUS_ACCEPT_SESSION;
|
||||
}
|
||||
|
||||
return STATUS_ACCEPTED;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
already_AddRefed<Cookie> CookieCommons::CreateCookieFromDocument(
|
||||
Document* aDocument, const nsACString& aCookieString,
|
||||
int64_t currentTimeInUsec, nsIEffectiveTLDService* aTLDService,
|
||||
mozIThirdPartyUtil* aThirdPartyUtil,
|
||||
std::function<bool(const nsACString&, const OriginAttributes&)>&&
|
||||
aHasExistingCookiesLambda,
|
||||
nsIURI** aDocumentURI, nsACString& aBaseDomain, OriginAttributes& aAttrs) {
|
||||
nsCOMPtr<nsIPrincipal> storagePrincipal =
|
||||
aDocument->EffectiveStoragePrincipal();
|
||||
MOZ_ASSERT(storagePrincipal);
|
||||
|
||||
nsCOMPtr<nsIURI> principalURI;
|
||||
auto* basePrincipal = BasePrincipal::Cast(aDocument->NodePrincipal());
|
||||
basePrincipal->GetURI(getter_AddRefs(principalURI));
|
||||
if (NS_WARN_IF(!principalURI)) {
|
||||
// Document's principal is not a content or null (may be system), so
|
||||
// can't set cookies
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsAutoCString baseDomain;
|
||||
bool requireHostMatch = false;
|
||||
nsresult rv = CookieCommons::GetBaseDomain(aTLDService, principalURI,
|
||||
baseDomain, requireHostMatch);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsPIDOMWindowInner* innerWindow = aDocument->GetInnerWindow();
|
||||
if (NS_WARN_IF(!innerWindow)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Check if limit-foreign is required.
|
||||
uint32_t dummyRejectedReason = 0;
|
||||
if (aDocument->CookieJarSettings()->GetLimitForeignContexts() &&
|
||||
!aHasExistingCookiesLambda(baseDomain,
|
||||
storagePrincipal->OriginAttributesRef()) &&
|
||||
!ContentBlocking::ShouldAllowAccessFor(innerWindow, principalURI,
|
||||
&dummyRejectedReason)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool isForeignAndNotAddon = false;
|
||||
if (!BasePrincipal::Cast(aDocument->NodePrincipal())->AddonPolicy()) {
|
||||
rv = aThirdPartyUtil->IsThirdPartyWindow(
|
||||
innerWindow->GetOuterWindow(), principalURI, &isForeignAndNotAddon);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
isForeignAndNotAddon = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If we are here, we have been already accepted by the anti-tracking.
|
||||
// We just need to check if we have to be in session-only mode.
|
||||
CookieStatus cookieStatus = CookieStatusForWindow(innerWindow, principalURI);
|
||||
MOZ_ASSERT(cookieStatus == STATUS_ACCEPTED ||
|
||||
cookieStatus == STATUS_ACCEPT_SESSION);
|
||||
|
||||
// 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); });
|
||||
|
||||
nsCString cookieString(aCookieString);
|
||||
|
||||
CookieStruct cookieData;
|
||||
bool canSetCookie = false;
|
||||
CookieService::CanSetCookie(principalURI, baseDomain, cookieData,
|
||||
requireHostMatch, cookieStatus, cookieString,
|
||||
false, isForeignAndNotAddon, crc, canSetCookie);
|
||||
|
||||
if (!canSetCookie) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// check permissions from site permission list.
|
||||
if (!CookieCommons::CheckCookiePermission(aDocument->NodePrincipal(),
|
||||
aDocument->CookieJarSettings(),
|
||||
cookieData)) {
|
||||
NotifyRejectionToObservers(principalURI, OPERATION_WRITE);
|
||||
ContentBlockingNotifier::OnDecision(
|
||||
innerWindow, ContentBlockingNotifier::BlockingDecision::eBlock,
|
||||
nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<Cookie> cookie =
|
||||
Cookie::Create(cookieData, storagePrincipal->OriginAttributesRef());
|
||||
MOZ_ASSERT(cookie);
|
||||
|
||||
cookie->SetLastAccessed(currentTimeInUsec);
|
||||
cookie->SetCreationTime(
|
||||
Cookie::GenerateUniqueCreationTime(currentTimeInUsec));
|
||||
|
||||
aBaseDomain = baseDomain;
|
||||
aAttrs = storagePrincipal->OriginAttributesRef();
|
||||
principalURI.forget(aDocumentURI);
|
||||
|
||||
return cookie.forget();
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -7,19 +7,39 @@
|
|||
#define mozilla_net_CookieCommons_h
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include "prtime.h"
|
||||
#include "nsString.h"
|
||||
|
||||
class nsIChannel;
|
||||
class nsICookieJarSettings;
|
||||
class nsIEffectiveTLDService;
|
||||
class nsIPrincipal;
|
||||
class nsIURI;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class Document;
|
||||
}
|
||||
|
||||
namespace net {
|
||||
|
||||
// these constants represent an operation being performed on cookies
|
||||
enum CookieOperation { OPERATION_READ, OPERATION_WRITE };
|
||||
|
||||
// these constants represent a decision about a cookie based on user prefs.
|
||||
enum CookieStatus {
|
||||
STATUS_ACCEPTED,
|
||||
STATUS_ACCEPT_SESSION,
|
||||
STATUS_REJECTED,
|
||||
// STATUS_REJECTED_WITH_ERROR indicates the cookie should be rejected because
|
||||
// of an error (rather than something the user can control). this is used for
|
||||
// notification purposes, since we only want to notify of rejections where
|
||||
// the user can do something about it (e.g. whitelist the site).
|
||||
STATUS_REJECTED_WITH_ERROR
|
||||
};
|
||||
|
||||
class Cookie;
|
||||
|
||||
// pref string constants
|
||||
|
@ -46,9 +66,12 @@ class CookieCommons final {
|
|||
static bool PathMatches(Cookie* aCookie, const nsACString& aPath);
|
||||
|
||||
static nsresult GetBaseDomain(nsIEffectiveTLDService* aTLDService,
|
||||
nsIURI* aHostURI, nsCString& aBaseDomain,
|
||||
nsIURI* aHostURI, nsACString& aBaseDomain,
|
||||
bool& aRequireHostMatch);
|
||||
|
||||
static nsresult GetBaseDomain(nsIPrincipal* aPrincipal,
|
||||
nsACString& aBaseDomain);
|
||||
|
||||
static nsresult GetBaseDomainFromHost(nsIEffectiveTLDService* aTLDService,
|
||||
const nsACString& aHost,
|
||||
nsCString& aBaseDomain);
|
||||
|
@ -67,6 +90,18 @@ class CookieCommons final {
|
|||
|
||||
static bool CheckCookiePermission(nsIChannel* aChannel,
|
||||
CookieStruct& aCookieData);
|
||||
|
||||
static bool CheckCookiePermission(nsIPrincipal* aPrincipal,
|
||||
nsICookieJarSettings* aCookieJarSettings,
|
||||
CookieStruct& aCookieData);
|
||||
|
||||
static already_AddRefed<Cookie> CreateCookieFromDocument(
|
||||
dom::Document* aDocument, const nsACString& aCookieString,
|
||||
int64_t aCurrentTimeInUsec, nsIEffectiveTLDService* aTLDService,
|
||||
mozIThirdPartyUtil* aThirdPartyUtil,
|
||||
std::function<bool(const nsACString&, const OriginAttributes&)>&&
|
||||
aHasExistingCookiesLambda,
|
||||
nsIURI** aDocumentURI, nsACString& aBaseDomain, OriginAttributes& aAttrs);
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
|
|
|
@ -266,13 +266,7 @@ CookieService::GetCookieStringForPrincipal(nsIPrincipal* aPrincipal,
|
|||
CookieStorage* storage = PickStorage(aPrincipal->OriginAttributesRef());
|
||||
|
||||
nsAutoCString baseDomain;
|
||||
// for historical reasons we use ascii host for file:// URLs.
|
||||
if (aPrincipal->SchemeIs("file")) {
|
||||
rv = aPrincipal->GetAsciiHost(baseDomain);
|
||||
} else {
|
||||
rv = aPrincipal->GetBaseDomain(baseDomain);
|
||||
}
|
||||
|
||||
rv = CookieCommons::GetBaseDomain(aPrincipal, baseDomain);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -423,6 +417,43 @@ CookieService::SetCookieString(nsIURI* aHostURI,
|
|||
return SetCookieStringCommon(aHostURI, aCookieHeader, aChannel, false);
|
||||
}
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
RefPtr<Cookie> cookie = CookieCommons::CreateCookieFromDocument(
|
||||
aDocument, aCookieString, currentTimeInUsec, mTLDService, mThirdPartyUtil,
|
||||
hasExistingCookiesLambda, getter_AddRefs(documentURI), baseDomain, attrs);
|
||||
if (!cookie) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// add the cookie to the list. AddCookie() takes care of logging.
|
||||
PickStorage(attrs)->AddCookie(baseDomain, attrs, cookie, currentTimeInUsec,
|
||||
documentURI, aCookieString, false);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
CookieService::SetCookieStringFromHttp(nsIURI* aHostURI,
|
||||
const nsACString& aCookieHeader,
|
||||
|
@ -1077,8 +1108,6 @@ bool CookieService::SetCookieInternal(CookieStorage* aStorage, nsIURI* aHostURI,
|
|||
Cookie::GenerateUniqueCreationTime(currentTimeInUsec));
|
||||
|
||||
// add the cookie to the list. AddCookie() takes care of logging.
|
||||
// we get the current time again here, since it may have changed during
|
||||
// prompting
|
||||
aStorage->AddCookie(aBaseDomain, aOriginAttributes, cookie, currentTimeInUsec,
|
||||
aHostURI, savedCookieHeader, aFromHttp);
|
||||
return newCookie;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "nsWeakReference.h"
|
||||
|
||||
#include "Cookie.h"
|
||||
#include "CookieCommons.h"
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
|
@ -32,18 +33,6 @@ class CookiePersistentStorage;
|
|||
class CookiePrivateStorage;
|
||||
class CookieStorage;
|
||||
|
||||
// these constants represent a decision about a cookie based on user prefs.
|
||||
enum CookieStatus {
|
||||
STATUS_ACCEPTED,
|
||||
STATUS_ACCEPT_SESSION,
|
||||
STATUS_REJECTED,
|
||||
// STATUS_REJECTED_WITH_ERROR indicates the cookie should be rejected because
|
||||
// of an error (rather than something the user can control). this is used for
|
||||
// notification purposes, since we only want to notify of rejections where
|
||||
// the user can do something about it (e.g. whitelist the site).
|
||||
STATUS_REJECTED_WITH_ERROR
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
* CookieService:
|
||||
* class declaration
|
||||
|
|
|
@ -13,12 +13,10 @@
|
|||
#include "mozilla/BasePrincipal.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/nsMixedContentBlocker.h"
|
||||
#include "mozilla/ipc/URIUtils.h"
|
||||
#include "mozilla/net/NeckoChild.h"
|
||||
#include "mozilla/StaticPrefs_network.h"
|
||||
#include "mozilla/StoragePrincipalHelper.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsIChannel.h"
|
||||
|
@ -225,7 +223,7 @@ void CookieServiceChild::PrefChanged(nsIPrefBranch* aPrefBranch) {
|
|||
}
|
||||
|
||||
uint32_t CookieServiceChild::CountCookiesFromHashTable(
|
||||
const nsCString& aBaseDomain, const OriginAttributes& aOriginAttrs) {
|
||||
const nsACString& aBaseDomain, const OriginAttributes& aOriginAttrs) {
|
||||
CookiesList* cookiesList = nullptr;
|
||||
|
||||
nsCString baseDomain;
|
||||
|
@ -469,18 +467,10 @@ CookieServiceChild::GetCookieStringForPrincipal(nsIPrincipal* aPrincipal,
|
|||
nsACString& aCookieString) {
|
||||
NS_ENSURE_ARG(aPrincipal);
|
||||
|
||||
nsresult rv;
|
||||
|
||||
aCookieString.Truncate();
|
||||
|
||||
nsAutoCString baseDomain;
|
||||
// for historical reasons we use ascii host for file:// URLs.
|
||||
if (aPrincipal->SchemeIs("file")) {
|
||||
rv = aPrincipal->GetAsciiHost(baseDomain);
|
||||
} else {
|
||||
rv = aPrincipal->GetBaseDomain(baseDomain);
|
||||
}
|
||||
|
||||
nsresult rv = CookieCommons::GetBaseDomain(aPrincipal, baseDomain);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -564,6 +554,62 @@ CookieServiceChild::SetCookieString(nsIURI* aHostURI,
|
|||
return SetCookieStringInternal(aHostURI, aChannel, aCookieString, false);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
CookieServiceChild::SetCookieStringFromDocument(
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
|
@ -57,7 +57,7 @@ class CookieServiceChild final : public PCookieServiceChild,
|
|||
|
||||
void RecordDocumentCookie(Cookie* aCookie, const OriginAttributes& aAttrs);
|
||||
|
||||
uint32_t CountCookiesFromHashTable(const nsCString& aBaseDomain,
|
||||
uint32_t CountCookiesFromHashTable(const nsACString& aBaseDomain,
|
||||
const OriginAttributes& aOriginAttrs);
|
||||
|
||||
void PrefChanged(nsIPrefBranch* aPrefBranch);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
interface nsIURI;
|
||||
interface nsIChannel;
|
||||
interface nsIPrincipal;
|
||||
webidl Document;
|
||||
|
||||
/**
|
||||
* @see nsICookieService::runInTransaction
|
||||
|
@ -121,6 +122,18 @@ 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 associated with the URI.
|
||||
*
|
||||
|
|
Загрузка…
Ссылка в новой задаче