Bug 1286858 - Data storage and interface changes for SameSite cookies. r=valentin

This commit is contained in:
Amy Chung 2017-09-25 01:27:04 +08:00
parent 89ab2c1423
commit e30f2f6227
11 changed files with 160 additions and 30 deletions

View file

@ -18,7 +18,7 @@
// c) Schema 3: the 'creationTime' column already exists; or the // c) Schema 3: the 'creationTime' column already exists; or the
// 'moz_uniqueid' index already exists. // 'moz_uniqueid' index already exists.
var COOKIE_DATABASE_SCHEMA_CURRENT = 8; var COOKIE_DATABASE_SCHEMA_CURRENT = 9;
var test_generator = do_run_test(); var test_generator = do_run_test();

View file

@ -178,7 +178,8 @@ CookieServiceChild::RecvAddCookie(const CookieStruct &aCookie,
aCookie.isSession(), aCookie.isSession(),
aCookie.isSecure(), aCookie.isSecure(),
false, false,
aAttrs); aAttrs,
aCookie.sameSite());
RecordDocumentCookie(cookie, aAttrs); RecordDocumentCookie(cookie, aAttrs);
return IPC_OK(); return IPC_OK();
} }
@ -210,7 +211,8 @@ CookieServiceChild::RecvTrackCookiesLoad(nsTArray<CookieStruct>&& aCookiesList,
aCookiesList[i].isSession(), aCookiesList[i].isSession(),
aCookiesList[i].isSecure(), aCookiesList[i].isSecure(),
false, false,
aAttrs); aAttrs,
aCookiesList[i].sameSite());
RecordDocumentCookie(cookie, aAttrs); RecordDocumentCookie(cookie, aAttrs);
} }
@ -365,7 +367,8 @@ CookieServiceChild::SetCookieInternal(nsCookieAttributes &aCookieAt
aCookieAttributes.isSession, aCookieAttributes.isSession,
aCookieAttributes.isSecure, aCookieAttributes.isSecure,
aCookieAttributes.isHttpOnly, aCookieAttributes.isHttpOnly,
aAttrs); aAttrs,
aCookieAttributes.sameSite);
RecordDocumentCookie(cookie, aAttrs); RecordDocumentCookie(cookie, aAttrs);
} }

View file

@ -91,6 +91,7 @@ GetInfoFromCookie(nsCookie *aCookie,
aCookieStruct.creationTime() = aCookie->CreationTime(); aCookieStruct.creationTime() = aCookie->CreationTime();
aCookieStruct.isSession() = aCookie->IsSession(); aCookieStruct.isSession() = aCookie->IsSession();
aCookieStruct.isSecure() = aCookie->IsSecure(); aCookieStruct.isSecure() = aCookie->IsSecure();
aCookieStruct.sameSite() = aCookie->SameSite();
} }
void void
@ -186,6 +187,7 @@ CookieServiceParent::SerialializeCookieList(const nsTArray<nsCookie*> &aFoundCoo
cookieStruct->creationTime() = cookie->CreationTime(); cookieStruct->creationTime() = cookie->CreationTime();
cookieStruct->isSession() = cookie->IsSession(); cookieStruct->isSession() = cookie->IsSession();
cookieStruct->isSecure() = cookie->IsSecure(); cookieStruct->isSecure() = cookie->IsSecure();
cookieStruct->sameSite() = cookie->SameSite();
} }
} }

View file

