Bug 1910886 - Reduce duplicated code between CookieService and CookieServiceChild - part 1 - Unify nsICookieService.getCookieStringFromDocument implementations, r=edgul,cookie-reviewers

Differential Revision: https://phabricator.services.mozilla.com/D218312
This commit is contained in:
Andrea Marchesini 2024-08-15 21:35:41 +00:00
parent 0be12ad573
commit 8cf7d4e9d4
10 changed files with 267 additions and 338 deletions

View File

@ -266,6 +266,8 @@
#include "mozilla/ipc/IdleSchedulerChild.h"
#include "mozilla/ipc/MessageChannel.h"
#include "mozilla/net/ChannelEventQueue.h"
#include "mozilla/net/Cookie.h"
#include "mozilla/net/CookieCommons.h"
#include "mozilla/net/CookieJarSettings.h"
#include "mozilla/net/NeckoChannelParams.h"
#include "mozilla/net/RequestContextService.h"
@ -462,6 +464,9 @@ mozilla::LazyLogModule gTimeoutDeferralLog("TimeoutDefer");
mozilla::LazyLogModule gUseCountersLog("UseCounters");
namespace mozilla {
using namespace net;
namespace dom {
class Document::HeaderData {
@ -6623,13 +6628,157 @@ void Document::GetCookie(nsAString& aCookie, ErrorResult& aRv) {
// not having a cookie service isn't an error
nsCOMPtr<nsICookieService> service =
do_GetService(NS_COOKIESERVICE_CONTRACTID);
if (service) {
nsAutoCString cookie;
service->GetCookieStringFromDocument(this, cookie);
// CopyUTF8toUTF16 doesn't handle error
// because it assumes that the input is valid.
UTF_8_ENCODING->DecodeWithoutBOMHandling(cookie, aCookie);
if (!service) {
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) {
ThirdPartyUtil* thirdPartyUtil = ThirdPartyUtil::GetInstance();
if (thirdPartyUtil) {
Unused << thirdPartyUtil->IsThirdPartyWindow(
innerWindow->GetOuterWindow(), nullptr, &thirdParty);
}
}
nsCOMPtr<nsIPrincipal> cookiePrincipal = EffectiveCookiePrincipal();
nsTArray<nsCOMPtr<nsIPrincipal>> principals;
principals.AppendElement(cookiePrincipal);
// CHIPS - If CHIPS is enabled the partitioned cookie jar is always available
// (and therefore the partitioned principal), the unpartitioned cookie jar is
// only available in first-party or third-party with storageAccess contexts.
// In both cases, the document will have storage access.
bool isCHIPS = StaticPrefs::network_cookie_CHIPS_enabled() &&
CookieJarSettings()->GetPartitionForeign();
bool documentHasStorageAccess = false;
nsresult rv = HasStorageAccessSync(documentHasStorageAccess);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
if (isCHIPS && documentHasStorageAccess) {
// Assert that the cookie principal is unpartitioned.
MOZ_ASSERT(cookiePrincipal->OriginAttributesRef().mPartitionKey.IsEmpty());
// Only append the partitioned originAttributes if the partitionKey is set.
// The partitionKey could be empty for partitionKey in partitioned
// originAttributes if the document is for privilege context, such as the
// extension's background page.
if (!PartitionedPrincipal()
->OriginAttributesRef()
.mPartitionKey.IsEmpty()) {
principals.AppendElement(PartitionedPrincipal());
}
}
nsTArray<RefPtr<Cookie>> cookieList;
bool stale = false;
int64_t currentTimeInUsec = PR_Now();
int64_t currentTime = currentTimeInUsec / PR_USEC_PER_SEC;
for (auto& principal : principals) {
if (!CookieCommons::IsSchemeSupported(principal)) {
return;
}
nsAutoCString baseDomain;
rv = CookieCommons::GetBaseDomain(principal, baseDomain);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
nsAutoCString hostFromURI;
rv = nsContentUtils::GetHostOrIPv6WithBrackets(principal, hostFromURI);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
nsAutoCString pathFromURI;
rv = principal->GetFilePath(pathFromURI);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
nsTArray<RefPtr<Cookie>> cookies;
service->GetCookiesFromHost(baseDomain, principal->OriginAttributesRef(),
cookies);
if (cookies.IsEmpty()) {
continue;
}
// 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();
// 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, this)) {
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()) {
return;
}
// 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) {
service->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).
cookieList.Sort(CompareCookiesForSending());
nsAutoCString cookieString;
CookieCommons::ComposeCookieString(cookieList, cookieString);
// CopyUTF8toUTF16 doesn't handle error
// because it assumes that the input is valid.
UTF_8_ENCODING->DecodeWithoutBOMHandling(cookieString, aCookie);
}
void Document::SetCookie(const nsAString& aCookie, ErrorResult& aRv) {

View File

@ -818,5 +818,27 @@ bool CookieCommons::ChipsLimitEnabledAndChipsCookie(
cookie.IsPartitioned() && cookie.RawIsPartitioned() && tcpEnabled;
}
void CookieCommons::ComposeCookieString(nsTArray<RefPtr<Cookie>>& aCookieList,
nsACString& aCookieString) {
for (Cookie* cookie : aCookieList) {
// check if we have anything to write
if (!cookie->Name().IsEmpty() || !cookie->Value().IsEmpty()) {
// if we've already added a cookie to the return list, append a "; " so
// that subsequent cookies are delimited in the final list.
if (!aCookieString.IsEmpty()) {
aCookieString.AppendLiteral("; ");
}
if (!cookie->Name().IsEmpty()) {
// we have a name and value - write both
aCookieString += cookie->Name() + "="_ns + cookie->Value();
} else {
// just write value
aCookieString += cookie->Value();
}
}
}
}
} // namespace net
} // namespace mozilla

View File

@ -143,6 +143,9 @@ class CookieCommons final {
static bool ChipsLimitEnabledAndChipsCookie(
const Cookie& cookie, dom::BrowsingContext* aBrowsingContext);
static void ComposeCookieString(nsTArray<RefPtr<Cookie>>& aCookieList,
nsACString& aCookieString);
};
} // namespace net

View File

@ -138,28 +138,6 @@ constexpr auto CONSOLE_REJECTION_CATEGORY = "cookiesRejection"_ns;
namespace {
void ComposeCookieString(nsTArray<RefPtr<Cookie>>& aCookieList,
nsACString& aCookieString) {
for (Cookie* cookie : aCookieList) {
// check if we have anything to write
if (!cookie->Name().IsEmpty() || !cookie->Value().IsEmpty()) {
// if we've already added a cookie to the return list, append a "; " so
// that subsequent cookies are delimited in the final list.
if (!aCookieString.IsEmpty()) {
aCookieString.AppendLiteral("; ");
}
if (!cookie->Name().IsEmpty()) {
// we have a name and value - write both
aCookieString += cookie->Name() + "="_ns + cookie->Value();
} else {
// just write value
aCookieString += cookie->Value();
}
}
}
}
// Return false if the cookie should be ignored for the current channel.
bool ProcessSameSiteCookieForForeignRequest(nsIChannel* aChannel,
Cookie* aCookie,
@ -365,170 +343,6 @@ CookieService::GetCookieBehavior(bool aIsPrivate, uint32_t* aCookieBehavior) {
return NS_OK;
}
NS_IMETHODIMP
CookieService::GetCookieStringFromDocument(Document* aDocument,
nsACString& aCookie) {
NS_ENSURE_ARG(aDocument);
nsresult rv;
aCookie.Truncate();
if (!IsInitialized()) {
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);
}
}
nsCOMPtr<nsIPrincipal> cookiePrincipal =
aDocument->EffectiveCookiePrincipal();
nsTArray<nsCOMPtr<nsIPrincipal>> principals;
principals.AppendElement(cookiePrincipal);
// CHIPS - If CHIPS is enabled the partitioned cookie jar is always available
// (and therefore the partitioned principal), the unpartitioned cookie jar is
// only available in first-party or third-party with storageAccess contexts.
// In both cases, the document will have storage access.
bool isCHIPS = StaticPrefs::network_cookie_CHIPS_enabled() &&
aDocument->CookieJarSettings()->GetPartitionForeign();
bool documentHasStorageAccess = false;
rv = aDocument->HasStorageAccessSync(documentHasStorageAccess);
NS_ENSURE_SUCCESS(rv, rv);
if (isCHIPS && documentHasStorageAccess) {
// Assert that the cookie principal is unpartitioned.
MOZ_ASSERT(cookiePrincipal->OriginAttributesRef().mPartitionKey.IsEmpty());
// Only append the partitioned originAttributes if the partitionKey is set.
// The partitionKey could be empty for partitionKey in partitioned
// originAttributes if the document is for privilege context, such as the
// extension's background page.
if (!aDocument->PartitionedPrincipal()
->OriginAttributesRef()
.mPartitionKey.IsEmpty()) {
principals.AppendElement(aDocument->PartitionedPrincipal());
}
}
nsTArray<RefPtr<Cookie>> cookieList;
for (auto& principal : principals) {
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;
nsTArray<RefPtr<Cookie>> cookies;
storage->GetCookiesFromHost(baseDomain, principal->OriginAttributesRef(),
cookies);
if (cookies.IsEmpty()) {
continue;
}
// 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;
}
// 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);
}
}
if (cookieList.IsEmpty()) {
return NS_OK;
}
// 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).
cookieList.Sort(CompareCookiesForSending());
ComposeCookieString(cookieList, aCookie);
return NS_OK;
}
NS_IMETHODIMP
CookieService::GetCookieStringFromHttp(nsIURI* aHostURI, nsIChannel* aChannel,
nsACString& aCookieString) {
@ -597,7 +411,7 @@ CookieService::GetCookieStringFromHttp(nsIURI* aHostURI, nsIChannel* aChannel,
hadCrossSiteRedirects, true, false, originAttributesList,
foundCookieList);
ComposeCookieString(foundCookieList, aCookieString);
CookieCommons::ComposeCookieString(foundCookieList, aCookieString);
if (!aCookieString.IsEmpty()) {
COOKIE_LOGSUCCESS(GET_COOKIE, aHostURI, aCookieString, nullptr, false);
@ -1879,5 +1693,39 @@ bool CookieService::SetCookiesFromIPC(const nsACString& aBaseDomain,
return true;
}
void CookieService::GetCookiesFromHost(
const nsACString& aBaseDomain,
const mozilla::OriginAttributes& aOriginAttributes,
nsTArray<RefPtr<mozilla::net::Cookie>>& aCookies) {
if (!IsInitialized()) {
return;
}
CookieStorage* storage = PickStorage(aOriginAttributes);
storage->GetCookiesFromHost(aBaseDomain, aOriginAttributes, aCookies);
}
void CookieService::StaleCookies(
const nsTArray<RefPtr<mozilla::net::Cookie>>& aCookies,
int64_t aCurrentTimeInUsec) {
if (!IsInitialized()) {
return;
}
if (aCookies.IsEmpty()) {
return;
}
OriginAttributes originAttributes = aCookies[0]->OriginAttributesRef();
#ifdef MOZ_DEBUG
for (Cookie* cookie : aCookies) {
MOZ_ASSERT(originAttributes == cookie->OriginAttributesRef());
}
#endif
CookieStorage* storage = PickStorage(originAttributes);
storage->StaleCookies(aCookies, aCurrentTimeInUsec);
}
} // namespace net
} // namespace mozilla

