Home | History | Annotate | Download | only in loader
      1 /*
      2  * Copyright (C) 2006, 2007, 2009 Apple 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
      6  * are met:
      7  *
      8  * 1.  Redistributions of source code must retain the above copyright
      9  *     notice, this list of conditions and the following disclaimer.
     10  * 2.  Redistributions in binary form must reproduce the above copyright
     11  *     notice, this list of conditions and the following disclaimer in the
     12  *     documentation and/or other materials provided with the distribution.
     13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
     14  *     its contributors may be used to endorse or promote products derived
     15  *     from this software without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include "config.h"
     30 #include "SubresourceLoader.h"
     31 
     32 #include "DocumentLoader.h"
     33 #include "Frame.h"
     34 #include "FrameLoader.h"
     35 #include "ResourceHandle.h"
     36 #include "SecurityOrigin.h"
     37 #include "SubresourceLoaderClient.h"
     38 #include <wtf/RefCountedLeakCounter.h>
     39 
     40 namespace WebCore {
     41 
     42 #ifndef NDEBUG
     43 static WTF::RefCountedLeakCounter subresourceLoaderCounter("SubresourceLoader");
     44 #endif
     45 
     46 SubresourceLoader::SubresourceLoader(Frame* frame, SubresourceLoaderClient* client, bool sendResourceLoadCallbacks, bool shouldContentSniff)
     47     : ResourceLoader(frame, sendResourceLoadCallbacks, shouldContentSniff)
     48     , m_client(client)
     49     , m_loadingMultipartContent(false)
     50 {
     51 #ifndef NDEBUG
     52     subresourceLoaderCounter.increment();
     53 #endif
     54     m_documentLoader->addSubresourceLoader(this);
     55 }
     56 
     57 SubresourceLoader::~SubresourceLoader()
     58 {
     59 #ifndef NDEBUG
     60     subresourceLoaderCounter.decrement();
     61 #endif
     62 }
     63 
     64 PassRefPtr<SubresourceLoader> SubresourceLoader::create(Frame* frame, SubresourceLoaderClient* client, const ResourceRequest& request, SecurityCheckPolicy securityCheck, bool sendResourceLoadCallbacks, bool shouldContentSniff)
     65 {
     66     if (!frame)
     67         return 0;
     68 
     69     FrameLoader* fl = frame->loader();
     70     if (securityCheck == DoSecurityCheck && (fl->state() == FrameStateProvisional || fl->activeDocumentLoader()->isStopping()))
     71         return 0;
     72 
     73     ResourceRequest newRequest = request;
     74 
     75     if (securityCheck == DoSecurityCheck
     76             && SecurityOrigin::restrictAccessToLocal()
     77             && !SecurityOrigin::canLoad(request.url(), String(), frame->document())) {
     78         FrameLoader::reportLocalLoadFailed(frame, request.url().string());
     79         return 0;
     80     }
     81 
     82     if (SecurityOrigin::shouldHideReferrer(request.url(), fl->outgoingReferrer()))
     83         newRequest.clearHTTPReferrer();
     84 #ifdef ANDROID_FIX
     85     else if (request.httpReferrer().isEmpty())
     86 #else
     87     else if (!request.httpReferrer())
     88 #endif
     89         newRequest.setHTTPReferrer(fl->outgoingReferrer());
     90     FrameLoader::addHTTPOriginIfNeeded(newRequest, fl->outgoingOrigin());
     91 
     92     // Use the original request's cache policy for two reasons:
     93     // 1. For POST requests, we mutate the cache policy for the main resource,
     94     //    but we do not want this to apply to subresources
     95     // 2. Delegates that modify the cache policy using willSendRequest: should
     96     //    not affect any other resources. Such changes need to be done
     97     //    per request.
     98     if (newRequest.isConditional())
     99         newRequest.setCachePolicy(ReloadIgnoringCacheData);
    100     else
    101         newRequest.setCachePolicy(fl->originalRequest().cachePolicy());
    102 
    103     fl->addExtraFieldsToSubresourceRequest(newRequest);
    104 
    105     RefPtr<SubresourceLoader> subloader(adoptRef(new SubresourceLoader(frame, client, sendResourceLoadCallbacks, shouldContentSniff)));
    106     if (!subloader->load(newRequest))
    107         return 0;
    108 
    109     return subloader.release();
    110 }
    111 
    112 void SubresourceLoader::willSendRequest(ResourceRequest& newRequest, const ResourceResponse& redirectResponse)
    113 {
    114     // Store the previous URL because the call to ResourceLoader::willSendRequest will modify it.
    115     KURL previousURL = request().url();
    116 
    117     ResourceLoader::willSendRequest(newRequest, redirectResponse);
    118     if (!previousURL.isNull() && !newRequest.isNull() && previousURL != newRequest.url() && m_client)
    119         m_client->willSendRequest(this, newRequest, redirectResponse);
    120 }
    121 
    122 void SubresourceLoader::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
    123 {
    124     RefPtr<SubresourceLoader> protect(this);
    125 
    126     if (m_client)
    127         m_client->didSendData(this, bytesSent, totalBytesToBeSent);
    128 }
    129 
    130 void SubresourceLoader::didReceiveResponse(const ResourceResponse& r)
    131 {
    132     ASSERT(!r.isNull());
    133 
    134     if (r.isMultipart())
    135         m_loadingMultipartContent = true;
    136 
    137     // Reference the object in this method since the additional processing can do
    138     // anything including removing the last reference to this object; one example of this is 3266216.
    139     RefPtr<SubresourceLoader> protect(this);
    140 
    141     if (m_client)
    142         m_client->didReceiveResponse(this, r);
    143 
    144     // The loader can cancel a load if it receives a multipart response for a non-image
    145     if (reachedTerminalState())
    146         return;
    147     ResourceLoader::didReceiveResponse(r);
    148 
    149     RefPtr<SharedBuffer> buffer = resourceData();
    150     if (m_loadingMultipartContent && buffer && buffer->size()) {
    151         // Since a subresource loader does not load multipart sections progressively,
    152         // deliver the previously received data to the loader all at once now.
    153         // Then clear the data to make way for the next multipart section.
    154         if (m_client)
    155             m_client->didReceiveData(this, buffer->data(), buffer->size());
    156         clearResourceData();
    157 
    158         // After the first multipart section is complete, signal to delegates that this load is "finished"
    159         m_documentLoader->subresourceLoaderFinishedLoadingOnePart(this);
    160         didFinishLoadingOnePart();
    161     }
    162 }
    163 
    164 void SubresourceLoader::didReceiveData(const char* data, int length, long long lengthReceived, bool allAtOnce)
    165 {
    166     // Reference the object in this method since the additional processing can do
    167     // anything including removing the last reference to this object; one example of this is 3266216.
    168     RefPtr<SubresourceLoader> protect(this);
    169 
    170     ResourceLoader::didReceiveData(data, length, lengthReceived, allAtOnce);
    171 
    172     // A subresource loader does not load multipart sections progressively.
    173     // So don't deliver any data to the loader yet.
    174     if (!m_loadingMultipartContent && m_client)
    175         m_client->didReceiveData(this, data, length);
    176 }
    177 
    178 void SubresourceLoader::didFinishLoading()
    179 {
    180     if (cancelled())
    181         return;
    182     ASSERT(!reachedTerminalState());
    183 
    184     // Calling removeSubresourceLoader will likely result in a call to deref, so we must protect ourselves.
    185     RefPtr<SubresourceLoader> protect(this);
    186 
    187     if (m_client)
    188         m_client->didFinishLoading(this);
    189 
    190     m_handle = 0;
    191 
    192     if (cancelled())
    193         return;
    194     m_documentLoader->removeSubresourceLoader(this);
    195     ResourceLoader::didFinishLoading();
    196 }
    197 
    198 void SubresourceLoader::didFail(const ResourceError& error)
    199 {
    200     if (cancelled())
    201         return;
    202     ASSERT(!reachedTerminalState());
    203 
    204     // Calling removeSubresourceLoader will likely result in a call to deref, so we must protect ourselves.
    205     RefPtr<SubresourceLoader> protect(this);
    206 
    207     if (m_client)
    208         m_client->didFail(this, error);
    209 
    210     m_handle = 0;
    211 
    212     if (cancelled())
    213         return;
    214     m_documentLoader->removeSubresourceLoader(this);
    215     ResourceLoader::didFail(error);
    216 }
    217 
    218 void SubresourceLoader::didCancel(const ResourceError& error)
    219 {
    220     ASSERT(!reachedTerminalState());
    221 
    222     // Calling removeSubresourceLoader will likely result in a call to deref, so we must protect ourselves.
    223     RefPtr<SubresourceLoader> protect(this);
    224 
    225     if (m_client)
    226         m_client->didFail(this, error);
    227 
    228     if (cancelled())
    229         return;
    230 
    231     // The only way the subresource loader can reach the terminal state here is if the run loop spins when calling
    232     // m_client->didFail. This should in theory not happen which is why the assert is here.
    233     ASSERT(!reachedTerminalState());
    234     if (reachedTerminalState())
    235         return;
    236 
    237     m_documentLoader->removeSubresourceLoader(this);
    238     ResourceLoader::didCancel(error);
    239 }
    240 
    241 bool SubresourceLoader::shouldUseCredentialStorage()
    242 {
    243     RefPtr<SubresourceLoader> protect(this);
    244 
    245     bool shouldUse;
    246     if (m_client && m_client->getShouldUseCredentialStorage(this, shouldUse))
    247         return shouldUse;
    248 
    249     return ResourceLoader::shouldUseCredentialStorage();
    250 }
    251 
    252 void SubresourceLoader::didReceiveAuthenticationChallenge(const AuthenticationChallenge& challenge)
    253 {
    254     RefPtr<SubresourceLoader> protect(this);
    255 
    256     if (m_client)
    257         m_client->didReceiveAuthenticationChallenge(this, challenge);
    258 
    259     // The SubResourceLoaderClient may have cancelled this ResourceLoader in response to the challenge.
    260     // If that's the case, don't call didReceiveAuthenticationChallenge
    261     if (reachedTerminalState())
    262         return;
    263 
    264     ResourceLoader::didReceiveAuthenticationChallenge(challenge);
    265 }
    266 
    267 void SubresourceLoader::receivedCancellation(const AuthenticationChallenge& challenge)
    268 {
    269     ASSERT(!reachedTerminalState());
    270 
    271     RefPtr<SubresourceLoader> protect(this);
    272 
    273     if (m_client)
    274         m_client->receivedCancellation(this, challenge);
    275 
    276     ResourceLoader::receivedCancellation(challenge);
    277 }
    278 
    279 
    280 }
    281