/*
 * Copyright (C) 2013-2020 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "StorageAreaMap.h"

#include "Logging.h"
#include "NetworkProcessConnection.h"
#include "NetworkStorageManagerMessages.h"
#include "StorageAreaImpl.h"
#include "StorageAreaMapMessages.h"
#include "StorageManagerSetMessages.h"
#include "StorageNamespaceImpl.h"
#include "WebPage.h"
#include "WebPageGroupProxy.h"
#include "WebProcess.h"
#include <WebCore/DOMWindow.h>
#include <WebCore/Document.h>
#include <WebCore/Frame.h>
#include <WebCore/Page.h>
#include <WebCore/PageGroup.h>
#include <WebCore/SecurityOriginData.h>
#include <WebCore/Storage.h>
#include <WebCore/StorageEventDispatcher.h>
#include <WebCore/StorageMap.h>
#include <WebCore/StorageType.h>

namespace WebKit {
using namespace WebCore;

StorageAreaMap::StorageAreaMap(StorageNamespaceImpl& storageNamespace, Ref<WebCore::SecurityOrigin>&& securityOrigin)
    : m_identifier(StorageAreaMapIdentifier::generate())
    , m_namespace(storageNamespace)
    , m_securityOrigin(WTFMove(securityOrigin))
    , m_quotaInBytes(storageNamespace.quotaInBytes())
    , m_type(storageNamespace.storageType())
{
    WebProcess::singleton().registerStorageAreaMap(*this);
}

StorageAreaMap::~StorageAreaMap()
{
    disconnect();
    WebProcess::singleton().unregisterStorageAreaMap(*this);
}

unsigned StorageAreaMap::length()
{
    return ensureMap().length();
}

String StorageAreaMap::key(unsigned index)
{
    return ensureMap().key(index);
}

String StorageAreaMap::item(const String& key)
{
    return ensureMap().getItem(key);
}

void StorageAreaMap::setItem(Frame* sourceFrame, StorageAreaImpl* sourceArea, const String& key, const String& value, bool& quotaException)
{
    auto& map = ensureMap();
    ASSERT(!map.isShared());

    String oldValue;
    quotaException = false;
    map.setItem(key, value, oldValue, quotaException);
    if (quotaException)
        return;

    if (oldValue == value)
        return;

    m_pendingValueChanges.add(key);

    if (!m_remoteAreaIdentifier) {
        RELEASE_LOG_ERROR(Storage, "StorageAreaMap::setItem failed because storage map ID is invalid");
        return;
    }
        
    auto callback = [weakThis = WeakPtr { *this }, seed = m_currentSeed, key](bool hasQuotaException) mutable {
        if (weakThis)
            weakThis->didSetItem(seed, key, hasQuotaException);
    };
    auto& connection = WebProcess::singleton().ensureNetworkProcessConnection().connection();
    connection.sendWithAsyncReply(Messages::NetworkStorageManager::SetItem(*m_remoteAreaIdentifier, sourceArea->identifier(), key, value, sourceFrame->document()->url().string()), WTFMove(callback));
}

void StorageAreaMap::removeItem(WebCore::Frame* sourceFrame, StorageAreaImpl* sourceArea, const String& key)
{
    auto& map = ensureMap();
    ASSERT(!map.isShared());

    String oldValue;
    map.removeItem(key, oldValue);

    if (oldValue.isNull())
        return;

    m_pendingValueChanges.add(key);

    if (!m_remoteAreaIdentifier) {
        RELEASE_LOG_ERROR(Storage, "StorageAreaMap::removeItem failed because storage map ID is invalid");
        return;
    }

    auto callback = [weakThis = WeakPtr { *this }, seed = m_currentSeed, key]() mutable {
        if (weakThis)
            weakThis->didRemoveItem(seed, key);
    };
    WebProcess::singleton().ensureNetworkProcessConnection().connection().sendWithAsyncReply(Messages::NetworkStorageManager::RemoveItem(*m_remoteAreaIdentifier, sourceArea->identifier(), key, sourceFrame->document()->url().string()), WTFMove(callback));
}

void StorageAreaMap::clear(WebCore::Frame* sourceFrame, StorageAreaImpl* sourceArea)
{
    connectSync();
    resetValues();

    m_hasPendingClear = true;
    m_map = makeUnique<StorageMap>(m_quotaInBytes);

    if (!m_remoteAreaIdentifier) {
        RELEASE_LOG_ERROR(Storage, "StorageAreaMap::clear failed because storage map ID is invalid");
        return;
    }

    auto callback = [weakThis = WeakPtr { *this }, seed = m_currentSeed]() mutable {
        if (weakThis)
            weakThis->didClear(seed);
    };
    WebProcess::singleton().ensureNetworkProcessConnection().connection().sendWithAsyncReply(Messages::NetworkStorageManager::Clear(*m_remoteAreaIdentifier, sourceArea->identifier(), sourceFrame->document()->url().string()), WTFMove(callback));
}

bool StorageAreaMap::contains(const String& key)
{
    return ensureMap().contains(key);
}

void StorageAreaMap::resetValues()
{
    m_map = nullptr;

    m_pendingValueChanges.clear();
    m_hasPendingClear = false;
    ++m_currentSeed;
}

StorageMap& StorageAreaMap::ensureMap()
{
    connectSync();

    if (!m_map)
        m_map = makeUnique<StorageMap>(m_quotaInBytes);

    return *m_map;
}

void StorageAreaMap::didSetItem(uint64_t mapSeed, const String& key, bool quotaError)
{
    if (m_currentSeed != mapSeed)
        return;

    ASSERT(m_pendingValueChanges.contains(key));

    if (quotaError) {
        resetValues();
        return;
    }

    m_pendingValueChanges.remove(key);
}

void StorageAreaMap::didRemoveItem(uint64_t mapSeed, const String& key)
{
    if (m_currentSeed != mapSeed)
        return;

    ASSERT(m_pendingValueChanges.contains(key));
    m_pendingValueChanges.remove(key);
}

void StorageAreaMap::didClear(uint64_t mapSeed)
{
    if (m_currentSeed != mapSeed)
        return;

    ASSERT(m_hasPendingClear);
    m_hasPendingClear = false;
}

bool StorageAreaMap::shouldApplyChangeForKey(const String& key) const
{
    // We have not yet loaded anything from this storage map.
    if (!m_map)
        return false;

    // Check if this storage area is currently waiting for the storage manager to update the given key.
    // If that is the case, we don't want to apply any changes made by other storage areas, since
    // our change was made last.
    if (m_pendingValueChanges.contains(key))
        return false;

    return true;
}

void StorageAreaMap::applyChange(const String& key, const String& newValue)
{
    ASSERT(!m_map || !m_map->isShared());

    // There is at least one clear pending we don't want to apply any changes until we get the corresponding DidClear messages.
    if (m_hasPendingClear)
        return;

    if (!key) {
        // A null key means clear.
        auto newMap = makeUnique<StorageMap>(m_quotaInBytes);

        // Any changes that were made locally after the clear must still be kept around in the new map.
        for (auto& change : m_pendingValueChanges) {
            auto& key = change.key;
            String value = m_map->getItem(key);
            if (!value) {
                // This change must have been a pending remove, ignore it.
                continue;
            }

            String oldValue;
            newMap->setItemIgnoringQuota(key, oldValue);
        }

        m_map = WTFMove(newMap);
        return;
    }

    if (!shouldApplyChangeForKey(key))
        return;

    if (!newValue) {
        // A null new value means that the item should be removed.
        String oldValue;
        m_map->removeItem(key, oldValue);
        return;
    }

    m_map->setItemIgnoringQuota(key, newValue);
}

void StorageAreaMap::dispatchStorageEvent(const std::optional<StorageAreaImplIdentifier>& storageAreaImplID, const String& key, const String& oldValue, const String& newValue, const String& urlString, uint64_t messageIdentifier)
{
    if (messageIdentifier < m_lastHandledMessageIdentifier)
        return;

    m_lastHandledMessageIdentifier = messageIdentifier;
    if (!storageAreaImplID) {
        // This storage event originates from another process so we need to apply the change to our storage area map.
        applyChange(key, newValue);
    }

    if (type() == StorageType::Session)
        dispatchSessionStorageEvent(storageAreaImplID, key, oldValue, newValue, urlString);
    else
        dispatchLocalStorageEvent(storageAreaImplID, key, oldValue, newValue, urlString);
}

void StorageAreaMap::clearCache(uint64_t messageIdentifier)
{
    if (messageIdentifier < m_lastHandledMessageIdentifier)
        return;

    m_lastHandledMessageIdentifier = messageIdentifier;
    resetValues();
}

static Vector<RefPtr<Frame>> framesForEventDispatching(Page& page, SecurityOrigin& origin, StorageType storageType, const std::optional<StorageAreaImplIdentifier>& storageAreaImplID)
{
    Vector<RefPtr<Frame>> frames;
    page.forEachDocument([&](auto& document) {
        if (!document.securityOrigin().equal(&origin))
            return;

        auto* window = document.domWindow();
        if (!window)
            return;
        
        Storage* storage = nullptr;
        switch (storageType) {
        case StorageType::Session:
            storage = window->optionalSessionStorage();
            break;
        case StorageType::Local:
        case StorageType::TransientLocal:
            storage = window->optionalLocalStorage();
            break;
        }

        if (!storage)
            return;
        
        auto& storageArea = static_cast<StorageAreaImpl&>(storage->area());
        if (storageArea.identifier() == storageAreaImplID) {
            // This is the storage area that caused the event to be dispatched.
            return;
        }
       
        if (auto* frame = document.frame()) 
            frames.append(frame);
    });
    return frames;
}

void StorageAreaMap::dispatchSessionStorageEvent(const std::optional<StorageAreaImplIdentifier>& storageAreaImplID, const String& key, const String& oldValue, const String& newValue, const String& urlString)
{
    // Namespace IDs for session storage namespaces are equivalent to web page IDs
    // so we can get the right page here.
    auto* webPage = WebProcess::singleton().webPage(m_namespace.sessionStoragePageID());
    if (!webPage)
        return;

    auto* page = webPage->corePage();
    if (!page)
        return;

    auto frames = framesForEventDispatching(*page, m_securityOrigin, StorageType::Session, storageAreaImplID);
    StorageEventDispatcher::dispatchSessionStorageEventsToFrames(*page, frames, key, oldValue, newValue, urlString, m_securityOrigin->data());
}

void StorageAreaMap::dispatchLocalStorageEvent(const std::optional<StorageAreaImplIdentifier>& storageAreaImplID, const String& key, const String& oldValue, const String& newValue, const String& urlString)
{
    ASSERT(isLocalStorage(type()));

    Vector<RefPtr<Frame>> frames;

    // Namespace IDs for local storage namespaces are currently equivalent to web page group IDs.
    auto& pageGroup = *WebProcess::singleton().webPageGroup(m_namespace.pageGroupID())->corePageGroup();
    for (auto& page : pageGroup.pages())
        frames.appendVector(framesForEventDispatching(page, m_securityOrigin, StorageType::Local, storageAreaImplID));

    StorageEventDispatcher::dispatchLocalStorageEventsToFrames(pageGroup, frames, key, oldValue, newValue, urlString, m_securityOrigin->data());
}

void StorageAreaMap::sendConnectMessage(SendMode mode)
{
    auto& ipcConnection = WebProcess::singleton().ensureNetworkProcessConnection().connection();
    auto namespaceIdentifier = m_namespace.storageNamespaceID();
    auto originData = m_securityOrigin->data();
    auto topOriginData = m_namespace.topLevelOrigin() ? m_namespace.topLevelOrigin()->data() : originData;
    auto origin = WebCore::ClientOrigin { topOriginData, originData };
    auto type = m_type;
    if ((type == StorageType::Local || type == StorageType::TransientLocal) && m_namespace.topLevelOrigin())
        type = StorageType::TransientLocal;

    if (mode == SendMode::Sync) {
        StorageAreaIdentifier remoteAreaIdentifier;
        HashMap<String, String> items;
        uint64_t messageIdentifier;
        ipcConnection.sendSync(Messages::NetworkStorageManager::ConnectToStorageAreaSync(type, m_identifier, namespaceIdentifier, origin), Messages::NetworkStorageManager::ConnectToStorageAreaSync::Reply(remoteAreaIdentifier, items, messageIdentifier), 0);
        didConnect(remoteAreaIdentifier, WTFMove(items), messageIdentifier);
        return;
    }

    auto completionHandler = [this, weakThis = WeakPtr { *this }, weakConnection = WeakPtr { ipcConnection }](auto remoteAreaIdentifier, auto items, auto messageIdentifier) mutable {
        if (weakThis)
            return didConnect(remoteAreaIdentifier, WTFMove(items), messageIdentifier);

        if (weakConnection && remoteAreaIdentifier.isValid())
            weakConnection->send(Messages::NetworkStorageManager::DisconnectFromStorageArea(remoteAreaIdentifier), 0);
    };

    ipcConnection.sendWithAsyncReply(Messages::NetworkStorageManager::ConnectToStorageArea(type, m_identifier, namespaceIdentifier, origin), WTFMove(completionHandler));
}

void StorageAreaMap::connectSync()
{
    if (m_remoteAreaIdentifier)
        return;

    sendConnectMessage(SendMode::Sync);
}

void StorageAreaMap::connect()
{
    if (m_remoteAreaIdentifier)
        return;

    sendConnectMessage(SendMode::Async);
}

void StorageAreaMap::didConnect(StorageAreaIdentifier remoteAreaIdentifier, HashMap<String, String>&& items, uint64_t messageIdentifier)
{
    if (messageIdentifier < m_lastHandledMessageIdentifier)
        return;

    m_lastHandledMessageIdentifier = messageIdentifier;
    if (!remoteAreaIdentifier.isValid())
        return;

    m_remoteAreaIdentifier = remoteAreaIdentifier;
    m_map = makeUnique<StorageMap>(m_quotaInBytes);
    m_map->importItems(WTFMove(items));
}

void StorageAreaMap::disconnect()
{
    if (!m_remoteAreaIdentifier)
        return;

    resetValues();

    if (auto* networkProcessConnection = WebProcess::singleton().existingNetworkProcessConnection())
        networkProcessConnection->connection().send(Messages::NetworkStorageManager::DisconnectFromStorageArea(*m_remoteAreaIdentifier), 0);

    m_remoteAreaIdentifier = { };
    m_lastHandledMessageIdentifier = 0;
}

void StorageAreaMap::incrementUseCount()
{
    ++m_useCount;
}

void StorageAreaMap::decrementUseCount()
{
    if (!--m_useCount)
        m_namespace.destroyStorageAreaMap(*this);
}

} // namespace WebKit