@ -79,7 +79,8 @@ nsCookie::Create(const nsACString &aName,
bool aIsSession, bool aIsSession,
bool aIsSecure, bool aIsSecure,
bool aIsHttpOnly, bool aIsHttpOnly,
const OriginAttributes& aOriginAttributes) const OriginAttributes& aOriginAttributes,
int32_t aSameSite)
{ {
// Ensure mValue contains a valid UTF-8 sequence. Otherwise XPConnect will // Ensure mValue contains a valid UTF-8 sequence. Otherwise XPConnect will
// truncate the string after the first invalid octet. // truncate the string after the first invalid octet.
@ -108,11 +109,16 @@ nsCookie::Create(const nsACString &aName,
if (aCreationTime > gLastCreationTime) if (aCreationTime > gLastCreationTime)
gLastCreationTime = aCreationTime; gLastCreationTime = aCreationTime;
// If aSameSite is not a sensible value, assume strict
if (aSameSite < 0 || aSameSite > nsICookie2::SAMESITE_STRICT) {
aSameSite = nsICookie2::SAMESITE_STRICT;
}
// construct the cookie. placement new, oh yeah! // construct the cookie. placement new, oh yeah!
return new (place) nsCookie(name, value, host, path, end, return new (place) nsCookie(name, value, host, path, end,
aExpiry, aLastAccessed, aCreationTime, aExpiry, aLastAccessed, aCreationTime,
aIsSession, aIsSecure, aIsHttpOnly, aIsSession, aIsSecure, aIsHttpOnly,
aOriginAttributes); aOriginAttributes, aSameSite);
} }
size_t size_t
@ -151,6 +157,7 @@ NS_IMETHODIMP nsCookie::GetStatus(nsCookieStatus *aStatus) { *aStatus = 0;
NS_IMETHODIMP nsCookie::GetPolicy(nsCookiePolicy *aPolicy) { *aPolicy = 0; return NS_OK; } NS_IMETHODIMP nsCookie::GetPolicy(nsCookiePolicy *aPolicy) { *aPolicy = 0; return NS_OK; }
NS_IMETHODIMP nsCookie::GetCreationTime(int64_t *aCreation){ *aCreation = CreationTime(); return NS_OK; } NS_IMETHODIMP nsCookie::GetCreationTime(int64_t *aCreation){ *aCreation = CreationTime(); return NS_OK; }
NS_IMETHODIMP nsCookie::GetLastAccessed(int64_t *aTime) { *aTime = LastAccessed(); return NS_OK; } NS_IMETHODIMP nsCookie::GetLastAccessed(int64_t *aTime) { *aTime = LastAccessed(); return NS_OK; }
NS_IMETHODIMP nsCookie::GetSameSite(int32_t *aSameSite) { *aSameSite = SameSite(); return NS_OK; }
NS_IMETHODIMP NS_IMETHODIMP
nsCookie::GetOriginAttributes(JSContext *aCx, JS::MutableHandle<JS::Value> aVal) nsCookie::GetOriginAttributes(JSContext *aCx, JS::MutableHandle<JS::Value> aVal)

View file

@ -48,7 +48,8 @@ class nsCookie : public nsICookie2
bool aIsSession, bool aIsSession,
bool aIsSecure, bool aIsSecure,
bool aIsHttpOnly, bool aIsHttpOnly,
const OriginAttributes& aOriginAttributes) const OriginAttributes& aOriginAttributes,
int32_t aSameSite)
: mName(aName) : mName(aName)
, mValue(aValue) , mValue(aValue)
, mHost(aHost) , mHost(aHost)
@ -61,6 +62,7 @@ class nsCookie : public nsICookie2
, mIsSecure(aIsSecure) , mIsSecure(aIsSecure)
, mIsHttpOnly(aIsHttpOnly) , mIsHttpOnly(aIsHttpOnly)
, mOriginAttributes(aOriginAttributes) , mOriginAttributes(aOriginAttributes)
, mSameSite(aSameSite)
{ {
} }
@ -92,7 +94,8 @@ class nsCookie : public nsICookie2
bool aIsSession, bool aIsSession,
bool aIsSecure, bool aIsSecure,
bool aIsHttpOnly, bool aIsHttpOnly,
const OriginAttributes& aOriginAttributes); const OriginAttributes& aOriginAttributes,
int32_t aSameSite);
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
@ -110,6 +113,7 @@ class nsCookie : public nsICookie2
inline bool IsSecure() const { return mIsSecure; } inline bool IsSecure() const { return mIsSecure; }
inline bool IsHttpOnly() const { return mIsHttpOnly; } inline bool IsHttpOnly() const { return mIsHttpOnly; }
inline const OriginAttributes& OriginAttributesRef() const { return mOriginAttributes; } inline const OriginAttributes& OriginAttributesRef() const { return mOriginAttributes; }
inline int32_t SameSite() const { return mSameSite; }
// setters // setters
inline void SetExpiry(int64_t aExpiry) { mExpiry = aExpiry; } inline void SetExpiry(int64_t aExpiry) { mExpiry = aExpiry; }
@ -144,6 +148,7 @@ class nsCookie : public nsICookie2
bool mIsSecure; bool mIsSecure;
bool mIsHttpOnly; bool mIsHttpOnly;
mozilla::OriginAttributes mOriginAttributes; mozilla::OriginAttributes mOriginAttributes;
int32_t mSameSite;
}; };
// Comparator class for sorting cookies before sending to a server. // Comparator class for sorting cookies before sending to a server.

