blob: d76b7244e99642ceed274ac1a8f36187bedea551 [file] [log] [blame]
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001/*
2 * Copyright (C) 2009, 2010 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
33#include "core/loader/WorkerThreadableLoader.h"
34
35#include "core/dom/CrossThreadTask.h"
36#include "core/dom/Document.h"
37#include "core/loader/DocumentThreadableLoader.h"
38#include "core/loader/ThreadableLoader.h"
39#include "core/platform/network/ResourceError.h"
40#include "core/platform/network/ResourceRequest.h"
41#include "core/platform/network/ResourceResponse.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010042#include "core/workers/WorkerGlobalScope.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010043#include "core/workers/WorkerLoaderProxy.h"
44#include "core/workers/WorkerThread.h"
Ben Murdoche69819b2013-07-17 14:56:49 +010045#include "wtf/MainThread.h"
46#include "wtf/OwnPtr.h"
47#include "wtf/Vector.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010048
49using namespace std;
50
51namespace WebCore {
52
53static const char loadResourceSynchronouslyMode[] = "loadResourceSynchronouslyMode";
54
Ben Murdoch591b9582013-07-10 11:41:44 +010055WorkerThreadableLoader::WorkerThreadableLoader(WorkerGlobalScope* workerGlobalScope, ThreadableLoaderClient* client, const String& taskMode, const ResourceRequest& request, const ThreadableLoaderOptions& options)
56 : m_workerGlobalScope(workerGlobalScope)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010057 , m_workerClientWrapper(ThreadableLoaderClientWrapper::create(client))
Ben Murdoch591b9582013-07-10 11:41:44 +010058 , m_bridge(*(new MainThreadBridge(m_workerClientWrapper, m_workerGlobalScope->thread()->workerLoaderProxy(), taskMode, request, options, workerGlobalScope->url().strippedForUseAsReferrer())))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010059{
60}
61
62WorkerThreadableLoader::~WorkerThreadableLoader()
63{
64 m_bridge.destroy();
65}
66
Ben Murdoch591b9582013-07-10 11:41:44 +010067void WorkerThreadableLoader::loadResourceSynchronously(WorkerGlobalScope* workerGlobalScope, const ResourceRequest& request, ThreadableLoaderClient& client, const ThreadableLoaderOptions& options)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010068{
Ben Murdoch591b9582013-07-10 11:41:44 +010069 WorkerRunLoop& runLoop = workerGlobalScope->thread()->runLoop();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010070
71 // Create a unique mode just for this synchronous resource load.
72 String mode = loadResourceSynchronouslyMode;
73 mode.append(String::number(runLoop.createUniqueId()));
74
Ben Murdoch591b9582013-07-10 11:41:44 +010075 RefPtr<WorkerThreadableLoader> loader = WorkerThreadableLoader::create(workerGlobalScope, &client, mode, request, options);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010076 MessageQueueWaitResult result = MessageQueueMessageReceived;
77 while (!loader->done() && result != MessageQueueTerminated)
Ben Murdoch591b9582013-07-10 11:41:44 +010078 result = runLoop.runInMode(workerGlobalScope, mode);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010079
80 if (!loader->done() && result == MessageQueueTerminated)
81 loader->cancel();
82}
83
84void WorkerThreadableLoader::cancel()
85{
86 m_bridge.cancel();
87}
88
89WorkerThreadableLoader::MainThreadBridge::MainThreadBridge(PassRefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, WorkerLoaderProxy& loaderProxy, const String& taskMode,
90 const ResourceRequest& request, const ThreadableLoaderOptions& options, const String& outgoingReferrer)
91 : m_workerClientWrapper(workerClientWrapper)
92 , m_loaderProxy(loaderProxy)
93 , m_taskMode(taskMode.isolatedCopy())
94{
95 ASSERT(m_workerClientWrapper.get());
96 m_loaderProxy.postTaskToLoader(
Ben Murdoch02772c62013-07-26 10:21:05 +010097 createCallbackTask(&MainThreadBridge::mainThreadCreateLoader,
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010098 AllowCrossThreadAccess(this), request, options, outgoingReferrer));
99}
100
101WorkerThreadableLoader::MainThreadBridge::~MainThreadBridge()
102{
103}
104
105void WorkerThreadableLoader::MainThreadBridge::mainThreadCreateLoader(ScriptExecutionContext* context, MainThreadBridge* thisPtr, PassOwnPtr<CrossThreadResourceRequestData> requestData, ThreadableLoaderOptions options, const String& outgoingReferrer)
106{
107 ASSERT(isMainThread());
108 Document* document = toDocument(context);
109
110 OwnPtr<ResourceRequest> request(ResourceRequest::adopt(requestData));
111 request->setHTTPReferrer(outgoingReferrer);
Ben Murdoche69819b2013-07-17 14:56:49 +0100112 options.requestInitiatorContext = WorkerContext;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100113 // FIXME: If the a site requests a local resource, then this will return a non-zero value but the sync path
114 // will return a 0 value. Either this should return 0 or the other code path should do a callback with
115 // a failure.
116 thisPtr->m_mainThreadLoader = DocumentThreadableLoader::create(document, thisPtr, *request, options);
117 ASSERT(thisPtr->m_mainThreadLoader);
118}
119
120void WorkerThreadableLoader::MainThreadBridge::mainThreadDestroy(ScriptExecutionContext* context, MainThreadBridge* thisPtr)
121{
122 ASSERT(isMainThread());
123 ASSERT_UNUSED(context, context->isDocument());
124 delete thisPtr;
125}
126
127void WorkerThreadableLoader::MainThreadBridge::destroy()
128{
129 // Ensure that no more client callbacks are done in the worker context's thread.
130 clearClientWrapper();
131
132 // "delete this" and m_mainThreadLoader::deref() on the worker object's thread.
133 m_loaderProxy.postTaskToLoader(
134 createCallbackTask(&MainThreadBridge::mainThreadDestroy, AllowCrossThreadAccess(this)));
135}
136
137void WorkerThreadableLoader::MainThreadBridge::mainThreadCancel(ScriptExecutionContext* context, MainThreadBridge* thisPtr)
138{
139 ASSERT(isMainThread());
140 ASSERT_UNUSED(context, context->isDocument());
141
142 if (!thisPtr->m_mainThreadLoader)
143 return;
144 thisPtr->m_mainThreadLoader->cancel();
145 thisPtr->m_mainThreadLoader = 0;
146}
147
148void WorkerThreadableLoader::MainThreadBridge::cancel()
149{
150 m_loaderProxy.postTaskToLoader(
151 createCallbackTask(&MainThreadBridge::mainThreadCancel, AllowCrossThreadAccess(this)));
152 ThreadableLoaderClientWrapper* clientWrapper = m_workerClientWrapper.get();
153 if (!clientWrapper->done()) {
154 // If the client hasn't reached a termination state, then transition it by sending a cancellation error.
155 // Note: no more client callbacks will be done after this method -- the clearClientWrapper() call ensures that.
156 ResourceError error(String(), 0, String(), String());
157 error.setIsCancellation(true);
158 clientWrapper->didFail(error);
159 }
160 clearClientWrapper();
161}
162
163void WorkerThreadableLoader::MainThreadBridge::clearClientWrapper()
164{
165 m_workerClientWrapper->clearClient();
166}
167
Ben Murdoch591b9582013-07-10 11:41:44 +0100168static void workerGlobalScopeDidSendData(ScriptExecutionContext* context, RefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100169{
Ben Murdoch591b9582013-07-10 11:41:44 +0100170 ASSERT_UNUSED(context, context->isWorkerGlobalScope());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100171 workerClientWrapper->didSendData(bytesSent, totalBytesToBeSent);
172}
173
174void WorkerThreadableLoader::MainThreadBridge::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
175{
Ben Murdoch591b9582013-07-10 11:41:44 +0100176 m_loaderProxy.postTaskForModeToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidSendData, m_workerClientWrapper, bytesSent, totalBytesToBeSent), m_taskMode);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100177}
178
Ben Murdoch591b9582013-07-10 11:41:44 +0100179static void workerGlobalScopeDidReceiveResponse(ScriptExecutionContext* context, RefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, unsigned long identifier, PassOwnPtr<CrossThreadResourceResponseData> responseData)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100180{
Ben Murdoch591b9582013-07-10 11:41:44 +0100181 ASSERT_UNUSED(context, context->isWorkerGlobalScope());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100182 OwnPtr<ResourceResponse> response(ResourceResponse::adopt(responseData));
183 workerClientWrapper->didReceiveResponse(identifier, *response);
184}
185
186void WorkerThreadableLoader::MainThreadBridge::didReceiveResponse(unsigned long identifier, const ResourceResponse& response)
187{
Ben Murdoch591b9582013-07-10 11:41:44 +0100188 m_loaderProxy.postTaskForModeToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidReceiveResponse, m_workerClientWrapper, identifier, response), m_taskMode);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100189}
190
Ben Murdoch591b9582013-07-10 11:41:44 +0100191static void workerGlobalScopeDidReceiveData(ScriptExecutionContext* context, RefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, PassOwnPtr<Vector<char> > vectorData)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100192{
Ben Murdoch591b9582013-07-10 11:41:44 +0100193 ASSERT_UNUSED(context, context->isWorkerGlobalScope());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100194 workerClientWrapper->didReceiveData(vectorData->data(), vectorData->size());
195}
196
197void WorkerThreadableLoader::MainThreadBridge::didReceiveData(const char* data, int dataLength)
198{
199 OwnPtr<Vector<char> > vector = adoptPtr(new Vector<char>(dataLength)); // needs to be an OwnPtr for usage with createCallbackTask.
200 memcpy(vector->data(), data, dataLength);
Ben Murdoch591b9582013-07-10 11:41:44 +0100201 m_loaderProxy.postTaskForModeToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidReceiveData, m_workerClientWrapper, vector.release()), m_taskMode);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100202}
203
Ben Murdoch591b9582013-07-10 11:41:44 +0100204static void workerGlobalScopeDidReceiveCachedMetadata(ScriptExecutionContext* context, RefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, PassOwnPtr<Vector<char> > vectorData)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100205{
Ben Murdoch591b9582013-07-10 11:41:44 +0100206 ASSERT_UNUSED(context, context->isWorkerGlobalScope());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100207 workerClientWrapper->didReceiveCachedMetadata(vectorData->data(), vectorData->size());
208}
209
210void WorkerThreadableLoader::MainThreadBridge::didReceiveCachedMetadata(const char* data, int dataLength)
211{
212 OwnPtr<Vector<char> > vector = adoptPtr(new Vector<char>(dataLength)); // needs to be an OwnPtr for usage with createCallbackTask.
213 memcpy(vector->data(), data, dataLength);
Ben Murdoch591b9582013-07-10 11:41:44 +0100214 m_loaderProxy.postTaskForModeToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidReceiveCachedMetadata, m_workerClientWrapper, vector.release()), m_taskMode);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100215}
216
Ben Murdoch591b9582013-07-10 11:41:44 +0100217static void workerGlobalScopeDidFinishLoading(ScriptExecutionContext* context, RefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, unsigned long identifier, double finishTime)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100218{
Ben Murdoch591b9582013-07-10 11:41:44 +0100219 ASSERT_UNUSED(context, context->isWorkerGlobalScope());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100220 workerClientWrapper->didFinishLoading(identifier, finishTime);
221}
222
223void WorkerThreadableLoader::MainThreadBridge::didFinishLoading(unsigned long identifier, double finishTime)
224{
Ben Murdoch591b9582013-07-10 11:41:44 +0100225 m_loaderProxy.postTaskForModeToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidFinishLoading, m_workerClientWrapper, identifier, finishTime), m_taskMode);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100226}
227
Ben Murdoch591b9582013-07-10 11:41:44 +0100228static void workerGlobalScopeDidFail(ScriptExecutionContext* context, RefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, const ResourceError& error)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100229{
Ben Murdoch591b9582013-07-10 11:41:44 +0100230 ASSERT_UNUSED(context, context->isWorkerGlobalScope());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100231 workerClientWrapper->didFail(error);
232}
233
234void WorkerThreadableLoader::MainThreadBridge::didFail(const ResourceError& error)
235{
Ben Murdoch591b9582013-07-10 11:41:44 +0100236 m_loaderProxy.postTaskForModeToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidFail, m_workerClientWrapper, error), m_taskMode);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100237}
238
Ben Murdoch591b9582013-07-10 11:41:44 +0100239static void workerGlobalScopeDidFailAccessControlCheck(ScriptExecutionContext* context, PassRefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, const ResourceError& error)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100240{
Ben Murdoch591b9582013-07-10 11:41:44 +0100241 ASSERT_UNUSED(context, context->isWorkerGlobalScope());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100242 workerClientWrapper->didFailAccessControlCheck(error);
243}
244
245void WorkerThreadableLoader::MainThreadBridge::didFailAccessControlCheck(const ResourceError& error)
246{
Ben Murdoch591b9582013-07-10 11:41:44 +0100247 m_loaderProxy.postTaskForModeToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidFailAccessControlCheck, m_workerClientWrapper, error), m_taskMode);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100248}
249
Ben Murdoch591b9582013-07-10 11:41:44 +0100250static void workerGlobalScopeDidFailRedirectCheck(ScriptExecutionContext* context, RefPtr<ThreadableLoaderClientWrapper> workerClientWrapper)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100251{
Ben Murdoch591b9582013-07-10 11:41:44 +0100252 ASSERT_UNUSED(context, context->isWorkerGlobalScope());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100253 workerClientWrapper->didFailRedirectCheck();
254}
255
256void WorkerThreadableLoader::MainThreadBridge::didFailRedirectCheck()
257{
Ben Murdoch591b9582013-07-10 11:41:44 +0100258 m_loaderProxy.postTaskForModeToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidFailRedirectCheck, m_workerClientWrapper), m_taskMode);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100259}
260
261} // namespace WebCore