/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "SessionStorageCache.h" #include "mozilla/dom/PContent.h" namespace mozilla { namespace dom { SessionStorageCache::SessionStorageCache() = default; SessionStorageCache::DataSet* SessionStorageCache::Set( DataSetType aDataSetType) { if (aDataSetType == eDefaultSetType) { return &mDefaultSet; } MOZ_ASSERT(aDataSetType == eSessionSetType); return &mSessionSet; } int64_t SessionStorageCache::GetOriginQuotaUsage(DataSetType aDataSetType) { return Set(aDataSetType)->mOriginQuotaUsage; } uint32_t SessionStorageCache::Length(DataSetType aDataSetType) { return Set(aDataSetType)->mKeys.Count(); } void SessionStorageCache::Key(DataSetType aDataSetType, uint32_t aIndex, nsAString& aResult) { aResult.SetIsVoid(true); for (auto iter = Set(aDataSetType)->mKeys.Iter(); !iter.Done(); iter.Next()) { if (aIndex == 0) { aResult = iter.Key(); return; } aIndex--; } } void SessionStorageCache::GetItem(DataSetType aDataSetType, const nsAString& aKey, nsAString& aResult) { // not using AutoString since we don't want to copy buffer to result nsString value; if (!Set(aDataSetType)->mKeys.Get(aKey, &value)) { SetDOMStringToNull(value); } aResult = value; } void SessionStorageCache::GetKeys(DataSetType aDataSetType, nsTArray& aKeys) { for (auto iter = Set(aDataSetType)->mKeys.Iter(); !iter.Done(); iter.Next()) { aKeys.AppendElement(iter.Key()); } } nsresult SessionStorageCache::SetItem(DataSetType aDataSetType, const nsAString& aKey, const nsAString& aValue, nsString& aOldValue) { int64_t delta = 0; DataSet* dataSet = Set(aDataSetType); if (!dataSet->mKeys.Get(aKey, &aOldValue)) { SetDOMStringToNull(aOldValue); // We only consider key size if the key doesn't exist before. delta = static_cast(aKey.Length()); } delta += static_cast(aValue.Length()) - static_cast(aOldValue.Length()); if (aValue == aOldValue && DOMStringIsNull(aValue) == DOMStringIsNull(aOldValue)) { return NS_SUCCESS_DOM_NO_OPERATION; } if (!dataSet->ProcessUsageDelta(delta)) { return NS_ERROR_DOM_QUOTA_EXCEEDED_ERR; } dataSet->mKeys.Put(aKey, nsString(aValue)); return NS_OK; } nsresult SessionStorageCache::RemoveItem(DataSetType aDataSetType, const nsAString& aKey, nsString& aOldValue) { DataSet* dataSet = Set(aDataSetType); if (!dataSet->mKeys.Get(aKey, &aOldValue)) { return NS_SUCCESS_DOM_NO_OPERATION; } // Recalculate the cached data size dataSet->ProcessUsageDelta(-(static_cast(aOldValue.Length()) + static_cast(aKey.Length()))); dataSet->mKeys.Remove(aKey); return NS_OK; } void SessionStorageCache::Clear(DataSetType aDataSetType, bool aByUserInteraction) { DataSet* dataSet = Set(aDataSetType); dataSet->ProcessUsageDelta(-dataSet->mOriginQuotaUsage); dataSet->mKeys.Clear(); } already_AddRefed SessionStorageCache::Clone() const { RefPtr cache = new SessionStorageCache(); cache->mDefaultSet.mOriginQuotaUsage = mDefaultSet.mOriginQuotaUsage; for (auto iter = mDefaultSet.mKeys.ConstIter(); !iter.Done(); iter.Next()) { cache->mDefaultSet.mKeys.Put(iter.Key(), iter.Data()); } cache->mSessionSet.mOriginQuotaUsage = mSessionSet.mOriginQuotaUsage; for (auto iter = mSessionSet.mKeys.ConstIter(); !iter.Done(); iter.Next()) { cache->mSessionSet.mKeys.Put(iter.Key(), iter.Data()); } return cache.forget(); } nsTArray SessionStorageCache::SerializeData( DataSetType aDataSetType) { nsTArray data; for (auto iter = Set(aDataSetType)->mKeys.Iter(); !iter.Done(); iter.Next()) { KeyValuePair keyValuePair; keyValuePair.key() = iter.Key(); keyValuePair.value() = iter.Data(); data.EmplaceBack(std::move(keyValuePair)); } return data; } void SessionStorageCache::DeserializeData(DataSetType aDataSetType, const nsTArray& aData) { Clear(aDataSetType, false); for (const auto& keyValuePair : aData) { nsString oldValue; SetItem(aDataSetType, keyValuePair.key(), keyValuePair.value(), oldValue); } } bool SessionStorageCache::DataSet::ProcessUsageDelta(int64_t aDelta) { // Check limit per this origin uint64_t newOriginUsage = mOriginQuotaUsage + aDelta; if (aDelta > 0 && newOriginUsage > LocalStorageManager::GetQuota()) { return false; } // Update size in our data set mOriginQuotaUsage = newOriginUsage; return true; } } // namespace dom } // namespace mozilla