Home | History | Annotate | Download | only in fetch
      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/fetch/ResourceFetcher.h"
     29 
     30 #include "bindings/v8/ScriptController.h"
     31 #include "core/dom/Document.h"
     32 #include "core/fetch/CSSStyleSheetResource.h"
     33 #include "core/fetch/CrossOriginAccessControl.h"
     34 #include "core/fetch/DocumentResource.h"
     35 #include "core/fetch/FetchContext.h"
     36 #include "core/fetch/FontResource.h"
     37 #include "core/fetch/ImageResource.h"
     38 #include "core/fetch/MemoryCache.h"
     39 #include "core/fetch/RawResource.h"
     40 #include "core/fetch/ResourceLoader.h"
     41 #include "core/fetch/ResourceLoaderSet.h"
     42 #include "core/fetch/ScriptResource.h"
     43 #include "core/fetch/XSLStyleSheetResource.h"
     44 #include "core/html/HTMLElement.h"
     45 #include "core/html/HTMLFrameOwnerElement.h"
     46 #include "core/html/imports/HTMLImportsController.h"
     47 #include "core/inspector/InspectorInstrumentation.h"
     48 #include "core/loader/DocumentLoader.h"
     49 #include "core/loader/FrameLoader.h"
     50 #include "core/loader/FrameLoaderClient.h"
     51 #include "core/loader/PingLoader.h"
     52 #include "core/loader/SubstituteData.h"
     53 #include "core/loader/UniqueIdentifier.h"
     54 #include "core/loader/appcache/ApplicationCacheHost.h"
     55 #include "core/frame/LocalDOMWindow.h"
     56 #include "core/frame/LocalFrame.h"
     57 #include "core/frame/csp/ContentSecurityPolicy.h"
     58 #include "core/timing/Performance.h"
     59 #include "core/timing/ResourceTimingInfo.h"
     60 #include "core/frame/Settings.h"
     61 #include "core/svg/graphics/SVGImageChromeClient.h"
     62 #include "platform/Logging.h"
     63 #include "platform/RuntimeEnabledFeatures.h"
     64 #include "platform/TraceEvent.h"
     65 #include "platform/weborigin/SecurityOrigin.h"
     66 #include "platform/weborigin/SecurityPolicy.h"
     67 #include "public/platform/Platform.h"
     68 #include "public/platform/WebURL.h"
     69 #include "wtf/text/CString.h"
     70 #include "wtf/text/WTFString.h"
     71 
     72 #define PRELOAD_DEBUG 0
     73 
     74 namespace WebCore {
     75 
     76 static Resource* createResource(Resource::Type type, const ResourceRequest& request, const String& charset)
     77 {
     78     switch (type) {
     79     case Resource::Image:
     80         return new ImageResource(request);
     81     case Resource::CSSStyleSheet:
     82         return new CSSStyleSheetResource(request, charset);
     83     case Resource::Script:
     84         return new ScriptResource(request, charset);
     85     case Resource::SVGDocument:
     86         return new DocumentResource(request, Resource::SVGDocument);
     87     case Resource::Font:
     88         return new FontResource(request);
     89     case Resource::MainResource:
     90     case Resource::Raw:
     91     case Resource::TextTrack:
     92     case Resource::Media:
     93         return new RawResource(request, type);
     94     case Resource::XSLStyleSheet:
     95         return new XSLStyleSheetResource(request, charset);
     96     case Resource::LinkPrefetch:
     97         return new Resource(request, Resource::LinkPrefetch);
     98     case Resource::LinkSubresource:
     99         return new Resource(request, Resource::LinkSubresource);
    100     case Resource::ImportResource:
    101         return new RawResource(request, type);
    102     }
    103 
    104     ASSERT_NOT_REACHED();
    105     return 0;
    106 }
    107 
    108 static ResourceLoadPriority loadPriority(Resource::Type type, const FetchRequest& request)
    109 {
    110     if (request.priority() != ResourceLoadPriorityUnresolved)
    111         return request.priority();
    112 
    113     switch (type) {
    114     case Resource::MainResource:
    115         return ResourceLoadPriorityVeryHigh;
    116     case Resource::CSSStyleSheet:
    117         return ResourceLoadPriorityHigh;
    118     case Resource::Raw:
    119         return request.options().synchronousPolicy == RequestSynchronously ? ResourceLoadPriorityVeryHigh : ResourceLoadPriorityMedium;
    120     case Resource::Script:
    121     case Resource::Font:
    122     case Resource::ImportResource:
    123         return ResourceLoadPriorityMedium;
    124     case Resource::Image:
    125         // We'll default images to VeryLow, and promote whatever is visible. This improves
    126         // speed-index by ~5% on average, ~14% at the 99th percentile.
    127         return ResourceLoadPriorityVeryLow;
    128     case Resource::Media:
    129         return ResourceLoadPriorityLow;
    130     case Resource::XSLStyleSheet:
    131         ASSERT(RuntimeEnabledFeatures::xsltEnabled());
    132         return ResourceLoadPriorityHigh;
    133     case Resource::SVGDocument:
    134         return ResourceLoadPriorityLow;
    135     case Resource::LinkPrefetch:
    136         return ResourceLoadPriorityVeryLow;
    137     case Resource::LinkSubresource:
    138         return ResourceLoadPriorityLow;
    139     case Resource::TextTrack:
    140         return ResourceLoadPriorityLow;
    141     }
    142     ASSERT_NOT_REACHED();
    143     return ResourceLoadPriorityUnresolved;
    144 }
    145 
    146 static Resource* resourceFromDataURIRequest(const ResourceRequest& request, const ResourceLoaderOptions& resourceOptions)
    147 {
    148     const KURL& url = request.url();
    149     ASSERT(url.protocolIsData());
    150 
    151     blink::WebString mimetype;
    152     blink::WebString charset;
    153     RefPtr<SharedBuffer> data = PassRefPtr<SharedBuffer>(blink::Platform::current()->parseDataURL(url, mimetype, charset));
    154     if (!data)
    155         return 0;
    156     ResourceResponse response(url, mimetype, data->size(), charset, String());
    157 
    158     Resource* resource = createResource(Resource::Image, request, charset);
    159     resource->setOptions(resourceOptions);
    160     resource->responseReceived(response);
    161     if (data->size())
    162         resource->setResourceBuffer(data);
    163     resource->finish();
    164     return resource;
    165 }
    166 
    167 static void populateResourceTiming(ResourceTimingInfo* info, Resource* resource, bool clearLoadTimings)
    168 {
    169     info->setInitialRequest(resource->resourceRequest());
    170     info->setFinalResponse(resource->response());
    171     if (clearLoadTimings) {
    172         info->clearLoadTimings();
    173         info->setLoadFinishTime(info->initialTime());
    174     } else {
    175         info->setLoadFinishTime(resource->loadFinishTime());
    176     }
    177 }
    178 
    179 static void reportResourceTiming(ResourceTimingInfo* info, Document* initiatorDocument, bool isMainResource)
    180 {
    181     if (initiatorDocument && isMainResource)
    182         initiatorDocument = initiatorDocument->parentDocument();
    183     if (!initiatorDocument || !initiatorDocument->loader())
    184         return;
    185     if (LocalDOMWindow* initiatorWindow = initiatorDocument->domWindow())
    186         initiatorWindow->performance().addResourceTiming(*info, initiatorDocument);
    187 }
    188 
    189 static ResourceRequest::TargetType requestTargetType(const ResourceFetcher* fetcher, const ResourceRequest& request, Resource::Type type)
    190 {
    191     switch (type) {
    192     case Resource::MainResource:
    193         if (fetcher->frame()->tree().parent())
    194             return ResourceRequest::TargetIsSubframe;
    195         return ResourceRequest::TargetIsMainFrame;
    196     case Resource::XSLStyleSheet:
    197         ASSERT(RuntimeEnabledFeatures::xsltEnabled());
    198     case Resource::CSSStyleSheet:
    199         return ResourceRequest::TargetIsStyleSheet;
    200     case Resource::Script:
    201         return ResourceRequest::TargetIsScript;
    202     case Resource::Font:
    203         return ResourceRequest::TargetIsFont;
    204     case Resource::Image:
    205         return ResourceRequest::TargetIsImage;
    206     case Resource::Raw:
    207     case Resource::ImportResource:
    208         return ResourceRequest::TargetIsSubresource;
    209     case Resource::LinkPrefetch:
    210         return ResourceRequest::TargetIsPrefetch;
    211     case Resource::LinkSubresource:
    212         return ResourceRequest::TargetIsSubresource;
    213     case Resource::TextTrack:
    214         return ResourceRequest::TargetIsTextTrack;
    215     case Resource::SVGDocument:
    216         return ResourceRequest::TargetIsImage;
    217     case Resource::Media:
    218         return ResourceRequest::TargetIsMedia;
    219     }
    220     ASSERT_NOT_REACHED();
    221     return ResourceRequest::TargetIsSubresource;
    222 }
    223 
    224 ResourceFetcher::ResourceFetcher(DocumentLoader* documentLoader)
    225     : m_document(nullptr)
    226     , m_documentLoader(documentLoader)
    227     , m_requestCount(0)
    228     , m_garbageCollectDocumentResourcesTimer(this, &ResourceFetcher::garbageCollectDocumentResourcesTimerFired)
    229     , m_resourceTimingReportTimer(this, &ResourceFetcher::resourceTimingReportTimerFired)
    230     , m_autoLoadImages(true)
    231     , m_imagesEnabled(true)
    232     , m_allowStaleResources(false)
    233 {
    234 }
    235 
    236 ResourceFetcher::~ResourceFetcher()
    237 {
    238     m_documentLoader = 0;
    239     m_document = nullptr;
    240 
    241     clearPreloads();
    242 
    243     // Make sure no requests still point to this ResourceFetcher
    244     ASSERT(!m_requestCount);
    245 }
    246 
    247 Resource* ResourceFetcher::cachedResource(const KURL& resourceURL) const
    248 {
    249     KURL url = MemoryCache::removeFragmentIdentifierIfNeeded(resourceURL);
    250     return m_documentResources.get(url).get();
    251 }
    252 
    253 LocalFrame* ResourceFetcher::frame() const
    254 {
    255     if (m_documentLoader)
    256         return m_documentLoader->frame();
    257     if (m_document && m_document->importsController())
    258         return m_document->importsController()->master()->frame();
    259     return 0;
    260 }
    261 
    262 FetchContext& ResourceFetcher::context() const
    263 {
    264     if (LocalFrame* frame = this->frame())
    265         return frame->fetchContext();
    266     return FetchContext::nullInstance();
    267 }
    268 
    269 ResourcePtr<Resource> ResourceFetcher::fetchSynchronously(FetchRequest& request)
    270 {
    271     ASSERT(document());
    272     request.mutableResourceRequest().setTimeoutInterval(10);
    273     ResourceLoaderOptions options(request.options());
    274     options.synchronousPolicy = RequestSynchronously;
    275     request.setOptions(options);
    276     return requestResource(Resource::Raw, request);
    277 }
    278 
    279 ResourcePtr<ImageResource> ResourceFetcher::fetchImage(FetchRequest& request)
    280 {
    281     if (LocalFrame* f = frame()) {
    282         if (f->document()->pageDismissalEventBeingDispatched() != Document::NoDismissal) {
    283             KURL requestURL = request.resourceRequest().url();
    284             if (requestURL.isValid() && canRequest(Resource::Image, requestURL, request.options(), request.forPreload(), request.originRestriction()))
    285                 PingLoader::loadImage(f, requestURL);
    286             return 0;
    287         }
    288     }
    289 
    290     if (request.resourceRequest().url().protocolIsData())
    291         preCacheDataURIImage(request);
    292 
    293     request.setDefer(clientDefersImage(request.resourceRequest().url()) ? FetchRequest::DeferredByClient : FetchRequest::NoDefer);
    294     return toImageResource(requestResource(Resource::Image, request));
    295 }
    296 
    297 void ResourceFetcher::preCacheDataURIImage(const FetchRequest& request)
    298 {
    299     const KURL& url = request.resourceRequest().url();
    300     ASSERT(url.protocolIsData());
    301 
    302     if (memoryCache()->resourceForURL(url))
    303         return;
    304 
    305     if (Resource* resource = resourceFromDataURIRequest(request.resourceRequest(), request.options())) {
    306         memoryCache()->add(resource);
    307         scheduleDocumentResourcesGC();
    308     }
    309 }
    310 
    311 ResourcePtr<FontResource> ResourceFetcher::fetchFont(FetchRequest& request)
    312 {
    313     return toFontResource(requestResource(Resource::Font, request));
    314 }
    315 
    316 ResourcePtr<RawResource> ResourceFetcher::fetchImport(FetchRequest& request)
    317 {
    318     return toRawResource(requestResource(Resource::ImportResource, request));
    319 }
    320 
    321 ResourcePtr<CSSStyleSheetResource> ResourceFetcher::fetchCSSStyleSheet(FetchRequest& request)
    322 {
    323     return toCSSStyleSheetResource(requestResource(Resource::CSSStyleSheet, request));
    324 }
    325 
    326 ResourcePtr<CSSStyleSheetResource> ResourceFetcher::fetchUserCSSStyleSheet(FetchRequest& request)
    327 {
    328     KURL url = MemoryCache::removeFragmentIdentifierIfNeeded(request.resourceRequest().url());
    329 
    330     if (Resource* existing = memoryCache()->resourceForURL(url)) {
    331         if (existing->type() == Resource::CSSStyleSheet)
    332             return toCSSStyleSheetResource(existing);
    333         memoryCache()->remove(existing);
    334     }
    335 
    336     request.setOptions(ResourceLoaderOptions(SniffContent, BufferData, AllowStoredCredentials, ClientRequestedCredentials, CheckContentSecurityPolicy, DocumentContext));
    337     return toCSSStyleSheetResource(requestResource(Resource::CSSStyleSheet, request));
    338 }
    339 
    340 ResourcePtr<ScriptResource> ResourceFetcher::fetchScript(FetchRequest& request)
    341 {
    342     return toScriptResource(requestResource(Resource::Script, request));
    343 }
    344 
    345 ResourcePtr<XSLStyleSheetResource> ResourceFetcher::fetchXSLStyleSheet(FetchRequest& request)
    346 {
    347     ASSERT(RuntimeEnabledFeatures::xsltEnabled());
    348     return toXSLStyleSheetResource(requestResource(Resource::XSLStyleSheet, request));
    349 }
    350 
    351 ResourcePtr<DocumentResource> ResourceFetcher::fetchSVGDocument(FetchRequest& request)
    352 {
    353     return toDocumentResource(requestResource(Resource::SVGDocument, request));
    354 }
    355 
    356 ResourcePtr<Resource> ResourceFetcher::fetchLinkResource(Resource::Type type, FetchRequest& request)
    357 {
    358     ASSERT(frame());
    359     ASSERT(type == Resource::LinkPrefetch || type == Resource::LinkSubresource);
    360     return requestResource(type, request);
    361 }
    362 
    363 ResourcePtr<RawResource> ResourceFetcher::fetchRawResource(FetchRequest& request)
    364 {
    365     return toRawResource(requestResource(Resource::Raw, request));
    366 }
    367 
    368 ResourcePtr<RawResource> ResourceFetcher::fetchMainResource(FetchRequest& request, const SubstituteData& substituteData)
    369 {
    370     if (substituteData.isValid())
    371         preCacheSubstituteDataForMainResource(request, substituteData);
    372     return toRawResource(requestResource(Resource::MainResource, request));
    373 }
    374 
    375 ResourcePtr<RawResource> ResourceFetcher::fetchMedia(FetchRequest& request)
    376 {
    377     return toRawResource(requestResource(Resource::Media, request));
    378 }
    379 
    380 ResourcePtr<RawResource> ResourceFetcher::fetchTextTrack(FetchRequest& request)
    381 {
    382     return toRawResource(requestResource(Resource::TextTrack, request));
    383 }
    384 
    385 void ResourceFetcher::preCacheSubstituteDataForMainResource(const FetchRequest& request, const SubstituteData& substituteData)
    386 {
    387     const KURL& url = request.url();
    388     if (Resource* oldResource = memoryCache()->resourceForURL(url))
    389         memoryCache()->remove(oldResource);
    390 
    391     ResourceResponse response(url, substituteData.mimeType(), substituteData.content()->size(), substituteData.textEncoding(), emptyString());
    392     ResourcePtr<Resource> resource = createResource(Resource::MainResource, request.resourceRequest(), substituteData.textEncoding());
    393     resource->setNeedsSynchronousCacheHit(substituteData.forceSynchronousLoad());
    394     resource->setOptions(request.options());
    395     resource->setDataBufferingPolicy(BufferData);
    396     resource->responseReceived(response);
    397     if (substituteData.content()->size())
    398         resource->setResourceBuffer(substituteData.content());
    399     resource->finish();
    400     memoryCache()->add(resource.get());
    401 }
    402 
    403 bool ResourceFetcher::checkInsecureContent(Resource::Type type, const KURL& url, MixedContentBlockingTreatment treatment) const
    404 {
    405     if (treatment == TreatAsDefaultForType) {
    406         switch (type) {
    407         case Resource::XSLStyleSheet:
    408             ASSERT(RuntimeEnabledFeatures::xsltEnabled());
    409         case Resource::Script:
    410         case Resource::SVGDocument:
    411         case Resource::CSSStyleSheet:
    412         case Resource::ImportResource:
    413             // These resource can inject script into the current document (Script,
    414             // XSL) or exfiltrate the content of the current document (CSS).
    415             treatment = TreatAsActiveContent;
    416             break;
    417 
    418         case Resource::Font:
    419             // These resources are passive, but mixed usage is low enough that we
    420             // can block them in a mixed context.
    421             treatment = TreatAsActiveContent;
    422             break;
    423 
    424         case Resource::TextTrack:
    425         case Resource::Raw:
    426         case Resource::Image:
    427         case Resource::Media:
    428             // These resources can corrupt only the frame's pixels.
    429             treatment = TreatAsPassiveContent;
    430             break;
    431 
    432         case Resource::MainResource:
    433         case Resource::LinkPrefetch:
    434         case Resource::LinkSubresource:
    435             // These cannot affect the current document.
    436             treatment = TreatAsAlwaysAllowedContent;
    437             break;
    438         }
    439     }
    440     // FIXME: We need a way to access the top-level frame's mixedContentChecker when that frame
    441     // is in a different process from the current frame. Until that is done, we fail loading
    442     // mixed content in remote frames.
    443     if (frame() && !frame()->tree().top()->isLocalFrame())
    444         return false;
    445     if (treatment == TreatAsActiveContent) {
    446         if (LocalFrame* f = frame()) {
    447             if (!f->loader().mixedContentChecker()->canRunInsecureContent(m_document->securityOrigin(), url))
    448                 return false;
    449             Frame* top = f->tree().top();
    450             if (top != f && !toLocalFrame(top)->loader().mixedContentChecker()->canRunInsecureContent(toLocalFrame(top)->document()->securityOrigin(), url))
    451                 return false;
    452         }
    453     } else if (treatment == TreatAsPassiveContent) {
    454         if (LocalFrame* f = frame()) {
    455             Frame* top = f->tree().top();
    456             if (!toLocalFrame(top)->loader().mixedContentChecker()->canDisplayInsecureContent(toLocalFrame(top)->document()->securityOrigin(), url))
    457                 return false;
    458             if (MixedContentChecker::isMixedContent(toLocalFrame(top)->document()->securityOrigin(), url)) {
    459                 switch (type) {
    460                 case Resource::TextTrack:
    461                     UseCounter::count(toLocalFrame(top)->document(), UseCounter::MixedContentTextTrack);
    462                     break;
    463 
    464                 case Resource::Raw:
    465                     UseCounter::count(toLocalFrame(top)->document(), UseCounter::MixedContentRaw);
    466                     break;
    467 
    468                 case Resource::Image:
    469                     UseCounter::count(toLocalFrame(top)->document(), UseCounter::MixedContentImage);
    470                     break;
    471 
    472                 case Resource::Media:
    473                     UseCounter::count(toLocalFrame(top)->document(), UseCounter::MixedContentMedia);
    474                     break;
    475 
    476                 default:
    477                     ASSERT_NOT_REACHED();
    478                 }
    479             }
    480         }
    481     } else {
    482         ASSERT(treatment == TreatAsAlwaysAllowedContent);
    483     }
    484     return true;
    485 }
    486 
    487 bool ResourceFetcher::canRequest(Resource::Type type, const KURL& url, const ResourceLoaderOptions& options, bool forPreload, FetchRequest::OriginRestriction originRestriction) const
    488 {
    489     SecurityOrigin* securityOrigin = options.securityOrigin.get();
    490     if (!securityOrigin && document())
    491         securityOrigin = document()->securityOrigin();
    492 
    493     if (securityOrigin && !securityOrigin->canDisplay(url)) {
    494         if (!forPreload)
    495             context().reportLocalLoadFailed(url);
    496         WTF_LOG(ResourceLoading, "ResourceFetcher::requestResource URL was not allowed by SecurityOrigin::canDisplay");
    497         return 0;
    498     }
    499 
    500     // FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved.
    501     bool shouldBypassMainWorldContentSecurityPolicy = (frame() && frame()->script().shouldBypassMainWorldContentSecurityPolicy()) || (options.contentSecurityPolicyOption == DoNotCheckContentSecurityPolicy);
    502 
    503     // Some types of resources can be loaded only from the same origin. Other
    504     // types of resources, like Images, Scripts, and CSS, can be loaded from
    505     // any URL.
    506     switch (type) {
    507     case Resource::MainResource:
    508     case Resource::Image:
    509     case Resource::CSSStyleSheet:
    510     case Resource::Script:
    511     case Resource::Font:
    512     case Resource::Raw:
    513     case Resource::LinkPrefetch:
    514     case Resource::LinkSubresource:
    515     case Resource::TextTrack:
    516     case Resource::ImportResource:
    517     case Resource::Media:
    518         // By default these types of resources can be loaded from any origin.
    519         // FIXME: Are we sure about Resource::Font?
    520         if (originRestriction == FetchRequest::RestrictToSameOrigin && !securityOrigin->canRequest(url)) {
    521             printAccessDeniedMessage(url);
    522             return false;
    523         }
    524         break;
    525     case Resource::XSLStyleSheet:
    526         ASSERT(RuntimeEnabledFeatures::xsltEnabled());
    527     case Resource::SVGDocument:
    528         if (!securityOrigin->canRequest(url)) {
    529             printAccessDeniedMessage(url);
    530             return false;
    531         }
    532         break;
    533     }
    534 
    535     // Don't send CSP messages for preloads, we might never actually display those items.
    536     ContentSecurityPolicy::ReportingStatus cspReporting = forPreload ?
    537         ContentSecurityPolicy::SuppressReport : ContentSecurityPolicy::SendReport;
    538 
    539     switch (type) {
    540     case Resource::XSLStyleSheet:
    541         ASSERT(RuntimeEnabledFeatures::xsltEnabled());
    542         if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowScriptFromSource(url, cspReporting))
    543             return false;
    544         break;
    545     case Resource::Script:
    546     case Resource::ImportResource:
    547         if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowScriptFromSource(url, cspReporting))
    548             return false;
    549 
    550         if (frame()) {
    551             Settings* settings = frame()->settings();
    552             if (!frame()->loader().client()->allowScriptFromSource(!settings || settings->scriptEnabled(), url)) {
    553                 frame()->loader().client()->didNotAllowScript();
    554                 return false;
    555             }
    556         }
    557         break;
    558     case Resource::CSSStyleSheet:
    559         if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowStyleFromSource(url, cspReporting))
    560             return false;
    561         break;
    562     case Resource::SVGDocument:
    563     case Resource::Image:
    564         if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowImageFromSource(url, cspReporting))
    565             return false;
    566         break;
    567     case Resource::Font: {
    568         if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowFontFromSource(url, cspReporting))
    569             return false;
    570         break;
    571     }
    572     case Resource::MainResource:
    573     case Resource::Raw:
    574     case Resource::LinkPrefetch:
    575     case Resource::LinkSubresource:
    576         break;
    577     case Resource::Media:
    578     case Resource::TextTrack:
    579         if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowMediaFromSource(url, cspReporting))
    580             return false;
    581         break;
    582     }
    583 
    584     // SVG Images have unique security rules that prevent all subresource requests
    585     // except for data urls.
    586     if (type != Resource::MainResource) {
    587         if (frame() && frame()->chromeClient().isSVGImageChromeClient() && !url.protocolIsData())
    588             return false;
    589     }
    590 
    591     // Last of all, check for insecure content. We do this last so that when
    592     // folks block insecure content with a CSP policy, they don't get a warning.
    593     // They'll still get a warning in the console about CSP blocking the load.
    594 
    595     // FIXME: Should we consider forPreload here?
    596     if (!checkInsecureContent(type, url, options.mixedContentBlockingTreatment))
    597         return false;
    598 
    599     return true;
    600 }
    601 
    602 bool ResourceFetcher::canAccessResource(Resource* resource, SecurityOrigin* sourceOrigin, const KURL& url) const
    603 {
    604     // Redirects can change the response URL different from one of request.
    605     if (!canRequest(resource->type(), url, resource->options(), false, FetchRequest::UseDefaultOriginRestrictionForType))
    606         return false;
    607 
    608     if (!sourceOrigin && document())
    609         sourceOrigin = document()->securityOrigin();
    610 
    611     if (sourceOrigin->canRequest(url))
    612         return true;
    613 
    614     String errorDescription;
    615     if (!resource->passesAccessControlCheck(sourceOrigin, errorDescription)) {
    616         if (frame() && frame()->document()) {
    617             String resourceType = Resource::resourceTypeToString(resource->type(), resource->options().initiatorInfo);
    618             frame()->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, resourceType + " from origin '" + SecurityOrigin::create(url)->toString() + "' has been blocked from loading by Cross-Origin Resource Sharing policy: " + errorDescription);
    619         }
    620         return false;
    621     }
    622     return true;
    623 }
    624 
    625 bool ResourceFetcher::shouldLoadNewResource(Resource::Type type) const
    626 {
    627     if (!frame())
    628         return false;
    629     if (!m_documentLoader)
    630         return true;
    631     if (type == Resource::MainResource)
    632         return m_documentLoader == frame()->loader().provisionalDocumentLoader();
    633     return m_documentLoader == frame()->loader().documentLoader();
    634 }
    635 
    636 bool ResourceFetcher::resourceNeedsLoad(Resource* resource, const FetchRequest& request, RevalidationPolicy policy)
    637 {
    638     if (FetchRequest::DeferredByClient == request.defer())
    639         return false;
    640     if (policy != Use)
    641         return true;
    642     if (resource->stillNeedsLoad())
    643         return true;
    644     return request.options().synchronousPolicy == RequestSynchronously && resource->isLoading();
    645 }
    646 
    647 void ResourceFetcher::requestLoadStarted(Resource* resource, const FetchRequest& request, ResourceLoadStartType type)
    648 {
    649     if (type == ResourceLoadingFromCache)
    650         notifyLoadedFromMemoryCache(resource);
    651 
    652     if (request.resourceRequest().url().protocolIsData() || (m_documentLoader && m_documentLoader->substituteData().isValid()))
    653         return;
    654 
    655     if (type == ResourceLoadingFromCache && !m_validatedURLs.contains(request.resourceRequest().url())) {
    656         // Resources loaded from memory cache should be reported the first time they're used.
    657         RefPtr<ResourceTimingInfo> info = ResourceTimingInfo::create(request.options().initiatorInfo.name, monotonicallyIncreasingTime());
    658         populateResourceTiming(info.get(), resource, true);
    659         m_scheduledResourceTimingReports.add(info, resource->type() == Resource::MainResource);
    660         if (!m_resourceTimingReportTimer.isActive())
    661             m_resourceTimingReportTimer.startOneShot(0, FROM_HERE);
    662     }
    663 
    664     m_validatedURLs.add(request.resourceRequest().url());
    665 }
    666 
    667 ResourcePtr<Resource> ResourceFetcher::requestResource(Resource::Type type, FetchRequest& request)
    668 {
    669     ASSERT(request.options().synchronousPolicy == RequestAsynchronously || type == Resource::Raw);
    670 
    671     TRACE_EVENT0("webkit", "ResourceFetcher::requestResource");
    672 
    673     KURL url = request.resourceRequest().url();
    674 
    675     WTF_LOG(ResourceLoading, "ResourceFetcher::requestResource '%s', charset '%s', priority=%d, forPreload=%u, type=%s", url.elidedString().latin1().data(), request.charset().latin1().data(), request.priority(), request.forPreload(), ResourceTypeName(type));
    676 
    677     // If only the fragment identifiers differ, it is the same resource.
    678     url = MemoryCache::removeFragmentIdentifierIfNeeded(url);
    679 
    680     if (!url.isValid())
    681         return 0;
    682 
    683     if (!canRequest(type, url, request.options(), request.forPreload(), request.originRestriction()))
    684         return 0;
    685 
    686     if (LocalFrame* f = frame())
    687         f->loader().client()->dispatchWillRequestResource(&request);
    688 
    689     // See if we can use an existing resource from the cache.
    690     ResourcePtr<Resource> resource = memoryCache()->resourceForURL(url);
    691 
    692     const RevalidationPolicy policy = determineRevalidationPolicy(type, request.mutableResourceRequest(), request.forPreload(), resource.get(), request.defer(), request.options());
    693     switch (policy) {
    694     case Reload:
    695         memoryCache()->remove(resource.get());
    696         // Fall through
    697     case Load:
    698         resource = createResourceForLoading(type, request, request.charset());
    699         break;
    700     case Revalidate:
    701         resource = createResourceForRevalidation(request, resource.get());
    702         break;
    703     case Use:
    704         memoryCache()->updateForAccess(resource.get());
    705         break;
    706     }
    707 
    708     if (!resource)
    709         return 0;
    710 
    711     if (!resource->hasClients())
    712         m_deadStatsRecorder.update(policy);
    713 
    714     if (policy != Use)
    715         resource->setIdentifier(createUniqueIdentifier());
    716 
    717     if (!request.forPreload() || policy != Use) {
    718         ResourceLoadPriority priority = loadPriority(type, request);
    719         if (priority != resource->resourceRequest().priority()) {
    720             resource->resourceRequest().setPriority(priority);
    721             resource->didChangePriority(priority, 0);
    722         }
    723     }
    724 
    725     if (resourceNeedsLoad(resource.get(), request, policy)) {
    726         if (!shouldLoadNewResource(type)) {
    727             if (memoryCache()->contains(resource.get()))
    728                 memoryCache()->remove(resource.get());
    729             return 0;
    730         }
    731 
    732         if (!m_documentLoader || !m_documentLoader->scheduleArchiveLoad(resource.get(), request.resourceRequest()))
    733             resource->load(this, request.options());
    734 
    735         // For asynchronous loads that immediately fail, it's sufficient to return a
    736         // null Resource, as it indicates that something prevented the load from starting.
    737         // If there's a network error, that failure will happen asynchronously. However, if
    738         // a sync load receives a network error, it will have already happened by this point.
    739         // In that case, the requester should have access to the relevant ResourceError, so
    740         // we need to return a non-null Resource.
    741         if (resource->errorOccurred()) {
    742             if (memoryCache()->contains(resource.get()))
    743                 memoryCache()->remove(resource.get());
    744             return request.options().synchronousPolicy == RequestSynchronously ? resource : 0;
    745         }
    746     }
    747 
    748     // FIXME: Temporarily leave main resource caching disabled for chromium,
    749     // see https://bugs.webkit.org/show_bug.cgi?id=107962. Before caching main
    750     // resources, we should be sure to understand the implications for memory
    751     // use.
    752     // Remove main resource from cache to prevent reuse.
    753     if (type == Resource::MainResource) {
    754         ASSERT(policy != Use || m_documentLoader->substituteData().isValid());
    755         ASSERT(policy != Revalidate);
    756         memoryCache()->remove(resource.get());
    757     }
    758 
    759     requestLoadStarted(resource.get(), request, policy == Use ? ResourceLoadingFromCache : ResourceLoadingFromNetwork);
    760 
    761     ASSERT(resource->url() == url.string());
    762     m_documentResources.set(resource->url(), resource);
    763     return resource;
    764 }
    765 
    766 void ResourceFetcher::resourceTimingReportTimerFired(Timer<ResourceFetcher>* timer)
    767 {
    768     ASSERT_UNUSED(timer, timer == &m_resourceTimingReportTimer);
    769     HashMap<RefPtr<ResourceTimingInfo>, bool> timingReports;
    770     timingReports.swap(m_scheduledResourceTimingReports);
    771     HashMap<RefPtr<ResourceTimingInfo>, bool>::iterator end = timingReports.end();
    772     for (HashMap<RefPtr<ResourceTimingInfo>, bool>::iterator it = timingReports.begin(); it != end; ++it) {
    773         RefPtr<ResourceTimingInfo> info = it->key;
    774         bool isMainResource = it->value;
    775         reportResourceTiming(info.get(), document(), isMainResource);
    776     }
    777 }
    778 
    779 void ResourceFetcher::determineTargetType(ResourceRequest& request, Resource::Type type)
    780 {
    781     ResourceRequest::TargetType targetType = requestTargetType(this, request, type);
    782     request.setTargetType(targetType);
    783 }
    784 
    785 ResourceRequestCachePolicy ResourceFetcher::resourceRequestCachePolicy(const ResourceRequest& request, Resource::Type type)
    786 {
    787     if (type == Resource::MainResource) {
    788         FrameLoadType frameLoadType = frame()->loader().loadType();
    789         if (request.httpMethod() == "POST" && frameLoadType == FrameLoadTypeBackForward)
    790             return ReturnCacheDataDontLoad;
    791         if (!m_documentLoader->overrideEncoding().isEmpty() || frameLoadType == FrameLoadTypeBackForward)
    792             return ReturnCacheDataElseLoad;
    793         if (frameLoadType == FrameLoadTypeReloadFromOrigin)
    794             return ReloadBypassingCache;
    795         if (frameLoadType == FrameLoadTypeReload || frameLoadType == FrameLoadTypeSame || request.isConditional() || request.httpMethod() == "POST")
    796             return ReloadIgnoringCacheData;
    797         Frame* parent = frame()->tree().parent();
    798         if (parent && parent->isLocalFrame())
    799             return toLocalFrame(parent)->document()->fetcher()->resourceRequestCachePolicy(request, type);
    800         return UseProtocolCachePolicy;
    801     }
    802 
    803     if (request.isConditional())
    804         return ReloadIgnoringCacheData;
    805 
    806     if (m_documentLoader && m_document && !m_document->loadEventFinished()) {
    807         // For POST requests, we mutate the main resource's cache policy to avoid form resubmission.
    808         // This policy should not be inherited by subresources.
    809         ResourceRequestCachePolicy mainResourceCachePolicy = m_documentLoader->request().cachePolicy();
    810         if (mainResourceCachePolicy == ReturnCacheDataDontLoad)
    811             return ReturnCacheDataElseLoad;
    812         return mainResourceCachePolicy;
    813     }
    814     return UseProtocolCachePolicy;
    815 }
    816 
    817 void ResourceFetcher::addAdditionalRequestHeaders(ResourceRequest& request, Resource::Type type)
    818 {
    819     if (!frame())
    820         return;
    821 
    822     if (request.cachePolicy() == UseProtocolCachePolicy)
    823         request.setCachePolicy(resourceRequestCachePolicy(request, type));
    824     if (request.targetType() == ResourceRequest::TargetIsUnspecified)
    825         determineTargetType(request, type);
    826     if (type == Resource::LinkPrefetch || type == Resource::LinkSubresource)
    827         request.setHTTPHeaderField("Purpose", "prefetch");
    828 
    829     context().addAdditionalRequestHeaders(document(), request, (type == Resource::MainResource) ? FetchMainResource : FetchSubresource);
    830 }
    831 
    832 ResourcePtr<Resource> ResourceFetcher::createResourceForRevalidation(const FetchRequest& request, Resource* resource)
    833 {
    834     ASSERT(resource);
    835     ASSERT(memoryCache()->contains(resource));
    836     ASSERT(resource->isLoaded());
    837     ASSERT(resource->canUseCacheValidator());
    838     ASSERT(!resource->resourceToRevalidate());
    839 
    840     ResourceRequest revalidatingRequest(resource->resourceRequest());
    841     revalidatingRequest.clearHTTPReferrer();
    842     addAdditionalRequestHeaders(revalidatingRequest, resource->type());
    843 
    844     const AtomicString& lastModified = resource->response().httpHeaderField("Last-Modified");
    845     const AtomicString& eTag = resource->response().httpHeaderField("ETag");
    846     if (!lastModified.isEmpty() || !eTag.isEmpty()) {
    847         ASSERT(context().cachePolicy(document()) != CachePolicyReload);
    848         if (context().cachePolicy(document()) == CachePolicyRevalidate)
    849             revalidatingRequest.setHTTPHeaderField("Cache-Control", "max-age=0");
    850     }
    851     if (!lastModified.isEmpty())
    852         revalidatingRequest.setHTTPHeaderField("If-Modified-Since", lastModified);
    853     if (!eTag.isEmpty())
    854         revalidatingRequest.setHTTPHeaderField("If-None-Match", eTag);
    855 
    856     ResourcePtr<Resource> newResource = createResource(resource->type(), revalidatingRequest, resource->encoding());
    857     WTF_LOG(ResourceLoading, "Resource %p created to revalidate %p", newResource.get(), resource);
    858 
    859     newResource->setResourceToRevalidate(resource);
    860 
    861     memoryCache()->remove(resource);
    862     memoryCache()->add(newResource.get());
    863     return newResource;
    864 }
    865 
    866 ResourcePtr<Resource> ResourceFetcher::createResourceForLoading(Resource::Type type, FetchRequest& request, const String& charset)
    867 {
    868     ASSERT(!memoryCache()->resourceForURL(request.resourceRequest().url()));
    869 
    870     WTF_LOG(ResourceLoading, "Loading Resource for '%s'.", request.resourceRequest().url().elidedString().latin1().data());
    871 
    872     addAdditionalRequestHeaders(request.mutableResourceRequest(), type);
    873     ResourcePtr<Resource> resource = createResource(type, request.resourceRequest(), charset);
    874 
    875     memoryCache()->add(resource.get());
    876     return resource;
    877 }
    878 
    879 void ResourceFetcher::storeResourceTimingInitiatorInformation(Resource* resource)
    880 {
    881     if (resource->options().requestInitiatorContext != DocumentContext)
    882         return;
    883 
    884     RefPtr<ResourceTimingInfo> info = ResourceTimingInfo::create(resource->options().initiatorInfo.name, monotonicallyIncreasingTime());
    885 
    886     if (resource->isCacheValidator()) {
    887         const AtomicString& timingAllowOrigin = resource->resourceToRevalidate()->response().httpHeaderField("Timing-Allow-Origin");
    888         if (!timingAllowOrigin.isEmpty())
    889             info->setOriginalTimingAllowOrigin(timingAllowOrigin);
    890     }
    891 
    892     if (resource->type() == Resource::MainResource) {
    893         // <iframe>s should report the initial navigation requested by the parent document, but not subsequent navigations.
    894         // FIXME: Resource timing is broken when the parent is a remote frame.
    895         if (frame()->deprecatedLocalOwner() && !frame()->deprecatedLocalOwner()->loadedNonEmptyDocument()) {
    896             info->setInitiatorType(frame()->deprecatedLocalOwner()->localName());
    897             m_resourceTimingInfoMap.add(resource, info);
    898             frame()->deprecatedLocalOwner()->didLoadNonEmptyDocument();
    899         }
    900     } else {
    901         m_resourceTimingInfoMap.add(resource, info);
    902     }
    903 }
    904 
    905 ResourceFetcher::RevalidationPolicy ResourceFetcher::determineRevalidationPolicy(Resource::Type type, ResourceRequest& request, bool forPreload, Resource* existingResource, FetchRequest::DeferOption defer, const ResourceLoaderOptions& options) const
    906 {
    907     if (!existingResource)
    908         return Load;
    909 
    910     // We already have a preload going for this URL.
    911     if (forPreload && existingResource->isPreloaded())
    912         return Use;
    913 
    914     // If the same URL has been loaded as a different type, we need to reload.
    915     if (existingResource->type() != type) {
    916         WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to type mismatch.");
    917         return Reload;
    918     }
    919 
    920     // Do not load from cache if images are not enabled. The load for this image will be blocked
    921     // in ImageResource::load.
    922     if (FetchRequest::DeferredByClient == defer)
    923         return Reload;
    924 
    925     // Always use data uris.
    926     // FIXME: Extend this to non-images.
    927     if (type == Resource::Image && request.url().protocolIsData())
    928         return Use;
    929 
    930     // If a main resource was populated from a SubstituteData load, use it.
    931     if (type == Resource::MainResource && m_documentLoader->substituteData().isValid())
    932         return Use;
    933 
    934     if (!existingResource->canReuse(request))
    935         return Reload;
    936 
    937     // Never use cache entries for downloadToFile requests. The caller expects the resource in a file.
    938     if (request.downloadToFile())
    939         return Reload;
    940 
    941     // Certain requests (e.g., XHRs) might have manually set headers that require revalidation.
    942     // FIXME: In theory, this should be a Revalidate case. In practice, the MemoryCache revalidation path assumes a whole bunch
    943     // of things about how revalidation works that manual headers violate, so punt to Reload instead.
    944     if (request.isConditional())
    945         return Reload;
    946 
    947     // Don't reload resources while pasting.
    948     if (m_allowStaleResources)
    949         return Use;
    950 
    951     // Always use preloads.
    952     if (existingResource->isPreloaded())
    953         return Use;
    954 
    955     // CachePolicyHistoryBuffer uses the cache no matter what.
    956     CachePolicy cachePolicy = context().cachePolicy(document());
    957     if (cachePolicy == CachePolicyHistoryBuffer)
    958         return Use;
    959 
    960     // Don't reuse resources with Cache-control: no-store.
    961     if (existingResource->hasCacheControlNoStoreHeader()) {
    962         WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to Cache-control: no-store.");
    963         return Reload;
    964     }
    965 
    966     // If fetching a resource with a different 'CORS enabled' flag, reload.
    967     if (type != Resource::MainResource && options.corsEnabled != existingResource->options().corsEnabled)
    968         return Reload;
    969 
    970     // If credentials were sent with the previous request and won't be
    971     // with this one, or vice versa, re-fetch the resource.
    972     //
    973     // This helps with the case where the server sends back
    974     // "Access-Control-Allow-Origin: *" all the time, but some of the
    975     // client's requests are made without CORS and some with.
    976     if (existingResource->resourceRequest().allowStoredCredentials() != request.allowStoredCredentials()) {
    977         WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to difference in credentials settings.");
    978         return Reload;
    979     }
    980 
    981     // During the initial load, avoid loading the same resource multiple times for a single document,
    982     // even if the cache policies would tell us to.
    983     // We also group loads of the same resource together.
    984     // Raw resources are exempted, as XHRs fall into this category and may have user-set Cache-Control:
    985     // headers or other factors that require separate requests.
    986     if (type != Resource::Raw) {
    987         if (document() && !document()->loadEventFinished() && m_validatedURLs.contains(existingResource->url()))
    988             return Use;
    989         if (existingResource->isLoading())
    990             return Use;
    991     }
    992 
    993     // CachePolicyReload always reloads
    994     if (cachePolicy == CachePolicyReload) {
    995         WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to CachePolicyReload.");
    996         return Reload;
    997     }
    998 
    999     // We'll try to reload the resource if it failed last time.
   1000     if (existingResource->errorOccurred()) {
   1001         WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicye reloading due to resource being in the error state");
   1002         return Reload;
   1003     }
   1004 
   1005     // List of available images logic allows images to be re-used without cache validation. We restrict this only to images
   1006     // from memory cache which are the same as the version in the current document.
   1007     if (type == Resource::Image && existingResource == cachedResource(request.url()))
   1008         return Use;
   1009 
   1010     // If any of the redirects in the chain to loading the resource were not cacheable, we cannot reuse our cached resource.
   1011     if (!existingResource->canReuseRedirectChain()) {
   1012         WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to an uncacheable redirect");
   1013         return Reload;
   1014     }
   1015 
   1016     // Check if the cache headers requires us to revalidate (cache expiration for example).
   1017     if (cachePolicy == CachePolicyRevalidate || existingResource->mustRevalidateDueToCacheHeaders()
   1018         || request.cacheControlContainsNoCache()) {
   1019         // See if the resource has usable ETag or Last-modified headers.
   1020         if (existingResource->canUseCacheValidator())
   1021             return Revalidate;
   1022 
   1023         // No, must reload.
   1024         WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to missing cache validators.");
   1025         return Reload;
   1026     }
   1027 
   1028     return Use;
   1029 }
   1030 
   1031 void ResourceFetcher::printAccessDeniedMessage(const KURL& url) const
   1032 {
   1033     if (url.isNull())
   1034         return;
   1035 
   1036     if (!frame())
   1037         return;
   1038 
   1039     String message;
   1040     if (!m_document || m_document->url().isNull())
   1041         message = "Unsafe attempt to load URL " + url.elidedString() + '.';
   1042     else
   1043         message = "Unsafe attempt to load URL " + url.elidedString() + " from frame with URL " + m_document->url().elidedString() + ". Domains, protocols and ports must match.\n";
   1044 
   1045     frame()->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message);
   1046 }
   1047 
   1048 void ResourceFetcher::setAutoLoadImages(bool enable)
   1049 {
   1050     if (enable == m_autoLoadImages)
   1051         return;
   1052 
   1053     m_autoLoadImages = enable;
   1054 
   1055     if (!m_autoLoadImages)
   1056         return;
   1057 
   1058     reloadImagesIfNotDeferred();
   1059 }
   1060 
   1061 void ResourceFetcher::setImagesEnabled(bool enable)
   1062 {
   1063     if (enable == m_imagesEnabled)
   1064         return;
   1065 
   1066     m_imagesEnabled = enable;
   1067 
   1068     if (!m_imagesEnabled)
   1069         return;
   1070 
   1071     reloadImagesIfNotDeferred();
   1072 }
   1073 
   1074 bool ResourceFetcher::clientDefersImage(const KURL& url) const
   1075 {
   1076     return frame() && !frame()->loader().client()->allowImage(m_imagesEnabled, url);
   1077 }
   1078 
   1079 bool ResourceFetcher::shouldDeferImageLoad(const KURL& url) const
   1080 {
   1081     return clientDefersImage(url) || !m_autoLoadImages;
   1082 }
   1083 
   1084 void ResourceFetcher::reloadImagesIfNotDeferred()
   1085 {
   1086     DocumentResourceMap::iterator end = m_documentResources.end();
   1087     for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != end; ++it) {
   1088         Resource* resource = it->value.get();
   1089         if (resource->type() == Resource::Image && resource->stillNeedsLoad() && !clientDefersImage(resource->url()))
   1090             const_cast<Resource*>(resource)->load(this, defaultResourceOptions());
   1091     }
   1092 }
   1093 
   1094 void ResourceFetcher::redirectReceived(Resource* resource, const ResourceResponse& redirectResponse)
   1095 {
   1096     ResourceTimingInfoMap::iterator it = m_resourceTimingInfoMap.find(resource);
   1097     if (it != m_resourceTimingInfoMap.end())
   1098         it->value->addRedirect(redirectResponse);
   1099 }
   1100 
   1101 void ResourceFetcher::didLoadResource(Resource* resource)
   1102 {
   1103     RefPtr<DocumentLoader> protectDocumentLoader(m_documentLoader);
   1104     RefPtrWillBeRawPtr<Document> protectDocument(m_document.get());
   1105 
   1106     if (resource && resource->response().isHTTP() && ((!resource->errorOccurred() && !resource->wasCanceled()) || resource->response().httpStatusCode() == 304) && document()) {
   1107         ResourceTimingInfoMap::iterator it = m_resourceTimingInfoMap.find(resource);
   1108         if (it != m_resourceTimingInfoMap.end()) {
   1109             RefPtr<ResourceTimingInfo> info = it->value;
   1110             m_resourceTimingInfoMap.remove(it);
   1111             populateResourceTiming(info.get(), resource, false);
   1112             reportResourceTiming(info.get(), document(), resource->type() == Resource::MainResource);
   1113         }
   1114     }
   1115 
   1116     if (frame())
   1117         frame()->loader().loadDone();
   1118     scheduleDocumentResourcesGC();
   1119 }
   1120 
   1121 void ResourceFetcher::scheduleDocumentResourcesGC()
   1122 {
   1123     if (!m_garbageCollectDocumentResourcesTimer.isActive())
   1124         m_garbageCollectDocumentResourcesTimer.startOneShot(0, FROM_HERE);
   1125 }
   1126 
   1127 // Garbage collecting m_documentResources is a workaround for the
   1128 // ResourcePtrs on the RHS being strong references. Ideally this
   1129 // would be a weak map, however ResourcePtrs perform additional
   1130 // bookkeeping on Resources, so instead pseudo-GC them -- when the
   1131 // reference count reaches 1, m_documentResources is the only reference, so
   1132 // remove it from the map.
   1133 void ResourceFetcher::garbageCollectDocumentResourcesTimerFired(Timer<ResourceFetcher>* timer)
   1134 {
   1135     ASSERT_UNUSED(timer, timer == &m_garbageCollectDocumentResourcesTimer);
   1136     garbageCollectDocumentResources();
   1137 }
   1138 
   1139 void ResourceFetcher::garbageCollectDocumentResources()
   1140 {
   1141     typedef Vector<String, 10> StringVector;
   1142     StringVector resourcesToDelete;
   1143 
   1144     for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != m_documentResources.end(); ++it) {
   1145         if (it->value->hasOneHandle())
   1146             resourcesToDelete.append(it->key);
   1147     }
   1148 
   1149     m_documentResources.removeAll(resourcesToDelete);
   1150 }
   1151 
   1152 void ResourceFetcher::notifyLoadedFromMemoryCache(Resource* resource)
   1153 {
   1154     if (!frame() || !frame()->page() || resource->status() != Resource::Cached || m_validatedURLs.contains(resource->url()))
   1155         return;
   1156 
   1157     ResourceRequest request(resource->url());
   1158     unsigned long identifier = createUniqueIdentifier();
   1159     context().dispatchDidLoadResourceFromMemoryCache(request, resource->response());
   1160     // FIXME: If willSendRequest changes the request, we don't respect it.
   1161     willSendRequest(identifier, request, ResourceResponse(), resource->options().initiatorInfo);
   1162     InspectorInstrumentation::markResourceAsCached(frame()->page(), identifier);
   1163     context().sendRemainingDelegateMessages(m_documentLoader, identifier, resource->response(), resource->encodedSize());
   1164 }
   1165 
   1166 void ResourceFetcher::incrementRequestCount(const Resource* res)
   1167 {
   1168     if (res->ignoreForRequestCount())
   1169         return;
   1170 
   1171     ++m_requestCount;
   1172 }
   1173 
   1174 void ResourceFetcher::decrementRequestCount(const Resource* res)
   1175 {
   1176     if (res->ignoreForRequestCount())
   1177         return;
   1178 
   1179     --m_requestCount;
   1180     ASSERT(m_requestCount > -1);
   1181 }
   1182 
   1183 void ResourceFetcher::preload(Resource::Type type, FetchRequest& request, const String& charset)
   1184 {
   1185     requestPreload(type, request, charset);
   1186 }
   1187 
   1188 void ResourceFetcher::requestPreload(Resource::Type type, FetchRequest& request, const String& charset)
   1189 {
   1190     // Ensure main resources aren't preloaded, since the cache can't actually reuse the preload.
   1191     if (type == Resource::MainResource)
   1192         return;
   1193 
   1194     String encoding;
   1195     if (type == Resource::Script || type == Resource::CSSStyleSheet)
   1196         encoding = charset.isEmpty() ? m_document->charset().string() : charset;
   1197 
   1198     request.setCharset(encoding);
   1199     request.setForPreload(true);
   1200 
   1201     ResourcePtr<Resource> resource = requestResource(type, request);
   1202     if (!resource || (m_preloads && m_preloads->contains(resource.get())))
   1203         return;
   1204     TRACE_EVENT_ASYNC_STEP_INTO0("net", "Resource", resource.get(), "Preload");
   1205     resource->increasePreloadCount();
   1206 
   1207     if (!m_preloads)
   1208         m_preloads = adoptPtr(new ListHashSet<Resource*>);
   1209     m_preloads->add(resource.get());
   1210 
   1211 #if PRELOAD_DEBUG
   1212     printf("PRELOADING %s\n",  resource->url().string().latin1().data());
   1213 #endif
   1214 }
   1215 
   1216 bool ResourceFetcher::isPreloaded(const String& urlString) const
   1217 {
   1218     const KURL& url = m_document->completeURL(urlString);
   1219 
   1220     if (m_preloads) {
   1221         ListHashSet<Resource*>::iterator end = m_preloads->end();
   1222         for (ListHashSet<Resource*>::iterator it = m_preloads->begin(); it != end; ++it) {
   1223             Resource* resource = *it;
   1224             if (resource->url() == url)
   1225                 return true;
   1226         }
   1227     }
   1228 
   1229     return false;
   1230 }
   1231 
   1232 void ResourceFetcher::clearPreloads()
   1233 {
   1234 #if PRELOAD_DEBUG
   1235     printPreloadStats();
   1236 #endif
   1237     if (!m_preloads)
   1238         return;
   1239 
   1240     ListHashSet<Resource*>::iterator end = m_preloads->end();
   1241     for (ListHashSet<Resource*>::iterator it = m_preloads->begin(); it != end; ++it) {
   1242         Resource* res = *it;
   1243         res->decreasePreloadCount();
   1244         bool deleted = res->deleteIfPossible();
   1245         if (!deleted && res->preloadResult() == Resource::PreloadNotReferenced)
   1246             memoryCache()->remove(res);
   1247     }
   1248     m_preloads.clear();
   1249 }
   1250 
   1251 void ResourceFetcher::didFinishLoading(const Resource* resource, double finishTime, int64_t encodedDataLength)
   1252 {
   1253     TRACE_EVENT_ASYNC_END0("net", "Resource", resource);
   1254     context().dispatchDidFinishLoading(m_documentLoader, resource->identifier(), finishTime, encodedDataLength);
   1255 }
   1256 
   1257 void ResourceFetcher::didChangeLoadingPriority(const Resource* resource, ResourceLoadPriority loadPriority, int intraPriorityValue)
   1258 {
   1259     TRACE_EVENT_ASYNC_STEP_INTO1("net", "Resource", resource, "ChangePriority", "priority", loadPriority);
   1260     context().dispatchDidChangeResourcePriority(resource->identifier(), loadPriority, intraPriorityValue);
   1261 }
   1262 
   1263 void ResourceFetcher::didFailLoading(const Resource* resource, const ResourceError& error)
   1264 {
   1265     TRACE_EVENT_ASYNC_END0("net", "Resource", resource);
   1266     context().dispatchDidFail(m_documentLoader, resource->identifier(), error);
   1267 }
   1268 
   1269 void ResourceFetcher::willSendRequest(unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse, const FetchInitiatorInfo& initiatorInfo)
   1270 {
   1271     context().dispatchWillSendRequest(m_documentLoader, identifier, request, redirectResponse, initiatorInfo);
   1272 }
   1273 
   1274 void ResourceFetcher::didReceiveResponse(const Resource* resource, const ResourceResponse& response)
   1275 {
   1276     context().dispatchDidReceiveResponse(m_documentLoader, resource->identifier(), response, resource->loader());
   1277 }
   1278 
   1279 void ResourceFetcher::didReceiveData(const Resource* resource, const char* data, int dataLength, int encodedDataLength)
   1280 {
   1281     context().dispatchDidReceiveData(m_documentLoader, resource->identifier(), data, dataLength, encodedDataLength);
   1282 }
   1283 
   1284 void ResourceFetcher::didDownloadData(const Resource* resource, int dataLength, int encodedDataLength)
   1285 {
   1286     context().dispatchDidDownloadData(m_documentLoader, resource->identifier(), dataLength, encodedDataLength);
   1287 }
   1288 
   1289 void ResourceFetcher::subresourceLoaderFinishedLoadingOnePart(ResourceLoader* loader)
   1290 {
   1291     if (!m_multipartLoaders)
   1292         m_multipartLoaders = adoptPtr(new ResourceLoaderSet());
   1293     m_multipartLoaders->add(loader);
   1294     m_loaders->remove(loader);
   1295     if (LocalFrame* frame = this->frame())
   1296         return frame->loader().checkLoadComplete();
   1297 }
   1298 
   1299 void ResourceFetcher::didInitializeResourceLoader(ResourceLoader* loader)
   1300 {
   1301     if (!m_document)
   1302         return;
   1303     if (!m_loaders)
   1304         m_loaders = adoptPtr(new ResourceLoaderSet());
   1305     ASSERT(!m_loaders->contains(loader));
   1306     m_loaders->add(loader);
   1307 }
   1308 
   1309 void ResourceFetcher::willTerminateResourceLoader(ResourceLoader* loader)
   1310 {
   1311     if (m_loaders && m_loaders->contains(loader))
   1312         m_loaders->remove(loader);
   1313     if (m_multipartLoaders && m_multipartLoaders->contains(loader))
   1314         m_multipartLoaders->remove(loader);
   1315     if (LocalFrame* frame = this->frame())
   1316         frame->loader().checkLoadComplete();
   1317 }
   1318 
   1319 void ResourceFetcher::willStartLoadingResource(Resource* resource, ResourceRequest& request)
   1320 {
   1321     if (m_documentLoader)
   1322         m_documentLoader->applicationCacheHost()->willStartLoadingResource(request);
   1323 
   1324     storeResourceTimingInitiatorInformation(resource);
   1325     TRACE_EVENT_ASYNC_BEGIN2("net", "Resource", resource, "url", resource->url().string().ascii(), "priority", resource->resourceRequest().priority());
   1326 }
   1327 
   1328 void ResourceFetcher::stopFetching()
   1329 {
   1330     if (m_multipartLoaders)
   1331         m_multipartLoaders->cancelAll();
   1332     if (m_loaders)
   1333         m_loaders->cancelAll();
   1334 }
   1335 
   1336 bool ResourceFetcher::isFetching() const
   1337 {
   1338     return m_loaders && !m_loaders->isEmpty();
   1339 }
   1340 
   1341 void ResourceFetcher::setDefersLoading(bool defers)
   1342 {
   1343     if (m_loaders)
   1344         m_loaders->setAllDefersLoading(defers);
   1345 }
   1346 
   1347 bool ResourceFetcher::defersLoading() const
   1348 {
   1349     if (LocalFrame* frame = this->frame())
   1350         return frame->page()->defersLoading();
   1351     return false;
   1352 }
   1353 
   1354 bool ResourceFetcher::isLoadedBy(ResourceLoaderHost* possibleOwner) const
   1355 {
   1356     return this == possibleOwner;
   1357 }
   1358 
   1359 bool ResourceFetcher::canAccessRedirect(Resource* resource, ResourceRequest& request, const ResourceResponse& redirectResponse, ResourceLoaderOptions& options)
   1360 {
   1361     if (!canRequest(resource->type(), request.url(), options, false, FetchRequest::UseDefaultOriginRestrictionForType))
   1362         return false;
   1363     if (options.corsEnabled == IsCORSEnabled) {
   1364         SecurityOrigin* sourceOrigin = options.securityOrigin.get();
   1365         if (!sourceOrigin && document())
   1366             sourceOrigin = document()->securityOrigin();
   1367 
   1368         String errorMessage;
   1369         if (!CrossOriginAccessControl::handleRedirect(resource, sourceOrigin, request, redirectResponse, options, errorMessage)) {
   1370             if (frame() && frame()->document())
   1371                 frame()->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, errorMessage);
   1372             return false;
   1373         }
   1374     }
   1375     if (resource->type() == Resource::Image && shouldDeferImageLoad(request.url()))
   1376         return false;
   1377     return true;
   1378 }
   1379 
   1380 #if !ENABLE(OILPAN)
   1381 void ResourceFetcher::refResourceLoaderHost()
   1382 {
   1383     ref();
   1384 }
   1385 
   1386 void ResourceFetcher::derefResourceLoaderHost()
   1387 {
   1388     deref();
   1389 }
   1390 #endif
   1391 
   1392 #if PRELOAD_DEBUG
   1393 void ResourceFetcher::printPreloadStats()
   1394 {
   1395     if (!m_preloads)
   1396         return;
   1397 
   1398     unsigned scripts = 0;
   1399     unsigned scriptMisses = 0;
   1400     unsigned stylesheets = 0;
   1401     unsigned stylesheetMisses = 0;
   1402     unsigned images = 0;
   1403     unsigned imageMisses = 0;
   1404     ListHashSet<Resource*>::iterator end = m_preloads->end();
   1405     for (ListHashSet<Resource*>::iterator it = m_preloads->begin(); it != end; ++it) {
   1406         Resource* res = *it;
   1407         if (res->preloadResult() == Resource::PreloadNotReferenced)
   1408             printf("!! UNREFERENCED PRELOAD %s\n", res->url().string().latin1().data());
   1409         else if (res->preloadResult() == Resource::PreloadReferencedWhileComplete)
   1410             printf("HIT COMPLETE PRELOAD %s\n", res->url().string().latin1().data());
   1411         else if (res->preloadResult() == Resource::PreloadReferencedWhileLoading)
   1412             printf("HIT LOADING PRELOAD %s\n", res->url().string().latin1().data());
   1413 
   1414         if (res->type() == Resource::Script) {
   1415             scripts++;
   1416             if (res->preloadResult() < Resource::PreloadReferencedWhileLoading)
   1417                 scriptMisses++;
   1418         } else if (res->type() == Resource::CSSStyleSheet) {
   1419             stylesheets++;
   1420             if (res->preloadResult() < Resource::PreloadReferencedWhileLoading)
   1421                 stylesheetMisses++;
   1422         } else {
   1423             images++;
   1424             if (res->preloadResult() < Resource::PreloadReferencedWhileLoading)
   1425                 imageMisses++;
   1426         }
   1427 
   1428         if (res->errorOccurred())
   1429             memoryCache()->remove(res);
   1430 
   1431         res->decreasePreloadCount();
   1432     }
   1433     m_preloads.clear();
   1434 
   1435     if (scripts)
   1436         printf("SCRIPTS: %d (%d hits, hit rate %d%%)\n", scripts, scripts - scriptMisses, (scripts - scriptMisses) * 100 / scripts);
   1437     if (stylesheets)
   1438         printf("STYLESHEETS: %d (%d hits, hit rate %d%%)\n", stylesheets, stylesheets - stylesheetMisses, (stylesheets - stylesheetMisses) * 100 / stylesheets);
   1439     if (images)
   1440         printf("IMAGES:  %d (%d hits, hit rate %d%%)\n", images, images - imageMisses, (images - imageMisses) * 100 / images);
   1441 }
   1442 #endif
   1443 
   1444 const ResourceLoaderOptions& ResourceFetcher::defaultResourceOptions()
   1445 {
   1446     DEFINE_STATIC_LOCAL(ResourceLoaderOptions, options, (SniffContent, BufferData, AllowStoredCredentials, ClientRequestedCredentials, CheckContentSecurityPolicy, DocumentContext));
   1447     return options;
   1448 }
   1449 
   1450 ResourceFetcher::DeadResourceStatsRecorder::DeadResourceStatsRecorder()
   1451     : m_useCount(0)
   1452     , m_revalidateCount(0)
   1453     , m_loadCount(0)
   1454 {
   1455 }
   1456 
   1457 ResourceFetcher::DeadResourceStatsRecorder::~DeadResourceStatsRecorder()
   1458 {
   1459     blink::Platform::current()->histogramCustomCounts(
   1460         "WebCore.ResourceFetcher.HitCount", m_useCount, 0, 1000, 50);
   1461     blink::Platform::current()->histogramCustomCounts(
   1462         "WebCore.ResourceFetcher.RevalidateCount", m_revalidateCount, 0, 1000, 50);
   1463     blink::Platform::current()->histogramCustomCounts(
   1464         "WebCore.ResourceFetcher.LoadCount", m_loadCount, 0, 1000, 50);
   1465 }
   1466 
   1467 void ResourceFetcher::DeadResourceStatsRecorder::update(RevalidationPolicy policy)
   1468 {
   1469     switch (policy) {
   1470     case Reload:
   1471     case Load:
   1472         ++m_loadCount;
   1473         return;
   1474     case Revalidate:
   1475         ++m_revalidateCount;
   1476         return;
   1477     case Use:
   1478         ++m_useCount;
   1479         return;
   1480     }
   1481 }
   1482 
   1483 void ResourceFetcher::trace(Visitor* visitor)
   1484 {
   1485     visitor->trace(m_document);
   1486     ResourceLoaderHost::trace(visitor);
   1487 }
   1488 
   1489 }
   1490