Home | History | Annotate | Download | only in loader
      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