View file

@ -80,7 +80,7 @@ static StaticRefPtr<nsCookieService> gCookieService;
#define HTTP_ONLY_PREFIX "#HttpOnly_" #define HTTP_ONLY_PREFIX "#HttpOnly_"
#define COOKIES_FILE "cookies.sqlite" #define COOKIES_FILE "cookies.sqlite"
#define COOKIES_SCHEMA_VERSION 8 #define COOKIES_SCHEMA_VERSION 9
// parameter indexes; see EnsureReadDomain, EnsureReadComplete and // parameter indexes; see EnsureReadDomain, EnsureReadComplete and
// ReadCookieDBListener::HandleResult // ReadCookieDBListener::HandleResult
@ -95,6 +95,7 @@ static StaticRefPtr<nsCookieService> gCookieService;
#define IDX_HTTPONLY 8 #define IDX_HTTPONLY 8
#define IDX_BASE_DOMAIN 9 #define IDX_BASE_DOMAIN 9
#define IDX_ORIGIN_ATTRIBUTES 10 #define IDX_ORIGIN_ATTRIBUTES 10
#define IDX_SAME_SITE 11
#define TOPIC_CLEAR_ORIGIN_DATA "clear-origin-attributes-data" #define TOPIC_CLEAR_ORIGIN_DATA "clear-origin-attributes-data"
@ -1391,6 +1392,16 @@ nsCookieService::TryInitDB(bool aRecreateDB)
COOKIE_LOGSTRING(LogLevel::Debug, COOKIE_LOGSTRING(LogLevel::Debug,
("Upgraded database to schema version 8")); ("Upgraded database to schema version 8"));
} }
MOZ_FALLTHROUGH;
case 8:
{
// Add the sameSite column to the table.
rv = mDefaultDBState->dbConn->ExecuteSimpleSQL(
NS_LITERAL_CSTRING("ALTER TABLE moz_cookies ADD sameSite INTEGER"));
COOKIE_LOGSTRING(LogLevel::Debug,
("Upgraded database to schema version 9"));
}
// No more upgrades. Update the schema version. // No more upgrades. Update the schema version.
rv = mDefaultDBState->dbConn->SetSchemaVersion(COOKIES_SCHEMA_VERSION); rv = mDefaultDBState->dbConn->SetSchemaVersion(COOKIES_SCHEMA_VERSION);
@ -1438,7 +1449,8 @@ nsCookieService::TryInitDB(bool aRecreateDB)
"lastAccessed, " "lastAccessed, "
"creationTime, " "creationTime, "
"isSecure, " "isSecure, "
"isHttpOnly " "isHttpOnly, "
"sameSite "
"FROM moz_cookies"), getter_AddRefs(stmt)); "FROM moz_cookies"), getter_AddRefs(stmt));
if (NS_SUCCEEDED(rv)) if (NS_SUCCEEDED(rv))
break; break;
@ -1479,7 +1491,8 @@ nsCookieService::TryInitDB(bool aRecreateDB)
"lastAccessed, " "lastAccessed, "
"creationTime, " "creationTime, "
"isSecure, " "isSecure, "
"isHttpOnly" "isHttpOnly, "
"sameSite "
") VALUES (" ") VALUES ("
":baseDomain, " ":baseDomain, "
":originAttributes, " ":originAttributes, "
@ -1491,7 +1504,8 @@ nsCookieService::TryInitDB(bool aRecreateDB)
":lastAccessed, " ":lastAccessed, "
":creationTime, " ":creationTime, "
":isSecure, " ":isSecure, "
":isHttpOnly" ":isHttpOnly, "
":sameSite"
")"), ")"),
getter_AddRefs(mDefaultDBState->stmtInsert)); getter_AddRefs(mDefaultDBState->stmtInsert));
NS_ENSURE_SUCCESS(rv, RESULT_RETRY); NS_ENSURE_SUCCESS(rv, RESULT_RETRY);
@ -1558,6 +1572,7 @@ nsCookieService::CreateTableWorker(const char* aName)
"isSecure INTEGER, " "isSecure INTEGER, "
"isHttpOnly INTEGER, " "isHttpOnly INTEGER, "
"inBrowserElement INTEGER DEFAULT 0, " "inBrowserElement INTEGER DEFAULT 0, "
"sameSite INTEGER DEFAULT 0, "
"CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes)" "CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes)"
")"); ")");
return mDefaultDBState->dbConn->ExecuteSimpleSQL(command); return mDefaultDBState->dbConn->ExecuteSimpleSQL(command);
@ -2476,6 +2491,7 @@ nsCookieService::Add(const nsACString &aHost,
bool aIsSession, bool aIsSession,
int64_t aExpiry, int64_t aExpiry,
JS::HandleValue aOriginAttributes, JS::HandleValue aOriginAttributes,
int32_t aSameSite,
JSContext* aCx, JSContext* aCx,
uint8_t aArgc) uint8_t aArgc)
{ {
@ -2491,7 +2507,7 @@ nsCookieService::Add(const nsACString &aHost,
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
return AddNative(aHost, aPath, aName, aValue, aIsSecure, aIsHttpOnly, return AddNative(aHost, aPath, aName, aValue, aIsSecure, aIsHttpOnly,
aIsSession, aExpiry, &attrs); aIsSession, aExpiry, &attrs, aSameSite);
} }
NS_IMETHODIMP_(nsresult) NS_IMETHODIMP_(nsresult)
@ -2503,7 +2519,8 @@ nsCookieService::AddNative(const nsACString &aHost,
bool aIsHttpOnly, bool aIsHttpOnly,
bool aIsSession, bool aIsSession,
int64_t aExpiry, int64_t aExpiry,
OriginAttributes* aOriginAttributes) OriginAttributes* aOriginAttributes,
int32_t aSameSite)
{ {
if (NS_WARN_IF(!aOriginAttributes)) { if (NS_WARN_IF(!aOriginAttributes)) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
@ -2539,7 +2556,8 @@ nsCookieService::AddNative(const nsACString &aHost,
aIsSession, aIsSession,
aIsSecure, aIsSecure,
aIsHttpOnly, aIsHttpOnly,
key.mOriginAttributes); key.mOriginAttributes,
aSameSite);
if (!cookie) { if (!cookie) {
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
} }
@ -2671,7 +2689,8 @@ nsCookieService::Read()
"isSecure, " "isSecure, "
"isHttpOnly, " "isHttpOnly, "
"baseDomain, " "baseDomain, "
"originAttributes " "originAttributes, "
"sameSite "
"FROM moz_cookies " "FROM moz_cookies "
"WHERE baseDomain NOTNULL"), getter_AddRefs(stmtRead)); "WHERE baseDomain NOTNULL"), getter_AddRefs(stmtRead));
NS_ENSURE_SUCCESS(rv, RESULT_RETRY); NS_ENSURE_SUCCESS(rv, RESULT_RETRY);
@ -2732,6 +2751,7 @@ nsCookieService::GetCookieFromRow(T &aRow, const OriginAttributes& aOriginAttrib
int64_t creationTime = aRow->AsInt64(IDX_CREATION_TIME); int64_t creationTime = aRow->AsInt64(IDX_CREATION_TIME);
bool isSecure = 0 != aRow->AsInt32(IDX_SECURE); bool isSecure = 0 != aRow->AsInt32(IDX_SECURE);
bool isHttpOnly = 0 != aRow->AsInt32(IDX_HTTPONLY); bool isHttpOnly = 0 != aRow->AsInt32(IDX_HTTPONLY);
int32_t sameSite = aRow->AsInt32(IDX_SAME_SITE);
// Create a new nsCookie and assign the data. // Create a new nsCookie and assign the data.
return nsCookie::Create(name, value, host, path, return nsCookie::Create(name, value, host, path,
@ -2741,7 +2761,8 @@ nsCookieService::GetCookieFromRow(T &aRow, const OriginAttributes& aOriginAttrib
false, false,
isSecure, isSecure,
isHttpOnly, isHttpOnly,
aOriginAttributes); aOriginAttributes,
sameSite);
} }
void void
@ -2850,7 +2871,10 @@ nsCookieService::EnsureReadDomain(const nsCookieKey &aKey)
"lastAccessed, " "lastAccessed, "
"creationTime, " "creationTime, "
"isSecure, " "isSecure, "
"isHttpOnly " "isHttpOnly, "
"baseDomain, "
"originAttributes, "
"sameSite "
"FROM moz_cookies " "FROM moz_cookies "
"WHERE baseDomain = :baseDomain " "WHERE baseDomain = :baseDomain "
" AND originAttributes = :originAttributes"), " AND originAttributes = :originAttributes"),
@ -2947,7 +2971,8 @@ nsCookieService::EnsureReadComplete()
"isSecure, " "isSecure, "
"isHttpOnly, " "isHttpOnly, "
"baseDomain, " "baseDomain, "
"originAttributes " "originAttributes, "
"sameSite "
"FROM moz_cookies " "FROM moz_cookies "
"WHERE baseDomain NOTNULL"), getter_AddRefs(stmt)); "WHERE baseDomain NOTNULL"), getter_AddRefs(stmt));
@ -3151,7 +3176,8 @@ nsCookieService::ImportCookies(nsIFile *aCookieFile)
false, false,
Substring(buffer, secureIndex, expiresIndex - secureIndex - 1).EqualsLiteral(kTrue), Substring(buffer, secureIndex, expiresIndex - secureIndex - 1).EqualsLiteral(kTrue),
isHttpOnly, isHttpOnly,
key.mOriginAttributes); key.mOriginAttributes,
nsICookie2::SAMESITE_UNSET);
if (!newCookie) { if (!newCookie) {
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
} }
@ -3601,7 +3627,8 @@ nsCookieService::SetCookieInternal(nsIURI *aHostURI,
cookieAttributes.isSession, cookieAttributes.isSession,
cookieAttributes.isSecure, cookieAttributes.isSecure,
cookieAttributes.isHttpOnly, cookieAttributes.isHttpOnly,
aKey.mOriginAttributes); aKey.mOriginAttributes,
cookieAttributes.sameSite);
if (!cookie) if (!cookie)
return newCookie; return newCookie;
@ -3993,6 +4020,8 @@ nsCookieService::ParseAttributes(nsDependentCString &aCookieHeader,
static const char kMaxage[] = "max-age"; static const char kMaxage[] = "max-age";
static const char kSecure[] = "secure"; static const char kSecure[] = "secure";
static const char kHttpOnly[] = "httponly"; static const char kHttpOnly[] = "httponly";
static const char kSameSite[] = "samesite";
static const char kSameSiteLax[] = "lax";
nsACString::const_char_iterator tempBegin, tempEnd; nsACString::const_char_iterator tempBegin, tempEnd;
nsACString::const_char_iterator cookieStart, cookieEnd; nsACString::const_char_iterator cookieStart, cookieEnd;
@ -4001,6 +4030,7 @@ nsCookieService::ParseAttributes(nsDependentCString &aCookieHeader,
aCookieAttributes.isSecure = false; aCookieAttributes.isSecure = false;
aCookieAttributes.isHttpOnly = false; aCookieAttributes.isHttpOnly = false;
aCookieAttributes.sameSite = nsICookie2::SAMESITE_UNSET;
nsDependentCSubstring tokenString(cookieStart, cookieStart); nsDependentCSubstring tokenString(cookieStart, cookieStart);
nsDependentCSubstring tokenValue (cookieStart, cookieStart); nsDependentCSubstring tokenValue (cookieStart, cookieStart);
@ -4049,6 +4079,14 @@ nsCookieService::ParseAttributes(nsDependentCString &aCookieHeader,
// just set the boolean // just set the boolean
else if (tokenString.LowerCaseEqualsLiteral(kHttpOnly)) else if (tokenString.LowerCaseEqualsLiteral(kHttpOnly))
aCookieAttributes.isHttpOnly = true; aCookieAttributes.isHttpOnly = true;
else if (tokenString.LowerCaseEqualsLiteral(kSameSite)) {
if (tokenValue.LowerCaseEqualsLiteral(kSameSiteLax)) {
aCookieAttributes.sameSite = nsICookie2::SAMESITE_LAX;
} else {
aCookieAttributes.sameSite = nsICookie2::SAMESITE_STRICT;
}
}
} }
// rebind aCookieHeader, in case we need to process another cookie // rebind aCookieHeader, in case we need to process another cookie
@ -5213,6 +5251,10 @@ bindCookieParameters(mozIStorageBindingParamsArray *aParamsArray,
aCookie->IsHttpOnly()); aCookie->IsHttpOnly());
NS_ASSERT_SUCCESS(rv); NS_ASSERT_SUCCESS(rv);
rv = params->BindInt32ByName(NS_LITERAL_CSTRING("sameSite"),
aCookie->SameSite());
NS_ASSERT_SUCCESS(rv);
// Bind the params to the array. // Bind the params to the array.
rv = aParamsArray->AddParams(params); rv = aParamsArray->AddParams(params);
NS_ASSERT_SUCCESS(rv); NS_ASSERT_SUCCESS(rv);

