Torne (Richard Coles) | a854de0 | 2013-12-18 16:25:25 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2013 Google Inc. All rights reserved. |
| 3 | * |
| 4 | * Redistribution and use in source and binary forms, with or without |
| 5 | * modification, are permitted provided that the following conditions are |
| 6 | * met: |
| 7 | * |
| 8 | * * Redistributions of source code must retain the above copyright |
| 9 | * notice, this list of conditions and the following disclaimer. |
| 10 | * * Redistributions in binary form must reproduce the above |
| 11 | * copyright notice, this list of conditions and the following disclaimer |
| 12 | * in the documentation and/or other materials provided with the |
| 13 | * distribution. |
| 14 | * * Neither the name of Google Inc. nor the names of its |
| 15 | * contributors may be used to endorse or promote products derived from |
| 16 | * this software without specific prior written permission. |
| 17 | * |
| 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 22 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 29 | */ |
| 30 | |
| 31 | #include "config.h" |
| 32 | #include "WebEmbeddedWorkerImpl.h" |
| 33 | |
Torne (Richard Coles) | 0938029 | 2014-02-21 12:17:33 +0000 | [diff] [blame] | 34 | #include "ServiceWorkerGlobalScopeClientImpl.h" |
Torne (Richard Coles) | a854de0 | 2013-12-18 16:25:25 +0000 | [diff] [blame] | 35 | #include "ServiceWorkerGlobalScopeProxy.h" |
| 36 | #include "WebDataSourceImpl.h" |
| 37 | #include "WebFrameImpl.h" |
| 38 | #include "WebServiceWorkerContextClient.h" |
Torne (Richard Coles) | 43e7502 | 2014-03-21 14:26:12 +0000 | [diff] [blame] | 39 | #include "WebServiceWorkerNetworkProvider.h" |
Torne (Richard Coles) | a854de0 | 2013-12-18 16:25:25 +0000 | [diff] [blame] | 40 | #include "WebView.h" |
| 41 | #include "WebWorkerPermissionClientProxy.h" |
| 42 | #include "WorkerPermissionClient.h" |
| 43 | #include "core/dom/Document.h" |
| 44 | #include "core/loader/FrameLoadRequest.h" |
| 45 | #include "core/loader/SubstituteData.h" |
| 46 | #include "core/workers/WorkerClients.h" |
| 47 | #include "core/workers/WorkerLoaderProxy.h" |
| 48 | #include "core/workers/WorkerScriptLoader.h" |
| 49 | #include "core/workers/WorkerScriptLoaderClient.h" |
| 50 | #include "core/workers/WorkerThreadStartupData.h" |
Torne (Richard Coles) | d5428f3 | 2014-03-18 10:21:16 +0000 | [diff] [blame] | 51 | #include "heap/Handle.h" |
Torne (Richard Coles) | a854de0 | 2013-12-18 16:25:25 +0000 | [diff] [blame] | 52 | #include "modules/serviceworkers/ServiceWorkerThread.h" |
| 53 | #include "platform/NotImplemented.h" |
| 54 | #include "platform/SharedBuffer.h" |
Torne (Richard Coles) | d5428f3 | 2014-03-18 10:21:16 +0000 | [diff] [blame] | 55 | #include "platform/network/ContentSecurityPolicyParsers.h" |
Torne (Richard Coles) | a854de0 | 2013-12-18 16:25:25 +0000 | [diff] [blame] | 56 | #include "wtf/Functional.h" |
| 57 | |
| 58 | using namespace WebCore; |
| 59 | |
| 60 | namespace blink { |
| 61 | |
| 62 | // A thin wrapper for one-off script loading. |
| 63 | class WebEmbeddedWorkerImpl::Loader : public WorkerScriptLoaderClient { |
| 64 | public: |
Torne (Richard Coles) | 0938029 | 2014-02-21 12:17:33 +0000 | [diff] [blame] | 65 | static PassOwnPtr<Loader> create() |
Torne (Richard Coles) | a854de0 | 2013-12-18 16:25:25 +0000 | [diff] [blame] | 66 | { |
Torne (Richard Coles) | 0938029 | 2014-02-21 12:17:33 +0000 | [diff] [blame] | 67 | return adoptPtr(new Loader()); |
Torne (Richard Coles) | a854de0 | 2013-12-18 16:25:25 +0000 | [diff] [blame] | 68 | } |
| 69 | |
| 70 | virtual ~Loader() |
| 71 | { |
| 72 | m_scriptLoader->setClient(0); |
| 73 | } |
| 74 | |
Torne (Richard Coles) | 0938029 | 2014-02-21 12:17:33 +0000 | [diff] [blame] | 75 | void load(ExecutionContext* loadingContext, const KURL& scriptURL, const Closure& callback) |
| 76 | { |
| 77 | m_callback = callback; |
| 78 | m_scriptLoader->setTargetType(ResourceRequest::TargetIsServiceWorker); |
| 79 | m_scriptLoader->loadAsynchronously( |
| 80 | loadingContext, scriptURL, DenyCrossOriginRequests, this); |
| 81 | } |
| 82 | |
Torne (Richard Coles) | a854de0 | 2013-12-18 16:25:25 +0000 | [diff] [blame] | 83 | virtual void notifyFinished() OVERRIDE |
| 84 | { |
| 85 | m_callback(); |
| 86 | } |
| 87 | |
| 88 | void cancel() |
| 89 | { |
| 90 | m_scriptLoader->cancel(); |
| 91 | } |
| 92 | |
| 93 | bool failed() const { return m_scriptLoader->failed(); } |
| 94 | const KURL& url() const { return m_scriptLoader->responseURL(); } |
| 95 | String script() const { return m_scriptLoader->script(); } |
| 96 | |
| 97 | private: |
Torne (Richard Coles) | 0938029 | 2014-02-21 12:17:33 +0000 | [diff] [blame] | 98 | Loader() : m_scriptLoader(WorkerScriptLoader::create()) |
Torne (Richard Coles) | a854de0 | 2013-12-18 16:25:25 +0000 | [diff] [blame] | 99 | { |
Torne (Richard Coles) | a854de0 | 2013-12-18 16:25:25 +0000 | [diff] [blame] | 100 | } |
| 101 | |
| 102 | RefPtr<WorkerScriptLoader> m_scriptLoader; |
| 103 | Closure m_callback; |
| 104 | }; |
| 105 | |
| 106 | class WebEmbeddedWorkerImpl::LoaderProxy : public WorkerLoaderProxy { |
| 107 | public: |
| 108 | static PassOwnPtr<LoaderProxy> create(WebEmbeddedWorkerImpl& embeddedWorker) |
| 109 | { |
| 110 | return adoptPtr(new LoaderProxy(embeddedWorker)); |
| 111 | } |
| 112 | |
| 113 | virtual void postTaskToLoader(PassOwnPtr<ExecutionContextTask> task) OVERRIDE |
| 114 | { |
Torne (Richard Coles) | 0938029 | 2014-02-21 12:17:33 +0000 | [diff] [blame] | 115 | toWebFrameImpl(m_embeddedWorker.m_mainFrame)->frame()->document()->postTask(task); |
Torne (Richard Coles) | a854de0 | 2013-12-18 16:25:25 +0000 | [diff] [blame] | 116 | } |
| 117 | |
Torne (Richard Coles) | 0938029 | 2014-02-21 12:17:33 +0000 | [diff] [blame] | 118 | virtual bool postTaskToWorkerGlobalScope(PassOwnPtr<ExecutionContextTask> task) OVERRIDE |
Torne (Richard Coles) | a854de0 | 2013-12-18 16:25:25 +0000 | [diff] [blame] | 119 | { |
| 120 | if (m_embeddedWorker.m_askedToTerminate || !m_embeddedWorker.m_workerThread) |
| 121 | return false; |
Torne (Richard Coles) | 0938029 | 2014-02-21 12:17:33 +0000 | [diff] [blame] | 122 | return m_embeddedWorker.m_workerThread->runLoop().postTask(task); |
Torne (Richard Coles) | a854de0 | 2013-12-18 16:25:25 +0000 | [diff] [blame] | 123 | } |
| 124 | |
| 125 | private: |
| 126 | explicit LoaderProxy(WebEmbeddedWorkerImpl& embeddedWorker) |
| 127 | : m_embeddedWorker(embeddedWorker) |
| 128 | { |
| 129 | } |
| 130 | |
| 131 | // Not owned, embedded worker owns this. |
| 132 | WebEmbeddedWorkerImpl& m_embeddedWorker; |
| 133 | }; |
| 134 | |
| 135 | WebEmbeddedWorker* WebEmbeddedWorker::create( |
| 136 | WebServiceWorkerContextClient* client, |
| 137 | WebWorkerPermissionClientProxy* permissionClient) |
| 138 | { |
| 139 | return new WebEmbeddedWorkerImpl(adoptPtr(client), adoptPtr(permissionClient)); |
| 140 | } |
| 141 | |
| 142 | WebEmbeddedWorkerImpl::WebEmbeddedWorkerImpl( |
| 143 | PassOwnPtr<WebServiceWorkerContextClient> client, |
| 144 | PassOwnPtr<WebWorkerPermissionClientProxy> permissionClient) |
| 145 | : m_workerContextClient(client) |
| 146 | , m_permissionClient(permissionClient) |
Torne (Richard Coles) | 0938029 | 2014-02-21 12:17:33 +0000 | [diff] [blame] | 147 | , m_webView(0) |
| 148 | , m_mainFrame(0) |
Torne (Richard Coles) | a854de0 | 2013-12-18 16:25:25 +0000 | [diff] [blame] | 149 | , m_askedToTerminate(false) |
| 150 | { |
| 151 | } |
| 152 | |
| 153 | WebEmbeddedWorkerImpl::~WebEmbeddedWorkerImpl() |
| 154 | { |
| 155 | ASSERT(m_webView); |
| 156 | |
| 157 | // Detach the client before closing the view to avoid getting called back. |
| 158 | toWebFrameImpl(m_mainFrame)->setClient(0); |
| 159 | |
| 160 | m_webView->close(); |
| 161 | m_mainFrame->close(); |
| 162 | } |
| 163 | |
| 164 | void WebEmbeddedWorkerImpl::startWorkerContext( |
| 165 | const WebEmbeddedWorkerStartData& data) |
| 166 | { |
| 167 | ASSERT(!m_askedToTerminate); |
| 168 | ASSERT(!m_mainScriptLoader); |
| 169 | m_workerStartData = data; |
| 170 | |
| 171 | prepareShadowPageForLoader(); |
Torne (Richard Coles) | a854de0 | 2013-12-18 16:25:25 +0000 | [diff] [blame] | 172 | } |
| 173 | |
| 174 | void WebEmbeddedWorkerImpl::terminateWorkerContext() |
| 175 | { |
| 176 | if (m_askedToTerminate) |
| 177 | return; |
| 178 | m_askedToTerminate = true; |
| 179 | if (m_mainScriptLoader) |
| 180 | m_mainScriptLoader->cancel(); |
| 181 | if (m_workerThread) |
| 182 | m_workerThread->stop(); |
| 183 | } |
| 184 | |
| 185 | void WebEmbeddedWorkerImpl::prepareShadowPageForLoader() |
| 186 | { |
| 187 | // Create 'shadow page', which is never displayed and is used mainly to |
| 188 | // provide a context for loading on the main thread. |
| 189 | // |
| 190 | // FIXME: This does mostly same as WebSharedWorkerImpl::initializeLoader. |
| 191 | // This code, and probably most of the code in this class should be shared |
| 192 | // with SharedWorker. |
| 193 | ASSERT(!m_webView); |
| 194 | m_webView = WebView::create(0); |
| 195 | m_mainFrame = WebFrame::create(this); |
| 196 | m_webView->setMainFrame(m_mainFrame); |
| 197 | |
| 198 | WebFrameImpl* webFrame = toWebFrameImpl(m_webView->mainFrame()); |
| 199 | |
| 200 | // Construct substitute data source for the 'shadow page'. We only need it |
| 201 | // to have same origin as the worker so the loading checks work correctly. |
| 202 | CString content(""); |
| 203 | int length = static_cast<int>(content.length()); |
| 204 | RefPtr<SharedBuffer> buffer(SharedBuffer::create(content.data(), length)); |
| 205 | webFrame->frame()->loader().load(FrameLoadRequest(0, ResourceRequest(m_workerStartData.scriptURL), SubstituteData(buffer, "text/html", "UTF-8", KURL()))); |
Torne (Richard Coles) | a854de0 | 2013-12-18 16:25:25 +0000 | [diff] [blame] | 206 | } |
| 207 | |
Torne (Richard Coles) | 43e7502 | 2014-03-21 14:26:12 +0000 | [diff] [blame] | 208 | void WebEmbeddedWorkerImpl::willSendRequest( |
| 209 | WebFrame* frame, unsigned, WebURLRequest& request, |
| 210 | const WebURLResponse& redirectResponse) |
| 211 | { |
| 212 | if (m_networkProvider) |
| 213 | m_networkProvider->willSendRequest(frame->dataSource(), request); |
| 214 | } |
| 215 | |
Torne (Richard Coles) | 0938029 | 2014-02-21 12:17:33 +0000 | [diff] [blame] | 216 | void WebEmbeddedWorkerImpl::didFinishDocumentLoad(WebFrame* frame) |
Torne (Richard Coles) | a854de0 | 2013-12-18 16:25:25 +0000 | [diff] [blame] | 217 | { |
Torne (Richard Coles) | 0938029 | 2014-02-21 12:17:33 +0000 | [diff] [blame] | 218 | ASSERT(!m_mainScriptLoader); |
Torne (Richard Coles) | 43e7502 | 2014-03-21 14:26:12 +0000 | [diff] [blame] | 219 | ASSERT(!m_networkProvider); |
Torne (Richard Coles) | 0938029 | 2014-02-21 12:17:33 +0000 | [diff] [blame] | 220 | ASSERT(m_mainFrame); |
Torne (Richard Coles) | 43e7502 | 2014-03-21 14:26:12 +0000 | [diff] [blame] | 221 | ASSERT(m_workerContextClient); |
| 222 | m_networkProvider = adoptPtr(m_workerContextClient->createServiceWorkerNetworkProvider(frame->dataSource())); |
Torne (Richard Coles) | 0938029 | 2014-02-21 12:17:33 +0000 | [diff] [blame] | 223 | m_mainScriptLoader = Loader::create(); |
| 224 | m_mainScriptLoader->load( |
| 225 | toWebFrameImpl(m_mainFrame)->frame()->document(), |
| 226 | m_workerStartData.scriptURL, |
| 227 | bind(&WebEmbeddedWorkerImpl::onScriptLoaderFinished, this)); |
Torne (Richard Coles) | a854de0 | 2013-12-18 16:25:25 +0000 | [diff] [blame] | 228 | } |
| 229 | |
| 230 | void WebEmbeddedWorkerImpl::onScriptLoaderFinished() |
| 231 | { |
| 232 | ASSERT(m_mainScriptLoader); |
| 233 | |
| 234 | if (m_mainScriptLoader->failed() || m_askedToTerminate) { |
Torne (Richard Coles) | a854de0 | 2013-12-18 16:25:25 +0000 | [diff] [blame] | 235 | m_mainScriptLoader.clear(); |
Torne (Richard Coles) | 0938029 | 2014-02-21 12:17:33 +0000 | [diff] [blame] | 236 | // This may delete 'this'. |
| 237 | m_workerContextClient->workerContextFailedToStart(); |
Torne (Richard Coles) | a854de0 | 2013-12-18 16:25:25 +0000 | [diff] [blame] | 238 | return; |
| 239 | } |
| 240 | |
| 241 | WorkerThreadStartMode startMode = |
| 242 | (m_workerStartData.startMode == WebEmbeddedWorkerStartModePauseOnStart) |
| 243 | ? PauseWorkerGlobalScopeOnStart : DontPauseWorkerGlobalScopeOnStart; |
| 244 | |
Torne (Richard Coles) | 0938029 | 2014-02-21 12:17:33 +0000 | [diff] [blame] | 245 | // This is to be owned by ServiceWorker's WorkerGlobalScope, and is |
| 246 | // guaranteed to be around while the WorkerGlobalScope is alive. |
| 247 | WebServiceWorkerContextClient* contextClient = m_workerContextClient.get(); |
| 248 | |
Torne (Richard Coles) | a854de0 | 2013-12-18 16:25:25 +0000 | [diff] [blame] | 249 | OwnPtr<WorkerClients> workerClients = WorkerClients::create(); |
| 250 | providePermissionClientToWorker(workerClients.get(), m_permissionClient.release()); |
Torne (Richard Coles) | 0938029 | 2014-02-21 12:17:33 +0000 | [diff] [blame] | 251 | provideServiceWorkerGlobalScopeClientToWorker(workerClients.get(), ServiceWorkerGlobalScopeClientImpl::create(m_workerContextClient.release())); |
Torne (Richard Coles) | a854de0 | 2013-12-18 16:25:25 +0000 | [diff] [blame] | 252 | |
Torne (Richard Coles) | d5428f3 | 2014-03-18 10:21:16 +0000 | [diff] [blame] | 253 | OwnPtrWillBeRawPtr<WorkerThreadStartupData> startupData = |
Torne (Richard Coles) | a854de0 | 2013-12-18 16:25:25 +0000 | [diff] [blame] | 254 | WorkerThreadStartupData::create( |
| 255 | m_mainScriptLoader->url(), |
| 256 | m_workerStartData.userAgent, |
| 257 | m_mainScriptLoader->script(), |
| 258 | startMode, |
| 259 | // FIXME: fill appropriate CSP info and policy type. |
| 260 | String(), |
Torne (Richard Coles) | d5428f3 | 2014-03-18 10:21:16 +0000 | [diff] [blame] | 261 | ContentSecurityPolicyHeaderTypeEnforce, |
Torne (Richard Coles) | a854de0 | 2013-12-18 16:25:25 +0000 | [diff] [blame] | 262 | workerClients.release()); |
| 263 | |
| 264 | m_mainScriptLoader.clear(); |
| 265 | |
Torne (Richard Coles) | 0938029 | 2014-02-21 12:17:33 +0000 | [diff] [blame] | 266 | m_workerGlobalScopeProxy = ServiceWorkerGlobalScopeProxy::create(*this, *toWebFrameImpl(m_mainFrame)->frame()->document(), *contextClient); |
Torne (Richard Coles) | a854de0 | 2013-12-18 16:25:25 +0000 | [diff] [blame] | 267 | m_loaderProxy = LoaderProxy::create(*this); |
| 268 | |
| 269 | m_workerThread = ServiceWorkerThread::create(*m_loaderProxy, *m_workerGlobalScopeProxy, startupData.release()); |
| 270 | m_workerThread->start(); |
| 271 | } |
| 272 | |
| 273 | } // namespace blink |