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/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/ContentSecurityPolicy.h"
58 #include "core/frame/DOMWindow.h"
59 #include "core/frame/Frame.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 if (Performance* performance = initiatorWindow->performance())
185 performance->addResourceTiming(*info, initiatorDocument);
189 static ResourceRequest::TargetType requestTargetType(const ResourceFetcher* fetcher, const ResourceRequest& request, Resource::Type type)
192 case Resource::MainResource:
193 if (fetcher->frame()->tree().parent())
194 return ResourceRequest::TargetIsSubframe;
195 return ResourceRequest::TargetIsMainFrame;
196 case Resource::XSLStyleSheet:
197 ASSERT(RuntimeEnabledFeatures::xsltEnabled());
198 case Resource::CSSStyleSheet:
199 return ResourceRequest::TargetIsStyleSheet;
200 case Resource::Script:
201 return ResourceRequest::TargetIsScript;
203 return ResourceRequest::TargetIsFont;
204 case Resource::Image:
205 return ResourceRequest::TargetIsImage;
206 case Resource::Shader:
208 case Resource::ImportResource:
209 return ResourceRequest::TargetIsSubresource;
210 case Resource::LinkPrefetch:
211 return ResourceRequest::TargetIsPrefetch;
212 case Resource::LinkSubresource:
213 return ResourceRequest::TargetIsSubresource;
214 case Resource::TextTrack:
215 return ResourceRequest::TargetIsTextTrack;
216 case Resource::SVGDocument:
217 return ResourceRequest::TargetIsImage;
219 ASSERT_NOT_REACHED();
220 return ResourceRequest::TargetIsSubresource;
223 ResourceFetcher::ResourceFetcher(DocumentLoader* documentLoader)
225 , m_documentLoader(documentLoader)
227 , m_garbageCollectDocumentResourcesTimer(this, &ResourceFetcher::garbageCollectDocumentResourcesTimerFired)
228 , m_resourceTimingReportTimer(this, &ResourceFetcher::resourceTimingReportTimerFired)
229 , m_autoLoadImages(true)
230 , m_imagesEnabled(true)
231 , m_allowStaleResources(false)
235 ResourceFetcher::~ResourceFetcher()
237 m_documentLoader = 0;
242 // Make sure no requests still point to this ResourceFetcher
243 ASSERT(!m_requestCount);
246 Resource* ResourceFetcher::cachedResource(const KURL& resourceURL) const
248 KURL url = MemoryCache::removeFragmentIdentifierIfNeeded(resourceURL);
249 return m_documentResources.get(url).get();
252 Frame* ResourceFetcher::frame() const
254 if (m_documentLoader)
255 return m_documentLoader->frame();
256 if (m_document && m_document->import())
257 return m_document->import()->frame();
261 FetchContext& ResourceFetcher::context() const
263 if (Frame* frame = this->frame())
264 return frame->fetchContext();
265 return FetchContext::nullInstance();
268 ResourcePtr<Resource> ResourceFetcher::fetchSynchronously(FetchRequest& request)
271 request.mutableResourceRequest().setTimeoutInterval(10);
272 ResourceLoaderOptions options(request.options());
273 options.synchronousPolicy = RequestSynchronously;
274 request.setOptions(options);
275 return requestResource(Resource::Raw, request);
278 ResourcePtr<ImageResource> ResourceFetcher::fetchImage(FetchRequest& request)
280 if (Frame* f = frame()) {
281 if (f->document()->pageDismissalEventBeingDispatched() != Document::NoDismissal) {
282 KURL requestURL = request.resourceRequest().url();
283 if (requestURL.isValid() && canRequest(Resource::Image, requestURL, request.options(), request.forPreload(), request.originRestriction()))
284 PingLoader::loadImage(f, requestURL);
289 if (request.resourceRequest().url().protocolIsData())
290 preCacheDataURIImage(request);
292 request.setDefer(clientDefersImage(request.resourceRequest().url()) ? FetchRequest::DeferredByClient : FetchRequest::NoDefer);
293 return toImageResource(requestResource(Resource::Image, request));
296 void ResourceFetcher::preCacheDataURIImage(const FetchRequest& request)
298 const KURL& url = request.resourceRequest().url();
299 ASSERT(url.protocolIsData());
301 if (memoryCache()->resourceForURL(url))
304 if (Resource* resource = resourceFromDataURIRequest(request.resourceRequest(), request.options())) {
305 memoryCache()->add(resource);
306 scheduleDocumentResourcesGC();
310 ResourcePtr<FontResource> ResourceFetcher::fetchFont(FetchRequest& request)
312 return toFontResource(requestResource(Resource::Font, request));
315 ResourcePtr<ShaderResource> ResourceFetcher::fetchShader(FetchRequest& request)
317 return toShaderResource(requestResource(Resource::Shader, request));
320 ResourcePtr<RawResource> ResourceFetcher::fetchImport(FetchRequest& request)
322 return toRawResource(requestResource(Resource::ImportResource, request));
325 ResourcePtr<CSSStyleSheetResource> ResourceFetcher::fetchCSSStyleSheet(FetchRequest& request)
327 return toCSSStyleSheetResource(requestResource(Resource::CSSStyleSheet, request));
330 ResourcePtr<CSSStyleSheetResource> ResourceFetcher::fetchUserCSSStyleSheet(FetchRequest& request)
332 KURL url = MemoryCache::removeFragmentIdentifierIfNeeded(request.resourceRequest().url());
334 if (Resource* existing = memoryCache()->resourceForURL(url)) {
335 if (existing->type() == Resource::CSSStyleSheet)
336 return toCSSStyleSheetResource(existing);
337 memoryCache()->remove(existing);
340 request.setOptions(ResourceLoaderOptions(SniffContent, BufferData, AllowStoredCredentials, ClientRequestedCredentials, CheckContentSecurityPolicy, DocumentContext));
341 return toCSSStyleSheetResource(requestResource(Resource::CSSStyleSheet, request));
344 ResourcePtr<ScriptResource> ResourceFetcher::fetchScript(FetchRequest& request)
346 return toScriptResource(requestResource(Resource::Script, request));
349 ResourcePtr<XSLStyleSheetResource> ResourceFetcher::fetchXSLStyleSheet(FetchRequest& request)
351 ASSERT(RuntimeEnabledFeatures::xsltEnabled());
352 return toXSLStyleSheetResource(requestResource(Resource::XSLStyleSheet, request));
355 ResourcePtr<DocumentResource> ResourceFetcher::fetchSVGDocument(FetchRequest& request)
357 return toDocumentResource(requestResource(Resource::SVGDocument, request));
360 ResourcePtr<Resource> ResourceFetcher::fetchLinkResource(Resource::Type type, FetchRequest& request)
363 ASSERT(type == Resource::LinkPrefetch || type == Resource::LinkSubresource);
364 return requestResource(type, request);
367 ResourcePtr<RawResource> ResourceFetcher::fetchRawResource(FetchRequest& request)
369 return toRawResource(requestResource(Resource::Raw, request));
372 ResourcePtr<RawResource> ResourceFetcher::fetchMainResource(FetchRequest& request, const SubstituteData& substituteData)
374 if (substituteData.isValid())
375 preCacheSubstituteDataForMainResource(request, substituteData);
376 return toRawResource(requestResource(Resource::MainResource, request));
379 void ResourceFetcher::preCacheSubstituteDataForMainResource(const FetchRequest& request, const SubstituteData& substituteData)
381 const KURL& url = request.url();
382 if (Resource* oldResource = memoryCache()->resourceForURL(url))
383 memoryCache()->remove(oldResource);
385 ResourceResponse response(url, substituteData.mimeType(), substituteData.content()->size(), substituteData.textEncoding(), emptyString());
386 ResourcePtr<Resource> resource = createResource(Resource::MainResource, request.resourceRequest(), substituteData.textEncoding());
387 resource->setNeedsSynchronousCacheHit(substituteData.forceSynchronousLoad());
388 resource->setOptions(request.options());
389 resource->setDataBufferingPolicy(BufferData);
390 resource->responseReceived(response);
391 if (substituteData.content()->size())
392 resource->setResourceBuffer(substituteData.content());
394 memoryCache()->add(resource.get());
397 bool ResourceFetcher::checkInsecureContent(Resource::Type type, const KURL& url, MixedContentBlockingTreatment treatment) const
399 if (treatment == TreatAsDefaultForType) {
401 case Resource::XSLStyleSheet:
402 ASSERT(RuntimeEnabledFeatures::xsltEnabled());
403 case Resource::Script:
404 case Resource::SVGDocument:
405 case Resource::CSSStyleSheet:
406 case Resource::ImportResource:
407 // These resource can inject script into the current document (Script,
408 // XSL) or exfiltrate the content of the current document (CSS).
409 treatment = TreatAsActiveContent;
412 case Resource::TextTrack:
413 case Resource::Shader:
415 case Resource::Image:
417 // These resources can corrupt only the frame's pixels.
418 treatment = TreatAsPassiveContent;
421 case Resource::MainResource:
422 case Resource::LinkPrefetch:
423 case Resource::LinkSubresource:
424 // These cannot affect the current document.
425 treatment = TreatAsAlwaysAllowedContent;
429 if (treatment == TreatAsActiveContent) {
430 if (Frame* f = frame()) {
431 if (!f->loader().mixedContentChecker()->canRunInsecureContent(m_document->securityOrigin(), url))
433 Frame* top = f->tree().top();
434 if (top != f && !top->loader().mixedContentChecker()->canRunInsecureContent(top->document()->securityOrigin(), url))
437 } else if (treatment == TreatAsPassiveContent) {
438 if (Frame* f = frame()) {
439 Frame* top = f->tree().top();
440 if (!top->loader().mixedContentChecker()->canDisplayInsecureContent(top->document()->securityOrigin(), url))
444 ASSERT(treatment == TreatAsAlwaysAllowedContent);
449 bool ResourceFetcher::canRequest(Resource::Type type, const KURL& url, const ResourceLoaderOptions& options, bool forPreload, FetchRequest::OriginRestriction originRestriction) const
451 SecurityOrigin* securityOrigin = options.securityOrigin.get();
452 if (!securityOrigin && document())
453 securityOrigin = document()->securityOrigin();
455 if (securityOrigin && !securityOrigin->canDisplay(url)) {
457 context().reportLocalLoadFailed(url);
458 WTF_LOG(ResourceLoading, "ResourceFetcher::requestResource URL was not allowed by SecurityOrigin::canDisplay");
462 // FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved.
463 bool shouldBypassMainWorldContentSecurityPolicy = (frame() && frame()->script().shouldBypassMainWorldContentSecurityPolicy()) || (options.contentSecurityPolicyOption == DoNotCheckContentSecurityPolicy);
465 // Some types of resources can be loaded only from the same origin. Other
466 // types of resources, like Images, Scripts, and CSS, can be loaded from
469 case Resource::MainResource:
470 case Resource::Image:
471 case Resource::CSSStyleSheet:
472 case Resource::Script:
475 case Resource::LinkPrefetch:
476 case Resource::LinkSubresource:
477 case Resource::TextTrack:
478 case Resource::Shader:
479 case Resource::ImportResource:
480 // By default these types of resources can be loaded from any origin.
481 // FIXME: Are we sure about Resource::Font?
482 if (originRestriction == FetchRequest::RestrictToSameOrigin && !securityOrigin->canRequest(url)) {
483 printAccessDeniedMessage(url);
487 case Resource::XSLStyleSheet:
488 ASSERT(RuntimeEnabledFeatures::xsltEnabled());
489 case Resource::SVGDocument:
490 if (!securityOrigin->canRequest(url)) {
491 printAccessDeniedMessage(url);
498 case Resource::XSLStyleSheet:
499 ASSERT(RuntimeEnabledFeatures::xsltEnabled());
500 if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowScriptFromSource(url))
503 case Resource::Script:
504 case Resource::ImportResource:
505 if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowScriptFromSource(url))
509 Settings* settings = frame()->settings();
510 if (!frame()->loader().client()->allowScriptFromSource(!settings || settings->scriptEnabled(), url)) {
511 frame()->loader().client()->didNotAllowScript();
516 case Resource::Shader:
517 // Since shaders are referenced from CSS Styles use the same rules here.
518 case Resource::CSSStyleSheet:
519 if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowStyleFromSource(url))
522 case Resource::SVGDocument:
523 case Resource::Image:
524 if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowImageFromSource(url))
527 case Resource::Font: {
528 if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowFontFromSource(url))
532 case Resource::MainResource:
534 case Resource::LinkPrefetch:
535 case Resource::LinkSubresource:
537 case Resource::TextTrack:
538 if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowMediaFromSource(url))
543 // Last of all, check for insecure content. We do this last so that when
544 // folks block insecure content with a CSP policy, they don't get a warning.
545 // They'll still get a warning in the console about CSP blocking the load.
547 // FIXME: Should we consider forPreload here?
548 if (!checkInsecureContent(type, url, options.mixedContentBlockingTreatment))
554 bool ResourceFetcher::canAccessResource(Resource* resource, SecurityOrigin* sourceOrigin, const KURL& url) const
556 // Redirects can change the response URL different from one of request.
557 if (!canRequest(resource->type(), url, resource->options(), false, FetchRequest::UseDefaultOriginRestrictionForType))
560 if (!sourceOrigin && document())
561 sourceOrigin = document()->securityOrigin();
563 if (sourceOrigin->canRequest(url))
566 String errorDescription;
567 if (!resource->passesAccessControlCheck(sourceOrigin, errorDescription)) {
568 if (frame() && frame()->document()) {
569 String resourceType = Resource::resourceTypeToString(resource->type(), resource->options().initiatorInfo);
570 frame()->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, resourceType + " from origin '" + SecurityOrigin::create(url)->toString() + "' has been blocked from loading by Cross-Origin Resource Sharing policy: " + errorDescription);
577 bool ResourceFetcher::shouldLoadNewResource(Resource::Type type) const
581 if (!m_documentLoader)
583 if (type == Resource::MainResource)
584 return m_documentLoader == frame()->loader().provisionalDocumentLoader();
585 return m_documentLoader == frame()->loader().documentLoader();
588 bool ResourceFetcher::resourceNeedsLoad(Resource* resource, const FetchRequest& request, RevalidationPolicy policy)
590 if (FetchRequest::DeferredByClient == request.defer())
594 if (resource->stillNeedsLoad())
596 return request.options().synchronousPolicy == RequestSynchronously && resource->isLoading();
599 ResourcePtr<Resource> ResourceFetcher::requestResource(Resource::Type type, FetchRequest& request)
601 ASSERT(request.options().synchronousPolicy == RequestAsynchronously || type == Resource::Raw);
603 KURL url = request.resourceRequest().url();
605 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));
607 // If only the fragment identifiers differ, it is the same resource.
608 url = MemoryCache::removeFragmentIdentifierIfNeeded(url);
613 if (!canRequest(type, url, request.options(), request.forPreload(), request.originRestriction()))
616 if (Frame* f = frame())
617 f->loader().client()->dispatchWillRequestResource(&request);
619 // See if we can use an existing resource from the cache.
620 ResourcePtr<Resource> resource = memoryCache()->resourceForURL(url);
622 const RevalidationPolicy policy = determineRevalidationPolicy(type, request.mutableResourceRequest(), request.forPreload(), resource.get(), request.defer(), request.options());
625 memoryCache()->remove(resource.get());
628 resource = loadResource(type, request, request.charset());
631 resource = revalidateResource(request, resource.get());
634 resource->updateForAccess();
635 notifyLoadedFromMemoryCache(resource.get());
642 if (!resource->hasClients())
643 m_deadStatsRecorder.update(policy);
646 resource->setIdentifier(createUniqueIdentifier());
648 if (!request.forPreload() || policy != Use) {
649 ResourceLoadPriority priority = loadPriority(type, request);
650 if (priority != resource->resourceRequest().priority()) {
651 resource->resourceRequest().setPriority(priority);
652 resource->didChangePriority(priority);
656 if (resourceNeedsLoad(resource.get(), request, policy)) {
657 if (!shouldLoadNewResource(type)) {
658 if (resource->inCache())
659 memoryCache()->remove(resource.get());
663 if (!m_documentLoader || !m_documentLoader->scheduleArchiveLoad(resource.get(), request.resourceRequest()))
664 resource->load(this, request.options());
666 // For asynchronous loads that immediately fail, it's sufficient to return a
667 // null Resource, as it indicates that something prevented the load from starting.
668 // If there's a network error, that failure will happen asynchronously. However, if
669 // a sync load receives a network error, it will have already happened by this point.
670 // In that case, the requester should have access to the relevant ResourceError, so
671 // we need to return a non-null Resource.
672 if (resource->errorOccurred()) {
673 if (resource->inCache())
674 memoryCache()->remove(resource.get());
675 return request.options().synchronousPolicy == RequestSynchronously ? resource : 0;
679 // FIXME: Temporarily leave main resource caching disabled for chromium,
680 // see https://bugs.webkit.org/show_bug.cgi?id=107962. Before caching main
681 // resources, we should be sure to understand the implications for memory
684 // Ensure main resources aren't preloaded, and other main resource loads
685 // are removed from cache to prevent reuse.
686 if (type == Resource::MainResource) {
687 ASSERT(policy != Use || m_documentLoader->substituteData().isValid());
688 ASSERT(policy != Revalidate);
689 memoryCache()->remove(resource.get());
690 if (request.forPreload())
694 if (!request.resourceRequest().url().protocolIsData() && (!m_documentLoader || !m_documentLoader->substituteData().isValid())) {
695 if (policy == Use && !m_validatedURLs.contains(request.resourceRequest().url())) {
696 // Resources loaded from memory cache should be reported the first time they're used.
697 RefPtr<ResourceTimingInfo> info = ResourceTimingInfo::create(request.options().initiatorInfo.name, monotonicallyIncreasingTime());
698 populateResourceTiming(info.get(), resource.get(), true);
699 m_scheduledResourceTimingReports.add(info, resource->type() == Resource::MainResource);
700 if (!m_resourceTimingReportTimer.isActive())
701 m_resourceTimingReportTimer.startOneShot(0);
704 m_validatedURLs.add(request.resourceRequest().url());
707 ASSERT(resource->url() == url.string());
708 m_documentResources.set(resource->url(), resource);
712 void ResourceFetcher::resourceTimingReportTimerFired(Timer<ResourceFetcher>* timer)
714 ASSERT_UNUSED(timer, timer == &m_resourceTimingReportTimer);
715 HashMap<RefPtr<ResourceTimingInfo>, bool> timingReports;
716 timingReports.swap(m_scheduledResourceTimingReports);
717 HashMap<RefPtr<ResourceTimingInfo>, bool>::iterator end = timingReports.end();
718 for (HashMap<RefPtr<ResourceTimingInfo>, bool>::iterator it = timingReports.begin(); it != end; ++it) {
719 RefPtr<ResourceTimingInfo> info = it->key;
720 bool isMainResource = it->value;
721 reportResourceTiming(info.get(), document(), isMainResource);
725 void ResourceFetcher::determineTargetType(ResourceRequest& request, Resource::Type type)
727 ResourceRequest::TargetType targetType = requestTargetType(this, request, type);
728 request.setTargetType(targetType);
731 ResourceRequestCachePolicy ResourceFetcher::resourceRequestCachePolicy(const ResourceRequest& request, Resource::Type type)
733 if (type == Resource::MainResource) {
734 FrameLoadType frameLoadType = frame()->loader().loadType();
735 bool isReload = frameLoadType == FrameLoadTypeReload || frameLoadType == FrameLoadTypeReloadFromOrigin;
736 if (request.httpMethod() == "POST" && frameLoadType == FrameLoadTypeBackForward)
737 return ReturnCacheDataDontLoad;
738 if (!m_documentLoader->overrideEncoding().isEmpty() || frameLoadType == FrameLoadTypeBackForward)
739 return ReturnCacheDataElseLoad;
740 if (isReload || frameLoadType == FrameLoadTypeSame || request.isConditional() || request.httpMethod() == "POST")
741 return ReloadIgnoringCacheData;
742 if (Frame* parent = frame()->tree().parent())
743 return parent->document()->fetcher()->resourceRequestCachePolicy(request, type);
744 return UseProtocolCachePolicy;
747 if (request.isConditional())
748 return ReloadIgnoringCacheData;
750 if (m_documentLoader && m_documentLoader->isLoadingInAPISense()) {
751 // For POST requests, we mutate the main resource's cache policy to avoid form resubmission.
752 // This policy should not be inherited by subresources.
753 ResourceRequestCachePolicy mainResourceCachePolicy = m_documentLoader->request().cachePolicy();
754 if (mainResourceCachePolicy == ReturnCacheDataDontLoad)
755 return ReturnCacheDataElseLoad;
756 return mainResourceCachePolicy;
758 return UseProtocolCachePolicy;
761 void ResourceFetcher::addAdditionalRequestHeaders(ResourceRequest& request, Resource::Type type)
766 if (request.cachePolicy() == UseProtocolCachePolicy)
767 request.setCachePolicy(resourceRequestCachePolicy(request, type));
768 if (request.targetType() == ResourceRequest::TargetIsUnspecified)
769 determineTargetType(request, type);
770 if (type == Resource::LinkPrefetch || type == Resource::LinkSubresource)
771 request.setHTTPHeaderField("Purpose", "prefetch");
773 context().addAdditionalRequestHeaders(document(), request, (type == Resource::MainResource) ? FetchMainResource : FetchSubresource);
776 ResourcePtr<Resource> ResourceFetcher::revalidateResource(const FetchRequest& request, Resource* resource)
779 ASSERT(resource->inCache());
780 ASSERT(resource->isLoaded());
781 ASSERT(resource->canUseCacheValidator());
782 ASSERT(!resource->resourceToRevalidate());
784 ResourceRequest revalidatingRequest(resource->resourceRequest());
785 addAdditionalRequestHeaders(revalidatingRequest, resource->type());
787 const AtomicString& lastModified = resource->response().httpHeaderField("Last-Modified");
788 const AtomicString& eTag = resource->response().httpHeaderField("ETag");
789 if (!lastModified.isEmpty() || !eTag.isEmpty()) {
790 ASSERT(context().cachePolicy(document()) != CachePolicyReload);
791 if (context().cachePolicy(document()) == CachePolicyRevalidate)
792 revalidatingRequest.setHTTPHeaderField("Cache-Control", "max-age=0");
793 if (!lastModified.isEmpty())
794 revalidatingRequest.setHTTPHeaderField("If-Modified-Since", lastModified);
796 revalidatingRequest.setHTTPHeaderField("If-None-Match", eTag);
799 ResourcePtr<Resource> newResource = createResource(resource->type(), revalidatingRequest, resource->encoding());
801 WTF_LOG(ResourceLoading, "Resource %p created to revalidate %p", newResource.get(), resource);
802 newResource->setResourceToRevalidate(resource);
804 memoryCache()->remove(resource);
805 memoryCache()->add(newResource.get());
806 storeResourceTimingInitiatorInformation(newResource, request);
807 TRACE_EVENT_ASYNC_BEGIN2("net", "Resource", newResource.get(), "url", newResource->url().string().ascii(), "priority", newResource->resourceRequest().priority());
811 ResourcePtr<Resource> ResourceFetcher::loadResource(Resource::Type type, FetchRequest& request, const String& charset)
813 ASSERT(!memoryCache()->resourceForURL(request.resourceRequest().url()));
815 WTF_LOG(ResourceLoading, "Loading Resource for '%s'.", request.resourceRequest().url().elidedString().latin1().data());
817 addAdditionalRequestHeaders(request.mutableResourceRequest(), type);
818 ResourcePtr<Resource> resource = createResource(type, request.mutableResourceRequest(), charset);
820 memoryCache()->add(resource.get());
821 storeResourceTimingInitiatorInformation(resource, request);
822 TRACE_EVENT_ASYNC_BEGIN2("net", "Resource", resource.get(), "url", resource->url().string().ascii(), "priority", resource->resourceRequest().priority());
826 void ResourceFetcher::storeResourceTimingInitiatorInformation(const ResourcePtr<Resource>& resource, const FetchRequest& request)
828 if (request.options().requestInitiatorContext != DocumentContext)
831 RefPtr<ResourceTimingInfo> info = ResourceTimingInfo::create(request.options().initiatorInfo.name, monotonicallyIncreasingTime());
833 if (resource->type() == Resource::MainResource) {
834 // <iframe>s should report the initial navigation requested by the parent document, but not subsequent navigations.
835 if (frame()->ownerElement() && !frame()->ownerElement()->loadedNonEmptyDocument()) {
836 info->setInitiatorType(frame()->ownerElement()->localName());
837 m_resourceTimingInfoMap.add(resource.get(), info);
838 frame()->ownerElement()->didLoadNonEmptyDocument();
841 m_resourceTimingInfoMap.add(resource.get(), info);
845 ResourceFetcher::RevalidationPolicy ResourceFetcher::determineRevalidationPolicy(Resource::Type type, ResourceRequest& request, bool forPreload, Resource* existingResource, FetchRequest::DeferOption defer, const ResourceLoaderOptions& options) const
847 if (!existingResource)
850 // We already have a preload going for this URL.
851 if (forPreload && existingResource->isPreloaded())
854 // If the same URL has been loaded as a different type, we need to reload.
855 if (existingResource->type() != type) {
856 WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to type mismatch.");
860 // Do not load from cache if images are not enabled. The load for this image will be blocked
861 // in ImageResource::load.
862 if (FetchRequest::DeferredByClient == defer)
865 // Always use data uris.
866 // FIXME: Extend this to non-images.
867 if (type == Resource::Image && request.url().protocolIsData())
870 // If a main resource was populated from a SubstituteData load, use it.
871 if (type == Resource::MainResource && m_documentLoader->substituteData().isValid())
874 if (!existingResource->canReuse(request))
877 // Never use cache entries for downloadToFile requests. The caller expects the resource in a file.
878 if (request.downloadToFile())
881 // Certain requests (e.g., XHRs) might have manually set headers that require revalidation.
882 // FIXME: In theory, this should be a Revalidate case. In practice, the MemoryCache revalidation path assumes a whole bunch
883 // of things about how revalidation works that manual headers violate, so punt to Reload instead.
884 if (request.isConditional())
887 // Don't reload resources while pasting.
888 if (m_allowStaleResources)
891 // Always use preloads.
892 if (existingResource->isPreloaded())
895 // CachePolicyHistoryBuffer uses the cache no matter what.
896 CachePolicy cachePolicy = context().cachePolicy(document());
897 if (cachePolicy == CachePolicyHistoryBuffer)
900 // Don't reuse resources with Cache-control: no-store.
901 if (existingResource->response().cacheControlContainsNoStore()) {
902 WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to Cache-control: no-store.");
906 // If fetching a resource with a different 'CORS enabled' flag, reload.
907 if (type != Resource::MainResource && options.corsEnabled != existingResource->options().corsEnabled)
910 // If credentials were sent with the previous request and won't be
911 // with this one, or vice versa, re-fetch the resource.
913 // This helps with the case where the server sends back
914 // "Access-Control-Allow-Origin: *" all the time, but some of the
915 // client's requests are made without CORS and some with.
916 if (existingResource->resourceRequest().allowCookies() != request.allowCookies()) {
917 WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to difference in credentials settings.");
921 // During the initial load, avoid loading the same resource multiple times for a single document,
922 // even if the cache policies would tell us to. Raw resources are exempted.
923 if (type != Resource::Raw && document() && !document()->loadEventFinished() && m_validatedURLs.contains(existingResource->url()))
926 // CachePolicyReload always reloads
927 if (cachePolicy == CachePolicyReload) {
928 WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to CachePolicyReload.");
932 // We'll try to reload the resource if it failed last time.
933 if (existingResource->errorOccurred()) {
934 WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicye reloading due to resource being in the error state");
938 // For resources that are not yet loaded we ignore the cache policy.
939 if (existingResource->isLoading())
942 // If any of the redirects in the chain to loading the resource were not cacheable, we cannot reuse our cached resource.
943 if (!existingResource->canReuseRedirectChain()) {
944 WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to an uncacheable redirect");
948 // Check if the cache headers requires us to revalidate (cache expiration for example).
949 if (cachePolicy == CachePolicyRevalidate || existingResource->mustRevalidateDueToCacheHeaders()) {
950 // See if the resource has usable ETag or Last-modified headers.
951 if (existingResource->canUseCacheValidator())
955 WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to missing cache validators.");
962 void ResourceFetcher::printAccessDeniedMessage(const KURL& url) const
971 if (!m_document || m_document->url().isNull())
972 message = "Unsafe attempt to load URL " + url.elidedString() + '.';
974 message = "Unsafe attempt to load URL " + url.elidedString() + " from frame with URL " + m_document->url().elidedString() + ". Domains, protocols and ports must match.\n";
976 frame()->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message);
979 void ResourceFetcher::setAutoLoadImages(bool enable)
981 if (enable == m_autoLoadImages)
984 m_autoLoadImages = enable;
986 if (!m_autoLoadImages)
989 reloadImagesIfNotDeferred();
992 void ResourceFetcher::setImagesEnabled(bool enable)
994 if (enable == m_imagesEnabled)
997 m_imagesEnabled = enable;
999 if (!m_imagesEnabled)
1002 reloadImagesIfNotDeferred();
1005 bool ResourceFetcher::clientDefersImage(const KURL& url) const
1007 return frame() && !frame()->loader().client()->allowImage(m_imagesEnabled, url);
1010 bool ResourceFetcher::shouldDeferImageLoad(const KURL& url) const
1012 return clientDefersImage(url) || !m_autoLoadImages;
1015 void ResourceFetcher::reloadImagesIfNotDeferred()
1017 DocumentResourceMap::iterator end = m_documentResources.end();
1018 for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != end; ++it) {
1019 Resource* resource = it->value.get();
1020 if (resource->type() == Resource::Image && resource->stillNeedsLoad() && !clientDefersImage(resource->url()))
1021 const_cast<Resource*>(resource)->load(this, defaultResourceOptions());
1025 void ResourceFetcher::redirectReceived(Resource* resource, const ResourceResponse& redirectResponse)
1027 ResourceTimingInfoMap::iterator it = m_resourceTimingInfoMap.find(resource);
1028 if (it != m_resourceTimingInfoMap.end())
1029 it->value->addRedirect(redirectResponse);
1032 void ResourceFetcher::didLoadResource(Resource* resource)
1034 RefPtr<DocumentLoader> protectDocumentLoader(m_documentLoader);
1035 RefPtr<Document> protectDocument(m_document);
1037 if (resource && resource->response().isHTTP() && ((!resource->errorOccurred() && !resource->wasCanceled()) || resource->response().httpStatusCode() == 304) && document()) {
1038 ResourceTimingInfoMap::iterator it = m_resourceTimingInfoMap.find(resource);
1039 if (it != m_resourceTimingInfoMap.end()) {
1040 RefPtr<ResourceTimingInfo> info = it->value;
1041 m_resourceTimingInfoMap.remove(it);
1042 populateResourceTiming(info.get(), resource, false);
1043 reportResourceTiming(info.get(), document(), resource->type() == Resource::MainResource);
1048 frame()->loader().loadDone();
1049 scheduleDocumentResourcesGC();
1052 void ResourceFetcher::scheduleDocumentResourcesGC()
1054 if (!m_garbageCollectDocumentResourcesTimer.isActive())
1055 m_garbageCollectDocumentResourcesTimer.startOneShot(0);
1058 // Garbage collecting m_documentResources is a workaround for the
1059 // ResourcePtrs on the RHS being strong references. Ideally this
1060 // would be a weak map, however ResourcePtrs perform additional
1061 // bookkeeping on Resources, so instead pseudo-GC them -- when the
1062 // reference count reaches 1, m_documentResources is the only reference, so
1063 // remove it from the map.
1064 void ResourceFetcher::garbageCollectDocumentResourcesTimerFired(Timer<ResourceFetcher>* timer)
1066 ASSERT_UNUSED(timer, timer == &m_garbageCollectDocumentResourcesTimer);
1067 garbageCollectDocumentResources();
1070 void ResourceFetcher::garbageCollectDocumentResources()
1072 typedef Vector<String, 10> StringVector;
1073 StringVector resourcesToDelete;
1075 for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != m_documentResources.end(); ++it) {
1076 if (it->value->hasOneHandle())
1077 resourcesToDelete.append(it->key);
1080 for (StringVector::const_iterator it = resourcesToDelete.begin(); it != resourcesToDelete.end(); ++it)
1081 m_documentResources.remove(*it);
1084 void ResourceFetcher::notifyLoadedFromMemoryCache(Resource* resource)
1086 if (!frame() || !frame()->page() || resource->status() != Resource::Cached || m_validatedURLs.contains(resource->url()))
1089 ResourceRequest request(resource->url());
1090 unsigned long identifier = createUniqueIdentifier();
1091 context().dispatchDidLoadResourceFromMemoryCache(request, resource->response());
1092 // FIXME: If willSendRequest changes the request, we don't respect it.
1093 willSendRequest(identifier, request, ResourceResponse(), resource->options().initiatorInfo);
1094 InspectorInstrumentation::markResourceAsCached(frame()->page(), identifier);
1095 context().sendRemainingDelegateMessages(m_documentLoader, identifier, resource->response(), resource->encodedSize());
1098 void ResourceFetcher::incrementRequestCount(const Resource* res)
1100 if (res->ignoreForRequestCount())
1106 void ResourceFetcher::decrementRequestCount(const Resource* res)
1108 if (res->ignoreForRequestCount())
1112 ASSERT(m_requestCount > -1);
1115 void ResourceFetcher::preload(Resource::Type type, FetchRequest& request, const String& charset)
1117 requestPreload(type, request, charset);
1120 void ResourceFetcher::requestPreload(Resource::Type type, FetchRequest& request, const String& charset)
1123 if (type == Resource::Script || type == Resource::CSSStyleSheet)
1124 encoding = charset.isEmpty() ? m_document->charset().string() : charset;
1126 request.setCharset(encoding);
1127 request.setForPreload(true);
1129 ResourcePtr<Resource> resource = requestResource(type, request);
1130 if (!resource || (m_preloads && m_preloads->contains(resource.get())))
1132 TRACE_EVENT_ASYNC_STEP_INTO0("net", "Resource", resource.get(), "Preload");
1133 resource->increasePreloadCount();
1136 m_preloads = adoptPtr(new ListHashSet<Resource*>);
1137 m_preloads->add(resource.get());
1140 printf("PRELOADING %s\n", resource->url().string().latin1().data());
1144 bool ResourceFetcher::isPreloaded(const String& urlString) const
1146 const KURL& url = m_document->completeURL(urlString);
1149 ListHashSet<Resource*>::iterator end = m_preloads->end();
1150 for (ListHashSet<Resource*>::iterator it = m_preloads->begin(); it != end; ++it) {
1151 Resource* resource = *it;
1152 if (resource->url() == url)
1160 void ResourceFetcher::clearPreloads()
1163 printPreloadStats();
1168 ListHashSet<Resource*>::iterator end = m_preloads->end();
1169 for (ListHashSet<Resource*>::iterator it = m_preloads->begin(); it != end; ++it) {
1170 Resource* res = *it;
1171 res->decreasePreloadCount();
1172 bool deleted = res->deleteIfPossible();
1173 if (!deleted && res->preloadResult() == Resource::PreloadNotReferenced)
1174 memoryCache()->remove(res);
1179 void ResourceFetcher::didFinishLoading(const Resource* resource, double finishTime, int64_t encodedDataLength)
1181 TRACE_EVENT_ASYNC_END0("net", "Resource", resource);
1182 context().dispatchDidFinishLoading(m_documentLoader, resource->identifier(), finishTime, encodedDataLength);
1185 void ResourceFetcher::didChangeLoadingPriority(const Resource* resource, ResourceLoadPriority loadPriority)
1187 TRACE_EVENT_ASYNC_STEP_INTO1("net", "Resource", resource, "ChangePriority", "priority", loadPriority);
1188 context().dispatchDidChangeResourcePriority(resource->identifier(), loadPriority);
1191 void ResourceFetcher::didFailLoading(const Resource* resource, const ResourceError& error)
1193 TRACE_EVENT_ASYNC_END0("net", "Resource", resource);
1194 context().dispatchDidFail(m_documentLoader, resource->identifier(), error);
1197 void ResourceFetcher::willSendRequest(unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse, const FetchInitiatorInfo& initiatorInfo)
1199 context().dispatchWillSendRequest(m_documentLoader, identifier, request, redirectResponse, initiatorInfo);
1202 void ResourceFetcher::didReceiveResponse(const Resource* resource, const ResourceResponse& response)
1204 context().dispatchDidReceiveResponse(m_documentLoader, resource->identifier(), response, resource->loader());
1207 void ResourceFetcher::didReceiveData(const Resource* resource, const char* data, int dataLength, int encodedDataLength)
1209 // FIXME: use frame of master document for imported documents.
1210 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willReceiveResourceData(frame(), resource->identifier(), encodedDataLength);
1211 context().dispatchDidReceiveData(m_documentLoader, resource->identifier(), data, dataLength, encodedDataLength);
1212 InspectorInstrumentation::didReceiveResourceData(cookie);
1215 void ResourceFetcher::didDownloadData(const Resource* resource, int dataLength, int encodedDataLength)
1217 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willReceiveResourceData(frame(), resource->identifier(), encodedDataLength);
1218 context().dispatchDidDownloadData(m_documentLoader, resource->identifier(), dataLength, encodedDataLength);
1219 InspectorInstrumentation::didReceiveResourceData(cookie);
1222 void ResourceFetcher::subresourceLoaderFinishedLoadingOnePart(ResourceLoader* loader)
1224 if (m_multipartLoaders)
1225 m_multipartLoaders->add(loader);
1227 m_loaders->remove(loader);
1228 if (Frame* frame = this->frame())
1229 return frame->loader().checkLoadComplete(m_documentLoader);
1232 void ResourceFetcher::didInitializeResourceLoader(ResourceLoader* loader)
1237 m_loaders = adoptPtr(new ResourceLoaderSet());
1238 ASSERT(!m_loaders->contains(loader));
1239 m_loaders->add(loader);
1242 void ResourceFetcher::willTerminateResourceLoader(ResourceLoader* loader)
1244 if (!m_loaders || !m_loaders->contains(loader))
1246 m_loaders->remove(loader);
1247 if (Frame* frame = this->frame())
1248 frame->loader().checkLoadComplete(m_documentLoader);
1251 void ResourceFetcher::willStartLoadingResource(ResourceRequest& request)
1253 if (m_documentLoader)
1254 m_documentLoader->applicationCacheHost()->willStartLoadingResource(request);
1257 void ResourceFetcher::stopFetching()
1259 if (m_multipartLoaders)
1260 m_multipartLoaders->cancelAll();
1262 m_loaders->cancelAll();
1265 bool ResourceFetcher::isFetching() const
1267 return m_loaders && !m_loaders->isEmpty();
1270 void ResourceFetcher::setDefersLoading(bool defers)
1273 m_loaders->setAllDefersLoading(defers);
1276 bool ResourceFetcher::defersLoading() const
1278 if (Frame* frame = this->frame())
1279 return frame->page()->defersLoading();
1283 bool ResourceFetcher::isLoadedBy(ResourceLoaderHost* possibleOwner) const
1285 return this == possibleOwner;
1288 bool ResourceFetcher::canAccessRedirect(Resource* resource, ResourceRequest& request, const ResourceResponse& redirectResponse, ResourceLoaderOptions& options)
1290 if (!canRequest(resource->type(), request.url(), options, false, FetchRequest::UseDefaultOriginRestrictionForType))
1292 if (options.corsEnabled == IsCORSEnabled) {
1293 SecurityOrigin* sourceOrigin = options.securityOrigin.get();
1294 if (!sourceOrigin && document())
1295 sourceOrigin = document()->securityOrigin();
1297 String errorMessage;
1298 if (!CrossOriginAccessControl::handleRedirect(resource, sourceOrigin, request, redirectResponse, options, errorMessage)) {
1299 if (frame() && frame()->document())
1300 frame()->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, errorMessage);
1304 if (resource->type() == Resource::Image && shouldDeferImageLoad(request.url()))
1309 void ResourceFetcher::refResourceLoaderHost()
1314 void ResourceFetcher::derefResourceLoaderHost()
1320 void ResourceFetcher::printPreloadStats()
1325 unsigned scripts = 0;
1326 unsigned scriptMisses = 0;
1327 unsigned stylesheets = 0;
1328 unsigned stylesheetMisses = 0;
1329 unsigned images = 0;
1330 unsigned imageMisses = 0;
1331 ListHashSet<Resource*>::iterator end = m_preloads->end();
1332 for (ListHashSet<Resource*>::iterator it = m_preloads->begin(); it != end; ++it) {
1333 Resource* res = *it;
1334 if (res->preloadResult() == Resource::PreloadNotReferenced)
1335 printf("!! UNREFERENCED PRELOAD %s\n", res->url().string().latin1().data());
1336 else if (res->preloadResult() == Resource::PreloadReferencedWhileComplete)
1337 printf("HIT COMPLETE PRELOAD %s\n", res->url().string().latin1().data());
1338 else if (res->preloadResult() == Resource::PreloadReferencedWhileLoading)
1339 printf("HIT LOADING PRELOAD %s\n", res->url().string().latin1().data());
1341 if (res->type() == Resource::Script) {
1343 if (res->preloadResult() < Resource::PreloadReferencedWhileLoading)
1345 } else if (res->type() == Resource::CSSStyleSheet) {
1347 if (res->preloadResult() < Resource::PreloadReferencedWhileLoading)
1351 if (res->preloadResult() < Resource::PreloadReferencedWhileLoading)
1355 if (res->errorOccurred())
1356 memoryCache()->remove(res);
1358 res->decreasePreloadCount();
1363 printf("SCRIPTS: %d (%d hits, hit rate %d%%)\n", scripts, scripts - scriptMisses, (scripts - scriptMisses) * 100 / scripts);
1365 printf("STYLESHEETS: %d (%d hits, hit rate %d%%)\n", stylesheets, stylesheets - stylesheetMisses, (stylesheets - stylesheetMisses) * 100 / stylesheets);
1367 printf("IMAGES: %d (%d hits, hit rate %d%%)\n", images, images - imageMisses, (images - imageMisses) * 100 / images);
1371 const ResourceLoaderOptions& ResourceFetcher::defaultResourceOptions()
1373 DEFINE_STATIC_LOCAL(ResourceLoaderOptions, options, (SniffContent, BufferData, AllowStoredCredentials, ClientRequestedCredentials, CheckContentSecurityPolicy, DocumentContext));
1377 ResourceFetcher::DeadResourceStatsRecorder::DeadResourceStatsRecorder()
1379 , m_revalidateCount(0)
1384 ResourceFetcher::DeadResourceStatsRecorder::~DeadResourceStatsRecorder()
1386 blink::Platform::current()->histogramCustomCounts(
1387 "WebCore.ResourceFetcher.HitCount", m_useCount, 0, 1000, 50);
1388 blink::Platform::current()->histogramCustomCounts(
1389 "WebCore.ResourceFetcher.RevalidateCount", m_revalidateCount, 0, 1000, 50);
1390 blink::Platform::current()->histogramCustomCounts(
1391 "WebCore.ResourceFetcher.LoadCount", m_loadCount, 0, 1000, 50);
1394 void ResourceFetcher::DeadResourceStatsRecorder::update(RevalidationPolicy policy)
1402 ++m_revalidateCount;