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