summaryrefslogtreecommitdiff
path: root/Source/WebCore/loader/WorkerThreadableLoader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/loader/WorkerThreadableLoader.cpp')
-rw-r--r--Source/WebCore/loader/WorkerThreadableLoader.cpp221
1 files changed, 107 insertions, 114 deletions
diff --git a/Source/WebCore/loader/WorkerThreadableLoader.cpp b/Source/WebCore/loader/WorkerThreadableLoader.cpp
index d10ef7ed2..31ea9bb83 100644
--- a/Source/WebCore/loader/WorkerThreadableLoader.cpp
+++ b/Source/WebCore/loader/WorkerThreadableLoader.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2009, 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2016 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
@@ -31,29 +32,30 @@
#include "config.h"
#include "WorkerThreadableLoader.h"
+#include "ContentSecurityPolicy.h"
#include "Document.h"
#include "DocumentThreadableLoader.h"
-#include "CrossThreadTask.h"
+#include "Performance.h"
#include "ResourceError.h"
#include "ResourceRequest.h"
#include "ResourceResponse.h"
+#include "ResourceTiming.h"
#include "SecurityOrigin.h"
#include "ThreadableLoader.h"
#include "WorkerGlobalScope.h"
#include "WorkerLoaderProxy.h"
#include "WorkerThread.h"
#include <wtf/MainThread.h>
-#include <wtf/OwnPtr.h>
#include <wtf/Vector.h>
namespace WebCore {
static const char loadResourceSynchronouslyMode[] = "loadResourceSynchronouslyMode";
-WorkerThreadableLoader::WorkerThreadableLoader(WorkerGlobalScope* workerGlobalScope, ThreadableLoaderClient* client, const String& taskMode, const ResourceRequest& request, const ThreadableLoaderOptions& options)
+WorkerThreadableLoader::WorkerThreadableLoader(WorkerGlobalScope& workerGlobalScope, ThreadableLoaderClient& client, const String& taskMode, ResourceRequest&& request, const ThreadableLoaderOptions& options, const String& referrer)
: m_workerGlobalScope(workerGlobalScope)
- , m_workerClientWrapper(ThreadableLoaderClientWrapper::create(client))
- , m_bridge(*(new MainThreadBridge(m_workerClientWrapper, m_workerGlobalScope->thread()->workerLoaderProxy(), taskMode, request, options, workerGlobalScope->url().strippedForUseAsReferrer())))
+ , m_workerClientWrapper(ThreadableLoaderClientWrapper::create(client, options.initiator))
+ , m_bridge(*new MainThreadBridge(m_workerClientWrapper.get(), workerGlobalScope.thread().workerLoaderProxy(), taskMode, WTFMove(request), options, referrer.isEmpty() ? workerGlobalScope.url().strippedForUseAsReferrer() : referrer, workerGlobalScope.securityOrigin(), workerGlobalScope.contentSecurityPolicy()))
{
}
@@ -62,18 +64,18 @@ WorkerThreadableLoader::~WorkerThreadableLoader()
m_bridge.destroy();
}
-void WorkerThreadableLoader::loadResourceSynchronously(WorkerGlobalScope* workerGlobalScope, const ResourceRequest& request, ThreadableLoaderClient& client, const ThreadableLoaderOptions& options)
+void WorkerThreadableLoader::loadResourceSynchronously(WorkerGlobalScope& workerGlobalScope, ResourceRequest&& request, ThreadableLoaderClient& client, const ThreadableLoaderOptions& options)
{
- WorkerRunLoop& runLoop = workerGlobalScope->thread()->runLoop();
+ WorkerRunLoop& runLoop = workerGlobalScope.thread().runLoop();
// Create a unique mode just for this synchronous resource load.
String mode = loadResourceSynchronouslyMode;
mode.append(String::number(runLoop.createUniqueId()));
- RefPtr<WorkerThreadableLoader> loader = WorkerThreadableLoader::create(workerGlobalScope, &client, mode, request, options);
+ RefPtr<WorkerThreadableLoader> loader = WorkerThreadableLoader::create(workerGlobalScope, client, mode, WTFMove(request), options, String());
MessageQueueWaitResult result = MessageQueueMessageReceived;
while (!loader->done() && result != MessageQueueTerminated)
- result = runLoop.runInMode(workerGlobalScope, mode);
+ result = runLoop.runInMode(&workerGlobalScope, mode);
if (!loader->done() && result == MessageQueueTerminated)
loader->cancel();
@@ -84,41 +86,51 @@ void WorkerThreadableLoader::cancel()
m_bridge.cancel();
}
-WorkerThreadableLoader::MainThreadBridge::MainThreadBridge(PassRefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, WorkerLoaderProxy& loaderProxy, const String& taskMode,
- const ResourceRequest& request, const ThreadableLoaderOptions& options, const String& outgoingReferrer)
- : m_workerClientWrapper(workerClientWrapper)
- , m_loaderProxy(loaderProxy)
- , m_taskMode(taskMode.isolatedCopy())
-{
- ASSERT(m_workerClientWrapper.get());
- m_loaderProxy.postTaskToLoader(
- createCallbackTask(&MainThreadBridge::mainThreadCreateLoader,
- AllowCrossThreadAccess(this), request, options, outgoingReferrer));
-}
+struct LoaderTaskOptions {
+ LoaderTaskOptions(const ThreadableLoaderOptions&, const String&, Ref<SecurityOrigin>&&);
+ ThreadableLoaderOptions options;
+ String referrer;
+ Ref<SecurityOrigin> origin;
+};
-WorkerThreadableLoader::MainThreadBridge::~MainThreadBridge()
+LoaderTaskOptions::LoaderTaskOptions(const ThreadableLoaderOptions& options, const String& referrer, Ref<SecurityOrigin>&& origin)
+ : options(options, options.preflightPolicy, options.contentSecurityPolicyEnforcement, options.initiator.isolatedCopy(), options.filteringPolicy)
+ , referrer(referrer.isolatedCopy())
+ , origin(WTFMove(origin))
{
}
-void WorkerThreadableLoader::MainThreadBridge::mainThreadCreateLoader(ScriptExecutionContext* context, MainThreadBridge* thisPtr, PassOwnPtr<CrossThreadResourceRequestData> requestData, ThreadableLoaderOptions options, const String& outgoingReferrer)
+WorkerThreadableLoader::MainThreadBridge::MainThreadBridge(ThreadableLoaderClientWrapper& workerClientWrapper, WorkerLoaderProxy& loaderProxy, const String& taskMode,
+ ResourceRequest&& request, const ThreadableLoaderOptions& options, const String& outgoingReferrer,
+ const SecurityOrigin* securityOrigin, const ContentSecurityPolicy* contentSecurityPolicy)
+ : m_workerClientWrapper(&workerClientWrapper)
+ , m_loaderProxy(loaderProxy)
+ , m_taskMode(taskMode.isolatedCopy())
{
- ASSERT(isMainThread());
- Document* document = toDocument(context);
-
- OwnPtr<ResourceRequest> request(ResourceRequest::adopt(requestData));
- request->setHTTPReferrer(outgoingReferrer);
- // FIXME: If the a site requests a local resource, then this will return a non-zero value but the sync path
- // will return a 0 value. Either this should return 0 or the other code path should do a callback with
- // a failure.
- thisPtr->m_mainThreadLoader = DocumentThreadableLoader::create(document, thisPtr, *request, options);
- ASSERT(thisPtr->m_mainThreadLoader);
-}
+ ASSERT(securityOrigin);
+ ASSERT(contentSecurityPolicy);
-void WorkerThreadableLoader::MainThreadBridge::mainThreadDestroy(ScriptExecutionContext* context, MainThreadBridge* thisPtr)
-{
- ASSERT(isMainThread());
- ASSERT_UNUSED(context, context->isDocument());
- delete thisPtr;
+ auto securityOriginCopy = securityOrigin->isolatedCopy();
+ auto contentSecurityPolicyCopy = std::make_unique<ContentSecurityPolicy>(securityOriginCopy);
+ contentSecurityPolicyCopy->copyStateFrom(contentSecurityPolicy);
+ contentSecurityPolicyCopy->copyUpgradeInsecureRequestStateFrom(*contentSecurityPolicy);
+
+ auto optionsCopy = std::make_unique<LoaderTaskOptions>(options, request.httpReferrer().isNull() ? outgoingReferrer : request.httpReferrer(), WTFMove(securityOriginCopy));
+
+ // All loads start out as Document. Inside WorkerThreadableLoader we upgrade this to a Worker load.
+ ASSERT(optionsCopy->options.initiatorContext == InitiatorContext::Document);
+ optionsCopy->options.initiatorContext = InitiatorContext::Worker;
+
+ // Can we benefit from request being an r-value to create more efficiently its isolated copy?
+ m_loaderProxy.postTaskToLoader([this, request = request.isolatedCopy(), options = WTFMove(optionsCopy), contentSecurityPolicyCopy = WTFMove(contentSecurityPolicyCopy)](ScriptExecutionContext& context) mutable {
+ ASSERT(isMainThread());
+ Document& document = downcast<Document>(context);
+
+ // FIXME: If the site requests a local resource, then this will return a non-zero value but the sync path will return a 0 value.
+ // Either this should return 0 or the other code path should call a failure callback.
+ m_mainThreadLoader = DocumentThreadableLoader::create(document, *this, WTFMove(request), options->options, WTFMove(options->origin), WTFMove(contentSecurityPolicyCopy), WTFMove(options->referrer), DocumentThreadableLoader::ShouldLogError::No);
+ ASSERT(m_mainThreadLoader || m_loadingFinished);
+ });
}
void WorkerThreadableLoader::MainThreadBridge::destroy()
@@ -127,34 +139,35 @@ void WorkerThreadableLoader::MainThreadBridge::destroy()
clearClientWrapper();
// "delete this" and m_mainThreadLoader::deref() on the worker object's thread.
- m_loaderProxy.postTaskToLoader(
- createCallbackTask(&MainThreadBridge::mainThreadDestroy, AllowCrossThreadAccess(this)));
+ m_loaderProxy.postTaskToLoader([self = std::unique_ptr<WorkerThreadableLoader::MainThreadBridge>(this)] (ScriptExecutionContext& context) {
+ ASSERT(isMainThread());
+ ASSERT_UNUSED(context, context.isDocument());
+ });
}
-void WorkerThreadableLoader::MainThreadBridge::mainThreadCancel(ScriptExecutionContext* context, MainThreadBridge* thisPtr)
+void WorkerThreadableLoader::MainThreadBridge::cancel()
{
- ASSERT(isMainThread());
- ASSERT_UNUSED(context, context->isDocument());
+ m_loaderProxy.postTaskToLoader([this] (ScriptExecutionContext& context) {
+ ASSERT(isMainThread());
+ ASSERT_UNUSED(context, context.isDocument());
- if (!thisPtr->m_mainThreadLoader)
- return;
- thisPtr->m_mainThreadLoader->cancel();
- thisPtr->m_mainThreadLoader = 0;
-}
+ if (!m_mainThreadLoader)
+ return;
+ m_mainThreadLoader->cancel();
+ m_mainThreadLoader = nullptr;
+ });
-void WorkerThreadableLoader::MainThreadBridge::cancel()
-{
- m_loaderProxy.postTaskToLoader(
- createCallbackTask(&MainThreadBridge::mainThreadCancel, AllowCrossThreadAccess(this)));
- ThreadableLoaderClientWrapper* clientWrapper = m_workerClientWrapper.get();
- if (!clientWrapper->done()) {
- // If the client hasn't reached a termination state, then transition it by sending a cancellation error.
- // Note: no more client callbacks will be done after this method -- the clearClientWrapper() call ensures that.
- ResourceError error(String(), 0, String(), String());
- error.setIsCancellation(true);
- clientWrapper->didFail(error);
+ if (m_workerClientWrapper->done()) {
+ clearClientWrapper();
+ return;
}
- clearClientWrapper();
+ // Taking a ref of client wrapper as call to didFail may take out the last reference of it.
+ Ref<ThreadableLoaderClientWrapper> protectedWorkerClientWrapper(*m_workerClientWrapper);
+ // If the client hasn't reached a termination state, then transition it by sending a cancellation error.
+ // Note: no more client callbacks will be done after this method -- we clear the client wrapper to ensure that.
+ ResourceError error(ResourceError::Type::Cancellation);
+ protectedWorkerClientWrapper->didFail(error);
+ protectedWorkerClientWrapper->clearClient();
}
void WorkerThreadableLoader::MainThreadBridge::clearClientWrapper()
@@ -162,84 +175,64 @@ void WorkerThreadableLoader::MainThreadBridge::clearClientWrapper()
m_workerClientWrapper->clearClient();
}
-static void workerGlobalScopeDidSendData(ScriptExecutionContext* context, RefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
-{
- ASSERT_UNUSED(context, context->isWorkerGlobalScope());
- workerClientWrapper->didSendData(bytesSent, totalBytesToBeSent);
-}
-
void WorkerThreadableLoader::MainThreadBridge::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
{
- m_loaderProxy.postTaskForModeToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidSendData, m_workerClientWrapper, bytesSent, totalBytesToBeSent), m_taskMode);
-}
-
-static void workerGlobalScopeDidReceiveResponse(ScriptExecutionContext* context, RefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, unsigned long identifier, PassOwnPtr<CrossThreadResourceResponseData> responseData)
-{
- ASSERT_UNUSED(context, context->isWorkerGlobalScope());
- OwnPtr<ResourceResponse> response(ResourceResponse::adopt(responseData));
- workerClientWrapper->didReceiveResponse(identifier, *response);
+ m_loaderProxy.postTaskForModeToWorkerGlobalScope([protectedWorkerClientWrapper = makeRef(*m_workerClientWrapper), bytesSent, totalBytesToBeSent] (ScriptExecutionContext& context) mutable {
+ ASSERT_UNUSED(context, context.isWorkerGlobalScope());
+ protectedWorkerClientWrapper->didSendData(bytesSent, totalBytesToBeSent);
+ }, m_taskMode);
}
void WorkerThreadableLoader::MainThreadBridge::didReceiveResponse(unsigned long identifier, const ResourceResponse& response)
{
- m_loaderProxy.postTaskForModeToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidReceiveResponse, m_workerClientWrapper, identifier, response), m_taskMode);
-}
-
-static void workerGlobalScopeDidReceiveData(ScriptExecutionContext* context, RefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, PassOwnPtr<Vector<char>> vectorData)
-{
- ASSERT_UNUSED(context, context->isWorkerGlobalScope());
- workerClientWrapper->didReceiveData(vectorData->data(), vectorData->size());
+ m_loaderProxy.postTaskForModeToWorkerGlobalScope([protectedWorkerClientWrapper = makeRef(*m_workerClientWrapper), identifier, responseData = response.crossThreadData()] (ScriptExecutionContext& context) mutable {
+ ASSERT_UNUSED(context, context.isWorkerGlobalScope());
+ protectedWorkerClientWrapper->didReceiveResponse(identifier, ResourceResponse::fromCrossThreadData(WTFMove(responseData)));
+ }, m_taskMode);
}
void WorkerThreadableLoader::MainThreadBridge::didReceiveData(const char* data, int dataLength)
{
- OwnPtr<Vector<char>> vector = adoptPtr(new Vector<char>(dataLength)); // needs to be an OwnPtr for usage with createCallbackTask.
- memcpy(vector->data(), data, dataLength);
- m_loaderProxy.postTaskForModeToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidReceiveData, m_workerClientWrapper, vector.release()), m_taskMode);
-}
-
-static void workerGlobalScopeDidFinishLoading(ScriptExecutionContext* context, RefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, unsigned long identifier, double finishTime)
-{
- ASSERT_UNUSED(context, context->isWorkerGlobalScope());
- workerClientWrapper->didFinishLoading(identifier, finishTime);
+ Vector<char> vector(dataLength);
+ memcpy(vector.data(), data, dataLength);
+ m_loaderProxy.postTaskForModeToWorkerGlobalScope([protectedWorkerClientWrapper = makeRef(*m_workerClientWrapper), vector = WTFMove(vector)] (ScriptExecutionContext& context) mutable {
+ ASSERT_UNUSED(context, context.isWorkerGlobalScope());
+ protectedWorkerClientWrapper->didReceiveData(vector.data(), vector.size());
+ }, m_taskMode);
}
void WorkerThreadableLoader::MainThreadBridge::didFinishLoading(unsigned long identifier, double finishTime)
{
- m_loaderProxy.postTaskForModeToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidFinishLoading, m_workerClientWrapper, identifier, finishTime), m_taskMode);
-}
-
-static void workerGlobalScopeDidFail(ScriptExecutionContext* context, RefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, const ResourceError& error)
-{
- ASSERT_UNUSED(context, context->isWorkerGlobalScope());
- workerClientWrapper->didFail(error);
+ m_loadingFinished = true;
+ m_loaderProxy.postTaskForModeToWorkerGlobalScope([protectedWorkerClientWrapper = makeRef(*m_workerClientWrapper), identifier, finishTime] (ScriptExecutionContext& context) mutable {
+ ASSERT_UNUSED(context, context.isWorkerGlobalScope());
+ protectedWorkerClientWrapper->didFinishLoading(identifier, finishTime);
+ }, m_taskMode);
}
void WorkerThreadableLoader::MainThreadBridge::didFail(const ResourceError& error)
{
- m_loaderProxy.postTaskForModeToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidFail, m_workerClientWrapper, error), m_taskMode);
-}
+ m_loadingFinished = true;
+ m_loaderProxy.postTaskForModeToWorkerGlobalScope([workerClientWrapper = Ref<ThreadableLoaderClientWrapper>(*m_workerClientWrapper), error = error.isolatedCopy()] (ScriptExecutionContext& context) mutable {
+ ASSERT(context.isWorkerGlobalScope());
-static void workerGlobalScopeDidFailAccessControlCheck(ScriptExecutionContext* context, PassRefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, const ResourceError& error)
-{
- ASSERT_UNUSED(context, context->isWorkerGlobalScope());
- workerClientWrapper->didFailAccessControlCheck(error);
-}
+ ThreadableLoader::logError(context, error, workerClientWrapper->initiator());
-void WorkerThreadableLoader::MainThreadBridge::didFailAccessControlCheck(const ResourceError& error)
-{
- m_loaderProxy.postTaskForModeToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidFailAccessControlCheck, m_workerClientWrapper, error), m_taskMode);
+ workerClientWrapper->didFail(error);
+ }, m_taskMode);
}
-static void workerGlobalScopeDidFailRedirectCheck(ScriptExecutionContext* context, RefPtr<ThreadableLoaderClientWrapper> workerClientWrapper)
+#if ENABLE(WEB_TIMING)
+void WorkerThreadableLoader::MainThreadBridge::didFinishTiming(const ResourceTiming& resourceTiming)
{
- ASSERT_UNUSED(context, context->isWorkerGlobalScope());
- workerClientWrapper->didFailRedirectCheck();
-}
+ m_loaderProxy.postTaskForModeToWorkerGlobalScope([protectedWorkerClientWrapper = makeRef(*m_workerClientWrapper), resourceTiming = resourceTiming.isolatedCopy()] (ScriptExecutionContext& context) mutable {
+ ASSERT(context.isWorkerGlobalScope());
+ ASSERT(!resourceTiming.initiator().isEmpty());
-void WorkerThreadableLoader::MainThreadBridge::didFailRedirectCheck()
-{
- m_loaderProxy.postTaskForModeToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidFailRedirectCheck, m_workerClientWrapper), m_taskMode);
+ // No need to notify clients, just add the performance timing entry.
+ downcast<WorkerGlobalScope>(context).performance().addResourceTiming(WTFMove(resourceTiming));
+ }, m_taskMode);
}
+#endif
} // namespace WebCore