bool ResourceFetcher::resourceNeedsLoad(Resource* resource, const FetchRequest& request, RevalidationPolicy policy) { if (FetchRequest::DeferredByClient == request.defer()) return false; if (policy != Use) return true; return resource->stillNeedsLoad(); }
ResourceLoadPriority FrameFetchContext::modifyPriorityForExperiments(ResourceLoadPriority priority, Resource::Type type, const FetchRequest& request, ResourcePriority::VisibilityStatus visibility) { // An image fetch is used to distinguish between "early" and "late" scripts in a document if (type == Resource::Image) m_imageFetched = true; // If Settings is null, we can't verify any experiments are in force. if (!frame()->settings()) return priority; // If enabled, drop the priority of all resources in a subframe. if (frame()->settings()->lowPriorityIframes() && !frame()->isMainFrame()) return ResourceLoadPriorityVeryLow; // Async/Defer scripts. if (type == Resource::Script && FetchRequest::LazyLoad == request.defer()) return frame()->settings()->fetchIncreaseAsyncScriptPriority() ? ResourceLoadPriorityMedium : ResourceLoadPriorityLow; // Runtime experiment that change how we prioritize resources. // The toggles do not depend on each other and can be flipped individually // though the cumulative result will depend on the interaction between them. // Background doc: https://docs.google.com/document/d/1bCDuq9H1ih9iNjgzyAL0gpwNFiEP4TZS-YLRp_RuMlc/edit?usp=sharing // Increases the priorities for CSS, Scripts, Fonts and Images all by one level // and parser-blocking scripts and visible images by 2. // This is used in conjunction with logic on the Chrome side to raise the threshold // of "layout-blocking" resources and provide a boost to resources that are needed // as soon as possible for something currently on the screen. int modifiedPriority = static_cast<int>(priority); if (frame()->settings()->fetchIncreasePriorities()) { if (type == Resource::CSSStyleSheet || type == Resource::Script || type == Resource::Font || type == Resource::Image) modifiedPriority++; } // Always give visible resources a bump, and an additional bump if generally increasing priorities. if (visibility == ResourcePriority::Visible) { modifiedPriority++; if (frame()->settings()->fetchIncreasePriorities()) modifiedPriority++; } if (frame()->settings()->fetchIncreaseFontPriority() && type == Resource::Font) modifiedPriority++; if (type == Resource::Script) { // Reduce the priority of late-body scripts. if (frame()->settings()->fetchDeferLateScripts() && request.forPreload() && m_imageFetched) modifiedPriority--; // Parser-blocking scripts. if (frame()->settings()->fetchIncreasePriorities() && !request.forPreload()) modifiedPriority++; } // Clamp priority modifiedPriority = std::min(static_cast<int>(ResourceLoadPriorityHighest), std::max(static_cast<int>(ResourceLoadPriorityLowest), modifiedPriority)); return static_cast<ResourceLoadPriority>(modifiedPriority); }
ResourceFetcher::RevalidationPolicy ResourceFetcher::determineRevalidationPolicy(Resource::Type type, const FetchRequest& fetchRequest, Resource* existingResource) const { const ResourceRequest& request = fetchRequest.resourceRequest(); if (!existingResource) return Load; // If the same URL has been loaded as a different type, we need to reload. if (existingResource->type() != type) { WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to type mismatch."); return Reload; } // Do not load from cache if images are not enabled. The load for this image will be blocked // in ImageResource::load. if (FetchRequest::DeferredByClient == fetchRequest.defer()) return Reload; // Always use data uris. // FIXME: Extend this to non-images. if (type == Resource::Image && request.url().protocolIsData()) return Use; if (!existingResource->canReuse(request)) return Reload; // Never use cache entries for downloadToFile requests. The caller expects the resource in a file. if (request.downloadToFile()) return Reload; // Certain requests (e.g., XHRs) might have manually set headers that require revalidation. // FIXME: In theory, this should be a Revalidate case. In practice, the MemoryCache revalidation path assumes a whole bunch // of things about how revalidation works that manual headers violate, so punt to Reload instead. if (request.isConditional()) return Reload; // Don't reload resources while pasting. if (m_allowStaleResources) return Use; if (!fetchRequest.options().canReuseRequest(existingResource->options())) return Reload; // CachePolicyHistoryBuffer uses the cache no matter what. CachePolicy cachePolicy = context().cachePolicy(document()); if (cachePolicy == CachePolicyHistoryBuffer) return Use; // Don't reuse resources with Cache-control: no-store. if (existingResource->hasCacheControlNoStoreHeader()) { WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to Cache-control: no-store."); return Reload; } // If credentials were sent with the previous request and won't be // with this one, or vice versa, re-fetch the resource. // // This helps with the case where the server sends back // "Access-Control-Allow-Origin: *" all the time, but some of the // client's requests are made without CORS and some with. if (existingResource->resourceRequest().allowStoredCredentials() != request.allowStoredCredentials()) { WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to difference in credentials settings."); return Reload; } // During the initial load, avoid loading the same resource multiple times for a single document, // even if the cache policies would tell us to. // We also group loads of the same resource together. // Raw resources are exempted, as XHRs fall into this category and may have user-set Cache-Control: // headers or other factors that require separate requests. if (type != Resource::Raw) { if (document() && !document()->loadEventFinished() && m_validatedURLs.contains(existingResource->url())) return Use; if (existingResource->isLoading()) return Use; } // CachePolicyReload always reloads if (cachePolicy == CachePolicyReload) { WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to CachePolicyReload."); return Reload; } // We'll try to reload the resource if it failed last time. if (existingResource->errorOccurred()) { WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicye reloading due to resource being in the error state"); return Reload; } // List of available images logic allows images to be re-used without cache validation. We restrict this only to images // from memory cache which are the same as the version in the current document. if (type == Resource::Image && existingResource == cachedResource(request.url())) return Use; // Check if the cache headers requires us to revalidate (cache expiration for example). if (cachePolicy == CachePolicyRevalidate || existingResource->mustRevalidateDueToCacheHeaders() || request.cacheControlContainsNoCache()) { // See if the resource has usable ETag or Last-modified headers. if (existingResource->canUseCacheValidator()) return Revalidate; // No, must reload. WTF_LOG(ResourceLoading, "ResourceFetcher::determineRevalidationPolicy reloading due to missing cache validators."); return Reload; } return Use; }