Upstream version 7.35.139.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / fetch / ResourceFetcher.cpp
1 /*
2     Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
3     Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
4     Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
5     Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
6     Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
7
8     This library is free software; you can redistribute it and/or
9     modify it under the terms of the GNU Library General Public
10     License as published by the Free Software Foundation; either
11     version 2 of the License, or (at your option) any later version.
12
13     This library is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16     Library General Public License for more details.
17
18     You should have received a copy of the GNU Library General Public License
19     along with this library; see the file COPYING.LIB.  If not, write to
20     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21     Boston, MA 02110-1301, USA.
22
23     This class provides all functionality needed for loading images, style sheets and html
24     pages from the web. It has a memory cache for these objects.
25 */
26
27 #include "config.h"
28 #include "core/fetch/ResourceFetcher.h"
29
30 #include "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"
71
72 #define PRELOAD_DEBUG 0
73
74 namespace WebCore {
75
76 static Resource* createResource(Resource::Type type, const ResourceRequest& request, const String& charset)
77 {
78     switch (type) {
79     case Resource::Image:
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);
87     case Resource::Font:
88         return new FontResource(request);
89     case Resource::MainResource:
90     case Resource::Raw:
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);
103     }
104
105     ASSERT_NOT_REACHED();
106     return 0;
107 }
108
109 static ResourceLoadPriority loadPriority(Resource::Type type, const FetchRequest& request)
110 {
111     if (request.priority() != ResourceLoadPriorityUnresolved)
112         return request.priority();
113
114     switch (type) {
115     case Resource::MainResource:
116         return ResourceLoadPriorityVeryHigh;
117     case Resource::CSSStyleSheet:
118         return ResourceLoadPriorityHigh;
119     case Resource::Raw:
120         return request.options().synchronousPolicy == RequestSynchronously ? ResourceLoadPriorityVeryHigh : ResourceLoadPriorityMedium;
121     case Resource::Script:
122     case Resource::Font:
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;
142     }
143     ASSERT_NOT_REACHED();
144     return ResourceLoadPriorityUnresolved;
145 }
146
147 static Resource* resourceFromDataURIRequest(const ResourceRequest& request, const ResourceLoaderOptions& resourceOptions)
148 {
149     const KURL& url = request.url();
150     ASSERT(url.protocolIsData());
151
152     blink::WebString mimetype;
153     blink::WebString charset;
154     RefPtr<SharedBuffer> data = PassRefPtr<SharedBuffer>(blink::Platform::current()->parseDataURL(url, mimetype, charset));
155     if (!data)
156         return 0;
157     ResourceResponse response(url, mimetype, data->size(), charset, String());
158
159     Resource* resource = createResource(Resource::Image, request, charset);
160     resource->setOptions(resourceOptions);
161     resource->responseReceived(response);
162     if (data->size())
163         resource->setResourceBuffer(data);
164     resource->finish();
165     return resource;
166 }
167
168 static void populateResourceTiming(ResourceTimingInfo* info, Resource* resource, bool clearLoadTimings)
169 {
170     info->setInitialRequest(resource->resourceRequest());
171     info->setFinalResponse(resource->response());
172     if (clearLoadTimings) {
173         info->clearLoadTimings();
174         info->setLoadFinishTime(info->initialTime());
175     } else {
176         info->setLoadFinishTime(resource->loadFinishTime());
177     }
178 }
179
180 static void reportResourceTiming(ResourceTimingInfo* info, Document* initiatorDocument, bool isMainResource)
181 {
182     if (initiatorDocument && isMainResource)
183         initiatorDocument = initiatorDocument->parentDocument();
184     if (!initiatorDocument || !initiatorDocument->loader())
185         return;
186     if (DOMWindow* initiatorWindow = initiatorDocument->domWindow())
187         initiatorWindow->performance().addResourceTiming(*info, initiatorDocument);
188 }
189
190 static ResourceRequest::TargetType requestTargetType(const ResourceFetcher* fetcher, const ResourceRequest& request, Resource::Type type)
191 {
192     switch (type) {
193     case Resource::MainResource:
194         if (fetcher->frame()->tree().parent())
195             return ResourceRequest::TargetIsSubframe;
196         return ResourceRequest::TargetIsMainFrame;
197     case Resource::XSLStyleSheet:
198         ASSERT(RuntimeEnabledFeatures::xsltEnabled());
199     case Resource::CSSStyleSheet:
200         return ResourceRequest::TargetIsStyleSheet;
201     case Resource::Script:
202         return ResourceRequest::TargetIsScript;
203     case Resource::Font:
204         return ResourceRequest::TargetIsFont;
205     case Resource::Image:
206         return ResourceRequest::TargetIsImage;
207     case Resource::Shader:
208     case Resource::Raw:
209     case Resource::ImportResource:
210         return ResourceRequest::TargetIsSubresource;
211     case Resource::LinkPrefetch:
212         return ResourceRequest::TargetIsPrefetch;
213     case Resource::LinkSubresource:
214         return ResourceRequest::TargetIsSubresource;
215     case Resource::TextTrack:
216         return ResourceRequest::TargetIsTextTrack;
217     case Resource::SVGDocument:
218         return ResourceRequest::TargetIsImage;
219     }
220     ASSERT_NOT_REACHED();
221     return ResourceRequest::TargetIsSubresource;
222 }
223
224 ResourceFetcher::ResourceFetcher(DocumentLoader* documentLoader)
225     : m_document(0)
226     , m_documentLoader(documentLoader)
227     , m_requestCount(0)
228     , m_garbageCollectDocumentResourcesTimer(this, &ResourceFetcher::garbageCollectDocumentResourcesTimerFired)
229     , m_resourceTimingReportTimer(this, &ResourceFetcher::resourceTimingReportTimerFired)
230     , m_autoLoadImages(true)
231     , m_imagesEnabled(true)
232     , m_allowStaleResources(false)
233 {
234 }
235
236 ResourceFetcher::~ResourceFetcher()
237 {
238     m_documentLoader = 0;
239     m_document = 0;
240
241     clearPreloads();
242
243     // Make sure no requests still point to this ResourceFetcher
244     ASSERT(!m_requestCount);
245 }
246
247 Resource* ResourceFetcher::cachedResource(const KURL& resourceURL) const
248 {
249     KURL url = MemoryCache::removeFragmentIdentifierIfNeeded(resourceURL);
250     return m_documentResources.get(url).get();
251 }
252
253 LocalFrame* ResourceFetcher::frame() const
254 {
255     if (m_documentLoader)
256         return m_documentLoader->frame();
257     if (m_document && m_document->import())
258         return m_document->import()->frame();
259     return 0;
260 }
261
262 FetchContext& ResourceFetcher::context() const
263 {
264     if (LocalFrame* frame = this->frame())
265         return frame->fetchContext();
266     return FetchContext::nullInstance();
267 }
268
269 ResourcePtr<Resource> ResourceFetcher::fetchSynchronously(FetchRequest& request)
270 {
271     ASSERT(document());
272     request.mutableResourceRequest().setTimeoutInterval(10);
273     ResourceLoaderOptions options(request.options());
274     options.synchronousPolicy = RequestSynchronously;
275     request.setOptions(options);
276     return requestResource(Resource::Raw, request);
277 }
278
279 ResourcePtr<ImageResource> ResourceFetcher::fetchImage(FetchRequest& request)
280 {
281     if (LocalFrame* f = frame()) {
282         if (f->document()->pageDismissalEventBeingDispatched() != Document::NoDismissal) {
283             KURL requestURL = request.resourceRequest().url();
284             if (requestURL.isValid() && canRequest(Resource::Image, requestURL, request.options(), request.forPreload(), request.originRestriction()))
285                 PingLoader::loadImage(f, requestURL);
286             return 0;
287         }
288     }
289
290     if (request.resourceRequest().url().protocolIsData())
291         preCacheDataURIImage(request);
292
293     request.setDefer(clientDefersImage(request.resourceRequest().url()) ? FetchRequest::DeferredByClient : FetchRequest::NoDefer);
294     return toImageResource(requestResource(Resource::Image, request));
295 }
296
297 void ResourceFetcher::preCacheDataURIImage(const FetchRequest& request)
298 {
299     const KURL& url = request.resourceRequest().url();
300     ASSERT(url.protocolIsData());
301
302     if (memoryCache()->resourceForURL(url))
303         return;
304
305     if (Resource* resource = resourceFromDataURIRequest(request.resourceRequest(), request.options())) {
306         memoryCache()->add(resource);
307         scheduleDocumentResourcesGC();
308     }
309 }
310
311 ResourcePtr<FontResource> ResourceFetcher::fetchFont(FetchRequest& request)
312 {
313     return toFontResource(requestResource(Resource::Font, request));
314 }
315
316 ResourcePtr<ShaderResource> ResourceFetcher::fetchShader(FetchRequest& request)
317 {
318     return toShaderResource(requestResource(Resource::Shader, request));
319 }
320
321 ResourcePtr<RawResource> ResourceFetcher::fetchImport(FetchRequest& request)
322 {
323     return toRawResource(requestResource(Resource::ImportResource, request));
324 }
325
326 ResourcePtr<CSSStyleSheetResource> ResourceFetcher::fetchCSSStyleSheet(FetchRequest& request)
327 {
328     return toCSSStyleSheetResource(requestResource(Resource::CSSStyleSheet, request));
329 }
330
331 ResourcePtr<CSSStyleSheetResource> ResourceFetcher::fetchUserCSSStyleSheet(FetchRequest& request)
332 {
333     KURL url = MemoryCache::removeFragmentIdentifierIfNeeded(request.resourceRequest().url());
334
335     if (Resource* existing = memoryCache()->resourceForURL(url)) {
336         if (existing->type() == Resource::CSSStyleSheet)
337             return toCSSStyleSheetResource(existing);
338         memoryCache()->remove(existing);
339     }
340
341     request.setOptions(ResourceLoaderOptions(SniffContent, BufferData, AllowStoredCredentials, ClientRequestedCredentials, CheckContentSecurityPolicy, DocumentContext));
342     return toCSSStyleSheetResource(requestResource(Resource::CSSStyleSheet, request));
343 }
344
345 ResourcePtr<ScriptResource> ResourceFetcher::fetchScript(FetchRequest& request)
346 {
347     return toScriptResource(requestResource(Resource::Script, request));
348 }
349
350 ResourcePtr<XSLStyleSheetResource> ResourceFetcher::fetchXSLStyleSheet(FetchRequest& request)
351 {
352     ASSERT(RuntimeEnabledFeatures::xsltEnabled());
353     return toXSLStyleSheetResource(requestResource(Resource::XSLStyleSheet, request));
354 }
355
356 ResourcePtr<DocumentResource> ResourceFetcher::fetchSVGDocument(FetchRequest& request)
357 {
358     return toDocumentResource(requestResource(Resource::SVGDocument, request));
359 }
360
361 ResourcePtr<Resource> ResourceFetcher::fetchLinkResource(Resource::Type type, FetchRequest& request)
362 {
363     ASSERT(frame());
364     ASSERT(type == Resource::LinkPrefetch || type == Resource::LinkSubresource);
365     return requestResource(type, request);
366 }
367
368 ResourcePtr<RawResource> ResourceFetcher::fetchRawResource(FetchRequest& request)
369 {
370     return toRawResource(requestResource(Resource::Raw, request));
371 }
372
373 ResourcePtr<RawResource> ResourceFetcher::fetchMainResource(FetchRequest& request, const SubstituteData& substituteData)
374 {
375     if (substituteData.isValid())
376         preCacheSubstituteDataForMainResource(request, substituteData);
377     return toRawResource(requestResource(Resource::MainResource, request));
378 }
379
380 void ResourceFetcher::preCacheSubstituteDataForMainResource(const FetchRequest& request, const SubstituteData& substituteData)
381 {
382     const KURL& url = request.url();
383     if (Resource* oldResource = memoryCache()->resourceForURL(url))
384         memoryCache()->remove(oldResource);
385
386     ResourceResponse response(url, substituteData.mimeType(), substituteData.content()->size(), substituteData.textEncoding(), emptyString());
387     ResourcePtr<Resource> resource = createResource(Resource::MainResource, request.resourceRequest(), substituteData.textEncoding());
388     resource->setNeedsSynchronousCacheHit(substituteData.forceSynchronousLoad());
389     resource->setOptions(request.options());
390     resource->setDataBufferingPolicy(BufferData);
391     resource->responseReceived(response);
392     if (substituteData.content()->size())
393         resource->setResourceBuffer(substituteData.content());
394     resource->finish();
395     memoryCache()->add(resource.get());
396 }
397
398 bool ResourceFetcher::checkInsecureContent(Resource::Type type, const KURL& url, MixedContentBlockingTreatment treatment) const
399 {
400     if (treatment == TreatAsDefaultForType) {
401         switch (type) {
402         case Resource::XSLStyleSheet:
403             ASSERT(RuntimeEnabledFeatures::xsltEnabled());
404         case Resource::Script:
405         case Resource::SVGDocument:
406         case Resource::CSSStyleSheet:
407         case Resource::ImportResource:
408             // These resource can inject script into the current document (Script,
409             // XSL) or exfiltrate the content of the current document (CSS).
410             treatment = TreatAsActiveContent;
411             break;
412
413         case Resource::TextTrack:
414         case Resource::Shader:
415         case Resource::Raw:
416         case Resource::Image:
417         case Resource::Font:
418             // These resources can corrupt only the frame's pixels.
419             treatment = TreatAsPassiveContent;
420             break;
421
422         case Resource::MainResource:
423         case Resource::LinkPrefetch:
424         case Resource::LinkSubresource:
425             // These cannot affect the current document.
426             treatment = TreatAsAlwaysAllowedContent;
427             break;
428         }
429     }
430     if (treatment == TreatAsActiveContent) {
431         if (LocalFrame* f = frame()) {
432             if (!f->loader().mixedContentChecker()->canRunInsecureContent(m_document->securityOrigin(), url))
433                 return false;
434             LocalFrame* top = f->tree().top();
435             if (top != f && !top->loader().mixedContentChecker()->canRunInsecureContent(top->document()->securityOrigin(), url))
436                 return false;
437         }
438     } else if (treatment == TreatAsPassiveContent) {
439         if (LocalFrame* f = frame()) {
440             LocalFrame* top = f->tree().top();
441             if (!top->loader().mixedContentChecker()->canDisplayInsecureContent(top->document()->securityOrigin(), url))
442                 return false;
443         }
444     } else {
445         ASSERT(treatment == TreatAsAlwaysAllowedContent);
446     }
447     return true;
448 }
449
450 bool ResourceFetcher::canRequest(Resource::Type type, const KURL& url, const ResourceLoaderOptions& options, bool forPreload, FetchRequest::OriginRestriction originRestriction) const
451 {
452     SecurityOrigin* securityOrigin = options.securityOrigin.get();
453     if (!securityOrigin && document())
454         securityOrigin = document()->securityOrigin();
455
456     if (securityOrigin && !securityOrigin->canDisplay(url)) {
457         if (!forPreload)
458             context().reportLocalLoadFailed(url);
459         WTF_LOG(ResourceLoading, "ResourceFetcher::requestResource URL was not allowed by SecurityOrigin::canDisplay");
460         return 0;
461     }
462
463     // FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved.
464     bool shouldBypassMainWorldContentSecurityPolicy = (frame() && frame()->script().shouldBypassMainWorldContentSecurityPolicy()) || (options.contentSecurityPolicyOption == DoNotCheckContentSecurityPolicy);
465
466     // Some types of resources can be loaded only from the same origin. Other
467     // types of resources, like Images, Scripts, and CSS, can be loaded from
468     // any URL.
469     switch (type) {
470     case Resource::MainResource:
471     case Resource::Image:
472     case Resource::CSSStyleSheet:
473     case Resource::Script:
474     case Resource::Font:
475     case Resource::Raw:
476     case Resource::LinkPrefetch:
477     case Resource::LinkSubresource:
478     case Resource::TextTrack:
479     case Resource::Shader:
480     case Resource::ImportResource:
481         // By default these types of resources can be loaded from any origin.
482         // FIXME: Are we sure about Resource::Font?
483         if (originRestriction == FetchRequest::RestrictToSameOrigin && !securityOrigin->canRequest(url)) {
484             printAccessDeniedMessage(url);
485             return false;
486         }
487         break;
488     case Resource::XSLStyleSheet:
489         ASSERT(RuntimeEnabledFeatures::xsltEnabled());
490     case Resource::SVGDocument:
491         if (!securityOrigin->canRequest(url)) {
492             printAccessDeniedMessage(url);
493             return false;
494         }
495         break;
496     }
497
498     switch (type) {
499     case Resource::XSLStyleSheet:
500         ASSERT(RuntimeEnabledFeatures::xsltEnabled());
501         if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowScriptFromSource(url))
502             return false;
503         break;
504     case Resource::Script:
505     case Resource::ImportResource:
506         if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowScriptFromSource(url))
507             return false;
508
509         if (frame()) {
510             Settings* settings = frame()->settings();
511             if (!frame()->loader().client()->allowScriptFromSource(!settings || settings->scriptEnabled(), url)) {
512                 frame()->loader().client()->didNotAllowScript();
513                 return false;
514             }
515         }
516         break;
517     case Resource::Shader:
518         // Since shaders are referenced from CSS Styles use the same rules here.
519     case Resource::CSSStyleSheet:
520         if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowStyleFromSource(url))
521             return false;
522         break;
523     case Resource::SVGDocument:
524     case Resource::Image:
525         if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowImageFromSource(url))
526             return false;
527         break;
528     case Resource::Font: {
529         if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowFontFromSource(url))
530             return false;
531         break;
532     }
533     case Resource::MainResource:
534     case Resource::Raw:
535     case Resource::LinkPrefetch:
536     case Resource::LinkSubresource:
537         break;
538     case Resource::TextTrack:
539         if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowMediaFromSource(url))
540             return false;
541         break;
542     }
543
544     // Last of all, check for insecure content. We do this last so that when
545     // folks block insecure content with a CSP policy, they don't get a warning.
546     // They'll still get a warning in the console about CSP blocking the load.
547
548     // FIXME: Should we consider forPreload here?
549     if (!checkInsecureContent(type, url, options.mixedContentBlockingTreatment))
550         return false;
551
552     return true;
553 }
554
555 bool ResourceFetcher::canAccessResource(Resource* resource, SecurityOrigin* sourceOrigin, const KURL& url) const
556 {
557     // Redirects can change the response URL different from one of request.
558     if (!canRequest(resource->type(), url, resource->options(), false, FetchRequest::UseDefaultOriginRestrictionForType))
559         return false;
560
561     if (!sourceOrigin && document())
562         sourceOrigin = document()->securityOrigin();
563
564     if (sourceOrigin->canRequest(url))
565         return true;
566
567     String errorDescription;
568     if (!resource->passesAccessControlCheck(sourceOrigin, errorDescription)) {
569         if (frame() && frame()->document()) {
570             String resourceType = Resource::resourceTypeToString(resource->type(), resource->options().initiatorInfo);
571             frame()->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, resourceType + " from origin '" + SecurityOrigin::create(url)->toString() + "' has been blocked from loading by Cross-Origin Resource Sharing policy: " + errorDescription);
572         }
573         return false;
574     }
575     return true;
576 }
577
578 bool ResourceFetcher::shouldLoadNewResource(Resource::Type type) const
579 {
580     if (!frame())
581         return false;
582     if (!m_documentLoader)
583         return true;
584     if (type == Resource::MainResource)
585         return m_documentLoader == frame()->loader().provisionalDocumentLoader();
586     return m_documentLoader == frame()->loader().documentLoader();
587 }
588
589 bool ResourceFetcher::resourceNeedsLoad(Resource* resource, const FetchRequest& request, RevalidationPolicy policy)
590 {
591     if (FetchRequest::DeferredByClient == request.defer())
592         return false;
593     if (policy != Use)
594         return true;
595     if (resource->stillNeedsLoad())
596         return true;
597     return request.options().synchronousPolicy == RequestSynchronously && resource->isLoading();
598 }
599
600 ResourcePtr<Resource> ResourceFetcher::requestResource(Resource::Type type, FetchRequest& request)
601 {
602     ASSERT(request.options().synchronousPolicy == RequestAsynchronously || type == Resource::Raw);
603
604     KURL url = request.resourceRequest().url();
605
606     WTF_LOG(ResourceLoading, "ResourceFetcher::requestResource '%s', charset '%s', priority=%d, forPreload=%u, type=%s", url.elidedString().latin1().data(), request.charset().latin1().data(), request.priority(), request.forPreload(), ResourceTypeName(type));
607
608     // If only the fragment identifiers differ, it is the same resource.
609     url = MemoryCache::removeFragmentIdentifierIfNeeded(url);
610
611     if (!url.isValid())
612         return 0;
613
614     if (!canRequest(type, url, request.options(), request.forPreload(), request.originRestriction()))
615         return 0;
616
617     if (LocalFrame* f = frame())
618         f->loader().client()->dispatchWillRequestResource(&request);
619
620     // See if we can use an existing resource from the cache.
621     ResourcePtr<Resource> resource = memoryCache()->resourceForURL(url);
622
623     const RevalidationPolicy policy = determineRevalidationPolicy(type, request.mutableResourceRequest(), request.forPreload(), resource.get(), request.defer(), request.options());
624     switch (policy) {
625     case Reload:
626         memoryCache()->remove(resource.get());
627         // Fall through
628     case Load:
629         resource = loadResource(type, request, request.charset());
630         break;
631     case Revalidate:
632         resource = revalidateResource(request, resource.get());
633         break;
634     case Use:
635         memoryCache()->updateForAccess(resource.get());
636         notifyLoadedFromMemoryCache(resource.get());
637         break;
638     }
639
640     if (!resource)
641         return 0;
642
643     if (!resource->hasClients())
644         m_deadStatsRecorder.update(policy);
645
646     if (policy != Use)
647         resource->setIdentifier(createUniqueIdentifier());
648
649     if (!request.forPreload() || policy != Use) {
650         ResourceLoadPriority priority = loadPriority(type, request);
651         if (priority != resource->resourceRequest().priority()) {
652             resource->resourceRequest().setPriority(priority);
653             resource->didChangePriority(priority, 0);
654         }
655     }
656
657     if (resourceNeedsLoad(resource.get(), request, policy)) {
658         if (!shouldLoadNewResource(type)) {
659             if (memoryCache()->contains(resource.get()))
660                 memoryCache()->remove(resource.get());
661             return 0;
662         }
663
664         if (!m_documentLoader || !m_documentLoader->scheduleArchiveLoad(resource.get(), request.resourceRequest()))
665             resource->load(this, request.options());
666
667         // For asynchronous loads that immediately fail, it's sufficient to return a
668         // null Resource, as it indicates that something prevented the load from starting.
669         // If there's a network error, that failure will happen asynchronously. However, if
670         // a sync load receives a network error, it will have already happened by this point.
671         // In that case, the requester should have access to the relevant ResourceError, so
672         // we need to return a non-null Resource.
673         if (resource->errorOccurred()) {
674             if (memoryCache()->contains(resource.get()))
675                 memoryCache()->remove(resource.get());
676             return request.options().synchronousPolicy == RequestSynchronously ? resource : 0;
677         }
678     }
679
680     // FIXME: Temporarily leave main resource caching disabled for chromium,
681     // see https://bugs.webkit.org/show_bug.cgi?id=107962. Before caching main
682     // resources, we should be sure to understand the implications for memory
683     // use.
684     //
685     // Ensure main resources aren't preloaded, and other main resource loads
686     // are removed from cache to prevent reuse.
687     if (type == Resource::MainResource) {
688         ASSERT(policy != Use || m_documentLoader->substituteData().isValid());
689         ASSERT(policy != Revalidate);
690         memoryCache()->remove(resource.get());
691         if (request.forPreload())
692             return 0;
693     }
694
695     if (!request.resourceRequest().url().protocolIsData() && (!m_documentLoader || !m_documentLoader->substituteData().isValid())) {
696         if (policy == Use && !m_validatedURLs.contains(request.resourceRequest().url())) {
697             // Resources loaded from memory cache should be reported the first time they're used.
698             RefPtr<ResourceTimingInfo> info = ResourceTimingInfo::create(request.options().initiatorInfo.name, monotonicallyIncreasingTime());
699             populateResourceTiming(info.get(), resource.get(), true);
700             m_scheduledResourceTimingReports.add(info, resource->type() == Resource::MainResource);
701             if (!m_resourceTimingReportTimer.isActive())
702                 m_resourceTimingReportTimer.startOneShot(0, FROM_HERE);
703         }
704
705         m_validatedURLs.add(request.resourceRequest().url());
706     }
707
708     ASSERT(resource->url() == url.string());
709     m_documentResources.set(resource->url(), resource);
710     return resource;
711 }
712
713 void ResourceFetcher::resourceTimingReportTimerFired(Timer<ResourceFetcher>* timer)
714 {
715     ASSERT_UNUSED(timer, timer == &m_resourceTimingReportTimer);
716     HashMap<RefPtr<ResourceTimingInfo>, bool> timingReports;
717     timingReports.swap(m_scheduledResourceTimingReports);
718     HashMap<RefPtr<ResourceTimingInfo>, bool>::iterator end = timingReports.end();
719     for (HashMap<RefPtr<ResourceTimingInfo>, bool>::iterator it = timingReports.begin(); it != end; ++it) {
720         RefPtr<ResourceTimingInfo> info = it->key;
721         bool isMainResource = it->value;
722         reportResourceTiming(info.get(), document(), isMainResource);
723     }
724 }
725
726 void ResourceFetcher::determineTargetType(ResourceRequest& request, Resource::Type type)
727 {
728     ResourceRequest::TargetType targetType = requestTargetType(this, request, type);
729     request.setTargetType(targetType);
730 }
731
732 ResourceRequestCachePolicy ResourceFetcher::resourceRequestCachePolicy(const ResourceRequest& request, Resource::Type type)
733 {
734     if (type == Resource::MainResource) {
735         FrameLoadType frameLoadType = frame()->loader().loadType();
736         bool isReload = frameLoadType == FrameLoadTypeReload || frameLoadType == FrameLoadTypeReloadFromOrigin;
737         if (request.httpMethod() == "POST" && frameLoadType == FrameLoadTypeBackForward)
738             return ReturnCacheDataDontLoad;
739         if (!m_documentLoader->overrideEncoding().isEmpty() || frameLoadType == FrameLoadTypeBackForward)
740             return ReturnCacheDataElseLoad;
741         if (isReload || frameLoadType == FrameLoadTypeSame || request.isConditional() || request.httpMethod() == "POST")
742             return ReloadIgnoringCacheData;
743         if (LocalFrame* parent = frame()->tree().parent())
744             return parent->document()->fetcher()->resourceRequestCachePolicy(request, type);
745         return UseProtocolCachePolicy;
746     }
747
748     if (request.isConditional())
749         return ReloadIgnoringCacheData;
750
751     if (m_documentLoader && m_document && !m_document->loadEventFinished()) {
752         // For POST requests, we mutate the main resource's cache policy to avoid form resubmission.
753         // This policy should not be inherited by subresources.
754         ResourceRequestCachePolicy mainResourceCachePolicy = m_documentLoader->request().cachePolicy();
755         if (mainResourceCachePolicy == ReturnCacheDataDontLoad)
756             return ReturnCacheDataElseLoad;
757         return mainResourceCachePolicy;
758     }
759     return UseProtocolCachePolicy;
760 }
761
762 void ResourceFetcher::addAdditionalRequestHeaders(ResourceRequest& request, Resource::Type type)
763 {
764     if (!frame())
765         return;
766
767     if (request.cachePolicy() == UseProtocolCachePolicy)
768         request.setCachePolicy(resourceRequestCachePolicy(request, type));
769     if (request.targetType() == ResourceRequest::TargetIsUnspecified)
770         determineTargetType(request, type);
771     if (type == Resource::LinkPrefetch || type == Resource::LinkSubresource)
772         request.setHTTPHeaderField("Purpose", "prefetch");
773
774     context().addAdditionalRequestHeaders(document(), request, (type == Resource::MainResource) ? FetchMainResource : FetchSubresource);
775 }
776
777 ResourcePtr<Resource> ResourceFetcher::revalidateResource(const FetchRequest& request, Resource* resource)
778 {
779     ASSERT(resource);
780     ASSERT(memoryCache()->contains(resource));
781     ASSERT(resource->isLoaded());
782     ASSERT(resource->canUseCacheValidator());
783     ASSERT(!resource->resourceToRevalidate());
784
785     ResourceRequest revalidatingRequest(resource->resourceRequest());
786     revalidatingRequest.clearHTTPReferrer();
787     addAdditionalRequestHeaders(revalidatingRequest, resource->type());
788
789     const AtomicString& lastModified = resource->response().httpHeaderField("Last-Modified");
790     const AtomicString& eTag = resource->response().httpHeaderField("ETag");
791     if (!lastModified.isEmpty() || !eTag.isEmpty()) {
792         ASSERT(context().cachePolicy(document()) != CachePolicyReload);
793         if (context().cachePolicy(document()) == CachePolicyRevalidate)
794             revalidatingRequest.setHTTPHeaderField("Cache-Control", "max-age=0");
795         if (!lastModified.isEmpty())
796             revalidatingRequest.setHTTPHeaderField("If-Modified-Since", lastModified);
797         if (!eTag.isEmpty())
798             revalidatingRequest.setHTTPHeaderField("If-None-Match", eTag);
799     }
800
801     ResourcePtr<Resource> newResource = createResource(resource->type(), revalidatingRequest, resource->encoding());
802
803     WTF_LOG(ResourceLoading, "Resource %p created to revalidate %p", newResource.get(), resource);
804     newResource->setResourceToRevalidate(resource);
805
806     memoryCache()->remove(resource);
807     memoryCache()->add(newResource.get());
808     storeResourceTimingInitiatorInformation(newResource, request);
809     TRACE_EVENT_ASYNC_BEGIN2("net", "Resource", newResource.get(), "url", newResource->url().string().ascii(), "priority", newResource->resourceRequest().priority());
810     return newResource;
811 }
812
813 ResourcePtr<Resource> ResourceFetcher::loadResource(Resource::Type type, FetchRequest& request, const String& charset)
814 {
815     ASSERT(!memoryCache()->resourceForURL(request.resourceRequest().url()));
816
817     WTF_LOG(ResourceLoading, "Loading Resource for '%s'.", request.resourceRequest().url().elidedString().latin1().data());
818
819     addAdditionalRequestHeaders(request.mutableResourceRequest(), type);
820     ResourcePtr<Resource> resource = createResource(type, request.mutableResourceRequest(), charset);
821
822     memoryCache()->add(resource.get());
823     storeResourceTimingInitiatorInformation(resource, request);
824     TRACE_EVENT_ASYNC_BEGIN2("net", "Resource", resource.get(), "url", resource->url().string().ascii(), "priority", resource->resourceRequest().priority());
825     return resource;
826 }
827
828 void ResourceFetcher::storeResourceTimingInitiatorInformation(const ResourcePtr<Resource>& resource, const FetchRequest& request)
829 {
830     if (request.options().requestInitiatorContext != DocumentContext)
831         return;
832
833     RefPtr<ResourceTimingInfo> info = ResourceTimingInfo::create(request.options().initiatorInfo.name, monotonicallyIncreasingTime());
834
835     if (resource->type() == Resource::MainResource) {
836         // <iframe>s should report the initial navigation requested by the parent document, but not subsequent navigations.
837         if (frame()->ownerElement() && !frame()->ownerElement()->loadedNonEmptyDocument()) {
838             info->setInitiatorType(frame()->ownerElement()->localName());
839             m_resourceTimingInfoMap.add(resource.get(), info);
840             frame()->ownerElement()->didLoadNonEmptyDocument();
841         }
842     } else {
843         m_resourceTimingInfoMap.add(resource.get(), info);
844     }
845 }
846
847 ResourceFetcher::RevalidationPolicy ResourceFetcher::determineRevalidationPolicy(Resource::Type type, ResourceRequest& request, bool forPreload, Resource* existingResource, FetchRequest::DeferOption defer, const ResourceLoaderOptions& options) const
848 {
849     if (!existingResource)
850         return Load;
851
852     // We already have a preload going for this URL.
853     if (forPreload && existingResource->isPreloaded())
854         return Use;
855
856     // If the same URL has been loaded as a different type, we need to reload.
857     if (existingResource->type() != type) {
858         WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to type mismatch.");
859         return Reload;
860     }
861
862     // Do not load from cache if images are not enabled. The load for this image will be blocked
863     // in ImageResource::load.
864     if (FetchRequest::DeferredByClient == defer)
865         return Reload;
866
867     // Always use data uris.
868     // FIXME: Extend this to non-images.
869     if (type == Resource::Image && request.url().protocolIsData())
870         return Use;
871
872     // If a main resource was populated from a SubstituteData load, use it.
873     if (type == Resource::MainResource && m_documentLoader->substituteData().isValid())
874         return Use;
875
876     if (!existingResource->canReuse(request))
877         return Reload;
878
879     // Never use cache entries for downloadToFile requests. The caller expects the resource in a file.
880     if (request.downloadToFile())
881         return Reload;
882
883     // Certain requests (e.g., XHRs) might have manually set headers that require revalidation.
884     // FIXME: In theory, this should be a Revalidate case. In practice, the MemoryCache revalidation path assumes a whole bunch
885     // of things about how revalidation works that manual headers violate, so punt to Reload instead.
886     if (request.isConditional())
887         return Reload;
888
889     // Don't reload resources while pasting.
890     if (m_allowStaleResources)
891         return Use;
892
893     // Always use preloads.
894     if (existingResource->isPreloaded())
895         return Use;
896
897     // CachePolicyHistoryBuffer uses the cache no matter what.
898     CachePolicy cachePolicy = context().cachePolicy(document());
899     if (cachePolicy == CachePolicyHistoryBuffer)
900         return Use;
901
902     // Don't reuse resources with Cache-control: no-store.
903     if (existingResource->response().cacheControlContainsNoStore()) {
904         WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to Cache-control: no-store.");
905         return Reload;
906     }
907
908     // If fetching a resource with a different 'CORS enabled' flag, reload.
909     if (type != Resource::MainResource && options.corsEnabled != existingResource->options().corsEnabled)
910         return Reload;
911
912     // If credentials were sent with the previous request and won't be
913     // with this one, or vice versa, re-fetch the resource.
914     //
915     // This helps with the case where the server sends back
916     // "Access-Control-Allow-Origin: *" all the time, but some of the
917     // client's requests are made without CORS and some with.
918     if (existingResource->resourceRequest().allowStoredCredentials() != request.allowStoredCredentials()) {
919         WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to difference in credentials settings.");
920         return Reload;
921     }
922
923     // During the initial load, avoid loading the same resource multiple times for a single document,
924     // even if the cache policies would tell us to. Raw resources are exempted.
925     if (type != Resource::Raw && document() && !document()->loadEventFinished() && m_validatedURLs.contains(existingResource->url()))
926         return Use;
927
928     // CachePolicyReload always reloads
929     if (cachePolicy == CachePolicyReload) {
930         WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to CachePolicyReload.");
931         return Reload;
932     }
933
934     // We'll try to reload the resource if it failed last time.
935     if (existingResource->errorOccurred()) {
936         WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicye reloading due to resource being in the error state");
937         return Reload;
938     }
939
940     // For resources that are not yet loaded we ignore the cache policy.
941     if (existingResource->isLoading())
942         return Use;
943
944     // If any of the redirects in the chain to loading the resource were not cacheable, we cannot reuse our cached resource.
945     if (!existingResource->canReuseRedirectChain()) {
946         WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to an uncacheable redirect");
947         return Reload;
948     }
949
950     // Check if the cache headers requires us to revalidate (cache expiration for example).
951     if (cachePolicy == CachePolicyRevalidate || existingResource->mustRevalidateDueToCacheHeaders()) {
952         // See if the resource has usable ETag or Last-modified headers.
953         if (existingResource->canUseCacheValidator())
954             return Revalidate;
955
956         // No, must reload.
957         WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to missing cache validators.");
958         return Reload;
959     }
960
961     return Use;
962 }
963
964 void ResourceFetcher::printAccessDeniedMessage(const KURL& url) const
965 {
966     if (url.isNull())
967         return;
968
969     if (!frame())
970         return;
971
972     String message;
973     if (!m_document || m_document->url().isNull())
974         message = "Unsafe attempt to load URL " + url.elidedString() + '.';
975     else
976         message = "Unsafe attempt to load URL " + url.elidedString() + " from frame with URL " + m_document->url().elidedString() + ". Domains, protocols and ports must match.\n";
977
978     frame()->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message);
979 }
980
981 void ResourceFetcher::setAutoLoadImages(bool enable)
982 {
983     if (enable == m_autoLoadImages)
984         return;
985
986     m_autoLoadImages = enable;
987
988     if (!m_autoLoadImages)
989         return;
990
991     reloadImagesIfNotDeferred();
992 }
993
994 void ResourceFetcher::setImagesEnabled(bool enable)
995 {
996     if (enable == m_imagesEnabled)
997         return;
998
999     m_imagesEnabled = enable;
1000
1001     if (!m_imagesEnabled)
1002         return;
1003
1004     reloadImagesIfNotDeferred();
1005 }
1006
1007 bool ResourceFetcher::clientDefersImage(const KURL& url) const
1008 {
1009     return frame() && !frame()->loader().client()->allowImage(m_imagesEnabled, url);
1010 }
1011
1012 bool ResourceFetcher::shouldDeferImageLoad(const KURL& url) const
1013 {
1014     return clientDefersImage(url) || !m_autoLoadImages;
1015 }
1016
1017 void ResourceFetcher::reloadImagesIfNotDeferred()
1018 {
1019     DocumentResourceMap::iterator end = m_documentResources.end();
1020     for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != end; ++it) {
1021         Resource* resource = it->value.get();
1022         if (resource->type() == Resource::Image && resource->stillNeedsLoad() && !clientDefersImage(resource->url()))
1023             const_cast<Resource*>(resource)->load(this, defaultResourceOptions());
1024     }
1025 }
1026
1027 void ResourceFetcher::redirectReceived(Resource* resource, const ResourceResponse& redirectResponse)
1028 {
1029     ResourceTimingInfoMap::iterator it = m_resourceTimingInfoMap.find(resource);
1030     if (it != m_resourceTimingInfoMap.end())
1031         it->value->addRedirect(redirectResponse);
1032 }
1033
1034 void ResourceFetcher::didLoadResource(Resource* resource)
1035 {
1036     RefPtr<DocumentLoader> protectDocumentLoader(m_documentLoader);
1037     RefPtr<Document> protectDocument(m_document);
1038
1039     if (resource && resource->response().isHTTP() && ((!resource->errorOccurred() && !resource->wasCanceled()) || resource->response().httpStatusCode() == 304) && document()) {
1040         ResourceTimingInfoMap::iterator it = m_resourceTimingInfoMap.find(resource);
1041         if (it != m_resourceTimingInfoMap.end()) {
1042             RefPtr<ResourceTimingInfo> info = it->value;
1043             m_resourceTimingInfoMap.remove(it);
1044             populateResourceTiming(info.get(), resource, false);
1045             reportResourceTiming(info.get(), document(), resource->type() == Resource::MainResource);
1046         }
1047     }
1048
1049     if (frame())
1050         frame()->loader().loadDone();
1051     scheduleDocumentResourcesGC();
1052 }
1053
1054 void ResourceFetcher::scheduleDocumentResourcesGC()
1055 {
1056     if (!m_garbageCollectDocumentResourcesTimer.isActive())
1057         m_garbageCollectDocumentResourcesTimer.startOneShot(0, FROM_HERE);
1058 }
1059
1060 // Garbage collecting m_documentResources is a workaround for the
1061 // ResourcePtrs on the RHS being strong references. Ideally this
1062 // would be a weak map, however ResourcePtrs perform additional
1063 // bookkeeping on Resources, so instead pseudo-GC them -- when the
1064 // reference count reaches 1, m_documentResources is the only reference, so
1065 // remove it from the map.
1066 void ResourceFetcher::garbageCollectDocumentResourcesTimerFired(Timer<ResourceFetcher>* timer)
1067 {
1068     ASSERT_UNUSED(timer, timer == &m_garbageCollectDocumentResourcesTimer);
1069     garbageCollectDocumentResources();
1070 }
1071
1072 void ResourceFetcher::garbageCollectDocumentResources()
1073 {
1074     typedef Vector<String, 10> StringVector;
1075     StringVector resourcesToDelete;
1076
1077     for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != m_documentResources.end(); ++it) {
1078         if (it->value->hasOneHandle())
1079             resourcesToDelete.append(it->key);
1080     }
1081
1082     for (StringVector::const_iterator it = resourcesToDelete.begin(); it != resourcesToDelete.end(); ++it)
1083         m_documentResources.remove(*it);
1084 }
1085
1086 void ResourceFetcher::notifyLoadedFromMemoryCache(Resource* resource)
1087 {
1088     if (!frame() || !frame()->page() || resource->status() != Resource::Cached || m_validatedURLs.contains(resource->url()))
1089         return;
1090
1091     ResourceRequest request(resource->url());
1092     unsigned long identifier = createUniqueIdentifier();
1093     context().dispatchDidLoadResourceFromMemoryCache(request, resource->response());
1094     // FIXME: If willSendRequest changes the request, we don't respect it.
1095     willSendRequest(identifier, request, ResourceResponse(), resource->options().initiatorInfo);
1096     InspectorInstrumentation::markResourceAsCached(frame()->page(), identifier);
1097     context().sendRemainingDelegateMessages(m_documentLoader, identifier, resource->response(), resource->encodedSize());
1098 }
1099
1100 void ResourceFetcher::incrementRequestCount(const Resource* res)
1101 {
1102     if (res->ignoreForRequestCount())
1103         return;
1104
1105     ++m_requestCount;
1106 }
1107
1108 void ResourceFetcher::decrementRequestCount(const Resource* res)
1109 {
1110     if (res->ignoreForRequestCount())
1111         return;
1112
1113     --m_requestCount;
1114     ASSERT(m_requestCount > -1);
1115 }
1116
1117 void ResourceFetcher::preload(Resource::Type type, FetchRequest& request, const String& charset)
1118 {
1119     requestPreload(type, request, charset);
1120 }
1121
1122 void ResourceFetcher::requestPreload(Resource::Type type, FetchRequest& request, const String& charset)
1123 {
1124     String encoding;
1125     if (type == Resource::Script || type == Resource::CSSStyleSheet)
1126         encoding = charset.isEmpty() ? m_document->charset().string() : charset;
1127
1128     request.setCharset(encoding);
1129     request.setForPreload(true);
1130
1131     ResourcePtr<Resource> resource = requestResource(type, request);
1132     if (!resource || (m_preloads && m_preloads->contains(resource.get())))
1133         return;
1134     TRACE_EVENT_ASYNC_STEP_INTO0("net", "Resource", resource.get(), "Preload");
1135     resource->increasePreloadCount();
1136
1137     if (!m_preloads)
1138         m_preloads = adoptPtr(new ListHashSet<Resource*>);
1139     m_preloads->add(resource.get());
1140
1141 #if PRELOAD_DEBUG
1142     printf("PRELOADING %s\n",  resource->url().string().latin1().data());
1143 #endif
1144 }
1145
1146 bool ResourceFetcher::isPreloaded(const String& urlString) const
1147 {
1148     const KURL& url = m_document->completeURL(urlString);
1149
1150     if (m_preloads) {
1151         ListHashSet<Resource*>::iterator end = m_preloads->end();
1152         for (ListHashSet<Resource*>::iterator it = m_preloads->begin(); it != end; ++it) {
1153             Resource* resource = *it;
1154             if (resource->url() == url)
1155                 return true;
1156         }
1157     }
1158
1159     return false;
1160 }
1161
1162 void ResourceFetcher::clearPreloads()
1163 {
1164 #if PRELOAD_DEBUG
1165     printPreloadStats();
1166 #endif
1167     if (!m_preloads)
1168         return;
1169
1170     ListHashSet<Resource*>::iterator end = m_preloads->end();
1171     for (ListHashSet<Resource*>::iterator it = m_preloads->begin(); it != end; ++it) {
1172         Resource* res = *it;
1173         res->decreasePreloadCount();
1174         bool deleted = res->deleteIfPossible();
1175         if (!deleted && res->preloadResult() == Resource::PreloadNotReferenced)
1176             memoryCache()->remove(res);
1177     }
1178     m_preloads.clear();
1179 }
1180
1181 void ResourceFetcher::didFinishLoading(const Resource* resource, double finishTime, int64_t encodedDataLength)
1182 {
1183     TRACE_EVENT_ASYNC_END0("net", "Resource", resource);
1184     context().dispatchDidFinishLoading(m_documentLoader, resource->identifier(), finishTime, encodedDataLength);
1185 }
1186
1187 void ResourceFetcher::didChangeLoadingPriority(const Resource* resource, ResourceLoadPriority loadPriority, int intraPriorityValue)
1188 {
1189     TRACE_EVENT_ASYNC_STEP_INTO1("net", "Resource", resource, "ChangePriority", "priority", loadPriority);
1190     context().dispatchDidChangeResourcePriority(resource->identifier(), loadPriority, intraPriorityValue);
1191 }
1192
1193 void ResourceFetcher::didFailLoading(const Resource* resource, const ResourceError& error)
1194 {
1195     TRACE_EVENT_ASYNC_END0("net", "Resource", resource);
1196     context().dispatchDidFail(m_documentLoader, resource->identifier(), error);
1197 }
1198
1199 void ResourceFetcher::willSendRequest(unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse, const FetchInitiatorInfo& initiatorInfo)
1200 {
1201     context().dispatchWillSendRequest(m_documentLoader, identifier, request, redirectResponse, initiatorInfo);
1202 }
1203
1204 void ResourceFetcher::didReceiveResponse(const Resource* resource, const ResourceResponse& response)
1205 {
1206     context().dispatchDidReceiveResponse(m_documentLoader, resource->identifier(), response, resource->loader());
1207 }
1208
1209 void ResourceFetcher::didReceiveData(const Resource* resource, const char* data, int dataLength, int encodedDataLength)
1210 {
1211     context().dispatchDidReceiveData(m_documentLoader, resource->identifier(), data, dataLength, encodedDataLength);
1212 }
1213
1214 void ResourceFetcher::didDownloadData(const Resource* resource, int dataLength, int encodedDataLength)
1215 {
1216     context().dispatchDidDownloadData(m_documentLoader, resource->identifier(), dataLength, encodedDataLength);
1217 }
1218
1219 void ResourceFetcher::subresourceLoaderFinishedLoadingOnePart(ResourceLoader* loader)
1220 {
1221     if (m_multipartLoaders)
1222         m_multipartLoaders->add(loader);
1223     if (m_loaders)
1224         m_loaders->remove(loader);
1225     if (LocalFrame* frame = this->frame())
1226         return frame->loader().checkLoadComplete(m_documentLoader);
1227 }
1228
1229 void ResourceFetcher::didInitializeResourceLoader(ResourceLoader* loader)
1230 {
1231     if (!m_document)
1232         return;
1233     if (!m_loaders)
1234         m_loaders = adoptPtr(new ResourceLoaderSet());
1235     ASSERT(!m_loaders->contains(loader));
1236     m_loaders->add(loader);
1237 }
1238
1239 void ResourceFetcher::willTerminateResourceLoader(ResourceLoader* loader)
1240 {
1241     if (!m_loaders || !m_loaders->contains(loader))
1242         return;
1243     m_loaders->remove(loader);
1244     if (LocalFrame* frame = this->frame())
1245         frame->loader().checkLoadComplete(m_documentLoader);
1246 }
1247
1248 void ResourceFetcher::willStartLoadingResource(ResourceRequest& request)
1249 {
1250     if (m_documentLoader)
1251         m_documentLoader->applicationCacheHost()->willStartLoadingResource(request);
1252 }
1253
1254 void ResourceFetcher::stopFetching()
1255 {
1256     if (m_multipartLoaders)
1257         m_multipartLoaders->cancelAll();
1258     if (m_loaders)
1259         m_loaders->cancelAll();
1260 }
1261
1262 bool ResourceFetcher::isFetching() const
1263 {
1264     return m_loaders && !m_loaders->isEmpty();
1265 }
1266
1267 void ResourceFetcher::setDefersLoading(bool defers)
1268 {
1269     if (m_loaders)
1270         m_loaders->setAllDefersLoading(defers);
1271 }
1272
1273 bool ResourceFetcher::defersLoading() const
1274 {
1275     if (LocalFrame* frame = this->frame())
1276         return frame->page()->defersLoading();
1277     return false;
1278 }
1279
1280 bool ResourceFetcher::isLoadedBy(ResourceLoaderHost* possibleOwner) const
1281 {
1282     return this == possibleOwner;
1283 }
1284
1285 bool ResourceFetcher::canAccessRedirect(Resource* resource, ResourceRequest& request, const ResourceResponse& redirectResponse, ResourceLoaderOptions& options)
1286 {
1287     if (!canRequest(resource->type(), request.url(), options, false, FetchRequest::UseDefaultOriginRestrictionForType))
1288         return false;
1289     if (options.corsEnabled == IsCORSEnabled) {
1290         SecurityOrigin* sourceOrigin = options.securityOrigin.get();
1291         if (!sourceOrigin && document())
1292             sourceOrigin = document()->securityOrigin();
1293
1294         String errorMessage;
1295         if (!CrossOriginAccessControl::handleRedirect(resource, sourceOrigin, request, redirectResponse, options, errorMessage)) {
1296             if (frame() && frame()->document())
1297                 frame()->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, errorMessage);
1298             return false;
1299         }
1300     }
1301     if (resource->type() == Resource::Image && shouldDeferImageLoad(request.url()))
1302         return false;
1303     return true;
1304 }
1305
1306 void ResourceFetcher::refResourceLoaderHost()
1307 {
1308     ref();
1309 }
1310
1311 void ResourceFetcher::derefResourceLoaderHost()
1312 {
1313     deref();
1314 }
1315
1316 #if PRELOAD_DEBUG
1317 void ResourceFetcher::printPreloadStats()
1318 {
1319     if (!m_preloads)
1320         return;
1321
1322     unsigned scripts = 0;
1323     unsigned scriptMisses = 0;
1324     unsigned stylesheets = 0;
1325     unsigned stylesheetMisses = 0;
1326     unsigned images = 0;
1327     unsigned imageMisses = 0;
1328     ListHashSet<Resource*>::iterator end = m_preloads->end();
1329     for (ListHashSet<Resource*>::iterator it = m_preloads->begin(); it != end; ++it) {
1330         Resource* res = *it;
1331         if (res->preloadResult() == Resource::PreloadNotReferenced)
1332             printf("!! UNREFERENCED PRELOAD %s\n", res->url().string().latin1().data());
1333         else if (res->preloadResult() == Resource::PreloadReferencedWhileComplete)
1334             printf("HIT COMPLETE PRELOAD %s\n", res->url().string().latin1().data());
1335         else if (res->preloadResult() == Resource::PreloadReferencedWhileLoading)
1336             printf("HIT LOADING PRELOAD %s\n", res->url().string().latin1().data());
1337
1338         if (res->type() == Resource::Script) {
1339             scripts++;
1340             if (res->preloadResult() < Resource::PreloadReferencedWhileLoading)
1341                 scriptMisses++;
1342         } else if (res->type() == Resource::CSSStyleSheet) {
1343             stylesheets++;
1344             if (res->preloadResult() < Resource::PreloadReferencedWhileLoading)
1345                 stylesheetMisses++;
1346         } else {
1347             images++;
1348             if (res->preloadResult() < Resource::PreloadReferencedWhileLoading)
1349                 imageMisses++;
1350         }
1351
1352         if (res->errorOccurred())
1353             memoryCache()->remove(res);
1354
1355         res->decreasePreloadCount();
1356     }
1357     m_preloads.clear();
1358
1359     if (scripts)
1360         printf("SCRIPTS: %d (%d hits, hit rate %d%%)\n", scripts, scripts - scriptMisses, (scripts - scriptMisses) * 100 / scripts);
1361     if (stylesheets)
1362         printf("STYLESHEETS: %d (%d hits, hit rate %d%%)\n", stylesheets, stylesheets - stylesheetMisses, (stylesheets - stylesheetMisses) * 100 / stylesheets);
1363     if (images)
1364         printf("IMAGES:  %d (%d hits, hit rate %d%%)\n", images, images - imageMisses, (images - imageMisses) * 100 / images);
1365 }
1366 #endif
1367
1368 const ResourceLoaderOptions& ResourceFetcher::defaultResourceOptions()
1369 {
1370     DEFINE_STATIC_LOCAL(ResourceLoaderOptions, options, (SniffContent, BufferData, AllowStoredCredentials, ClientRequestedCredentials, CheckContentSecurityPolicy, DocumentContext));
1371     return options;
1372 }
1373
1374 ResourceFetcher::DeadResourceStatsRecorder::DeadResourceStatsRecorder()
1375     : m_useCount(0)
1376     , m_revalidateCount(0)
1377     , m_loadCount(0)
1378 {
1379 }
1380
1381 ResourceFetcher::DeadResourceStatsRecorder::~DeadResourceStatsRecorder()
1382 {
1383     blink::Platform::current()->histogramCustomCounts(
1384         "WebCore.ResourceFetcher.HitCount", m_useCount, 0, 1000, 50);
1385     blink::Platform::current()->histogramCustomCounts(
1386         "WebCore.ResourceFetcher.RevalidateCount", m_revalidateCount, 0, 1000, 50);
1387     blink::Platform::current()->histogramCustomCounts(
1388         "WebCore.ResourceFetcher.LoadCount", m_loadCount, 0, 1000, 50);
1389 }
1390
1391 void ResourceFetcher::DeadResourceStatsRecorder::update(RevalidationPolicy policy)
1392 {
1393     switch (policy) {
1394     case Reload:
1395     case Load:
1396         ++m_loadCount;
1397         return;
1398     case Revalidate:
1399         ++m_revalidateCount;
1400         return;
1401     case Use:
1402         ++m_useCount;
1403         return;
1404     }
1405 }
1406
1407 }