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(resource->loadFinishTime());
177 static void reportResourceTiming(ResourceTimingInfo* info, Document* initiatorDocument, bool isMainResource)
179 if (initiatorDocument && isMainResource)
180 initiatorDocument = initiatorDocument->parentDocument();
181 if (!initiatorDocument || !initiatorDocument->loader())
183 if (DOMWindow* initiatorWindow = initiatorDocument->domWindow())
184 initiatorWindow->performance().addResourceTiming(*info, initiatorDocument);
187 static ResourceRequest::TargetType requestTargetType(const ResourceFetcher* fetcher, const ResourceRequest& request, Resource::Type type)
190 case Resource::MainResource:
191 if (fetcher->frame()->tree().parent())
192 return ResourceRequest::TargetIsSubframe;
193 return ResourceRequest::TargetIsMainFrame;
194 case Resource::XSLStyleSheet:
195 ASSERT(RuntimeEnabledFeatures::xsltEnabled());
196 case Resource::CSSStyleSheet:
197 return ResourceRequest::TargetIsStyleSheet;
198 case Resource::Script:
199 return ResourceRequest::TargetIsScript;
201 return ResourceRequest::TargetIsFont;
202 case Resource::Image:
203 return ResourceRequest::TargetIsImage;
204 case Resource::Shader:
206 case Resource::ImportResource:
207 return ResourceRequest::TargetIsSubresource;
208 case Resource::LinkPrefetch:
209 return ResourceRequest::TargetIsPrefetch;
210 case Resource::LinkSubresource:
211 return ResourceRequest::TargetIsSubresource;
212 case Resource::TextTrack:
213 return ResourceRequest::TargetIsTextTrack;
214 case Resource::SVGDocument:
215 return ResourceRequest::TargetIsImage;
217 ASSERT_NOT_REACHED();
218 return ResourceRequest::TargetIsSubresource;
221 ResourceFetcher::ResourceFetcher(DocumentLoader* documentLoader)
223 , m_documentLoader(documentLoader)
225 , m_garbageCollectDocumentResourcesTimer(this, &ResourceFetcher::garbageCollectDocumentResourcesTimerFired)
226 , m_resourceTimingReportTimer(this, &ResourceFetcher::resourceTimingReportTimerFired)
227 , m_autoLoadImages(true)
228 , m_imagesEnabled(true)
229 , m_allowStaleResources(false)
233 ResourceFetcher::~ResourceFetcher()
235 m_documentLoader = 0;
240 // Make sure no requests still point to this ResourceFetcher
241 ASSERT(!m_requestCount);
244 Resource* ResourceFetcher::cachedResource(const KURL& resourceURL) const
246 KURL url = MemoryCache::removeFragmentIdentifierIfNeeded(resourceURL);
247 return m_documentResources.get(url).get();
250 LocalFrame* ResourceFetcher::frame() const
252 if (m_documentLoader)
253 return m_documentLoader->frame();
254 if (m_document && m_document->import())
255 return m_document->import()->frame();
259 FetchContext& ResourceFetcher::context() const
261 if (LocalFrame* frame = this->frame())
262 return frame->fetchContext();
263 return FetchContext::nullInstance();
266 ResourcePtr<Resource> ResourceFetcher::fetchSynchronously(FetchRequest& request)
269 request.mutableResourceRequest().setTimeoutInterval(10);
270 ResourceLoaderOptions options(request.options());
271 options.synchronousPolicy = RequestSynchronously;
272 request.setOptions(options);
273 return requestResource(Resource::Raw, request);
276 ResourcePtr<ImageResource> ResourceFetcher::fetchImage(FetchRequest& request)
278 if (LocalFrame* f = frame()) {
279 if (f->document()->pageDismissalEventBeingDispatched() != Document::NoDismissal) {
280 KURL requestURL = request.resourceRequest().url();
281 if (requestURL.isValid() && canRequest(Resource::Image, requestURL, request.options(), request.forPreload(), request.originRestriction()))
282 PingLoader::loadImage(f, requestURL);
287 if (request.resourceRequest().url().protocolIsData())
288 preCacheDataURIImage(request);
290 request.setDefer(clientDefersImage(request.resourceRequest().url()) ? FetchRequest::DeferredByClient : FetchRequest::NoDefer);
291 return toImageResource(requestResource(Resource::Image, request));
294 void ResourceFetcher::preCacheDataURIImage(const FetchRequest& request)
296 const KURL& url = request.resourceRequest().url();
297 ASSERT(url.protocolIsData());
299 if (memoryCache()->resourceForURL(url))
302 if (Resource* resource = resourceFromDataURIRequest(request.resourceRequest(), request.options())) {
303 memoryCache()->add(resource);
304 scheduleDocumentResourcesGC();
308 ResourcePtr<FontResource> ResourceFetcher::fetchFont(FetchRequest& request)
310 return toFontResource(requestResource(Resource::Font, request));
313 ResourcePtr<ShaderResource> ResourceFetcher::fetchShader(FetchRequest& request)
315 return toShaderResource(requestResource(Resource::Shader, request));
318 ResourcePtr<RawResource> ResourceFetcher::fetchImport(FetchRequest& request)
320 return toRawResource(requestResource(Resource::ImportResource, request));
323 ResourcePtr<CSSStyleSheetResource> ResourceFetcher::fetchCSSStyleSheet(FetchRequest& request)
325 return toCSSStyleSheetResource(requestResource(Resource::CSSStyleSheet, request));
328 ResourcePtr<CSSStyleSheetResource> ResourceFetcher::fetchUserCSSStyleSheet(FetchRequest& request)
330 KURL url = MemoryCache::removeFragmentIdentifierIfNeeded(request.resourceRequest().url());
332 if (Resource* existing = memoryCache()->resourceForURL(url)) {
333 if (existing->type() == Resource::CSSStyleSheet)
334 return toCSSStyleSheetResource(existing);
335 memoryCache()->remove(existing);
338 request.setOptions(ResourceLoaderOptions(SniffContent, BufferData, AllowStoredCredentials, ClientRequestedCredentials, CheckContentSecurityPolicy, DocumentContext));
339 return toCSSStyleSheetResource(requestResource(Resource::CSSStyleSheet, request));
342 ResourcePtr<ScriptResource> ResourceFetcher::fetchScript(FetchRequest& request)
344 return toScriptResource(requestResource(Resource::Script, request));
347 ResourcePtr<XSLStyleSheetResource> ResourceFetcher::fetchXSLStyleSheet(FetchRequest& request)
349 ASSERT(RuntimeEnabledFeatures::xsltEnabled());
350 return toXSLStyleSheetResource(requestResource(Resource::XSLStyleSheet, request));
353 ResourcePtr<DocumentResource> ResourceFetcher::fetchSVGDocument(FetchRequest& request)
355 return toDocumentResource(requestResource(Resource::SVGDocument, request));
358 ResourcePtr<Resource> ResourceFetcher::fetchLinkResource(Resource::Type type, FetchRequest& request)
361 ASSERT(type == Resource::LinkPrefetch || type == Resource::LinkSubresource);
362 return requestResource(type, request);
365 ResourcePtr<RawResource> ResourceFetcher::fetchRawResource(FetchRequest& request)
367 return toRawResource(requestResource(Resource::Raw, request));
370 ResourcePtr<RawResource> ResourceFetcher::fetchMainResource(FetchRequest& request, const SubstituteData& substituteData)
372 if (substituteData.isValid())
373 preCacheSubstituteDataForMainResource(request, substituteData);
374 return toRawResource(requestResource(Resource::MainResource, request));
377 void ResourceFetcher::preCacheSubstituteDataForMainResource(const FetchRequest& request, const SubstituteData& substituteData)
379 const KURL& url = request.url();
380 if (Resource* oldResource = memoryCache()->resourceForURL(url))
381 memoryCache()->remove(oldResource);
383 ResourceResponse response(url, substituteData.mimeType(), substituteData.content()->size(), substituteData.textEncoding(), emptyString());
384 ResourcePtr<Resource> resource = createResource(Resource::MainResource, request.resourceRequest(), substituteData.textEncoding());
385 resource->setNeedsSynchronousCacheHit(substituteData.forceSynchronousLoad());
386 resource->setOptions(request.options());
387 resource->setDataBufferingPolicy(BufferData);
388 resource->responseReceived(response);
389 if (substituteData.content()->size())
390 resource->setResourceBuffer(substituteData.content());
392 memoryCache()->add(resource.get());
395 bool ResourceFetcher::checkInsecureContent(Resource::Type type, const KURL& url, MixedContentBlockingTreatment treatment) const
397 if (treatment == TreatAsDefaultForType) {
399 case Resource::XSLStyleSheet:
400 ASSERT(RuntimeEnabledFeatures::xsltEnabled());
401 case Resource::Script:
402 case Resource::SVGDocument:
403 case Resource::CSSStyleSheet:
404 case Resource::ImportResource:
405 // These resource can inject script into the current document (Script,
406 // XSL) or exfiltrate the content of the current document (CSS).
407 treatment = TreatAsActiveContent;
410 case Resource::TextTrack:
411 case Resource::Shader:
413 case Resource::Image:
415 // These resources can corrupt only the frame's pixels.
416 treatment = TreatAsPassiveContent;
419 case Resource::MainResource:
420 case Resource::LinkPrefetch:
421 case Resource::LinkSubresource:
422 // These cannot affect the current document.
423 treatment = TreatAsAlwaysAllowedContent;
427 if (treatment == TreatAsActiveContent) {
428 if (LocalFrame* f = frame()) {
429 if (!f->loader().mixedContentChecker()->canRunInsecureContent(m_document->securityOrigin(), url))
431 LocalFrame* top = f->tree().top();
432 if (top != f && !top->loader().mixedContentChecker()->canRunInsecureContent(top->document()->securityOrigin(), url))
435 } else if (treatment == TreatAsPassiveContent) {
436 if (LocalFrame* f = frame()) {
437 LocalFrame* top = f->tree().top();
438 if (!top->loader().mixedContentChecker()->canDisplayInsecureContent(top->document()->securityOrigin(), url))
442 ASSERT(treatment == TreatAsAlwaysAllowedContent);
447 bool ResourceFetcher::canRequest(Resource::Type type, const KURL& url, const ResourceLoaderOptions& options, bool forPreload, FetchRequest::OriginRestriction originRestriction) const
449 SecurityOrigin* securityOrigin = options.securityOrigin.get();
450 if (!securityOrigin && document())
451 securityOrigin = document()->securityOrigin();
453 if (securityOrigin && !securityOrigin->canDisplay(url)) {
455 context().reportLocalLoadFailed(url);
456 WTF_LOG(ResourceLoading, "ResourceFetcher::requestResource URL was not allowed by SecurityOrigin::canDisplay");
460 // FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved.
461 bool shouldBypassMainWorldContentSecurityPolicy = (frame() && frame()->script().shouldBypassMainWorldContentSecurityPolicy()) || (options.contentSecurityPolicyOption == DoNotCheckContentSecurityPolicy);
463 // Some types of resources can be loaded only from the same origin. Other
464 // types of resources, like Images, Scripts, and CSS, can be loaded from
467 case Resource::MainResource:
468 case Resource::Image:
469 case Resource::CSSStyleSheet:
470 case Resource::Script:
473 case Resource::LinkPrefetch:
474 case Resource::LinkSubresource:
475 case Resource::TextTrack:
476 case Resource::Shader:
477 case Resource::ImportResource:
478 // By default these types of resources can be loaded from any origin.
479 // FIXME: Are we sure about Resource::Font?
480 if (originRestriction == FetchRequest::RestrictToSameOrigin && !securityOrigin->canRequest(url)) {
481 printAccessDeniedMessage(url);
485 case Resource::XSLStyleSheet:
486 ASSERT(RuntimeEnabledFeatures::xsltEnabled());
487 case Resource::SVGDocument:
488 if (!securityOrigin->canRequest(url)) {
489 printAccessDeniedMessage(url);
496 case Resource::XSLStyleSheet:
497 ASSERT(RuntimeEnabledFeatures::xsltEnabled());
498 if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowScriptFromSource(url))
501 case Resource::Script:
502 case Resource::ImportResource:
503 if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowScriptFromSource(url))
507 Settings* settings = frame()->settings();
508 if (!frame()->loader().client()->allowScriptFromSource(!settings || settings->scriptEnabled(), url)) {
509 frame()->loader().client()->didNotAllowScript();
514 case Resource::Shader:
515 // Since shaders are referenced from CSS Styles use the same rules here.
516 case Resource::CSSStyleSheet:
517 if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowStyleFromSource(url))
520 case Resource::SVGDocument:
521 case Resource::Image:
522 if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowImageFromSource(url))
525 case Resource::Font: {
526 if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowFontFromSource(url))
530 case Resource::MainResource:
532 case Resource::LinkPrefetch:
533 case Resource::LinkSubresource:
535 case Resource::TextTrack:
536 if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowMediaFromSource(url))
541 // Last of all, check for insecure content. We do this last so that when
542 // folks block insecure content with a CSP policy, they don't get a warning.
543 // They'll still get a warning in the console about CSP blocking the load.
545 // FIXME: Should we consider forPreload here?
546 if (!checkInsecureContent(type, url, options.mixedContentBlockingTreatment))
552 bool ResourceFetcher::canAccessResource(Resource* resource, SecurityOrigin* sourceOrigin, const KURL& url) const
554 // Redirects can change the response URL different from one of request.
555 if (!canRequest(resource->type(), url, resource->options(), false, FetchRequest::UseDefaultOriginRestrictionForType))
558 if (!sourceOrigin && document())
559 sourceOrigin = document()->securityOrigin();
561 if (sourceOrigin->canRequest(url))
564 String errorDescription;
565 if (!resource->passesAccessControlCheck(sourceOrigin, errorDescription)) {
566 if (frame() && frame()->document()) {
567 String resourceType = Resource::resourceTypeToString(resource->type(), resource->options().initiatorInfo);
568 frame()->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, resourceType + " from origin '" + SecurityOrigin::create(url)->toString() + "' has been blocked from loading by Cross-Origin Resource Sharing policy: " + errorDescription);
575 bool ResourceFetcher::shouldLoadNewResource(Resource::Type type) const
579 if (!m_documentLoader)
581 if (type == Resource::MainResource)
582 return m_documentLoader == frame()->loader().provisionalDocumentLoader();
583 return m_documentLoader == frame()->loader().documentLoader();
586 bool ResourceFetcher::resourceNeedsLoad(Resource* resource, const FetchRequest& request, RevalidationPolicy policy)
588 if (FetchRequest::DeferredByClient == request.defer())
592 if (resource->stillNeedsLoad())
594 return request.options().synchronousPolicy == RequestSynchronously && resource->isLoading();
597 ResourcePtr<Resource> ResourceFetcher::requestResource(Resource::Type type, FetchRequest& request)
599 ASSERT(request.options().synchronousPolicy == RequestAsynchronously || type == Resource::Raw);
601 KURL url = request.resourceRequest().url();
603 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));
605 // If only the fragment identifiers differ, it is the same resource.
606 url = MemoryCache::removeFragmentIdentifierIfNeeded(url);
611 if (!canRequest(type, url, request.options(), request.forPreload(), request.originRestriction()))
614 if (LocalFrame* f = frame())
615 f->loader().client()->dispatchWillRequestResource(&request);
617 // See if we can use an existing resource from the cache.
618 ResourcePtr<Resource> resource = memoryCache()->resourceForURL(url);
620 const RevalidationPolicy policy = determineRevalidationPolicy(type, request.mutableResourceRequest(), request.forPreload(), resource.get(), request.defer(), request.options());
623 memoryCache()->remove(resource.get());
626 resource = loadResource(type, request, request.charset());
629 resource = revalidateResource(request, resource.get());
632 memoryCache()->updateForAccess(resource.get());
633 notifyLoadedFromMemoryCache(resource.get());
640 if (!resource->hasClients())
641 m_deadStatsRecorder.update(policy);
644 resource->setIdentifier(createUniqueIdentifier());
646 if (!request.forPreload() || policy != Use) {
647 ResourceLoadPriority priority = loadPriority(type, request);
648 if (priority != resource->resourceRequest().priority()) {
649 resource->resourceRequest().setPriority(priority);
650 resource->didChangePriority(priority, 0);
654 if (resourceNeedsLoad(resource.get(), request, policy)) {
655 if (!shouldLoadNewResource(type)) {
656 if (memoryCache()->contains(resource.get()))
657 memoryCache()->remove(resource.get());
661 if (!m_documentLoader || !m_documentLoader->scheduleArchiveLoad(resource.get(), request.resourceRequest()))
662 resource->load(this, request.options());
664 // For asynchronous loads that immediately fail, it's sufficient to return a
665 // null Resource, as it indicates that something prevented the load from starting.
666 // If there's a network error, that failure will happen asynchronously. However, if
667 // a sync load receives a network error, it will have already happened by this point.
668 // In that case, the requester should have access to the relevant ResourceError, so
669 // we need to return a non-null Resource.
670 if (resource->errorOccurred()) {
671 if (memoryCache()->contains(resource.get()))
672 memoryCache()->remove(resource.get());
673 return request.options().synchronousPolicy == RequestSynchronously ? resource : 0;
677 // FIXME: Temporarily leave main resource caching disabled for chromium,
678 // see https://bugs.webkit.org/show_bug.cgi?id=107962. Before caching main
679 // resources, we should be sure to understand the implications for memory
682 // Ensure main resources aren't preloaded, and other main resource loads
683 // are removed from cache to prevent reuse.
684 if (type == Resource::MainResource) {
685 ASSERT(policy != Use || m_documentLoader->substituteData().isValid());
686 ASSERT(policy != Revalidate);
687 memoryCache()->remove(resource.get());
688 if (request.forPreload())
692 if (!request.resourceRequest().url().protocolIsData() && (!m_documentLoader || !m_documentLoader->substituteData().isValid())) {
693 if (policy == Use && !m_validatedURLs.contains(request.resourceRequest().url())) {
694 // Resources loaded from memory cache should be reported the first time they're used.
695 RefPtr<ResourceTimingInfo> info = ResourceTimingInfo::create(request.options().initiatorInfo.name, monotonicallyIncreasingTime());
696 populateResourceTiming(info.get(), resource.get(), true);
697 m_scheduledResourceTimingReports.add(info, resource->type() == Resource::MainResource);
698 if (!m_resourceTimingReportTimer.isActive())
699 m_resourceTimingReportTimer.startOneShot(0, FROM_HERE);
702 m_validatedURLs.add(request.resourceRequest().url());
705 ASSERT(resource->url() == url.string());
706 m_documentResources.set(resource->url(), resource);
710 void ResourceFetcher::resourceTimingReportTimerFired(Timer<ResourceFetcher>* timer)
712 ASSERT_UNUSED(timer, timer == &m_resourceTimingReportTimer);
713 HashMap<RefPtr<ResourceTimingInfo>, bool> timingReports;
714 timingReports.swap(m_scheduledResourceTimingReports);
715 HashMap<RefPtr<ResourceTimingInfo>, bool>::iterator end = timingReports.end();
716 for (HashMap<RefPtr<ResourceTimingInfo>, bool>::iterator it = timingReports.begin(); it != end; ++it) {
717 RefPtr<ResourceTimingInfo> info = it->key;
718 bool isMainResource = it->value;
719 reportResourceTiming(info.get(), document(), isMainResource);
723 void ResourceFetcher::determineTargetType(ResourceRequest& request, Resource::Type type)
725 ResourceRequest::TargetType targetType = requestTargetType(this, request, type);
726 request.setTargetType(targetType);
729 ResourceRequestCachePolicy ResourceFetcher::resourceRequestCachePolicy(const ResourceRequest& request, Resource::Type type)
731 if (type == Resource::MainResource) {
732 FrameLoadType frameLoadType = frame()->loader().loadType();
733 bool isReload = frameLoadType == FrameLoadTypeReload || frameLoadType == FrameLoadTypeReloadFromOrigin;
734 if (request.httpMethod() == "POST" && frameLoadType == FrameLoadTypeBackForward)
735 return ReturnCacheDataDontLoad;
736 if (!m_documentLoader->overrideEncoding().isEmpty() || frameLoadType == FrameLoadTypeBackForward)
737 return ReturnCacheDataElseLoad;
738 if (isReload || frameLoadType == FrameLoadTypeSame || request.isConditional() || request.httpMethod() == "POST")
739 return ReloadIgnoringCacheData;
740 if (LocalFrame* parent = frame()->tree().parent())
741 return parent->document()->fetcher()->resourceRequestCachePolicy(request, type);
742 return UseProtocolCachePolicy;
745 if (request.isConditional())
746 return ReloadIgnoringCacheData;
748 if (m_documentLoader && m_document && !m_document->loadEventFinished()) {
749 // For POST requests, we mutate the main resource's cache policy to avoid form resubmission.
750 // This policy should not be inherited by subresources.
751 ResourceRequestCachePolicy mainResourceCachePolicy = m_documentLoader->request().cachePolicy();
752 if (mainResourceCachePolicy == ReturnCacheDataDontLoad)
753 return ReturnCacheDataElseLoad;
754 return mainResourceCachePolicy;
756 return UseProtocolCachePolicy;
759 void ResourceFetcher::addAdditionalRequestHeaders(ResourceRequest& request, Resource::Type type)
764 if (request.cachePolicy() == UseProtocolCachePolicy)
765 request.setCachePolicy(resourceRequestCachePolicy(request, type));
766 if (request.targetType() == ResourceRequest::TargetIsUnspecified)
767 determineTargetType(request, type);
768 if (type == Resource::LinkPrefetch || type == Resource::LinkSubresource)
769 request.setHTTPHeaderField("Purpose", "prefetch");
771 context().addAdditionalRequestHeaders(document(), request, (type == Resource::MainResource) ? FetchMainResource : FetchSubresource);
774 ResourcePtr<Resource> ResourceFetcher::revalidateResource(const FetchRequest& request, Resource* resource)
777 ASSERT(memoryCache()->contains(resource));
778 ASSERT(resource->isLoaded());
779 ASSERT(resource->canUseCacheValidator());
780 ASSERT(!resource->resourceToRevalidate());
782 ResourceRequest revalidatingRequest(resource->resourceRequest());
783 revalidatingRequest.clearHTTPReferrer();
784 addAdditionalRequestHeaders(revalidatingRequest, resource->type());
786 const AtomicString& lastModified = resource->response().httpHeaderField("Last-Modified");
787 const AtomicString& eTag = resource->response().httpHeaderField("ETag");
788 if (!lastModified.isEmpty() || !eTag.isEmpty()) {
789 ASSERT(context().cachePolicy(document()) != CachePolicyReload);
790 if (context().cachePolicy(document()) == CachePolicyRevalidate)
791 revalidatingRequest.setHTTPHeaderField("Cache-Control", "max-age=0");
792 if (!lastModified.isEmpty())
793 revalidatingRequest.setHTTPHeaderField("If-Modified-Since", lastModified);
795 revalidatingRequest.setHTTPHeaderField("If-None-Match", eTag);
798 ResourcePtr<Resource> newResource = createResource(resource->type(), revalidatingRequest, resource->encoding());
800 WTF_LOG(ResourceLoading, "Resource %p created to revalidate %p", newResource.get(), resource);
801 newResource->setResourceToRevalidate(resource);
803 memoryCache()->remove(resource);
804 memoryCache()->add(newResource.get());
805 storeResourceTimingInitiatorInformation(newResource, request);
806 TRACE_EVENT_ASYNC_BEGIN2("net", "Resource", newResource.get(), "url", newResource->url().string().ascii(), "priority", newResource->resourceRequest().priority());
810 ResourcePtr<Resource> ResourceFetcher::loadResource(Resource::Type type, FetchRequest& request, const String& charset)
812 ASSERT(!memoryCache()->resourceForURL(request.resourceRequest().url()));
814 WTF_LOG(ResourceLoading, "Loading Resource for '%s'.", request.resourceRequest().url().elidedString().latin1().data());
816 addAdditionalRequestHeaders(request.mutableResourceRequest(), type);
817 ResourcePtr<Resource> resource = createResource(type, request.mutableResourceRequest(), charset);
819 memoryCache()->add(resource.get());
820 storeResourceTimingInitiatorInformation(resource, request);
821 TRACE_EVENT_ASYNC_BEGIN2("net", "Resource", resource.get(), "url", resource->url().string().ascii(), "priority", resource->resourceRequest().priority());
825 void ResourceFetcher::storeResourceTimingInitiatorInformation(const ResourcePtr<Resource>& resource, const FetchRequest& request)
827 if (request.options().requestInitiatorContext != DocumentContext)
830 RefPtr<ResourceTimingInfo> info = ResourceTimingInfo::create(request.options().initiatorInfo.name, monotonicallyIncreasingTime());
832 if (resource->type() == Resource::MainResource) {
833 // <iframe>s should report the initial navigation requested by the parent document, but not subsequent navigations.
834 if (frame()->ownerElement() && !frame()->ownerElement()->loadedNonEmptyDocument()) {
835 info->setInitiatorType(frame()->ownerElement()->localName());
836 m_resourceTimingInfoMap.add(resource.get(), info);
837 frame()->ownerElement()->didLoadNonEmptyDocument();
840 m_resourceTimingInfoMap.add(resource.get(), info);
844 ResourceFetcher::RevalidationPolicy ResourceFetcher::determineRevalidationPolicy(Resource::Type type, ResourceRequest& request, bool forPreload, Resource* existingResource, FetchRequest::DeferOption defer, const ResourceLoaderOptions& options) const
846 if (!existingResource)
849 // We already have a preload going for this URL.
850 if (forPreload && existingResource->isPreloaded())
853 // If the same URL has been loaded as a different type, we need to reload.
854 if (existingResource->type() != type) {
855 WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to type mismatch.");
859 // Do not load from cache if images are not enabled. The load for this image will be blocked
860 // in ImageResource::load.
861 if (FetchRequest::DeferredByClient == defer)
864 // Always use data uris.
865 // FIXME: Extend this to non-images.
866 if (type == Resource::Image && request.url().protocolIsData())
869 // If a main resource was populated from a SubstituteData load, use it.
870 if (type == Resource::MainResource && m_documentLoader->substituteData().isValid())
873 if (!existingResource->canReuse(request))
876 // Never use cache entries for downloadToFile requests. The caller expects the resource in a file.
877 if (request.downloadToFile())
880 // Certain requests (e.g., XHRs) might have manually set headers that require revalidation.
881 // FIXME: In theory, this should be a Revalidate case. In practice, the MemoryCache revalidation path assumes a whole bunch
882 // of things about how revalidation works that manual headers violate, so punt to Reload instead.
883 if (request.isConditional())
886 // Don't reload resources while pasting.
887 if (m_allowStaleResources)
890 // Always use preloads.
891 if (existingResource->isPreloaded())
894 // CachePolicyHistoryBuffer uses the cache no matter what.
895 CachePolicy cachePolicy = context().cachePolicy(document());
896 if (cachePolicy == CachePolicyHistoryBuffer)
899 // Don't reuse resources with Cache-control: no-store.
900 if (existingResource->response().cacheControlContainsNoStore()) {
901 WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to Cache-control: no-store.");
905 // If fetching a resource with a different 'CORS enabled' flag, reload.
906 if (type != Resource::MainResource && options.corsEnabled != existingResource->options().corsEnabled)
909 // If credentials were sent with the previous request and won't be
910 // with this one, or vice versa, re-fetch the resource.
912 // This helps with the case where the server sends back
913 // "Access-Control-Allow-Origin: *" all the time, but some of the
914 // client's requests are made without CORS and some with.
915 if (existingResource->resourceRequest().allowStoredCredentials() != request.allowStoredCredentials()) {
916 WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to difference in credentials settings.");
920 // During the initial load, avoid loading the same resource multiple times for a single document,
921 // even if the cache policies would tell us to. Raw resources are exempted.
922 if (type != Resource::Raw && document() && !document()->loadEventFinished() && m_validatedURLs.contains(existingResource->url()))
925 // CachePolicyReload always reloads
926 if (cachePolicy == CachePolicyReload) {
927 WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to CachePolicyReload.");
931 // We'll try to reload the resource if it failed last time.
932 if (existingResource->errorOccurred()) {
933 WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicye reloading due to resource being in the error state");
937 // For resources that are not yet loaded we ignore the cache policy.
938 if (existingResource->isLoading())
941 // If any of the redirects in the chain to loading the resource were not cacheable, we cannot reuse our cached resource.
942 if (!existingResource->canReuseRedirectChain()) {
943 WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to an uncacheable redirect");
947 // Check if the cache headers requires us to revalidate (cache expiration for example).
948 if (cachePolicy == CachePolicyRevalidate || existingResource->mustRevalidateDueToCacheHeaders()) {
949 // See if the resource has usable ETag or Last-modified headers.
950 if (existingResource->canUseCacheValidator())
954 WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to missing cache validators.");
961 void ResourceFetcher::printAccessDeniedMessage(const KURL& url) const
970 if (!m_document || m_document->url().isNull())
971 message = "Unsafe attempt to load URL " + url.elidedString() + '.';
973 message = "Unsafe attempt to load URL " + url.elidedString() + " from frame with URL " + m_document->url().elidedString() + ". Domains, protocols and ports must match.\n";
975 frame()->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message);
978 void ResourceFetcher::setAutoLoadImages(bool enable)
980 if (enable == m_autoLoadImages)
983 m_autoLoadImages = enable;
985 if (!m_autoLoadImages)
988 reloadImagesIfNotDeferred();
991 void ResourceFetcher::setImagesEnabled(bool enable)
993 if (enable == m_imagesEnabled)
996 m_imagesEnabled = enable;
998 if (!m_imagesEnabled)
1001 reloadImagesIfNotDeferred();
1004 bool ResourceFetcher::clientDefersImage(const KURL& url) const
1006 return frame() && !frame()->loader().client()->allowImage(m_imagesEnabled, url);
1009 bool ResourceFetcher::shouldDeferImageLoad(const KURL& url) const
1011 return clientDefersImage(url) || !m_autoLoadImages;
1014 void ResourceFetcher::reloadImagesIfNotDeferred()
1016 DocumentResourceMap::iterator end = m_documentResources.end();
1017 for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != end; ++it) {
1018 Resource* resource = it->value.get();
1019 if (resource->type() == Resource::Image && resource->stillNeedsLoad() && !clientDefersImage(resource->url()))
1020 const_cast<Resource*>(resource)->load(this, defaultResourceOptions());
1024 void ResourceFetcher::redirectReceived(Resource* resource, const ResourceResponse& redirectResponse)
1026 ResourceTimingInfoMap::iterator it = m_resourceTimingInfoMap.find(resource);
1027 if (it != m_resourceTimingInfoMap.end())
1028 it->value->addRedirect(redirectResponse);
1031 void ResourceFetcher::didLoadResource(Resource* resource)
1033 RefPtr<DocumentLoader> protectDocumentLoader(m_documentLoader);
1034 RefPtr<Document> protectDocument(m_document);
1036 if (resource && resource->response().isHTTP() && ((!resource->errorOccurred() && !resource->wasCanceled()) || resource->response().httpStatusCode() == 304) && document()) {
1037 ResourceTimingInfoMap::iterator it = m_resourceTimingInfoMap.find(resource);
1038 if (it != m_resourceTimingInfoMap.end()) {
1039 RefPtr<ResourceTimingInfo> info = it->value;
1040 m_resourceTimingInfoMap.remove(it);
1041 populateResourceTiming(info.get(), resource, false);
1042 reportResourceTiming(info.get(), document(), resource->type() == Resource::MainResource);
1047 frame()->loader().loadDone();
1048 scheduleDocumentResourcesGC();
1051 void ResourceFetcher::scheduleDocumentResourcesGC()
1053 if (!m_garbageCollectDocumentResourcesTimer.isActive())
1054 m_garbageCollectDocumentResourcesTimer.startOneShot(0, FROM_HERE);
1057 // Garbage collecting m_documentResources is a workaround for the
1058 // ResourcePtrs on the RHS being strong references. Ideally this
1059 // would be a weak map, however ResourcePtrs perform additional
1060 // bookkeeping on Resources, so instead pseudo-GC them -- when the
1061 // reference count reaches 1, m_documentResources is the only reference, so
1062 // remove it from the map.
1063 void ResourceFetcher::garbageCollectDocumentResourcesTimerFired(Timer<ResourceFetcher>* timer)
1065 ASSERT_UNUSED(timer, timer == &m_garbageCollectDocumentResourcesTimer);
1066 garbageCollectDocumentResources();
1069 void ResourceFetcher::garbageCollectDocumentResources()
1071 typedef Vector<String, 10> StringVector;
1072 StringVector resourcesToDelete;
1074 for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != m_documentResources.end(); ++it) {
1075 if (it->value->hasOneHandle())
1076 resourcesToDelete.append(it->key);
1079 for (StringVector::const_iterator it = resourcesToDelete.begin(); it != resourcesToDelete.end(); ++it)
1080 m_documentResources.remove(*it);
1083 void ResourceFetcher::notifyLoadedFromMemoryCache(Resource* resource)
1085 if (!frame() || !frame()->page() || resource->status() != Resource::Cached || m_validatedURLs.contains(resource->url()))
1088 ResourceRequest request(resource->url());
1089 unsigned long identifier = createUniqueIdentifier();
1090 context().dispatchDidLoadResourceFromMemoryCache(request, resource->response());
1091 // FIXME: If willSendRequest changes the request, we don't respect it.
1092 willSendRequest(identifier, request, ResourceResponse(), resource->options().initiatorInfo);
1093 InspectorInstrumentation::markResourceAsCached(frame()->page(), identifier);
1094 context().sendRemainingDelegateMessages(m_documentLoader, identifier, resource->response(), resource->encodedSize());
1097 void ResourceFetcher::incrementRequestCount(const Resource* res)
1099 if (res->ignoreForRequestCount())
1105 void ResourceFetcher::decrementRequestCount(const Resource* res)
1107 if (res->ignoreForRequestCount())
1111 ASSERT(m_requestCount > -1);
1114 void ResourceFetcher::preload(Resource::Type type, FetchRequest& request, const String& charset)
1116 requestPreload(type, request, charset);
1119 void ResourceFetcher::requestPreload(Resource::Type type, FetchRequest& request, const String& charset)
1122 if (type == Resource::Script || type == Resource::CSSStyleSheet)
1123 encoding = charset.isEmpty() ? m_document->charset().string() : charset;
1125 request.setCharset(encoding);
1126 request.setForPreload(true);
1128 ResourcePtr<Resource> resource = requestResource(type, request);
1129 if (!resource || (m_preloads && m_preloads->contains(resource.get())))
1131 TRACE_EVENT_ASYNC_STEP_INTO0("net", "Resource", resource.get(), "Preload");
1132 resource->increasePreloadCount();
1135 m_preloads = adoptPtr(new ListHashSet<Resource*>);
1136 m_preloads->add(resource.get());
1139 printf("PRELOADING %s\n", resource->url().string().latin1().data());
1143 bool ResourceFetcher::isPreloaded(const String& urlString) const
1145 const KURL& url = m_document->completeURL(urlString);
1148 ListHashSet<Resource*>::iterator end = m_preloads->end();
1149 for (ListHashSet<Resource*>::iterator it = m_preloads->begin(); it != end; ++it) {
1150 Resource* resource = *it;
1151 if (resource->url() == url)
1159 void ResourceFetcher::clearPreloads()
1162 printPreloadStats();
1167 ListHashSet<Resource*>::iterator end = m_preloads->end();
1168 for (ListHashSet<Resource*>::iterator it = m_preloads->begin(); it != end; ++it) {
1169 Resource* res = *it;
1170 res->decreasePreloadCount();
1171 bool deleted = res->deleteIfPossible();
1172 if (!deleted && res->preloadResult() == Resource::PreloadNotReferenced)
1173 memoryCache()->remove(res);
1178 void ResourceFetcher::didFinishLoading(const Resource* resource, double finishTime, int64_t encodedDataLength)
1180 TRACE_EVENT_ASYNC_END0("net", "Resource", resource);
1181 context().dispatchDidFinishLoading(m_documentLoader, resource->identifier(), finishTime, encodedDataLength);
1184 void ResourceFetcher::didChangeLoadingPriority(const Resource* resource, ResourceLoadPriority loadPriority, int intraPriorityValue)
1186 TRACE_EVENT_ASYNC_STEP_INTO1("net", "Resource", resource, "ChangePriority", "priority", loadPriority);
1187 context().dispatchDidChangeResourcePriority(resource->identifier(), loadPriority, intraPriorityValue);
1190 void ResourceFetcher::didFailLoading(const Resource* resource, const ResourceError& error)
1192 TRACE_EVENT_ASYNC_END0("net", "Resource", resource);
1193 context().dispatchDidFail(m_documentLoader, resource->identifier(), error);
1196 void ResourceFetcher::willSendRequest(unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse, const FetchInitiatorInfo& initiatorInfo)
1198 context().dispatchWillSendRequest(m_documentLoader, identifier, request, redirectResponse, initiatorInfo);
1201 void ResourceFetcher::didReceiveResponse(const Resource* resource, const ResourceResponse& response)
1203 context().dispatchDidReceiveResponse(m_documentLoader, resource->identifier(), response, resource->loader());
1206 void ResourceFetcher::didReceiveData(const Resource* resource, const char* data, int dataLength, int encodedDataLength)
1208 context().dispatchDidReceiveData(m_documentLoader, resource->identifier(), data, dataLength, encodedDataLength);
1211 void ResourceFetcher::didDownloadData(const Resource* resource, int dataLength, int encodedDataLength)
1213 context().dispatchDidDownloadData(m_documentLoader, resource->identifier(), dataLength, encodedDataLength);
1216 void ResourceFetcher::subresourceLoaderFinishedLoadingOnePart(ResourceLoader* loader)
1218 if (m_multipartLoaders)
1219 m_multipartLoaders->add(loader);
1221 m_loaders->remove(loader);
1222 if (LocalFrame* frame = this->frame())
1223 return frame->loader().checkLoadComplete(m_documentLoader);
1226 void ResourceFetcher::didInitializeResourceLoader(ResourceLoader* loader)
1231 m_loaders = adoptPtr(new ResourceLoaderSet());
1232 ASSERT(!m_loaders->contains(loader));
1233 m_loaders->add(loader);
1236 void ResourceFetcher::willTerminateResourceLoader(ResourceLoader* loader)
1238 if (!m_loaders || !m_loaders->contains(loader))
1240 m_loaders->remove(loader);
1241 if (LocalFrame* frame = this->frame())
1242 frame->loader().checkLoadComplete(m_documentLoader);
1245 void ResourceFetcher::willStartLoadingResource(ResourceRequest& request)
1247 if (m_documentLoader)
1248 m_documentLoader->applicationCacheHost()->willStartLoadingResource(request);
1251 void ResourceFetcher::stopFetching()
1253 if (m_multipartLoaders)
1254 m_multipartLoaders->cancelAll();
1256 m_loaders->cancelAll();
1259 bool ResourceFetcher::isFetching() const
1261 return m_loaders && !m_loaders->isEmpty();
1264 void ResourceFetcher::setDefersLoading(bool defers)
1267 m_loaders->setAllDefersLoading(defers);
1270 bool ResourceFetcher::defersLoading() const
1272 if (LocalFrame* frame = this->frame())
1273 return frame->page()->defersLoading();
1277 bool ResourceFetcher::isLoadedBy(ResourceLoaderHost* possibleOwner) const
1279 return this == possibleOwner;
1282 bool ResourceFetcher::canAccessRedirect(Resource* resource, ResourceRequest& request, const ResourceResponse& redirectResponse, ResourceLoaderOptions& options)
1284 if (!canRequest(resource->type(), request.url(), options, false, FetchRequest::UseDefaultOriginRestrictionForType))
1286 if (options.corsEnabled == IsCORSEnabled) {
1287 SecurityOrigin* sourceOrigin = options.securityOrigin.get();
1288 if (!sourceOrigin && document())
1289 sourceOrigin = document()->securityOrigin();
1291 String errorMessage;
1292 if (!CrossOriginAccessControl::handleRedirect(resource, sourceOrigin, request, redirectResponse, options, errorMessage)) {
1293 if (frame() && frame()->document())
1294 frame()->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, errorMessage);
1298 if (resource->type() == Resource::Image && shouldDeferImageLoad(request.url()))
1303 void ResourceFetcher::refResourceLoaderHost()
1308 void ResourceFetcher::derefResourceLoaderHost()
1314 void ResourceFetcher::printPreloadStats()
1319 unsigned scripts = 0;
1320 unsigned scriptMisses = 0;
1321 unsigned stylesheets = 0;
1322 unsigned stylesheetMisses = 0;
1323 unsigned images = 0;
1324 unsigned imageMisses = 0;
1325 ListHashSet<Resource*>::iterator end = m_preloads->end();
1326 for (ListHashSet<Resource*>::iterator it = m_preloads->begin(); it != end; ++it) {
1327 Resource* res = *it;
1328 if (res->preloadResult() == Resource::PreloadNotReferenced)
1329 printf("!! UNREFERENCED PRELOAD %s\n", res->url().string().latin1().data());
1330 else if (res->preloadResult() == Resource::PreloadReferencedWhileComplete)
1331 printf("HIT COMPLETE PRELOAD %s\n", res->url().string().latin1().data());
1332 else if (res->preloadResult() == Resource::PreloadReferencedWhileLoading)
1333 printf("HIT LOADING PRELOAD %s\n", res->url().string().latin1().data());
1335 if (res->type() == Resource::Script) {
1337 if (res->preloadResult() < Resource::PreloadReferencedWhileLoading)
1339 } else if (res->type() == Resource::CSSStyleSheet) {
1341 if (res->preloadResult() < Resource::PreloadReferencedWhileLoading)
1345 if (res->preloadResult() < Resource::PreloadReferencedWhileLoading)
1349 if (res->errorOccurred())
1350 memoryCache()->remove(res);
1352 res->decreasePreloadCount();
1357 printf("SCRIPTS: %d (%d hits, hit rate %d%%)\n", scripts, scripts - scriptMisses, (scripts - scriptMisses) * 100 / scripts);
1359 printf("STYLESHEETS: %d (%d hits, hit rate %d%%)\n", stylesheets, stylesheets - stylesheetMisses, (stylesheets - stylesheetMisses) * 100 / stylesheets);
1361 printf("IMAGES: %d (%d hits, hit rate %d%%)\n", images, images - imageMisses, (images - imageMisses) * 100 / images);
1365 const ResourceLoaderOptions& ResourceFetcher::defaultResourceOptions()
1367 DEFINE_STATIC_LOCAL(ResourceLoaderOptions, options, (SniffContent, BufferData, AllowStoredCredentials, ClientRequestedCredentials, CheckContentSecurityPolicy, DocumentContext));
1371 ResourceFetcher::DeadResourceStatsRecorder::DeadResourceStatsRecorder()
1373 , m_revalidateCount(0)
1378 ResourceFetcher::DeadResourceStatsRecorder::~DeadResourceStatsRecorder()
1380 blink::Platform::current()->histogramCustomCounts(
1381 "WebCore.ResourceFetcher.HitCount", m_useCount, 0, 1000, 50);
1382 blink::Platform::current()->histogramCustomCounts(
1383 "WebCore.ResourceFetcher.RevalidateCount", m_revalidateCount, 0, 1000, 50);
1384 blink::Platform::current()->histogramCustomCounts(
1385 "WebCore.ResourceFetcher.LoadCount", m_loadCount, 0, 1000, 50);
1388 void ResourceFetcher::DeadResourceStatsRecorder::update(RevalidationPolicy policy)
1396 ++m_revalidateCount;