/*
 * Copyright (C) 2017 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 "WebSWServerToContextConnection.h"

#if ENABLE(SERVICE_WORKER)

#include "FormDataReference.h"
#include "Logging.h"
#include "NetworkProcess.h"
#include "ServiceWorkerFetchTask.h"
#include "ServiceWorkerFetchTaskMessages.h"
#include "WebCoreArgumentCoders.h"
#include "WebSWContextManagerConnectionMessages.h"
#include "WebSWServerConnection.h"
#include <WebCore/SWServer.h>
#include <WebCore/ServiceWorkerContextData.h>

namespace WebKit {
using namespace WebCore;

WebSWServerToContextConnection::WebSWServerToContextConnection(NetworkProcess& networkProcess, RegistrableDomain&& registrableDomain, SWServer& server, Ref<IPC::Connection>&& connection)
    : SWServerToContextConnection(WTFMove(registrableDomain))
    , m_ipcConnection(WTFMove(connection))
    , m_networkProcess(networkProcess)
    , m_server(makeWeakPtr(server))
{
    server.addContextConnection(*this);
}

WebSWServerToContextConnection::~WebSWServerToContextConnection()
{
    connectionClosed();
    if (m_server && m_server->contextConnectionForRegistrableDomain(registrableDomain()) == this)
        m_server->removeContextConnection(*this);
}

IPC::Connection* WebSWServerToContextConnection::messageSenderConnection() const
{
    return m_ipcConnection.ptr();
}

uint64_t WebSWServerToContextConnection::messageSenderDestinationID() const
{
    return 0;
}

void WebSWServerToContextConnection::connectionClosed()
{
    auto fetches = WTFMove(m_ongoingFetches);
    for (auto& fetch : fetches.values())
        fetch->fail(ResourceError { errorDomainWebKitInternal, 0, { }, "Service Worker context closed"_s });
}

void WebSWServerToContextConnection::postMessageToServiceWorkerClient(const ServiceWorkerClientIdentifier& destinationIdentifier, const MessageWithMessagePorts& message, ServiceWorkerIdentifier sourceIdentifier, const String& sourceOrigin)
{
    if (!m_server)
        return;

    if (auto* connection = m_server->connection(destinationIdentifier.serverConnectionIdentifier))
        connection->postMessageToServiceWorkerClient(destinationIdentifier.contextIdentifier, message, sourceIdentifier, sourceOrigin);
}

void WebSWServerToContextConnection::installServiceWorkerContext(const ServiceWorkerContextData& data, const String& userAgent)
{
    send(Messages::WebSWContextManagerConnection::InstallServiceWorker { data, userAgent });
}

void WebSWServerToContextConnection::fireInstallEvent(ServiceWorkerIdentifier serviceWorkerIdentifier)
{
    send(Messages::WebSWContextManagerConnection::FireInstallEvent(serviceWorkerIdentifier));
}

void WebSWServerToContextConnection::fireActivateEvent(ServiceWorkerIdentifier serviceWorkerIdentifier)
{
    send(Messages::WebSWContextManagerConnection::FireActivateEvent(serviceWorkerIdentifier));
}

void WebSWServerToContextConnection::softUpdate(ServiceWorkerIdentifier serviceWorkerIdentifier)
{
    send(Messages::WebSWContextManagerConnection::SoftUpdate(serviceWorkerIdentifier));
}

void WebSWServerToContextConnection::terminateWorker(ServiceWorkerIdentifier serviceWorkerIdentifier)
{
    send(Messages::WebSWContextManagerConnection::TerminateWorker(serviceWorkerIdentifier));
}

void WebSWServerToContextConnection::syncTerminateWorker(ServiceWorkerIdentifier serviceWorkerIdentifier)
{
    sendSync(Messages::WebSWContextManagerConnection::SyncTerminateWorker(serviceWorkerIdentifier), Messages::WebSWContextManagerConnection::SyncTerminateWorker::Reply());
}

void WebSWServerToContextConnection::findClientByIdentifierCompleted(uint64_t requestIdentifier, const Optional<ServiceWorkerClientData>& data, bool hasSecurityError)
{
    send(Messages::WebSWContextManagerConnection::FindClientByIdentifierCompleted { requestIdentifier, data, hasSecurityError });
}

void WebSWServerToContextConnection::matchAllCompleted(uint64_t requestIdentifier, const Vector<ServiceWorkerClientData>& clientsData)
{
    send(Messages::WebSWContextManagerConnection::MatchAllCompleted { requestIdentifier, clientsData });
}

void WebSWServerToContextConnection::claimCompleted(uint64_t requestIdentifier)
{
    send(Messages::WebSWContextManagerConnection::ClaimCompleted { requestIdentifier });
}

void WebSWServerToContextConnection::didFinishSkipWaiting(uint64_t callbackID)
{
    send(Messages::WebSWContextManagerConnection::DidFinishSkipWaiting { callbackID });
}

void WebSWServerToContextConnection::connectionIsNoLongerNeeded()
{
    RELEASE_LOG(ServiceWorker, "Service worker process is no longer needed, terminating it");
    terminate();
    connectionClosed();
}

void WebSWServerToContextConnection::setThrottleState(bool isThrottleable)
{
    m_isThrottleable = isThrottleable;
    send(Messages::WebSWContextManagerConnection::SetThrottleState { isThrottleable });
}

void WebSWServerToContextConnection::terminate()
{
    send(Messages::WebSWContextManagerConnection::TerminateProcess());
}

void WebSWServerToContextConnection::startFetch(PAL::SessionID sessionID, WebSWServerConnection& contentConnection, FetchIdentifier contentFetchIdentifier, ServiceWorkerIdentifier serviceWorkerIdentifier, const ResourceRequest& request, const FetchOptions& options, const IPC::FormDataReference& data, const String& referrer)
{
    auto serverConnectionIdentifier = contentConnection.identifier();
    auto fetchIdentifier = FetchIdentifier::generate();

    auto result = m_ongoingFetches.add(fetchIdentifier, makeUnique<ServiceWorkerFetchTask>(sessionID, contentConnection, *this, contentFetchIdentifier, serviceWorkerIdentifier, m_networkProcess->serviceWorkerFetchTimeout()));

    ASSERT(!m_ongoingFetchIdentifiers.contains({ serverConnectionIdentifier, contentFetchIdentifier }));
    m_ongoingFetchIdentifiers.add({ serverConnectionIdentifier, contentFetchIdentifier }, fetchIdentifier);

    if (!send(Messages::WebSWContextManagerConnection::StartFetch { serverConnectionIdentifier, serviceWorkerIdentifier, fetchIdentifier, request, options, data, referrer }))
        result.iterator->value->didNotHandle();
}

void WebSWServerToContextConnection::cancelFetch(WebCore::SWServerConnectionIdentifier serverConnectionIdentifier, FetchIdentifier contentFetchIdentifier, ServiceWorkerIdentifier serviceWorkerIdentifier)
{
    auto iterator = m_ongoingFetchIdentifiers.find({ serverConnectionIdentifier, contentFetchIdentifier });
    if (iterator == m_ongoingFetchIdentifiers.end())
        return;

    send(Messages::WebSWContextManagerConnection::CancelFetch { serverConnectionIdentifier, serviceWorkerIdentifier, iterator->value });

    m_ongoingFetches.remove(iterator->value);
    m_ongoingFetchIdentifiers.remove(iterator);
}

void WebSWServerToContextConnection::continueDidReceiveFetchResponse(WebCore::SWServerConnectionIdentifier serverConnectionIdentifier, FetchIdentifier contentFetchIdentifier, ServiceWorkerIdentifier serviceWorkerIdentifier)
{
    auto iterator = m_ongoingFetchIdentifiers.find({ serverConnectionIdentifier, contentFetchIdentifier });
    if (iterator == m_ongoingFetchIdentifiers.end())
        return;
    
    send(Messages::WebSWContextManagerConnection::ContinueDidReceiveFetchResponse { serverConnectionIdentifier, serviceWorkerIdentifier, iterator->value });
}

void WebSWServerToContextConnection::didReceiveFetchTaskMessage(IPC::Connection& connection, IPC::Decoder& decoder)
{
    auto iterator = m_ongoingFetches.find(makeObjectIdentifier<FetchIdentifierType>(decoder.destinationID()));
    if (iterator == m_ongoingFetches.end())
        return;
    
    bool shouldRemove = decoder.messageName() == Messages::ServiceWorkerFetchTask::DidFail::name()
        || decoder.messageName() == Messages::ServiceWorkerFetchTask::DidNotHandle::name()
        || decoder.messageName() == Messages::ServiceWorkerFetchTask::DidFinish::name()
        || decoder.messageName() == Messages::ServiceWorkerFetchTask::DidReceiveRedirectResponse::name();

    iterator->value->didReceiveMessage(connection, decoder);

    if (shouldRemove) {
        ASSERT(m_ongoingFetchIdentifiers.contains(iterator->value->identifier()));
        m_ongoingFetchIdentifiers.remove(iterator->value->identifier());
        m_ongoingFetches.remove(iterator);
    }
}

void WebSWServerToContextConnection::fetchTaskTimedOut(ServiceWorkerFetchTask& task)
{
    ASSERT(m_ongoingFetchIdentifiers.contains(task.identifier()));
    auto takenIdentifier = m_ongoingFetchIdentifiers.take(task.identifier());

    ASSERT(m_ongoingFetches.contains(takenIdentifier));
    auto takenTask = m_ongoingFetches.take(takenIdentifier);
    ASSERT(takenTask);
    ASSERT(takenTask.get() == &task);

    // Gather all other fetches in this service worker
    Vector<ServiceWorkerFetchTask*> otherFetches;
    for (auto& fetchTask : m_ongoingFetches.values()) {
        if (fetchTask->serviceWorkerIdentifier() == task.serviceWorkerIdentifier())
            otherFetches.append(fetchTask.get());
    }

    // Signal load failure for them
    for (auto* fetchTask : otherFetches) {
        if (fetchTask->wasHandled())
            fetchTask->fail({ errorDomainWebKitInternal, 0, { }, "Service Worker context closed"_s });
        else
            fetchTask->didNotHandle();

        auto identifier = m_ongoingFetchIdentifiers.take(fetchTask->identifier());
        m_ongoingFetches.remove(identifier);
    }

    if (m_server) {
        if (auto* worker = m_server->workerByID(task.serviceWorkerIdentifier())) {
            worker->setHasTimedOutAnyFetchTasks();
            if (worker->isRunning())
                m_server->syncTerminateWorker(*worker);
        }
    }
}

} // namespace WebKit

#endif // ENABLE(SERVICE_WORKER)