View File

@ -345,139 +345,6 @@ void CookieServiceChild::RecordDocumentCookie(Cookie* aCookie,
cookiesList->AppendElement(aCookie);
}
NS_IMETHODIMP
CookieServiceChild::GetCookieStringFromDocument(dom::Document* aDocument,
nsACString& aCookieString) {
NS_ENSURE_ARG(aDocument);
aCookieString.Truncate();
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);
}
}
nsCOMPtr<nsIPrincipal> cookiePrincipal =
aDocument->EffectiveCookiePrincipal();
nsTArray<nsCOMPtr<nsIPrincipal>> principals;
principals.AppendElement(cookiePrincipal);
// CHIPS - If CHIPS is enabled the partitioned cookie jar is always available
// (and therefore the partitioned principal), the unpartitioned cookie jar is
// only available in first-party or third-party with storageAccess contexts.
// In both cases, the document will have storage access.
bool isCHIPS = aDocument->CookieJarSettings()->GetPartitionForeign() &&
StaticPrefs::network_cookie_CHIPS_enabled();
bool documentHasStorageAccess = false;
nsresult rv = aDocument->HasStorageAccessSync(documentHasStorageAccess);
NS_ENSURE_SUCCESS(rv, rv);
if (isCHIPS && documentHasStorageAccess) {
/// Assert that the cookie principal is unpartitioned.
MOZ_ASSERT(cookiePrincipal->OriginAttributesRef().mPartitionKey.IsEmpty());
// Only append the partitioned originAttributes if the partitionKey is set.
// The partitionKey could be empty for partitionKey in partitioned
// originAttributes if the document is for privilege context, such as the
// extension's background page.
if (!aDocument->PartitionedPrincipal()
->OriginAttributesRef()
.mPartitionKey.IsEmpty()) {
principals.AppendElement(aDocument->PartitionedPrincipal());
}
}
for (auto& principal : principals) {
if (!CookieCommons::IsSchemeSupported(principal)) {
return NS_OK;
}
nsAutoCString baseDomain;
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) {
continue;
}
nsAutoCString hostFromURI;
rv = nsContentUtils::GetHostOrIPv6WithBrackets(principal, hostFromURI);
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_OK;
}
nsAutoCString pathFromURI;
principal->GetFilePath(pathFromURI);
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, aDocument)) {
continue;
}
// do not display the cookie if it is secure and the host scheme isn't
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*/,
@ -785,5 +652,25 @@ CookieServiceChild::RunInTransaction(
return NS_ERROR_NOT_IMPLEMENTED;
}
void CookieServiceChild::GetCookiesFromHost(
const nsACString& aBaseDomain,
const mozilla::OriginAttributes& aOriginAttributes,
nsTArray<RefPtr<mozilla::net::Cookie>>& aCookies) {
CookieKey key(aBaseDomain, aOriginAttributes);
CookiesList* cookiesList = nullptr;
mCookiesMap.Get(key, &cookiesList);
if (cookiesList) {
aCookies.AppendElements(*cookiesList);
}
}
void CookieServiceChild::StaleCookies(
const nsTArray<RefPtr<mozilla::net::Cookie>>& aCookies,
int64_t aCurrentTimeInUsec) {
// Nothing to do here.
}
} // namespace net
} // namespace mozilla

