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 }
     55 
     56 SubresourceLoader::~SubresourceLoader()
     57 {
     58 #ifndef NDEBUG
     59     subresourceLoaderCounter.decrement();
     60 #endif
     61 }
     62 
     63 PassRefPtr<SubresourceLoader> SubresourceLoader::create(Frame* frame, SubresourceLoaderClient* client, const ResourceRequest& request, SecurityCheckPolicy securityCheck, bool sendResourceLoadCallbacks, bool shouldContentSniff, const String& optionalOutgoingReferrer, bool shouldBufferData)
     64 {
     65     if (!frame)
     66         return 0;
     67 
     68     FrameLoader* fl = frame->loader();
     69     if (securityCheck == DoSecurityCheck && (fl->state() == FrameStateProvisional || !fl->activeDocumentLoader() || fl->activeDocumentLoader()->isStopping()))
     70         return 0;
     71 
     72     ResourceRequest newRequest = request;
     73 
     74     if (securityCheck == DoSecurityCheck && !frame->document()->securityOrigin()->canDisplay(request.url())) {
     75         FrameLoader::reportLocalLoadFailed(frame, request.url().string());
     76         return 0;
     77     }
     78 
     79     String outgoingReferrer;
     80     String outgoingOrigin;
     81     if (optionalOutgoingReferrer.isNull()) {
     82         outgoingReferrer = fl->outgoingReferrer();
     83         outgoingOrigin = fl->outgoingOrigin();
     84     } else {
     85         outgoingReferrer = optionalOutgoingReferrer;
     86         outgoingOrigin = SecurityOrigin::createFromString(outgoingReferrer)->toString();
     87     }
     88 
     89     if (SecurityOrigin::shouldHideReferrer(request.url(), outgoingReferrer))
     90         newRequest.clearHTTPReferrer();
     91     else if (!request.httpReferrer())
     92         newRequest.setHTTPReferrer(outgoingReferrer);
     93     FrameLoader::addHTTPOriginIfNeeded(newRequest, outgoingOrigin);
     94 
     95     fl->addExtraFieldsToSubresourceRequest(newRequest);
     96 
     97     RefPtr<SubresourceLoader> subloader(adoptRef(new SubresourceLoader(frame, client, sendResourceLoadCallbacks, shouldContentSniff)));
     98     subloader->setShouldBufferData(shouldBufferData);
     99     subloader->documentLoader()->addSubresourceLoader(subloader.get());
    100     if (!subloader->init(newRequest))
    101         return 0;
    102 
    103     return subloader.release();
    104 }
    105 
    106 void SubresourceLoader::willSendRequest(ResourceRequest& newRequest, const ResourceResponse& redirectResponse)
    107 {
    108     // Store the previous URL because the call to ResourceLoader::willSendRequest will modify it.
    109     KURL previousURL = request().url();
    110 
    111     ResourceLoader::willSendRequest(newRequest, redirectResponse);
    112     if (!previousURL.isNull() && !newRequest.isNull() && previousURL != newRequest.url() && m_client)
    113         m_client->willSendRequest(this, newRequest, redirectResponse);
    114 }
    115 
    116 void SubresourceLoader::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
    117 {
    118     RefPtr<SubresourceLoader> protect(this);
    119 
    120     if (m_client)
    121         m_client->didSendData(this, bytesSent, totalBytesToBeSent);
    122 }
    123 
    124 void SubresourceLoader::didReceiveResponse(const ResourceResponse& r)
    125 {
    126     ASSERT(!r.isNull());
    127 
    128     if (r.isMultipart())
    129         m_loadingMultipartContent = true;
    130 
    131     // Reference the object in this method since the additional processing can do
    132     // anything including removing the last reference to this object; one example of this is 3266216.
    133     RefPtr<SubresourceLoader> protect(this);
    134 
    135     if (m_client)
    136         m_client->didReceiveResponse(this, r);
    137 
    138     // The loader can cancel a load if it receives a multipart response for a non-image
    139     if (reachedTerminalState())
    140         return;
    141     ResourceLoader::didReceiveResponse(r);
    142 
    143     RefPtr<SharedBuffer> buffer = resourceData();
    144     if (m_loadingMultipartContent && buffer && buffer->size()) {
    145         // Since a subresource loader does not load multipart sections progressively,
    146         // deliver the previously received data to the loader all at once now.
    147         // Then clear the data to make way for the next multipart section.
    148         if (m_client)
    149             m_client->didReceiveData(this, buffer->data(), buffer->size());
    150         clearResourceData();
    151 
    152         // After the first multipart section is complete, signal to delegates that this load is "finished"
    153         m_documentLoader->subresourceLoaderFinishedLoadingOnePart(this);
    154         didFinishLoadingOnePart(0);
    155     }
    156 }
    157 
    158 void SubresourceLoader::didReceiveData(const char* data, int length, long long encodedDataLength, bool allAtOnce)
    159 {
    160     // Reference the object in this method since the additional processing can do
    161     // anything including removing the last reference to this object; one example of this is 3266216.
    162     RefPtr<SubresourceLoader> protect(this);
    163 
    164     ResourceLoader::didReceiveData(data, length, encodedDataLength, allAtOnce);
    165 
    166     // A subresource loader does not load multipart sections progressively.
    167     // So don't deliver any data to the loader yet.
    168     if (!m_loadingMultipartContent && m_client)
    169         m_client->didReceiveData(this, data, length);
    170 }
    171 
    172 void SubresourceLoader::didReceiveCachedMetadata(const char* data, int length)
    173 {
    174     // Reference the object in this method since the additional processing can do
    175     // anything including removing the last reference to this object; one example of this is 3266216.
    176     RefPtr<SubresourceLoader> protect(this);
    177 
    178     if (m_client)
    179         m_client->didReceiveCachedMetadata(this, data, length);
    180 }
    181 
    182 void SubresourceLoader::didFinishLoading(double finishTime)
    183 {
    184     if (cancelled())
    185         return;
    186     ASSERT(!reachedTerminalState());
    187 
    188     // Calling removeSubresourceLoader will likely result in a call to deref, so we must protect ourselves.
    189     RefPtr<SubresourceLoader> protect(this);
    190 
    191     if (m_client)
    192         m_client->didFinishLoading(this, finishTime);
    193 
    194     m_handle = 0;
    195 
    196     if (cancelled())
    197         return;
    198     m_documentLoader->removeSubresourceLoader(this);
    199     ResourceLoader::didFinishLoading(finishTime);
    200 }
    201 
    202 void SubresourceLoader::didFail(const ResourceError& error)
    203 {
    204     if (cancelled())
    205         return;
    206     ASSERT(!reachedTerminalState());
    207 
    208     // Calling removeSubresourceLoader will likely result in a call to deref, so we must protect ourselves.
    209     RefPtr<SubresourceLoader> protect(this);
    210 
    211     if (m_client)
    212         m_client->didFail(this, error);
    213 
    214     m_handle = 0;
    215 
    216     if (cancelled())
    217         return;
    218     m_documentLoader->removeSubresourceLoader(this);
    219     ResourceLoader::didFail(error);
    220 }
    221 
    222 void SubresourceLoader::didCancel(const ResourceError& error)
    223 {
    224     ASSERT(!reachedTerminalState());
    225 
    226     // Calling removeSubresourceLoader will likely result in a call to deref, so we must protect ourselves.
    227     RefPtr<SubresourceLoader> protect(this);
    228 
    229     if (m_client)
    230         m_client->didFail(this, error);
    231 
    232     if (cancelled())
    233         return;
    234 
    235     // The only way the subresource loader can reach the terminal state here is if the run loop spins when calling
    236     // m_client->didFail. This should in theory not happen which is why the assert is here.
    237     ASSERT(!reachedTerminalState());
    238     if (reachedTerminalState())
    239         return;
    240 
    241     m_documentLoader->removeSubresourceLoader(this);
    242     ResourceLoader::didCancel(error);
    243 }
    244 
    245 bool SubresourceLoader::shouldUseCredentialStorage()
    246 {
    247     RefPtr<SubresourceLoader> protect(this);
    248 
    249     bool shouldUse;
    250     if (m_client && m_client->getShouldUseCredentialStorage(this, shouldUse))
    251         return shouldUse;
    252 
    253     return ResourceLoader::shouldUseCredentialStorage();
    254 }
    255 
    256 void SubresourceLoader::didReceiveAuthenticationChallenge(const AuthenticationChallenge& challenge)
    257 {
    258     RefPtr<SubresourceLoader> protect(this);
    259 
    260     ASSERT(handle()->hasAuthenticationChallenge());
    261 
    262     if (m_client)
    263         m_client->didReceiveAuthenticationChallenge(this, challenge);
    264 
    265     // The SubResourceLoaderClient may have cancelled this ResourceLoader in response to the challenge.
    266     // If that's the case, don't call didReceiveAuthenticationChallenge.
    267     if (reachedTerminalState())
    268         return;
    269 
    270     // It may have also handled authentication on its own.
    271     if (!handle()->hasAuthenticationChallenge())
    272         return;
    273 
    274     ResourceLoader::didReceiveAuthenticationChallenge(challenge);
    275 }
    276 
    277 void SubresourceLoader::receivedCancellation(const AuthenticationChallenge& challenge)
    278 {
    279     ASSERT(!reachedTerminalState());
    280 
    281     RefPtr<SubresourceLoader> protect(this);
    282 
    283     if (m_client)
    284         m_client->receivedCancellation(this, challenge);
    285 
    286     ResourceLoader::receivedCancellation(challenge);
    287 }
    288 
    289 
    290 }
    291