Upstream version 5.34.104.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/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"
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(resource->loadFinishTime());
175 }
176
177 static void reportResourceTiming(ResourceTimingInfo* info, Document* initiatorDocument, bool isMainResource)
178 {
179     if (initiatorDocument && isMainResource)
180         initiatorDocument = initiatorDocument->parentDocument();
181     if (!initiatorDocument || !initiatorDocument->loader())
182         return;
183     if (DOMWindow* initiatorWindow = initiatorDocument->domWindow()) {
184         if (Performance* performance = initiatorWindow->performance())
185             performance->addResourceTiming(*info, initiatorDocument);
186     }
187 }
188
189 static ResourceRequest::TargetType requestTargetType(const ResourceFetcher* fetcher, const ResourceRequest& request, Resource::Type type)
190 {
191     switch (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;
202     case Resource::Font:
203         return ResourceRequest::TargetIsFont;
204     case Resource::Image:
205         return ResourceRequest::TargetIsImage;
206     case Resource::Shader:
207     case Resource::Raw:
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;
218     }
219     ASSERT_NOT_REACHED();
220     return ResourceRequest::TargetIsSubresource;
221 }
222
223 ResourceFetcher::ResourceFetcher(DocumentLoader* documentLoader)
224     : m_document(0)
225     , m_documentLoader(documentLoader)
226     , m_requestCount(0)
227     , m_garbageCollectDocumentResourcesTimer(this, &ResourceFetcher::garbageCollectDocumentResourcesTimerFired)
228     , m_resourceTimingReportTimer(this, &ResourceFetcher::resourceTimingReportTimerFired)
229     , m_autoLoadImages(true)
230     , m_imagesEnabled(true)
231     , m_allowStaleResources(false)
232 {
233 }
234
235 ResourceFetcher::~ResourceFetcher()
236 {
237     m_documentLoader = 0;
238     m_document = 0;
239
240     clearPreloads();
241
242     // Make sure no requests still point to this ResourceFetcher
243     ASSERT(!m_requestCount);
244 }
245
246 Resource* ResourceFetcher::cachedResource(const KURL& resourceURL) const
247 {
248     KURL url = MemoryCache::removeFragmentIdentifierIfNeeded(resourceURL);
249     return m_documentResources.get(url).get();
250 }
251
252 Frame* ResourceFetcher::frame() const
253 {
254     if (m_documentLoader)
255         return m_documentLoader->frame();
256     if (m_document && m_document->import())
257         return m_document->import()->frame();
258     return 0;
259 }
260
261 FetchContext& ResourceFetcher::context() const
262 {
263     if (Frame* frame = this->frame())
264         return frame->fetchContext();
265     return FetchContext::nullInstance();
266 }
267
268 ResourcePtr<Resource> ResourceFetcher::fetchSynchronously(FetchRequest& request)
269 {
270     ASSERT(document());
271     request.mutableResourceRequest().setTimeoutInterval(10);
272     ResourceLoaderOptions options(request.options());
273     options.synchronousPolicy = RequestSynchronously;
274     request.setOptions(options);
275     return requestResource(Resource::Raw, request);
276 }
277
278 ResourcePtr<ImageResource> ResourceFetcher::fetchImage(FetchRequest& request)
279 {
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);
285             return 0;
286         }
287     }
288
289     if (request.resourceRequest().url().protocolIsData())
290         preCacheDataURIImage(request);
291
292     request.setDefer(clientDefersImage(request.resourceRequest().url()) ? FetchRequest::DeferredByClient : FetchRequest::NoDefer);
293     return toImageResource(requestResource(Resource::Image, request));
294 }
295
296 void ResourceFetcher::preCacheDataURIImage(const FetchRequest& request)
297 {
298     const KURL& url = request.resourceRequest().url();
299     ASSERT(url.protocolIsData());
300
301     if (memoryCache()->resourceForURL(url))
302         return;
303
304     if (Resource* resource = resourceFromDataURIRequest(request.resourceRequest(), request.options())) {
305         memoryCache()->add(resource);
306         scheduleDocumentResourcesGC();
307     }
308 }
309
310 ResourcePtr<FontResource> ResourceFetcher::fetchFont(FetchRequest& request)
311 {
312     return toFontResource(requestResource(Resource::Font, request));
313 }
314
315 ResourcePtr<ShaderResource> ResourceFetcher::fetchShader(FetchRequest& request)
316 {
317     return toShaderResource(requestResource(Resource::Shader, request));
318 }
319
320 ResourcePtr<RawResource> ResourceFetcher::fetchImport(FetchRequest& request)
321 {
322     return toRawResource(requestResource(Resource::ImportResource, request));
323 }
324
325 ResourcePtr<CSSStyleSheetResource> ResourceFetcher::fetchCSSStyleSheet(FetchRequest& request)
326 {
327     return toCSSStyleSheetResource(requestResource(Resource::CSSStyleSheet, request));
328 }
329
330 ResourcePtr<CSSStyleSheetResource> ResourceFetcher::fetchUserCSSStyleSheet(FetchRequest& request)
331 {
332     KURL url = MemoryCache::removeFragmentIdentifierIfNeeded(request.resourceRequest().url());
333
334     if (Resource* existing = memoryCache()->resourceForURL(url)) {
335         if (existing->type() == Resource::CSSStyleSheet)
336             return toCSSStyleSheetResource(existing);
337         memoryCache()->remove(existing);
338     }
339
340     request.setOptions(ResourceLoaderOptions(SniffContent, BufferData, AllowStoredCredentials, ClientRequestedCredentials, CheckContentSecurityPolicy, DocumentContext));
341     return toCSSStyleSheetResource(requestResource(Resource::CSSStyleSheet, request));
342 }
343
344 ResourcePtr<ScriptResource> ResourceFetcher::fetchScript(FetchRequest& request)
345 {
346     return toScriptResource(requestResource(Resource::Script, request));
347 }
348
349 ResourcePtr<XSLStyleSheetResource> ResourceFetcher::fetchXSLStyleSheet(FetchRequest& request)
350 {
351     ASSERT(RuntimeEnabledFeatures::xsltEnabled());
352     return toXSLStyleSheetResource(requestResource(Resource::XSLStyleSheet, request));
353 }
354
355 ResourcePtr<DocumentResource> ResourceFetcher::fetchSVGDocument(FetchRequest& request)
356 {
357     return toDocumentResource(requestResource(Resource::SVGDocument, request));
358 }
359
360 ResourcePtr<Resource> ResourceFetcher::fetchLinkResource(Resource::Type type, FetchRequest& request)
361 {
362     ASSERT(frame());
363     ASSERT(type == Resource::LinkPrefetch || type == Resource::LinkSubresource);
364     return requestResource(type, request);
365 }
366
367 ResourcePtr<RawResource> ResourceFetcher::fetchRawResource(FetchRequest& request)
368 {
369     return toRawResource(requestResource(Resource::Raw, request));
370 }
371
372 ResourcePtr<RawResource> ResourceFetcher::fetchMainResource(FetchRequest& request, const SubstituteData& substituteData)
373 {
374     if (substituteData.isValid())
375         preCacheSubstituteDataForMainResource(request, substituteData);
376     return toRawResource(requestResource(Resource::MainResource, request));
377 }
378
379 void ResourceFetcher::preCacheSubstituteDataForMainResource(const FetchRequest& request, const SubstituteData& substituteData)
380 {
381     const KURL& url = request.url();
382     if (Resource* oldResource = memoryCache()->resourceForURL(url))
383         memoryCache()->remove(oldResource);
384
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());
393     resource->finish();
394     memoryCache()->add(resource.get());
395 }
396
397 bool ResourceFetcher::checkInsecureContent(Resource::Type type, const KURL& url, MixedContentBlockingTreatment treatment) const
398 {
399     if (treatment == TreatAsDefaultForType) {
400         switch (type) {
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;
410             break;
411
412         case Resource::TextTrack:
413         case Resource::Shader:
414         case Resource::Raw:
415         case Resource::Image:
416         case Resource::Font:
417             // These resources can corrupt only the frame's pixels.
418             treatment = TreatAsPassiveContent;
419             break;
420
421         case Resource::MainResource:
422         case Resource::LinkPrefetch:
423         case Resource::LinkSubresource:
424             // These cannot affect the current document.
425             treatment = TreatAsAlwaysAllowedContent;
426             break;
427         }
428     }
429     if (treatment == TreatAsActiveContent) {
430         if (Frame* f = frame()) {
431             if (!f->loader().mixedContentChecker()->canRunInsecureContent(m_document->securityOrigin(), url))
432                 return false;
433             Frame* top = f->tree().top();
434             if (top != f && !top->loader().mixedContentChecker()->canRunInsecureContent(top->document()->securityOrigin(), url))
435                 return false;
436         }
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))
441                 return false;
442         }
443     } else {
444         ASSERT(treatment == TreatAsAlwaysAllowedContent);
445     }
446     return true;
447 }
448
449 bool ResourceFetcher::canRequest(Resource::Type type, const KURL& url, const ResourceLoaderOptions& options, bool forPreload, FetchRequest::OriginRestriction originRestriction) const
450 {
451     SecurityOrigin* securityOrigin = options.securityOrigin.get();
452     if (!securityOrigin && document())
453         securityOrigin = document()->securityOrigin();
454
455     if (securityOrigin && !securityOrigin->canDisplay(url)) {
456         if (!forPreload)
457             context().reportLocalLoadFailed(url);
458         WTF_LOG(ResourceLoading, "ResourceFetcher::requestResource URL was not allowed by SecurityOrigin::canDisplay");
459         return 0;
460     }
461
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);
464
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
467     // any URL.
468     switch (type) {
469     case Resource::MainResource:
470     case Resource::Image:
471     case Resource::CSSStyleSheet:
472     case Resource::Script:
473     case Resource::Font:
474     case Resource::Raw:
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);
484             return false;
485         }
486         break;
487     case Resource::XSLStyleSheet:
488         ASSERT(RuntimeEnabledFeatures::xsltEnabled());
489     case Resource::SVGDocument:
490         if (!securityOrigin->canRequest(url)) {
491             printAccessDeniedMessage(url);
492             return false;
493         }
494         break;
495     }
496
497     switch (type) {
498     case Resource::XSLStyleSheet:
499         ASSERT(RuntimeEnabledFeatures::xsltEnabled());
500         if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowScriptFromSource(url))
501             return false;
502         break;
503     case Resource::Script:
504     case Resource::ImportResource:
505         if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowScriptFromSource(url))
506             return false;
507
508         if (frame()) {
509             Settings* settings = frame()->settings();
510             if (!frame()->loader().client()->allowScriptFromSource(!settings || settings->scriptEnabled(), url)) {
511                 frame()->loader().client()->didNotAllowScript();
512                 return false;
513             }
514         }
515         break;
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))
520             return false;
521         break;
522     case Resource::SVGDocument:
523     case Resource::Image:
524         if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowImageFromSource(url))
525             return false;
526         break;
527     case Resource::Font: {
528         if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowFontFromSource(url))
529             return false;
530         break;
531     }
532     case Resource::MainResource:
533     case Resource::Raw:
534     case Resource::LinkPrefetch:
535     case Resource::LinkSubresource:
536         break;
537     case Resource::TextTrack:
538         if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowMediaFromSource(url))
539             return false;
540         break;
541     }
542
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.
546
547     // FIXME: Should we consider forPreload here?
548     if (!checkInsecureContent(type, url, options.mixedContentBlockingTreatment))
549         return false;
550
551     return true;
552 }
553
554 bool ResourceFetcher::canAccessResource(Resource* resource, SecurityOrigin* sourceOrigin, const KURL& url) const
555 {
556     // Redirects can change the response URL different from one of request.
557     if (!canRequest(resource->type(), url, resource->options(), false, FetchRequest::UseDefaultOriginRestrictionForType))
558         return false;
559
560     if (!sourceOrigin && document())
561         sourceOrigin = document()->securityOrigin();
562
563     if (sourceOrigin->canRequest(url))
564         return true;
565
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);
571         }
572         return false;
573     }
574     return true;
575 }
576
577 bool ResourceFetcher::shouldLoadNewResource(Resource::Type type) const
578 {
579     if (!frame())
580         return false;
581     if (!m_documentLoader)
582         return true;
583     if (type == Resource::MainResource)
584         return m_documentLoader == frame()->loader().provisionalDocumentLoader();
585     return m_documentLoader == frame()->loader().documentLoader();
586 }
587
588 bool ResourceFetcher::resourceNeedsLoad(Resource* resource, const FetchRequest& request, RevalidationPolicy policy)
589 {
590     if (FetchRequest::DeferredByClient == request.defer())
591         return false;
592     if (policy != Use)
593         return true;
594     if (resource->stillNeedsLoad())
595         return true;
596     return request.options().synchronousPolicy == RequestSynchronously && resource->isLoading();
597 }
598
599 ResourcePtr<Resource> ResourceFetcher::requestResource(Resource::Type type, FetchRequest& request)
600 {
601     ASSERT(request.options().synchronousPolicy == RequestAsynchronously || type == Resource::Raw);
602
603     KURL url = request.resourceRequest().url();
604
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));
606
607     // If only the fragment identifiers differ, it is the same resource.
608     url = MemoryCache::removeFragmentIdentifierIfNeeded(url);
609
610     if (!url.isValid())
611         return 0;
612
613     if (!canRequest(type, url, request.options(), request.forPreload(), request.originRestriction()))
614         return 0;
615
616     if (Frame* f = frame())
617         f->loader().client()->dispatchWillRequestResource(&request);
618
619     // See if we can use an existing resource from the cache.
620     ResourcePtr<Resource> resource = memoryCache()->resourceForURL(url);
621
622     const RevalidationPolicy policy = determineRevalidationPolicy(type, request.mutableResourceRequest(), request.forPreload(), resource.get(), request.defer(), request.options());
623     switch (policy) {
624     case Reload:
625         memoryCache()->remove(resource.get());
626         // Fall through
627     case Load:
628         resource = loadResource(type, request, request.charset());
629         break;
630     case Revalidate:
631         resource = revalidateResource(request, resource.get());
632         break;
633     case Use:
634         resource->updateForAccess();
635         notifyLoadedFromMemoryCache(resource.get());
636         break;
637     }
638
639     if (!resource)
640         return 0;
641
642     if (!resource->hasClients())
643         m_deadStatsRecorder.update(policy);
644
645     if (policy != Use)
646         resource->setIdentifier(createUniqueIdentifier());
647
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);
653         }
654     }
655
656     if (resourceNeedsLoad(resource.get(), request, policy)) {
657         if (!shouldLoadNewResource(type)) {
658             if (resource->inCache())
659                 memoryCache()->remove(resource.get());
660             return 0;
661         }
662
663         if (!m_documentLoader || !m_documentLoader->scheduleArchiveLoad(resource.get(), request.resourceRequest()))
664             resource->load(this, request.options());
665
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;
676         }
677     }
678
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
682     // use.
683     //
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())
691             return 0;
692     }
693
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);
702         }
703
704         m_validatedURLs.add(request.resourceRequest().url());
705     }
706
707     ASSERT(resource->url() == url.string());
708     m_documentResources.set(resource->url(), resource);
709     return resource;
710 }
711
712 void ResourceFetcher::resourceTimingReportTimerFired(Timer<ResourceFetcher>* timer)
713 {
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);
722     }
723 }
724
725 void ResourceFetcher::determineTargetType(ResourceRequest& request, Resource::Type type)
726 {
727     ResourceRequest::TargetType targetType = requestTargetType(this, request, type);
728     request.setTargetType(targetType);
729 }
730
731 ResourceRequestCachePolicy ResourceFetcher::resourceRequestCachePolicy(const ResourceRequest& request, Resource::Type type)
732 {
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;
745     }
746
747     if (request.isConditional())
748         return ReloadIgnoringCacheData;
749
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;
757     }
758     return UseProtocolCachePolicy;
759 }
760
761 void ResourceFetcher::addAdditionalRequestHeaders(ResourceRequest& request, Resource::Type type)
762 {
763     if (!frame())
764         return;
765
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");
772
773     context().addAdditionalRequestHeaders(document(), request, (type == Resource::MainResource) ? FetchMainResource : FetchSubresource);
774 }
775
776 ResourcePtr<Resource> ResourceFetcher::revalidateResource(const FetchRequest& request, Resource* resource)
777 {
778     ASSERT(resource);
779     ASSERT(resource->inCache());
780     ASSERT(resource->isLoaded());
781     ASSERT(resource->canUseCacheValidator());
782     ASSERT(!resource->resourceToRevalidate());
783
784     ResourceRequest revalidatingRequest(resource->resourceRequest());
785     addAdditionalRequestHeaders(revalidatingRequest, resource->type());
786
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);
795         if (!eTag.isEmpty())
796             revalidatingRequest.setHTTPHeaderField("If-None-Match", eTag);
797     }
798
799     ResourcePtr<Resource> newResource = createResource(resource->type(), revalidatingRequest, resource->encoding());
800
801     WTF_LOG(ResourceLoading, "Resource %p created to revalidate %p", newResource.get(), resource);
802     newResource->setResourceToRevalidate(resource);
803
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());
808     return newResource;
809 }
810
811 ResourcePtr<Resource> ResourceFetcher::loadResource(Resource::Type type, FetchRequest& request, const String& charset)
812 {
813     ASSERT(!memoryCache()->resourceForURL(request.resourceRequest().url()));
814
815     WTF_LOG(ResourceLoading, "Loading Resource for '%s'.", request.resourceRequest().url().elidedString().latin1().data());
816
817     addAdditionalRequestHeaders(request.mutableResourceRequest(), type);
818     ResourcePtr<Resource> resource = createResource(type, request.mutableResourceRequest(), charset);
819
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());
823     return resource;
824 }
825
826 void ResourceFetcher::storeResourceTimingInitiatorInformation(const ResourcePtr<Resource>& resource, const FetchRequest& request)
827 {
828     if (request.options().requestInitiatorContext != DocumentContext)
829         return;
830
831     RefPtr<ResourceTimingInfo> info = ResourceTimingInfo::create(request.options().initiatorInfo.name, monotonicallyIncreasingTime());
832
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();
839         }
840     } else {
841         m_resourceTimingInfoMap.add(resource.get(), info);
842     }
843 }
844
845 ResourceFetcher::RevalidationPolicy ResourceFetcher::determineRevalidationPolicy(Resource::Type type, ResourceRequest& request, bool forPreload, Resource* existingResource, FetchRequest::DeferOption defer, const ResourceLoaderOptions& options) const
846 {
847     if (!existingResource)
848         return Load;
849
850     // We already have a preload going for this URL.
851     if (forPreload && existingResource->isPreloaded())
852         return Use;
853
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.");
857         return Reload;
858     }
859
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)
863         return Reload;
864
865     // Always use data uris.
866     // FIXME: Extend this to non-images.
867     if (type == Resource::Image && request.url().protocolIsData())
868         return Use;
869
870     // If a main resource was populated from a SubstituteData load, use it.
871     if (type == Resource::MainResource && m_documentLoader->substituteData().isValid())
872         return Use;
873
874     if (!existingResource->canReuse(request))
875         return Reload;
876
877     // Never use cache entries for downloadToFile requests. The caller expects the resource in a file.
878     if (request.downloadToFile())
879         return Reload;
880
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())
885         return Reload;
886
887     // Don't reload resources while pasting.
888     if (m_allowStaleResources)
889         return Use;
890
891     // Always use preloads.
892     if (existingResource->isPreloaded())
893         return Use;
894
895     // CachePolicyHistoryBuffer uses the cache no matter what.
896     CachePolicy cachePolicy = context().cachePolicy(document());
897     if (cachePolicy == CachePolicyHistoryBuffer)
898         return Use;
899
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.");
903         return Reload;
904     }
905
906     // If fetching a resource with a different 'CORS enabled' flag, reload.
907     if (type != Resource::MainResource && options.corsEnabled != existingResource->options().corsEnabled)
908         return Reload;
909
910     // If credentials were sent with the previous request and won't be
911     // with this one, or vice versa, re-fetch the resource.
912     //
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.");
918         return Reload;
919     }
920
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()))
924         return Use;
925
926     // CachePolicyReload always reloads
927     if (cachePolicy == CachePolicyReload) {
928         WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to CachePolicyReload.");
929         return Reload;
930     }
931
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");
935         return Reload;
936     }
937
938     // For resources that are not yet loaded we ignore the cache policy.
939     if (existingResource->isLoading())
940         return Use;
941
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");
945         return Reload;
946     }
947
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())
952             return Revalidate;
953
954         // No, must reload.
955         WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to missing cache validators.");
956         return Reload;
957     }
958
959     return Use;
960 }
961
962 void ResourceFetcher::printAccessDeniedMessage(const KURL& url) const
963 {
964     if (url.isNull())
965         return;
966
967     if (!frame())
968         return;
969
970     String message;
971     if (!m_document || m_document->url().isNull())
972         message = "Unsafe attempt to load URL " + url.elidedString() + '.';
973     else
974         message = "Unsafe attempt to load URL " + url.elidedString() + " from frame with URL " + m_document->url().elidedString() + ". Domains, protocols and ports must match.\n";
975
976     frame()->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message);
977 }
978
979 void ResourceFetcher::setAutoLoadImages(bool enable)
980 {
981     if (enable == m_autoLoadImages)
982         return;
983
984     m_autoLoadImages = enable;
985
986     if (!m_autoLoadImages)
987         return;
988
989     reloadImagesIfNotDeferred();
990 }
991
992 void ResourceFetcher::setImagesEnabled(bool enable)
993 {
994     if (enable == m_imagesEnabled)
995         return;
996
997     m_imagesEnabled = enable;
998
999     if (!m_imagesEnabled)
1000         return;
1001
1002     reloadImagesIfNotDeferred();
1003 }
1004
1005 bool ResourceFetcher::clientDefersImage(const KURL& url) const
1006 {
1007     return frame() && !frame()->loader().client()->allowImage(m_imagesEnabled, url);
1008 }
1009
1010 bool ResourceFetcher::shouldDeferImageLoad(const KURL& url) const
1011 {
1012     return clientDefersImage(url) || !m_autoLoadImages;
1013 }
1014
1015 void ResourceFetcher::reloadImagesIfNotDeferred()
1016 {
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());
1022     }
1023 }
1024
1025 void ResourceFetcher::redirectReceived(Resource* resource, const ResourceResponse& redirectResponse)
1026 {
1027     ResourceTimingInfoMap::iterator it = m_resourceTimingInfoMap.find(resource);
1028     if (it != m_resourceTimingInfoMap.end())
1029         it->value->addRedirect(redirectResponse);
1030 }
1031
1032 void ResourceFetcher::didLoadResource(Resource* resource)
1033 {
1034     RefPtr<DocumentLoader> protectDocumentLoader(m_documentLoader);
1035     RefPtr<Document> protectDocument(m_document);
1036
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);
1044         }
1045     }
1046
1047     if (frame())
1048         frame()->loader().loadDone();
1049     scheduleDocumentResourcesGC();
1050 }
1051
1052 void ResourceFetcher::scheduleDocumentResourcesGC()
1053 {
1054     if (!m_garbageCollectDocumentResourcesTimer.isActive())
1055         m_garbageCollectDocumentResourcesTimer.startOneShot(0);
1056 }
1057
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)
1065 {
1066     ASSERT_UNUSED(timer, timer == &m_garbageCollectDocumentResourcesTimer);
1067     garbageCollectDocumentResources();
1068 }
1069
1070 void ResourceFetcher::garbageCollectDocumentResources()
1071 {
1072     typedef Vector<String, 10> StringVector;
1073     StringVector resourcesToDelete;
1074
1075     for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != m_documentResources.end(); ++it) {
1076         if (it->value->hasOneHandle())
1077             resourcesToDelete.append(it->key);
1078     }
1079
1080     for (StringVector::const_iterator it = resourcesToDelete.begin(); it != resourcesToDelete.end(); ++it)
1081         m_documentResources.remove(*it);
1082 }
1083
1084 void ResourceFetcher::notifyLoadedFromMemoryCache(Resource* resource)
1085 {
1086     if (!frame() || !frame()->page() || resource->status() != Resource::Cached || m_validatedURLs.contains(resource->url()))
1087         return;
1088
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());
1096 }
1097
1098 void ResourceFetcher::incrementRequestCount(const Resource* res)
1099 {
1100     if (res->ignoreForRequestCount())
1101         return;
1102
1103     ++m_requestCount;
1104 }
1105
1106 void ResourceFetcher::decrementRequestCount(const Resource* res)
1107 {
1108     if (res->ignoreForRequestCount())
1109         return;
1110
1111     --m_requestCount;
1112     ASSERT(m_requestCount > -1);
1113 }
1114
1115 void ResourceFetcher::preload(Resource::Type type, FetchRequest& request, const String& charset)
1116 {
1117     requestPreload(type, request, charset);
1118 }
1119
1120 void ResourceFetcher::requestPreload(Resource::Type type, FetchRequest& request, const String& charset)
1121 {
1122     String encoding;
1123     if (type == Resource::Script || type == Resource::CSSStyleSheet)
1124         encoding = charset.isEmpty() ? m_document->charset().string() : charset;
1125
1126     request.setCharset(encoding);
1127     request.setForPreload(true);
1128
1129     ResourcePtr<Resource> resource = requestResource(type, request);
1130     if (!resource || (m_preloads && m_preloads->contains(resource.get())))
1131         return;
1132     TRACE_EVENT_ASYNC_STEP_INTO0("net", "Resource", resource.get(), "Preload");
1133     resource->increasePreloadCount();
1134
1135     if (!m_preloads)
1136         m_preloads = adoptPtr(new ListHashSet<Resource*>);
1137     m_preloads->add(resource.get());
1138
1139 #if PRELOAD_DEBUG
1140     printf("PRELOADING %s\n",  resource->url().string().latin1().data());
1141 #endif
1142 }
1143
1144 bool ResourceFetcher::isPreloaded(const String& urlString) const
1145 {
1146     const KURL& url = m_document->completeURL(urlString);
1147
1148     if (m_preloads) {
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)
1153                 return true;
1154         }
1155     }
1156
1157     return false;
1158 }
1159
1160 void ResourceFetcher::clearPreloads()
1161 {
1162 #if PRELOAD_DEBUG
1163     printPreloadStats();
1164 #endif
1165     if (!m_preloads)
1166         return;
1167
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);
1175     }
1176     m_preloads.clear();
1177 }
1178
1179 void ResourceFetcher::didFinishLoading(const Resource* resource, double finishTime, int64_t encodedDataLength)
1180 {
1181     TRACE_EVENT_ASYNC_END0("net", "Resource", resource);
1182     context().dispatchDidFinishLoading(m_documentLoader, resource->identifier(), finishTime, encodedDataLength);
1183 }
1184
1185 void ResourceFetcher::didChangeLoadingPriority(const Resource* resource, ResourceLoadPriority loadPriority)
1186 {
1187     TRACE_EVENT_ASYNC_STEP_INTO1("net", "Resource", resource, "ChangePriority", "priority", loadPriority);
1188     context().dispatchDidChangeResourcePriority(resource->identifier(), loadPriority);
1189 }
1190
1191 void ResourceFetcher::didFailLoading(const Resource* resource, const ResourceError& error)
1192 {
1193     TRACE_EVENT_ASYNC_END0("net", "Resource", resource);
1194     context().dispatchDidFail(m_documentLoader, resource->identifier(), error);
1195 }
1196
1197 void ResourceFetcher::willSendRequest(unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse, const FetchInitiatorInfo& initiatorInfo)
1198 {
1199     context().dispatchWillSendRequest(m_documentLoader, identifier, request, redirectResponse, initiatorInfo);
1200 }
1201
1202 void ResourceFetcher::didReceiveResponse(const Resource* resource, const ResourceResponse& response)
1203 {
1204     context().dispatchDidReceiveResponse(m_documentLoader, resource->identifier(), response, resource->loader());
1205 }
1206
1207 void ResourceFetcher::didReceiveData(const Resource* resource, const char* data, int dataLength, int encodedDataLength)
1208 {
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);
1213 }
1214
1215 void ResourceFetcher::didDownloadData(const Resource* resource, int dataLength, int encodedDataLength)
1216 {
1217     InspectorInstrumentationCookie cookie = InspectorInstrumentation::willReceiveResourceData(frame(), resource->identifier(), encodedDataLength);
1218     context().dispatchDidDownloadData(m_documentLoader, resource->identifier(), dataLength, encodedDataLength);
1219     InspectorInstrumentation::didReceiveResourceData(cookie);
1220 }
1221
1222 void ResourceFetcher::subresourceLoaderFinishedLoadingOnePart(ResourceLoader* loader)
1223 {
1224     if (m_multipartLoaders)
1225         m_multipartLoaders->add(loader);
1226     if (m_loaders)
1227         m_loaders->remove(loader);
1228     if (Frame* frame = this->frame())
1229         return frame->loader().checkLoadComplete(m_documentLoader);
1230 }
1231
1232 void ResourceFetcher::didInitializeResourceLoader(ResourceLoader* loader)
1233 {
1234     if (!m_document)
1235         return;
1236     if (!m_loaders)
1237         m_loaders = adoptPtr(new ResourceLoaderSet());
1238     ASSERT(!m_loaders->contains(loader));
1239     m_loaders->add(loader);
1240 }
1241
1242 void ResourceFetcher::willTerminateResourceLoader(ResourceLoader* loader)
1243 {
1244     if (!m_loaders || !m_loaders->contains(loader))
1245         return;
1246     m_loaders->remove(loader);
1247     if (Frame* frame = this->frame())
1248         frame->loader().checkLoadComplete(m_documentLoader);
1249 }
1250
1251 void ResourceFetcher::willStartLoadingResource(ResourceRequest& request)
1252 {
1253     if (m_documentLoader)
1254         m_documentLoader->applicationCacheHost()->willStartLoadingResource(request);
1255 }
1256
1257 void ResourceFetcher::stopFetching()
1258 {
1259     if (m_multipartLoaders)
1260         m_multipartLoaders->cancelAll();
1261     if (m_loaders)
1262         m_loaders->cancelAll();
1263 }
1264
1265 bool ResourceFetcher::isFetching() const
1266 {
1267     return m_loaders && !m_loaders->isEmpty();
1268 }
1269
1270 void ResourceFetcher::setDefersLoading(bool defers)
1271 {
1272     if (m_loaders)
1273         m_loaders->setAllDefersLoading(defers);
1274 }
1275
1276 bool ResourceFetcher::defersLoading() const
1277 {
1278     if (Frame* frame = this->frame())
1279         return frame->page()->defersLoading();
1280     return false;
1281 }
1282
1283 bool ResourceFetcher::isLoadedBy(ResourceLoaderHost* possibleOwner) const
1284 {
1285     return this == possibleOwner;
1286 }
1287
1288 bool ResourceFetcher::canAccessRedirect(Resource* resource, ResourceRequest& request, const ResourceResponse& redirectResponse, ResourceLoaderOptions& options)
1289 {
1290     if (!canRequest(resource->type(), request.url(), options, false, FetchRequest::UseDefaultOriginRestrictionForType))
1291         return false;
1292     if (options.corsEnabled == IsCORSEnabled) {
1293         SecurityOrigin* sourceOrigin = options.securityOrigin.get();
1294         if (!sourceOrigin && document())
1295             sourceOrigin = document()->securityOrigin();
1296
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);
1301             return false;
1302         }
1303     }
1304     if (resource->type() == Resource::Image && shouldDeferImageLoad(request.url()))
1305         return false;
1306     return true;
1307 }
1308
1309 void ResourceFetcher::refResourceLoaderHost()
1310 {
1311     ref();
1312 }
1313
1314 void ResourceFetcher::derefResourceLoaderHost()
1315 {
1316     deref();
1317 }
1318
1319 #if PRELOAD_DEBUG
1320 void ResourceFetcher::printPreloadStats()
1321 {
1322     if (!m_preloads)
1323         return;
1324
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());
1340
1341         if (res->type() == Resource::Script) {
1342             scripts++;
1343             if (res->preloadResult() < Resource::PreloadReferencedWhileLoading)
1344                 scriptMisses++;
1345         } else if (res->type() == Resource::CSSStyleSheet) {
1346             stylesheets++;
1347             if (res->preloadResult() < Resource::PreloadReferencedWhileLoading)
1348                 stylesheetMisses++;
1349         } else {
1350             images++;
1351             if (res->preloadResult() < Resource::PreloadReferencedWhileLoading)
1352                 imageMisses++;
1353         }
1354
1355         if (res->errorOccurred())
1356             memoryCache()->remove(res);
1357
1358         res->decreasePreloadCount();
1359     }
1360     m_preloads.clear();
1361
1362     if (scripts)
1363         printf("SCRIPTS: %d (%d hits, hit rate %d%%)\n", scripts, scripts - scriptMisses, (scripts - scriptMisses) * 100 / scripts);
1364     if (stylesheets)
1365         printf("STYLESHEETS: %d (%d hits, hit rate %d%%)\n", stylesheets, stylesheets - stylesheetMisses, (stylesheets - stylesheetMisses) * 100 / stylesheets);
1366     if (images)
1367         printf("IMAGES:  %d (%d hits, hit rate %d%%)\n", images, images - imageMisses, (images - imageMisses) * 100 / images);
1368 }
1369 #endif
1370
1371 const ResourceLoaderOptions& ResourceFetcher::defaultResourceOptions()
1372 {
1373     DEFINE_STATIC_LOCAL(ResourceLoaderOptions, options, (SniffContent, BufferData, AllowStoredCredentials, ClientRequestedCredentials, CheckContentSecurityPolicy, DocumentContext));
1374     return options;
1375 }
1376
1377 ResourceFetcher::DeadResourceStatsRecorder::DeadResourceStatsRecorder()
1378     : m_useCount(0)
1379     , m_revalidateCount(0)
1380     , m_loadCount(0)
1381 {
1382 }
1383
1384 ResourceFetcher::DeadResourceStatsRecorder::~DeadResourceStatsRecorder()
1385 {
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);
1392 }
1393
1394 void ResourceFetcher::DeadResourceStatsRecorder::update(RevalidationPolicy policy)
1395 {
1396     switch (policy) {
1397     case Reload:
1398     case Load:
1399         ++m_loadCount;
1400         return;
1401     case Revalidate:
1402         ++m_revalidateCount;
1403         return;
1404     case Use:
1405         ++m_useCount;
1406         return;
1407     }
1408 }
1409
1410 }