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 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 61 WorkerThreadableLoader::~WorkerThreadableLoader() 62 { 63 m_bridge.destroy(); 64 } 65 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 98 void WorkerThreadableLoader::overrideTimeout(unsigned long timeoutMilliseconds) 99 { 100 m_bridge.overrideTimeout(timeoutMilliseconds); 101 } 102 103 void WorkerThreadableLoader::cancel() 104 { 105 m_bridge.cancel(); 106 } 107 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 126 WorkerThreadableLoader::MainThreadBridge::~MainThreadBridge() 127 { 128 } 129 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 145 void WorkerThreadableLoader::MainThreadBridge::mainThreadDestroy(ExecutionContext* context, MainThreadBridge* thisPtr) 146 { 147 ASSERT(isMainThread()); 148 ASSERT_UNUSED(context, context->isDocument()); 149 delete thisPtr; 150 } 151 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 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 172 void WorkerThreadableLoader::MainThreadBridge::overrideTimeout(unsigned long timeoutMilliseconds) 173 { 174 m_loaderProxy.postTaskToLoader( 175 createCrossThreadTask(&MainThreadBridge::mainThreadOverrideTimeout, AllowCrossThreadAccess(this), 176 timeoutMilliseconds)); 177 } 178 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 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 205 void WorkerThreadableLoader::MainThreadBridge::clearClientWrapper() 206 { 207 m_workerClientWrapper->clearClient(); 208 } 209 210 void WorkerThreadableLoader::MainThreadBridge::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent) 211 { 212 m_clientBridge->didSendData(bytesSent, totalBytesToBeSent); 213 } 214 215 void WorkerThreadableLoader::MainThreadBridge::didReceiveResponse(unsigned long identifier, const ResourceResponse& response) 216 { 217 m_clientBridge->didReceiveResponse(identifier, response); 218 } 219 220 void WorkerThreadableLoader::MainThreadBridge::didReceiveData(const char* data, int dataLength) 221 { 222 m_clientBridge->didReceiveData(data, dataLength); 223 } 224 225 void WorkerThreadableLoader::MainThreadBridge::didDownloadData(int dataLength) 226 { 227 m_clientBridge->didDownloadData(dataLength); 228 } 229 230 void WorkerThreadableLoader::MainThreadBridge::didReceiveCachedMetadata(const char* data, int dataLength) 231 { 232 m_clientBridge->didReceiveCachedMetadata(data, dataLength); 233 } 234 235 void WorkerThreadableLoader::MainThreadBridge::didFinishLoading(unsigned long identifier, double finishTime) 236 { 237 m_clientBridge->didFinishLoading(identifier, finishTime); 238 } 239 240 void WorkerThreadableLoader::MainThreadBridge::didFail(const ResourceError& error) 241 { 242 m_clientBridge->didFail(error); 243 } 244 245 void WorkerThreadableLoader::MainThreadBridge::didFailAccessControlCheck(const ResourceError& error) 246 { 247 m_clientBridge->didFailAccessControlCheck(error); 248 } 249 250 void WorkerThreadableLoader::MainThreadBridge::didFailRedirectCheck() 251 { 252 m_clientBridge->didFailRedirectCheck(); 253 } 254 255 } // namespace blink 256