View file

@ -195,6 +195,7 @@ struct nsCookieAttributes
bool isSession; bool isSession;
bool isSecure; bool isSecure;
bool isHttpOnly; bool isHttpOnly;
int8_t sameSite;
}; };
class nsCookieService final : public nsICookieService class nsCookieService final : public nsICookieService

View file

@ -11,10 +11,13 @@
* access of cookie objects * access of cookie objects
*/ */
[scriptable, uuid(05c420e5-03d0-4c7b-a605-df7ebe5ca326)] [scriptable, uuid(be205dae-4f4c-11e6-80ba-ea5cd310c1a8)]
interface nsICookie2 : nsICookie interface nsICookie2 : nsICookie
{ {
const uint32_t SAMESITE_UNSET = 0;
const uint32_t SAMESITE_LAX = 1;
const uint32_t SAMESITE_STRICT = 2;
/** /**
* the host (possibly fully qualified) of the cookie, * the host (possibly fully qualified) of the cookie,
@ -60,4 +63,15 @@ interface nsICookie2 : nsICookie
*/ */
readonly attribute int64_t lastAccessed; readonly attribute int64_t lastAccessed;
/**
* the sameSite attribute; this controls the cookie behavior for cross-site
* requests as per
* https://tools.ietf.org/html/draft-west-first-party-cookies-07
*
* This should be one of:
* - SAMESITE_UNSET - the SameSite attribute is not present
* - SAMESITE_LAX - the SameSite attribute is present, but not strict
* - SAMESITE_STRICT - the SameSite attribute is present and strict
*/
readonly attribute int32_t sameSite;
}; };

