nsresult nsDOMStorage::Clear() { if (!CacheStoragePermissions()) return NS_ERROR_DOM_SECURITY_ERR; if (UseDB()) CacheKeysFromDB(); PRBool foundSecureItem = PR_FALSE; mItems.EnumerateEntries(CheckSecure, &foundSecureItem); if (foundSecureItem && !IsCallerSecure()) { return NS_ERROR_DOM_SECURITY_ERR; } #ifdef MOZ_STORAGE if (UseDB()) { nsresult rv = InitDB(); NS_ENSURE_SUCCESS(rv, rv); rv = gStorageDB->ClearStorage(this); NS_ENSURE_SUCCESS(rv, rv); } #endif mItems.Clear(); BroadcastChangeNotification(); return NS_OK; }
NS_IMETHODIMP nsDOMStorage::Key(PRUint32 aIndex, nsAString& aKey) { // XXXjst: This is as retarded as the DOM spec is, takes an unsigned // int, but the spec talks about what to do if a negative value is // passed in. // XXX: This does a linear search for the key at index, which would // suck if there's a large numer of indexes. Do we care? If so, // maybe we need to have a lazily populated key array here or // something? if (!CacheStoragePermissions()) return NS_ERROR_DOM_SECURITY_ERR; if (UseDB()) CacheKeysFromDB(); IndexFinderData data(IsCallerSecure(), aIndex); mItems.EnumerateEntries(IndexFinder, &data); if (!data.mItem) { // aIndex was larger than the number of accessible keys. Throw. return NS_ERROR_DOM_INDEX_SIZE_ERR; } aKey = data.mItem->GetKey(); return NS_OK; }
NS_IMETHODIMP nsDOMStorage::RemoveItem(const nsAString& aKey) { if (!CacheStoragePermissions()) return NS_ERROR_DOM_SECURITY_ERR; if (aKey.IsEmpty()) return NS_OK; nsSessionStorageEntry *entry = mItems.GetEntry(aKey); if (entry && entry->mItem->IsSecure() && !IsCallerSecure()) { return NS_ERROR_DOM_SECURITY_ERR; } if (UseDB()) { #ifdef MOZ_STORAGE nsresult rv = InitDB(); NS_ENSURE_SUCCESS(rv, rv); nsAutoString value; PRBool secureItem; nsAutoString owner; rv = GetDBValue(aKey, value, &secureItem, owner); if (rv == NS_ERROR_DOM_NOT_FOUND_ERR) return NS_OK; NS_ENSURE_SUCCESS(rv, rv); rv = gStorageDB->RemoveKey(mDomain, aKey, owner, aKey.Length() + value.Length()); NS_ENSURE_SUCCESS(rv, rv); mItemsCached = PR_FALSE; BroadcastChangeNotification(); #endif } else if (entry) { // clear string as StorageItems may be referencing this item entry->mItem->ClearValue(); BroadcastChangeNotification(); } if (entry) { mItems.RawRemoveEntry(entry); } return NS_OK; }
NS_IMETHODIMP nsDOMStorageItem::SetSecure(PRBool aSecure) { if (!mStorage->CacheStoragePermissions() || !IsCallerSecure()) { return NS_ERROR_DOM_INVALID_ACCESS_ERR; } if (mStorage->UseDB()) { nsresult rv = mStorage->SetSecure(mKey, aSecure); NS_ENSURE_SUCCESS(rv, rv); } mSecure = aSecure; return NS_OK; }
NS_IMETHODIMP nsDOMStorageItem::GetSecure(PRBool* aSecure) { if (!mStorage->CacheStoragePermissions() || !IsCallerSecure()) { return NS_ERROR_DOM_INVALID_ACCESS_ERR; } if (mStorage->UseDB()) { nsAutoString value; return mStorage->GetDBValue(mKey, value, aSecure); } *aSecure = IsSecure(); return NS_OK; }
NS_IMETHODIMP nsDOMStorage::SetItem(const nsAString& aKey, const nsAString& aData) { if (!CacheStoragePermissions()) return NS_ERROR_DOM_SECURITY_ERR; if (aKey.IsEmpty()) return NS_OK; nsresult rv; nsRefPtr<nsDOMStorageItem> newitem = nsnull; nsSessionStorageEntry *entry = mItems.GetEntry(aKey); if (entry) { if (entry->mItem->IsSecure() && !IsCallerSecure()) { return NS_ERROR_DOM_SECURITY_ERR; } if (!UseDB()) { entry->mItem->SetValueInternal(aData); } } else { if (UseDB()) newitem = new nsDOMStorageItem(this, aKey, aData, PR_FALSE); else newitem = new nsDOMStorageItem(this, aKey, aData, PR_FALSE); if (!newitem) return NS_ERROR_OUT_OF_MEMORY; } if (UseDB()) { rv = SetDBValue(aKey, aData, IsCallerSecure()); NS_ENSURE_SUCCESS(rv, rv); } if (newitem) { entry = mItems.PutEntry(aKey); NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY); entry->mItem = newitem; } // SetDBValue already calls BroadcastChangeNotification so don't do it again if (!UseDB()) BroadcastChangeNotification(); return NS_OK; }
NS_IMETHODIMP nsDOMStorage::GetLength(PRUint32 *aLength) { if (!CacheStoragePermissions()) return NS_ERROR_DOM_SECURITY_ERR; if (UseDB()) CacheKeysFromDB(); ItemCounterState state(IsCallerSecure()); mItems.EnumerateEntries(ItemCounter, &state); *aLength = state.mCount; return NS_OK; }
NS_IMETHODIMP nsDOMStorage::GetItem(const nsAString& aKey, nsIDOMStorageItem **aItem) { *aItem = nsnull; if (!CacheStoragePermissions()) return NS_ERROR_DOM_SECURITY_ERR; if (aKey.IsEmpty()) return NS_OK; nsSessionStorageEntry *entry = mItems.GetEntry(aKey); if (entry) { if (!IsCallerSecure() && entry->mItem->IsSecure()) { return NS_OK; } NS_ADDREF(*aItem = entry->mItem); } else if (UseDB()) { PRBool secure; nsAutoString value; nsAutoString unused; nsresult rv = GetDBValue(aKey, value, &secure, unused); // return null if access isn't allowed or the key wasn't found if (rv == NS_ERROR_DOM_SECURITY_ERR || rv == NS_ERROR_DOM_NOT_FOUND_ERR) return NS_OK; NS_ENSURE_SUCCESS(rv, rv); nsRefPtr<nsDOMStorageItem> newitem = new nsDOMStorageItem(this, aKey, value, secure); if (!newitem) return NS_ERROR_OUT_OF_MEMORY; entry = mItems.PutEntry(aKey); NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY); entry->mItem = newitem; NS_ADDREF(*aItem = newitem); } return NS_OK; }
nsIDOMStorageItem* nsDOMStorage::GetNamedItem(const nsAString& aKey, nsresult* aResult) { if (!CacheStoragePermissions()) { *aResult = NS_ERROR_DOM_SECURITY_ERR; return nsnull; } *aResult = NS_OK; if (aKey.IsEmpty()) return nsnull; nsSessionStorageEntry *entry = mItems.GetEntry(aKey); nsIDOMStorageItem* item = nsnull; if (entry) { if (IsCallerSecure() || !entry->mItem->IsSecure()) { item = entry->mItem; } } else if (UseDB()) { PRBool secure; nsAutoString value; nsresult rv = GetDBValue(aKey, value, &secure); // return null if access isn't allowed or the key wasn't found if (rv == NS_ERROR_DOM_SECURITY_ERR || rv == NS_ERROR_DOM_NOT_FOUND_ERR) return nsnull; *aResult = rv; NS_ENSURE_SUCCESS(rv, nsnull); nsRefPtr<nsDOMStorageItem> newitem = new nsDOMStorageItem(this, aKey, value, secure); if (newitem && (entry = mItems.PutEntry(aKey))) { item = entry->mItem = newitem; } else { *aResult = NS_ERROR_OUT_OF_MEMORY; } } return item; }
NS_IMETHODIMP nsDOMStorage::GetLength(PRUint32 *aLength) { if (!CacheStoragePermissions()) return NS_ERROR_DOM_SECURITY_ERR; // Force reload of items from database. This ensures sync localStorages for // same origins among different windows. mItemsCached = PR_FALSE; if (UseDB()) CacheKeysFromDB(); ItemCounterState state(IsCallerSecure()); mItems.EnumerateEntries(ItemCounter, &state); *aLength = state.mCount; return NS_OK; }
NS_IMETHODIMP nsDOMStorageItem::GetValue(nsAString& aValue) { if (!mStorage->CacheStoragePermissions()) return NS_ERROR_DOM_INVALID_ACCESS_ERR; if (mStorage->UseDB()) { // GetDBValue checks the secure state so no need to do it here PRBool secure; nsresult rv = mStorage->GetDBValue(mKey, aValue, &secure); if (rv == NS_ERROR_DOM_NOT_FOUND_ERR) return NS_OK; return rv; } if (IsSecure() && !IsCallerSecure()) { return NS_ERROR_DOM_SECURITY_ERR; } aValue = mValue; return NS_OK; }
NS_IMETHODIMP nsDOMStorageItem::SetValue(const nsAString& aValue) { if (!mStorage->CacheStoragePermissions()) return NS_ERROR_DOM_INVALID_ACCESS_ERR; PRBool secureCaller = IsCallerSecure(); if (mStorage->UseDB()) { // SetDBValue() does the security checks for us. return mStorage->SetDBValue(mKey, aValue, secureCaller); } PRBool secureItem = IsSecure(); if (!secureCaller && secureItem) { // The item is secure, but the caller isn't. Throw. return NS_ERROR_DOM_SECURITY_ERR; } mValue = aValue; mSecure = secureCaller; return NS_OK; }