diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/loader/WorkerThreadableLoader.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/loader/WorkerThreadableLoader.cpp')
-rw-r--r-- | Source/WebCore/loader/WorkerThreadableLoader.cpp | 221 |
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 |