Chromium Code Reviews| Index: Source/web/WebEmbeddedWorkerImpl.cpp |
| diff --git a/Source/web/WebEmbeddedWorkerImpl.cpp b/Source/web/WebEmbeddedWorkerImpl.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..6a4c0158374b9f6abbcf07dfd7c637c4fdcc2d68 |
| --- /dev/null |
| +++ b/Source/web/WebEmbeddedWorkerImpl.cpp |
| @@ -0,0 +1,237 @@ |
| +/* |
| + * Copyright (C) 2013 Google 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: |
| + * |
| + * * Redistributions of source code must retain the above copyright |
| + * notice, this list of conditions and the following disclaimer. |
| + * * 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. |
| + * * Neither the name of Google Inc. nor the names of its |
| + * contributors may be used to endorse or promote products derived from |
| + * this software without specific prior written permission. |
| + * |
| + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT |
| + * OWNER OR 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 "WebEmbeddedWorkerImpl.h" |
| + |
| +#include "WebDataSourceImpl.h" |
| +#include "WebFrameImpl.h" |
| +#include "WebServiceWorkerContextClient.h" |
| +#include "WebView.h" |
| +#include "WebWorkerPermissionClientProxy.h" |
| +#include "WorkerPermissionClient.h" |
| +#include "core/dom/Document.h" |
| +#include "core/frame/ContentSecurityPolicyResponseHeaders.h" |
| +#include "core/loader/FrameLoadRequest.h" |
| +#include "core/loader/SubstituteData.h" |
| +#include "core/workers/WorkerClients.h" |
| +#include "core/workers/WorkerScriptLoader.h" |
| +#include "core/workers/WorkerScriptLoaderClient.h" |
| +#include "core/workers/WorkerThreadStartupData.h" |
| +#include "platform/NotImplemented.h" |
| +#include "platform/SharedBuffer.h" |
| +#include "wtf/Functional.h" |
| + |
| +using namespace WebCore; |
| + |
| +namespace blink { |
| + |
| +// A thin wrapper for one-off script loading. |
| +class WebEmbeddedWorkerImpl::Loader : public WorkerScriptLoaderClient { |
| +public: |
| + static PassOwnPtr<Loader> create(ExecutionContext* loadingContext, const KURL& scriptURL, const Closure& callback) |
| + { |
| + return adoptPtr(new Loader(loadingContext, scriptURL, callback)); |
| + } |
| + |
| + virtual ~Loader() |
| + { |
| + m_scriptLoader->setClient(0); |
|
michaeln
2013/11/21 22:05:35
was wondering where the that setter was used
|
| + } |
| + |
| + virtual void didReceiveResponse(unsigned long, const WebCore::ResourceResponse& response) |
|
michaeln
2013/11/21 22:05:35
OVERRIDE keyword?
kinuko
2013/11/22 02:23:33
Done.
|
| + { |
| + m_cspHeader = ContentSecurityPolicyResponseHeaders(response); |
| + } |
| + |
| + virtual void notifyFinished() OVERRIDE |
| + { |
| + m_callback(); |
| + } |
| + |
| + void cancel() |
| + { |
| + m_scriptLoader->cancel(); |
| + } |
| + |
| + bool failed() const { return m_scriptLoader->failed(); } |
| + String script() const { return m_scriptLoader->script(); } |
| + const ContentSecurityPolicyResponseHeaders& cspHeader() const { return m_cspHeader; } |
| + |
| +private: |
| + Loader(ExecutionContext* loadingContext, const KURL& scriptURL, const Closure& callback) |
| + : m_scriptLoader(WorkerScriptLoader::create()) |
| + , m_callback(callback) |
| + { |
| + m_scriptLoader->setTargetType(ResourceRequest::TargetIsServiceWorker); |
| + m_scriptLoader->loadAsynchronously( |
| + loadingContext, scriptURL, DenyCrossOriginRequests, this); |
| + } |
| + |
| + RefPtr<WorkerScriptLoader> m_scriptLoader; |
| + Closure m_callback; |
| + ContentSecurityPolicyResponseHeaders m_cspHeader; |
| +}; |
| + |
| +WebEmbeddedWorker* WebEmbeddedWorker::create( |
| + WebServiceWorkerContextClient* client, |
| + WebWorkerPermissionClientProxy* permissionClient) |
| +{ |
| + return new WebEmbeddedWorkerImpl(adoptPtr(client), adoptPtr(permissionClient)); |
| +} |
| + |
| +WebEmbeddedWorkerImpl::WebEmbeddedWorkerImpl( |
| + PassOwnPtr<WebServiceWorkerContextClient> client, |
| + PassOwnPtr<WebWorkerPermissionClientProxy> permissionClient) |
| + : m_workerContextClient(client) |
| + , m_permissionClient(permissionClient) |
| + , m_askedToTerminate(false) |
| +{ |
| +} |
| + |
| +WebEmbeddedWorkerImpl::~WebEmbeddedWorkerImpl() |
| +{ |
| + ASSERT(m_webView); |
| + |
| + // Detach the client before closing the view to avoid getting called back. |
| + toWebFrameImpl(m_mainFrame)->setClient(0); |
| + |
| + m_webView->close(); |
| + m_mainFrame->close(); |
| +} |
| + |
| +void WebEmbeddedWorkerImpl::startWorkerContext( |
| + const WebEmbeddedWorkerStartData& data) |
| +{ |
| + ASSERT(!m_askedToTerminate); |
| + ASSERT(!m_mainScriptLoader); |
| + m_workerStartData = data; |
| + |
| + prepareShadowPageForLoader(); |
| + |
| + m_mainScriptLoader = Loader::create( |
| + m_loadingDocument.get(), |
| + data.scriptURL, |
| + bind(&WebEmbeddedWorkerImpl::didLoadScriptAndStartWorkerContext, this)); |
|
michaeln
2013/11/21 22:05:35
i have to remind myself that despite looking like
|
| +} |
| + |
| +void WebEmbeddedWorkerImpl::terminateWorkerContext() |
| +{ |
| + if (m_askedToTerminate) |
| + return; |
| + m_askedToTerminate = true; |
| + if (m_mainScriptLoader) |
| + m_mainScriptLoader->cancel(); |
|
kinuko
2013/11/21 06:36:05
note: this will call didLoadScriptAndStartWorkerCo
|
| + if (m_workerThread) |
| + m_workerThread->stop(); |
| +} |
| + |
| +void WebEmbeddedWorkerImpl::postTaskToLoader(PassOwnPtr<WebCore::ExecutionContextTask> task) |
| +{ |
| + m_loadingDocument->postTask(task); |
| +} |
| + |
| +bool WebEmbeddedWorkerImpl::postTaskForModeToWorkerGlobalScope(PassOwnPtr<WebCore::ExecutionContextTask> task, const String& mode) |
| +{ |
| + m_workerThread->runLoop().postTaskForMode(task, mode); |
| + return true; |
| +} |
| + |
| +void WebEmbeddedWorkerImpl::prepareShadowPageForLoader() |
| +{ |
| + // Create 'shadow page', which is never displayed and is used mainly to |
| + // provide a context for loading on the main thread. |
| + ASSERT(!m_webView); |
| + m_webView = WebView::create(0); |
| + m_mainFrame = WebFrame::create(this); |
| + m_webView->setMainFrame(m_mainFrame); |
| + |
| + WebFrameImpl* webFrame = toWebFrameImpl(m_webView->mainFrame()); |
| + |
| + // Construct substitute data source for the 'shadow page'. We only need it |
| + // to have same origin as the worker so the loading checks work correctly. |
| + CString content(""); |
| + int length = static_cast<int>(content.length()); |
| + RefPtr<SharedBuffer> buffer(SharedBuffer::create(content.data(), length)); |
| + webFrame->frame()->loader().load(FrameLoadRequest(0, ResourceRequest(m_workerStartData.scriptURL), SubstituteData(buffer, "text/html", "UTF-8", KURL()))); |
| + |
| + // This document will be used as 'loading context' for the worker. |
| + m_loadingDocument = webFrame->frame()->document(); |
| +} |
| + |
| +void WebEmbeddedWorkerImpl::didCreateDataSource(WebFrame*, WebDataSource* ds) |
| +{ |
| + // Tell the loader to load the data into the 'shadow page' synchronously, |
| + // so we can grab the resulting Document right after load. |
| + static_cast<WebDataSourceImpl*>(ds)->setDeferMainResourceDataLoad(false); |
| +} |
| + |
| +void WebEmbeddedWorkerImpl::didLoadScriptAndStartWorkerContext() |
|
michaeln
2013/11/21 22:05:35
nit: method naming, its a combo of a notification
kinuko
2013/11/22 02:23:33
Actually I suspected this name would be bad for th
|
| +{ |
| + ASSERT(m_mainScriptLoader); |
| + |
| + if (m_mainScriptLoader->failed() || m_askedToTerminate) { |
| + m_workerContextClient->workerContextFailedToStart(); |
| + m_mainScriptLoader.clear(); |
| + return; |
| + } |
| + |
| + // Setting up worker startup data. |
| + WorkerThreadStartMode startMode = |
| + (m_workerStartData.startMode == WebEmbeddedWorkerStartModePauseOnStart) |
| + ? PauseWorkerGlobalScopeOnStart : DontPauseWorkerGlobalScopeOnStart; |
| + |
| + const ContentSecurityPolicyResponseHeaders& header = m_mainScriptLoader->cspHeader(); |
| + String cspHeader = header.contentSecurityPolicy(); |
| + ContentSecurityPolicy::HeaderType cspType = ContentSecurityPolicy::Enforce; |
| + if (!header.contentSecurityPolicyReportOnly().isEmpty()) |
| + cspType = ContentSecurityPolicy::Report; |
|
michaeln
2013/11/21 22:05:35
I'm trying to figure out how the ContentSecurityPo
kinuko
2013/11/22 02:23:33
I'm thinking about passing ContentSecurityPolicyRe
|
| + |
| + OwnPtr<WorkerClients> workerClients = WorkerClients::create(); |
| + providePermissionClientToWorker(workerClients.get(), m_permissionClient.release()); |
| + |
| + OwnPtr<WorkerThreadStartupData> startupData = |
| + WorkerThreadStartupData::create( |
| + m_workerStartData.scriptURL, |
|
michaeln
2013/11/21 22:05:35
If there is a same-origin redirect, i think we nee
kinuko
2013/11/22 02:23:33
I was going to do so, but existing worker code is
michaeln
2013/11/22 20:01:15
If SharedWorkers get the baseurl wrong, that's no
|
| + m_workerStartData.userAgent, |
| + m_mainScriptLoader->script(), |
| + startMode, |
| + cspHeader, |
| + cspType, |
| + workerClients.release()); |
| + |
| + m_mainScriptLoader.clear(); |
| + |
| + // FIXME: Create WorkerReportingProxy, create ServiceWorkerThread and |
| + // start it with m_scripLoader->script(). |
| + notImplemented(); |
| +} |
| + |
| +} // namespace blink |