Home | History | Annotate | Download | only in cache
      1 /*
      2     Copyright (C) 1998 Lars Knoll (knoll (at) mpi-hd.mpg.de)
      3     Copyright (C) 2001 Dirk Mueller (mueller (at) kde.org)
      4     Copyright (C) 2002 Waldo Bastian (bastian (at) kde.org)
      5     Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
      6     Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
      7 
      8     This library is free software; you can redistribute it and/or
      9     modify it under the terms of the GNU Library General Public
     10     License as published by the Free Software Foundation; either
     11     version 2 of the License, or (at your option) any later version.
     12 
     13     This library is distributed in the hope that it will be useful,
     14     but WITHOUT ANY WARRANTY; without even the implied warranty of
     15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     16     Library General Public License for more details.
     17 
     18     You should have received a copy of the GNU Library General Public License
     19     along with this library; see the file COPYING.LIB.  If not, write to
     20     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     21     Boston, MA 02110-1301, USA.
     22 
     23     This class provides all functionality needed for loading images, style sheets and html
     24     pages from the web. It has a memory cache for these objects.
     25 */
     26 
     27 #include "config.h"
     28 #include "core/loader/cache/ResourceFetcher.h"
     29 
     30 #include "bindings/v8/ScriptController.h"
     31 #include "core/dom/Document.h"
     32 #include "core/html/HTMLElement.h"
     33 #include "core/html/HTMLFrameOwnerElement.h"
     34 #include "core/html/HTMLImport.h"
     35 #include "core/inspector/InspectorInstrumentation.h"
     36 #include "core/loader/DocumentLoader.h"
     37 #include "core/loader/FrameLoader.h"
     38 #include "core/loader/FrameLoaderClient.h"
     39 #include "core/loader/PingLoader.h"
     40 #include "core/loader/UniqueIdentifier.h"
     41 #include "core/loader/appcache/ApplicationCacheHost.h"
     42 #include "core/loader/cache/CSSStyleSheetResource.h"
     43 #include "core/loader/cache/DocumentResource.h"
     44 #include "core/loader/cache/FetchRequest.h"
     45 #include "core/loader/cache/FontResource.h"
     46 #include "core/loader/cache/ImageResource.h"
     47 #include "core/loader/cache/MemoryCache.h"
     48 #include "core/loader/cache/RawResource.h"
     49 #include "core/loader/cache/ScriptResource.h"
     50 #include "core/loader/cache/ShaderResource.h"
     51 #include "core/loader/cache/TextTrackResource.h"
     52 #include "core/loader/cache/XSLStyleSheetResource.h"
     53 #include "core/page/ContentSecurityPolicy.h"
     54 #include "core/page/DOMWindow.h"
     55 #include "core/page/Frame.h"
     56 #include "core/page/Performance.h"
     57 #include "core/page/ResourceTimingInfo.h"
     58 #include "core/page/Settings.h"
     59 #include "core/platform/Logging.h"
     60 #include "core/platform/chromium/TraceEvent.h"
     61 #include "public/platform/Platform.h"
     62 #include "public/platform/WebURL.h"
     63 #include "weborigin/SecurityOrigin.h"
     64 #include "weborigin/SecurityPolicy.h"
     65 #include "wtf/text/CString.h"
     66 #include "wtf/text/WTFString.h"
     67 
     68 #define PRELOAD_DEBUG 0
     69 
     70 namespace WebCore {
     71 
     72 static Resource* createResource(Resource::Type type, const ResourceRequest& request, const String& charset)
     73 {
     74     switch (type) {
     75     case Resource::Image:
     76         return new ImageResource(request);
     77     case Resource::CSSStyleSheet:
     78         return new CSSStyleSheetResource(request, charset);
     79     case Resource::Script:
     80         return new ScriptResource(request, charset);
     81     case Resource::SVGDocument:
     82         return new DocumentResource(request, Resource::SVGDocument);
     83     case Resource::Font:
     84         return new FontResource(request);
     85     case Resource::Raw:
     86     case Resource::MainResource:
     87         return new RawResource(request, type);
     88     case Resource::XSLStyleSheet:
     89         return new XSLStyleSheetResource(request);
     90     case Resource::LinkPrefetch:
     91         return new Resource(request, Resource::LinkPrefetch);
     92     case Resource::LinkSubresource:
     93         return new Resource(request, Resource::LinkSubresource);
     94     case Resource::TextTrack:
     95         return new TextTrackResource(request);
     96     case Resource::Shader:
     97         return new ShaderResource(request);
     98     case Resource::ImportResource:
     99         return new RawResource(request, type);
    100     }
    101 
    102     ASSERT_NOT_REACHED();
    103     return 0;
    104 }
    105 
    106 static ResourceLoadPriority loadPriority(Resource::Type type, const FetchRequest& request)
    107 {
    108     if (request.priority() != ResourceLoadPriorityUnresolved)
    109         return request.priority();
    110 
    111     switch (type) {
    112     case Resource::MainResource:
    113         return ResourceLoadPriorityVeryHigh;
    114     case Resource::CSSStyleSheet:
    115         return ResourceLoadPriorityHigh;
    116     case Resource::Script:
    117     case Resource::Font:
    118     case Resource::Raw:
    119     case Resource::ImportResource:
    120         return ResourceLoadPriorityMedium;
    121     case Resource::Image:
    122         return request.forPreload() ? ResourceLoadPriorityVeryLow : ResourceLoadPriorityLow;
    123     case Resource::XSLStyleSheet:
    124         return ResourceLoadPriorityHigh;
    125     case Resource::SVGDocument:
    126         return ResourceLoadPriorityLow;
    127     case Resource::LinkPrefetch:
    128         return ResourceLoadPriorityVeryLow;
    129     case Resource::LinkSubresource:
    130         return ResourceLoadPriorityLow;
    131     case Resource::TextTrack:
    132         return ResourceLoadPriorityLow;
    133     case Resource::Shader:
    134         return ResourceLoadPriorityMedium;
    135     }
    136     ASSERT_NOT_REACHED();
    137     return ResourceLoadPriorityUnresolved;
    138 }
    139 
    140 static Resource* resourceFromDataURIRequest(const ResourceRequest& request)
    141 {
    142     const KURL& url = request.url();
    143     ASSERT(url.protocolIsData());
    144 
    145     WebKit::WebString mimetype;
    146     WebKit::WebString charset;
    147     RefPtr<SharedBuffer> data = PassRefPtr<SharedBuffer>(WebKit::Platform::current()->parseDataURL(url, mimetype, charset));
    148     if (!data)
    149         return 0;
    150     ResourceResponse response(url, mimetype, data->size(), charset, String());
    151 
    152     Resource* resource = createResource(Resource::Image, request, charset);
    153     resource->responseReceived(response);
    154     // FIXME: AppendData causes an unnecessary memcpy.
    155     if (data->size())
    156         resource->appendData(data->data(), data->size());
    157     resource->finish();
    158     return resource;
    159 }
    160 
    161 ResourceFetcher::ResourceFetcher(DocumentLoader* documentLoader)
    162     : m_document(0)
    163     , m_documentLoader(documentLoader)
    164     , m_requestCount(0)
    165     , m_garbageCollectDocumentResourcesTimer(this, &ResourceFetcher::garbageCollectDocumentResourcesTimerFired)
    166     , m_autoLoadImages(true)
    167     , m_imagesEnabled(true)
    168     , m_allowStaleResources(false)
    169 {
    170 }
    171 
    172 ResourceFetcher::~ResourceFetcher()
    173 {
    174     m_documentLoader = 0;
    175     m_document = 0;
    176 
    177     clearPreloads();
    178 
    179     // Make sure no requests still point to this ResourceFetcher
    180     ASSERT(!m_requestCount);
    181 }
    182 
    183 Resource* ResourceFetcher::cachedResource(const String& resourceURL) const
    184 {
    185     KURL url = m_document->completeURL(resourceURL);
    186     return cachedResource(url);
    187 }
    188 
    189 Resource* ResourceFetcher::cachedResource(const KURL& resourceURL) const
    190 {
    191     KURL url = MemoryCache::removeFragmentIdentifierIfNeeded(resourceURL);
    192     return m_documentResources.get(url).get();
    193 }
    194 
    195 Frame* ResourceFetcher::frame() const
    196 {
    197     if (m_documentLoader)
    198         return m_documentLoader->frame();
    199     if (m_document && m_document->import())
    200         return m_document->import()->frame();
    201     return 0;
    202 }
    203 
    204 ResourcePtr<ImageResource> ResourceFetcher::requestImage(FetchRequest& request)
    205 {
    206     if (Frame* f = frame()) {
    207         if (f->loader()->pageDismissalEventBeingDispatched() != FrameLoader::NoDismissal) {
    208             KURL requestURL = request.resourceRequest().url();
    209             if (requestURL.isValid() && canRequest(Resource::Image, requestURL, request.options(), request.forPreload()))
    210                 PingLoader::loadImage(f, requestURL);
    211             return 0;
    212         }
    213     }
    214 
    215     if (request.resourceRequest().url().protocolIsData())
    216         preCacheDataURIImage(request);
    217 
    218     request.setDefer(clientDefersImage(request.resourceRequest().url()) ? FetchRequest::DeferredByClient : FetchRequest::NoDefer);
    219     return static_cast<ImageResource*>(requestResource(Resource::Image, request).get());
    220 }
    221 
    222 void ResourceFetcher::preCacheDataURIImage(const FetchRequest& request)
    223 {
    224     const KURL& url = request.resourceRequest().url();
    225     ASSERT(url.protocolIsData());
    226 
    227     if (Resource* existing = memoryCache()->resourceForURL(url))
    228         return;
    229 
    230     if (Resource* resource = resourceFromDataURIRequest(request.resourceRequest()))
    231         memoryCache()->add(resource);
    232 }
    233 
    234 ResourcePtr<FontResource> ResourceFetcher::requestFont(FetchRequest& request)
    235 {
    236     return static_cast<FontResource*>(requestResource(Resource::Font, request).get());
    237 }
    238 
    239 ResourcePtr<TextTrackResource> ResourceFetcher::requestTextTrack(FetchRequest& request)
    240 {
    241     return static_cast<TextTrackResource*>(requestResource(Resource::TextTrack, request).get());
    242 }
    243 
    244 ResourcePtr<ShaderResource> ResourceFetcher::requestShader(FetchRequest& request)
    245 {
    246     return static_cast<ShaderResource*>(requestResource(Resource::Shader, request).get());
    247 }
    248 
    249 ResourcePtr<RawResource> ResourceFetcher::requestImport(FetchRequest& request)
    250 {
    251     return static_cast<RawResource*>(requestResource(Resource::ImportResource, request).get());
    252 }
    253 
    254 ResourcePtr<CSSStyleSheetResource> ResourceFetcher::requestCSSStyleSheet(FetchRequest& request)
    255 {
    256     return static_cast<CSSStyleSheetResource*>(requestResource(Resource::CSSStyleSheet, request).get());
    257 }
    258 
    259 ResourcePtr<CSSStyleSheetResource> ResourceFetcher::requestUserCSSStyleSheet(FetchRequest& request)
    260 {
    261     KURL url = MemoryCache::removeFragmentIdentifierIfNeeded(request.resourceRequest().url());
    262 
    263     if (Resource* existing = memoryCache()->resourceForURL(url)) {
    264         if (existing->type() == Resource::CSSStyleSheet)
    265             return static_cast<CSSStyleSheetResource*>(existing);
    266         memoryCache()->remove(existing);
    267     }
    268 
    269     request.setOptions(ResourceLoaderOptions(DoNotSendCallbacks, SniffContent, BufferData, AllowStoredCredentials, ClientRequestedCredentials, AskClientForCrossOriginCredentials, SkipSecurityCheck, CheckContentSecurityPolicy, UseDefaultOriginRestrictionsForType, DocumentContext));
    270     return static_cast<CSSStyleSheetResource*>(requestResource(Resource::CSSStyleSheet, request).get());
    271 }
    272 
    273 ResourcePtr<ScriptResource> ResourceFetcher::requestScript(FetchRequest& request)
    274 {
    275     return static_cast<ScriptResource*>(requestResource(Resource::Script, request).get());
    276 }
    277 
    278 ResourcePtr<XSLStyleSheetResource> ResourceFetcher::requestXSLStyleSheet(FetchRequest& request)
    279 {
    280     return static_cast<XSLStyleSheetResource*>(requestResource(Resource::XSLStyleSheet, request).get());
    281 }
    282 
    283 ResourcePtr<DocumentResource> ResourceFetcher::requestSVGDocument(FetchRequest& request)
    284 {
    285     return static_cast<DocumentResource*>(requestResource(Resource::SVGDocument, request).get());
    286 }
    287 
    288 ResourcePtr<Resource> ResourceFetcher::requestLinkResource(Resource::Type type, FetchRequest& request)
    289 {
    290     ASSERT(frame());
    291     ASSERT(type == Resource::LinkPrefetch || type == Resource::LinkSubresource);
    292     return requestResource(type, request);
    293 }
    294 
    295 ResourcePtr<RawResource> ResourceFetcher::requestRawResource(FetchRequest& request)
    296 {
    297     return static_cast<RawResource*>(requestResource(Resource::Raw, request).get());
    298 }
    299 
    300 ResourcePtr<RawResource> ResourceFetcher::requestMainResource(FetchRequest& request)
    301 {
    302     return static_cast<RawResource*>(requestResource(Resource::MainResource, request).get());
    303 }
    304 
    305 bool ResourceFetcher::checkInsecureContent(Resource::Type type, const KURL& url) const
    306 {
    307     switch (type) {
    308     case Resource::Script:
    309     case Resource::XSLStyleSheet:
    310     case Resource::SVGDocument:
    311     case Resource::CSSStyleSheet:
    312     case Resource::ImportResource:
    313         // These resource can inject script into the current document (Script,
    314         // XSL) or exfiltrate the content of the current document (CSS).
    315         if (Frame* f = frame()) {
    316             if (!f->loader()->mixedContentChecker()->canRunInsecureContent(m_document->securityOrigin(), url))
    317                 return false;
    318         }
    319 
    320         break;
    321     case Resource::TextTrack:
    322     case Resource::Shader:
    323     case Resource::Raw:
    324     case Resource::Image:
    325     case Resource::Font: {
    326         // These resources can corrupt only the frame's pixels.
    327         if (Frame* f = frame()) {
    328             Frame* top = f->tree()->top();
    329             if (!top->loader()->mixedContentChecker()->canDisplayInsecureContent(top->document()->securityOrigin(), url))
    330                 return false;
    331         }
    332         break;
    333     }
    334     case Resource::MainResource:
    335     case Resource::LinkPrefetch:
    336     case Resource::LinkSubresource:
    337         // Prefetch cannot affect the current document.
    338         break;
    339     }
    340     return true;
    341 }
    342 
    343 bool ResourceFetcher::canRequest(Resource::Type type, const KURL& url, const ResourceLoaderOptions& options, bool forPreload)
    344 {
    345     if (document() && !document()->securityOrigin()->canDisplay(url)) {
    346         if (!forPreload)
    347             FrameLoader::reportLocalLoadFailed(frame(), url.elidedString());
    348         LOG(ResourceLoading, "ResourceFetcher::requestResource URL was not allowed by SecurityOrigin::canDisplay");
    349         return 0;
    350     }
    351 
    352     // FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved.
    353     bool shouldBypassMainWorldContentSecurityPolicy = (frame() && frame()->script()->shouldBypassMainWorldContentSecurityPolicy()) || (options.contentSecurityPolicyOption == DoNotCheckContentSecurityPolicy);
    354 
    355     // Some types of resources can be loaded only from the same origin. Other
    356     // types of resources, like Images, Scripts, and CSS, can be loaded from
    357     // any URL.
    358     switch (type) {
    359     case Resource::MainResource:
    360     case Resource::Image:
    361     case Resource::CSSStyleSheet:
    362     case Resource::Script:
    363     case Resource::Font:
    364     case Resource::Raw:
    365     case Resource::LinkPrefetch:
    366     case Resource::LinkSubresource:
    367     case Resource::TextTrack:
    368     case Resource::Shader:
    369     case Resource::ImportResource:
    370         // By default these types of resources can be loaded from any origin.
    371         // FIXME: Are we sure about Resource::Font?
    372         if (options.requestOriginPolicy == RestrictToSameOrigin && !m_document->securityOrigin()->canRequest(url)) {
    373             printAccessDeniedMessage(url);
    374             return false;
    375         }
    376         break;
    377     case Resource::SVGDocument:
    378     case Resource::XSLStyleSheet:
    379         if (!m_document->securityOrigin()->canRequest(url)) {
    380             printAccessDeniedMessage(url);
    381             return false;
    382         }
    383         break;
    384     }
    385 
    386     switch (type) {
    387     case Resource::XSLStyleSheet:
    388         if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowScriptFromSource(url))
    389             return false;
    390         break;
    391     case Resource::Script:
    392     case Resource::ImportResource:
    393         if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowScriptFromSource(url))
    394             return false;
    395 
    396         if (frame()) {
    397             Settings* settings = frame()->settings();
    398             if (!frame()->loader()->client()->allowScriptFromSource(!settings || settings->isScriptEnabled(), url)) {
    399                 frame()->loader()->client()->didNotAllowScript();
    400                 return false;
    401             }
    402         }
    403         break;
    404     case Resource::Shader:
    405         // Since shaders are referenced from CSS Styles use the same rules here.
    406     case Resource::CSSStyleSheet:
    407         if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowStyleFromSource(url))
    408             return false;
    409         break;
    410     case Resource::SVGDocument:
    411     case Resource::Image:
    412         if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowImageFromSource(url))
    413             return false;
    414         break;
    415     case Resource::Font: {
    416         if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowFontFromSource(url))
    417             return false;
    418         break;
    419     }
    420     case Resource::MainResource:
    421     case Resource::Raw:
    422     case Resource::LinkPrefetch:
    423     case Resource::LinkSubresource:
    424         break;
    425     case Resource::TextTrack:
    426         // Cues aren't called out in the CPS spec yet, but they only work with a media element
    427         // so use the media policy.
    428         if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowMediaFromSource(url))
    429             return false;
    430         break;
    431     }
    432 
    433     // Last of all, check for insecure content. We do this last so that when
    434     // folks block insecure content with a CSP policy, they don't get a warning.
    435     // They'll still get a warning in the console about CSP blocking the load.
    436 
    437     // FIXME: Should we consider forPreload here?
    438     if (!checkInsecureContent(type, url))
    439         return false;
    440 
    441     return true;
    442 }
    443 
    444 bool ResourceFetcher::canAccess(Resource* resource)
    445 {
    446     // Redirects can change the response URL different from one of request.
    447     if (!canRequest(resource->type(), resource->response().url(), resource->options(), false))
    448         return false;
    449 
    450     String error;
    451     switch (resource->type()) {
    452     case Resource::Script:
    453     case Resource::ImportResource:
    454         if (resource->options().requestOriginPolicy == PotentiallyCrossOriginEnabled
    455             && !m_document->securityOrigin()->canRequest(resource->response().url())
    456             && !resource->passesAccessControlCheck(m_document->securityOrigin(), error)) {
    457             if (frame() && frame()->document())
    458                 frame()->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Script from origin '" + SecurityOrigin::create(resource->response().url())->toString() + "' has been blocked from loading by Cross-Origin Resource Sharing policy: " + error);
    459             return false;
    460         }
    461 
    462         break;
    463     default:
    464         ASSERT_NOT_REACHED(); // FIXME: generalize to non-script resources
    465         return false;
    466     }
    467 
    468     return true;
    469 }
    470 
    471 bool ResourceFetcher::shouldLoadNewResource() const
    472 {
    473     if (!frame())
    474         return false;
    475     if (m_documentLoader) {
    476         if (m_documentLoader != frame()->loader()->activeDocumentLoader())
    477             return false;
    478         if (m_documentLoader->isStopping())
    479             return false;
    480     }
    481 
    482     return true;
    483 }
    484 
    485 ResourcePtr<Resource> ResourceFetcher::requestResource(Resource::Type type, FetchRequest& request)
    486 {
    487     KURL url = request.resourceRequest().url();
    488 
    489     LOG(ResourceLoading, "ResourceFetcher::requestResource '%s', charset '%s', priority=%d, forPreload=%u", url.elidedString().latin1().data(), request.charset().latin1().data(), request.priority(), request.forPreload());
    490 
    491     // If only the fragment identifiers differ, it is the same resource.
    492     url = MemoryCache::removeFragmentIdentifierIfNeeded(url);
    493 
    494     if (!url.isValid())
    495         return 0;
    496 
    497     if (!canRequest(type, url, request.options(), request.forPreload()))
    498         return 0;
    499 
    500     if (Frame* f = frame())
    501         f->loader()->client()->dispatchWillRequestResource(&request);
    502 
    503     // See if we can use an existing resource from the cache.
    504     ResourcePtr<Resource> resource = memoryCache()->resourceForURL(url);
    505 
    506     const RevalidationPolicy policy = determineRevalidationPolicy(type, request.mutableResourceRequest(), request.forPreload(), resource.get(), request.defer());
    507     switch (policy) {
    508     case Reload:
    509         memoryCache()->remove(resource.get());
    510         // Fall through
    511     case Load:
    512         resource = loadResource(type, request, request.charset());
    513         break;
    514     case Revalidate:
    515         resource = revalidateResource(request, resource.get());
    516         break;
    517     case Use:
    518         resource->updateForAccess();
    519         notifyLoadedFromMemoryCache(resource.get());
    520         break;
    521     }
    522 
    523     if (!resource)
    524         return 0;
    525 
    526     if (policy != Use)
    527         resource->setIdentifier(createUniqueIdentifier());
    528 
    529     if (!request.forPreload() || policy != Use) {
    530         ResourceLoadPriority priority = loadPriority(type, request);
    531         if (priority != resource->resourceRequest().priority()) {
    532             resource->resourceRequest().setPriority(priority);
    533             resource->didChangePriority(priority);
    534         }
    535     }
    536 
    537     if ((policy != Use || resource->stillNeedsLoad()) && FetchRequest::NoDefer == request.defer()) {
    538         if (!shouldLoadNewResource()) {
    539             if (resource->inCache())
    540                 memoryCache()->remove(resource.get());
    541             return 0;
    542         }
    543 
    544         if (!m_documentLoader || !m_documentLoader->scheduleArchiveLoad(resource.get(), request.resourceRequest()))
    545             resource->load(this, request.options());
    546 
    547         // We don't support immediate loads, but we do support immediate failure.
    548         if (resource->errorOccurred()) {
    549             if (resource->inCache())
    550                 memoryCache()->remove(resource.get());
    551             return 0;
    552         }
    553     }
    554 
    555     // FIXME: Temporarily leave main resource caching disabled for chromium,
    556     // see https://bugs.webkit.org/show_bug.cgi?id=107962. Before caching main
    557     // resources, we should be sure to understand the implications for memory
    558     // use.
    559     //
    560     // Ensure main resources aren't preloaded, and other main resource loads
    561     // are removed from cache to prevent reuse.
    562     if (type == Resource::MainResource) {
    563         ASSERT(policy != Use);
    564         ASSERT(policy != Revalidate);
    565         memoryCache()->remove(resource.get());
    566         if (request.forPreload())
    567             return 0;
    568     }
    569 
    570     if (!request.resourceRequest().url().protocolIsData())
    571         m_validatedURLs.add(request.resourceRequest().url());
    572 
    573     ASSERT(resource->url() == url.string());
    574     m_documentResources.set(resource->url(), resource);
    575     return resource;
    576 }
    577 
    578 void ResourceFetcher::determineTargetType(ResourceRequest& request, Resource::Type type)
    579 {
    580     ResourceRequest::TargetType targetType;
    581 
    582     switch (type) {
    583     case Resource::MainResource:
    584         if (frame()->tree()->parent())
    585             targetType = ResourceRequest::TargetIsSubframe;
    586         else
    587             targetType = ResourceRequest::TargetIsMainFrame;
    588         break;
    589     case Resource::CSSStyleSheet:
    590     case Resource::XSLStyleSheet:
    591         targetType = ResourceRequest::TargetIsStyleSheet;
    592         break;
    593     case Resource::Script:
    594         targetType = ResourceRequest::TargetIsScript;
    595         break;
    596     case Resource::Font:
    597         targetType = ResourceRequest::TargetIsFont;
    598         break;
    599     case Resource::Image:
    600         targetType = ResourceRequest::TargetIsImage;
    601         break;
    602     case Resource::Shader:
    603     case Resource::Raw:
    604     case Resource::ImportResource:
    605         targetType = ResourceRequest::TargetIsSubresource;
    606         break;
    607     case Resource::LinkPrefetch:
    608         targetType = ResourceRequest::TargetIsPrefetch;
    609         break;
    610     case Resource::LinkSubresource:
    611         targetType = ResourceRequest::TargetIsSubresource;
    612         break;
    613     case Resource::TextTrack:
    614         targetType = ResourceRequest::TargetIsTextTrack;
    615         break;
    616     case Resource::SVGDocument:
    617         targetType = ResourceRequest::TargetIsImage;
    618         break;
    619     default:
    620         ASSERT_NOT_REACHED();
    621         targetType = ResourceRequest::TargetIsSubresource;
    622         break;
    623     }
    624     request.setTargetType(targetType);
    625 }
    626 
    627 ResourceRequestCachePolicy ResourceFetcher::resourceRequestCachePolicy(const ResourceRequest& request, Resource::Type type)
    628 {
    629     if (type == Resource::MainResource) {
    630         FrameLoadType frameLoadType = frame()->loader()->loadType();
    631         bool isReload = frameLoadType == FrameLoadTypeReload || frameLoadType == FrameLoadTypeReloadFromOrigin;
    632         if (request.httpMethod() == "POST" && frameLoadType == FrameLoadTypeBackForward)
    633             return ReturnCacheDataDontLoad;
    634         if (!m_documentLoader->overrideEncoding().isEmpty() || frameLoadType == FrameLoadTypeBackForward)
    635             return ReturnCacheDataElseLoad;
    636         if (isReload || frameLoadType == FrameLoadTypeSame || request.isConditional())
    637             return ReloadIgnoringCacheData;
    638         return UseProtocolCachePolicy;
    639     }
    640 
    641     if (request.isConditional())
    642         return ReloadIgnoringCacheData;
    643 
    644     if (m_documentLoader && m_documentLoader->isLoadingInAPISense()) {
    645         // For POST requests, we mutate the main resource's cache policy to avoid form resubmission.
    646         // This policy should not be inherited by subresources.
    647         ResourceRequestCachePolicy mainResourceCachePolicy = m_documentLoader->request().cachePolicy();
    648         if (mainResourceCachePolicy == ReturnCacheDataDontLoad)
    649             return ReturnCacheDataElseLoad;
    650         return mainResourceCachePolicy;
    651     }
    652     return UseProtocolCachePolicy;
    653 }
    654 
    655 void ResourceFetcher::addAdditionalRequestHeaders(ResourceRequest& request, Resource::Type type)
    656 {
    657     if (!frame())
    658         return;
    659 
    660     bool isMainResource = type == Resource::MainResource;
    661 
    662     FrameLoader* frameLoader = frame()->loader();
    663 
    664     if (!isMainResource) {
    665         String outgoingReferrer;
    666         String outgoingOrigin;
    667         if (request.httpReferrer().isNull()) {
    668             outgoingReferrer = frameLoader->outgoingReferrer();
    669             outgoingOrigin = frameLoader->outgoingOrigin();
    670         } else {
    671             outgoingReferrer = request.httpReferrer();
    672             outgoingOrigin = SecurityOrigin::createFromString(outgoingReferrer)->toString();
    673         }
    674 
    675         outgoingReferrer = SecurityPolicy::generateReferrerHeader(document()->referrerPolicy(), request.url(), outgoingReferrer);
    676         if (outgoingReferrer.isEmpty())
    677             request.clearHTTPReferrer();
    678         else if (!request.httpReferrer())
    679             request.setHTTPReferrer(outgoingReferrer);
    680 
    681         FrameLoader::addHTTPOriginIfNeeded(request, outgoingOrigin);
    682     }
    683 
    684     if (request.cachePolicy() == UseProtocolCachePolicy)
    685         request.setCachePolicy(resourceRequestCachePolicy(request, type));
    686     if (request.targetType() == ResourceRequest::TargetIsUnspecified)
    687         determineTargetType(request, type);
    688     if (type == Resource::LinkPrefetch || type == Resource::LinkSubresource)
    689         request.setHTTPHeaderField("Purpose", "prefetch");
    690     frameLoader->addExtraFieldsToRequest(request);
    691 }
    692 
    693 ResourcePtr<Resource> ResourceFetcher::revalidateResource(const FetchRequest& request, Resource* resource)
    694 {
    695     ASSERT(resource);
    696     ASSERT(resource->inCache());
    697     ASSERT(resource->isLoaded());
    698     ASSERT(resource->canUseCacheValidator());
    699     ASSERT(!resource->resourceToRevalidate());
    700 
    701     ResourceRequest revalidatingRequest(resource->resourceRequest());
    702     addAdditionalRequestHeaders(revalidatingRequest, resource->type());
    703 
    704     const String& lastModified = resource->response().httpHeaderField("Last-Modified");
    705     const String& eTag = resource->response().httpHeaderField("ETag");
    706     if (!lastModified.isEmpty() || !eTag.isEmpty()) {
    707         ASSERT(cachePolicy(resource->type()) != CachePolicyReload);
    708         if (cachePolicy(resource->type()) == CachePolicyRevalidate)
    709             revalidatingRequest.setHTTPHeaderField("Cache-Control", "max-age=0");
    710         if (!lastModified.isEmpty())
    711             revalidatingRequest.setHTTPHeaderField("If-Modified-Since", lastModified);
    712         if (!eTag.isEmpty())
    713             revalidatingRequest.setHTTPHeaderField("If-None-Match", eTag);
    714     }
    715 
    716     ResourcePtr<Resource> newResource = createResource(resource->type(), revalidatingRequest, resource->encoding());
    717 
    718     LOG(ResourceLoading, "Resource %p created to revalidate %p", newResource.get(), resource);
    719     newResource->setResourceToRevalidate(resource);
    720 
    721     memoryCache()->remove(resource);
    722     memoryCache()->add(newResource.get());
    723     storeResourceTimingInitiatorInformation(newResource, request);
    724     TRACE_EVENT_ASYNC_BEGIN2("net", "Resource", newResource.get(), "url", newResource->url().string().ascii(), "priority", newResource->resourceRequest().priority());
    725     return newResource;
    726 }
    727 
    728 ResourcePtr<Resource> ResourceFetcher::loadResource(Resource::Type type, FetchRequest& request, const String& charset)
    729 {
    730     ASSERT(!memoryCache()->resourceForURL(request.resourceRequest().url()));
    731 
    732     LOG(ResourceLoading, "Loading Resource for '%s'.", request.resourceRequest().url().elidedString().latin1().data());
    733 
    734     addAdditionalRequestHeaders(request.mutableResourceRequest(), type);
    735     ResourcePtr<Resource> resource = createResource(type, request.mutableResourceRequest(), charset);
    736 
    737     memoryCache()->add(resource.get());
    738     storeResourceTimingInitiatorInformation(resource, request);
    739     TRACE_EVENT_ASYNC_BEGIN2("net", "Resource", resource.get(), "url", resource->url().string().ascii(), "priority", resource->resourceRequest().priority());
    740     return resource;
    741 }
    742 
    743 void ResourceFetcher::storeResourceTimingInitiatorInformation(const ResourcePtr<Resource>& resource, const FetchRequest& request)
    744 {
    745     if (request.options().requestInitiatorContext != DocumentContext)
    746         return;
    747 
    748     RefPtr<ResourceTimingInfo> info = ResourceTimingInfo::create(request.options().initiatorInfo.name, monotonicallyIncreasingTime());
    749 
    750     if (resource->type() == Resource::MainResource) {
    751         // <iframe>s should report the initial navigation requested by the parent document, but not subsequent navigations.
    752         if (frame()->ownerElement() && !frame()->ownerElement()->loadedNonEmptyDocument()) {
    753             info->setInitiatorType(frame()->ownerElement()->localName());
    754             m_resourceTimingInfoMap.add(resource.get(), info);
    755             frame()->ownerElement()->didLoadNonEmptyDocument();
    756         }
    757     } else {
    758         m_resourceTimingInfoMap.add(resource.get(), info);
    759     }
    760 }
    761 
    762 ResourceFetcher::RevalidationPolicy ResourceFetcher::determineRevalidationPolicy(Resource::Type type, ResourceRequest& request, bool forPreload, Resource* existingResource, FetchRequest::DeferOption defer) const
    763 {
    764     if (!existingResource)
    765         return Load;
    766 
    767     // We already have a preload going for this URL.
    768     if (forPreload && existingResource->isPreloaded())
    769         return Use;
    770 
    771     // If the same URL has been loaded as a different type, we need to reload.
    772     if (existingResource->type() != type) {
    773         LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to type mismatch.");
    774         return Reload;
    775     }
    776 
    777     // Do not load from cache if images are not enabled. The load for this image will be blocked
    778     // in ImageResource::load.
    779     if (FetchRequest::DeferredByClient == defer)
    780         return Reload;
    781 
    782     // Always use data uris.
    783     // FIXME: Extend this to non-images.
    784     if (type == Resource::Image && request.url().protocolIsData())
    785         return Use;
    786 
    787     if (!existingResource->canReuse(request))
    788         return Reload;
    789 
    790     // Certain requests (e.g., XHRs) might have manually set headers that require revalidation.
    791     // FIXME: In theory, this should be a Revalidate case. In practice, the MemoryCache revalidation path assumes a whole bunch
    792     // of things about how revalidation works that manual headers violate, so punt to Reload instead.
    793     if (request.isConditional())
    794         return Reload;
    795 
    796     // Don't reload resources while pasting.
    797     if (m_allowStaleResources)
    798         return Use;
    799 
    800     // Alwaus use preloads.
    801     if (existingResource->isPreloaded())
    802         return Use;
    803 
    804     // CachePolicyHistoryBuffer uses the cache no matter what.
    805     if (cachePolicy(type) == CachePolicyHistoryBuffer)
    806         return Use;
    807 
    808     // Don't reuse resources with Cache-control: no-store.
    809     if (existingResource->response().cacheControlContainsNoStore()) {
    810         LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to Cache-control: no-store.");
    811         return Reload;
    812     }
    813 
    814     // If credentials were sent with the previous request and won't be
    815     // with this one, or vice versa, re-fetch the resource.
    816     //
    817     // This helps with the case where the server sends back
    818     // "Access-Control-Allow-Origin: *" all the time, but some of the
    819     // client's requests are made without CORS and some with.
    820     if (existingResource->resourceRequest().allowCookies() != request.allowCookies()) {
    821         LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to difference in credentials settings.");
    822         return Reload;
    823     }
    824 
    825     // During the initial load, avoid loading the same resource multiple times for a single document, even if the cache policies would tell us to.
    826     if (document() && !document()->loadEventFinished() && m_validatedURLs.contains(existingResource->url()))
    827         return Use;
    828 
    829     // CachePolicyReload always reloads
    830     if (cachePolicy(type) == CachePolicyReload) {
    831         LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to CachePolicyReload.");
    832         return Reload;
    833     }
    834 
    835     // We'll try to reload the resource if it failed last time.
    836     if (existingResource->errorOccurred()) {
    837         LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicye reloading due to resource being in the error state");
    838         return Reload;
    839     }
    840 
    841     // For resources that are not yet loaded we ignore the cache policy.
    842     if (existingResource->isLoading())
    843         return Use;
    844 
    845     // Check if the cache headers requires us to revalidate (cache expiration for example).
    846     if (existingResource->mustRevalidateDueToCacheHeaders(cachePolicy(type))) {
    847         // See if the resource has usable ETag or Last-modified headers.
    848         if (existingResource->canUseCacheValidator())
    849             return Revalidate;
    850 
    851         // No, must reload.
    852         LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to missing cache validators.");
    853         return Reload;
    854     }
    855 
    856     return Use;
    857 }
    858 
    859 void ResourceFetcher::printAccessDeniedMessage(const KURL& url) const
    860 {
    861     if (url.isNull())
    862         return;
    863 
    864     if (!frame())
    865         return;
    866 
    867     String message;
    868     if (!m_document || m_document->url().isNull())
    869         message = "Unsafe attempt to load URL " + url.elidedString() + '.';
    870     else
    871         message = "Unsafe attempt to load URL " + url.elidedString() + " from frame with URL " + m_document->url().elidedString() + ". Domains, protocols and ports must match.\n";
    872 
    873     frame()->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message);
    874 }
    875 
    876 void ResourceFetcher::setAutoLoadImages(bool enable)
    877 {
    878     if (enable == m_autoLoadImages)
    879         return;
    880 
    881     m_autoLoadImages = enable;
    882 
    883     if (!m_autoLoadImages)
    884         return;
    885 
    886     reloadImagesIfNotDeferred();
    887 }
    888 
    889 void ResourceFetcher::setImagesEnabled(bool enable)
    890 {
    891     if (enable == m_imagesEnabled)
    892         return;
    893 
    894     m_imagesEnabled = enable;
    895 
    896     if (!m_imagesEnabled)
    897         return;
    898 
    899     reloadImagesIfNotDeferred();
    900 }
    901 
    902 bool ResourceFetcher::clientDefersImage(const KURL& url) const
    903 {
    904     return frame() && !frame()->loader()->client()->allowImage(m_imagesEnabled, url);
    905 }
    906 
    907 bool ResourceFetcher::shouldDeferImageLoad(const KURL& url) const
    908 {
    909     return clientDefersImage(url) || !m_autoLoadImages;
    910 }
    911 
    912 void ResourceFetcher::reloadImagesIfNotDeferred()
    913 {
    914     DocumentResourceMap::iterator end = m_documentResources.end();
    915     for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != end; ++it) {
    916         Resource* resource = it->value.get();
    917         if (resource->type() == Resource::Image && resource->stillNeedsLoad() && !clientDefersImage(resource->url()))
    918             const_cast<Resource*>(resource)->load(this, defaultResourceOptions());
    919     }
    920 }
    921 
    922 CachePolicy ResourceFetcher::cachePolicy(Resource::Type type) const
    923 {
    924     if (!frame())
    925         return CachePolicyVerify;
    926 
    927     if (type != Resource::MainResource)
    928         return frame()->loader()->subresourceCachePolicy();
    929 
    930     if (frame()->loader()->loadType() == FrameLoadTypeReloadFromOrigin || frame()->loader()->loadType() == FrameLoadTypeReload)
    931         return CachePolicyReload;
    932     return CachePolicyVerify;
    933 }
    934 
    935 void ResourceFetcher::redirectReceived(Resource* resource, const ResourceResponse& redirectResponse)
    936 {
    937     ResourceTimingInfoMap::iterator it = m_resourceTimingInfoMap.find(resource);
    938     if (it != m_resourceTimingInfoMap.end())
    939         it->value->addRedirect(redirectResponse);
    940 }
    941 
    942 void ResourceFetcher::didLoadResource(Resource* resource)
    943 {
    944     RefPtr<DocumentLoader> protectDocumentLoader(m_documentLoader);
    945     RefPtr<Document> protectDocument(m_document);
    946 
    947     if (resource && resource->response().isHTTP() && ((!resource->errorOccurred() && !resource->wasCanceled()) || resource->response().httpStatusCode() == 304) && document()) {
    948         ResourceTimingInfoMap::iterator it = m_resourceTimingInfoMap.find(resource);
    949         if (it != m_resourceTimingInfoMap.end()) {
    950             Document* initiatorDocument = document();
    951             if (resource->type() == Resource::MainResource)
    952                 initiatorDocument = document()->parentDocument();
    953             ASSERT(initiatorDocument);
    954             RefPtr<ResourceTimingInfo> info = it->value;
    955             m_resourceTimingInfoMap.remove(it);
    956             info->setInitialRequest(resource->resourceRequest());
    957             info->setFinalResponse(resource->response());
    958             info->setLoadFinishTime(resource->loadFinishTime());
    959             if (DOMWindow* initiatorWindow = initiatorDocument->domWindow())
    960                 initiatorWindow->performance()->addResourceTiming(*info, initiatorDocument);
    961         }
    962     }
    963 
    964     if (frame())
    965         frame()->loader()->loadDone();
    966     performPostLoadActions();
    967 
    968     if (!m_garbageCollectDocumentResourcesTimer.isActive())
    969         m_garbageCollectDocumentResourcesTimer.startOneShot(0);
    970 }
    971 
    972 // Garbage collecting m_documentResources is a workaround for the
    973 // ResourcePtrs on the RHS being strong references. Ideally this
    974 // would be a weak map, however ResourcePtrs perform additional
    975 // bookkeeping on Resources, so instead pseudo-GC them -- when the
    976 // reference count reaches 1, m_documentResources is the only reference, so
    977 // remove it from the map.
    978 void ResourceFetcher::garbageCollectDocumentResourcesTimerFired(Timer<ResourceFetcher>* timer)
    979 {
    980     ASSERT_UNUSED(timer, timer == &m_garbageCollectDocumentResourcesTimer);
    981     garbageCollectDocumentResources();
    982 }
    983 
    984 void ResourceFetcher::garbageCollectDocumentResources()
    985 {
    986     typedef Vector<String, 10> StringVector;
    987     StringVector resourcesToDelete;
    988 
    989     for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != m_documentResources.end(); ++it) {
    990         if (it->value->hasOneHandle())
    991             resourcesToDelete.append(it->key);
    992     }
    993 
    994     for (StringVector::const_iterator it = resourcesToDelete.begin(); it != resourcesToDelete.end(); ++it)
    995         m_documentResources.remove(*it);
    996 }
    997 
    998 void ResourceFetcher::performPostLoadActions()
    999 {
   1000     checkForPendingPreloads();
   1001 }
   1002 
   1003 void ResourceFetcher::notifyLoadedFromMemoryCache(Resource* resource)
   1004 {
   1005     if (!frame() || resource->status() != Resource::Cached || m_validatedURLs.contains(resource->url()))
   1006         return;
   1007 
   1008     // FIXME: If the WebKit client changes or cancels the request, WebCore does not respect this and continues the load.
   1009     frame()->loader()->loadedResourceFromMemoryCache(resource);
   1010 }
   1011 
   1012 void ResourceFetcher::incrementRequestCount(const Resource* res)
   1013 {
   1014     if (res->ignoreForRequestCount())
   1015         return;
   1016 
   1017     ++m_requestCount;
   1018 }
   1019 
   1020 void ResourceFetcher::decrementRequestCount(const Resource* res)
   1021 {
   1022     if (res->ignoreForRequestCount())
   1023         return;
   1024 
   1025     --m_requestCount;
   1026     ASSERT(m_requestCount > -1);
   1027 }
   1028 
   1029 void ResourceFetcher::preload(Resource::Type type, FetchRequest& request, const String& charset)
   1030 {
   1031     bool delaySubresourceLoad = true;
   1032     delaySubresourceLoad = false;
   1033     if (delaySubresourceLoad) {
   1034         bool hasRendering = m_document->body() && m_document->body()->renderer();
   1035         bool canBlockParser = type == Resource::Script || type == Resource::CSSStyleSheet;
   1036         if (!hasRendering && !canBlockParser) {
   1037             // Don't preload subresources that can't block the parser before we have something to draw.
   1038             // This helps prevent preloads from delaying first display when bandwidth is limited.
   1039             PendingPreload pendingPreload = { type, request, charset };
   1040             m_pendingPreloads.append(pendingPreload);
   1041             return;
   1042         }
   1043     }
   1044     requestPreload(type, request, charset);
   1045 }
   1046 
   1047 void ResourceFetcher::checkForPendingPreloads()
   1048 {
   1049     if (m_pendingPreloads.isEmpty() || !m_document->body() || !m_document->body()->renderer())
   1050         return;
   1051     while (!m_pendingPreloads.isEmpty()) {
   1052         PendingPreload preload = m_pendingPreloads.takeFirst();
   1053         // Don't request preload if the resource already loaded normally (this will result in double load if the page is being reloaded with cached results ignored).
   1054         if (!cachedResource(preload.m_request.resourceRequest().url()))
   1055             requestPreload(preload.m_type, preload.m_request, preload.m_charset);
   1056     }
   1057     m_pendingPreloads.clear();
   1058 }
   1059 
   1060 void ResourceFetcher::requestPreload(Resource::Type type, FetchRequest& request, const String& charset)
   1061 {
   1062     String encoding;
   1063     if (type == Resource::Script || type == Resource::CSSStyleSheet)
   1064         encoding = charset.isEmpty() ? m_document->charset() : charset;
   1065 
   1066     request.setCharset(encoding);
   1067     request.setForPreload(true);
   1068 
   1069     ResourcePtr<Resource> resource = requestResource(type, request);
   1070     if (!resource || (m_preloads && m_preloads->contains(resource.get())))
   1071         return;
   1072     TRACE_EVENT_ASYNC_STEP0("net", "Resource", resource.get(), "Preload");
   1073     resource->increasePreloadCount();
   1074 
   1075     if (!m_preloads)
   1076         m_preloads = adoptPtr(new ListHashSet<Resource*>);
   1077     m_preloads->add(resource.get());
   1078 
   1079 #if PRELOAD_DEBUG
   1080     printf("PRELOADING %s\n",  resource->url().latin1().data());
   1081 #endif
   1082 }
   1083 
   1084 bool ResourceFetcher::isPreloaded(const String& urlString) const
   1085 {
   1086     const KURL& url = m_document->completeURL(urlString);
   1087 
   1088     if (m_preloads) {
   1089         ListHashSet<Resource*>::iterator end = m_preloads->end();
   1090         for (ListHashSet<Resource*>::iterator it = m_preloads->begin(); it != end; ++it) {
   1091             Resource* resource = *it;
   1092             if (resource->url() == url)
   1093                 return true;
   1094         }
   1095     }
   1096 
   1097     Deque<PendingPreload>::const_iterator dequeEnd = m_pendingPreloads.end();
   1098     for (Deque<PendingPreload>::const_iterator it = m_pendingPreloads.begin(); it != dequeEnd; ++it) {
   1099         PendingPreload pendingPreload = *it;
   1100         if (pendingPreload.m_request.resourceRequest().url() == url)
   1101             return true;
   1102     }
   1103     return false;
   1104 }
   1105 
   1106 void ResourceFetcher::clearPreloads()
   1107 {
   1108 #if PRELOAD_DEBUG
   1109     printPreloadStats();
   1110 #endif
   1111     if (!m_preloads)
   1112         return;
   1113 
   1114     ListHashSet<Resource*>::iterator end = m_preloads->end();
   1115     for (ListHashSet<Resource*>::iterator it = m_preloads->begin(); it != end; ++it) {
   1116         Resource* res = *it;
   1117         res->decreasePreloadCount();
   1118         bool deleted = res->deleteIfPossible();
   1119         if (!deleted && res->preloadResult() == Resource::PreloadNotReferenced)
   1120             memoryCache()->remove(res);
   1121     }
   1122     m_preloads.clear();
   1123 }
   1124 
   1125 void ResourceFetcher::clearPendingPreloads()
   1126 {
   1127     m_pendingPreloads.clear();
   1128 }
   1129 
   1130 inline FrameLoader* ResourceFetcher::frameLoader()
   1131 {
   1132     if (Frame* frame = this->frame())
   1133         return frame->loader();
   1134     return 0;
   1135 }
   1136 
   1137 void ResourceFetcher::didFinishLoading(const Resource* resource, double finishTime, const ResourceLoaderOptions& options)
   1138 {
   1139     TRACE_EVENT_ASYNC_END0("net", "Resource", resource);
   1140     if (options.sendLoadCallbacks != SendCallbacks)
   1141         return;
   1142     if (FrameLoader* loader = frameLoader())
   1143         loader->notifier()->dispatchDidFinishLoading(m_documentLoader, resource->identifier(), finishTime);
   1144 }
   1145 
   1146 void ResourceFetcher::didChangeLoadingPriority(const Resource* resource, ResourceLoadPriority loadPriority)
   1147 {
   1148     TRACE_EVENT_ASYNC_STEP1("net", "Resource", resource, "ChangePriority", "priority", loadPriority);
   1149     if (FrameLoader* loader = frameLoader())
   1150         loader->client()->dispatchDidChangeResourcePriority(resource->identifier(), loadPriority);
   1151 }
   1152 
   1153 void ResourceFetcher::didFailLoading(const Resource* resource, const ResourceError& error, const ResourceLoaderOptions& options)
   1154 {
   1155     TRACE_EVENT_ASYNC_END0("net", "Resource", resource);
   1156     if (options.sendLoadCallbacks != SendCallbacks)
   1157         return;
   1158     if (FrameLoader* loader = frameLoader())
   1159         loader->notifier()->dispatchDidFail(m_documentLoader, resource->identifier(), error);
   1160 }
   1161 
   1162 void ResourceFetcher::willSendRequest(const Resource* resource, ResourceRequest& request, const ResourceResponse& redirectResponse, const ResourceLoaderOptions& options)
   1163 {
   1164     if (options.sendLoadCallbacks == SendCallbacks) {
   1165         if (FrameLoader* loader = frameLoader())
   1166             loader->notifier()->dispatchWillSendRequest(m_documentLoader, resource->identifier(), request, redirectResponse, options.initiatorInfo);
   1167     } else {
   1168         InspectorInstrumentation::willSendRequest(frame(), resource->identifier(), m_documentLoader, request, redirectResponse, options.initiatorInfo);
   1169     }
   1170 }
   1171 
   1172 void ResourceFetcher::didReceiveResponse(const Resource* resource, const ResourceResponse& response, const ResourceLoaderOptions& options)
   1173 {
   1174     if (options.sendLoadCallbacks != SendCallbacks)
   1175         return;
   1176     if (FrameLoader* loader = frameLoader())
   1177         loader->notifier()->dispatchDidReceiveResponse(m_documentLoader, resource->identifier(), response);
   1178 }
   1179 
   1180 void ResourceFetcher::didReceiveData(const Resource* resource, const char* data, int dataLength, int encodedDataLength, const ResourceLoaderOptions& options)
   1181 {
   1182     // FIXME: use frame of master document for imported documents.
   1183     InspectorInstrumentationCookie cookie = InspectorInstrumentation::willReceiveResourceData(frame(), resource->identifier(), encodedDataLength);
   1184     if (options.sendLoadCallbacks != SendCallbacks)
   1185         return;
   1186     if (FrameLoader* loader = frameLoader())
   1187         loader->notifier()->dispatchDidReceiveData(m_documentLoader, resource->identifier(), data, dataLength, encodedDataLength);
   1188     InspectorInstrumentation::didReceiveResourceData(cookie);
   1189 }
   1190 
   1191 void ResourceFetcher::subresourceLoaderFinishedLoadingOnePart(ResourceLoader* loader)
   1192 {
   1193     if (m_documentLoader)
   1194         m_documentLoader->subresourceLoaderFinishedLoadingOnePart(loader);
   1195 }
   1196 
   1197 void ResourceFetcher::didInitializeResourceLoader(ResourceLoader* loader)
   1198 {
   1199     if (m_documentLoader)
   1200         m_documentLoader->addResourceLoader(loader);
   1201 }
   1202 
   1203 void ResourceFetcher::willTerminateResourceLoader(ResourceLoader* loader)
   1204 {
   1205     if (m_documentLoader)
   1206         m_documentLoader->removeResourceLoader(loader);
   1207 }
   1208 
   1209 void ResourceFetcher::willStartLoadingResource(ResourceRequest& request)
   1210 {
   1211     if (m_documentLoader)
   1212         m_documentLoader->applicationCacheHost()->willStartLoadingResource(request);
   1213 }
   1214 
   1215 bool ResourceFetcher::defersLoading() const
   1216 {
   1217     if (Frame* frame = this->frame())
   1218         return frame->page()->defersLoading();
   1219     return false;
   1220 }
   1221 
   1222 bool ResourceFetcher::isLoadedBy(ResourceLoaderHost* possibleOwner) const
   1223 {
   1224     return this == possibleOwner;
   1225 }
   1226 
   1227 bool ResourceFetcher::shouldRequest(Resource* resource, const ResourceRequest& request, const ResourceLoaderOptions& options)
   1228 {
   1229     if (!canRequest(resource->type(), request.url(), options))
   1230         return false;
   1231     if (resource->type() == Resource::Image && shouldDeferImageLoad(request.url()))
   1232         return false;
   1233     return true;
   1234 }
   1235 
   1236 void ResourceFetcher::refResourceLoaderHost()
   1237 {
   1238     ref();
   1239 }
   1240 
   1241 void ResourceFetcher::derefResourceLoaderHost()
   1242 {
   1243     deref();
   1244 }
   1245 
   1246 #if PRELOAD_DEBUG
   1247 void ResourceFetcher::printPreloadStats()
   1248 {
   1249     unsigned scripts = 0;
   1250     unsigned scriptMisses = 0;
   1251     unsigned stylesheets = 0;
   1252     unsigned stylesheetMisses = 0;
   1253     unsigned images = 0;
   1254     unsigned imageMisses = 0;
   1255     ListHashSet<Resource*>::iterator end = m_preloads.end();
   1256     for (ListHashSet<Resource*>::iterator it = m_preloads.begin(); it != end; ++it) {
   1257         Resource* res = *it;
   1258         if (res->preloadResult() == Resource::PreloadNotReferenced)
   1259             printf("!! UNREFERENCED PRELOAD %s\n", res->url().latin1().data());
   1260         else if (res->preloadResult() == Resource::PreloadReferencedWhileComplete)
   1261             printf("HIT COMPLETE PRELOAD %s\n", res->url().latin1().data());
   1262         else if (res->preloadResult() == Resource::PreloadReferencedWhileLoading)
   1263             printf("HIT LOADING PRELOAD %s\n", res->url().latin1().data());
   1264 
   1265         if (res->type() == Resource::Script) {
   1266             scripts++;
   1267             if (res->preloadResult() < Resource::PreloadReferencedWhileLoading)
   1268                 scriptMisses++;
   1269         } else if (res->type() == Resource::CSSStyleSheet) {
   1270             stylesheets++;
   1271             if (res->preloadResult() < Resource::PreloadReferencedWhileLoading)
   1272                 stylesheetMisses++;
   1273         } else {
   1274             images++;
   1275             if (res->preloadResult() < Resource::PreloadReferencedWhileLoading)
   1276                 imageMisses++;
   1277         }
   1278 
   1279         if (res->errorOccurred())
   1280             memoryCache()->remove(res);
   1281 
   1282         res->decreasePreloadCount();
   1283     }
   1284     m_preloads.clear();
   1285 
   1286     if (scripts)
   1287         printf("SCRIPTS: %d (%d hits, hit rate %d%%)\n", scripts, scripts - scriptMisses, (scripts - scriptMisses) * 100 / scripts);
   1288     if (stylesheets)
   1289         printf("STYLESHEETS: %d (%d hits, hit rate %d%%)\n", stylesheets, stylesheets - stylesheetMisses, (stylesheets - stylesheetMisses) * 100 / stylesheets);
   1290     if (images)
   1291         printf("IMAGES:  %d (%d hits, hit rate %d%%)\n", images, images - imageMisses, (images - imageMisses) * 100 / images);
   1292 }
   1293 #endif
   1294 
   1295 const ResourceLoaderOptions& ResourceFetcher::defaultResourceOptions()
   1296 {
   1297     DEFINE_STATIC_LOCAL(ResourceLoaderOptions, options, (SendCallbacks, SniffContent, BufferData, AllowStoredCredentials, ClientRequestedCredentials, AskClientForCrossOriginCredentials, DoSecurityCheck, CheckContentSecurityPolicy, UseDefaultOriginRestrictionsForType, DocumentContext));
   1298     return options;
   1299 }
   1300 
   1301 }
   1302