dom/storage/SessionStorage.cpp
author Kris Maglione <maglione.k@gmail.com>
Thu, 14 Feb 2019 17:54:00 -0800
changeset 517406 7436c0f5b8b1583d20d5ea2d1d9d3b2c665bdf33
parent 512282 188f4b17a553dd31889c64fa5695df535a7cf0a1
child 519087 1c359cdcf69f276b4a58de7b8c11a07f7e4e8b9c
permissions -rw-r--r--
Fix botched backout (bug 1524687). r=bustage

/* -*- 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 "SessionStorage.h"
#include "SessionStorageCache.h"
#include "SessionStorageManager.h"

#include "mozilla/dom/StorageBinding.h"
#include "mozilla/Preferences.h"
#include "nsContentUtils.h"
#include "nsIPrincipal.h"
#include "nsIWebProgressListener.h"
#include "nsPIDOMWindow.h"

#define DATASET                                          \
  IsSessionOnly() ? SessionStorageCache::eSessionSetType \
                  : SessionStorageCache::eDefaultSetType

namespace mozilla {
namespace dom {

NS_IMPL_CYCLE_COLLECTION_INHERITED(SessionStorage, Storage, mManager);

NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SessionStorage)
NS_INTERFACE_MAP_END_INHERITING(Storage)

NS_IMPL_ADDREF_INHERITED(SessionStorage, Storage)
NS_IMPL_RELEASE_INHERITED(SessionStorage, Storage)

SessionStorage::SessionStorage(nsPIDOMWindowInner* aWindow,
                               nsIPrincipal* aPrincipal,
                               SessionStorageCache* aCache,
                               SessionStorageManager* aManager,
                               const nsAString& aDocumentURI, bool aIsPrivate)
    : Storage(aWindow, aPrincipal),
      mCache(aCache),
      mManager(aManager),
      mDocumentURI(aDocumentURI),
      mIsPrivate(aIsPrivate) {
  MOZ_ASSERT(aCache);
}

SessionStorage::~SessionStorage() {}

already_AddRefed<SessionStorage> SessionStorage::Clone() const {
  RefPtr<SessionStorage> storage =
      new SessionStorage(GetParentObject(), Principal(), mCache, mManager,
                         mDocumentURI, mIsPrivate);
  return storage.forget();
}

int64_t SessionStorage::GetOriginQuotaUsage() const {
  return mCache->GetOriginQuotaUsage(DATASET);
}

uint32_t SessionStorage::GetLength(nsIPrincipal& aSubjectPrincipal,
                                   ErrorResult& aRv) {
  if (!CanUseStorage(aSubjectPrincipal)) {
    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
    return 0;
  }

  return mCache->Length(DATASET);
}

void SessionStorage::Key(uint32_t aIndex, nsAString& aResult,
                         nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) {
  if (!CanUseStorage(aSubjectPrincipal)) {
    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
    return;
  }

  mCache->Key(DATASET, aIndex, aResult);
}

void SessionStorage::GetItem(const nsAString& aKey, nsAString& aResult,
                             nsIPrincipal& aSubjectPrincipal,
                             ErrorResult& aRv) {
  if (!CanUseStorage(aSubjectPrincipal)) {
    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
    return;
  }

  mCache->GetItem(DATASET, aKey, aResult);
}

void SessionStorage::GetSupportedNames(nsTArray<nsString>& aKeys) {
  if (!CanUseStorage(*nsContentUtils::SubjectPrincipal())) {
    // return just an empty array
    aKeys.Clear();
    return;
  }

  mCache->GetKeys(DATASET, aKeys);
}

void SessionStorage::SetItem(const nsAString& aKey, const nsAString& aValue,
                             nsIPrincipal& aSubjectPrincipal,
                             ErrorResult& aRv) {
  if (!CanUseStorage(aSubjectPrincipal)) {
    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
    return;
  }

  nsString oldValue;
  nsresult rv = mCache->SetItem(DATASET, aKey, aValue, oldValue);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    aRv.Throw(rv);
    return;
  }

  if (rv == NS_SUCCESS_DOM_NO_OPERATION) {
    return;
  }

  BroadcastChangeNotification(aKey, oldValue, aValue);
}

void SessionStorage::RemoveItem(const nsAString& aKey,
                                nsIPrincipal& aSubjectPrincipal,
                                ErrorResult& aRv) {
  if (!CanUseStorage(aSubjectPrincipal)) {
    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
    return;
  }

  nsString oldValue;
  nsresult rv = mCache->RemoveItem(DATASET, aKey, oldValue);
  MOZ_ASSERT(NS_SUCCEEDED(rv));

  if (rv == NS_SUCCESS_DOM_NO_OPERATION) {
    return;
  }

  BroadcastChangeNotification(aKey, oldValue, VoidString());
}

void SessionStorage::Clear(nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) {
  uint32_t length = GetLength(aSubjectPrincipal, aRv);
  if (!length) {
    return;
  }

  mCache->Clear(DATASET);
  BroadcastChangeNotification(VoidString(), VoidString(), VoidString());
}

void SessionStorage::BroadcastChangeNotification(const nsAString& aKey,
                                                 const nsAString& aOldValue,
                                                 const nsAString& aNewValue) {
  NotifyChange(this, Principal(), aKey, aOldValue, aNewValue, u"sessionStorage",
               mDocumentURI, mIsPrivate, false);
}

bool SessionStorage::IsForkOf(const Storage* aOther) const {
  MOZ_ASSERT(aOther);
  if (aOther->Type() != eSessionStorage) {
    return false;
  }

  return mCache == static_cast<const SessionStorage*>(aOther)->mCache;
}

bool SessionStorage::ShouldThrowWhenStorageAccessDenied(
    uint32_t aRejectedReason) {
  return aRejectedReason !=
         nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN;
}

}  // namespace dom
}  // namespace mozilla