ServiceWorkerJob.cpp [plain text]
#include "config.h"
#include "ServiceWorkerJob.h"
#if ENABLE(SERVICE_WORKER)
#include "HTTPHeaderNames.h"
#include "JSDOMPromiseDeferred.h"
#include "MIMETypeRegistry.h"
#include "ResourceError.h"
#include "ResourceResponse.h"
#include "ServiceWorkerJobData.h"
#include "ServiceWorkerRegistration.h"
namespace WebCore {
ServiceWorkerJob::ServiceWorkerJob(ServiceWorkerJobClient& client, RefPtr<DeferredPromise>&& promise, ServiceWorkerJobData&& jobData)
: m_client(client)
, m_jobData(WTFMove(jobData))
, m_promise(WTFMove(promise))
, m_contextIdentifier(client.contextIdentifier())
{
}
ServiceWorkerJob::~ServiceWorkerJob()
{
ASSERT(m_creationThread.ptr() == &Thread::current());
}
void ServiceWorkerJob::failedWithException(const Exception& exception)
{
ASSERT(m_creationThread.ptr() == &Thread::current());
ASSERT(!m_completed);
m_completed = true;
m_client->jobFailedWithException(*this, exception);
}
void ServiceWorkerJob::resolvedWithRegistration(ServiceWorkerRegistrationData&& data, ShouldNotifyWhenResolved shouldNotifyWhenResolved)
{
ASSERT(m_creationThread.ptr() == &Thread::current());
ASSERT(!m_completed);
m_completed = true;
m_client->jobResolvedWithRegistration(*this, WTFMove(data), shouldNotifyWhenResolved);
}
void ServiceWorkerJob::resolvedWithUnregistrationResult(bool unregistrationResult)
{
ASSERT(m_creationThread.ptr() == &Thread::current());
ASSERT(!m_completed);
m_completed = true;
m_client->jobResolvedWithUnregistrationResult(*this, unregistrationResult);
}
void ServiceWorkerJob::startScriptFetch(FetchOptions::Cache cachePolicy)
{
ASSERT(m_creationThread.ptr() == &Thread::current());
ASSERT(!m_completed);
m_client->startScriptFetchForJob(*this, cachePolicy);
}
void ServiceWorkerJob::fetchScriptWithContext(ScriptExecutionContext& context, FetchOptions::Cache cachePolicy)
{
ASSERT(m_creationThread.ptr() == &Thread::current());
ASSERT(!m_completed);
m_scriptLoader = WorkerScriptLoader::create();
ResourceRequest request { m_jobData.scriptURL };
request.setInitiatorIdentifier("serviceWorkerScriptLoad:");
request.addHTTPHeaderField("Service-Worker"_s, "script"_s);
FetchOptions options;
options.mode = FetchOptions::Mode::SameOrigin;
options.cache = cachePolicy;
options.redirect = FetchOptions::Redirect::Error;
options.destination = FetchOptions::Destination::Serviceworker;
m_scriptLoader->loadAsynchronously(context, WTFMove(request), WTFMove(options), ContentSecurityPolicyEnforcement::DoNotEnforce, ServiceWorkersMode::None, *this);
}
void ServiceWorkerJob::didReceiveResponse(unsigned long, const ResourceResponse& response)
{
ASSERT(m_creationThread.ptr() == &Thread::current());
ASSERT(!m_completed);
ASSERT(m_scriptLoader);
if (!MIMETypeRegistry::isSupportedJavaScriptMIMEType(response.mimeType())) {
Exception exception { SecurityError, "MIME Type is not a JavaScript MIME type"_s };
ResourceError error { errorDomainWebKitInternal, 0, response.url(), "Unexpected MIME type"_s };
m_client->jobFailedLoadingScript(*this, WTFMove(error), WTFMove(exception));
m_scriptLoader = nullptr;
}
String serviceWorkerAllowed = response.httpHeaderField(HTTPHeaderName::ServiceWorkerAllowed);
String maxScopeString;
if (serviceWorkerAllowed.isNull()) {
String path = m_jobData.scriptURL.path();
maxScopeString = path.substring(0, path.reverseFind('/') + 1);
} else {
auto maxScope = URL(m_jobData.scriptURL, serviceWorkerAllowed);
maxScopeString = maxScope.path();
}
String scopeString = m_jobData.scopeURL.path();
if (!scopeString.startsWith(maxScopeString)) {
Exception exception { SecurityError, "Scope URL should start with the given script URL"_s };
ResourceError error { errorDomainWebKitInternal, 0, response.url(), "Scope URL should start with the given script URL"_s };
m_client->jobFailedLoadingScript(*this, WTFMove(error), WTFMove(exception));
m_scriptLoader = nullptr;
}
}
void ServiceWorkerJob::notifyFinished()
{
ASSERT(m_creationThread.ptr() == &Thread::current());
ASSERT(m_scriptLoader);
if (!m_scriptLoader->failed())
m_client->jobFinishedLoadingScript(*this, m_scriptLoader->script(), m_scriptLoader->contentSecurityPolicy());
else {
auto& error = m_scriptLoader->error();
ASSERT(!error.isNull());
m_client->jobFailedLoadingScript(*this, error, std::nullopt);
}
m_scriptLoader = nullptr;
}
void ServiceWorkerJob::cancelPendingLoad()
{
if (!m_scriptLoader)
return;
m_scriptLoader->cancel();
m_scriptLoader = nullptr;
}
}
#endif // ENABLE(SERVICE_WORKER)