mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 23:31:56 +00:00
Bug 1331680 - Part 2: Use local cookie hashtable in content process, and perform cookie permission checks synchronously. r=jdm
This commit is contained in:
parent
1f101b071c
commit
b01732f8ca
@ -2212,6 +2212,7 @@ pref("network.cookie.cookieBehavior", 0); // Keep the old default of accep
|
||||
#endif
|
||||
pref("network.cookie.thirdparty.sessionOnly", false);
|
||||
pref("network.cookie.leave-secure-alone", true);
|
||||
pref("network.cookie.ipc.sync", false);
|
||||
pref("network.cookie.lifetimePolicy", 0); // 0-accept, 1-dontUse 2-acceptForSession, 3-acceptForNDays
|
||||
pref("network.cookie.prefsMigrated", false);
|
||||
pref("network.cookie.lifetime.days", 90); // Ignored unless network.cookie.lifetimePolicy is 3.
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsICookiePermission.h"
|
||||
#include "nsIEffectiveTLDService.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIPrefService.h"
|
||||
@ -31,6 +32,8 @@ namespace net {
|
||||
static const char kPrefCookieBehavior[] = "network.cookie.cookieBehavior";
|
||||
static const char kPrefThirdPartySession[] =
|
||||
"network.cookie.thirdparty.sessionOnly";
|
||||
static const char kPrefCookieIPCSync[] = "network.cookie.ipc.sync";
|
||||
static const char kCookieLeaveSecurityAlone[] = "network.cookie.leave-secure-alone";
|
||||
|
||||
static CookieServiceChild *gCookieService;
|
||||
|
||||
@ -52,6 +55,8 @@ NS_IMPL_ISUPPORTS(CookieServiceChild,
|
||||
CookieServiceChild::CookieServiceChild()
|
||||
: mCookieBehavior(nsICookieService::BEHAVIOR_ACCEPT)
|
||||
, mThirdPartySession(false)
|
||||
, mIPCSync(false)
|
||||
, mLeaveSecureAlone(true)
|
||||
{
|
||||
NS_ASSERTION(IsNeckoChild(), "not a child process");
|
||||
|
||||
@ -78,6 +83,8 @@ CookieServiceChild::CookieServiceChild()
|
||||
if (prefBranch) {
|
||||
prefBranch->AddObserver(kPrefCookieBehavior, this, true);
|
||||
prefBranch->AddObserver(kPrefThirdPartySession, this, true);
|
||||
prefBranch->AddObserver(kPrefCookieIPCSync, this, true);
|
||||
prefBranch->AddObserver(kCookieLeaveSecurityAlone, this, true);
|
||||
PrefChanged(prefBranch);
|
||||
}
|
||||
}
|
||||
@ -142,12 +149,145 @@ CookieServiceChild::PrefChanged(nsIPrefBranch *aPrefBranch)
|
||||
if (NS_SUCCEEDED(aPrefBranch->GetBoolPref(kPrefThirdPartySession, &boolval)))
|
||||
mThirdPartySession = !!boolval;
|
||||
|
||||
if (NS_SUCCEEDED(aPrefBranch->GetBoolPref(kPrefCookieIPCSync, &boolval)))
|
||||
mIPCSync = !!boolval;
|
||||
|
||||
if (NS_SUCCEEDED(aPrefBranch->GetBoolPref(kCookieLeaveSecurityAlone, &boolval)))
|
||||
mLeaveSecureAlone = !!boolval;
|
||||
|
||||
if (!mThirdPartyUtil && RequireThirdPartyCheck()) {
|
||||
mThirdPartyUtil = do_GetService(THIRDPARTYUTIL_CONTRACTID);
|
||||
NS_ASSERTION(mThirdPartyUtil, "require ThirdPartyUtil service");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CookieServiceChild::GetCookieStringFromCookieHashTable(nsIURI *aHostURI,
|
||||
bool aIsForeign,
|
||||
const OriginAttributes &aOriginAttrs,
|
||||
nsCString &aCookieString)
|
||||
{
|
||||
nsCOMPtr<nsIEffectiveTLDService> TLDService =
|
||||
do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
|
||||
NS_ASSERTION(TLDService, "Can't get TLDService");
|
||||
bool requireHostMatch;
|
||||
nsAutoCString baseDomain;
|
||||
nsCookieService::
|
||||
GetBaseDomain(TLDService, aHostURI, baseDomain, requireHostMatch);
|
||||
nsCookieKey key(baseDomain, aOriginAttrs);
|
||||
CookiesList *cookiesList = nullptr;
|
||||
mCookiesMap.Get(key, &cookiesList);
|
||||
|
||||
if (!cookiesList) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoCString hostFromURI, pathFromURI;
|
||||
bool isSecure;
|
||||
aHostURI->GetAsciiHost(hostFromURI);
|
||||
aHostURI->GetPath(pathFromURI);
|
||||
aHostURI->SchemeIs("https", &isSecure);
|
||||
int64_t currentTimeInUsec = PR_Now();
|
||||
int64_t currentTime = currentTimeInUsec / PR_USEC_PER_SEC;
|
||||
|
||||
nsCOMPtr<nsICookiePermission> permissionService = do_GetService(NS_COOKIEPERMISSION_CONTRACTID);
|
||||
CookieStatus cookieStatus =
|
||||
nsCookieService::CheckPrefs(permissionService, mCookieBehavior,
|
||||
mThirdPartySession, aHostURI,
|
||||
aIsForeign, nullptr,
|
||||
CountCookiesFromHashTable(baseDomain, aOriginAttrs));
|
||||
|
||||
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;
|
||||
|
||||
// if the cookie is secure and the host scheme isn't, we can't send it
|
||||
if (cookie->IsSecure() && !isSecure)
|
||||
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.Append("; ");
|
||||
}
|
||||
if (!cookie->Name().IsEmpty()) {
|
||||
aCookieString.Append(cookie->Name().get());
|
||||
aCookieString.Append("=");
|
||||
aCookieString.Append(cookie->Value().get());
|
||||
} else {
|
||||
aCookieString.Append(cookie->Value().get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CookieServiceChild::GetCookieStringSyncIPC(nsIURI *aHostURI,
|
||||
bool aIsForeign,
|
||||
const OriginAttributes &aAttrs,
|
||||
nsAutoCString &aCookieString)
|
||||
{
|
||||
URIParams uriParams;
|
||||
SerializeURI(aHostURI, uriParams);
|
||||
|
||||
SendGetCookieString(uriParams, aIsForeign, aAttrs, &aCookieString);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (aCookieAttributes.isHttpOnly) {
|
||||
return;
|
||||
}
|
||||
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);
|
||||
|
||||
RecordDocumentCookie(cookie, aAttrs);
|
||||
}
|
||||
|
||||
bool
|
||||
CookieServiceChild::RequireThirdPartyCheck()
|
||||
{
|
||||
@ -206,14 +346,6 @@ CookieServiceChild::GetCookieStringInternal(nsIURI *aHostURI,
|
||||
if (scheme.EqualsLiteral("moz-nullprincipal"))
|
||||
return NS_OK;
|
||||
|
||||
// Determine whether the request is foreign. Failure is acceptable.
|
||||
bool isForeign = true;
|
||||
if (RequireThirdPartyCheck())
|
||||
mThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI, &isForeign);
|
||||
|
||||
URIParams uriParams;
|
||||
SerializeURI(aHostURI, uriParams);
|
||||
|
||||
mozilla::OriginAttributes attrs;
|
||||
if (aChannel) {
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
|
||||
@ -222,9 +354,16 @@ CookieServiceChild::GetCookieStringInternal(nsIURI *aHostURI,
|
||||
}
|
||||
}
|
||||
|
||||
// Synchronously call the parent.
|
||||
// Asynchronously call the parent.
|
||||
bool isForeign = true;
|
||||
if (RequireThirdPartyCheck())
|
||||
mThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI, &isForeign);
|
||||
nsAutoCString result;
|
||||
SendGetCookieString(uriParams, !!isForeign, attrs, &result);
|
||||
if (!mIPCSync) {
|
||||
GetCookieStringFromCookieHashTable(aHostURI, !!isForeign, attrs, result);
|
||||
} else {
|
||||
GetCookieStringSyncIPC(aHostURI, !!isForeign, attrs, result);
|
||||
}
|
||||
|
||||
if (!result.IsEmpty())
|
||||
*aCookieString = ToNewCString(result);
|
||||
@ -255,9 +394,9 @@ CookieServiceChild::SetCookieStringInternal(nsIURI *aHostURI,
|
||||
mThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI, &isForeign);
|
||||
|
||||
nsDependentCString cookieString(aCookieString);
|
||||
nsDependentCString serverTime;
|
||||
nsDependentCString stringServerTime;
|
||||
if (aServerTime)
|
||||
serverTime.Rebind(aServerTime);
|
||||
stringServerTime.Rebind(aServerTime);
|
||||
|
||||
URIParams uriParams;
|
||||
SerializeURI(aHostURI, uriParams);
|
||||
@ -270,9 +409,53 @@ CookieServiceChild::SetCookieStringInternal(nsIURI *aHostURI,
|
||||
}
|
||||
}
|
||||
|
||||
// Synchronously call the parent.
|
||||
SendSetCookieString(uriParams, !!isForeign, cookieString, serverTime,
|
||||
attrs, aFromHttp);
|
||||
// Asynchronously call the parent.
|
||||
SendSetCookieString(uriParams, !!isForeign, cookieString,
|
||||
stringServerTime, attrs, aFromHttp);
|
||||
if (mIPCSync) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool requireHostMatch;
|
||||
nsCString baseDomain;
|
||||
nsCookieService::
|
||||
GetBaseDomain(mTLDService, aHostURI, baseDomain, requireHostMatch);
|
||||
|
||||
nsCOMPtr<nsICookiePermission> permissionService = do_GetService(NS_COOKIEPERMISSION_CONTRACTID);
|
||||
|
||||
CookieStatus cookieStatus =
|
||||
nsCookieService::CheckPrefs(permissionService, mCookieBehavior,
|
||||
mThirdPartySession, aHostURI,
|
||||
!!isForeign, aCookieString,
|
||||
CountCookiesFromHashTable(baseDomain, attrs));
|
||||
|
||||
if (cookieStatus != STATUS_ACCEPTED && cookieStatus != STATUS_ACCEPT_SESSION) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCString serverTimeString(aServerTime);
|
||||
int64_t serverTime = nsCookieService::ParseServerTime(serverTimeString);
|
||||
bool moreCookies;
|
||||
do {
|
||||
nsCookieAttributes cookieAttributes;
|
||||
bool canSetCookie = false;
|
||||
nsCookieKey key(baseDomain, attrs);
|
||||
moreCookies = nsCookieService::CanSetCookie(aHostURI, key, cookieAttributes,
|
||||
requireHostMatch, cookieStatus,
|
||||
cookieString, serverTime, aFromHttp,
|
||||
aChannel, mLeaveSecureAlone, canSetCookie);
|
||||
|
||||
if (canSetCookie) {
|
||||
SetCookieInternal(cookieAttributes, attrs, aChannel,
|
||||
aFromHttp, permissionService);
|
||||
}
|
||||
|
||||
// document.cookie can only set one cookie at a time.
|
||||
if (!aFromHttp) {
|
||||
break;
|
||||
}
|
||||
|
||||
} while (moreCookies);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -16,8 +16,11 @@
|
||||
#include "nsWeakReference.h"
|
||||
|
||||
class nsCookie;
|
||||
class nsICookiePermission;
|
||||
class nsIEffectiveTLDService;
|
||||
|
||||
struct nsCookieAttributes;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
class CookieStruct;
|
||||
@ -56,6 +59,17 @@ protected:
|
||||
nsIChannel *aChannel,
|
||||
char **aCookieString);
|
||||
|
||||
void GetCookieStringFromCookieHashTable(nsIURI *aHostURI,
|
||||
bool aIsForeign,
|
||||
const OriginAttributes &aAttrs,
|
||||
nsCString &aCookieString);
|
||||
|
||||
void
|
||||
GetCookieStringSyncIPC(nsIURI *aHostURI,
|
||||
bool aIsForeign,
|
||||
const OriginAttributes &aAttrs,
|
||||
nsAutoCString &aCookieString);
|
||||
|
||||
nsresult SetCookieStringInternal(nsIURI *aHostURI,
|
||||
nsIChannel *aChannel,
|
||||
const char *aCookieString,
|
||||
@ -66,6 +80,17 @@ protected:
|
||||
RecordDocumentCookie(nsCookie *aCookie,
|
||||
const OriginAttributes &aAttrs);
|
||||
|
||||
void
|
||||
SetCookieInternal(nsCookieAttributes &aCookieAttributes,
|
||||
const mozilla::OriginAttributes &aAttrs,
|
||||
nsIChannel *aChannel,
|
||||
bool aFromHttp,
|
||||
nsICookiePermission *aPermissionService);
|
||||
|
||||
uint32_t
|
||||
CountCookiesFromHashTable(const nsCString &aBaseDomain,
|
||||
const OriginAttributes &aOriginAttrs);
|
||||
|
||||
void PrefChanged(nsIPrefBranch *aPrefBranch);
|
||||
|
||||
bool RequireThirdPartyCheck();
|
||||
@ -79,6 +104,8 @@ protected:
|
||||
nsCOMPtr<nsIEffectiveTLDService> mTLDService;
|
||||
uint8_t mCookieBehavior;
|
||||
bool mThirdPartySession;
|
||||
bool mIPCSync;
|
||||
bool mLeaveSecureAlone;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
|
@ -19,6 +19,8 @@
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
|
||||
#include "nsIIOService.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsIProtocolHandler.h"
|
||||
#include "nsIPrefBranch.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "nsIScriptError.h"
|
||||
@ -137,21 +139,6 @@ bindCookieParameters(mozIStorageBindingParamsArray *aParamsArray,
|
||||
const nsCookieKey &aKey,
|
||||
const nsCookie *aCookie);
|
||||
|
||||
// struct for temporarily storing cookie attributes during header parsing
|
||||
struct nsCookieAttributes
|
||||
{
|
||||
nsAutoCString name;
|
||||
nsAutoCString value;
|
||||
nsAutoCString host;
|
||||
nsAutoCString path;
|
||||
nsAutoCString expires;
|
||||
nsAutoCString maxage;
|
||||
int64_t expiryTime;
|
||||
bool isSession;
|
||||
bool isSecure;
|
||||
bool isHttpOnly;
|
||||
};
|
||||
|
||||
// stores the nsCookieEntry entryclass and an index into the cookie array
|
||||
// within that entryclass, for purposes of storing an iteration state that
|
||||
// points to a certain cookie.
|
||||
@ -2054,6 +2041,27 @@ nsCookieService::SetCookieStringFromHttp(nsIURI *aHostURI,
|
||||
true);
|
||||
}
|
||||
|
||||
int64_t
|
||||
nsCookieService::ParseServerTime(const nsCString &aServerTime)
|
||||
{
|
||||
// parse server local time. this is not just done here for efficiency
|
||||
// reasons - if there's an error parsing it, and we need to default it
|
||||
// to the current time, we must do it here since the current time in
|
||||
// SetCookieInternal() will change for each cookie processed (e.g. if the
|
||||
// user is prompted).
|
||||
PRTime tempServerTime;
|
||||
int64_t serverTime;
|
||||
PRStatus result = PR_ParseTimeString(aServerTime.get(), true,
|
||||
&tempServerTime);
|
||||
if (result == PR_SUCCESS) {
|
||||
serverTime = tempServerTime / int64_t(PR_USEC_PER_SEC);
|
||||
} else {
|
||||
serverTime = PR_Now() / PR_USEC_PER_SEC;
|
||||
}
|
||||
|
||||
return serverTime;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCookieService::SetCookieStringCommon(nsIURI *aHostURI,
|
||||
const char *aCookieHeader,
|
||||
@ -2117,7 +2125,13 @@ nsCookieService::SetCookieStringInternal(nsIURI *aHostURI,
|
||||
nsCookieKey key(baseDomain, aOriginAttrs);
|
||||
|
||||
// check default prefs
|
||||
CookieStatus cookieStatus = CheckPrefs(aHostURI, aIsForeign, aCookieHeader.get());
|
||||
uint32_t priorCookieCount = 0;
|
||||
nsAutoCString hostFromURI;
|
||||
aHostURI->GetHost(hostFromURI);
|
||||
CountCookiesFromHost(hostFromURI, &priorCookieCount);
|
||||
CookieStatus cookieStatus = CheckPrefs(mPermissionService, mCookieBehavior,
|
||||
mThirdPartySession, aHostURI, aIsForeign,
|
||||
aCookieHeader.get(), priorCookieCount);
|
||||
|
||||
// fire a notification if third party or if cookie was rejected
|
||||
// (but not if there was an error)
|
||||
@ -2140,20 +2154,7 @@ nsCookieService::SetCookieStringInternal(nsIURI *aHostURI,
|
||||
break;
|
||||
}
|
||||
|
||||
// parse server local time. this is not just done here for efficiency
|
||||
// reasons - if there's an error parsing it, and we need to default it
|
||||
// to the current time, we must do it here since the current time in
|
||||
// SetCookieInternal() will change for each cookie processed (e.g. if the
|
||||
// user is prompted).
|
||||
PRTime tempServerTime;
|
||||
int64_t serverTime;
|
||||
PRStatus result = PR_ParseTimeString(aServerTime.get(), true,
|
||||
&tempServerTime);
|
||||
if (result == PR_SUCCESS) {
|
||||
serverTime = tempServerTime / int64_t(PR_USEC_PER_SEC);
|
||||
} else {
|
||||
serverTime = PR_Now() / PR_USEC_PER_SEC;
|
||||
}
|
||||
int64_t serverTime = ParseServerTime(aServerTime);
|
||||
|
||||
// process each cookie in the header
|
||||
while (SetCookieInternal(aHostURI, key, requireHostMatch, cookieStatus,
|
||||
@ -3271,7 +3272,11 @@ nsCookieService::GetCookiesForURI(nsIURI *aHostURI,
|
||||
}
|
||||
|
||||
// check default prefs
|
||||
CookieStatus cookieStatus = CheckPrefs(aHostURI, aIsForeign, nullptr);
|
||||
uint32_t priorCookieCount = 0;
|
||||
CountCookiesFromHost(hostFromURI, &priorCookieCount);
|
||||
CookieStatus cookieStatus = CheckPrefs(mPermissionService, mCookieBehavior,
|
||||
mThirdPartySession, aHostURI, aIsForeign,
|
||||
nullptr, priorCookieCount);
|
||||
|
||||
// for GetCookie(), we don't fire rejection notifications.
|
||||
switch (cookieStatus) {
|
||||
@ -3424,23 +3429,24 @@ nsCookieService::GetCookieStringInternal(nsIURI *aHostURI,
|
||||
// processes a single cookie, and returns true if there are more cookies
|
||||
// to be processed
|
||||
bool
|
||||
nsCookieService::SetCookieInternal(nsIURI *aHostURI,
|
||||
const nsCookieKey &aKey,
|
||||
bool aRequireHostMatch,
|
||||
CookieStatus aStatus,
|
||||
nsDependentCString &aCookieHeader,
|
||||
int64_t aServerTime,
|
||||
bool aFromHttp,
|
||||
nsIChannel *aChannel)
|
||||
nsCookieService::CanSetCookie(nsIURI* aHostURI,
|
||||
const nsCookieKey& aKey,
|
||||
nsCookieAttributes& aCookieAttributes,
|
||||
bool aRequireHostMatch,
|
||||
CookieStatus aStatus,
|
||||
nsDependentCString& aCookieHeader,
|
||||
int64_t aServerTime,
|
||||
bool aFromHttp,
|
||||
nsIChannel* aChannel,
|
||||
bool aLeaveSecureAlone,
|
||||
bool& aSetCookie)
|
||||
{
|
||||
NS_ASSERTION(aHostURI, "null host!");
|
||||
|
||||
// create a stack-based nsCookieAttributes, to store all the
|
||||
// attributes parsed from the cookie
|
||||
nsCookieAttributes cookieAttributes;
|
||||
aSetCookie = false;
|
||||
|
||||
// init expiryTime such that session cookies won't prematurely expire
|
||||
cookieAttributes.expiryTime = INT64_MAX;
|
||||
aCookieAttributes.expiryTime = INT64_MAX;
|
||||
|
||||
// aCookieHeader is an in/out param to point to the next cookie, if
|
||||
// there is one. Save the present value for logging purposes
|
||||
@ -3448,7 +3454,7 @@ nsCookieService::SetCookieInternal(nsIURI *aHostURI,
|
||||
|
||||
// newCookie says whether there are multiple cookies in the header;
|
||||
// so we can handle them separately.
|
||||
bool newCookie = ParseAttributes(aCookieHeader, cookieAttributes);
|
||||
bool newCookie = ParseAttributes(aCookieHeader, aCookieAttributes);
|
||||
|
||||
// Collect telemetry on how often secure cookies are set from non-secure
|
||||
// origins, and vice-versa.
|
||||
@ -3461,23 +3467,23 @@ nsCookieService::SetCookieInternal(nsIURI *aHostURI,
|
||||
nsresult rv = aHostURI->SchemeIs("https", &isHTTPS);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
Telemetry::Accumulate(Telemetry::COOKIE_SCHEME_SECURITY,
|
||||
((cookieAttributes.isSecure)? 0x02 : 0x00) |
|
||||
((aCookieAttributes.isSecure)? 0x02 : 0x00) |
|
||||
((isHTTPS)? 0x01 : 0x00));
|
||||
}
|
||||
|
||||
int64_t currentTimeInUsec = PR_Now();
|
||||
|
||||
// calculate expiry time of cookie.
|
||||
cookieAttributes.isSession = GetExpiry(cookieAttributes, aServerTime,
|
||||
aCookieAttributes.isSession = GetExpiry(aCookieAttributes, aServerTime,
|
||||
currentTimeInUsec / PR_USEC_PER_SEC);
|
||||
if (aStatus == STATUS_ACCEPT_SESSION) {
|
||||
// force lifetime to session. note that the expiration time, if set above,
|
||||
// will still apply.
|
||||
cookieAttributes.isSession = true;
|
||||
aCookieAttributes.isSession = true;
|
||||
}
|
||||
|
||||
// reject cookie if it's over the size limit, per RFC2109
|
||||
if ((cookieAttributes.name.Length() + cookieAttributes.value.Length()) > kMaxBytesPerCookie) {
|
||||
if ((aCookieAttributes.name.Length() + aCookieAttributes.value.Length()) > kMaxBytesPerCookie) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader, "cookie too big (> 4kb)");
|
||||
return newCookie;
|
||||
}
|
||||
@ -3488,22 +3494,22 @@ nsCookieService::SetCookieInternal(nsIURI *aHostURI,
|
||||
0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
||||
0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E,
|
||||
0x1F, 0x00 };
|
||||
if (cookieAttributes.name.FindCharInSet(illegalNameCharacters, 0) != -1) {
|
||||
if (aCookieAttributes.name.FindCharInSet(illegalNameCharacters, 0) != -1) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader, "invalid name character");
|
||||
return newCookie;
|
||||
}
|
||||
|
||||
// domain & path checks
|
||||
if (!CheckDomain(cookieAttributes, aHostURI, aKey.mBaseDomain, aRequireHostMatch)) {
|
||||
if (!CheckDomain(aCookieAttributes, aHostURI, aKey.mBaseDomain, aRequireHostMatch)) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader, "failed the domain tests");
|
||||
return newCookie;
|
||||
}
|
||||
if (!CheckPath(cookieAttributes, aHostURI)) {
|
||||
if (!CheckPath(aCookieAttributes, aHostURI)) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader, "failed the path tests");
|
||||
return newCookie;
|
||||
}
|
||||
// magic prefix checks. MUST be run after CheckDomain() and CheckPath()
|
||||
if (!CheckPrefixes(cookieAttributes, isHTTPS)) {
|
||||
if (!CheckPrefixes(aCookieAttributes, isHTTPS)) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader, "failed the prefix tests");
|
||||
return newCookie;
|
||||
}
|
||||
@ -3520,11 +3526,63 @@ nsCookieService::SetCookieInternal(nsIURI *aHostURI,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
|
||||
0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
|
||||
0x1E, 0x1F, 0x3B, 0x00 };
|
||||
if (aFromHttp && (cookieAttributes.value.FindCharInSet(illegalCharacters, 0) != -1)) {
|
||||
if (aFromHttp && (aCookieAttributes.value.FindCharInSet(illegalCharacters, 0) != -1)) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader, "invalid value character");
|
||||
return newCookie;
|
||||
}
|
||||
|
||||
// if the new cookie is httponly, make sure we're not coming from script
|
||||
if (!aFromHttp && aCookieAttributes.isHttpOnly) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader,
|
||||
"cookie is httponly; coming from script");
|
||||
return newCookie;
|
||||
}
|
||||
|
||||
bool isSecure = true;
|
||||
if (aHostURI) {
|
||||
aHostURI->SchemeIs("https", &isSecure);
|
||||
}
|
||||
|
||||
// If the new cookie is non-https and wants to set secure flag,
|
||||
// browser have to ignore this new cookie.
|
||||
// (draft-ietf-httpbis-cookie-alone section 3.1)
|
||||
if (aLeaveSecureAlone && aCookieAttributes.isSecure && !isSecure) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader,
|
||||
"non-https cookie can't set secure flag");
|
||||
Telemetry::Accumulate(Telemetry::COOKIE_LEAVE_SECURE_ALONE,
|
||||
BLOCKED_SECURE_SET_FROM_HTTP);
|
||||
return newCookie;
|
||||
}
|
||||
|
||||
aSetCookie = true;
|
||||
return newCookie;
|
||||
}
|
||||
|
||||
// processes a single cookie, and returns true if there are more cookies
|
||||
// to be processed
|
||||
bool
|
||||
nsCookieService::SetCookieInternal(nsIURI *aHostURI,
|
||||
const mozilla::nsCookieKey &aKey,
|
||||
bool aRequireHostMatch,
|
||||
CookieStatus aStatus,
|
||||
nsDependentCString &aCookieHeader,
|
||||
int64_t aServerTime,
|
||||
bool aFromHttp,
|
||||
nsIChannel *aChannel)
|
||||
{
|
||||
NS_ASSERTION(aHostURI, "null host!");
|
||||
bool canSetCookie = false;
|
||||
nsDependentCString savedCookieHeader(aCookieHeader);
|
||||
nsCookieAttributes cookieAttributes;
|
||||
bool newCookie = CanSetCookie(aHostURI, aKey, cookieAttributes, aRequireHostMatch,
|
||||
aStatus, aCookieHeader, aServerTime, aFromHttp,
|
||||
aChannel, mLeaveSecureAlone, canSetCookie);
|
||||
|
||||
if (!canSetCookie) {
|
||||
return newCookie;
|
||||
}
|
||||
|
||||
int64_t currentTimeInUsec = PR_Now();
|
||||
// create a new nsCookie and copy attributes
|
||||
RefPtr<nsCookie> cookie =
|
||||
nsCookie::Create(cookieAttributes.name,
|
||||
@ -3584,33 +3642,15 @@ nsCookieService::AddInternal(const nsCookieKey &aKey,
|
||||
{
|
||||
int64_t currentTime = aCurrentTimeInUsec / PR_USEC_PER_SEC;
|
||||
|
||||
// if the new cookie is httponly, make sure we're not coming from script
|
||||
if (!aFromHttp && aCookie->IsHttpOnly()) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader,
|
||||
"cookie is httponly; coming from script");
|
||||
return;
|
||||
}
|
||||
|
||||
bool isSecure = true;
|
||||
if (aHostURI && NS_FAILED(aHostURI->SchemeIs("https", &isSecure))) {
|
||||
isSecure = false;
|
||||
}
|
||||
|
||||
// If the new cookie is non-https and wants to set secure flag,
|
||||
// browser have to ignore this new cookie.
|
||||
// (draft-ietf-httpbis-cookie-alone section 3.1)
|
||||
if (mLeaveSecureAlone && aCookie->IsSecure() && !isSecure) {
|
||||
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader,
|
||||
"non-https cookie can't set secure flag");
|
||||
Telemetry::Accumulate(Telemetry::COOKIE_LEAVE_SECURE_ALONE,
|
||||
BLOCKED_SECURE_SET_FROM_HTTP);
|
||||
return;
|
||||
}
|
||||
nsListIter exactIter;
|
||||
bool foundCookie = false;
|
||||
foundCookie = FindCookie(aKey, aCookie->Host(),
|
||||
aCookie->Name(), aCookie->Path(), exactIter);
|
||||
bool foundSecureExact = foundCookie && exactIter.Cookie()->IsSecure();
|
||||
bool isSecure = true;
|
||||
if (aHostURI && NS_FAILED(aHostURI->SchemeIs("https", &isSecure))) {
|
||||
isSecure = false;
|
||||
}
|
||||
bool oldCookieIsSession = false;
|
||||
if (mLeaveSecureAlone) {
|
||||
// Step1, call FindSecureCookie(). FindSecureCookie() would
|
||||
@ -4123,9 +4163,13 @@ static inline bool IsSubdomainOf(const nsCString &a, const nsCString &b)
|
||||
}
|
||||
|
||||
CookieStatus
|
||||
nsCookieService::CheckPrefs(nsIURI *aHostURI,
|
||||
bool aIsForeign,
|
||||
const char *aCookieHeader)
|
||||
nsCookieService::CheckPrefs(nsICookiePermission *aPermissionService,
|
||||
uint8_t aCookieBehavior,
|
||||
bool aThirdPartySession,
|
||||
nsIURI *aHostURI,
|
||||
bool aIsForeign,
|
||||
const char *aCookieHeader,
|
||||
const int aNumOfCookies)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
@ -4138,11 +4182,11 @@ nsCookieService::CheckPrefs(nsIURI *aHostURI,
|
||||
|
||||
// check the permission list first; if we find an entry, it overrides
|
||||
// default prefs. see bug 184059.
|
||||
if (mPermissionService) {
|
||||
if (aPermissionService) {
|
||||
nsCookieAccess access;
|
||||
// Not passing an nsIChannel here is probably OK; our implementation
|
||||
// doesn't do anything with it anyway.
|
||||
rv = mPermissionService->CanAccess(aHostURI, nullptr, &access);
|
||||
rv = aPermissionService->CanAccess(aHostURI, nullptr, &access);
|
||||
|
||||
// if we found an entry, use it
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
@ -4168,11 +4212,7 @@ nsCookieService::CheckPrefs(nsIURI *aHostURI,
|
||||
case nsICookiePermission::ACCESS_LIMIT_THIRD_PARTY:
|
||||
if (!aIsForeign)
|
||||
return STATUS_ACCEPTED;
|
||||
uint32_t priorCookieCount = 0;
|
||||
nsAutoCString hostFromURI;
|
||||
aHostURI->GetHost(hostFromURI);
|
||||
CountCookiesFromHost(hostFromURI, &priorCookieCount);
|
||||
if (priorCookieCount == 0) {
|
||||
if (aNumOfCookies == 0) {
|
||||
COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI,
|
||||
aCookieHeader, "third party cookies are blocked "
|
||||
"for this site");
|
||||
@ -4184,31 +4224,27 @@ nsCookieService::CheckPrefs(nsIURI *aHostURI,
|
||||
}
|
||||
|
||||
// check default prefs
|
||||
if (mCookieBehavior == nsICookieService::BEHAVIOR_REJECT) {
|
||||
if (aCookieBehavior == nsICookieService::BEHAVIOR_REJECT) {
|
||||
COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "cookies are disabled");
|
||||
return STATUS_REJECTED;
|
||||
}
|
||||
|
||||
// check if cookie is foreign
|
||||
if (aIsForeign) {
|
||||
if (mCookieBehavior == nsICookieService::BEHAVIOR_ACCEPT && mThirdPartySession)
|
||||
if (aCookieBehavior == nsICookieService::BEHAVIOR_ACCEPT && aThirdPartySession)
|
||||
return STATUS_ACCEPT_SESSION;
|
||||
|
||||
if (mCookieBehavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN) {
|
||||
if (aCookieBehavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN) {
|
||||
COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "context is third party");
|
||||
return STATUS_REJECTED;
|
||||
}
|
||||
|
||||
if (mCookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN) {
|
||||
uint32_t priorCookieCount = 0;
|
||||
nsAutoCString hostFromURI;
|
||||
aHostURI->GetHost(hostFromURI);
|
||||
CountCookiesFromHost(hostFromURI, &priorCookieCount);
|
||||
if (priorCookieCount == 0) {
|
||||
if (aCookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN) {
|
||||
if (aNumOfCookies == 0) {
|
||||
COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "context is third party");
|
||||
return STATUS_REJECTED;
|
||||
}
|
||||
if (mThirdPartySession)
|
||||
if (aThirdPartySession)
|
||||
return STATUS_ACCEPT_SESSION;
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +47,6 @@ class mozIStorageService;
|
||||
class mozIThirdPartyUtil;
|
||||
class ReadCookieDBListener;
|
||||
|
||||
struct nsCookieAttributes;
|
||||
struct nsListIter;
|
||||
|
||||
namespace mozilla {
|
||||
@ -183,6 +182,21 @@ enum OpenDBResult
|
||||
* class declaration
|
||||
******************************************************************************/
|
||||
|
||||
// struct for temporarily storing cookie attributes during header parsing
|
||||
struct nsCookieAttributes
|
||||
{
|
||||
nsAutoCString name;
|
||||
nsAutoCString value;
|
||||
nsAutoCString host;
|
||||
nsAutoCString path;
|
||||
nsAutoCString expires;
|
||||
nsAutoCString maxage;
|
||||
int64_t expiryTime;
|
||||
bool isSession;
|
||||
bool isSecure;
|
||||
bool isHttpOnly;
|
||||
};
|
||||
|
||||
class nsCookieService final : public nsICookieService
|
||||
, public nsICookieManager2
|
||||
, public nsIObserver
|
||||
@ -216,6 +230,9 @@ class nsCookieService final : public nsICookieService
|
||||
static nsresult GetBaseDomainFromHost(nsIEffectiveTLDService *aTLDService, const nsACString &aHost, nsCString &aBaseDomain);
|
||||
static bool DomainMatches(nsCookie* aCookie, const nsACString& aHost);
|
||||
static bool PathMatches(nsCookie* aCookie, const nsACString& aPath);
|
||||
static bool CanSetCookie(nsIURI *aHostURI, const nsCookieKey& aKey, nsCookieAttributes &aCookieAttributes, bool aRequireHostMatch, CookieStatus aStatus, nsDependentCString &aCookieHeader, int64_t aServerTime, bool aFromHttp, nsIChannel* aChannel, bool aLeaveSercureAlone, bool &aSetCookie);
|
||||
static CookieStatus CheckPrefs(nsICookiePermission *aPermissionServices, uint8_t aCookieBehavior, bool aThirdPartyUtil, nsIURI *aHostURI, bool aIsForeign, const char *aCookieHeader, const int aNumOfCookies);
|
||||
static int64_t ParseServerTime(const nsCString &aServerTime);
|
||||
void GetCookiesForURI(nsIURI *aHostURI, bool aIsForeign, bool aHttpBound, const OriginAttributes& aOriginAttrs, nsTArray<nsCookie*>& aCookieList);
|
||||
|
||||
protected:
|
||||
@ -254,8 +271,7 @@ class nsCookieService final : public nsICookieService
|
||||
static bool GetTokenValue(nsACString::const_char_iterator &aIter, nsACString::const_char_iterator &aEndIter, nsDependentCSubstring &aTokenString, nsDependentCSubstring &aTokenValue, bool &aEqualsFound);
|
||||
static bool ParseAttributes(nsDependentCString &aCookieHeader, nsCookieAttributes &aCookie);
|
||||
bool RequireThirdPartyCheck();
|
||||
CookieStatus CheckPrefs(nsIURI *aHostURI, bool aIsForeign, const char *aCookieHeader);
|
||||
bool CheckDomain(nsCookieAttributes &aCookie, nsIURI *aHostURI, const nsCString &aBaseDomain, bool aRequireHostMatch);
|
||||
static bool CheckDomain(nsCookieAttributes &aCookie, nsIURI *aHostURI, const nsCString &aBaseDomain, bool aRequireHostMatch);
|
||||
static bool CheckPath(nsCookieAttributes &aCookie, nsIURI *aHostURI);
|
||||
static bool CheckPrefixes(nsCookieAttributes &aCookie, bool aSecureRequest);
|
||||
static bool GetExpiry(nsCookieAttributes &aCookie, int64_t aServerTime, int64_t aCurrentTime);
|
||||
|
Loading…
Reference in New Issue
Block a user