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