View file

@ -46,8 +46,12 @@ interface nsICookieManager2 : nsICookieManager
* expiration date, in seconds since midnight (00:00:00), January 1, * expiration date, in seconds since midnight (00:00:00), January 1,
* 1970 UTC. note that expiry time will also be honored for session cookies; * 1970 UTC. note that expiry time will also be honored for session cookies;
* in this way, the more restrictive of the two will take effect. * in this way, the more restrictive of the two will take effect.
* @param aOriginAttributes The originAttributes of this cookie. This * @param aOriginAttributes
* attribute is optional to avoid breaking add-ons. * the originAttributes of this cookie. This attribute is optional to
* avoid breaking add-ons.
* @param aSameSite
* the SameSite attribute. This attribute is optional to avoid breaking
* addons
*/ */
[implicit_jscontext, optional_argc] [implicit_jscontext, optional_argc]
void add(in AUTF8String aHost, void add(in AUTF8String aHost,
@ -58,7 +62,8 @@ interface nsICookieManager2 : nsICookieManager
in boolean aIsHttpOnly, in boolean aIsHttpOnly,
in boolean aIsSession, in boolean aIsSession,
in int64_t aExpiry, in int64_t aExpiry,
[optional] in jsval aOriginAttributes); [optional] in jsval aOriginAttributes,
[optional] in int32_t aSameSite);
[notxpcom] [notxpcom]
nsresult addNative(in AUTF8String aHost, nsresult addNative(in AUTF8String aHost,
@ -69,7 +74,8 @@ interface nsICookieManager2 : nsICookieManager
in boolean aIsHttpOnly, in boolean aIsHttpOnly,
in boolean aIsSession, in boolean aIsSession,
in int64_t aExpiry, in int64_t aExpiry,
in OriginAttributesPtr aOriginAttributes); in OriginAttributesPtr aOriginAttributes,
in int32_t aSameSite);
/** /**
* Find whether a given cookie already exists. * Find whether a given cookie already exists.

View file

@ -212,6 +212,7 @@ struct CookieStruct
int64_t creationTime; int64_t creationTime;
bool isSession; bool isSession;
bool isSecure; bool isSecure;
int8_t sameSite;
}; };
} // namespace ipc } // namespace ipc

View file

@ -634,7 +634,8 @@ TEST(TestCookie,TestCookieMain)
false, // is httponly false, // is httponly
true, // is session true, // is session
INT64_MAX, // expiry time INT64_MAX, // expiry time
&attrs))); // originAttributes &attrs, // originAttributes
nsICookie2::SAMESITE_UNSET)));
EXPECT_TRUE(NS_SUCCEEDED(cookieMgr2->AddNative(NS_LITERAL_CSTRING("cookiemgr.test"), // domain EXPECT_TRUE(NS_SUCCEEDED(cookieMgr2->AddNative(NS_LITERAL_CSTRING("cookiemgr.test"), // domain
NS_LITERAL_CSTRING("/foo"), // path NS_LITERAL_CSTRING("/foo"), // path
NS_LITERAL_CSTRING("test2"), // name NS_LITERAL_CSTRING("test2"), // name
@ -643,7 +644,8 @@ TEST(TestCookie,TestCookieMain)
true, // is httponly true, // is httponly
true, // is session true, // is session
PR_Now() / PR_USEC_PER_SEC + 2, // expiry time PR_Now() / PR_USEC_PER_SEC + 2, // expiry time
&attrs))); // originAttributes &attrs, // originAttributes
nsICookie2::SAMESITE_UNSET)));
EXPECT_TRUE(NS_SUCCEEDED(cookieMgr2->AddNative(NS_LITERAL_CSTRING("new.domain"), // domain EXPECT_TRUE(NS_SUCCEEDED(cookieMgr2->AddNative(NS_LITERAL_CSTRING("new.domain"), // domain
NS_LITERAL_CSTRING("/rabbit"), // path NS_LITERAL_CSTRING("/rabbit"), // path
NS_LITERAL_CSTRING("test3"), // name NS_LITERAL_CSTRING("test3"), // name
@ -652,7 +654,8 @@ TEST(TestCookie,TestCookieMain)
false, // is httponly false, // is httponly
true, // is session true, // is session
INT64_MAX, // expiry time INT64_MAX, // expiry time
&attrs))); // originAttributes &attrs, // originAttributes
nsICookie2::SAMESITE_UNSET)));
// confirm using enumerator // confirm using enumerator
nsCOMPtr<nsISimpleEnumerator> enumerator; nsCOMPtr<nsISimpleEnumerator> enumerator;
EXPECT_TRUE(NS_SUCCEEDED(cookieMgr->GetEnumerator(getter_AddRefs(enumerator)))); EXPECT_TRUE(NS_SUCCEEDED(cookieMgr->GetEnumerator(getter_AddRefs(enumerator))));
@ -706,7 +709,8 @@ TEST(TestCookie,TestCookieMain)
false, // is httponly false, // is httponly
true, // is session true, // is session
INT64_MIN, // expiry time INT64_MIN, // expiry time
&attrs))); // originAttributes &attrs, // originAttributes
nsICookie2::SAMESITE_UNSET)));
EXPECT_TRUE(NS_SUCCEEDED(cookieMgr2->CookieExistsNative(newDomainCookie, &attrs, &found))); EXPECT_TRUE(NS_SUCCEEDED(cookieMgr2->CookieExistsNative(newDomainCookie, &attrs, &found)));
EXPECT_FALSE(found); EXPECT_FALSE(found);
// sleep four seconds, to make sure the second cookie has expired // sleep four seconds, to make sure the second cookie has expired
@ -764,8 +768,53 @@ TEST(TestCookie,TestCookieMain)
} }
} }
GetACookie(cookieService, "http://creation.ordering.tests/", nullptr, getter_Copies(cookie)); GetACookie(cookieService, "http://creation.ordering.tests/", nullptr, getter_Copies(cookie));
EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL));
// *** SameSite attribute - parsing and cookie storage tests
// Clear the cookies
EXPECT_TRUE(NS_SUCCEEDED(cookieMgr->RemoveAll()));
// Set cookies with various incantations of the samesite attribute:
// No same site attribute present
SetACookie(cookieService, "http://samesite.test", nullptr, "unset=yes", nullptr);
// samesite attribute present but with no value
SetACookie(cookieService, "http://samesite.test", nullptr, "unspecified=yes; samesite", nullptr);
// samesite=strict
SetACookie(cookieService, "http://samesite.test", nullptr, "strict=yes; samesite=strict", nullptr);
// samesite=lax
SetACookie(cookieService, "http://samesite.test", nullptr, "lax=yes; samesite=lax", nullptr);
EXPECT_TRUE(NS_SUCCEEDED(cookieMgr->GetEnumerator(getter_AddRefs(enumerator))));
i = 0;
// check the cookies for the required samesite value
while (NS_SUCCEEDED(enumerator->HasMoreElements(&more)) && more) {
nsCOMPtr<nsISupports> cookie;
if (NS_FAILED(enumerator->GetNext(getter_AddRefs(cookie)))) break;
++i;
// keep tabs on the second and third cookies, so we can check them later
nsCOMPtr<nsICookie2> cookie2(do_QueryInterface(cookie));
if (!cookie2) break;
nsAutoCString name;
cookie2->GetName(name);
int32_t sameSiteAttr;
cookie2->GetSameSite(&sameSiteAttr);
if (name.EqualsLiteral("unset")) {
EXPECT_TRUE(sameSiteAttr == nsICookie2::SAMESITE_UNSET);
} else if (name.EqualsLiteral("unspecified")) {
EXPECT_TRUE(sameSiteAttr == nsICookie2::SAMESITE_STRICT);
} else if (name.EqualsLiteral("strict")) {
EXPECT_TRUE(sameSiteAttr == nsICookie2::SAMESITE_STRICT);
} else if (name.EqualsLiteral("lax")) {
EXPECT_TRUE(sameSiteAttr == nsICookie2::SAMESITE_LAX);
}
}
EXPECT_TRUE(i == 4);
// XXX the following are placeholders: add these tests please! // XXX the following are placeholders: add these tests please!
// *** "noncompliant cookie" tests // *** "noncompliant cookie" tests
// *** IP address tests // *** IP address tests