1 /*
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/WorkerLoaderClientBridgeSyncHelper.h"
39 #include "core/workers/WorkerGlobalScope.h"
40 #include "core/workers/WorkerLoaderProxy.h"
41 #include "core/workers/WorkerThread.h"
42 #include "platform/network/ResourceError.h"
43 #include "platform/network/ResourceRequest.h"
44 #include "platform/network/ResourceResponse.h"
45 #include "platform/weborigin/Referrer.h"
46 #include "public/platform/Platform.h"
47 #include "public/platform/WebWaitableEvent.h"
48 #include "wtf/MainThread.h"
49 #include "wtf/OwnPtr.h"
50 #include "wtf/Vector.h"
51
52 namespace blink {
53
WorkerThreadableLoader(WorkerGlobalScope & workerGlobalScope,PassRefPtr<ThreadableLoaderClientWrapper> clientWrapper,PassOwnPtr<ThreadableLoaderClient> clientBridge,const ResourceRequest & request,const ThreadableLoaderOptions & options,const ResourceLoaderOptions & resourceLoaderOptions)54 WorkerThreadableLoader::WorkerThreadableLoader(WorkerGlobalScope& workerGlobalScope, PassRefPtr<ThreadableLoaderClientWrapper> clientWrapper, PassOwnPtr<ThreadableLoaderClient> clientBridge, const ResourceRequest& request, const ThreadableLoaderOptions& options, const ResourceLoaderOptions& resourceLoaderOptions)
55 : m_workerGlobalScope(&workerGlobalScope)
56 , m_workerClientWrapper(clientWrapper)
57 , m_bridge(*(new MainThreadBridge(m_workerClientWrapper, clientBridge, workerGlobalScope.thread()->workerLoaderProxy(), request, options, resourceLoaderOptions, workerGlobalScope.url().strippedForUseAsReferrer())))
58 {
59 }
60
~WorkerThreadableLoader()61 WorkerThreadableLoader::~WorkerThreadableLoader()
62 {
63 m_bridge.destroy();
64 }
65
loadResourceSynchronously(WorkerGlobalScope & workerGlobalScope,const ResourceRequest & request,ThreadableLoaderClient & client,const ThreadableLoaderOptions & options,const ResourceLoaderOptions & resourceLoaderOptions)66 void WorkerThreadableLoader::loadResourceSynchronously(WorkerGlobalScope& workerGlobalScope, const ResourceRequest& request, ThreadableLoaderClient& client, const ThreadableLoaderOptions& options, const ResourceLoaderOptions& resourceLoaderOptions)
67 {
68 blink::WebWaitableEvent* shutdownEvent =
69 workerGlobalScope.thread()->shutdownEvent();
70 OwnPtr<blink::WebWaitableEvent> loaderDone =
71 adoptPtr(blink::Platform::current()->createWaitableEvent());
72
73 Vector<blink::WebWaitableEvent*> events;
74 events.append(shutdownEvent);
75 events.append(loaderDone.get());
76
77 RefPtr<ThreadableLoaderClientWrapper> clientWrapper(ThreadableLoaderClientWrapper::create(&client));
78 OwnPtr<WorkerLoaderClientBridgeSyncHelper> clientBridge(WorkerLoaderClientBridgeSyncHelper::create(client, loaderDone.release()));
79
80 // This must be valid while loader is around.
81 WorkerLoaderClientBridgeSyncHelper* clientBridgePtr = clientBridge.get();
82
83 RefPtr<WorkerThreadableLoader> loader = WorkerThreadableLoader::create(workerGlobalScope, clientWrapper, clientBridge.release(), request, options, resourceLoaderOptions);
84
85 blink::WebWaitableEvent* signalled;
86 {
87 ThreadState::SafePointScope scope(ThreadState::HeapPointersOnStack);
88 signalled = blink::Platform::current()->waitMultipleEvents(events);
89 }
90 if (signalled == shutdownEvent) {
91 loader->cancel();
92 return;
93 }
94
95 clientBridgePtr->run();
96 }
97
overrideTimeout(unsigned long timeoutMilliseconds)98 void WorkerThreadableLoader::overrideTimeout(unsigned long timeoutMilliseconds)
99 {
100 m_bridge.overrideTimeout(timeoutMilliseconds);
101 }
102
cancel()103 void WorkerThreadableLoader::cancel()
104 {
105 m_bridge.cancel();
106 }
107
MainThreadBridge(PassRefPtr<ThreadableLoaderClientWrapper> workerClientWrapper,PassOwnPtr<ThreadableLoaderClient> clientBridge,WorkerLoaderProxy & loaderProxy,const ResourceRequest & request,const ThreadableLoaderOptions & options,const ResourceLoaderOptions & resourceLoaderOptions,const String & outgoingReferrer)108 WorkerThreadableLoader::MainThreadBridge::MainThreadBridge(
109 PassRefPtr<ThreadableLoaderClientWrapper> workerClientWrapper,
110 PassOwnPtr<ThreadableLoaderClient> clientBridge,
111 WorkerLoaderProxy& loaderProxy,
112 const ResourceRequest& request,
113 const ThreadableLoaderOptions& options,
114 const ResourceLoaderOptions& resourceLoaderOptions,
115 const String& outgoingReferrer)
116 : m_clientBridge(clientBridge)
117 , m_workerClientWrapper(workerClientWrapper)
118 , m_loaderProxy(loaderProxy)
119 {
120 ASSERT(m_workerClientWrapper.get());
121 ASSERT(m_clientBridge.get());
122 m_loaderProxy.postTaskToLoader(
123 createCrossThreadTask(&MainThreadBridge::mainThreadCreateLoader, AllowCrossThreadAccess(this), request, options, resourceLoaderOptions, outgoingReferrer));
124 }
125
~MainThreadBridge()126 WorkerThreadableLoader::MainThreadBridge::~MainThreadBridge()
127 {
128 }
129
mainThreadCreateLoader(ExecutionContext * context,MainThreadBridge * thisPtr,PassOwnPtr<CrossThreadResourceRequestData> requestData,ThreadableLoaderOptions options,ResourceLoaderOptions resourceLoaderOptions,const String & outgoingReferrer)130 void WorkerThreadableLoader::MainThreadBridge::mainThreadCreateLoader(ExecutionContext* context, MainThreadBridge* thisPtr, PassOwnPtr<CrossThreadResourceRequestData> requestData, ThreadableLoaderOptions options, ResourceLoaderOptions resourceLoaderOptions, const String& outgoingReferrer)
131 {
132 ASSERT(isMainThread());
133 Document* document = toDocument(context);
134
135 OwnPtr<ResourceRequest> request(ResourceRequest::adopt(requestData));
136 request->setHTTPReferrer(Referrer(outgoingReferrer, ReferrerPolicyDefault));
137 resourceLoaderOptions.requestInitiatorContext = WorkerContext;
138 thisPtr->m_mainThreadLoader = DocumentThreadableLoader::create(*document, thisPtr, *request, options, resourceLoaderOptions);
139 if (!thisPtr->m_mainThreadLoader) {
140 // DocumentThreadableLoader::create may return 0 when the document loader has been already changed.
141 thisPtr->didFail(ResourceError(errorDomainBlinkInternal, 0, request->url().string(), "Can't create DocumentThreadableLoader"));
142 }
143 }
144
mainThreadDestroy(ExecutionContext * context,MainThreadBridge * thisPtr)145 void WorkerThreadableLoader::MainThreadBridge::mainThreadDestroy(ExecutionContext* context, MainThreadBridge* thisPtr)
146 {
147 ASSERT(isMainThread());
148 ASSERT_UNUSED(context, context->isDocument());
149 delete thisPtr;
150 }
151
destroy()152 void WorkerThreadableLoader::MainThreadBridge::destroy()
153 {
154 // Ensure that no more client callbacks are done in the worker context's thread.
155 clearClientWrapper();
156
157 // "delete this" and m_mainThreadLoader::deref() on the worker object's thread.
158 m_loaderProxy.postTaskToLoader(
159 createCrossThreadTask(&MainThreadBridge::mainThreadDestroy, AllowCrossThreadAccess(this)));
160 }
161
mainThreadOverrideTimeout(ExecutionContext * context,MainThreadBridge * thisPtr,unsigned long timeoutMilliseconds)162 void WorkerThreadableLoader::MainThreadBridge::mainThreadOverrideTimeout(ExecutionContext* context, MainThreadBridge* thisPtr, unsigned long timeoutMilliseconds)
163 {
164 ASSERT(isMainThread());
165 ASSERT_UNUSED(context, context->isDocument());
166
167 if (!thisPtr->m_mainThreadLoader)
168 return;
169 thisPtr->m_mainThreadLoader->overrideTimeout(timeoutMilliseconds);
170 }
171
overrideTimeout(unsigned long timeoutMilliseconds)172 void WorkerThreadableLoader::MainThreadBridge::overrideTimeout(unsigned long timeoutMilliseconds)
173 {
174 m_loaderProxy.postTaskToLoader(
175 createCrossThreadTask(&MainThreadBridge::mainThreadOverrideTimeout, AllowCrossThreadAccess(this),
176 timeoutMilliseconds));
177 }
178
mainThreadCancel(ExecutionContext * context,MainThreadBridge * thisPtr)179 void WorkerThreadableLoader::MainThreadBridge::mainThreadCancel(ExecutionContext* context, MainThreadBridge* thisPtr)
180 {
181 ASSERT(isMainThread());
182 ASSERT_UNUSED(context, context->isDocument());
183
184 if (!thisPtr->m_mainThreadLoader)
185 return;
186 thisPtr->m_mainThreadLoader->cancel();
187 thisPtr->m_mainThreadLoader = nullptr;
188 }
189
cancel()190 void WorkerThreadableLoader::MainThreadBridge::cancel()
191 {
192 m_loaderProxy.postTaskToLoader(
193 createCrossThreadTask(&MainThreadBridge::mainThreadCancel, AllowCrossThreadAccess(this)));
194 ThreadableLoaderClientWrapper* clientWrapper = m_workerClientWrapper.get();
195 if (!clientWrapper->done()) {
196 // If the client hasn't reached a termination state, then transition it by sending a cancellation error.
197 // Note: no more client callbacks will be done after this method -- the clearClientWrapper() call ensures that.
198 ResourceError error(String(), 0, String(), String());
199 error.setIsCancellation(true);
200 clientWrapper->didFail(error);
201 }
202 clearClientWrapper();
203 }
204
clearClientWrapper()205 void WorkerThreadableLoader::MainThreadBridge::clearClientWrapper()
206 {
207 m_workerClientWrapper->clearClient();
208 }
209
didSendData(unsigned long long bytesSent,unsigned long long totalBytesToBeSent)210 void WorkerThreadableLoader::MainThreadBridge::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
211 {
212 m_clientBridge->didSendData(bytesSent, totalBytesToBeSent);
213 }
214
didReceiveResponse(unsigned long identifier,const ResourceResponse & response)215 void WorkerThreadableLoader::MainThreadBridge::didReceiveResponse(unsigned long identifier, const ResourceResponse& response)
216 {
217 m_clientBridge->didReceiveResponse(identifier, response);
218 }
219
didReceiveData(const char * data,int dataLength)220 void WorkerThreadableLoader::MainThreadBridge::didReceiveData(const char* data, int dataLength)
221 {
222 m_clientBridge->didReceiveData(data, dataLength);
223 }
224
didDownloadData(int dataLength)225 void WorkerThreadableLoader::MainThreadBridge::didDownloadData(int dataLength)
226 {
227 m_clientBridge->didDownloadData(dataLength);
228 }
229
didReceiveCachedMetadata(const char * data,int dataLength)230 void WorkerThreadableLoader::MainThreadBridge::didReceiveCachedMetadata(const char* data, int dataLength)
231 {
232 m_clientBridge->didReceiveCachedMetadata(data, dataLength);
233 }
234
didFinishLoading(unsigned long identifier,double finishTime)235 void WorkerThreadableLoader::MainThreadBridge::didFinishLoading(unsigned long identifier, double finishTime)
236 {
237 m_clientBridge->didFinishLoading(identifier, finishTime);
238 }
239
didFail(const ResourceError & error)240 void WorkerThreadableLoader::MainThreadBridge::didFail(const ResourceError& error)
241 {
242 m_clientBridge->didFail(error);
243 }
244
didFailAccessControlCheck(const ResourceError & error)245 void WorkerThreadableLoader::MainThreadBridge::didFailAccessControlCheck(const ResourceError& error)
246 {
247 m_clientBridge->didFailAccessControlCheck(error);
248 }
249
didFailRedirectCheck()250 void WorkerThreadableLoader::MainThreadBridge::didFailRedirectCheck()
251 {
252 m_clientBridge->didFailRedirectCheck();
253 }
254
255 } // namespace blink
256