bool ApplicationCacheHost::shouldLoadResourceFromApplicationCache(const ResourceRequest& originalRequest, ApplicationCacheResource*& resource) { ApplicationCache* cache = applicationCache(); if (!cache || !cache->isComplete()) return false; ResourceRequest request(originalRequest); if (Frame* loaderFrame = m_documentLoader.frame()) { if (Document* document = loaderFrame->document()) document->contentSecurityPolicy()->upgradeInsecureRequestIfNeeded(request, ContentSecurityPolicy::InsecureRequestType::Load); } // If the resource is not to be fetched using the HTTP GET mechanism or equivalent, or if its URL has a different // <scheme> component than the application cache's manifest, then fetch the resource normally. if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request) || !equalIgnoringASCIICase(request.url().protocol(), cache->manifestResource()->url().protocol())) return false; // If the resource's URL is an master entry, the manifest, an explicit entry, or a fallback entry // in the application cache, then get the resource from the cache (instead of fetching it). resource = cache->resourceForURL(request.url()); // Resources that match fallback namespaces or online whitelist entries are fetched from the network, // unless they are also cached. if (!resource && (cache->allowsAllNetworkRequests() || cache->urlMatchesFallbackNamespace(request.url()) || cache->isURLInOnlineWhitelist(request.url()))) return false; // Resources that are not present in the manifest will always fail to load (at least, after the // cache has been primed the first time), making the testing of offline applications simpler. return true; }
bool DocumentLoader::shouldLoadResourceFromApplicationCache(const ResourceRequest& request, ApplicationCacheResource*& resource) { ApplicationCache* cache = topLevelApplicationCache(); if (!cache) return false; // If the resource is not a HTTP/HTTPS GET, then abort if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request)) return false; if (cache->isURLInOnlineWhitelist(request.url())) return false; resource = cache->resourceForURL(request.url()); // Don't load foreign resources. if (resource && (resource->type() & ApplicationCacheResource::Foreign)) resource = 0; return true; }
bool DocumentLoader::shouldLoadResourceFromApplicationCache(const ResourceRequest& request, ApplicationCacheResource*& resource) { ApplicationCache* cache = applicationCache(); if (!cache) return false; // If the resource is not a HTTP/HTTPS GET, then abort if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request)) return false; // If the resource's URL is an master entry, the manifest, an explicit entry, a fallback entry, or a dynamic entry // in the application cache, then get the resource from the cache (instead of fetching it). resource = cache->resourceForURL(request.url()); // Resources that match fallback namespaces or online whitelist entries are fetched from the network, // unless they are also cached. if (!resource && (cache->urlMatchesFallbackNamespace(request.url()) || cache->isURLInOnlineWhitelist(request.url()))) return false; // Resources that are not present in the manifest will always fail to load (at least, after the // cache has been primed the first time), making the testing of offline applications simpler. return true; }
void ApplicationCacheGroup::selectCache(Frame* frame, const KURL& manifestURL) { ASSERT(frame && frame->page()); if (!frame->settings()->offlineWebApplicationCacheEnabled()) return; DocumentLoader* documentLoader = frame->loader()->documentLoader(); ASSERT(!documentLoader->applicationCache()); if (manifestURL.isNull()) { selectCacheWithoutManifestURL(frame); return; } ApplicationCache* mainResourceCache = documentLoader->mainResourceApplicationCache(); if (mainResourceCache) { if (manifestURL == mainResourceCache->group()->m_manifestURL) { mainResourceCache->group()->associateDocumentLoaderWithCache(documentLoader, mainResourceCache); mainResourceCache->group()->update(frame); } else { // The main resource was loaded from cache, so the cache must have an entry for it. Mark it as foreign. ApplicationCacheResource* resource = mainResourceCache->resourceForURL(documentLoader->url()); bool inStorage = resource->storageID(); resource->addType(ApplicationCacheResource::Foreign); if (inStorage) cacheStorage().storeUpdatedType(resource, mainResourceCache); // Restart the current navigation from the top of the navigation algorithm, undoing any changes that were made // as part of the initial load. // The navigation will not result in the same resource being loaded, because "foreign" entries are never picked during navigation. frame->loader()->scheduleLocationChange(documentLoader->url(), frame->loader()->referrer(), true); } return; } // The resource was loaded from the network, check if it is a HTTP/HTTPS GET. const ResourceRequest& request = frame->loader()->activeDocumentLoader()->request(); if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request)) { selectCacheWithoutManifestURL(frame); return; } // Check that the resource URL has the same scheme/host/port as the manifest URL. if (!protocolHostAndPortAreEqual(manifestURL, request.url())) { selectCacheWithoutManifestURL(frame); return; } ApplicationCacheGroup* group = cacheStorage().findOrCreateCacheGroup(manifestURL); if (ApplicationCache* cache = group->newestCache()) { ASSERT(cache->manifestResource()); group->associateDocumentLoaderWithCache(frame->loader()->documentLoader(), cache); if (!frame->loader()->documentLoader()->isLoadingMainResource()) group->finishedLoadingMainResource(frame->loader()->documentLoader()); group->update(frame); } else { bool isUpdating = group->m_cacheBeingUpdated; if (!isUpdating) group->m_cacheBeingUpdated = ApplicationCache::create(); documentLoader->setCandidateApplicationCacheGroup(group); group->m_cacheCandidates.add(documentLoader); const KURL& url = frame->loader()->documentLoader()->originalURL(); unsigned type = 0; // If the resource has already been downloaded, remove it so that it will be replaced with the implicit resource if (isUpdating) type = group->m_cacheBeingUpdated->removeResource(url); // Add the main resource URL as an implicit entry. group->addEntry(url, type | ApplicationCacheResource::Implicit); if (!frame->loader()->documentLoader()->isLoadingMainResource()) group->finishedLoadingMainResource(frame->loader()->documentLoader()); if (!isUpdating) group->update(frame); } }
void ApplicationCacheGroup::selectCache(Frame* frame, const URL& passedManifestURL) { ASSERT(frame && frame->page()); if (!frame->settings().offlineWebApplicationCacheEnabled()) return; DocumentLoader* documentLoader = frame->loader().documentLoader(); ASSERT(!documentLoader->applicationCacheHost()->applicationCache()); if (passedManifestURL.isNull()) { selectCacheWithoutManifestURL(frame); return; } // Don't access anything on disk if private browsing is enabled. if (frame->page()->usesEphemeralSession() || !frame->document()->securityOrigin()->canAccessApplicationCache(frame->tree().top().document()->securityOrigin())) { postListenerTask(ApplicationCacheHost::CHECKING_EVENT, documentLoader); postListenerTask(ApplicationCacheHost::ERROR_EVENT, documentLoader); return; } URL manifestURL(passedManifestURL); if (manifestURL.hasFragmentIdentifier()) manifestURL.removeFragmentIdentifier(); ApplicationCache* mainResourceCache = documentLoader->applicationCacheHost()->mainResourceApplicationCache(); if (mainResourceCache) { if (manifestURL == mainResourceCache->group()->m_manifestURL) { // The cache may have gotten obsoleted after we've loaded from it, but before we parsed the document and saw cache manifest. if (mainResourceCache->group()->isObsolete()) return; mainResourceCache->group()->associateDocumentLoaderWithCache(documentLoader, mainResourceCache); mainResourceCache->group()->update(frame, ApplicationCacheUpdateWithBrowsingContext); } else { // The main resource was loaded from cache, so the cache must have an entry for it. Mark it as foreign. URL resourceURL(documentLoader->responseURL()); if (resourceURL.hasFragmentIdentifier()) resourceURL.removeFragmentIdentifier(); ApplicationCacheResource* resource = mainResourceCache->resourceForURL(resourceURL); bool inStorage = resource->storageID(); resource->addType(ApplicationCacheResource::Foreign); if (inStorage) frame->page()->applicationCacheStorage().storeUpdatedType(resource, mainResourceCache); // Restart the current navigation from the top of the navigation algorithm, undoing any changes that were made // as part of the initial load. // The navigation will not result in the same resource being loaded, because "foreign" entries are never picked during navigation. frame->navigationScheduler().scheduleLocationChange(frame->document(), frame->document()->securityOrigin(), documentLoader->url(), frame->loader().referrer()); } return; } // The resource was loaded from the network, check if it is a HTTP/HTTPS GET. const ResourceRequest& request = frame->loader().activeDocumentLoader()->request(); if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request)) return; // Check that the resource URL has the same scheme/host/port as the manifest URL. if (!protocolHostAndPortAreEqual(manifestURL, request.url())) return; ApplicationCacheGroup* group = frame->page()->applicationCacheStorage().findOrCreateCacheGroup(manifestURL); documentLoader->applicationCacheHost()->setCandidateApplicationCacheGroup(group); group->m_pendingMasterResourceLoaders.add(documentLoader); group->m_downloadingPendingMasterResourceLoadersCount++; ASSERT(!group->m_cacheBeingUpdated || group->m_updateStatus != Idle); group->update(frame, ApplicationCacheUpdateWithBrowsingContext); }