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