View File

@ -22,6 +22,7 @@ XPIDL_MODULE = "necko_cookie"
EXPORTS.mozilla.net = [
"Cookie.h",
"CookieCommons.h",
"CookieJarSettings.h",
"CookieKey.h",
"CookieNotification.h",

View File

@ -5,10 +5,24 @@
#include "nsISupports.idl"
interface nsIURI;
interface nsIChannel;
interface nsICookie;
interface nsIURI;
webidl Document;
%{C++
namespace mozilla {
class OriginAttributes;
namespace net {
class Cookie;
}
}
%}
[ref] native const_OriginAttributes(const mozilla::OriginAttributes);
native CookiePtr(RefPtr<mozilla::net::Cookie>);
/**
* @see nsICookieService::runInTransaction
*/
@ -50,7 +64,7 @@ interface nsICookieTransactionCallback : nsISupports
* to set the cookie.
* data : none.
*/
[scriptable, uuid(1e94e283-2811-4f43-b947-d22b1549d824)]
[builtinclass, scriptable, uuid(1e94e283-2811-4f43-b947-d22b1549d824)]
interface nsICookieService : nsISupports
{
/*
@ -67,17 +81,18 @@ interface nsICookieService : nsISupports
const uint32_t BEHAVIOR_LAST = 5;
/*
* Get the complete cookie string associated with the document's principal.
* Get the list of cookies associated with a base domain and an OriginAttributes.
* 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.
*
* @return the resulting cookie string
*/
ACString getCookieStringFromDocument(in Document aDocument);
[noscript, notxpcom, nostdcall] void getCookiesFromHost(in ACString aBaseDomain,
in const_OriginAttributes aOriginAttributes,
out Array<CookiePtr> aCookies);
/* Update the last access to stale cookies */
[noscript, notxpcom, nostdcall] void staleCookies(in Array<CookiePtr> aCookies,
in int64_t aCurrentTimeInUsec);
/*
* Get the complete cookie string associated with the URI.

View File

@ -300,7 +300,7 @@ add_task(
// CookieService::SetCookieStringFromHttp() call.
// Get partitioned and unpartitioned cookies from document (child).
// This calls CookieServiceChild::GetCookieStringFromDocument() internally.
// This uses CookieServiceChild internally.
add_task(
async function test_chips_send_partitioned_and_unpartitioned_document_child() {
const tab = BrowserTestUtils.addTab(gBrowser, URL_DOCUMENT_FIRSTPARTY);

View File

@ -154,7 +154,12 @@ void GetACookieNoHttp(nsICookieService* aCookieService, const char* aSpec,
DocumentFlavorHTML);
Unused << NS_WARN_IF(NS_FAILED(rv));
Unused << aCookieService->GetCookieStringFromDocument(document, aCookie);
nsAutoString cookie;
ErrorResult err;
document->GetCookie(cookie, err);
MOZ_ASSERT(!err.Failed());
CopyUTF16toUTF8(cookie, aCookie);
}
// some #defines for comparison rules

View File

@ -7707,7 +7707,6 @@ interface nsICookieService extends nsISupports {
readonly BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN: 5;
readonly BEHAVIOR_LAST: 5;
getCookieStringFromDocument(aDocument: Document): string;
getCookieStringFromHttp(aURI: nsIURI, aChannel: nsIChannel): string;
setCookieStringFromDocument(aDocument: Document, aCookie: string): void;
setCookieStringFromHttp(aURI: nsIURI, aCookie: string, aChannel: nsIChannel): void;