landing last patch to separate cookie backend from permissions system, b=210561, r=dwitte, sr=bryner

git-svn-id: svn://10.0.0.236/trunk@147853 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
darin%meer.net
2003-10-10 21:23:44 +00:00
parent 2b346eb707
commit caa6b530dd
6 changed files with 373 additions and 294 deletions

View File

@@ -1,3 +1,4 @@
// vim:ts=2:sw=2:et:
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@@ -19,6 +20,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Darin Fisher <darin@meer.net>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -39,8 +41,17 @@
#include "nsICookie.h"
#include "nsIServiceManager.h"
#include "nsICookiePromptService.h"
#include "nsIDOMWindow.h"
#include "nsIURI.h"
#include "nsIPrefService.h"
#include "nsIPrefBranch.h"
#include "nsIPrefBranchInternal.h"
#include "nsIDocShell.h"
#include "nsIDocShellTreeItem.h"
#include "nsIInterfaceRequestor.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsILoadGroup.h"
#include "nsIChannel.h"
#include "nsIDOMWindow.h"
#include "nsString.h"
/****************************************************************
@@ -48,43 +59,186 @@
****************************************************************/
static const PRBool kDefaultPolicy = PR_TRUE;
static const char kCookiesAskPermission[] = "network.cookie.warnAboutCookies";
static const char kCookiesDisabledForMailNews[] = "network.cookie.disableCookieForMailNews";
static const char kPermissionType[] = "cookie";
NS_IMPL_ISUPPORTS1(nsCookiePermission, nsICookiePermission)
NS_IMETHODIMP
nsCookiePermission::TestPermission(nsIURI *aURI,
nsICookie *aCookie,
nsIDOMWindow *aParent,
PRInt32 aCookiesFromHost,
PRBool aChangingCookie,
PRBool aShowDialog,
PRBool *aPermission)
#ifndef MOZ_PHOENIX
// returns PR_TRUE if URI appears to be the URI of a mailnews protocol
static PRBool
IsFromMailNews(nsIURI *aURI)
{
NS_ASSERTION(aURI, "could not get uri");
static const char *kMailNewsProtocols[] =
{ "imap", "news", "snews", "mailbox", nsnull };
PRBool result;
for (const char **p = kMailNewsProtocols; *p; ++p) {
if (NS_SUCCEEDED(aURI->SchemeIs(*p, &result)) && result)
return PR_TRUE;
}
return PR_FALSE;
}
#endif
*aPermission = kDefaultPolicy;
static void
GetInterfaceFromChannel(nsIChannel *aChannel,
const nsIID &aIID,
void **aResult)
{
if (!aChannel)
return; // no context, no interface!
NS_ASSERTION(!*aResult, "result not initialized to null");
nsCOMPtr<nsIInterfaceRequestor> cbs;
aChannel->GetNotificationCallbacks(getter_AddRefs(cbs));
if (cbs)
cbs->GetInterface(aIID, aResult);
if (!*aResult) {
// try load group's notification callbacks...
nsCOMPtr<nsILoadGroup> loadGroup;
aChannel->GetLoadGroup(getter_AddRefs(loadGroup));
if (loadGroup) {
loadGroup->GetNotificationCallbacks(getter_AddRefs(cbs));
if (cbs)
cbs->GetInterface(aIID, aResult);
}
}
}
NS_IMPL_ISUPPORTS2(nsCookiePermission,
nsICookiePermission,
nsIObserver)
nsresult
nsCookiePermission::Init()
{
nsresult rv;
if (!mPermMgr) {
mPermMgr = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
mPermMgr = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
// failure to access the pref service is non-fatal...
nsCOMPtr<nsIPrefBranch> prefBranch =
do_GetService(NS_PREFSERVICE_CONTRACTID);
if (prefBranch) {
nsCOMPtr<nsIPrefBranchInternal> prefInt = do_QueryInterface(prefBranch);
if (prefInt) {
prefInt->AddObserver(kCookiesAskPermission, this, PR_FALSE);
prefInt->AddObserver(kCookiesDisabledForMailNews, this, PR_FALSE);
}
PrefChanged(prefBranch, nsnull);
}
PRUint32 listPermission;
mPermMgr->TestPermission(aURI, "cookie", &listPermission);
if (listPermission == nsIPermissionManager::DENY_ACTION) {
*aPermission = PR_FALSE;
} else if (listPermission == nsIPermissionManager::ALLOW_ACTION) {
*aPermission = PR_TRUE;
} else if (aShowDialog) {
return NS_OK;
}
void
nsCookiePermission::PrefChanged(nsIPrefBranch *prefBranch,
const char *pref)
{
PRBool val;
#define PREF_CHANGED(_P) (!pref || !strcmp(pref, _P))
if (PREF_CHANGED(kCookiesAskPermission) &&
NS_SUCCEEDED(prefBranch->GetBoolPref(kCookiesAskPermission, &val)))
mCookiesAskPermission = val;
#ifndef MOZ_PHOENIX
if (PREF_CHANGED(kCookiesDisabledForMailNews) &&
NS_SUCCEEDED(prefBranch->GetBoolPref(kCookiesDisabledForMailNews, &val)))
mCookiesDisabledForMailNews = val;
#endif
}
NS_IMETHODIMP
nsCookiePermission::SetAccess(nsIURI *aURI,
nsCookieAccess aAccess)
{
//
// NOTE: nsCookieAccess values conveniently match up with
// the permission codes used by nsIPermissionManager.
// this is nice because it avoids conversion code.
//
return mPermMgr->Add(aURI, kPermissionType, aAccess);
}
NS_IMETHODIMP
nsCookiePermission::CanAccess(nsIURI *aURI,
nsIURI *aFirstURI,
nsIChannel *aChannel,
nsCookieAccess *aResult)
{
#ifndef MOZ_PHOENIX
// disable cookies in mailnews if user's prefs say so
if (mCookiesDisabledForMailNews) {
//
// try to examine the "app type" of the docshell owning this request. if
// we find a docshell in the heirarchy of type APP_TYPE_MAIL, then assume
// this URI is being loaded from within mailnews.
//
// XXX this is a pretty ugly hack at the moment since cookies really
// shouldn't have to talk to the docshell directly. ultimately, we want
// to talk to some more generic interface, which the docshell would also
// implement. but, the basic mechanism here of leveraging the channel's
// (or loadgroup's) notification callbacks attribute seems ideal as it
// avoids the problem of having to modify all places in the code which
// kick off network requests.
//
PRUint32 appType = nsIDocShell::APP_TYPE_UNKNOWN;
if (aChannel) {
nsCOMPtr<nsIDocShellTreeItem> item, parent;
GetInterfaceFromChannel(aChannel, NS_GET_IID(nsIDocShellTreeItem),
getter_AddRefs(parent));
if (parent) {
do {
item = parent;
nsCOMPtr<nsIDocShell> docshell = do_QueryInterface(item);
if (docshell)
docshell->GetAppType(&appType);
} while (appType != nsIDocShell::APP_TYPE_MAIL &&
NS_SUCCEEDED(item->GetParent(getter_AddRefs(parent))) &&
parent);
}
}
if ((appType == nsIDocShell::APP_TYPE_MAIL) ||
(aFirstURI && IsFromMailNews(aFirstURI)) ||
IsFromMailNews(aURI)) {
*aResult = ACCESS_DENY;
return NS_OK;
}
}
#endif // MOZ_PHOENIX
// finally, check with permission manager...
return mPermMgr->TestPermission(aURI, kPermissionType, (PRUint32 *) aResult);
}
NS_IMETHODIMP
nsCookiePermission::CanSetCookie(nsIURI *aURI,
nsIChannel *aChannel,
nsICookie *aCookie,
PRInt32 aNumCookiesFromHost,
PRBool aChangingCookie,
PRBool *aResult)
{
NS_ASSERTION(aURI, "null uri");
*aResult = kDefaultPolicy;
nsresult rv;
PRUint32 perm;
mPermMgr->TestPermission(aURI, kPermissionType, &perm);
if (perm == nsIPermissionManager::DENY_ACTION) {
*aResult = PR_FALSE;
} else if (perm == nsIPermissionManager::ALLOW_ACTION) {
*aResult = PR_TRUE;
} else if (mCookiesAskPermission) {
// check whether the user wants to be prompted. we only do this if the
// permissionlist lookup returned UNKNOWN_ACTION (i.e., no permissionlist
// entry exists for this host).
NS_ASSERTION(listPermission == nsIPermissionManager::UNKNOWN_ACTION,
"unknown permission");
NS_ASSERTION(perm == nsIPermissionManager::UNKNOWN_ACTION, "unknown permission");
// default to rejecting, in case the prompting process fails
*aPermission = PR_FALSE;
*aResult = PR_FALSE;
nsCAutoString hostPort;
aURI->GetHostPort(hostPort);
@@ -111,18 +265,34 @@ nsCookiePermission::TestPermission(nsIURI *aURI,
do_GetService(NS_COOKIEPROMPTSERVICE_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
// try to get a nsIDOMWindow from the channel...
nsCOMPtr<nsIDOMWindow> parent;
GetInterfaceFromChannel(aChannel, NS_GET_IID(nsIDOMWindow),
getter_AddRefs(parent));
PRBool rememberDecision = PR_FALSE;
rv = cookiePromptService->CookieDialog(nsnull, aCookie, hostPort,
aCookiesFromHost, aChangingCookie,
&rememberDecision, aPermission);
rv = cookiePromptService->CookieDialog(parent, aCookie, hostPort,
aNumCookiesFromHost, aChangingCookie,
&rememberDecision, aResult);
if (NS_FAILED(rv)) return rv;
if (rememberDecision) {
mPermMgr->Add(aURI, "cookie",
*aPermission ? (PRUint32) nsIPermissionManager::ALLOW_ACTION
: (PRUint32) nsIPermissionManager::DENY_ACTION);
mPermMgr->Add(aURI, kPermissionType,
*aResult ? (PRUint32) nsIPermissionManager::ALLOW_ACTION
: (PRUint32) nsIPermissionManager::DENY_ACTION);
}
}
return NS_OK;
}
NS_IMETHODIMP
nsCookiePermission::Observe(nsISupports *aSubject,
const char *aTopic,
const PRUnichar *aData)
{
nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(aSubject);
if (prefBranch)
PrefChanged(prefBranch, NS_LossyConvertUCS2toASCII(aData).get());
return NS_OK;
}

View File

@@ -19,6 +19,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Darin Fisher <darin@meer.net>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -39,19 +40,33 @@
#include "nsICookiePermission.h"
#include "nsIPermissionManager.h"
#include "nsIObserver.h"
#include "nsCOMPtr.h"
class nsIPrefBranch;
class nsCookiePermission : public nsICookiePermission
, public nsIObserver
{
public:
nsCookiePermission() {}
virtual ~nsCookiePermission() {}
NS_DECL_ISUPPORTS
NS_DECL_NSICOOKIEPERMISSION
NS_DECL_NSIOBSERVER
nsCookiePermission()
: mCookiesAskPermission(PR_FALSE)
, mCookiesDisabledForMailNews(PR_TRUE)
{}
virtual ~nsCookiePermission() {}
nsresult Init();
void PrefChanged(nsIPrefBranch *, const char *);
private:
nsCOMPtr<nsIPermissionManager> mPermMgr;
PRPackedBool mCookiesAskPermission;
PRPackedBool mCookiesDisabledForMailNews;
};
// {CE002B28-92B7-4701-8621-CC925866FB87}

View File

@@ -1,3 +1,4 @@
// vim:ts=2:sw=2:et:
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
@@ -39,18 +40,11 @@
#include "nsCookieService.h"
#include "nsIServiceManager.h"
#include "nsIGenericFactory.h"
#include "nsIScriptGlobalObject.h"
#include "nsIDocumentLoader.h"
#include "nsIWebProgress.h"
#include "nsIPermissionManager.h"
#include "nsIIOService.h"
#include "nsIPrefBranch.h"
#include "nsIPrefBranchInternal.h"
#include "nsIPrefService.h"
#include "nsIDocShell.h"
#include "nsIDocShellTreeItem.h"
#include "nsICookieConsent.h"
#include "nsICookiePermission.h"
#include "nsIURI.h"
@@ -73,7 +67,6 @@
#include "prnetdb.h"
#include "nsNetUtil.h"
#include "nsNetCID.h"
#include "nsCURILoader.h"
#include "nsAppDirectoryServiceDefs.h"
/******************************************************************************
@@ -81,12 +74,10 @@
* useful types & constants
******************************************************************************/
static NS_DEFINE_IID(kDocLoaderServiceCID, NS_DOCUMENTLOADER_SERVICE_CID);
static const char kCookieFileName[] = "cookies.txt";
static const PRUint32 kLazyWriteLoadingTimeout = 10000; //msec
static const PRUint32 kLazyWriteFinishedTimeout = 1000; //msec
static const PRUint32 kLazyWriteTimeout = 5000; //msec
static const PRUint32 kLazyNotifyTimeout = 1000; //msec
static const PRInt32 kMaxNumberOfCookies = 300;
static const PRInt32 kMaxCookiesPerHost = 20;
@@ -127,14 +118,12 @@ static const char kCookiesForDomainOnly[] = "network.cookie.enableForOriginating
static const char kCookiesLifetimeCurrentSession[] = "network.cookie.enableForCurrentSessionOnly";
#else
static const char kCookiesPermissions[] = "network.cookie.cookieBehavior";
static const char kCookiesDisabledForMailNews[] = "network.cookie.disableCookieForMailNews";
static const char kCookiesLifetimeEnabled[] = "network.cookie.lifetime.enabled";
static const char kCookiesLifetimeDays[] = "network.cookie.lifetime.days";
static const char kCookiesLifetimeCurrentSession[] = "network.cookie.lifetime.behavior";
static const char kCookiesP3PString[] = "network.cookie.p3p";
static const char kCookiesP3PString_Default[] = "drdraaaa";
#endif
static const char kCookiesAskPermission[] = "network.cookie.warnAboutCookies";
static const char kCookiesStrictDomains[] = "network.cookie.strictDomains";
// struct for temporarily storing cookie attributes during header parsing
@@ -300,18 +289,15 @@ nsCookieService::GetSingleton()
* public methods
******************************************************************************/
NS_IMPL_ISUPPORTS6(nsCookieService,
NS_IMPL_ISUPPORTS5(nsCookieService,
nsICookieService,
nsICookieManager,
nsICookieManager2,
nsIObserver,
nsIWebProgressListener,
nsISupportsWeakReference)
nsCookieService::nsCookieService()
: mLoadCount(0)
, mWritePending(PR_FALSE)
, mCookieChanged(PR_FALSE)
: mCookieChanged(PR_FALSE)
, mCookieIconVisible(PR_FALSE)
{
// AddRef now, so we don't cross XPCOM boundaries with a zero refcount
@@ -337,17 +323,6 @@ nsCookieService::nsCookieService()
mP3PService = do_GetService(NS_COOKIECONSENT_CONTRACTID);
mPermissionService = do_GetService(NS_COOKIEPERMISSION_CONTRACTID);
// Register as an observer for the document loader
nsCOMPtr<nsIDocumentLoader> docLoaderService = do_GetService(kDocLoaderServiceCID);
nsCOMPtr<nsIWebProgress> progress = do_QueryInterface(docLoaderService);
if (progress) {
progress->AddProgressListener(this,
nsIWebProgress::NOTIFY_STATE_DOCUMENT |
nsIWebProgress::NOTIFY_STATE_NETWORK);
} else {
NS_ERROR("Couldn't get nsIDocumentLoader");
}
}
nsCookieService::~nsCookieService()
@@ -356,6 +331,8 @@ nsCookieService::~nsCookieService()
if (mWriteTimer)
mWriteTimer->Cancel();
if (mNotifyTimer)
mNotifyTimer->Cancel();
// clean up memory
RemoveAllFromMemory();
@@ -372,8 +349,14 @@ nsCookieService::Observe(nsISupports *aSubject,
if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
// The profile is about to change,
// or is going away because the application is shutting down.
if (mWriteTimer)
if (mWriteTimer) {
mWriteTimer->Cancel();
mWriteTimer = 0;
}
if (mNotifyTimer) {
mNotifyTimer->Cancel();
mNotifyTimer = 0;
}
if (!nsCRT::strcmp(aData, NS_LITERAL_STRING("shutdown-cleanse").get())) {
RemoveAllFromMemory();
@@ -445,13 +428,6 @@ nsCookieService::Observe(nsISupports *aSubject,
}
mCookiesPermissions = tempPrefValue;
} else if (pref.Equals(kCookiesDisabledForMailNews)) {
rv = mPrefBranch->GetBoolPref(kCookiesDisabledForMailNews, &tempPrefValue);
if (NS_FAILED(rv)) {
tempPrefValue = PR_TRUE;
}
mCookiesDisabledForMailNews = tempPrefValue;
} else if (pref.Equals(kCookiesLifetimeEnabled)) {
rv = mPrefBranch->GetBoolPref(kCookiesLifetimeEnabled, &tempPrefValue);
if (NS_FAILED(rv)) {
@@ -486,13 +462,6 @@ nsCookieService::Observe(nsISupports *aSubject,
#endif
// common prefs between Phoenix & Mozilla
} else if (pref.Equals(kCookiesAskPermission)) {
rv = mPrefBranch->GetBoolPref(kCookiesAskPermission, &tempPrefValue);
if (NS_FAILED(rv)) {
tempPrefValue = PR_FALSE;
}
mCookiesAskPermission = tempPrefValue;
} else if (pref.Equals(kCookiesStrictDomains)) {
rv = mPrefBranch->GetBoolPref(kCookiesStrictDomains, &tempPrefValue);
if (NS_FAILED(rv)) {
@@ -736,33 +705,26 @@ nsCookieService::SetCookieStringFromHttp(nsIURI *aHostURI,
// switch to a nice string type now, and process each cookie in the header
nsDependentCString cookieHeader(aCookieHeader);
while (SetCookieInternal(aHostURI,
while (SetCookieInternal(aHostURI, aChannel,
cookieHeader, serverTime,
cookieStatus, cookiePolicy));
// write out the cookie file
LazyWrite(PR_TRUE);
LazyWrite();
LazyNotify();
return NS_OK;
}
void
nsCookieService::LazyWrite(PRBool aForce)
nsCookieService::LazyWrite()
{
// !aForce resets the timer at load end, but only if a write is pending
if (!aForce && !mWritePending)
return;
PRUint32 timeout = mLoadCount > 0 ? kLazyWriteLoadingTimeout :
kLazyWriteFinishedTimeout;
if (mWriteTimer) {
mWriteTimer->SetDelay(timeout);
mWritePending = PR_TRUE;
mWriteTimer->SetDelay(kLazyWriteTimeout);
} else {
mWriteTimer = do_CreateInstance("@mozilla.org/timer;1");
if (mWriteTimer) {
mWriteTimer->InitWithFuncCallback(DoLazyWrite, this, timeout,
mWriteTimer->InitWithFuncCallback(DoLazyWrite, this, kLazyWriteTimeout,
nsITimer::TYPE_ONE_SHOT);
mWritePending = PR_TRUE;
}
}
}
@@ -772,34 +734,35 @@ nsCookieService::DoLazyWrite(nsITimer *aTimer,
void *aClosure)
{
nsCookieService *service = NS_REINTERPRET_CAST(nsCookieService*, aClosure);
service->mWritePending = PR_FALSE;
service->Write();
service->mWriteTimer = 0;
}
NS_IMETHODIMP
nsCookieService::OnStateChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest,
PRUint32 aProgressStateFlags,
nsresult aStatus)
void
nsCookieService::LazyNotify()
{
if (aProgressStateFlags & STATE_IS_NETWORK) {
if (aProgressStateFlags & STATE_START)
++mLoadCount;
if (aProgressStateFlags & STATE_STOP) {
if (mLoadCount > 0) // needed because at startup we may miss initial STATE_START
--mLoadCount;
if (mLoadCount == 0)
LazyWrite(PR_FALSE);
// this algorithm is slightly different than the one used to write cookies.
// here we are concerned with update frequency of the UI (yes, yes, this
// code really shouldn't have to worry about the UI!)... so, we do not
// further delay an already delayed notification.
if (!mNotifyTimer) {
mNotifyTimer = do_CreateInstance("@mozilla.org/timer;1");
if (mNotifyTimer) {
mNotifyTimer->InitWithFuncCallback(DoLazyNotify, this, kLazyNotifyTimeout,
nsITimer::TYPE_ONE_SHOT);
}
}
}
if (mObserverService &&
(aProgressStateFlags & STATE_IS_DOCUMENT) &&
(aProgressStateFlags & STATE_STOP)) {
mObserverService->NotifyObservers(nsnull, "cookieChanged", NS_LITERAL_STRING("cookies").get());
}
return NS_OK;
void
nsCookieService::DoLazyNotify(nsITimer *aTimer,
void *aClosure)
{
nsCookieService *service = NS_REINTERPRET_CAST(nsCookieService*, aClosure);
if (service->mObserverService)
service->mObserverService->NotifyObservers(nsnull, "cookieChanged", NS_LITERAL_STRING("cookies").get());
service->mNotifyTimer = 0;
}
void
@@ -818,47 +781,6 @@ nsCookieService::GetCookieIconIsVisible(PRBool *aIsVisible)
return NS_OK;
}
// nsIWebProgressListener implementation
NS_IMETHODIMP
nsCookieService::OnProgressChange(nsIWebProgress *aProgress,
nsIRequest *aRequest,
PRInt32 aCurSelfProgress,
PRInt32 aMaxSelfProgress,
PRInt32 aCurTotalProgress,
PRInt32 aMaxTotalProgress)
{
NS_NOTREACHED("notification excluded in AddProgressListener(...)");
return NS_OK;
}
NS_IMETHODIMP
nsCookieService::OnLocationChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest,
nsIURI *aLocation)
{
NS_NOTREACHED("notification excluded in AddProgressListener(...)");
return NS_OK;
}
NS_IMETHODIMP
nsCookieService::OnStatusChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest,
nsresult aStatus,
const PRUnichar *aMessage)
{
NS_NOTREACHED("notification excluded in AddProgressListener(...)");
return NS_OK;
}
NS_IMETHODIMP
nsCookieService::OnSecurityChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest,
PRUint32 aState)
{
NS_NOTREACHED("notification excluded in AddProgressListener(...)");
return NS_OK;
}
/******************************************************************************
* nsCookieService:
* pref observer impl
@@ -882,13 +804,11 @@ nsCookieService::InitPrefObservers()
prefInternal->AddObserver(kCookiesLifetimeCurrentSession, this, PR_TRUE);
#else
prefInternal->AddObserver(kCookiesPermissions, this, PR_TRUE);
prefInternal->AddObserver(kCookiesDisabledForMailNews, this, PR_TRUE);
prefInternal->AddObserver(kCookiesLifetimeEnabled, this, PR_TRUE);
prefInternal->AddObserver(kCookiesLifetimeDays, this, PR_TRUE);
prefInternal->AddObserver(kCookiesLifetimeCurrentSession, this, PR_TRUE);
prefInternal->AddObserver(kCookiesP3PString, this, PR_TRUE);
#endif
prefInternal->AddObserver(kCookiesAskPermission, this, PR_TRUE);
prefInternal->AddObserver(kCookiesStrictDomains, this, PR_TRUE);
}
@@ -900,15 +820,11 @@ nsCookieService::InitPrefObservers()
} else {
// only called if getting the prefbranch failed.
#ifdef MOZ_PHOENIX
mCookiesDisabledForMailNews = PR_FALSE; // for efficiency
#else
mCookiesDisabledForMailNews = PR_TRUE;
#ifndef MOZ_PHOENIX
mCookiesP3PString = NS_LITERAL_CSTRING(kCookiesP3PString_Default);
#endif
mCookiesPermissions = BEHAVIOR_REJECT;
mCookiesLifetimeEnabled = PR_FALSE;
mCookiesAskPermission = PR_FALSE;
mCookiesStrictDomains = PR_FALSE;
}
}
@@ -955,7 +871,6 @@ nsCookieService::ReadPrefs()
mCookiesLifetimeCurrentSession = tempPrefValue;
// Phoenix hacks to reduce ifdefs in code
mCookiesLifetimeEnabled = mCookiesLifetimeCurrentSession;
mCookiesDisabledForMailNews = PR_FALSE;
mCookiesLifetimeSec = 0;
#else
@@ -966,13 +881,6 @@ nsCookieService::ReadPrefs()
}
mCookiesPermissions = tempPrefValue;
rv = mPrefBranch->GetBoolPref(kCookiesDisabledForMailNews, &tempPrefValue);
if (NS_FAILED(rv)) {
tempPrefValue = PR_TRUE;
rv2 = rv;
}
mCookiesDisabledForMailNews = tempPrefValue;
rv = mPrefBranch->GetBoolPref(kCookiesLifetimeEnabled, &tempPrefValue);
if (NS_FAILED(rv)) {
tempPrefValue = PR_FALSE;
@@ -1007,12 +915,6 @@ nsCookieService::ReadPrefs()
#endif
// common prefs between Phoenix & Mozilla
rv = mPrefBranch->GetBoolPref(kCookiesAskPermission, &tempPrefValue);
if (NS_FAILED(rv)) {
tempPrefValue = PR_FALSE;
rv2 = rv;
}
mCookiesAskPermission = tempPrefValue;
rv = mPrefBranch->GetBoolPref(kCookiesStrictDomains, &tempPrefValue);
if (NS_FAILED(rv)) {
@@ -1161,24 +1063,21 @@ nsCookieService::Remove(const nsACString &aHost,
cookieInList->Name().Equals(aName)) {
// check if we need to add the host to the permissions blacklist.
// we should push this portion into the UI, it shouldn't live here in the backend.
if (aBlocked) {
nsresult rv;
nsCOMPtr<nsIPermissionManager> permissionManager = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
if (aBlocked && mPermissionService) {
nsCAutoString buf;
NS_NAMED_LITERAL_CSTRING(httpPrefix, "http://");
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIURI> uri;
static NS_NAMED_LITERAL_CSTRING(httpPrefix, "http://");
// remove leading dot from host
if (cookieInList->IsDomain())
buf = httpPrefix + Substring(cookieInList->Host(), 1, cookieInList->Host().Length() - 1);
else
buf = httpPrefix + cookieInList->Host();
// remove leading dot from host
if (cookieInList->IsDomain()) {
rv = NS_NewURI(getter_AddRefs(uri), PromiseFlatCString(httpPrefix + Substring(cookieInList->Host(), 1, cookieInList->Host().Length() - 1)));
} else {
rv = NS_NewURI(getter_AddRefs(uri), PromiseFlatCString(httpPrefix + cookieInList->Host()));
}
nsCOMPtr<nsIURI> uri;
NS_NewURI(getter_AddRefs(uri), buf);
if (NS_SUCCEEDED(rv))
permissionManager->Add(uri, "cookie", nsIPermissionManager::DENY_ACTION);
}
if (uri)
mPermissionService->SetAccess(uri, nsICookiePermission::ACCESS_DENY);
}
mCookieList.RemoveElementAt(i);
@@ -1456,6 +1355,7 @@ nsCookieService::Write()
// to be processed
PRBool
nsCookieService::SetCookieInternal(nsIURI *aHostURI,
nsIChannel *aChannel,
nsDependentCString &aCookieHeader,
nsInt64 aServerTime,
nsCookieStatus aStatus,
@@ -1535,12 +1435,11 @@ nsCookieService::SetCookieInternal(nsIURI *aHostURI,
PRBool permission;
// we need to think about prompters/parent windows here - TestPermission
// needs one to prompt, so right now it has to fend for itself to get one
mPermissionService->TestPermission(aHostURI,
NS_STATIC_CAST(nsICookie*, NS_STATIC_CAST(nsCookie*, cookie)),
nsnull,
countFromHost, foundCookie,
mCookiesAskPermission,
&permission);
mPermissionService->CanSetCookie(aHostURI,
aChannel,
NS_STATIC_CAST(nsICookie*, NS_STATIC_CAST(nsCookie*, cookie)),
countFromHost, foundCookie,
&permission);
if (!permission) {
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, cookieHeader, "cookie rejected by permission manager");
return newCookie;
@@ -1879,16 +1778,6 @@ nsCookieService::IsIPAddress(const nsAFlatCString &aHost)
return (PR_StringToNetAddr(aHost.get(), &addr) == PR_SUCCESS);
}
// returns PR_TRUE if URI scheme is from mailnews
PRBool
nsCookieService::IsFromMailNews(const nsAFlatCString &aScheme)
{
return (aScheme.Equals(NS_LITERAL_CSTRING("imap")) ||
aScheme.Equals(NS_LITERAL_CSTRING("news")) ||
aScheme.Equals(NS_LITERAL_CSTRING("snews")) ||
aScheme.Equals(NS_LITERAL_CSTRING("mailbox")));
}
PRBool
nsCookieService::IsInDomain(const nsACString &aDomain,
const nsACString &aHost,
@@ -2116,68 +2005,19 @@ nsCookieService::CheckPrefs(nsIURI *aHostURI,
return nsICookie::STATUS_REJECTED;
}
// disable cookies in mailnews if user's prefs say so
if (mCookiesDisabledForMailNews) {
//
// try to examine the "app type" of the docshell owning this request. if
// we find a docshell in the heirarchy of type APP_TYPE_MAIL, then assume
// this URI is being loaded from within mailnews.
//
// XXX this is a pretty ugly hack at the moment since cookies really
// shouldn't have to talk to the docshell directly. ultimately, we want
// to talk to some more generic interface, which the docshell would also
// implement. but, the basic mechanism here of leveraging the channel's
// (or loadgroup's) notification callbacks attribute seems ideal as it
// avoids the problem of having to modify all places in the code which
// kick off network requests.
//
PRUint32 appType = nsIDocShell::APP_TYPE_UNKNOWN;
if (aChannel) {
nsCOMPtr<nsIInterfaceRequestor> req;
aChannel->GetNotificationCallbacks(getter_AddRefs(req));
if (!req) {
// check the load group's notification callbacks...
nsCOMPtr<nsILoadGroup> group;
aChannel->GetLoadGroup(getter_AddRefs(group));
if (group)
group->GetNotificationCallbacks(getter_AddRefs(req));
}
if (req) {
nsCOMPtr<nsIDocShellTreeItem> item, parent = do_GetInterface(req);
if (parent) {
do {
item = parent;
nsCOMPtr<nsIDocShell> docshell = do_QueryInterface(item);
if (docshell)
docshell->GetAppType(&appType);
} while (appType != nsIDocShell::APP_TYPE_MAIL &&
NS_SUCCEEDED(item->GetParent(getter_AddRefs(parent))) &&
parent);
}
}
}
if ((appType == nsIDocShell::APP_TYPE_MAIL) ||
(aFirstURI && IsFromMailNews(firstURIScheme)) ||
IsFromMailNews(currentURIScheme)) {
COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "cookies disabled for mailnews");
return nsICookie::STATUS_REJECTED;
}
}
// check the permission list first; if we find an entry, it overrides
// default prefs. see bug 184059.
nsCOMPtr<nsIPermissionManager> permissionManager = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv)) {
PRUint32 listPermission;
permissionManager->TestPermission(aHostURI, "cookie", &listPermission);
if (mPermissionService) {
nsCookieAccess access;
mPermissionService->CanAccess(aHostURI, aFirstURI, aChannel, &access);
// if we found an entry, use it
switch (listPermission) {
case nsIPermissionManager::DENY_ACTION:
switch (access) {
case nsICookiePermission::ACCESS_DENY:
COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "cookies are blocked for this site");
return nsICookie::STATUS_REJECTED;
case nsIPermissionManager::ALLOW_ACTION:
case nsICookiePermission::ACCESS_ALLOW:
return nsICookie::STATUS_ACCEPTED;
}
}

View File

@@ -44,7 +44,6 @@
#include "nsICookieManager.h"
#include "nsICookieManager2.h"
#include "nsIObserver.h"
#include "nsIWebProgressListener.h"
#include "nsWeakReference.h"
#include "nsCookie.h"
@@ -71,14 +70,12 @@ class nsInt64;
class nsCookieService : public nsICookieService
, public nsICookieManager2
, public nsIObserver
, public nsIWebProgressListener
, public nsSupportsWeakReference
{
public:
// nsISupports
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
NS_DECL_NSIWEBPROGRESSLISTENER
NS_DECL_NSICOOKIESERVICE
NS_DECL_NSICOOKIEMANAGER
NS_DECL_NSICOOKIEMANAGER2
@@ -92,7 +89,7 @@ class nsCookieService : public nsICookieService
nsresult ReadPrefs();
nsresult Read();
nsresult Write();
PRBool SetCookieInternal(nsIURI *aHostURI, nsDependentCString &aCookieHeader, nsInt64 aServerTime, nsCookieStatus aStatus, nsCookiePolicy aPolicy);
PRBool SetCookieInternal(nsIURI *aHostURI, nsIChannel *aChannel, nsDependentCString &aCookieHeader, nsInt64 aServerTime, nsCookieStatus aStatus, nsCookiePolicy aPolicy);
nsresult AddInternal(nsCookie *aCookie, nsInt64 aCurrentTime, nsIURI *aHostURI, const char *aCookieHeader);
static PRBool GetTokenValue(nsASingleFragmentCString::const_char_iterator &aIter, nsASingleFragmentCString::const_char_iterator &aEndIter, nsDependentSingleFragmentCSubstring &aTokenString, nsDependentSingleFragmentCSubstring &aTokenValue, PRBool &aEqualsFound);
static PRBool ParseAttributes(nsDependentCString &aCookieHeader, nsCookieAttributes &aCookie);
@@ -115,9 +112,14 @@ class nsCookieService : public nsICookieService
// Use LazyWrite to save the cookies file on a timer. It will write
// the file only once if repeatedly hammered quickly.
void LazyWrite(PRBool aForce);
void LazyWrite();
static void DoLazyWrite(nsITimer *aTimer, void *aClosure);
// Use LazyNotify to broadcast the "cookieChanged" notification at
// a reasonable frequency.
void LazyNotify();
static void DoLazyNotify(nsITimer *aTimer, void *aClosure);
protected:
// cached members
nsCOMPtr<nsIPrefBranch> mPrefBranch;
@@ -128,9 +130,8 @@ class nsCookieService : public nsICookieService
// impl members
nsCOMPtr<nsITimer> mWriteTimer;
nsCOMPtr<nsITimer> mNotifyTimer;
nsVoidArray mCookieList;
PRUint32 mLoadCount;
PRPackedBool mWritePending;
PRPackedBool mCookieChanged;
PRPackedBool mCookieIconVisible;
@@ -142,10 +143,8 @@ class nsCookieService : public nsICookieService
PRPackedBool mCookiesEnabled_temp, // These two prefs are collapsed
mCookiesForDomainOnly_temp; // into mCookiesPermissions.
#endif
PRPackedBool mCookiesAskPermission, // Ask user permission before storing cookie
mCookiesLifetimeEnabled, // Cookie lifetime limit enabled
PRPackedBool mCookiesLifetimeEnabled, // Cookie lifetime limit enabled
mCookiesLifetimeCurrentSession, // Limit cookie lifetime to current session
mCookiesDisabledForMailNews, // Disable cookies in mailnews
mCookiesStrictDomains; // Optional pref to apply stricter domain checks
PRUint8 mCookiesPermissions; // BEHAVIOR_{ACCEPT, REJECTFOREIGN, REJECT, P3P}
PRInt32 mCookiesLifetimeSec; // Lifetime limit specified in seconds

View File

@@ -36,36 +36,91 @@
#include "nsISupports.idl"
interface nsICookie;
interface nsIURI;
interface nsIChannel;
typedef long nsCookieAccess;
/**
* An interface to test for cookie permissions
*/
interface nsICookie;
interface nsIURI;
interface nsIDOMWindow;
[scriptable, uuid(EF565D0A-AB9A-4A13-9160-0644CDFD859A)]
[scriptable, uuid(91f1c3ec-73a0-4bf0-bdc5-348a1f181b0e)]
interface nsICookiePermission : nsISupports
{
/**
* Test if a cookie from the given host should be accepted or denied,
* only by prompting the user (does not perform a permissionlist lookup)
* @param uri the website to be tested
* @param cookie the cookie that wants to be set
* @param parent the parant window
* @param cookiesFromHost number of cookies this host already has set
* @param changingCookie are we changing this cookie?
* @param showDialog show a prompt to the user?
* @return whether the cookie has permission to be loaded
* nsCookieAccess values
*/
boolean testPermission(in nsIURI uri,
in nsICookie cookie,
in nsIDOMWindow parent,
in long cookiesFromHost,
in boolean changingCookie,
in boolean showDialog);
const nsCookieAccess ACCESS_DEFAULT = 0;
const nsCookieAccess ACCESS_ALLOW = 1;
const nsCookieAccess ACCESS_DENY = 2;
/**
* setAccess
*
* this method is called to block cookie access for the given URI. this
* may result in other URIs being blocked as well (e.g., URIs which share
* the same host name).
*
* @param aURI
* the URI to block
* @param aAccess
* the new cookie access for the URI
*/
void setAccess(in nsIURI aURI,
in nsCookieAccess aAccess);
/**
* canAccess
*
* this method is called to test whether or not the given URI/channel may
* access the cookie database, either to set or get cookies.
*
* @param aURI
* the URI trying to access cookies
* @param aFirstURI
* the URI initiated by the user that resulted in aURI being loaded
* @param aChannel
* the channel corresponding to aURI
*
* @return nsCookieAccess value
*/
nsCookieAccess canAccess(in nsIURI aURI,
in nsIURI aFirstURI,
in nsIChannel aChannel);
/**
* canSetCookie
*
* this method is called to test whether or not the given URI/channel may
* set a specific cookie. this method is always preceded by a call to
* canAccessCookies.
*
* @param aURI
* the URI trying to set the cookie
* @param aChannel
* the corresponding to aURI
* @param aCookie
* the cookie being added to the cookie database
* @param aNumCookiesFromHost
* the number of cookies this host already has set
* @param aChangingCookie
* PR_TRUE if the cookie is being modified; otherwise, the cookie
* is new
*
* @return true if the cookie can be set.
*/
boolean canSetCookie(in nsIURI aURI,
in nsIChannel aChannel,
in nsICookie aCookie,
in long aNumCookiesFromHost,
in boolean aChangingCookie);
};
%{ C++
/**
* The nsICookiePermission implementation is an XPCOM service registered
* under the ContractID:
*/
#define NS_COOKIEPERMISSION_CONTRACTID "@mozilla.org/cookie/permission;1"
%}

View File

@@ -55,7 +55,7 @@ NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsCookieService, nsCookieService::GetSi
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsImgManager, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPermissionManager, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPopupWindowManager, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsCookiePermission)
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsCookiePermission, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsCookiePromptService)
static NS_METHOD