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/
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.
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.
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.
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.
28 #include "core/fetch/ResourceFetcher.h"
30 #include "RuntimeEnabledFeatures.h"
31 #include "bindings/v8/ScriptController.h"
32 #include "core/dom/Document.h"
33 #include "core/fetch/CSSStyleSheetResource.h"
34 #include "core/fetch/CrossOriginAccessControl.h"
35 #include "core/fetch/DocumentResource.h"
36 #include "core/fetch/FetchContext.h"
37 #include "core/fetch/FontResource.h"
38 #include "core/fetch/ImageResource.h"
39 #include "core/fetch/MemoryCache.h"
40 #include "core/fetch/RawResource.h"
41 #include "core/fetch/ResourceLoader.h"
42 #include "core/fetch/ResourceLoaderSet.h"
43 #include "core/fetch/ScriptResource.h"
44 #include "core/fetch/ShaderResource.h"
45 #include "core/fetch/XSLStyleSheetResource.h"
46 #include "core/html/HTMLElement.h"
47 #include "core/html/HTMLFrameOwnerElement.h"
48 #include "core/html/imports/HTMLImport.h"
49 #include "core/inspector/InspectorInstrumentation.h"
50 #include "core/loader/DocumentLoader.h"
51 #include "core/loader/FrameLoader.h"
52 #include "core/loader/FrameLoaderClient.h"
53 #include "core/loader/PingLoader.h"
54 #include "core/loader/SubstituteData.h"
55 #include "core/loader/UniqueIdentifier.h"
56 #include "core/loader/appcache/ApplicationCacheHost.h"
57 #include "core/frame/DOMWindow.h"
58 #include "core/frame/LocalFrame.h"
59 #include "core/frame/csp/ContentSecurityPolicy.h"
60 #include "core/timing/Performance.h"
61 #include "core/timing/ResourceTimingInfo.h"
62 #include "core/frame/Settings.h"
63 #include "platform/Logging.h"
64 #include "platform/TraceEvent.h"
65 #include "platform/weborigin/SecurityOrigin.h"
66 #include "platform/weborigin/SecurityPolicy.h"
67 #include "public/platform/Platform.h"
68 #include "public/platform/WebURL.h"
69 #include "wtf/text/CString.h"
70 #include "wtf/text/WTFString.h"
72 #define PRELOAD_DEBUG 0
76 static Resource* createResource(Resource::Type type, const ResourceRequest& request, const String& charset)
80 return new ImageResource(request);
81 case Resource::CSSStyleSheet:
82 return new CSSStyleSheetResource(request, charset);
83 case Resource::Script:
84 return new ScriptResource(request, charset);
85 case Resource::SVGDocument:
86 return new DocumentResource(request, Resource::SVGDocument);
88 return new FontResource(request);
89 case Resource::MainResource:
91 case Resource::TextTrack:
92 return new RawResource(request, type);
93 case Resource::XSLStyleSheet:
94 return new XSLStyleSheetResource(request);
95 case Resource::LinkPrefetch:
96 return new Resource(request, Resource::LinkPrefetch);
97 case Resource::LinkSubresource:
98 return new Resource(request, Resource::LinkSubresource);
99 case Resource::Shader:
100 return new ShaderResource(request);
101 case Resource::ImportResource:
102 return new RawResource(request, type);
105 ASSERT_NOT_REACHED();
109 static ResourceLoadPriority loadPriority(Resource::Type type, const FetchRequest& request)
111 if (request.priority() != ResourceLoadPriorityUnresolved)
112 return request.priority();
115 case Resource::MainResource:
116 return ResourceLoadPriorityVeryHigh;
117 case Resource::CSSStyleSheet:
118 return ResourceLoadPriorityHigh;
120 return request.options().synchronousPolicy == RequestSynchronously ? ResourceLoadPriorityVeryHigh : ResourceLoadPriorityMedium;
121 case Resource::Script:
123 case Resource::ImportResource:
124 return ResourceLoadPriorityMedium;
125 case Resource::Image:
126 // We'll default images to VeryLow, and promote whatever is visible. This improves
127 // speed-index by ~5% on average, ~14% at the 99th percentile.
128 return ResourceLoadPriorityVeryLow;
129 case Resource::XSLStyleSheet:
130 ASSERT(RuntimeEnabledFeatures::xsltEnabled());
131 return ResourceLoadPriorityHigh;
132 case Resource::SVGDocument:
133 return ResourceLoadPriorityLow;
134 case Resource::LinkPrefetch:
135 return ResourceLoadPriorityVeryLow;
136 case Resource::LinkSubresource:
137 return ResourceLoadPriorityLow;
138 case Resource::TextTrack:
139 return ResourceLoadPriorityLow;
140 case Resource::Shader:
141 return ResourceLoadPriorityMedium;
143 ASSERT_NOT_REACHED();
144 return ResourceLoadPriorityUnresolved;
147 static Resource* resourceFromDataURIRequest(const ResourceRequest& request, const ResourceLoaderOptions& resourceOptions)
149 const KURL& url = request.url();
150 ASSERT(url.protocolIsData());
152 blink::WebString mimetype;
153 blink::WebString charset;
154 RefPtr<SharedBuffer> data = PassRefPtr<SharedBuffer>(blink::Platform::current()->parseDataURL(url, mimetype, charset));
157 ResourceResponse response(url, mimetype, data->size(), charset, String());
159 Resource* resource = createResource(Resource::Image, request, charset);
160 resource->setOptions(resourceOptions);
161 resource->responseReceived(response);
163 resource->setResourceBuffer(data);
168 static void populateResourceTiming(ResourceTimingInfo* info, Resource* resource, bool clearLoadTimings)
170 info->setInitialRequest(resource->resourceRequest());
171 info->setFinalResponse(resource->response());
172 if (clearLoadTimings) {
173 info->clearLoadTimings();
174 info->setLoadFinishTime(info->initialTime());
176 info->setLoadFinishTime(resource->loadFinishTime());
180 static void reportResourceTiming(ResourceTimingInfo* info, Document* initiatorDocument, bool isMainResource)
182 if (initiatorDocument && isMainResource)
183 initiatorDocument = initiatorDocument->parentDocument();
184 if (!initiatorDocument || !initiatorDocument->loader())
186 if (DOMWindow* initiatorWindow = initiatorDocument->domWindow())
187 initiatorWindow->performance().addResourceTiming(*info, initiatorDocument);
190 static ResourceRequest::TargetType requestTargetType(const ResourceFetcher* fetcher, const ResourceRequest& request, Resource::Type type)
193 case Resource::MainResource:
194 if (fetcher->frame()->tree().parent())
195 return ResourceRequest::TargetIsSubframe;
196 return ResourceRequest::TargetIsMainFrame;
197 case Resource::XSLStyleSheet:
198 ASSERT(RuntimeEnabledFeatures::xsltEnabled());
199 case Resource::CSSStyleSheet:
200 return ResourceRequest::TargetIsStyleSheet;
201 case Resource::Script:
202 return ResourceRequest::TargetIsScript;
204 return ResourceRequest::TargetIsFont;
205 case Resource::Image:
206 return ResourceRequest::TargetIsImage;
207 case Resource::Shader:
209 case Resource::ImportResource:
210 return ResourceRequest::TargetIsSubresource;
211 case Resource::LinkPrefetch:
212 return ResourceRequest::TargetIsPrefetch;
213 case Resource::LinkSubresource:
214 return ResourceRequest::TargetIsSubresource;
215 case Resource::TextTrack:
216 return ResourceRequest::TargetIsTextTrack;
217 case Resource::SVGDocument:
218 return ResourceRequest::TargetIsImage;
220 ASSERT_NOT_REACHED();
221 return ResourceRequest::TargetIsSubresource;
224 ResourceFetcher::ResourceFetcher(DocumentLoader* documentLoader)
226 , m_documentLoader(documentLoader)
228 , m_garbageCollectDocumentResourcesTimer(this, &ResourceFetcher::garbageCollectDocumentResourcesTimerFired)
229 , m_resourceTimingReportTimer(this, &ResourceFetcher::resourceTimingReportTimerFired)
230 , m_autoLoadImages(true)
231 , m_imagesEnabled(true)
232 , m_allowStaleResources(false)
236 ResourceFetcher::~ResourceFetcher()
238 m_documentLoader = 0;
243 // Make sure no requests still point to this ResourceFetcher
244 ASSERT(!m_requestCount);
247 Resource* ResourceFetcher::cachedResource(const KURL& resourceURL) const
249 KURL url = MemoryCache::removeFragmentIdentifierIfNeeded(resourceURL);
250 return m_documentResources.get(url).get();
253 LocalFrame* ResourceFetcher::frame() const
255 if (m_documentLoader)
256 return m_documentLoader->frame();
257 if (m_document && m_document->import())
258 return m_document->import()->frame();
262 FetchContext& ResourceFetcher::context() const
264 if (LocalFrame* frame = this->frame())
265 return frame->fetchContext();
266 return FetchContext::nullInstance();
269 ResourcePtr<Resource> ResourceFetcher::fetchSynchronously(FetchRequest& request)
272 request.mutableResourceRequest().setTimeoutInterval(10);
273 ResourceLoaderOptions options(request.options());
274 options.synchronousPolicy = RequestSynchronously;
275 request.setOptions(options);
276 return requestResource(Resource::Raw, request);
279 ResourcePtr<ImageResource> ResourceFetcher::fetchImage(FetchRequest& request)
281 if (LocalFrame* f = frame()) {
282 if (f->document()->pageDismissalEventBeingDispatched() != Document::NoDismissal) {
283 KURL requestURL = request.resourceRequest().url();
284 if (requestURL.isValid() && canRequest(Resource::Image, requestURL, request.options(), request.forPreload(), request.originRestriction()))
285 PingLoader::loadImage(f, requestURL);
290 if (request.resourceRequest().url().protocolIsData())
291 preCacheDataURIImage(request);
293 request.setDefer(clientDefersImage(request.resourceRequest().url()) ? FetchRequest::DeferredByClient : FetchRequest::NoDefer);
294 return toImageResource(requestResource(Resource::Image, request));
297 void ResourceFetcher::preCacheDataURIImage(const FetchRequest& request)
299 const KURL& url = request.resourceRequest().url();
300 ASSERT(url.protocolIsData());
302 if (memoryCache()->resourceForURL(url))
305 if (Resource* resource = resourceFromDataURIRequest(request.resourceRequest(), request.options())) {
306 memoryCache()->add(resource);
307 scheduleDocumentResourcesGC();
311 ResourcePtr<FontResource> ResourceFetcher::fetchFont(FetchRequest& request)
313 return toFontResource(requestResource(Resource::Font, request));
316 ResourcePtr<ShaderResource> ResourceFetcher::fetchShader(FetchRequest& request)
318 return toShaderResource(requestResource(Resource::Shader, request));
321 ResourcePtr<RawResource> ResourceFetcher::fetchImport(FetchRequest& request)
323 return toRawResource(requestResource(Resource::ImportResource, request));
326 ResourcePtr<CSSStyleSheetResource> ResourceFetcher::fetchCSSStyleSheet(FetchRequest& request)
328 return toCSSStyleSheetResource(requestResource(Resource::CSSStyleSheet, request));
331 ResourcePtr<CSSStyleSheetResource> ResourceFetcher::fetchUserCSSStyleSheet(FetchRequest& request)
333 KURL url = MemoryCache::removeFragmentIdentifierIfNeeded(request.resourceRequest().url());
335 if (Resource* existing = memoryCache()->resourceForURL(url)) {
336 if (existing->type() == Resource::CSSStyleSheet)
337 return toCSSStyleSheetResource(existing);
338 memoryCache()->remove(existing);
341 request.setOptions(ResourceLoaderOptions(SniffContent, BufferData, AllowStoredCredentials, ClientRequestedCredentials, CheckContentSecurityPolicy, DocumentContext));
342 return toCSSStyleSheetResource(requestResource(Resource::CSSStyleSheet, request));
345 ResourcePtr<ScriptResource> ResourceFetcher::fetchScript(FetchRequest& request)
347 return toScriptResource(requestResource(Resource::Script, request));
350 ResourcePtr<XSLStyleSheetResource> ResourceFetcher::fetchXSLStyleSheet(FetchRequest& request)
352 ASSERT(RuntimeEnabledFeatures::xsltEnabled());
353 return toXSLStyleSheetResource(requestResource(Resource::XSLStyleSheet, request));
356 ResourcePtr<DocumentResource> ResourceFetcher::fetchSVGDocument(FetchRequest& request)
358 return toDocumentResource(requestResource(Resource::SVGDocument, request));
361 ResourcePtr<Resource> ResourceFetcher::fetchLinkResource(Resource::Type type, FetchRequest& request)
364 ASSERT(type == Resource::LinkPrefetch || type == Resource::LinkSubresource);
365 return requestResource(type, request);
368 ResourcePtr<RawResource> ResourceFetcher::fetchRawResource(FetchRequest& request)
370 return toRawResource(requestResource(Resource::Raw, request));
373 ResourcePtr<RawResource> ResourceFetcher::fetchMainResource(FetchRequest& request, const SubstituteData& substituteData)
375 if (substituteData.isValid())
376 preCacheSubstituteDataForMainResource(request, substituteData);
377 return toRawResource(requestResource(Resource::MainResource, request));
380 void ResourceFetcher::preCacheSubstituteDataForMainResource(const FetchRequest& request, const SubstituteData& substituteData)
382 const KURL& url = request.url();
383 if (Resource* oldResource = memoryCache()->resourceForURL(url))
384 memoryCache()->remove(oldResource);
386 ResourceResponse response(url, substituteData.mimeType(), substituteData.content()->size(), substituteData.textEncoding(), emptyString());
387 ResourcePtr<Resource> resource = createResource(Resource::MainResource, request.resourceRequest(), substituteData.textEncoding());
388 resource->setNeedsSynchronousCacheHit(substituteData.forceSynchronousLoad());
389 resource->setOptions(request.options());
390 resource->setDataBufferingPolicy(BufferData);
391 resource->responseReceived(response);
392 if (substituteData.content()->size())
393 resource->setResourceBuffer(substituteData.content());
395 memoryCache()->add(resource.get());
398 bool ResourceFetcher::checkInsecureContent(Resource::Type type, const KURL& url, MixedContentBlockingTreatment treatment) const
400 if (treatment == TreatAsDefaultForType) {
402 case Resource::XSLStyleSheet:
403 ASSERT(RuntimeEnabledFeatures::xsltEnabled());
404 case Resource::Script:
405 case Resource::SVGDocument:
406 case Resource::CSSStyleSheet:
407 case Resource::ImportResource:
408 // These resource can inject script into the current document (Script,
409 // XSL) or exfiltrate the content of the current document (CSS).
410 treatment = TreatAsActiveContent;
413 case Resource::TextTrack:
414 case Resource::Shader:
416 case Resource::Image:
418 // These resources can corrupt only the frame's pixels.
419 treatment = TreatAsPassiveContent;
422 case Resource::MainResource:
423 case Resource::LinkPrefetch:
424 case Resource::LinkSubresource:
425 // These cannot affect the current document.
426 treatment = TreatAsAlwaysAllowedContent;
430 if (treatment == TreatAsActiveContent) {
431 if (LocalFrame* f = frame()) {
432 if (!f->loader().mixedContentChecker()->canRunInsecureContent(m_document->securityOrigin(), url))
434 LocalFrame* top = f->tree().top();
435 if (top != f && !top->loader().mixedContentChecker()->canRunInsecureContent(top->document()->securityOrigin(), url))
438 } else if (treatment == TreatAsPassiveContent) {
439 if (LocalFrame* f = frame()) {
440 LocalFrame* top = f->tree().top();
441 if (!top->loader().mixedContentChecker()->canDisplayInsecureContent(top->document()->securityOrigin(), url))
445 ASSERT(treatment == TreatAsAlwaysAllowedContent);
450 bool ResourceFetcher::canRequest(Resource::Type type, const KURL& url, const ResourceLoaderOptions& options, bool forPreload, FetchRequest::OriginRestriction originRestriction) const
452 SecurityOrigin* securityOrigin = options.securityOrigin.get();
453 if (!securityOrigin && document())
454 securityOrigin = document()->securityOrigin();
456 if (securityOrigin && !securityOrigin->canDisplay(url)) {
458 context().reportLocalLoadFailed(url);
459 WTF_LOG(ResourceLoading, "ResourceFetcher::requestResource URL was not allowed by SecurityOrigin::canDisplay");
463 // FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved.
464 bool shouldBypassMainWorldContentSecurityPolicy = (frame() && frame()->script().shouldBypassMainWorldContentSecurityPolicy()) || (options.contentSecurityPolicyOption == DoNotCheckContentSecurityPolicy);
466 // Some types of resources can be loaded only from the same origin. Other
467 // types of resources, like Images, Scripts, and CSS, can be loaded from
470 case Resource::MainResource:
471 case Resource::Image:
472 case Resource::CSSStyleSheet:
473 case Resource::Script:
476 case Resource::LinkPrefetch:
477 case Resource::LinkSubresource:
478 case Resource::TextTrack:
479 case Resource::Shader:
480 case Resource::ImportResource:
481 // By default these types of resources can be loaded from any origin.
482 // FIXME: Are we sure about Resource::Font?
483 if (originRestriction == FetchRequest::RestrictToSameOrigin && !securityOrigin->canRequest(url)) {
484 printAccessDeniedMessage(url);
488 case Resource::XSLStyleSheet:
489 ASSERT(RuntimeEnabledFeatures::xsltEnabled());
490 case Resource::SVGDocument:
491 if (!securityOrigin->canRequest(url)) {
492 printAccessDeniedMessage(url);
499 case Resource::XSLStyleSheet:
500 ASSERT(RuntimeEnabledFeatures::xsltEnabled());
501 if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowScriptFromSource(url))
504 case Resource::Script:
505 case Resource::ImportResource:
506 if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowScriptFromSource(url))
510 Settings* settings = frame()->settings();
511 if (!frame()->loader().client()->allowScriptFromSource(!settings || settings->scriptEnabled(), url)) {
512 frame()->loader().client()->didNotAllowScript();
517 case Resource::Shader:
518 // Since shaders are referenced from CSS Styles use the same rules here.
519 case Resource::CSSStyleSheet:
520 if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowStyleFromSource(url))
523 case Resource::SVGDocument:
524 case Resource::Image:
525 if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowImageFromSource(url))
528 case Resource::Font: {
529 if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowFontFromSource(url))
533 case Resource::MainResource:
535 case Resource::LinkPrefetch:
536 case Resource::LinkSubresource:
538 case Resource::TextTrack:
539 if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowMediaFromSource(url))
544 // Last of all, check for insecure content. We do this last so that when
545 // folks block insecure content with a CSP policy, they don't get a warning.
546 // They'll still get a warning in the console about CSP blocking the load.
548 // FIXME: Should we consider forPreload here?
549 if (!checkInsecureContent(type, url, options.mixedContentBlockingTreatment))
555 bool ResourceFetcher::canAccessResource(Resource* resource, SecurityOrigin* sourceOrigin, const KURL& url) const
557 // Redirects can change the response URL different from one of request.
558 if (!canRequest(resource->type(), url, resource->options(), false, FetchRequest::UseDefaultOriginRestrictionForType))
561 if (!sourceOrigin && document())
562 sourceOrigin = document()->securityOrigin();
564 if (sourceOrigin->canRequest(url))
567 String errorDescription;
568 if (!resource->passesAccessControlCheck(sourceOrigin, errorDescription)) {
569 if (frame() && frame()->document()) {
570 String resourceType = Resource::resourceTypeToString(resource->type(), resource->options().initiatorInfo);
571 frame()->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, resourceType + " from origin '" + SecurityOrigin::create(url)->toString() + "' has been blocked from loading by Cross-Origin Resource Sharing policy: " + errorDescription);
578 bool ResourceFetcher::shouldLoadNewResource(Resource::Type type) const
582 if (!m_documentLoader)
584 if (type == Resource::MainResource)
585 return m_documentLoader == frame()->loader().provisionalDocumentLoader();
586 return m_documentLoader == frame()->loader().documentLoader();
589 bool ResourceFetcher::resourceNeedsLoad(Resource* resource, const FetchRequest& request, RevalidationPolicy policy)
591 if (FetchRequest::DeferredByClient == request.defer())
595 if (resource->stillNeedsLoad())
597 return request.options().synchronousPolicy == RequestSynchronously && resource->isLoading();
600 ResourcePtr<Resource> ResourceFetcher::requestResource(Resource::Type type, FetchRequest& request)
602 ASSERT(request.options().synchronousPolicy == RequestAsynchronously || type == Resource::Raw);
604 KURL url = request.resourceRequest().url();
606 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));
608 // If only the fragment identifiers differ, it is the same resource.
609 url = MemoryCache::removeFragmentIdentifierIfNeeded(url);
614 if (!canRequest(type, url, request.options(), request.forPreload(), request.originRestriction()))
617 if (LocalFrame* f = frame())
618 f->loader().client()->dispatchWillRequestResource(&request);
620 // See if we can use an existing resource from the cache.
621 ResourcePtr<Resource> resource = memoryCache()->resourceForURL(url);
623 const RevalidationPolicy policy = determineRevalidationPolicy(type, request.mutableResourceRequest(), request.forPreload(), resource.get(), request.defer(), request.options());
626 memoryCache()->remove(resource.get());
629 resource = loadResource(type, request, request.charset());
632 resource = revalidateResource(request, resource.get());
635 memoryCache()->updateForAccess(resource.get());
636 notifyLoadedFromMemoryCache(resource.get());
643 if (!resource->hasClients())
644 m_deadStatsRecorder.update(policy);
647 resource->setIdentifier(createUniqueIdentifier());
649 if (!request.forPreload() || policy != Use) {
650 ResourceLoadPriority priority = loadPriority(type, request);
651 if (priority != resource->resourceRequest().priority()) {
652 resource->resourceRequest().setPriority(priority);
653 resource->didChangePriority(priority, 0);
657 if (resourceNeedsLoad(resource.get(), request, policy)) {
658 if (!shouldLoadNewResource(type)) {
659 if (memoryCache()->contains(resource.get()))
660 memoryCache()->remove(resource.get());
664 if (!m_documentLoader || !m_documentLoader->scheduleArchiveLoad(resource.get(), request.resourceRequest()))
665 resource->load(this, request.options());
667 // For asynchronous loads that immediately fail, it's sufficient to return a
668 // null Resource, as it indicates that something prevented the load from starting.
669 // If there's a network error, that failure will happen asynchronously. However, if
670 // a sync load receives a network error, it will have already happened by this point.
671 // In that case, the requester should have access to the relevant ResourceError, so
672 // we need to return a non-null Resource.
673 if (resource->errorOccurred()) {
674 if (memoryCache()->contains(resource.get()))
675 memoryCache()->remove(resource.get());
676 return request.options().synchronousPolicy == RequestSynchronously ? resource : 0;
680 // FIXME: Temporarily leave main resource caching disabled for chromium,
681 // see https://bugs.webkit.org/show_bug.cgi?id=107962. Before caching main
682 // resources, we should be sure to understand the implications for memory
685 // Ensure main resources aren't preloaded, and other main resource loads
686 // are removed from cache to prevent reuse.
687 if (type == Resource::MainResource) {
688 ASSERT(policy != Use || m_documentLoader->substituteData().isValid());
689 ASSERT(policy != Revalidate);
690 memoryCache()->remove(resource.get());
691 if (request.forPreload())
695 if (!request.resourceRequest().url().protocolIsData() && (!m_documentLoader || !m_documentLoader->substituteData().isValid())) {
696 if (policy == Use && !m_validatedURLs.contains(request.resourceRequest().url())) {
697 // Resources loaded from memory cache should be reported the first time they're used.
698 RefPtr<ResourceTimingInfo> info = ResourceTimingInfo::create(request.options().initiatorInfo.name, monotonicallyIncreasingTime());
699 populateResourceTiming(info.get(), resource.get(), true);
700 m_scheduledResourceTimingReports.add(info, resource->type() == Resource::MainResource);
701 if (!m_resourceTimingReportTimer.isActive())
702 m_resourceTimingReportTimer.startOneShot(0, FROM_HERE);
705 m_validatedURLs.add(request.resourceRequest().url());
708 ASSERT(resource->url() == url.string());
709 m_documentResources.set(resource->url(), resource);
713 void ResourceFetcher::resourceTimingReportTimerFired(Timer<ResourceFetcher>* timer)
715 ASSERT_UNUSED(timer, timer == &m_resourceTimingReportTimer);
716 HashMap<RefPtr<ResourceTimingInfo>, bool> timingReports;
717 timingReports.swap(m_scheduledResourceTimingReports);
718 HashMap<RefPtr<ResourceTimingInfo>, bool>::iterator end = timingReports.end();
719 for (HashMap<RefPtr<ResourceTimingInfo>, bool>::iterator it = timingReports.begin(); it != end; ++it) {
720 RefPtr<ResourceTimingInfo> info = it->key;
721 bool isMainResource = it->value;
722 reportResourceTiming(info.get(), document(), isMainResource);
726 void ResourceFetcher::determineTargetType(ResourceRequest& request, Resource::Type type)
728 ResourceRequest::TargetType targetType = requestTargetType(this, request, type);
729 request.setTargetType(targetType);
732 ResourceRequestCachePolicy ResourceFetcher::resourceRequestCachePolicy(const ResourceRequest& request, Resource::Type type)
734 if (type == Resource::MainResource) {
735 FrameLoadType frameLoadType = frame()->loader().loadType();
736 bool isReload = frameLoadType == FrameLoadTypeReload || frameLoadType == FrameLoadTypeReloadFromOrigin;
737 if (request.httpMethod() == "POST" && frameLoadType == FrameLoadTypeBackForward)
738 return ReturnCacheDataDontLoad;
739 if (!m_documentLoader->overrideEncoding().isEmpty() || frameLoadType == FrameLoadTypeBackForward)
740 return ReturnCacheDataElseLoad;
741 if (isReload || frameLoadType == FrameLoadTypeSame || request.isConditional() || request.httpMethod() == "POST")
742 return ReloadIgnoringCacheData;
743 if (LocalFrame* parent = frame()->tree().parent())
744 return parent->document()->fetcher()->resourceRequestCachePolicy(request, type);
745 return UseProtocolCachePolicy;
748 if (request.isConditional())
749 return ReloadIgnoringCacheData;
751 if (m_documentLoader && m_document && !m_document->loadEventFinished()) {
752 // For POST requests, we mutate the main resource's cache policy to avoid form resubmission.
753 // This policy should not be inherited by subresources.
754 ResourceRequestCachePolicy mainResourceCachePolicy = m_documentLoader->request().cachePolicy();
755 if (mainResourceCachePolicy == ReturnCacheDataDontLoad)
756 return ReturnCacheDataElseLoad;
757 return mainResourceCachePolicy;
759 return UseProtocolCachePolicy;
762 void ResourceFetcher::addAdditionalRequestHeaders(ResourceRequest& request, Resource::Type type)
767 if (request.cachePolicy() == UseProtocolCachePolicy)
768 request.setCachePolicy(resourceRequestCachePolicy(request, type));
769 if (request.targetType() == ResourceRequest::TargetIsUnspecified)
770 determineTargetType(request, type);
771 if (type == Resource::LinkPrefetch || type == Resource::LinkSubresource)
772 request.setHTTPHeaderField("Purpose", "prefetch");
774 context().addAdditionalRequestHeaders(document(), request, (type == Resource::MainResource) ? FetchMainResource : FetchSubresource);
777 ResourcePtr<Resource> ResourceFetcher::revalidateResource(const FetchRequest& request, Resource* resource)
780 ASSERT(memoryCache()->contains(resource));
781 ASSERT(resource->isLoaded());
782 ASSERT(resource->canUseCacheValidator());
783 ASSERT(!resource->resourceToRevalidate());
785 ResourceRequest revalidatingRequest(resource->resourceRequest());
786 revalidatingRequest.clearHTTPReferrer();
787 addAdditionalRequestHeaders(revalidatingRequest, resource->type());
789 const AtomicString& lastModified = resource->response().httpHeaderField("Last-Modified");
790 const AtomicString& eTag = resource->response().httpHeaderField("ETag");
791 if (!lastModified.isEmpty() || !eTag.isEmpty()) {
792 ASSERT(context().cachePolicy(document()) != CachePolicyReload);
793 if (context().cachePolicy(document()) == CachePolicyRevalidate)
794 revalidatingRequest.setHTTPHeaderField("Cache-Control", "max-age=0");
795 if (!lastModified.isEmpty())
796 revalidatingRequest.setHTTPHeaderField("If-Modified-Since", lastModified);
798 revalidatingRequest.setHTTPHeaderField("If-None-Match", eTag);
801 ResourcePtr<Resource> newResource = createResource(resource->type(), revalidatingRequest, resource->encoding());
803 WTF_LOG(ResourceLoading, "Resource %p created to revalidate %p", newResource.get(), resource);
804 newResource->setResourceToRevalidate(resource);
806 memoryCache()->remove(resource);
807 memoryCache()->add(newResource.get());
808 storeResourceTimingInitiatorInformation(newResource, request);
809 TRACE_EVENT_ASYNC_BEGIN2("net", "Resource", newResource.get(), "url", newResource->url().string().ascii(), "priority", newResource->resourceRequest().priority());
813 ResourcePtr<Resource> ResourceFetcher::loadResource(Resource::Type type, FetchRequest& request, const String& charset)
815 ASSERT(!memoryCache()->resourceForURL(request.resourceRequest().url()));
817 WTF_LOG(ResourceLoading, "Loading Resource for '%s'.", request.resourceRequest().url().elidedString().latin1().data());
819 addAdditionalRequestHeaders(request.mutableResourceRequest(), type);
820 ResourcePtr<Resource> resource = createResource(type, request.mutableResourceRequest(), charset);
822 memoryCache()->add(resource.get());
823 storeResourceTimingInitiatorInformation(resource, request);
824 TRACE_EVENT_ASYNC_BEGIN2("net", "Resource", resource.get(), "url", resource->url().string().ascii(), "priority", resource->resourceRequest().priority());
828 void ResourceFetcher::storeResourceTimingInitiatorInformation(const ResourcePtr<Resource>& resource, const FetchRequest& request)
830 if (request.options().requestInitiatorContext != DocumentContext)
833 RefPtr<ResourceTimingInfo> info = ResourceTimingInfo::create(request.options().initiatorInfo.name, monotonicallyIncreasingTime());
835 if (resource->type() == Resource::MainResource) {
836 // <iframe>s should report the initial navigation requested by the parent document, but not subsequent navigations.
837 if (frame()->ownerElement() && !frame()->ownerElement()->loadedNonEmptyDocument()) {
838 info->setInitiatorType(frame()->ownerElement()->localName());
839 m_resourceTimingInfoMap.add(resource.get(), info);
840 frame()->ownerElement()->didLoadNonEmptyDocument();
843 m_resourceTimingInfoMap.add(resource.get(), info);
847 ResourceFetcher::RevalidationPolicy ResourceFetcher::determineRevalidationPolicy(Resource::Type type, ResourceRequest& request, bool forPreload, Resource* existingResource, FetchRequest::DeferOption defer, const ResourceLoaderOptions& options) const
849 if (!existingResource)
852 // We already have a preload going for this URL.
853 if (forPreload && existingResource->isPreloaded())
856 // If the same URL has been loaded as a different type, we need to reload.
857 if (existingResource->type() != type) {
858 WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to type mismatch.");
862 // Do not load from cache if images are not enabled. The load for this image will be blocked
863 // in ImageResource::load.
864 if (FetchRequest::DeferredByClient == defer)
867 // Always use data uris.
868 // FIXME: Extend this to non-images.
869 if (type == Resource::Image && request.url().protocolIsData())
872 // If a main resource was populated from a SubstituteData load, use it.
873 if (type == Resource::MainResource && m_documentLoader->substituteData().isValid())
876 if (!existingResource->canReuse(request))
879 // Never use cache entries for downloadToFile requests. The caller expects the resource in a file.
880 if (request.downloadToFile())
883 // Certain requests (e.g., XHRs) might have manually set headers that require revalidation.
884 // FIXME: In theory, this should be a Revalidate case. In practice, the MemoryCache revalidation path assumes a whole bunch
885 // of things about how revalidation works that manual headers violate, so punt to Reload instead.
886 if (request.isConditional())
889 // Don't reload resources while pasting.
890 if (m_allowStaleResources)
893 // Always use preloads.
894 if (existingResource->isPreloaded())
897 // CachePolicyHistoryBuffer uses the cache no matter what.
898 CachePolicy cachePolicy = context().cachePolicy(document());
899 if (cachePolicy == CachePolicyHistoryBuffer)
902 // Don't reuse resources with Cache-control: no-store.
903 if (existingResource->response().cacheControlContainsNoStore()) {
904 WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to Cache-control: no-store.");
908 // If fetching a resource with a different 'CORS enabled' flag, reload.
909 if (type != Resource::MainResource && options.corsEnabled != existingResource->options().corsEnabled)
912 // If credentials were sent with the previous request and won't be
913 // with this one, or vice versa, re-fetch the resource.
915 // This helps with the case where the server sends back
916 // "Access-Control-Allow-Origin: *" all the time, but some of the
917 // client's requests are made without CORS and some with.
918 if (existingResource->resourceRequest().allowStoredCredentials() != request.allowStoredCredentials()) {
919 WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to difference in credentials settings.");
923 // During the initial load, avoid loading the same resource multiple times for a single document,
924 // even if the cache policies would tell us to. Raw resources are exempted.
925 if (type != Resource::Raw && document() && !document()->loadEventFinished() && m_validatedURLs.contains(existingResource->url()))
928 // CachePolicyReload always reloads
929 if (cachePolicy == CachePolicyReload) {
930 WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to CachePolicyReload.");
934 // We'll try to reload the resource if it failed last time.
935 if (existingResource->errorOccurred()) {
936 WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicye reloading due to resource being in the error state");
940 // For resources that are not yet loaded we ignore the cache policy.
941 if (existingResource->isLoading())
944 // If any of the redirects in the chain to loading the resource were not cacheable, we cannot reuse our cached resource.
945 if (!existingResource->canReuseRedirectChain()) {
946 WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to an uncacheable redirect");
950 // Check if the cache headers requires us to revalidate (cache expiration for example).
951 if (cachePolicy == CachePolicyRevalidate || existingResource->mustRevalidateDueToCacheHeaders()) {
952 // See if the resource has usable ETag or Last-modified headers.
953 if (existingResource->canUseCacheValidator())
957 WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to missing cache validators.");
964 void ResourceFetcher::printAccessDeniedMessage(const KURL& url) const
973 if (!m_document || m_document->url().isNull())
974 message = "Unsafe attempt to load URL " + url.elidedString() + '.';
976 message = "Unsafe attempt to load URL " + url.elidedString() + " from frame with URL " + m_document->url().elidedString() + ". Domains, protocols and ports must match.\n";
978 frame()->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message);
981 void ResourceFetcher::setAutoLoadImages(bool enable)
983 if (enable == m_autoLoadImages)
986 m_autoLoadImages = enable;
988 if (!m_autoLoadImages)
991 reloadImagesIfNotDeferred();
994 void ResourceFetcher::setImagesEnabled(bool enable)
996 if (enable == m_imagesEnabled)
999 m_imagesEnabled = enable;
1001 if (!m_imagesEnabled)
1004 reloadImagesIfNotDeferred();
1007 bool ResourceFetcher::clientDefersImage(const KURL& url) const
1009 return frame() && !frame()->loader().client()->allowImage(m_imagesEnabled, url);
1012 bool ResourceFetcher::shouldDeferImageLoad(const KURL& url) const
1014 return clientDefersImage(url) || !m_autoLoadImages;
1017 void ResourceFetcher::reloadImagesIfNotDeferred()
1019 DocumentResourceMap::iterator end = m_documentResources.end();
1020 for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != end; ++it) {
1021 Resource* resource = it->value.get();
1022 if (resource->type() == Resource::Image && resource->stillNeedsLoad() && !clientDefersImage(resource->url()))
1023 const_cast<Resource*>(resource)->load(this, defaultResourceOptions());
1027 void ResourceFetcher::redirectReceived(Resource* resource, const ResourceResponse& redirectResponse)
1029 ResourceTimingInfoMap::iterator it = m_resourceTimingInfoMap.find(resource);
1030 if (it != m_resourceTimingInfoMap.end())
1031 it->value->addRedirect(redirectResponse);
1034 void ResourceFetcher::didLoadResource(Resource* resource)
1036 RefPtr<DocumentLoader> protectDocumentLoader(m_documentLoader);
1037 RefPtr<Document> protectDocument(m_document);
1039 if (resource && resource->response().isHTTP() && ((!resource->errorOccurred() && !resource->wasCanceled()) || resource->response().httpStatusCode() == 304) && document()) {
1040 ResourceTimingInfoMap::iterator it = m_resourceTimingInfoMap.find(resource);
1041 if (it != m_resourceTimingInfoMap.end()) {
1042 RefPtr<ResourceTimingInfo> info = it->value;
1043 m_resourceTimingInfoMap.remove(it);
1044 populateResourceTiming(info.get(), resource, false);
1045 reportResourceTiming(info.get(), document(), resource->type() == Resource::MainResource);
1050 frame()->loader().loadDone();
1051 scheduleDocumentResourcesGC();
1054 void ResourceFetcher::scheduleDocumentResourcesGC()
1056 if (!m_garbageCollectDocumentResourcesTimer.isActive())
1057 m_garbageCollectDocumentResourcesTimer.startOneShot(0, FROM_HERE);
1060 // Garbage collecting m_documentResources is a workaround for the
1061 // ResourcePtrs on the RHS being strong references. Ideally this
1062 // would be a weak map, however ResourcePtrs perform additional
1063 // bookkeeping on Resources, so instead pseudo-GC them -- when the
1064 // reference count reaches 1, m_documentResources is the only reference, so
1065 // remove it from the map.
1066 void ResourceFetcher::garbageCollectDocumentResourcesTimerFired(Timer<ResourceFetcher>* timer)
1068 ASSERT_UNUSED(timer, timer == &m_garbageCollectDocumentResourcesTimer);
1069 garbageCollectDocumentResources();
1072 void ResourceFetcher::garbageCollectDocumentResources()
1074 typedef Vector<String, 10> StringVector;
1075 StringVector resourcesToDelete;
1077 for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != m_documentResources.end(); ++it) {
1078 if (it->value->hasOneHandle())
1079 resourcesToDelete.append(it->key);
1082 for (StringVector::const_iterator it = resourcesToDelete.begin(); it != resourcesToDelete.end(); ++it)
1083 m_documentResources.remove(*it);
1086 void ResourceFetcher::notifyLoadedFromMemoryCache(Resource* resource)
1088 if (!frame() || !frame()->page() || resource->status() != Resource::Cached || m_validatedURLs.contains(resource->url()))
1091 ResourceRequest request(resource->url());
1092 unsigned long identifier = createUniqueIdentifier();
1093 context().dispatchDidLoadResourceFromMemoryCache(request, resource->response());
1094 // FIXME: If willSendRequest changes the request, we don't respect it.
1095 willSendRequest(identifier, request, ResourceResponse(), resource->options().initiatorInfo);
1096 InspectorInstrumentation::markResourceAsCached(frame()->page(), identifier);
1097 context().sendRemainingDelegateMessages(m_documentLoader, identifier, resource->response(), resource->encodedSize());
1100 void ResourceFetcher::incrementRequestCount(const Resource* res)
1102 if (res->ignoreForRequestCount())
1108 void ResourceFetcher::decrementRequestCount(const Resource* res)
1110 if (res->ignoreForRequestCount())
1114 ASSERT(m_requestCount > -1);
1117 void ResourceFetcher::preload(Resource::Type type, FetchRequest& request, const String& charset)
1119 requestPreload(type, request, charset);
1122 void ResourceFetcher::requestPreload(Resource::Type type, FetchRequest& request, const String& charset)
1125 if (type == Resource::Script || type == Resource::CSSStyleSheet)
1126 encoding = charset.isEmpty() ? m_document->charset().string() : charset;
1128 request.setCharset(encoding);
1129 request.setForPreload(true);
1131 ResourcePtr<Resource> resource = requestResource(type, request);
1132 if (!resource || (m_preloads && m_preloads->contains(resource.get())))
1134 TRACE_EVENT_ASYNC_STEP_INTO0("net", "Resource", resource.get(), "Preload");
1135 resource->increasePreloadCount();
1138 m_preloads = adoptPtr(new ListHashSet<Resource*>);
1139 m_preloads->add(resource.get());
1142 printf("PRELOADING %s\n", resource->url().string().latin1().data());
1146 bool ResourceFetcher::isPreloaded(const String& urlString) const
1148 const KURL& url = m_document->completeURL(urlString);
1151 ListHashSet<Resource*>::iterator end = m_preloads->end();
1152 for (ListHashSet<Resource*>::iterator it = m_preloads->begin(); it != end; ++it) {
1153 Resource* resource = *it;
1154 if (resource->url() == url)
1162 void ResourceFetcher::clearPreloads()
1165 printPreloadStats();
1170 ListHashSet<Resource*>::iterator end = m_preloads->end();
1171 for (ListHashSet<Resource*>::iterator it = m_preloads->begin(); it != end; ++it) {
1172 Resource* res = *it;
1173 res->decreasePreloadCount();
1174 bool deleted = res->deleteIfPossible();
1175 if (!deleted && res->preloadResult() == Resource::PreloadNotReferenced)
1176 memoryCache()->remove(res);
1181 void ResourceFetcher::didFinishLoading(const Resource* resource, double finishTime, int64_t encodedDataLength)
1183 TRACE_EVENT_ASYNC_END0("net", "Resource", resource);
1184 context().dispatchDidFinishLoading(m_documentLoader, resource->identifier(), finishTime, encodedDataLength);
1187 void ResourceFetcher::didChangeLoadingPriority(const Resource* resource, ResourceLoadPriority loadPriority, int intraPriorityValue)
1189 TRACE_EVENT_ASYNC_STEP_INTO1("net", "Resource", resource, "ChangePriority", "priority", loadPriority);
1190 context().dispatchDidChangeResourcePriority(resource->identifier(), loadPriority, intraPriorityValue);
1193 void ResourceFetcher::didFailLoading(const Resource* resource, const ResourceError& error)
1195 TRACE_EVENT_ASYNC_END0("net", "Resource", resource);
1196 context().dispatchDidFail(m_documentLoader, resource->identifier(), error);
1199 void ResourceFetcher::willSendRequest(unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse, const FetchInitiatorInfo& initiatorInfo)
1201 context().dispatchWillSendRequest(m_documentLoader, identifier, request, redirectResponse, initiatorInfo);
1204 void ResourceFetcher::didReceiveResponse(const Resource* resource, const ResourceResponse& response)
1206 context().dispatchDidReceiveResponse(m_documentLoader, resource->identifier(), response, resource->loader());
1209 void ResourceFetcher::didReceiveData(const Resource* resource, const char* data, int dataLength, int encodedDataLength)
1211 context().dispatchDidReceiveData(m_documentLoader, resource->identifier(), data, dataLength, encodedDataLength);
1214 void ResourceFetcher::didDownloadData(const Resource* resource, int dataLength, int encodedDataLength)
1216 context().dispatchDidDownloadData(m_documentLoader, resource->identifier(), dataLength, encodedDataLength);
1219 void ResourceFetcher::subresourceLoaderFinishedLoadingOnePart(ResourceLoader* loader)
1221 if (m_multipartLoaders)
1222 m_multipartLoaders->add(loader);
1224 m_loaders->remove(loader);
1225 if (LocalFrame* frame = this->frame())
1226 return frame->loader().checkLoadComplete(m_documentLoader);
1229 void ResourceFetcher::didInitializeResourceLoader(ResourceLoader* loader)
1234 m_loaders = adoptPtr(new ResourceLoaderSet());
1235 ASSERT(!m_loaders->contains(loader));
1236 m_loaders->add(loader);
1239 void ResourceFetcher::willTerminateResourceLoader(ResourceLoader* loader)
1241 if (!m_loaders || !m_loaders->contains(loader))
1243 m_loaders->remove(loader);
1244 if (LocalFrame* frame = this->frame())
1245 frame->loader().checkLoadComplete(m_documentLoader);
1248 void ResourceFetcher::willStartLoadingResource(ResourceRequest& request)
1250 if (m_documentLoader)
1251 m_documentLoader->applicationCacheHost()->willStartLoadingResource(request);
1254 void ResourceFetcher::stopFetching()
1256 if (m_multipartLoaders)
1257 m_multipartLoaders->cancelAll();
1259 m_loaders->cancelAll();
1262 bool ResourceFetcher::isFetching() const
1264 return m_loaders && !m_loaders->isEmpty();
1267 void ResourceFetcher::setDefersLoading(bool defers)
1270 m_loaders->setAllDefersLoading(defers);
1273 bool ResourceFetcher::defersLoading() const
1275 if (LocalFrame* frame = this->frame())
1276 return frame->page()->defersLoading();
1280 bool ResourceFetcher::isLoadedBy(ResourceLoaderHost* possibleOwner) const
1282 return this == possibleOwner;
1285 bool ResourceFetcher::canAccessRedirect(Resource* resource, ResourceRequest& request, const ResourceResponse& redirectResponse, ResourceLoaderOptions& options)
1287 if (!canRequest(resource->type(), request.url(), options, false, FetchRequest::UseDefaultOriginRestrictionForType))
1289 if (options.corsEnabled == IsCORSEnabled) {
1290 SecurityOrigin* sourceOrigin = options.securityOrigin.get();
1291 if (!sourceOrigin && document())
1292 sourceOrigin = document()->securityOrigin();
1294 String errorMessage;
1295 if (!CrossOriginAccessControl::handleRedirect(resource, sourceOrigin, request, redirectResponse, options, errorMessage)) {
1296 if (frame() && frame()->document())
1297 frame()->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, errorMessage);
1301 if (resource->type() == Resource::Image && shouldDeferImageLoad(request.url()))
1306 void ResourceFetcher::refResourceLoaderHost()
1311 void ResourceFetcher::derefResourceLoaderHost()
1317 void ResourceFetcher::printPreloadStats()
1322 unsigned scripts = 0;
1323 unsigned scriptMisses = 0;
1324 unsigned stylesheets = 0;
1325 unsigned stylesheetMisses = 0;
1326 unsigned images = 0;
1327 unsigned imageMisses = 0;
1328 ListHashSet<Resource*>::iterator end = m_preloads->end();
1329 for (ListHashSet<Resource*>::iterator it = m_preloads->begin(); it != end; ++it) {
1330 Resource* res = *it;
1331 if (res->preloadResult() == Resource::PreloadNotReferenced)
1332 printf("!! UNREFERENCED PRELOAD %s\n", res->url().string().latin1().data());
1333 else if (res->preloadResult() == Resource::PreloadReferencedWhileComplete)
1334 printf("HIT COMPLETE PRELOAD %s\n", res->url().string().latin1().data());
1335 else if (res->preloadResult() == Resource::PreloadReferencedWhileLoading)
1336 printf("HIT LOADING PRELOAD %s\n", res->url().string().latin1().data());
1338 if (res->type() == Resource::Script) {
1340 if (res->preloadResult() < Resource::PreloadReferencedWhileLoading)
1342 } else if (res->type() == Resource::CSSStyleSheet) {
1344 if (res->preloadResult() < Resource::PreloadReferencedWhileLoading)
1348 if (res->preloadResult() < Resource::PreloadReferencedWhileLoading)
1352 if (res->errorOccurred())
1353 memoryCache()->remove(res);
1355 res->decreasePreloadCount();
1360 printf("SCRIPTS: %d (%d hits, hit rate %d%%)\n", scripts, scripts - scriptMisses, (scripts - scriptMisses) * 100 / scripts);
1362 printf("STYLESHEETS: %d (%d hits, hit rate %d%%)\n", stylesheets, stylesheets - stylesheetMisses, (stylesheets - stylesheetMisses) * 100 / stylesheets);
1364 printf("IMAGES: %d (%d hits, hit rate %d%%)\n", images, images - imageMisses, (images - imageMisses) * 100 / images);
1368 const ResourceLoaderOptions& ResourceFetcher::defaultResourceOptions()
1370 DEFINE_STATIC_LOCAL(ResourceLoaderOptions, options, (SniffContent, BufferData, AllowStoredCredentials, ClientRequestedCredentials, CheckContentSecurityPolicy, DocumentContext));
1374 ResourceFetcher::DeadResourceStatsRecorder::DeadResourceStatsRecorder()
1376 , m_revalidateCount(0)
1381 ResourceFetcher::DeadResourceStatsRecorder::~DeadResourceStatsRecorder()
1383 blink::Platform::current()->histogramCustomCounts(
1384 "WebCore.ResourceFetcher.HitCount", m_useCount, 0, 1000, 50);
1385 blink::Platform::current()->histogramCustomCounts(
1386 "WebCore.ResourceFetcher.RevalidateCount", m_revalidateCount, 0, 1000, 50);
1387 blink::Platform::current()->histogramCustomCounts(
1388 "WebCore.ResourceFetcher.LoadCount", m_loadCount, 0, 1000, 50);
1391 void ResourceFetcher::DeadResourceStatsRecorder::update(RevalidationPolicy policy)
1399 ++m_revalidateCount;