Bug 458091: Don't store an mURI in nsDOMStorage. r=bz

This commit is contained in:
Dave Camp 2009-01-12 21:52:00 -08:00
Родитель 7b0cf8b9ac
Коммит f3c17be4a6
11 изменённых файлов: 398 добавлений и 182 удалений

Просмотреть файл

@ -437,6 +437,7 @@ NS_INTERFACE_MAP_BEGIN(nsDocShell)
NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)
NS_INTERFACE_MAP_ENTRY(nsIObserver)
NS_INTERFACE_MAP_ENTRY(nsILoadContext)
NS_INTERFACE_MAP_ENTRY(nsIDocShell_MOZILLA_1_9_1)
NS_INTERFACE_MAP_END_INHERITING(nsDocLoader)
///*****************************************************************************
@ -1684,14 +1685,68 @@ nsDocShell::HistoryPurged(PRInt32 aNumEntries)
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::GetSessionStorageForPrincipal(nsIPrincipal* aPrincipal,
PRBool aCreate,
nsIDOMStorage** aStorage)
{
NS_ENSURE_ARG_POINTER(aStorage);
*aStorage = nsnull;
if (!aPrincipal)
return NS_OK;
nsCOMPtr<nsIURI> codebaseURI;
nsresult rv = aPrincipal->GetDomain(getter_AddRefs(codebaseURI));
NS_ENSURE_SUCCESS(rv, rv);
if (!codebaseURI) {
rv = aPrincipal->GetURI(getter_AddRefs(codebaseURI));
NS_ENSURE_SUCCESS(rv, rv);
}
if (!codebaseURI)
return NS_OK;
rv = GetSessionStorageForURI(codebaseURI, aCreate, aStorage);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsPIDOMStorage> piStorage = do_QueryInterface(*aStorage);
if (piStorage) {
PRBool canAccess = piStorage->CanAccess(aPrincipal);
NS_ASSERTION(canAccess,
"GetSessionStorageForPrincipal got a storage "
"that could not be accessed!");
if (!canAccess) {
NS_RELEASE(*aStorage);
return NS_ERROR_DOM_SECURITY_ERR;
}
}
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::GetSessionStorageForURI(nsIURI* aURI,
nsIDOMStorage** aStorage)
{
return GetSessionStorageForURI(aURI, PR_TRUE, aStorage);
}
nsresult
nsDocShell::GetSessionStorageForURI(nsIURI* aURI,
PRBool aCreate,
nsIDOMStorage** aStorage)
{
NS_ENSURE_ARG(aURI);
NS_ENSURE_ARG_POINTER(aStorage);
*aStorage = nsnull;
nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(aURI);
NS_ASSERTION(innerURI, "Failed to get innermost URI");
if (!innerURI)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIDocShellTreeItem> topItem;
nsresult rv = GetSameTypeRootTreeItem(getter_AddRefs(topItem));
if (NS_FAILED(rv))
@ -1700,18 +1755,18 @@ nsDocShell::GetSessionStorageForURI(nsIURI* aURI,
if (!topItem)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIDocShell> topDocShell = do_QueryInterface(topItem);
nsDocShell* topDocShell = static_cast<nsDocShell*>(topItem.get());
if (topDocShell != this)
return topDocShell->GetSessionStorageForURI(aURI, aStorage);
return topDocShell->GetSessionStorageForURI(aURI, aCreate, aStorage);
nsCAutoString currentDomain;
rv = aURI->GetAsciiHost(currentDomain);
rv = innerURI->GetAsciiHost(currentDomain);
NS_ENSURE_SUCCESS(rv, rv);
if (currentDomain.IsEmpty())
return NS_OK;
if (!mStorages.Get(currentDomain, aStorage)) {
if (!mStorages.Get(currentDomain, aStorage) && aCreate) {
nsCOMPtr<nsIDOMStorage> newstorage =
do_CreateInstance("@mozilla.org/dom/storage;1");
if (!newstorage)
@ -1720,13 +1775,12 @@ nsDocShell::GetSessionStorageForURI(nsIURI* aURI,
nsCOMPtr<nsPIDOMStorage> pistorage = do_QueryInterface(newstorage);
if (!pistorage)
return NS_ERROR_FAILURE;
pistorage->Init(aURI, NS_ConvertUTF8toUTF16(currentDomain), PR_FALSE);
pistorage->Init(NS_ConvertUTF8toUTF16(currentDomain), PR_FALSE);
if (!mStorages.Put(currentDomain, newstorage))
return NS_ERROR_OUT_OF_MEMORY;
*aStorage = newstorage;
NS_ADDREF(*aStorage);
newstorage.swap(*aStorage);
}
return NS_OK;
@ -1749,6 +1803,10 @@ nsDocShell::AddSessionStorage(const nsACString& aDomain,
if (topItem) {
nsCOMPtr<nsIDocShell> topDocShell = do_QueryInterface(topItem);
if (topDocShell == this) {
// Do not replace an existing session storage.
if (mStorages.GetWeak(aDomain))
return NS_ERROR_NOT_AVAILABLE;
if (!mStorages.Put(aDomain, aStorage))
return NS_ERROR_OUT_OF_MEMORY;
}
@ -6879,42 +6937,8 @@ nsDocShell::InternalLoad(nsIURI * aURI,
nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(newWin);
targetDocShell = do_QueryInterface(webNav);
nsCOMPtr<nsIScriptObjectPrincipal> sop =
do_QueryInterface(mScriptGlobal);
nsCOMPtr<nsIURI> currentCodebase;
if (sop) {
nsIPrincipal *principal = sop->GetPrincipal();
if (principal) {
principal->GetURI(getter_AddRefs(currentCodebase));
}
}
// We opened a new window for the target, clone the
// session storage if the current URI's domain matches
// that of the loading URI.
if (targetDocShell && currentCodebase && aURI) {
nsCAutoString thisDomain, newDomain;
nsresult gethostrv = currentCodebase->GetAsciiHost(thisDomain);
gethostrv |= aURI->GetAsciiHost(newDomain);
if (NS_SUCCEEDED(gethostrv) && thisDomain.Equals(newDomain)) {
nsCOMPtr<nsIDOMStorage> storage;
GetSessionStorageForURI(currentCodebase,
getter_AddRefs(storage));
nsCOMPtr<nsPIDOMStorage> piStorage =
do_QueryInterface(storage);
if (piStorage) {
nsCOMPtr<nsIDOMStorage> newstorage =
piStorage->Clone(currentCodebase);
targetDocShell->AddSessionStorage(thisDomain,
newstorage);
}
}
}
}
//
// Transfer the load to the target DocShell... Pass nsnull as the
// window target name from to prevent recursive retargeting!

Просмотреть файл

@ -187,7 +187,8 @@ class nsDocShell : public nsDocLoader,
public nsIWebPageDescriptor,
public nsIAuthPromptProvider,
public nsIObserver,
public nsILoadContext
public nsILoadContext,
public nsIDocShell_MOZILLA_1_9_1
{
friend class nsDSURIContentListener;
@ -217,6 +218,7 @@ public:
NS_DECL_NSIAUTHPROMPTPROVIDER
NS_DECL_NSIOBSERVER
NS_DECL_NSILOADCONTEXT
NS_DECL_NSIDOCSHELL_MOZILLA_1_9_1
NS_IMETHOD Stop() {
// Need this here because otherwise nsIWebNavigation::Stop
@ -549,6 +551,9 @@ protected:
void ReattachEditorToWindow(nsISHEntry *aSHEntry);
void DetachEditorFromWindow(nsISHEntry *aSHEntry);
nsresult GetSessionStorageForURI(nsIURI* aURI,
PRBool create,
nsIDOMStorage** aStorage);
protected:
// Override the parent setter from nsDocLoader
virtual nsresult SetDocLoaderParent(nsDocLoader * aLoader);

Просмотреть файл

@ -67,6 +67,7 @@ interface nsISHEntry;
interface nsILayoutHistoryState;
interface nsISecureBrowserUI;
interface nsIDOMStorage;
interface nsIPrincipal;
[scriptable, uuid(dc4daea1-b43d-406f-bd62-c2ee879192ad)]
interface nsIDocShell : nsISupports
@ -423,7 +424,7 @@ interface nsIDocShell : nsISupports
* Retrieves the WebApps session storage object for the supplied domain.
* If it doesn't already exist, a new one will be created.
*
* @param domain the domain of the storage object to retrieve
* @param uri the uri of the storage object to retrieve
*/
nsIDOMStorage getSessionStorageForURI(in nsIURI uri);
@ -475,3 +476,16 @@ interface nsIDocShell : nsISupports
attribute boolean isOffScreenBrowser;
};
[scriptable, uuid(460ba822-e664-4c38-9b08-98d2736473d7)]
interface nsIDocShell_MOZILLA_1_9_1 : nsISupports
{
/*
* Retrieves the WebApps session storage object for the supplied principal.
*
* @param principal returns a storage for this principal
* @param create If true and a session storage object doesn't
* already exist, a new one will be created.
*/
nsIDOMStorage getSessionStorageForPrincipal(in nsIPrincipal principal,
in boolean create);
};

Просмотреть файл

@ -45,21 +45,25 @@
class nsIDOMStorage;
class nsIURI;
class nsIPrincipal;
#define NS_PIDOMSTORAGE_IID \
{ 0x2fdbb82e, 0x4b47, 0x406a, \
{ 0xb1, 0x17, 0x6d, 0x67, 0x58, 0xc1, 0xee, 0x6b } }
{ 0x2cbaea60, 0x69e7, 0x4b49, \
{ 0xa2, 0xe2, 0x99, 0x53, 0xf4, 0x11, 0xd0, 0x8f } }
class nsPIDOMStorage : public nsISupports
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_PIDOMSTORAGE_IID)
virtual void Init(nsIURI* aURI, const nsAString &aDomain, PRBool aUseDB) = 0;
virtual void Init(const nsAString &aDomain, PRBool aUseDB) = 0;
virtual already_AddRefed<nsIDOMStorage> Clone(nsIURI* aURI) = 0;
virtual already_AddRefed<nsIDOMStorage> Clone() = 0;
virtual nsTArray<nsString> *GetKeys() = 0;
virtual const nsString &Domain() = 0;
virtual PRBool CanAccess(nsIPrincipal *aPrincipal) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsPIDOMStorage, NS_PIDOMSTORAGE_IID)

Просмотреть файл

@ -6693,20 +6693,23 @@ nsGlobalWindow::GetSessionStorage(nsIDOMStorage ** aSessionStorage)
*aSessionStorage = nsnull;
nsIPrincipal *principal = GetPrincipal();
nsIDocShell *docShell = GetDocShell();
nsCOMPtr<nsIDocShell_MOZILLA_1_9_1> docShell =
do_QueryInterface(GetDocShell());
if (!principal || !docShell) {
return NS_OK;
}
nsCOMPtr<nsIURI> codebase;
nsresult rv = principal->GetURI(getter_AddRefs(codebase));
nsresult rv = docShell->GetSessionStorageForPrincipal(principal,
PR_TRUE,
aSessionStorage);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_FAILED(rv) || !codebase) {
return NS_FAILED(rv) ? rv : NS_ERROR_DOM_NOT_SUPPORTED_ERR;
if (!*aSessionStorage) {
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}
return docShell->GetSessionStorageForURI(codebase, aSessionStorage);
return NS_OK;
}
NS_IMETHODIMP
@ -6863,16 +6866,23 @@ nsGlobalWindow::Observe(nsISupports* aSubject, const char* aTopic,
nsIPrincipal *principal;
nsresult rv;
principal = GetPrincipal();
if (!aData) {
nsCOMPtr<nsIDOMStorage> storage;
GetSessionStorage(getter_AddRefs(storage));
nsCOMPtr<nsIDocShell_MOZILLA_1_9_1> docShell =
do_QueryInterface(GetDocShell());
if (principal && docShell) {
nsCOMPtr<nsIDOMStorage> storage;
docShell->GetSessionStorageForPrincipal(principal,
PR_FALSE,
getter_AddRefs(storage));
if (storage != aSubject && !aData) {
// A sessionStorage object changed, but not our session storage
// object.
return NS_OK;
if (storage != aSubject) {
// A sessionStorage object changed, but not our session storage
// object.
return NS_OK;
}
}
} else if ((principal = GetPrincipal())) {
} else if (principal) {
// A global storage object changed, check to see if it's one
// this window can access.
@ -7088,12 +7098,6 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
const PRBool checkForPopup =
!aDialog && !WindowExists(aName, !aCalledNoScript);
nsCOMPtr<nsIURI> currentCodebase;
if (aCalleePrincipal) {
aCalleePrincipal->GetURI(getter_AddRefs(currentCodebase));
}
// Note: it's very important that this be an nsXPIDLCString, since we want
// .get() on it to return nsnull until we write stuff to it. The window
// watcher expects a null URL string if there is no URL to load.
@ -7239,38 +7243,6 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
FireAbuseEvents(PR_FALSE, PR_TRUE, aUrl, aName, aOptions);
}
// copy the session storage data over to the new window if
// necessary. If the new window has the same domain as this window
// did at the beginning of this function, the session storage data
// for that domain, and only that domain, is copied over.
nsGlobalWindow *opened = static_cast<nsGlobalWindow *>(*aReturn);
nsIDocShell* newDocShell = opened->GetDocShell();
if (currentCodebase && newDocShell && mDocShell && url.get()) {
nsCOMPtr<nsIURI> newURI;
JSContext *cx;
PRBool freePass;
BuildURIfromBase(url, getter_AddRefs(newURI), &freePass, &cx);
if (newURI) {
nsCAutoString thisDomain, newDomain;
nsresult gethostrv = currentCodebase->GetAsciiHost(thisDomain);
gethostrv |= newURI->GetAsciiHost(newDomain);
if (NS_SUCCEEDED(gethostrv) && thisDomain.Equals(newDomain)) {
nsCOMPtr<nsIDOMStorage> storage;
mDocShell->GetSessionStorageForURI(currentCodebase,
getter_AddRefs(storage));
nsCOMPtr<nsPIDOMStorage> piStorage = do_QueryInterface(storage);
if (piStorage) {
nsCOMPtr<nsIDOMStorage> newstorage = piStorage->Clone(newURI);
newDocShell->AddSessionStorage(thisDomain, newstorage);
}
}
}
}
return rv;
}

Просмотреть файл

@ -78,6 +78,40 @@ static const char kCookiesLifetimePolicy[] = "network.cookie.lifetimePolicy";
static const char kOfflineAppWarnQuota[] = "offline-apps.quota.warn";
static const char kOfflineAppQuota[] = "offline-apps.quota.max";
// The URI returned is the innermost URI that should be used for
// security-check-like stuff. aHost is its hostname, correctly canonicalized.
static nsresult
GetPrincipalURIAndHost(nsIPrincipal* aPrincipal, nsIURI** aURI, nsString& aHost)
{
nsresult rv = aPrincipal->GetDomain(aURI);
NS_ENSURE_SUCCESS(rv, rv);
if (!*aURI) {
rv = aPrincipal->GetURI(aURI);
NS_ENSURE_SUCCESS(rv, rv);
}
if (!*aURI) {
return NS_OK;
}
nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(*aURI);
if (!innerURI) {
return NS_ERROR_UNEXPECTED;
}
nsCAutoString asciiHost;
rv = innerURI->GetAsciiHost(asciiHost);
if (NS_FAILED(rv)) {
return NS_ERROR_DOM_SECURITY_ERR;
}
CopyUTF8toUTF16(asciiHost, aHost);
innerURI.swap(*aURI);
return NS_OK;
}
//
// Helper that tells us whether the caller is secure or not.
//
@ -375,11 +409,8 @@ SessionStorageTraverser(nsSessionStorageEntry* aEntry, void* userArg) {
}
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMStorage)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMStorage)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mURI)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsDOMStorage)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMStorage)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mURI)
{
if (tmp->mItems.IsInitialized()) {
tmp->mItems.EnumerateEntries(SessionStorageTraverser, &cb);
@ -417,11 +448,10 @@ nsDOMStorage::nsDOMStorage()
nsDOMStorageManager::gStorageManager->AddToStoragesHash(this);
}
nsDOMStorage::nsDOMStorage(nsIURI* aURI, const nsAString& aDomain, PRBool aUseDB)
nsDOMStorage::nsDOMStorage(const nsAString& aDomain, PRBool aUseDB)
: mUseDB(aUseDB),
mSessionOnly(PR_TRUE),
mItemsCached(PR_FALSE),
mURI(aURI),
mDomain(aDomain)
{
#ifndef MOZ_STORAGE
@ -440,9 +470,8 @@ nsDOMStorage::~nsDOMStorage()
}
void
nsDOMStorage::Init(nsIURI* aURI, const nsAString& aDomain, PRBool aUseDB)
nsDOMStorage::Init(const nsAString& aDomain, PRBool aUseDB)
{
mURI = aURI;
mDomain.Assign(aDomain);
#ifdef MOZ_STORAGE
mUseDB = aUseDB;
@ -453,10 +482,10 @@ nsDOMStorage::Init(nsIURI* aURI, const nsAString& aDomain, PRBool aUseDB)
//static
PRBool
nsDOMStorage::CanUseStorage(nsIURI* aURI, PRPackedBool* aSessionOnly)
nsDOMStorage::CanUseStorage(PRPackedBool* aSessionOnly)
{
// check if the domain can use storage. Downgrade to session only if only
// session storage may be used.
// check if the calling domain can use storage. Downgrade to session
// only if only session storage may be used.
NS_ASSERTION(aSessionOnly, "null session flag");
*aSessionOnly = PR_FALSE;
@ -467,13 +496,28 @@ nsDOMStorage::CanUseStorage(nsIURI* aURI, PRPackedBool* aSessionOnly)
if (nsContentUtils::IsCallerChrome())
return PR_TRUE;
nsCOMPtr<nsIPrincipal> subjectPrincipal;
nsContentUtils::GetSecurityManager()->
GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
// if subjectPrincipal were null we'd have returned after
// IsCallerChrome().
nsCOMPtr<nsIURI> subjectURI;
nsAutoString unused;
if (NS_FAILED(GetPrincipalURIAndHost(subjectPrincipal,
getter_AddRefs(subjectURI),
unused))) {
return PR_FALSE;
}
nsCOMPtr<nsIPermissionManager> permissionManager =
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
if (!permissionManager)
return PR_FALSE;
PRUint32 perm;
permissionManager->TestPermission(aURI, kPermissionType, &perm);
permissionManager->TestPermission(subjectURI, kPermissionType, &perm);
if (perm == nsIPermissionManager::DENY_ACTION)
return PR_FALSE;
@ -496,6 +540,23 @@ nsDOMStorage::CanUseStorage(nsIURI* aURI, PRPackedBool* aSessionOnly)
return PR_TRUE;
}
PRBool
nsDOMStorage::CacheStoragePermissions()
{
if (!CanUseStorage(&mSessionOnly))
return PR_FALSE;
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
if (!ssm)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIPrincipal> subjectPrincipal;
ssm->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
return CanAccess(subjectPrincipal);
}
class ItemCounterState
{
public:
@ -833,40 +894,6 @@ nsDOMStorage::GetDBValue(const nsAString& aKey, nsAString& aValue,
return NS_OK;
}
// The URI returned is the innermost URI that should be used for
// security-check-like stuff. aHost is its hostname, correctly canonicalized.
static nsresult
GetPrincipalURIAndHost(nsIPrincipal* aPrincipal, nsIURI** aURI, nsString& aHost)
{
nsresult rv = aPrincipal->GetDomain(aURI);
NS_ENSURE_SUCCESS(rv, rv);
if (!*aURI) {
rv = aPrincipal->GetURI(aURI);
NS_ENSURE_SUCCESS(rv, rv);
}
if (!*aURI) {
return NS_OK;
}
nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(*aURI);
if (!innerURI) {
return NS_ERROR_UNEXPECTED;
}
nsCAutoString asciiHost;
rv = innerURI->GetAsciiHost(asciiHost);
if (NS_FAILED(rv)) {
return NS_ERROR_DOM_SECURITY_ERR;
}
CopyUTF8toUTF16(asciiHost, aHost);
innerURI.swap(*aURI);
return NS_OK;
}
nsresult
nsDOMStorage::SetDBValue(const nsAString& aKey,
const nsAString& aValue,
@ -1000,7 +1027,7 @@ CopyStorageItems(nsSessionStorageEntry* aEntry, void* userArg)
}
already_AddRefed<nsIDOMStorage>
nsDOMStorage::Clone(nsIURI* aURI)
nsDOMStorage::Clone()
{
if (UseDB()) {
NS_ERROR("Uh, don't clone a global storage object.");
@ -1008,7 +1035,7 @@ nsDOMStorage::Clone(nsIURI* aURI)
return nsnull;
}
nsDOMStorage* storage = new nsDOMStorage(aURI, mDomain, PR_FALSE);
nsDOMStorage* storage = new nsDOMStorage(mDomain, PR_FALSE);
if (!storage)
return nsnull;
@ -1051,6 +1078,36 @@ nsDOMStorage::GetKeys()
return keystruct.keys;
}
const nsString &
nsDOMStorage::Domain()
{
return mDomain;
}
PRBool
nsDOMStorage::CanAccess(nsIPrincipal *aPrincipal)
{
// Allow C++/system callers to access the storage
if (!aPrincipal)
return PR_TRUE;
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
if (!ssm)
return PR_TRUE;
PRBool isSystem;
if (NS_SUCCEEDED(ssm->IsSystemPrincipal(aPrincipal, &isSystem) && isSystem))
return PR_TRUE;
nsAutoString domain;
nsCOMPtr<nsIURI> unused;
nsresult rv = GetPrincipalURIAndHost(aPrincipal,
getter_AddRefs(unused), domain);
NS_ENSURE_SUCCESS(rv, PR_FALSE);
return domain.Equals(mDomain);
}
void
nsDOMStorage::BroadcastChangeNotification()
{
@ -1111,31 +1168,28 @@ nsDOMStorageList::GetNamedItem(const nsAString& aDomain, nsresult* aResult)
*aResult = ssm->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
NS_ENSURE_SUCCESS(*aResult, nsnull);
nsCOMPtr<nsIURI> uri;
nsAutoString currentDomain;
if (subjectPrincipal) {
*aResult = GetPrincipalURIAndHost(subjectPrincipal, getter_AddRefs(uri),
nsCOMPtr<nsIURI> unused;
*aResult = GetPrincipalURIAndHost(subjectPrincipal, getter_AddRefs(unused),
currentDomain);
NS_ENSURE_SUCCESS(*aResult, nsnull);
if (uri) {
PRPackedBool sessionOnly;
if (!nsDOMStorage::CanUseStorage(uri, &sessionOnly)) {
*aResult = NS_ERROR_DOM_SECURITY_ERR;
return nsnull;
}
PRPackedBool sessionOnly;
if (!nsDOMStorage::CanUseStorage(&sessionOnly)) {
*aResult = NS_ERROR_DOM_SECURITY_ERR;
return nsnull;
}
}
PRBool isSystem = nsContentUtils::IsCallerTrustedForRead();
if (isSystem || !currentDomain.IsEmpty()) {
return GetStorageForDomain(uri, NS_ConvertUTF8toUTF16(requestedDomain),
currentDomain, isSystem, aResult);
if (currentDomain.IsEmpty() && !isSystem) {
*aResult = NS_ERROR_DOM_SECURITY_ERR;
return nsnull;
}
*aResult = NS_ERROR_DOM_SECURITY_ERR;
return nsnull;
return GetStorageForDomain(NS_ConvertUTF8toUTF16(requestedDomain),
currentDomain, isSystem, aResult);
}
NS_IMETHODIMP
@ -1156,8 +1210,7 @@ nsDOMStorageList::CanAccessDomain(const nsAString& aRequestedDomain,
}
nsIDOMStorage*
nsDOMStorageList::GetStorageForDomain(nsIURI* aURI,
const nsAString& aRequestedDomain,
nsDOMStorageList::GetStorageForDomain(const nsAString& aRequestedDomain,
const nsAString& aCurrentDomain,
PRBool aNoCurrentDomainCheck,
nsresult* aResult)
@ -1186,7 +1239,7 @@ nsDOMStorageList::GetStorageForDomain(nsIURI* aURI,
// now have a valid domain, so look it up in the storage table
nsIDOMStorage* storage = mStorages.GetWeak(usedDomain);
if (!storage) {
nsCOMPtr<nsIDOMStorage> newstorage = new nsDOMStorage(aURI, usedDomain, PR_TRUE);
nsCOMPtr<nsIDOMStorage> newstorage = new nsDOMStorage(usedDomain, PR_TRUE);
if (newstorage && mStorages.Put(usedDomain, newstorage))
storage = newstorage;
else

Просмотреть файл

@ -116,7 +116,7 @@ class nsDOMStorage : public nsIDOMStorage,
{
public:
nsDOMStorage();
nsDOMStorage(nsIURI* aURI, const nsAString& aDomain, PRBool aUseDB);
nsDOMStorage(const nsAString& aDomain, PRBool aUseDB);
virtual ~nsDOMStorage();
// nsISupports
@ -127,23 +127,29 @@ public:
NS_DECL_NSIDOMSTORAGE
// nsPIDOMStorage
virtual void Init(nsIURI* aURI, const nsAString& aDomain, PRBool aUseDB);
virtual already_AddRefed<nsIDOMStorage> Clone(nsIURI* aURI);
virtual void Init(const nsAString& aDomain, PRBool aUseDB);
virtual already_AddRefed<nsIDOMStorage> Clone();
virtual nsTArray<nsString> *GetKeys();
virtual const nsString &Domain();
virtual PRBool CanAccess(nsIPrincipal *aPrincipal);
// If true, the contents of the storage should be stored in the
// database, otherwise this storage should act like a session
// storage.
// This call relies on mSessionOnly, and should only be used
// after a CacheStoragePermissions() call. See the comments
// for mSessionOnly below.
PRBool UseDB() { return mUseDB && !mSessionOnly; }
// cache whether storage may be used by aURI, and whether it is session
// only. If aURI is null, the uri associated with this storage (mURI)
// is checked. Returns true if storage may be used.
// Check whether storage may be used by the caller, and whether it
// is session only. Returns true if storage may be used.
static PRBool
CanUseStorage(nsIURI* aURI, PRPackedBool* aSessionOnly);
CanUseStorage(PRPackedBool* aSessionOnly);
// Check whether storage may be used. Updates mSessionOnly based on
// the result of CanUseStorage.
PRBool
CacheStoragePermissions()
{
return CanUseStorage(mURI, &mSessionOnly);
}
CacheStoragePermissions();
// retrieve the value and secure state corresponding to a key out of storage.
nsresult
@ -188,15 +194,16 @@ protected:
// true if the storage database should be used for values
PRPackedBool mUseDB;
// true if the preferences indicates that this storage should be session only
// true if the preferences indicates that this storage should be
// session only. This member is updated by
// CacheStoragePermissions(), using the current principal.
// CacheStoragePermissions() must be called at each entry point to
// make sure this stays up to date.
PRPackedBool mSessionOnly;
// true if items from the database are cached
PRPackedBool mItemsCached;
// the URI this store is associated with
nsCOMPtr<nsIURI> mURI;
// domain this store is associated with
nsString mDomain;
@ -246,8 +253,7 @@ protected:
* @param aNoCurrentDomainCheck true to skip domain comparison
*/
nsIDOMStorage*
GetStorageForDomain(nsIURI* aURI,
const nsAString& aRequestedDomain,
GetStorageForDomain(const nsAString& aRequestedDomain,
const nsAString& aCurrentDomain,
PRBool aNoCurrentDomainCheck,
nsresult* aResult);

Просмотреть файл

@ -84,6 +84,8 @@ _TEST_FILES = \
test_bug440572.html \
iframe_bug440572.html \
test_bug437361.html \
test_bug458091.html \
bug458091_child.html \
test_bug459848.html \
test_bug465263.html \
$(NULL)

Просмотреть файл

@ -0,0 +1,13 @@
<html> <head>
<title></title>
<script type="text/javascript">
function finish() {
window.opener.finish(sessionStorage["testItem"]);
window.close();
}
</script>
</head>
<body onload="finish();">
</body>
</html>

Просмотреть файл

@ -0,0 +1,101 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=458091
-->
<head>
<title>Test for Bug 458091</title>
<script type="application/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=458091">Mozilla Bug 458091</a>
<div id="content" style="display: none">
</div>
<pre id="test">
<a id="testlink1" target="_blank" href="javascript:window.opener.finish(sessionStorage['testItem']);window.close();">Javascript Link</a>
<a id="testlink2" target="_blank" href="bug458091_child.html">HTTP Link</a>
<a id="testlink3" target="alreadyOpened" href="bug458091_child.html">Target Link</a>
<script type="application/javascript">
/** Test for Bug 458091 **/
var gTestWin;
var gRunningTests = 0;
function runNextTest()
{
if (gTests.length > 0) {
var test = gTests.shift();
test();
} else {
SimpleTest.finish();
}
}
function finish(val)
{
is(val, "correct value",
"New window should access the correct session storage");
if (--gRunningTests == 0) {
runNextTest();
}
}
SimpleTest.waitForExplicitFinish();
function test1() {
sessionStorage["testItem"] = "correct value";
gRunningTests++;
window.open('javascript:window.opener.finish(sessionStorage["testItem"]);window.close();');
gRunningTests++;
window.open("bug458091_child.html");
gRunningTests++;
sendMouseEvent({type: "click"}, "testlink1");
gRunningTests++;
sendMouseEvent({type: "click"}, "testlink2");
// targetted load into an existing window
var testWin = window.open("about:blank", "alreadyOpened");
gRunningTests++;
sendMouseEvent({type: "click"}, "testlink3");
// window.location into an existing window. Leave the window open
// for further tests...
gRunningTests++;
gTestWin = window.open("about:blank", "testWindow");
gTestWin.location = 'javascript:window.opener.finish(sessionStorage["testItem"]);';
}
function test2() {
// Now change session storage and load a new item in gTestWin, to
// verify that they properly diverged after window.open().
gRunningTests++;
sessionStorage["testItem"] = "incorrect value";
gTestWin.location = 'javascript:window.opener.finish(sessionStorage["testItem"]);';
}
function test3()
{
// Now, with session storage still changed, try the window.open()
// path, make sure it doesn't overwrite the session storage.
gRunningTests++;
window.open('javascript:window.opener.finish(sessionStorage["testItem"]);window.close();',
"testWindow");
}
var gTests = [test1, test2, test3];
runNextTest();
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -85,6 +85,8 @@
#include "nsIMutableArray.h"
#include "nsISupportsArray.h"
#include "nsIDeviceContext.h"
#include "nsIDOMStorage.h"
#include "nsPIDOMStorage.h"
#include "nsIPrefBranch.h"
#include "nsIPrefService.h"
@ -919,6 +921,26 @@ nsWindowWatcher::OpenWindowJSInternal(nsIDOMWindow *aParent,
nsIWebNavigation::LOAD_FLAGS_NONE, PR_TRUE);
}
// Copy the current session storage for the current domain.
nsCOMPtr<nsPIDOMWindow> piWindow = do_QueryInterface(aParent);
nsCOMPtr<nsIDocShell_MOZILLA_1_9_1> parentDocShell;
if (piWindow)
parentDocShell = do_QueryInterface(piWindow->GetDocShell());
if (subjectPrincipal && parentDocShell) {
nsCOMPtr<nsIDOMStorage> storage;
parentDocShell->GetSessionStorageForPrincipal(subjectPrincipal, PR_FALSE,
getter_AddRefs(storage));
nsCOMPtr<nsPIDOMStorage> piStorage =
do_QueryInterface(storage);
if (piStorage){
storage = piStorage->Clone();
newDocShell->AddSessionStorage(
NS_ConvertUTF16toUTF8(piStorage->Domain()),
storage);
}
}
if (isNewToplevelWindow)
SizeOpenedDocShellItem(newDocShellItem, aParent, sizeSpec);