Home | History | Annotate | Download | only in cache
      1 /*
      2  * Copyright (C) 2011 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
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "core/loader/cache/RawResource.h"
     28 
     29 #include "core/loader/ResourceLoader.h"
     30 #include "core/loader/cache/ResourceClient.h"
     31 #include "core/loader/cache/ResourceClientWalker.h"
     32 #include "core/loader/cache/ResourceFetcher.h"
     33 #include "core/platform/SharedBuffer.h"
     34 
     35 namespace WebCore {
     36 
     37 RawResource::RawResource(const ResourceRequest& resourceRequest, Type type)
     38     : Resource(resourceRequest, type)
     39 {
     40 }
     41 
     42 void RawResource::appendData(const char* data, int length)
     43 {
     44     Resource::appendData(data, length);
     45 
     46     ResourcePtr<RawResource> protect(this);
     47     ResourceClientWalker<RawResourceClient> w(m_clients);
     48     while (RawResourceClient* c = w.next())
     49         c->dataReceived(this, data, length);
     50 }
     51 
     52 void RawResource::didAddClient(ResourceClient* c)
     53 {
     54     if (!hasClient(c))
     55         return;
     56     // The calls to the client can result in events running, potentially causing
     57     // this resource to be evicted from the cache and all clients to be removed,
     58     // so a protector is necessary.
     59     ResourcePtr<RawResource> protect(this);
     60     RawResourceClient* client = static_cast<RawResourceClient*>(c);
     61     size_t redirectCount = m_redirectChain.size();
     62     for (size_t i = 0; i < redirectCount; i++) {
     63         RedirectPair redirect = m_redirectChain[i];
     64         ResourceRequest request(redirect.m_request);
     65         client->redirectReceived(this, request, redirect.m_redirectResponse);
     66         if (!hasClient(c))
     67             return;
     68     }
     69     ASSERT(redirectCount == m_redirectChain.size());
     70 
     71     if (!m_response.isNull())
     72         client->responseReceived(this, m_response);
     73     if (!hasClient(c))
     74         return;
     75     if (m_data)
     76         client->dataReceived(this, m_data->data(), m_data->size());
     77     if (!hasClient(c))
     78         return;
     79     Resource::didAddClient(client);
     80 }
     81 
     82 void RawResource::willSendRequest(ResourceRequest& request, const ResourceResponse& response)
     83 {
     84     ResourcePtr<RawResource> protect(this);
     85     if (!response.isNull()) {
     86         ResourceClientWalker<RawResourceClient> w(m_clients);
     87         while (RawResourceClient* c = w.next())
     88             c->redirectReceived(this, request, response);
     89         m_redirectChain.append(RedirectPair(request, response));
     90     }
     91     Resource::willSendRequest(request, response);
     92 }
     93 
     94 void RawResource::responseReceived(const ResourceResponse& response)
     95 {
     96     ResourcePtr<RawResource> protect(this);
     97     Resource::responseReceived(response);
     98     ResourceClientWalker<RawResourceClient> w(m_clients);
     99     while (RawResourceClient* c = w.next())
    100         c->responseReceived(this, m_response);
    101 }
    102 
    103 void RawResource::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
    104 {
    105     ResourceClientWalker<RawResourceClient> w(m_clients);
    106     while (RawResourceClient* c = w.next())
    107         c->dataSent(this, bytesSent, totalBytesToBeSent);
    108 }
    109 
    110 void RawResource::didDownloadData(int dataLength)
    111 {
    112     ResourceClientWalker<RawResourceClient> w(m_clients);
    113     while (RawResourceClient* c = w.next())
    114         c->dataDownloaded(this, dataLength);
    115 }
    116 
    117 void RawResource::setDefersLoading(bool defers)
    118 {
    119     if (m_loader)
    120         m_loader->setDefersLoading(defers);
    121 }
    122 
    123 void RawResource::setDataBufferingPolicy(DataBufferingPolicy dataBufferingPolicy)
    124 {
    125     m_options.dataBufferingPolicy = dataBufferingPolicy;
    126     clear();
    127 }
    128 
    129 static bool shouldIgnoreHeaderForCacheReuse(AtomicString headerName)
    130 {
    131     // FIXME: This list of headers that don't affect cache policy almost certainly isn't complete.
    132     DEFINE_STATIC_LOCAL(HashSet<AtomicString>, m_headers, ());
    133     if (m_headers.isEmpty()) {
    134         m_headers.add("Accept");
    135         m_headers.add("Cache-Control");
    136         m_headers.add("If-Modified-Since");
    137         m_headers.add("If-None-Match");
    138         m_headers.add("Origin");
    139         m_headers.add("Pragma");
    140         m_headers.add("Purpose");
    141         m_headers.add("Referer");
    142         m_headers.add("User-Agent");
    143     }
    144     return m_headers.contains(headerName);
    145 }
    146 
    147 bool RawResource::canReuse(const ResourceRequest& newRequest) const
    148 {
    149     if (m_options.dataBufferingPolicy == DoNotBufferData)
    150         return false;
    151 
    152     if (m_resourceRequest.httpMethod() != newRequest.httpMethod())
    153         return false;
    154 
    155     if (m_resourceRequest.httpBody() != newRequest.httpBody())
    156         return false;
    157 
    158     if (m_resourceRequest.allowCookies() != newRequest.allowCookies())
    159         return false;
    160 
    161     // Ensure most headers match the existing headers before continuing.
    162     // Note that the list of ignored headers includes some headers explicitly related to caching.
    163     // A more detailed check of caching policy will be performed later, this is simply a list of
    164     // headers that we might permit to be different and still reuse the existing Resource.
    165     const HTTPHeaderMap& newHeaders = newRequest.httpHeaderFields();
    166     const HTTPHeaderMap& oldHeaders = m_resourceRequest.httpHeaderFields();
    167 
    168     HTTPHeaderMap::const_iterator end = newHeaders.end();
    169     for (HTTPHeaderMap::const_iterator i = newHeaders.begin(); i != end; ++i) {
    170         AtomicString headerName = i->key;
    171         if (!shouldIgnoreHeaderForCacheReuse(headerName) && i->value != oldHeaders.get(headerName))
    172             return false;
    173     }
    174 
    175     end = oldHeaders.end();
    176     for (HTTPHeaderMap::const_iterator i = oldHeaders.begin(); i != end; ++i) {
    177         AtomicString headerName = i->key;
    178         if (!shouldIgnoreHeaderForCacheReuse(headerName) && i->value != newHeaders.get(headerName))
    179             return false;
    180     }
    181 
    182     for (size_t i = 0; i < m_redirectChain.size(); i++) {
    183         if (m_redirectChain[i].m_redirectResponse.cacheControlContainsNoStore())
    184             return false;
    185     }
    186 
    187     return true;
    188 }
    189 
    190 void RawResource::clear()
    191 {
    192     m_data.clear();
    193     setEncodedSize(0);
    194 }
    195 
    196 } // namespace WebCore
    197