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 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