nsresult
DOMStorageManager::GetStorageInternal(bool aCreate,
                                      mozIDOMWindow* aWindow,
                                      nsIPrincipal* aPrincipal,
                                      const nsAString& aDocumentURI,
                                      bool aPrivate,
                                      nsIDOMStorage** aRetval)
{
  nsresult rv;

  nsAutoCString originAttrSuffix;
  BasePrincipal::Cast(aPrincipal)->OriginAttributesRef().CreateSuffix(originAttrSuffix);

  nsAutoCString originKey;
  rv = AppendOriginNoSuffix(aPrincipal, originKey);
  if (NS_FAILED(rv)) {
    return NS_ERROR_NOT_AVAILABLE;
  }

  RefPtr<DOMStorageCache> cache = GetCache(originAttrSuffix, originKey);

  // Get or create a cache for the given scope
  if (!cache) {
    if (!aCreate) {
      *aRetval = nullptr;
      return NS_OK;
    }

    if (!aRetval) {
      // This is a demand to just preload the cache, if the scope has
      // no data stored, bypass creation and preload of the cache.
      DOMStorageDBBridge* db = DOMStorageCache::GetDatabase();
      if (db) {
        if (!db->ShouldPreloadOrigin(DOMStorageManager::CreateOrigin(originAttrSuffix, originKey))) {
          return NS_OK;
        }
      } else {
        if (originKey.EqualsLiteral("knalb.:about")) {
          return NS_OK;
        }
      }
    }

    // There is always a single instance of a cache per scope
    // in a single instance of a DOM storage manager.
    cache = PutCache(originAttrSuffix, originKey, aPrincipal);
  } else if (mType == SessionStorage) {
    if (!cache->CheckPrincipal(aPrincipal)) {
      return NS_ERROR_DOM_SECURITY_ERR;
    }
  }

  if (aRetval) {
    nsCOMPtr<nsPIDOMWindowInner> inner = nsPIDOMWindowInner::From(aWindow);

    nsCOMPtr<nsIDOMStorage> storage = new DOMStorage(
      inner, this, cache, aDocumentURI, aPrincipal, aPrivate);
    storage.forget(aRetval);
  }

  return NS_OK;
}