blob: 472a23139f768b0913c6ac14419f7d8bdf242eae [file] [log] [blame]
/*
* 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 "WebSWServerConnection.h"
#if ENABLE(SERVICE_WORKER)
#include "DataReference.h"
#include "FormDataReference.h"
#include "Logging.h"
#include "NetworkConnectionToWebProcessMessages.h"
#include "NetworkProcess.h"
#include "NetworkProcessProxyMessages.h"
#include "NetworkResourceLoader.h"
#include "NetworkSession.h"
#include "WebCoreArgumentCoders.h"
#include "WebProcess.h"
#include "WebProcessMessages.h"
#include "WebResourceLoaderMessages.h"
#include "WebSWClientConnectionMessages.h"
#include "WebSWContextManagerConnectionMessages.h"
#include "WebSWServerConnectionMessages.h"
#include "WebSWServerToContextConnection.h"
#include <WebCore/ExceptionData.h>
#include <WebCore/LegacySchemeRegistry.h>
#include <WebCore/NotImplemented.h>
#include <WebCore/SWServerRegistration.h>
#include <WebCore/ScriptExecutionContextIdentifier.h>
#include <WebCore/SecurityOrigin.h>
#include <WebCore/ServiceWorkerClientData.h>
#include <WebCore/ServiceWorkerContextData.h>
#include <WebCore/ServiceWorkerJobData.h>
#include <WebCore/ServiceWorkerUpdateViaCache.h>
#include <cstdint>
#include <wtf/Algorithms.h>
#include <wtf/MainThread.h>
namespace WebKit {
using namespace PAL;
using namespace WebCore;
#define SWSERVERCONNECTION_RELEASE_LOG(fmt, ...) RELEASE_LOG(ServiceWorker, "%p - WebSWServerConnection::" fmt, this, ##__VA_ARGS__)
#define SWSERVERCONNECTION_RELEASE_LOG_ERROR(fmt, ...) RELEASE_LOG_ERROR(ServiceWorker, "%p - WebSWServerConnection::" fmt, this, ##__VA_ARGS__)
WebSWServerConnection::WebSWServerConnection(NetworkProcess& networkProcess, SWServer& server, IPC::Connection& connection, ProcessIdentifier processIdentifier)
: SWServer::Connection(server, processIdentifier)
, m_contentConnection(connection)
, m_networkProcess(networkProcess)
{
if (auto* session = this->session())
session->registerSWServerConnection(*this);
}
WebSWServerConnection::~WebSWServerConnection()
{
if (auto* session = this->session())
session->unregisterSWServerConnection(*this);
for (const auto& keyValue : m_clientOrigins)
server().unregisterServiceWorkerClient(keyValue.value, keyValue.key);
for (auto& completionHandler : m_unregisterJobs.values())
completionHandler(false);
}
void WebSWServerConnection::rejectJobInClient(ServiceWorkerJobIdentifier jobIdentifier, const ExceptionData& exceptionData)
{
if (auto completionHandler = m_unregisterJobs.take(jobIdentifier))
return completionHandler(makeUnexpected(exceptionData));
send(Messages::WebSWClientConnection::JobRejectedInServer(jobIdentifier, exceptionData));
}
void WebSWServerConnection::resolveRegistrationJobInClient(ServiceWorkerJobIdentifier jobIdentifier, const ServiceWorkerRegistrationData& registrationData, ShouldNotifyWhenResolved shouldNotifyWhenResolved)
{
send(Messages::WebSWClientConnection::RegistrationJobResolvedInServer(jobIdentifier, registrationData, shouldNotifyWhenResolved));
}
void WebSWServerConnection::resolveUnregistrationJobInClient(ServiceWorkerJobIdentifier jobIdentifier, const ServiceWorkerRegistrationKey& registrationKey, bool unregistrationResult)
{
ASSERT(m_unregisterJobs.contains(jobIdentifier));
if (auto completionHandler = m_unregisterJobs.take(jobIdentifier))
completionHandler(unregistrationResult);
}
void WebSWServerConnection::startScriptFetchInClient(ServiceWorkerJobIdentifier jobIdentifier, const ServiceWorkerRegistrationKey& registrationKey, FetchOptions::Cache cachePolicy)
{
send(Messages::WebSWClientConnection::StartScriptFetchForServer(jobIdentifier, registrationKey, cachePolicy));
}
void WebSWServerConnection::updateRegistrationStateInClient(ServiceWorkerRegistrationIdentifier identifier, ServiceWorkerRegistrationState state, const std::optional<ServiceWorkerData>& serviceWorkerData)
{
send(Messages::WebSWClientConnection::UpdateRegistrationState(identifier, state, serviceWorkerData));
}
void WebSWServerConnection::fireUpdateFoundEvent(ServiceWorkerRegistrationIdentifier identifier)
{
send(Messages::WebSWClientConnection::FireUpdateFoundEvent(identifier));
}
void WebSWServerConnection::setRegistrationLastUpdateTime(ServiceWorkerRegistrationIdentifier identifier, WallTime lastUpdateTime)
{
send(Messages::WebSWClientConnection::SetRegistrationLastUpdateTime(identifier, lastUpdateTime));
}
void WebSWServerConnection::setRegistrationUpdateViaCache(ServiceWorkerRegistrationIdentifier identifier, ServiceWorkerUpdateViaCache updateViaCache)
{
send(Messages::WebSWClientConnection::SetRegistrationUpdateViaCache(identifier, updateViaCache));
}
void WebSWServerConnection::notifyClientsOfControllerChange(const HashSet<ScriptExecutionContextIdentifier>& contextIdentifiers, const ServiceWorkerData& newController)
{
send(Messages::WebSWClientConnection::NotifyClientsOfControllerChange(contextIdentifiers, newController));
}
void WebSWServerConnection::updateWorkerStateInClient(ServiceWorkerIdentifier worker, ServiceWorkerState state)
{
send(Messages::WebSWClientConnection::UpdateWorkerState(worker, state));
}
void WebSWServerConnection::controlClient(ScriptExecutionContextIdentifier clientIdentifier, SWServerRegistration& registration, const ResourceRequest& request)
{
// As per step 12 of https://w3c.github.io/ServiceWorker/#on-fetch-request-algorithm, the active service worker should be controlling the document.
// We register a temporary service worker client using the identifier provided by DocumentLoader and notify DocumentLoader about it.
// If notification is successful, DocumentLoader will unregister the temporary service worker client just after the document is created and registered as a client.
sendWithAsyncReply(Messages::WebSWClientConnection::SetDocumentIsControlled { clientIdentifier, registration.data() }, [weakThis = WeakPtr { *this }, this, clientIdentifier](bool isSuccess) {
if (!weakThis || isSuccess)
return;
unregisterServiceWorkerClient(clientIdentifier);
});
ServiceWorkerClientData data { clientIdentifier, ServiceWorkerClientType::Window, ServiceWorkerClientFrameType::None, request.url(), request.isAppInitiated() ? WebCore::LastNavigationWasAppInitiated::Yes : WebCore::LastNavigationWasAppInitiated::No };
registerServiceWorkerClient(SecurityOriginData { registration.key().topOrigin() }, WTFMove(data), registration.identifier(), request.httpUserAgent());
}
std::unique_ptr<ServiceWorkerFetchTask> WebSWServerConnection::createFetchTask(NetworkResourceLoader& loader, const ResourceRequest& request)
{
if (loader.parameters().serviceWorkersMode == ServiceWorkersMode::None) {
if (loader.parameters().request.requester() == ResourceRequest::Requester::Fetch && isNavigationRequest(loader.parameters().options.destination)) {
if (auto task = ServiceWorkerFetchTask::fromNavigationPreloader(*this, loader, request, session()))
return task;
}
return nullptr;
}
if (!server().canHandleScheme(loader.originalRequest().url().protocol()))
return nullptr;
std::optional<ServiceWorkerRegistrationIdentifier> serviceWorkerRegistrationIdentifier;
if (loader.parameters().options.mode == FetchOptions::Mode::Navigate) {
auto topOrigin = loader.parameters().isMainFrameNavigation ? SecurityOriginData::fromURL(request.url()) : loader.parameters().topOrigin->data();
auto* registration = doRegistrationMatching(topOrigin, request.url());
if (!registration)
return nullptr;
serviceWorkerRegistrationIdentifier = registration->identifier();
controlClient(*loader.parameters().options.clientIdentifier, *registration, request);
} else {
if (!loader.parameters().serviceWorkerRegistrationIdentifier)
return nullptr;
if (isPotentialNavigationOrSubresourceRequest(loader.parameters().options.destination))
return nullptr;
serviceWorkerRegistrationIdentifier = *loader.parameters().serviceWorkerRegistrationIdentifier;
}
auto* registration = server().getRegistration(*serviceWorkerRegistrationIdentifier);
auto* worker = registration ? registration->activeWorker() : nullptr;
if (!worker) {
SWSERVERCONNECTION_RELEASE_LOG_ERROR("startFetch: DidNotHandle because no active worker for registration %" PRIu64, serviceWorkerRegistrationIdentifier->toUInt64());
return nullptr;
}
if (worker->shouldSkipFetchEvent()) {
if (registration->shouldSoftUpdate(loader.parameters().options))
registration->scheduleSoftUpdate(loader.isAppInitiated() ? WebCore::IsAppInitiated::Yes : WebCore::IsAppInitiated::No);
return nullptr;
}
if (worker->hasTimedOutAnyFetchTasks()) {
SWSERVERCONNECTION_RELEASE_LOG_ERROR("startFetch: DidNotHandle because worker %" PRIu64 " has some timeouts", worker->identifier().toUInt64());
return nullptr;
}
bool isWorkerReady = worker->isRunning() && worker->state() == ServiceWorkerState::Activated;
auto task = makeUnique<ServiceWorkerFetchTask>(*this, loader, ResourceRequest { request }, identifier(), worker->identifier(), *registration, session(), isWorkerReady);
startFetch(*task, *worker);
return task;
}
void WebSWServerConnection::startFetch(ServiceWorkerFetchTask& task, SWServerWorker& worker)
{
auto runServerWorkerAndStartFetch = [weakThis = WeakPtr { *this }, this, task = WeakPtr { task }](bool success) mutable {
if (!task)
return;
if (!weakThis) {
task->cannotHandle();
return;
}
if (!success) {
SWSERVERCONNECTION_RELEASE_LOG_ERROR("startFetch: fetchIdentifier=%" PRIu64 " DidNotHandle because worker did not become activated", task->fetchIdentifier().toUInt64());
task->cannotHandle();
return;
}
auto* worker = server().workerByID(task->serviceWorkerIdentifier());
if (!worker || worker->hasTimedOutAnyFetchTasks()) {
task->cannotHandle();
return;
}
if (!worker->contextConnection())
server().createContextConnection(worker->registrableDomain(), worker->serviceWorkerPageIdentifier());
auto identifier = task->serviceWorkerIdentifier();
server().runServiceWorkerIfNecessary(identifier, [weakThis = WTFMove(weakThis), this, task = WTFMove(task)](auto* contextConnection) mutable {
if (!task)
return;
if (!weakThis) {
task->cannotHandle();
return;
}
if (!contextConnection) {
SWSERVERCONNECTION_RELEASE_LOG_ERROR("startFetch: fetchIdentifier=%s DidNotHandle because failed to run service worker", task->fetchIdentifier().loggingString().utf8().data());
task->cannotHandle();
return;
}
SWSERVERCONNECTION_RELEASE_LOG("startFetch: Starting fetch %" PRIu64 " via service worker %" PRIu64, task->fetchIdentifier().toUInt64(), task->serviceWorkerIdentifier().toUInt64());
static_cast<WebSWServerToContextConnection&>(*contextConnection).startFetch(*task);
});
};
worker.whenActivated(WTFMove(runServerWorkerAndStartFetch));
}
void WebSWServerConnection::postMessageToServiceWorker(ServiceWorkerIdentifier destinationIdentifier, MessageWithMessagePorts&& message, const ServiceWorkerOrClientIdentifier& sourceIdentifier)
{
auto* destinationWorker = server().workerByID(destinationIdentifier);
if (!destinationWorker)
return;
std::optional<ServiceWorkerOrClientData> sourceData;
WTF::switchOn(sourceIdentifier, [&](ServiceWorkerIdentifier identifier) {
if (auto* sourceWorker = server().workerByID(identifier))
sourceData = ServiceWorkerOrClientData { sourceWorker->data() };
}, [&](ScriptExecutionContextIdentifier identifier) {
if (auto clientData = destinationWorker->findClientByIdentifier(identifier))
sourceData = ServiceWorkerOrClientData { *clientData };
});
if (!sourceData)
return;
// It's possible this specific worker cannot be re-run (e.g. its registration has been removed)
server().runServiceWorkerIfNecessary(destinationIdentifier, [destinationIdentifier, message = WTFMove(message), sourceData = WTFMove(*sourceData)](auto* contextConnection) mutable {
if (contextConnection)
sendToContextProcess(*contextConnection, Messages::WebSWContextManagerConnection::PostMessageToServiceWorker { destinationIdentifier, WTFMove(message), WTFMove(sourceData) });
});
}
void WebSWServerConnection::scheduleJobInServer(ServiceWorkerJobData&& jobData)
{
ASSERT(!jobData.scopeURL.isNull());
if (jobData.scopeURL.isNull()) {
rejectJobInClient(jobData.identifier().jobIdentifier, ExceptionData { InvalidStateError, "Scope URL is empty"_s });
return;
}
SWSERVERCONNECTION_RELEASE_LOG("Scheduling ServiceWorker job %s in server", jobData.identifier().loggingString().utf8().data());
ASSERT(identifier() == jobData.connectionIdentifier());
server().scheduleJob(WTFMove(jobData));
}
URL WebSWServerConnection::clientURLFromIdentifier(ServiceWorkerOrClientIdentifier contextIdentifier)
{
return WTF::switchOn(contextIdentifier, [&](ScriptExecutionContextIdentifier clientIdentifier) -> URL {
auto iterator = m_clientOrigins.find(clientIdentifier);
if (iterator == m_clientOrigins.end())
return { };
auto clientData = server().serviceWorkerClientWithOriginByID(iterator->value, clientIdentifier);
if (!clientData)
return { };
return clientData->url;
}, [&](ServiceWorkerIdentifier serviceWorkerIdentifier) -> URL {
auto* worker = server().workerByID(serviceWorkerIdentifier);
if (!worker)
return { };
return worker->data().scriptURL;
});
}
void WebSWServerConnection::scheduleUnregisterJobInServer(ServiceWorkerJobIdentifier jobIdentifier, ServiceWorkerRegistrationIdentifier registrationIdentifier, ServiceWorkerOrClientIdentifier contextIdentifier, CompletionHandler<void(UnregisterJobResult&&)>&& completionHandler)
{
SWSERVERCONNECTION_RELEASE_LOG("Scheduling unregister ServiceWorker job in server");
auto* registration = server().getRegistration(registrationIdentifier);
if (!registration)
return completionHandler(false);
auto clientURL = clientURLFromIdentifier(contextIdentifier);
if (!clientURL.isValid())
return completionHandler(makeUnexpected(ExceptionData { InvalidStateError, "Client is unknown"_s }));
ASSERT(!m_unregisterJobs.contains(jobIdentifier));
m_unregisterJobs.add(jobIdentifier, WTFMove(completionHandler));
server().scheduleUnregisterJob(ServiceWorkerJobDataIdentifier { identifier(), jobIdentifier }, *registration, contextIdentifier, WTFMove(clientURL));
}
void WebSWServerConnection::postMessageToServiceWorkerClient(ScriptExecutionContextIdentifier destinationContextIdentifier, const MessageWithMessagePorts& message, ServiceWorkerIdentifier sourceIdentifier, const String& sourceOrigin)
{
auto* sourceServiceWorker = server().workerByID(sourceIdentifier);
if (!sourceServiceWorker)
return;
send(Messages::WebSWClientConnection::PostMessageToServiceWorkerClient { destinationContextIdentifier, message, sourceServiceWorker->data(), sourceOrigin });
}
void WebSWServerConnection::matchRegistration(const SecurityOriginData& topOrigin, const URL& clientURL, CompletionHandler<void(std::optional<ServiceWorkerRegistrationData>&&)>&& callback)
{
if (auto* registration = doRegistrationMatching(topOrigin, clientURL)) {
callback(registration->data());
return;
}
callback({ });
}
void WebSWServerConnection::getRegistrations(const SecurityOriginData& topOrigin, const URL& clientURL, CompletionHandler<void(const Vector<ServiceWorkerRegistrationData>&)>&& callback)
{
callback(server().getRegistrations(topOrigin, clientURL));
}
void WebSWServerConnection::registerServiceWorkerClient(SecurityOriginData&& topOrigin, ServiceWorkerClientData&& data, const std::optional<ServiceWorkerRegistrationIdentifier>& controllingServiceWorkerRegistrationIdentifier, String&& userAgent)
{
auto contextOrigin = SecurityOriginData::fromURL(data.url);
bool isNewOrigin = WTF::allOf(m_clientOrigins.values(), [&contextOrigin](auto& origin) {
return contextOrigin != origin.clientOrigin;
});
auto* contextConnection = isNewOrigin ? server().contextConnectionForRegistrableDomain(RegistrableDomain { contextOrigin }) : nullptr;
auto clientOrigin = ClientOrigin { WTFMove(topOrigin), WTFMove(contextOrigin) };
m_clientOrigins.add(data.identifier, clientOrigin);
server().registerServiceWorkerClient(WTFMove(clientOrigin), WTFMove(data), controllingServiceWorkerRegistrationIdentifier, WTFMove(userAgent));
if (!m_isThrottleable)
updateThrottleState();
if (contextConnection) {
auto& connection = static_cast<WebSWServerToContextConnection&>(*contextConnection);
m_networkProcess->parentProcessConnection()->send(Messages::NetworkProcessProxy::RegisterServiceWorkerClientProcess { identifier(), connection.webProcessIdentifier() }, 0);
}
}
void WebSWServerConnection::unregisterServiceWorkerClient(const ScriptExecutionContextIdentifier& clientIdentifier)
{
auto iterator = m_clientOrigins.find(clientIdentifier);
if (iterator == m_clientOrigins.end())
return;
auto clientOrigin = iterator->value;
server().unregisterServiceWorkerClient(clientOrigin, clientIdentifier);
m_clientOrigins.remove(iterator);
if (!m_isThrottleable)
updateThrottleState();
bool isDeletedOrigin = WTF::allOf(m_clientOrigins.values(), [&clientOrigin](auto& origin) {
return clientOrigin.clientOrigin != origin.clientOrigin;
});
if (isDeletedOrigin) {
if (auto* contextConnection = server().contextConnectionForRegistrableDomain(RegistrableDomain { clientOrigin.clientOrigin })) {
auto& connection = static_cast<WebSWServerToContextConnection&>(*contextConnection);
m_networkProcess->parentProcessConnection()->send(Messages::NetworkProcessProxy::UnregisterServiceWorkerClientProcess { identifier(), connection.webProcessIdentifier() }, 0);
}
}
}
bool WebSWServerConnection::hasMatchingClient(const RegistrableDomain& domain) const
{
return WTF::anyOf(m_clientOrigins.values(), [&domain](auto& origin) {
return domain.matches(origin.clientOrigin);
});
}
bool WebSWServerConnection::computeThrottleState(const RegistrableDomain& domain) const
{
return WTF::allOf(server().connections().values(), [&domain](auto& serverConnection) {
auto& connection = static_cast<WebSWServerConnection&>(*serverConnection);
return connection.isThrottleable() || !connection.hasMatchingClient(domain);
});
}
void WebSWServerConnection::setThrottleState(bool isThrottleable)
{
m_isThrottleable = isThrottleable;
updateThrottleState();
}
void WebSWServerConnection::updateThrottleState()
{
HashSet<SecurityOriginData> origins;
for (auto& origin : m_clientOrigins.values())
origins.add(origin.clientOrigin);
for (auto& origin : origins) {
if (auto* contextConnection = server().contextConnectionForRegistrableDomain(RegistrableDomain { origin })) {
auto& connection = static_cast<WebSWServerToContextConnection&>(*contextConnection);
if (connection.isThrottleable() == m_isThrottleable)
continue;
bool newThrottleState = computeThrottleState(connection.registrableDomain());
if (connection.isThrottleable() == newThrottleState)
continue;
connection.setThrottleState(newThrottleState);
}
}
}
void WebSWServerConnection::subscribeToPushService(WebCore::ServiceWorkerRegistrationIdentifier registrationIdentifier, Vector<uint8_t>&& applicationServerKey, CompletionHandler<void(Expected<PushSubscriptionData, ExceptionData>&&)>&& completionHandler)
{
UNUSED_PARAM(registrationIdentifier);
UNUSED_PARAM(applicationServerKey);
completionHandler(makeUnexpected(ExceptionData { NotAllowedError, "Push permission was denied"_s }));
}
void WebSWServerConnection::unsubscribeFromPushService(WebCore::ServiceWorkerRegistrationIdentifier registrationIdentifier, CompletionHandler<void(Expected<bool, ExceptionData>&&)>&& completionHandler)
{
UNUSED_PARAM(registrationIdentifier);
completionHandler(false);
}
void WebSWServerConnection::getPushSubscription(WebCore::ServiceWorkerRegistrationIdentifier registrationIdentifier, CompletionHandler<void(Expected<std::optional<PushSubscriptionData>, ExceptionData>&&)>&& completionHandler)
{
UNUSED_PARAM(registrationIdentifier);
completionHandler(std::optional<PushSubscriptionData>(std::nullopt));
}
void WebSWServerConnection::getPushPermissionState(WebCore::ServiceWorkerRegistrationIdentifier registrationIdentifier, CompletionHandler<void(Expected<uint8_t, ExceptionData>&&)>&& completionHandler)
{
UNUSED_PARAM(registrationIdentifier);
completionHandler(static_cast<uint8_t>(PushPermissionState::Denied));
}
void WebSWServerConnection::contextConnectionCreated(SWServerToContextConnection& contextConnection)
{
auto& connection = static_cast<WebSWServerToContextConnection&>(contextConnection);
connection.setThrottleState(computeThrottleState(connection.registrableDomain()));
if (hasMatchingClient(connection.registrableDomain()))
m_networkProcess->parentProcessConnection()->send(Messages::NetworkProcessProxy::RegisterServiceWorkerClientProcess { identifier(), connection.webProcessIdentifier() }, 0);
}
void WebSWServerConnection::terminateWorkerFromClient(ServiceWorkerIdentifier serviceWorkerIdentifier, CompletionHandler<void()>&& callback)
{
auto* worker = server().workerByID(serviceWorkerIdentifier);
if (!worker)
return callback();
worker->terminate(WTFMove(callback));
}
void WebSWServerConnection::whenServiceWorkerIsTerminatedForTesting(WebCore::ServiceWorkerIdentifier identifier, CompletionHandler<void()>&& completionHandler)
{
auto* worker = SWServerWorker::existingWorkerForIdentifier(identifier);
if (!worker || worker->isNotRunning())
return completionHandler();
worker->whenTerminated(WTFMove(completionHandler));
}
PAL::SessionID WebSWServerConnection::sessionID() const
{
return server().sessionID();
}
NetworkSession* WebSWServerConnection::session()
{
return m_networkProcess->networkSession(sessionID());
}
template<typename U> void WebSWServerConnection::sendToContextProcess(WebCore::SWServerToContextConnection& connection, U&& message)
{
static_cast<WebSWServerToContextConnection&>(connection).send(WTFMove(message));
}
void WebSWServerConnection::fetchTaskTimedOut(ServiceWorkerIdentifier serviceWorkerIdentifier)
{
auto* worker = server().workerByID(serviceWorkerIdentifier);
if (!worker)
return;
worker->setHasTimedOutAnyFetchTasks();
worker->terminate();
}
void WebSWServerConnection::enableNavigationPreload(WebCore::ServiceWorkerRegistrationIdentifier registrationIdentifier, ExceptionOrVoidCallback&& callback)
{
auto* registration = server().getRegistration(registrationIdentifier);
if (!registration) {
callback(ExceptionData { InvalidStateError, "No registration"_s });
return;
}
callback(registration->enableNavigationPreload());
}
void WebSWServerConnection::disableNavigationPreload(WebCore::ServiceWorkerRegistrationIdentifier registrationIdentifier, ExceptionOrVoidCallback&& callback)
{
auto* registration = server().getRegistration(registrationIdentifier);
if (!registration) {
callback(ExceptionData { InvalidStateError, "No registration"_s });
return;
}
callback(registration->disableNavigationPreload());
}
void WebSWServerConnection::setNavigationPreloadHeaderValue(WebCore::ServiceWorkerRegistrationIdentifier registrationIdentifier, String&& headerValue, ExceptionOrVoidCallback&& callback)
{
auto* registration = server().getRegistration(registrationIdentifier);
if (!registration) {
callback(ExceptionData { InvalidStateError, "No registration"_s });
return;
}
callback(registration->setNavigationPreloadHeaderValue(WTFMove(headerValue)));
}
void WebSWServerConnection::getNavigationPreloadState(WebCore::ServiceWorkerRegistrationIdentifier registrationIdentifier, ExceptionOrNavigationPreloadStateCallback&& callback)
{
auto* registration = server().getRegistration(registrationIdentifier);
if (!registration) {
callback(makeUnexpected(ExceptionData { InvalidStateError, { } }));
return;
}
callback(registration->navigationPreloadState());
}
} // namespace WebKit
#undef SWSERVERCONNECTION_RELEASE_LOG
#undef SWSERVERCONNECTION_RELEASE_LOG_ERROR
#endif // ENABLE(SERVICE_WORKER)