1 /* 2 Copyright (C) 1998 Lars Knoll (knoll (at) mpi-hd.mpg.de) 3 Copyright (C) 2001 Dirk Mueller (mueller (at) kde.org) 4 Copyright (C) 2002 Waldo Bastian (bastian (at) 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/loader/cache/ResourceFetcher.h" 29 30 #include "bindings/v8/ScriptController.h" 31 #include "core/dom/Document.h" 32 #include "core/html/HTMLElement.h" 33 #include "core/html/HTMLFrameOwnerElement.h" 34 #include "core/html/HTMLImport.h" 35 #include "core/inspector/InspectorInstrumentation.h" 36 #include "core/loader/DocumentLoader.h" 37 #include "core/loader/FrameLoader.h" 38 #include "core/loader/FrameLoaderClient.h" 39 #include "core/loader/PingLoader.h" 40 #include "core/loader/UniqueIdentifier.h" 41 #include "core/loader/appcache/ApplicationCacheHost.h" 42 #include "core/loader/cache/CSSStyleSheetResource.h" 43 #include "core/loader/cache/DocumentResource.h" 44 #include "core/loader/cache/FetchRequest.h" 45 #include "core/loader/cache/FontResource.h" 46 #include "core/loader/cache/ImageResource.h" 47 #include "core/loader/cache/MemoryCache.h" 48 #include "core/loader/cache/RawResource.h" 49 #include "core/loader/cache/ScriptResource.h" 50 #include "core/loader/cache/ShaderResource.h" 51 #include "core/loader/cache/TextTrackResource.h" 52 #include "core/loader/cache/XSLStyleSheetResource.h" 53 #include "core/page/ContentSecurityPolicy.h" 54 #include "core/page/DOMWindow.h" 55 #include "core/page/Frame.h" 56 #include "core/page/Performance.h" 57 #include "core/page/ResourceTimingInfo.h" 58 #include "core/page/Settings.h" 59 #include "core/platform/Logging.h" 60 #include "core/platform/chromium/TraceEvent.h" 61 #include "public/platform/Platform.h" 62 #include "public/platform/WebURL.h" 63 #include "weborigin/SecurityOrigin.h" 64 #include "weborigin/SecurityPolicy.h" 65 #include "wtf/text/CString.h" 66 #include "wtf/text/WTFString.h" 67 68 #define PRELOAD_DEBUG 0 69 70 namespace WebCore { 71 72 static Resource* createResource(Resource::Type type, const ResourceRequest& request, const String& charset) 73 { 74 switch (type) { 75 case Resource::Image: 76 return new ImageResource(request); 77 case Resource::CSSStyleSheet: 78 return new CSSStyleSheetResource(request, charset); 79 case Resource::Script: 80 return new ScriptResource(request, charset); 81 case Resource::SVGDocument: 82 return new DocumentResource(request, Resource::SVGDocument); 83 case Resource::Font: 84 return new FontResource(request); 85 case Resource::Raw: 86 case Resource::MainResource: 87 return new RawResource(request, type); 88 case Resource::XSLStyleSheet: 89 return new XSLStyleSheetResource(request); 90 case Resource::LinkPrefetch: 91 return new Resource(request, Resource::LinkPrefetch); 92 case Resource::LinkSubresource: 93 return new Resource(request, Resource::LinkSubresource); 94 case Resource::TextTrack: 95 return new TextTrackResource(request); 96 case Resource::Shader: 97 return new ShaderResource(request); 98 case Resource::ImportResource: 99 return new RawResource(request, type); 100 } 101 102 ASSERT_NOT_REACHED(); 103 return 0; 104 } 105 106 static ResourceLoadPriority loadPriority(Resource::Type type, const FetchRequest& request) 107 { 108 if (request.priority() != ResourceLoadPriorityUnresolved) 109 return request.priority(); 110 111 switch (type) { 112 case Resource::MainResource: 113 return ResourceLoadPriorityVeryHigh; 114 case Resource::CSSStyleSheet: 115 return ResourceLoadPriorityHigh; 116 case Resource::Script: 117 case Resource::Font: 118 case Resource::Raw: 119 case Resource::ImportResource: 120 return ResourceLoadPriorityMedium; 121 case Resource::Image: 122 return request.forPreload() ? ResourceLoadPriorityVeryLow : ResourceLoadPriorityLow; 123 case Resource::XSLStyleSheet: 124 return ResourceLoadPriorityHigh; 125 case Resource::SVGDocument: 126 return ResourceLoadPriorityLow; 127 case Resource::LinkPrefetch: 128 return ResourceLoadPriorityVeryLow; 129 case Resource::LinkSubresource: 130 return ResourceLoadPriorityLow; 131 case Resource::TextTrack: 132 return ResourceLoadPriorityLow; 133 case Resource::Shader: 134 return ResourceLoadPriorityMedium; 135 } 136 ASSERT_NOT_REACHED(); 137 return ResourceLoadPriorityUnresolved; 138 } 139 140 static Resource* resourceFromDataURIRequest(const ResourceRequest& request) 141 { 142 const KURL& url = request.url(); 143 ASSERT(url.protocolIsData()); 144 145 WebKit::WebString mimetype; 146 WebKit::WebString charset; 147 RefPtr<SharedBuffer> data = PassRefPtr<SharedBuffer>(WebKit::Platform::current()->parseDataURL(url, mimetype, charset)); 148 if (!data) 149 return 0; 150 ResourceResponse response(url, mimetype, data->size(), charset, String()); 151 152 Resource* resource = createResource(Resource::Image, request, charset); 153 resource->responseReceived(response); 154 // FIXME: AppendData causes an unnecessary memcpy. 155 if (data->size()) 156 resource->appendData(data->data(), data->size()); 157 resource->finish(); 158 return resource; 159 } 160 161 ResourceFetcher::ResourceFetcher(DocumentLoader* documentLoader) 162 : m_document(0) 163 , m_documentLoader(documentLoader) 164 , m_requestCount(0) 165 , m_garbageCollectDocumentResourcesTimer(this, &ResourceFetcher::garbageCollectDocumentResourcesTimerFired) 166 , m_autoLoadImages(true) 167 , m_imagesEnabled(true) 168 , m_allowStaleResources(false) 169 { 170 } 171 172 ResourceFetcher::~ResourceFetcher() 173 { 174 m_documentLoader = 0; 175 m_document = 0; 176 177 clearPreloads(); 178 179 // Make sure no requests still point to this ResourceFetcher 180 ASSERT(!m_requestCount); 181 } 182 183 Resource* ResourceFetcher::cachedResource(const String& resourceURL) const 184 { 185 KURL url = m_document->completeURL(resourceURL); 186 return cachedResource(url); 187 } 188 189 Resource* ResourceFetcher::cachedResource(const KURL& resourceURL) const 190 { 191 KURL url = MemoryCache::removeFragmentIdentifierIfNeeded(resourceURL); 192 return m_documentResources.get(url).get(); 193 } 194 195 Frame* ResourceFetcher::frame() const 196 { 197 if (m_documentLoader) 198 return m_documentLoader->frame(); 199 if (m_document && m_document->import()) 200 return m_document->import()->frame(); 201 return 0; 202 } 203 204 ResourcePtr<ImageResource> ResourceFetcher::requestImage(FetchRequest& request) 205 { 206 if (Frame* f = frame()) { 207 if (f->loader()->pageDismissalEventBeingDispatched() != FrameLoader::NoDismissal) { 208 KURL requestURL = request.resourceRequest().url(); 209 if (requestURL.isValid() && canRequest(Resource::Image, requestURL, request.options(), request.forPreload())) 210 PingLoader::loadImage(f, requestURL); 211 return 0; 212 } 213 } 214 215 if (request.resourceRequest().url().protocolIsData()) 216 preCacheDataURIImage(request); 217 218 request.setDefer(clientDefersImage(request.resourceRequest().url()) ? FetchRequest::DeferredByClient : FetchRequest::NoDefer); 219 return static_cast<ImageResource*>(requestResource(Resource::Image, request).get()); 220 } 221 222 void ResourceFetcher::preCacheDataURIImage(const FetchRequest& request) 223 { 224 const KURL& url = request.resourceRequest().url(); 225 ASSERT(url.protocolIsData()); 226 227 if (Resource* existing = memoryCache()->resourceForURL(url)) 228 return; 229 230 if (Resource* resource = resourceFromDataURIRequest(request.resourceRequest())) 231 memoryCache()->add(resource); 232 } 233 234 ResourcePtr<FontResource> ResourceFetcher::requestFont(FetchRequest& request) 235 { 236 return static_cast<FontResource*>(requestResource(Resource::Font, request).get()); 237 } 238 239 ResourcePtr<TextTrackResource> ResourceFetcher::requestTextTrack(FetchRequest& request) 240 { 241 return static_cast<TextTrackResource*>(requestResource(Resource::TextTrack, request).get()); 242 } 243 244 ResourcePtr<ShaderResource> ResourceFetcher::requestShader(FetchRequest& request) 245 { 246 return static_cast<ShaderResource*>(requestResource(Resource::Shader, request).get()); 247 } 248 249 ResourcePtr<RawResource> ResourceFetcher::requestImport(FetchRequest& request) 250 { 251 return static_cast<RawResource*>(requestResource(Resource::ImportResource, request).get()); 252 } 253 254 ResourcePtr<CSSStyleSheetResource> ResourceFetcher::requestCSSStyleSheet(FetchRequest& request) 255 { 256 return static_cast<CSSStyleSheetResource*>(requestResource(Resource::CSSStyleSheet, request).get()); 257 } 258 259 ResourcePtr<CSSStyleSheetResource> ResourceFetcher::requestUserCSSStyleSheet(FetchRequest& request) 260 { 261 KURL url = MemoryCache::removeFragmentIdentifierIfNeeded(request.resourceRequest().url()); 262 263 if (Resource* existing = memoryCache()->resourceForURL(url)) { 264 if (existing->type() == Resource::CSSStyleSheet) 265 return static_cast<CSSStyleSheetResource*>(existing); 266 memoryCache()->remove(existing); 267 } 268 269 request.setOptions(ResourceLoaderOptions(DoNotSendCallbacks, SniffContent, BufferData, AllowStoredCredentials, ClientRequestedCredentials, AskClientForCrossOriginCredentials, SkipSecurityCheck, CheckContentSecurityPolicy, UseDefaultOriginRestrictionsForType, DocumentContext)); 270 return static_cast<CSSStyleSheetResource*>(requestResource(Resource::CSSStyleSheet, request).get()); 271 } 272 273 ResourcePtr<ScriptResource> ResourceFetcher::requestScript(FetchRequest& request) 274 { 275 return static_cast<ScriptResource*>(requestResource(Resource::Script, request).get()); 276 } 277 278 ResourcePtr<XSLStyleSheetResource> ResourceFetcher::requestXSLStyleSheet(FetchRequest& request) 279 { 280 return static_cast<XSLStyleSheetResource*>(requestResource(Resource::XSLStyleSheet, request).get()); 281 } 282 283 ResourcePtr<DocumentResource> ResourceFetcher::requestSVGDocument(FetchRequest& request) 284 { 285 return static_cast<DocumentResource*>(requestResource(Resource::SVGDocument, request).get()); 286 } 287 288 ResourcePtr<Resource> ResourceFetcher::requestLinkResource(Resource::Type type, FetchRequest& request) 289 { 290 ASSERT(frame()); 291 ASSERT(type == Resource::LinkPrefetch || type == Resource::LinkSubresource); 292 return requestResource(type, request); 293 } 294 295 ResourcePtr<RawResource> ResourceFetcher::requestRawResource(FetchRequest& request) 296 { 297 return static_cast<RawResource*>(requestResource(Resource::Raw, request).get()); 298 } 299 300 ResourcePtr<RawResource> ResourceFetcher::requestMainResource(FetchRequest& request) 301 { 302 return static_cast<RawResource*>(requestResource(Resource::MainResource, request).get()); 303 } 304 305 bool ResourceFetcher::checkInsecureContent(Resource::Type type, const KURL& url) const 306 { 307 switch (type) { 308 case Resource::Script: 309 case Resource::XSLStyleSheet: 310 case Resource::SVGDocument: 311 case Resource::CSSStyleSheet: 312 case Resource::ImportResource: 313 // These resource can inject script into the current document (Script, 314 // XSL) or exfiltrate the content of the current document (CSS). 315 if (Frame* f = frame()) { 316 if (!f->loader()->mixedContentChecker()->canRunInsecureContent(m_document->securityOrigin(), url)) 317 return false; 318 } 319 320 break; 321 case Resource::TextTrack: 322 case Resource::Shader: 323 case Resource::Raw: 324 case Resource::Image: 325 case Resource::Font: { 326 // These resources can corrupt only the frame's pixels. 327 if (Frame* f = frame()) { 328 Frame* top = f->tree()->top(); 329 if (!top->loader()->mixedContentChecker()->canDisplayInsecureContent(top->document()->securityOrigin(), url)) 330 return false; 331 } 332 break; 333 } 334 case Resource::MainResource: 335 case Resource::LinkPrefetch: 336 case Resource::LinkSubresource: 337 // Prefetch cannot affect the current document. 338 break; 339 } 340 return true; 341 } 342 343 bool ResourceFetcher::canRequest(Resource::Type type, const KURL& url, const ResourceLoaderOptions& options, bool forPreload) 344 { 345 if (document() && !document()->securityOrigin()->canDisplay(url)) { 346 if (!forPreload) 347 FrameLoader::reportLocalLoadFailed(frame(), url.elidedString()); 348 LOG(ResourceLoading, "ResourceFetcher::requestResource URL was not allowed by SecurityOrigin::canDisplay"); 349 return 0; 350 } 351 352 // FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved. 353 bool shouldBypassMainWorldContentSecurityPolicy = (frame() && frame()->script()->shouldBypassMainWorldContentSecurityPolicy()) || (options.contentSecurityPolicyOption == DoNotCheckContentSecurityPolicy); 354 355 // Some types of resources can be loaded only from the same origin. Other 356 // types of resources, like Images, Scripts, and CSS, can be loaded from 357 // any URL. 358 switch (type) { 359 case Resource::MainResource: 360 case Resource::Image: 361 case Resource::CSSStyleSheet: 362 case Resource::Script: 363 case Resource::Font: 364 case Resource::Raw: 365 case Resource::LinkPrefetch: 366 case Resource::LinkSubresource: 367 case Resource::TextTrack: 368 case Resource::Shader: 369 case Resource::ImportResource: 370 // By default these types of resources can be loaded from any origin. 371 // FIXME: Are we sure about Resource::Font? 372 if (options.requestOriginPolicy == RestrictToSameOrigin && !m_document->securityOrigin()->canRequest(url)) { 373 printAccessDeniedMessage(url); 374 return false; 375 } 376 break; 377 case Resource::SVGDocument: 378 case Resource::XSLStyleSheet: 379 if (!m_document->securityOrigin()->canRequest(url)) { 380 printAccessDeniedMessage(url); 381 return false; 382 } 383 break; 384 } 385 386 switch (type) { 387 case Resource::XSLStyleSheet: 388 if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowScriptFromSource(url)) 389 return false; 390 break; 391 case Resource::Script: 392 case Resource::ImportResource: 393 if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowScriptFromSource(url)) 394 return false; 395 396 if (frame()) { 397 Settings* settings = frame()->settings(); 398 if (!frame()->loader()->client()->allowScriptFromSource(!settings || settings->isScriptEnabled(), url)) { 399 frame()->loader()->client()->didNotAllowScript(); 400 return false; 401 } 402 } 403 break; 404 case Resource::Shader: 405 // Since shaders are referenced from CSS Styles use the same rules here. 406 case Resource::CSSStyleSheet: 407 if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowStyleFromSource(url)) 408 return false; 409 break; 410 case Resource::SVGDocument: 411 case Resource::Image: 412 if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowImageFromSource(url)) 413 return false; 414 break; 415 case Resource::Font: { 416 if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowFontFromSource(url)) 417 return false; 418 break; 419 } 420 case Resource::MainResource: 421 case Resource::Raw: 422 case Resource::LinkPrefetch: 423 case Resource::LinkSubresource: 424 break; 425 case Resource::TextTrack: 426 // Cues aren't called out in the CPS spec yet, but they only work with a media element 427 // so use the media policy. 428 if (!shouldBypassMainWorldContentSecurityPolicy && !m_document->contentSecurityPolicy()->allowMediaFromSource(url)) 429 return false; 430 break; 431 } 432 433 // Last of all, check for insecure content. We do this last so that when 434 // folks block insecure content with a CSP policy, they don't get a warning. 435 // They'll still get a warning in the console about CSP blocking the load. 436 437 // FIXME: Should we consider forPreload here? 438 if (!checkInsecureContent(type, url)) 439 return false; 440 441 return true; 442 } 443 444 bool ResourceFetcher::canAccess(Resource* resource) 445 { 446 // Redirects can change the response URL different from one of request. 447 if (!canRequest(resource->type(), resource->response().url(), resource->options(), false)) 448 return false; 449 450 String error; 451 switch (resource->type()) { 452 case Resource::Script: 453 case Resource::ImportResource: 454 if (resource->options().requestOriginPolicy == PotentiallyCrossOriginEnabled 455 && !m_document->securityOrigin()->canRequest(resource->response().url()) 456 && !resource->passesAccessControlCheck(m_document->securityOrigin(), error)) { 457 if (frame() && frame()->document()) 458 frame()->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Script from origin '" + SecurityOrigin::create(resource->response().url())->toString() + "' has been blocked from loading by Cross-Origin Resource Sharing policy: " + error); 459 return false; 460 } 461 462 break; 463 default: 464 ASSERT_NOT_REACHED(); // FIXME: generalize to non-script resources 465 return false; 466 } 467 468 return true; 469 } 470 471 bool ResourceFetcher::shouldLoadNewResource() const 472 { 473 if (!frame()) 474 return false; 475 if (m_documentLoader) { 476 if (m_documentLoader != frame()->loader()->activeDocumentLoader()) 477 return false; 478 if (m_documentLoader->isStopping()) 479 return false; 480 } 481 482 return true; 483 } 484 485 ResourcePtr<Resource> ResourceFetcher::requestResource(Resource::Type type, FetchRequest& request) 486 { 487 KURL url = request.resourceRequest().url(); 488 489 LOG(ResourceLoading, "ResourceFetcher::requestResource '%s', charset '%s', priority=%d, forPreload=%u", url.elidedString().latin1().data(), request.charset().latin1().data(), request.priority(), request.forPreload()); 490 491 // If only the fragment identifiers differ, it is the same resource. 492 url = MemoryCache::removeFragmentIdentifierIfNeeded(url); 493 494 if (!url.isValid()) 495 return 0; 496 497 if (!canRequest(type, url, request.options(), request.forPreload())) 498 return 0; 499 500 if (Frame* f = frame()) 501 f->loader()->client()->dispatchWillRequestResource(&request); 502 503 // See if we can use an existing resource from the cache. 504 ResourcePtr<Resource> resource = memoryCache()->resourceForURL(url); 505 506 const RevalidationPolicy policy = determineRevalidationPolicy(type, request.mutableResourceRequest(), request.forPreload(), resource.get(), request.defer()); 507 switch (policy) { 508 case Reload: 509 memoryCache()->remove(resource.get()); 510 // Fall through 511 case Load: 512 resource = loadResource(type, request, request.charset()); 513 break; 514 case Revalidate: 515 resource = revalidateResource(request, resource.get()); 516 break; 517 case Use: 518 resource->updateForAccess(); 519 notifyLoadedFromMemoryCache(resource.get()); 520 break; 521 } 522 523 if (!resource) 524 return 0; 525 526 if (policy != Use) 527 resource->setIdentifier(createUniqueIdentifier()); 528 529 if (!request.forPreload() || policy != Use) { 530 ResourceLoadPriority priority = loadPriority(type, request); 531 if (priority != resource->resourceRequest().priority()) { 532 resource->resourceRequest().setPriority(priority); 533 resource->didChangePriority(priority); 534 } 535 } 536 537 if ((policy != Use || resource->stillNeedsLoad()) && FetchRequest::NoDefer == request.defer()) { 538 if (!shouldLoadNewResource()) { 539 if (resource->inCache()) 540 memoryCache()->remove(resource.get()); 541 return 0; 542 } 543 544 if (!m_documentLoader || !m_documentLoader->scheduleArchiveLoad(resource.get(), request.resourceRequest())) 545 resource->load(this, request.options()); 546 547 // We don't support immediate loads, but we do support immediate failure. 548 if (resource->errorOccurred()) { 549 if (resource->inCache()) 550 memoryCache()->remove(resource.get()); 551 return 0; 552 } 553 } 554 555 // FIXME: Temporarily leave main resource caching disabled for chromium, 556 // see https://bugs.webkit.org/show_bug.cgi?id=107962. Before caching main 557 // resources, we should be sure to understand the implications for memory 558 // use. 559 // 560 // Ensure main resources aren't preloaded, and other main resource loads 561 // are removed from cache to prevent reuse. 562 if (type == Resource::MainResource) { 563 ASSERT(policy != Use); 564 ASSERT(policy != Revalidate); 565 memoryCache()->remove(resource.get()); 566 if (request.forPreload()) 567 return 0; 568 } 569 570 if (!request.resourceRequest().url().protocolIsData()) 571 m_validatedURLs.add(request.resourceRequest().url()); 572 573 ASSERT(resource->url() == url.string()); 574 m_documentResources.set(resource->url(), resource); 575 return resource; 576 } 577 578 void ResourceFetcher::determineTargetType(ResourceRequest& request, Resource::Type type) 579 { 580 ResourceRequest::TargetType targetType; 581 582 switch (type) { 583 case Resource::MainResource: 584 if (frame()->tree()->parent()) 585 targetType = ResourceRequest::TargetIsSubframe; 586 else 587 targetType = ResourceRequest::TargetIsMainFrame; 588 break; 589 case Resource::CSSStyleSheet: 590 case Resource::XSLStyleSheet: 591 targetType = ResourceRequest::TargetIsStyleSheet; 592 break; 593 case Resource::Script: 594 targetType = ResourceRequest::TargetIsScript; 595 break; 596 case Resource::Font: 597 targetType = ResourceRequest::TargetIsFont; 598 break; 599 case Resource::Image: 600 targetType = ResourceRequest::TargetIsImage; 601 break; 602 case Resource::Shader: 603 case Resource::Raw: 604 case Resource::ImportResource: 605 targetType = ResourceRequest::TargetIsSubresource; 606 break; 607 case Resource::LinkPrefetch: 608 targetType = ResourceRequest::TargetIsPrefetch; 609 break; 610 case Resource::LinkSubresource: 611 targetType = ResourceRequest::TargetIsSubresource; 612 break; 613 case Resource::TextTrack: 614 targetType = ResourceRequest::TargetIsTextTrack; 615 break; 616 case Resource::SVGDocument: 617 targetType = ResourceRequest::TargetIsImage; 618 break; 619 default: 620 ASSERT_NOT_REACHED(); 621 targetType = ResourceRequest::TargetIsSubresource; 622 break; 623 } 624 request.setTargetType(targetType); 625 } 626 627 ResourceRequestCachePolicy ResourceFetcher::resourceRequestCachePolicy(const ResourceRequest& request, Resource::Type type) 628 { 629 if (type == Resource::MainResource) { 630 FrameLoadType frameLoadType = frame()->loader()->loadType(); 631 bool isReload = frameLoadType == FrameLoadTypeReload || frameLoadType == FrameLoadTypeReloadFromOrigin; 632 if (request.httpMethod() == "POST" && frameLoadType == FrameLoadTypeBackForward) 633 return ReturnCacheDataDontLoad; 634 if (!m_documentLoader->overrideEncoding().isEmpty() || frameLoadType == FrameLoadTypeBackForward) 635 return ReturnCacheDataElseLoad; 636 if (isReload || frameLoadType == FrameLoadTypeSame || request.isConditional()) 637 return ReloadIgnoringCacheData; 638 return UseProtocolCachePolicy; 639 } 640 641 if (request.isConditional()) 642 return ReloadIgnoringCacheData; 643 644 if (m_documentLoader && m_documentLoader->isLoadingInAPISense()) { 645 // For POST requests, we mutate the main resource's cache policy to avoid form resubmission. 646 // This policy should not be inherited by subresources. 647 ResourceRequestCachePolicy mainResourceCachePolicy = m_documentLoader->request().cachePolicy(); 648 if (mainResourceCachePolicy == ReturnCacheDataDontLoad) 649 return ReturnCacheDataElseLoad; 650 return mainResourceCachePolicy; 651 } 652 return UseProtocolCachePolicy; 653 } 654 655 void ResourceFetcher::addAdditionalRequestHeaders(ResourceRequest& request, Resource::Type type) 656 { 657 if (!frame()) 658 return; 659 660 bool isMainResource = type == Resource::MainResource; 661 662 FrameLoader* frameLoader = frame()->loader(); 663 664 if (!isMainResource) { 665 String outgoingReferrer; 666 String outgoingOrigin; 667 if (request.httpReferrer().isNull()) { 668 outgoingReferrer = frameLoader->outgoingReferrer(); 669 outgoingOrigin = frameLoader->outgoingOrigin(); 670 } else { 671 outgoingReferrer = request.httpReferrer(); 672 outgoingOrigin = SecurityOrigin::createFromString(outgoingReferrer)->toString(); 673 } 674 675 outgoingReferrer = SecurityPolicy::generateReferrerHeader(document()->referrerPolicy(), request.url(), outgoingReferrer); 676 if (outgoingReferrer.isEmpty()) 677 request.clearHTTPReferrer(); 678 else if (!request.httpReferrer()) 679 request.setHTTPReferrer(outgoingReferrer); 680 681 FrameLoader::addHTTPOriginIfNeeded(request, outgoingOrigin); 682 } 683 684 if (request.cachePolicy() == UseProtocolCachePolicy) 685 request.setCachePolicy(resourceRequestCachePolicy(request, type)); 686 if (request.targetType() == ResourceRequest::TargetIsUnspecified) 687 determineTargetType(request, type); 688 if (type == Resource::LinkPrefetch || type == Resource::LinkSubresource) 689 request.setHTTPHeaderField("Purpose", "prefetch"); 690 frameLoader->addExtraFieldsToRequest(request); 691 } 692 693 ResourcePtr<Resource> ResourceFetcher::revalidateResource(const FetchRequest& request, Resource* resource) 694 { 695 ASSERT(resource); 696 ASSERT(resource->inCache()); 697 ASSERT(resource->isLoaded()); 698 ASSERT(resource->canUseCacheValidator()); 699 ASSERT(!resource->resourceToRevalidate()); 700 701 ResourceRequest revalidatingRequest(resource->resourceRequest()); 702 addAdditionalRequestHeaders(revalidatingRequest, resource->type()); 703 704 const String& lastModified = resource->response().httpHeaderField("Last-Modified"); 705 const String& eTag = resource->response().httpHeaderField("ETag"); 706 if (!lastModified.isEmpty() || !eTag.isEmpty()) { 707 ASSERT(cachePolicy(resource->type()) != CachePolicyReload); 708 if (cachePolicy(resource->type()) == CachePolicyRevalidate) 709 revalidatingRequest.setHTTPHeaderField("Cache-Control", "max-age=0"); 710 if (!lastModified.isEmpty()) 711 revalidatingRequest.setHTTPHeaderField("If-Modified-Since", lastModified); 712 if (!eTag.isEmpty()) 713 revalidatingRequest.setHTTPHeaderField("If-None-Match", eTag); 714 } 715 716 ResourcePtr<Resource> newResource = createResource(resource->type(), revalidatingRequest, resource->encoding()); 717 718 LOG(ResourceLoading, "Resource %p created to revalidate %p", newResource.get(), resource); 719 newResource->setResourceToRevalidate(resource); 720 721 memoryCache()->remove(resource); 722 memoryCache()->add(newResource.get()); 723 storeResourceTimingInitiatorInformation(newResource, request); 724 TRACE_EVENT_ASYNC_BEGIN2("net", "Resource", newResource.get(), "url", newResource->url().string().ascii(), "priority", newResource->resourceRequest().priority()); 725 return newResource; 726 } 727 728 ResourcePtr<Resource> ResourceFetcher::loadResource(Resource::Type type, FetchRequest& request, const String& charset) 729 { 730 ASSERT(!memoryCache()->resourceForURL(request.resourceRequest().url())); 731 732 LOG(ResourceLoading, "Loading Resource for '%s'.", request.resourceRequest().url().elidedString().latin1().data()); 733 734 addAdditionalRequestHeaders(request.mutableResourceRequest(), type); 735 ResourcePtr<Resource> resource = createResource(type, request.mutableResourceRequest(), charset); 736 737 memoryCache()->add(resource.get()); 738 storeResourceTimingInitiatorInformation(resource, request); 739 TRACE_EVENT_ASYNC_BEGIN2("net", "Resource", resource.get(), "url", resource->url().string().ascii(), "priority", resource->resourceRequest().priority()); 740 return resource; 741 } 742 743 void ResourceFetcher::storeResourceTimingInitiatorInformation(const ResourcePtr<Resource>& resource, const FetchRequest& request) 744 { 745 if (request.options().requestInitiatorContext != DocumentContext) 746 return; 747 748 RefPtr<ResourceTimingInfo> info = ResourceTimingInfo::create(request.options().initiatorInfo.name, monotonicallyIncreasingTime()); 749 750 if (resource->type() == Resource::MainResource) { 751 // <iframe>s should report the initial navigation requested by the parent document, but not subsequent navigations. 752 if (frame()->ownerElement() && !frame()->ownerElement()->loadedNonEmptyDocument()) { 753 info->setInitiatorType(frame()->ownerElement()->localName()); 754 m_resourceTimingInfoMap.add(resource.get(), info); 755 frame()->ownerElement()->didLoadNonEmptyDocument(); 756 } 757 } else { 758 m_resourceTimingInfoMap.add(resource.get(), info); 759 } 760 } 761 762 ResourceFetcher::RevalidationPolicy ResourceFetcher::determineRevalidationPolicy(Resource::Type type, ResourceRequest& request, bool forPreload, Resource* existingResource, FetchRequest::DeferOption defer) const 763 { 764 if (!existingResource) 765 return Load; 766 767 // We already have a preload going for this URL. 768 if (forPreload && existingResource->isPreloaded()) 769 return Use; 770 771 // If the same URL has been loaded as a different type, we need to reload. 772 if (existingResource->type() != type) { 773 LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to type mismatch."); 774 return Reload; 775 } 776 777 // Do not load from cache if images are not enabled. The load for this image will be blocked 778 // in ImageResource::load. 779 if (FetchRequest::DeferredByClient == defer) 780 return Reload; 781 782 // Always use data uris. 783 // FIXME: Extend this to non-images. 784 if (type == Resource::Image && request.url().protocolIsData()) 785 return Use; 786 787 if (!existingResource->canReuse(request)) 788 return Reload; 789 790 // Certain requests (e.g., XHRs) might have manually set headers that require revalidation. 791 // FIXME: In theory, this should be a Revalidate case. In practice, the MemoryCache revalidation path assumes a whole bunch 792 // of things about how revalidation works that manual headers violate, so punt to Reload instead. 793 if (request.isConditional()) 794 return Reload; 795 796 // Don't reload resources while pasting. 797 if (m_allowStaleResources) 798 return Use; 799 800 // Alwaus use preloads. 801 if (existingResource->isPreloaded()) 802 return Use; 803 804 // CachePolicyHistoryBuffer uses the cache no matter what. 805 if (cachePolicy(type) == CachePolicyHistoryBuffer) 806 return Use; 807 808 // Don't reuse resources with Cache-control: no-store. 809 if (existingResource->response().cacheControlContainsNoStore()) { 810 LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to Cache-control: no-store."); 811 return Reload; 812 } 813 814 // If credentials were sent with the previous request and won't be 815 // with this one, or vice versa, re-fetch the resource. 816 // 817 // This helps with the case where the server sends back 818 // "Access-Control-Allow-Origin: *" all the time, but some of the 819 // client's requests are made without CORS and some with. 820 if (existingResource->resourceRequest().allowCookies() != request.allowCookies()) { 821 LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to difference in credentials settings."); 822 return Reload; 823 } 824 825 // During the initial load, avoid loading the same resource multiple times for a single document, even if the cache policies would tell us to. 826 if (document() && !document()->loadEventFinished() && m_validatedURLs.contains(existingResource->url())) 827 return Use; 828 829 // CachePolicyReload always reloads 830 if (cachePolicy(type) == CachePolicyReload) { 831 LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to CachePolicyReload."); 832 return Reload; 833 } 834 835 // We'll try to reload the resource if it failed last time. 836 if (existingResource->errorOccurred()) { 837 LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicye reloading due to resource being in the error state"); 838 return Reload; 839 } 840 841 // For resources that are not yet loaded we ignore the cache policy. 842 if (existingResource->isLoading()) 843 return Use; 844 845 // Check if the cache headers requires us to revalidate (cache expiration for example). 846 if (existingResource->mustRevalidateDueToCacheHeaders(cachePolicy(type))) { 847 // See if the resource has usable ETag or Last-modified headers. 848 if (existingResource->canUseCacheValidator()) 849 return Revalidate; 850 851 // No, must reload. 852 LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to missing cache validators."); 853 return Reload; 854 } 855 856 return Use; 857 } 858 859 void ResourceFetcher::printAccessDeniedMessage(const KURL& url) const 860 { 861 if (url.isNull()) 862 return; 863 864 if (!frame()) 865 return; 866 867 String message; 868 if (!m_document || m_document->url().isNull()) 869 message = "Unsafe attempt to load URL " + url.elidedString() + '.'; 870 else 871 message = "Unsafe attempt to load URL " + url.elidedString() + " from frame with URL " + m_document->url().elidedString() + ". Domains, protocols and ports must match.\n"; 872 873 frame()->document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message); 874 } 875 876 void ResourceFetcher::setAutoLoadImages(bool enable) 877 { 878 if (enable == m_autoLoadImages) 879 return; 880 881 m_autoLoadImages = enable; 882 883 if (!m_autoLoadImages) 884 return; 885 886 reloadImagesIfNotDeferred(); 887 } 888 889 void ResourceFetcher::setImagesEnabled(bool enable) 890 { 891 if (enable == m_imagesEnabled) 892 return; 893 894 m_imagesEnabled = enable; 895 896 if (!m_imagesEnabled) 897 return; 898 899 reloadImagesIfNotDeferred(); 900 } 901 902 bool ResourceFetcher::clientDefersImage(const KURL& url) const 903 { 904 return frame() && !frame()->loader()->client()->allowImage(m_imagesEnabled, url); 905 } 906 907 bool ResourceFetcher::shouldDeferImageLoad(const KURL& url) const 908 { 909 return clientDefersImage(url) || !m_autoLoadImages; 910 } 911 912 void ResourceFetcher::reloadImagesIfNotDeferred() 913 { 914 DocumentResourceMap::iterator end = m_documentResources.end(); 915 for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != end; ++it) { 916 Resource* resource = it->value.get(); 917 if (resource->type() == Resource::Image && resource->stillNeedsLoad() && !clientDefersImage(resource->url())) 918 const_cast<Resource*>(resource)->load(this, defaultResourceOptions()); 919 } 920 } 921 922 CachePolicy ResourceFetcher::cachePolicy(Resource::Type type) const 923 { 924 if (!frame()) 925 return CachePolicyVerify; 926 927 if (type != Resource::MainResource) 928 return frame()->loader()->subresourceCachePolicy(); 929 930 if (frame()->loader()->loadType() == FrameLoadTypeReloadFromOrigin || frame()->loader()->loadType() == FrameLoadTypeReload) 931 return CachePolicyReload; 932 return CachePolicyVerify; 933 } 934 935 void ResourceFetcher::redirectReceived(Resource* resource, const ResourceResponse& redirectResponse) 936 { 937 ResourceTimingInfoMap::iterator it = m_resourceTimingInfoMap.find(resource); 938 if (it != m_resourceTimingInfoMap.end()) 939 it->value->addRedirect(redirectResponse); 940 } 941 942 void ResourceFetcher::didLoadResource(Resource* resource) 943 { 944 RefPtr<DocumentLoader> protectDocumentLoader(m_documentLoader); 945 RefPtr<Document> protectDocument(m_document); 946 947 if (resource && resource->response().isHTTP() && ((!resource->errorOccurred() && !resource->wasCanceled()) || resource->response().httpStatusCode() == 304) && document()) { 948 ResourceTimingInfoMap::iterator it = m_resourceTimingInfoMap.find(resource); 949 if (it != m_resourceTimingInfoMap.end()) { 950 Document* initiatorDocument = document(); 951 if (resource->type() == Resource::MainResource) 952 initiatorDocument = document()->parentDocument(); 953 ASSERT(initiatorDocument); 954 RefPtr<ResourceTimingInfo> info = it->value; 955 m_resourceTimingInfoMap.remove(it); 956 info->setInitialRequest(resource->resourceRequest()); 957 info->setFinalResponse(resource->response()); 958 info->setLoadFinishTime(resource->loadFinishTime()); 959 if (DOMWindow* initiatorWindow = initiatorDocument->domWindow()) 960 initiatorWindow->performance()->addResourceTiming(*info, initiatorDocument); 961 } 962 } 963 964 if (frame()) 965 frame()->loader()->loadDone(); 966 performPostLoadActions(); 967 968 if (!m_garbageCollectDocumentResourcesTimer.isActive()) 969 m_garbageCollectDocumentResourcesTimer.startOneShot(0); 970 } 971 972 // Garbage collecting m_documentResources is a workaround for the 973 // ResourcePtrs on the RHS being strong references. Ideally this 974 // would be a weak map, however ResourcePtrs perform additional 975 // bookkeeping on Resources, so instead pseudo-GC them -- when the 976 // reference count reaches 1, m_documentResources is the only reference, so 977 // remove it from the map. 978 void ResourceFetcher::garbageCollectDocumentResourcesTimerFired(Timer<ResourceFetcher>* timer) 979 { 980 ASSERT_UNUSED(timer, timer == &m_garbageCollectDocumentResourcesTimer); 981 garbageCollectDocumentResources(); 982 } 983 984 void ResourceFetcher::garbageCollectDocumentResources() 985 { 986 typedef Vector<String, 10> StringVector; 987 StringVector resourcesToDelete; 988 989 for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != m_documentResources.end(); ++it) { 990 if (it->value->hasOneHandle()) 991 resourcesToDelete.append(it->key); 992 } 993 994 for (StringVector::const_iterator it = resourcesToDelete.begin(); it != resourcesToDelete.end(); ++it) 995 m_documentResources.remove(*it); 996 } 997 998 void ResourceFetcher::performPostLoadActions() 999 { 1000 checkForPendingPreloads(); 1001 } 1002 1003 void ResourceFetcher::notifyLoadedFromMemoryCache(Resource* resource) 1004 { 1005 if (!frame() || resource->status() != Resource::Cached || m_validatedURLs.contains(resource->url())) 1006 return; 1007 1008 // FIXME: If the WebKit client changes or cancels the request, WebCore does not respect this and continues the load. 1009 frame()->loader()->loadedResourceFromMemoryCache(resource); 1010 } 1011 1012 void ResourceFetcher::incrementRequestCount(const Resource* res) 1013 { 1014 if (res->ignoreForRequestCount()) 1015 return; 1016 1017 ++m_requestCount; 1018 } 1019 1020 void ResourceFetcher::decrementRequestCount(const Resource* res) 1021 { 1022 if (res->ignoreForRequestCount()) 1023 return; 1024 1025 --m_requestCount; 1026 ASSERT(m_requestCount > -1); 1027 } 1028 1029 void ResourceFetcher::preload(Resource::Type type, FetchRequest& request, const String& charset) 1030 { 1031 bool delaySubresourceLoad = true; 1032 delaySubresourceLoad = false; 1033 if (delaySubresourceLoad) { 1034 bool hasRendering = m_document->body() && m_document->body()->renderer(); 1035 bool canBlockParser = type == Resource::Script || type == Resource::CSSStyleSheet; 1036 if (!hasRendering && !canBlockParser) { 1037 // Don't preload subresources that can't block the parser before we have something to draw. 1038 // This helps prevent preloads from delaying first display when bandwidth is limited. 1039 PendingPreload pendingPreload = { type, request, charset }; 1040 m_pendingPreloads.append(pendingPreload); 1041 return; 1042 } 1043 } 1044 requestPreload(type, request, charset); 1045 } 1046 1047 void ResourceFetcher::checkForPendingPreloads() 1048 { 1049 if (m_pendingPreloads.isEmpty() || !m_document->body() || !m_document->body()->renderer()) 1050 return; 1051 while (!m_pendingPreloads.isEmpty()) { 1052 PendingPreload preload = m_pendingPreloads.takeFirst(); 1053 // Don't request preload if the resource already loaded normally (this will result in double load if the page is being reloaded with cached results ignored). 1054 if (!cachedResource(preload.m_request.resourceRequest().url())) 1055 requestPreload(preload.m_type, preload.m_request, preload.m_charset); 1056 } 1057 m_pendingPreloads.clear(); 1058 } 1059 1060 void ResourceFetcher::requestPreload(Resource::Type type, FetchRequest& request, const String& charset) 1061 { 1062 String encoding; 1063 if (type == Resource::Script || type == Resource::CSSStyleSheet) 1064 encoding = charset.isEmpty() ? m_document->charset() : charset; 1065 1066 request.setCharset(encoding); 1067 request.setForPreload(true); 1068 1069 ResourcePtr<Resource> resource = requestResource(type, request); 1070 if (!resource || (m_preloads && m_preloads->contains(resource.get()))) 1071 return; 1072 TRACE_EVENT_ASYNC_STEP0("net", "Resource", resource.get(), "Preload"); 1073 resource->increasePreloadCount(); 1074 1075 if (!m_preloads) 1076 m_preloads = adoptPtr(new ListHashSet<Resource*>); 1077 m_preloads->add(resource.get()); 1078 1079 #if PRELOAD_DEBUG 1080 printf("PRELOADING %s\n", resource->url().latin1().data()); 1081 #endif 1082 } 1083 1084 bool ResourceFetcher::isPreloaded(const String& urlString) const 1085 { 1086 const KURL& url = m_document->completeURL(urlString); 1087 1088 if (m_preloads) { 1089 ListHashSet<Resource*>::iterator end = m_preloads->end(); 1090 for (ListHashSet<Resource*>::iterator it = m_preloads->begin(); it != end; ++it) { 1091 Resource* resource = *it; 1092 if (resource->url() == url) 1093 return true; 1094 } 1095 } 1096 1097 Deque<PendingPreload>::const_iterator dequeEnd = m_pendingPreloads.end(); 1098 for (Deque<PendingPreload>::const_iterator it = m_pendingPreloads.begin(); it != dequeEnd; ++it) { 1099 PendingPreload pendingPreload = *it; 1100 if (pendingPreload.m_request.resourceRequest().url() == url) 1101 return true; 1102 } 1103 return false; 1104 } 1105 1106 void ResourceFetcher::clearPreloads() 1107 { 1108 #if PRELOAD_DEBUG 1109 printPreloadStats(); 1110 #endif 1111 if (!m_preloads) 1112 return; 1113 1114 ListHashSet<Resource*>::iterator end = m_preloads->end(); 1115 for (ListHashSet<Resource*>::iterator it = m_preloads->begin(); it != end; ++it) { 1116 Resource* res = *it; 1117 res->decreasePreloadCount(); 1118 bool deleted = res->deleteIfPossible(); 1119 if (!deleted && res->preloadResult() == Resource::PreloadNotReferenced) 1120 memoryCache()->remove(res); 1121 } 1122 m_preloads.clear(); 1123 } 1124 1125 void ResourceFetcher::clearPendingPreloads() 1126 { 1127 m_pendingPreloads.clear(); 1128 } 1129 1130 inline FrameLoader* ResourceFetcher::frameLoader() 1131 { 1132 if (Frame* frame = this->frame()) 1133 return frame->loader(); 1134 return 0; 1135 } 1136 1137 void ResourceFetcher::didFinishLoading(const Resource* resource, double finishTime, const ResourceLoaderOptions& options) 1138 { 1139 TRACE_EVENT_ASYNC_END0("net", "Resource", resource); 1140 if (options.sendLoadCallbacks != SendCallbacks) 1141 return; 1142 if (FrameLoader* loader = frameLoader()) 1143 loader->notifier()->dispatchDidFinishLoading(m_documentLoader, resource->identifier(), finishTime); 1144 } 1145 1146 void ResourceFetcher::didChangeLoadingPriority(const Resource* resource, ResourceLoadPriority loadPriority) 1147 { 1148 TRACE_EVENT_ASYNC_STEP1("net", "Resource", resource, "ChangePriority", "priority", loadPriority); 1149 if (FrameLoader* loader = frameLoader()) 1150 loader->client()->dispatchDidChangeResourcePriority(resource->identifier(), loadPriority); 1151 } 1152 1153 void ResourceFetcher::didFailLoading(const Resource* resource, const ResourceError& error, const ResourceLoaderOptions& options) 1154 { 1155 TRACE_EVENT_ASYNC_END0("net", "Resource", resource); 1156 if (options.sendLoadCallbacks != SendCallbacks) 1157 return; 1158 if (FrameLoader* loader = frameLoader()) 1159 loader->notifier()->dispatchDidFail(m_documentLoader, resource->identifier(), error); 1160 } 1161 1162 void ResourceFetcher::willSendRequest(const Resource* resource, ResourceRequest& request, const ResourceResponse& redirectResponse, const ResourceLoaderOptions& options) 1163 { 1164 if (options.sendLoadCallbacks == SendCallbacks) { 1165 if (FrameLoader* loader = frameLoader()) 1166 loader->notifier()->dispatchWillSendRequest(m_documentLoader, resource->identifier(), request, redirectResponse, options.initiatorInfo); 1167 } else { 1168 InspectorInstrumentation::willSendRequest(frame(), resource->identifier(), m_documentLoader, request, redirectResponse, options.initiatorInfo); 1169 } 1170 } 1171 1172 void ResourceFetcher::didReceiveResponse(const Resource* resource, const ResourceResponse& response, const ResourceLoaderOptions& options) 1173 { 1174 if (options.sendLoadCallbacks != SendCallbacks) 1175 return; 1176 if (FrameLoader* loader = frameLoader()) 1177 loader->notifier()->dispatchDidReceiveResponse(m_documentLoader, resource->identifier(), response); 1178 } 1179 1180 void ResourceFetcher::didReceiveData(const Resource* resource, const char* data, int dataLength, int encodedDataLength, const ResourceLoaderOptions& options) 1181 { 1182 // FIXME: use frame of master document for imported documents. 1183 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willReceiveResourceData(frame(), resource->identifier(), encodedDataLength); 1184 if (options.sendLoadCallbacks != SendCallbacks) 1185 return; 1186 if (FrameLoader* loader = frameLoader()) 1187 loader->notifier()->dispatchDidReceiveData(m_documentLoader, resource->identifier(), data, dataLength, encodedDataLength); 1188 InspectorInstrumentation::didReceiveResourceData(cookie); 1189 } 1190 1191 void ResourceFetcher::subresourceLoaderFinishedLoadingOnePart(ResourceLoader* loader) 1192 { 1193 if (m_documentLoader) 1194 m_documentLoader->subresourceLoaderFinishedLoadingOnePart(loader); 1195 } 1196 1197 void ResourceFetcher::didInitializeResourceLoader(ResourceLoader* loader) 1198 { 1199 if (m_documentLoader) 1200 m_documentLoader->addResourceLoader(loader); 1201 } 1202 1203 void ResourceFetcher::willTerminateResourceLoader(ResourceLoader* loader) 1204 { 1205 if (m_documentLoader) 1206 m_documentLoader->removeResourceLoader(loader); 1207 } 1208 1209 void ResourceFetcher::willStartLoadingResource(ResourceRequest& request) 1210 { 1211 if (m_documentLoader) 1212 m_documentLoader->applicationCacheHost()->willStartLoadingResource(request); 1213 } 1214 1215 bool ResourceFetcher::defersLoading() const 1216 { 1217 if (Frame* frame = this->frame()) 1218 return frame->page()->defersLoading(); 1219 return false; 1220 } 1221 1222 bool ResourceFetcher::isLoadedBy(ResourceLoaderHost* possibleOwner) const 1223 { 1224 return this == possibleOwner; 1225 } 1226 1227 bool ResourceFetcher::shouldRequest(Resource* resource, const ResourceRequest& request, const ResourceLoaderOptions& options) 1228 { 1229 if (!canRequest(resource->type(), request.url(), options)) 1230 return false; 1231 if (resource->type() == Resource::Image && shouldDeferImageLoad(request.url())) 1232 return false; 1233 return true; 1234 } 1235 1236 void ResourceFetcher::refResourceLoaderHost() 1237 { 1238 ref(); 1239 } 1240 1241 void ResourceFetcher::derefResourceLoaderHost() 1242 { 1243 deref(); 1244 } 1245 1246 #if PRELOAD_DEBUG 1247 void ResourceFetcher::printPreloadStats() 1248 { 1249 unsigned scripts = 0; 1250 unsigned scriptMisses = 0; 1251 unsigned stylesheets = 0; 1252 unsigned stylesheetMisses = 0; 1253 unsigned images = 0; 1254 unsigned imageMisses = 0; 1255 ListHashSet<Resource*>::iterator end = m_preloads.end(); 1256 for (ListHashSet<Resource*>::iterator it = m_preloads.begin(); it != end; ++it) { 1257 Resource* res = *it; 1258 if (res->preloadResult() == Resource::PreloadNotReferenced) 1259 printf("!! UNREFERENCED PRELOAD %s\n", res->url().latin1().data()); 1260 else if (res->preloadResult() == Resource::PreloadReferencedWhileComplete) 1261 printf("HIT COMPLETE PRELOAD %s\n", res->url().latin1().data()); 1262 else if (res->preloadResult() == Resource::PreloadReferencedWhileLoading) 1263 printf("HIT LOADING PRELOAD %s\n", res->url().latin1().data()); 1264 1265 if (res->type() == Resource::Script) { 1266 scripts++; 1267 if (res->preloadResult() < Resource::PreloadReferencedWhileLoading) 1268 scriptMisses++; 1269 } else if (res->type() == Resource::CSSStyleSheet) { 1270 stylesheets++; 1271 if (res->preloadResult() < Resource::PreloadReferencedWhileLoading) 1272 stylesheetMisses++; 1273 } else { 1274 images++; 1275 if (res->preloadResult() < Resource::PreloadReferencedWhileLoading) 1276 imageMisses++; 1277 } 1278 1279 if (res->errorOccurred()) 1280 memoryCache()->remove(res); 1281 1282 res->decreasePreloadCount(); 1283 } 1284 m_preloads.clear(); 1285 1286 if (scripts) 1287 printf("SCRIPTS: %d (%d hits, hit rate %d%%)\n", scripts, scripts - scriptMisses, (scripts - scriptMisses) * 100 / scripts); 1288 if (stylesheets) 1289 printf("STYLESHEETS: %d (%d hits, hit rate %d%%)\n", stylesheets, stylesheets - stylesheetMisses, (stylesheets - stylesheetMisses) * 100 / stylesheets); 1290 if (images) 1291 printf("IMAGES: %d (%d hits, hit rate %d%%)\n", images, images - imageMisses, (images - imageMisses) * 100 / images); 1292 } 1293 #endif 1294 1295 const ResourceLoaderOptions& ResourceFetcher::defaultResourceOptions() 1296 { 1297 DEFINE_STATIC_LOCAL(ResourceLoaderOptions, options, (SendCallbacks, SniffContent, BufferData, AllowStoredCredentials, ClientRequestedCredentials, AskClientForCrossOriginCredentials, DoSecurityCheck, CheckContentSecurityPolicy, UseDefaultOriginRestrictionsForType, DocumentContext)); 1298 return options; 1299 } 1300 1301 } 1302