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 WebCore { 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::cancel() 99 { 100 m_bridge.cancel(); 101 } 102 103 WorkerThreadableLoader::MainThreadBridge::MainThreadBridge( 104 PassRefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, 105 PassOwnPtr<ThreadableLoaderClient> clientBridge, 106 WorkerLoaderProxy& loaderProxy, 107 const ResourceRequest& request, 108 const ThreadableLoaderOptions& options, 109 const ResourceLoaderOptions& resourceLoaderOptions, 110 const String& outgoingReferrer) 111 : m_clientBridge(clientBridge) 112 , m_workerClientWrapper(workerClientWrapper) 113 , m_loaderProxy(loaderProxy) 114 { 115 ASSERT(m_workerClientWrapper.get()); 116 ASSERT(m_clientBridge.get()); 117 m_loaderProxy.postTaskToLoader( 118 createCallbackTask(&MainThreadBridge::mainThreadCreateLoader, AllowCrossThreadAccess(this), request, options, resourceLoaderOptions, outgoingReferrer)); 119 } 120 121 WorkerThreadableLoader::MainThreadBridge::~MainThreadBridge() 122 { 123 } 124 125 void WorkerThreadableLoader::MainThreadBridge::mainThreadCreateLoader(ExecutionContext* context, MainThreadBridge* thisPtr, PassOwnPtr<CrossThreadResourceRequestData> requestData, ThreadableLoaderOptions options, ResourceLoaderOptions resourceLoaderOptions, const String& outgoingReferrer) 126 { 127 ASSERT(isMainThread()); 128 Document* document = toDocument(context); 129 130 OwnPtr<ResourceRequest> request(ResourceRequest::adopt(requestData)); 131 request->setHTTPReferrer(Referrer(outgoingReferrer, ReferrerPolicyDefault)); 132 resourceLoaderOptions.requestInitiatorContext = WorkerContext; 133 thisPtr->m_mainThreadLoader = DocumentThreadableLoader::create(*document, thisPtr, *request, options, resourceLoaderOptions); 134 if (!thisPtr->m_mainThreadLoader) { 135 // DocumentThreadableLoader::create may return 0 when the document loader has been already changed. 136 thisPtr->didFail(ResourceError(errorDomainBlinkInternal, 0, request->url().string(), "Can't create DocumentThreadableLoader")); 137 } 138 } 139 140 void WorkerThreadableLoader::MainThreadBridge::mainThreadDestroy(ExecutionContext* context, MainThreadBridge* thisPtr) 141 { 142 ASSERT(isMainThread()); 143 ASSERT_UNUSED(context, context->isDocument()); 144 delete thisPtr; 145 } 146 147 void WorkerThreadableLoader::MainThreadBridge::destroy() 148 { 149 // Ensure that no more client callbacks are done in the worker context's thread. 150 clearClientWrapper(); 151 152 // "delete this" and m_mainThreadLoader::deref() on the worker object's thread. 153 m_loaderProxy.postTaskToLoader( 154 createCallbackTask(&MainThreadBridge::mainThreadDestroy, AllowCrossThreadAccess(this))); 155 } 156 157 void WorkerThreadableLoader::MainThreadBridge::mainThreadCancel(ExecutionContext* context, MainThreadBridge* thisPtr) 158 { 159 ASSERT(isMainThread()); 160 ASSERT_UNUSED(context, context->isDocument()); 161 162 if (!thisPtr->m_mainThreadLoader) 163 return; 164 thisPtr->m_mainThreadLoader->cancel(); 165 thisPtr->m_mainThreadLoader = nullptr; 166 } 167 168 void WorkerThreadableLoader::MainThreadBridge::cancel() 169 { 170 m_loaderProxy.postTaskToLoader( 171 createCallbackTask(&MainThreadBridge::mainThreadCancel, AllowCrossThreadAccess(this))); 172 ThreadableLoaderClientWrapper* clientWrapper = m_workerClientWrapper.get(); 173 if (!clientWrapper->done()) { 174 // If the client hasn't reached a termination state, then transition it by sending a cancellation error. 175 // Note: no more client callbacks will be done after this method -- the clearClientWrapper() call ensures that. 176 ResourceError error(String(), 0, String(), String()); 177 error.setIsCancellation(true); 178 clientWrapper->didFail(error); 179 } 180 clearClientWrapper(); 181 } 182 183 void WorkerThreadableLoader::MainThreadBridge::clearClientWrapper() 184 { 185 m_workerClientWrapper->clearClient(); 186 } 187 188 void WorkerThreadableLoader::MainThreadBridge::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent) 189 { 190 m_clientBridge->didSendData(bytesSent, totalBytesToBeSent); 191 } 192 193 void WorkerThreadableLoader::MainThreadBridge::didReceiveResponse(unsigned long identifier, const ResourceResponse& response) 194 { 195 m_clientBridge->didReceiveResponse(identifier, response); 196 } 197 198 void WorkerThreadableLoader::MainThreadBridge::didReceiveData(const char* data, int dataLength) 199 { 200 m_clientBridge->didReceiveData(data, dataLength); 201 } 202 203 void WorkerThreadableLoader::MainThreadBridge::didDownloadData(int dataLength) 204 { 205 m_clientBridge->didDownloadData(dataLength); 206 } 207 208 void WorkerThreadableLoader::MainThreadBridge::didReceiveCachedMetadata(const char* data, int dataLength) 209 { 210 m_clientBridge->didReceiveCachedMetadata(data, dataLength); 211 } 212 213 void WorkerThreadableLoader::MainThreadBridge::didFinishLoading(unsigned long identifier, double finishTime) 214 { 215 m_clientBridge->didFinishLoading(identifier, finishTime); 216 } 217 218 void WorkerThreadableLoader::MainThreadBridge::didFail(const ResourceError& error) 219 { 220 m_clientBridge->didFail(error); 221 } 222 223 void WorkerThreadableLoader::MainThreadBridge::didFailAccessControlCheck(const ResourceError& error) 224 { 225 m_clientBridge->didFailAccessControlCheck(error); 226 } 227 228 void WorkerThreadableLoader::MainThreadBridge::didFailRedirectCheck() 229 { 230 m_clientBridge->didFailRedirectCheck(); 231 } 232 233 } // namespace WebCore 234