void ApplicationCacheGroup::didFinishLoading(ResourceHandle* handle) { if (handle == m_manifestHandle) { didFinishLoadingManifest(); return; } ASSERT(m_currentHandle == handle); ASSERT(m_pendingEntries.contains(handle->request().url())); m_pendingEntries.remove(handle->request().url()); ASSERT(m_cacheBeingUpdated); m_cacheBeingUpdated->addResource(m_currentResource.release()); m_currentHandle = 0; // Load the next file. if (!m_pendingEntries.isEmpty()) { startLoadingEntry(); return; } checkIfLoadIsComplete(); }
void ApplicationCacheGroup::didFinishLoading(ResourceHandle* handle, double finishTime) { InspectorInstrumentation::didFinishLoading(m_frame, m_frame->loader().documentLoader(), m_currentResourceIdentifier, finishTime); if (handle == m_manifestHandle) { didFinishLoadingManifest(); return; } ASSERT(m_currentHandle == handle); ASSERT(m_pendingEntries.contains(handle->firstRequest().url())); m_pendingEntries.remove(handle->firstRequest().url()); ASSERT(m_cacheBeingUpdated); m_cacheBeingUpdated->addResource(m_currentResource.release()); m_currentHandle = nullptr; // While downloading check to see if we have exceeded the available quota. // We can stop immediately if we have already previously failed // due to an earlier quota restriction. The client was already notified // of the quota being reached and decided not to increase it then. // FIXME: Should we break earlier and prevent redownloading on later page loads? if (m_originQuotaExceededPreviously && m_availableSpaceInQuota < m_cacheBeingUpdated->estimatedSizeInStorage()) { m_currentResource = nullptr; m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, ASCIILiteral("Application Cache update failed, because size quota was exceeded.")); cacheUpdateFailed(); return; } // Load the next resource, if any. startLoadingEntry(); }
void ApplicationCacheGroup::didFinishLoading(ResourceHandle* handle) { #if ENABLE(INSPECTOR) if (Page* page = m_frame->page()) page->inspectorController()->didFinishLoading(m_currentResourceIdentifier); #endif if (handle == m_manifestHandle) { didFinishLoadingManifest(); return; } // After finishing the loading of any resource, we check if it will // fit in our last known quota limit. if (m_availableSpaceInQuota == ApplicationCacheStorage::unknownQuota()) { // Failed to determine what is left in the quota. Fallback to allowing anything. if (!cacheStorage().remainingSizeForOriginExcludingCache(m_origin.get(), m_newestCache.get(), m_availableSpaceInQuota)) m_availableSpaceInQuota = ApplicationCacheStorage::noQuota(); } // Check each resource, as it loads, to see if it would fit in our // idea of the available quota space. if (m_availableSpaceInQuota < m_loadedSize) { m_currentResource = 0; cacheUpdateFailedDueToOriginQuota(); return; } ASSERT(m_currentHandle == handle); ASSERT(m_pendingEntries.contains(handle->firstRequest().url())); m_pendingEntries.remove(handle->firstRequest().url()); ASSERT(m_cacheBeingUpdated); m_cacheBeingUpdated->addResource(m_currentResource.release()); m_currentHandle = 0; // Load the next resource, if any. startLoadingEntry(); }
void ApplicationCacheGroup::didFail(ResourceHandle* handle, const ResourceError& error) { #if ENABLE(INSPECTOR) InspectorInstrumentation::didFailLoading(m_frame, m_frame->loader().documentLoader(), m_currentResourceIdentifier, error); #else UNUSED_PARAM(error); #endif if (handle == m_manifestHandle) { // A network error is logged elsewhere, no need to log again. Also, it's normal for manifest fetching to fail when working offline. cacheUpdateFailed(); return; } ASSERT(handle == m_currentHandle); unsigned type = m_currentResource ? m_currentResource->type() : m_pendingEntries.get(handle->firstRequest().url()); URL url(handle->firstRequest().url()); if (url.hasFragmentIdentifier()) url.removeFragmentIdentifier(); ASSERT(!m_currentResource || !m_pendingEntries.contains(url)); m_currentResource = 0; m_pendingEntries.remove(url); if ((type & ApplicationCacheResource::Explicit) || (type & ApplicationCacheResource::Fallback)) { m_frame->document()->addConsoleMessage(AppCacheMessageSource, ErrorMessageLevel, "Application Cache update failed, because " + url.stringCenterEllipsizedToLength() + " could not be fetched."); // Note that cacheUpdateFailed() can cause the cache group to be deleted. cacheUpdateFailed(); } else { // Copy the resource and its metadata from the newest application cache in cache group whose completeness flag is complete, and act // as if that was the fetched resource, ignoring the resource obtained from the network. ASSERT(m_newestCache); ApplicationCacheResource* newestCachedResource = m_newestCache->resourceForURL(url); ASSERT(newestCachedResource); m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, newestCachedResource->response(), type, newestCachedResource->data(), newestCachedResource->path())); // Load the next resource, if any. startLoadingEntry(); } }
void ApplicationCacheGroup::didFail(ResourceHandle* handle, const ResourceError& error) { #if ENABLE(INSPECTOR) if (Page* page = m_frame->page()) page->inspectorController()->didFailLoading(m_currentResourceIdentifier, error); #else UNUSED_PARAM(error); #endif if (handle == m_manifestHandle) { cacheUpdateFailed(); return; } unsigned type = m_currentResource ? m_currentResource->type() : m_pendingEntries.get(handle->firstRequest().url()); KURL url(handle->firstRequest().url()); if (url.hasFragmentIdentifier()) url.removeFragmentIdentifier(); ASSERT(!m_currentResource || !m_pendingEntries.contains(url)); m_currentResource = 0; m_pendingEntries.remove(url); if ((type & ApplicationCacheResource::Explicit) || (type & ApplicationCacheResource::Fallback)) { // Note that cacheUpdateFailed() can cause the cache group to be deleted. cacheUpdateFailed(); } else { // Copy the resource and its metadata from the newest application cache in cache group whose completeness flag is complete, and act // as if that was the fetched resource, ignoring the resource obtained from the network. ASSERT(m_newestCache); ApplicationCacheResource* newestCachedResource = m_newestCache->resourceForURL(url); ASSERT(newestCachedResource); m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, newestCachedResource->response(), type, newestCachedResource->data())); // Load the next resource, if any. startLoadingEntry(); } }
void ApplicationCacheGroup::didFinishLoadingManifest() { if (!m_manifestResource) { didFailToLoadManifest(); return; } bool isUpgradeAttempt = m_newestCache; m_manifestHandle = 0; // Check if the manifest is byte-for-byte identical. if (isUpgradeAttempt) { ApplicationCacheResource* newestManifest = m_newestCache->manifestResource(); ASSERT(newestManifest); if (newestManifest->data()->size() == m_manifestResource->data()->size() && !memcmp(newestManifest->data()->data(), m_manifestResource->data()->data(), newestManifest->data()->size())) { callListenersOnAssociatedDocuments(&DOMApplicationCache::callNoUpdateListener); m_status = Idle; m_frame = 0; m_manifestResource = 0; return; } } Manifest manifest; if (!parseManifest(m_manifestURL, m_manifestResource->data()->data(), m_manifestResource->data()->size(), manifest)) { didFailToLoadManifest(); return; } // We have the manifest, now download the resources. m_status = Downloading; callListenersOnAssociatedDocuments(&DOMApplicationCache::callDownloadingListener); #ifndef NDEBUG // We should only have implicit entries. { EntryMap::const_iterator end = m_pendingEntries.end(); for (EntryMap::const_iterator it = m_pendingEntries.begin(); it != end; ++it) ASSERT(it->second & ApplicationCacheResource::Implicit); } #endif if (isUpgradeAttempt) { ASSERT(!m_cacheBeingUpdated); m_cacheBeingUpdated = ApplicationCache::create(); ApplicationCache::ResourceMap::const_iterator end = m_newestCache->end(); for (ApplicationCache::ResourceMap::const_iterator it = m_newestCache->begin(); it != end; ++it) { unsigned type = it->second->type(); if (type & (ApplicationCacheResource::Implicit | ApplicationCacheResource::Dynamic)) addEntry(it->first, type); } } HashSet<String>::const_iterator end = manifest.explicitURLs.end(); for (HashSet<String>::const_iterator it = manifest.explicitURLs.begin(); it != end; ++it) addEntry(*it, ApplicationCacheResource::Explicit); size_t fallbackCount = manifest.fallbackURLs.size(); for (size_t i = 0; i < fallbackCount; ++i) addEntry(manifest.fallbackURLs[i].second, ApplicationCacheResource::Fallback); m_cacheBeingUpdated->setOnlineWhitelist(manifest.onlineWhitelistedURLs); m_cacheBeingUpdated->setFallbackURLs(manifest.fallbackURLs); startLoadingEntry(); }
void ApplicationCacheGroup::didFinishLoadingManifest() { bool isUpgradeAttempt = m_newestCache; if (!isUpgradeAttempt && !m_manifestResource) { // The server returned 304 Not Modified even though we didn't send a conditional request. m_frame->document()->addConsoleMessage(OtherMessageSource, ErrorMessageLevel, "Application Cache manifest could not be fetched because of an unexpected 304 Not Modified server response."); cacheUpdateFailed(); return; } m_manifestHandle = 0; // Check if the manifest was not modified. if (isUpgradeAttempt) { ApplicationCacheResource* newestManifest = m_newestCache->manifestResource(); ASSERT(newestManifest); if (!m_manifestResource || // The resource will be null if HTTP response was 304 Not Modified. (newestManifest->data()->size() == m_manifestResource->data()->size() && !memcmp(newestManifest->data()->data(), m_manifestResource->data()->data(), newestManifest->data()->size()))) { m_completionType = NoUpdate; m_manifestResource = 0; deliverDelayedMainResources(); return; } } Manifest manifest; if (!parseManifest(m_manifestURL, m_manifestResource->data()->data(), m_manifestResource->data()->size(), manifest)) { // At the time of this writing, lack of "CACHE MANIFEST" signature is the only reason for parseManifest to fail. m_frame->document()->addConsoleMessage(OtherMessageSource, ErrorMessageLevel, "Application Cache manifest could not be parsed. Does it start with CACHE MANIFEST?"); cacheUpdateFailed(); return; } ASSERT(!m_cacheBeingUpdated); m_cacheBeingUpdated = ApplicationCache::create(); m_cacheBeingUpdated->setGroup(this); HashSet<DocumentLoader*>::const_iterator masterEnd = m_pendingMasterResourceLoaders.end(); for (HashSet<DocumentLoader*>::const_iterator iter = m_pendingMasterResourceLoaders.begin(); iter != masterEnd; ++iter) associateDocumentLoaderWithCache(*iter, m_cacheBeingUpdated.get()); // We have the manifest, now download the resources. setUpdateStatus(Downloading); postListenerTask(ApplicationCacheHost::DOWNLOADING_EVENT, m_associatedDocumentLoaders); ASSERT(m_pendingEntries.isEmpty()); if (isUpgradeAttempt) { ApplicationCache::ResourceMap::const_iterator end = m_newestCache->end(); for (ApplicationCache::ResourceMap::const_iterator it = m_newestCache->begin(); it != end; ++it) { unsigned type = it->value->type(); if (type & ApplicationCacheResource::Master) addEntry(it->key, type); } } HashSet<String>::const_iterator end = manifest.explicitURLs.end(); for (HashSet<String>::const_iterator it = manifest.explicitURLs.begin(); it != end; ++it) addEntry(*it, ApplicationCacheResource::Explicit); size_t fallbackCount = manifest.fallbackURLs.size(); for (size_t i = 0; i < fallbackCount; ++i) addEntry(manifest.fallbackURLs[i].second, ApplicationCacheResource::Fallback); m_cacheBeingUpdated->setOnlineWhitelist(manifest.onlineWhitelistedURLs); m_cacheBeingUpdated->setFallbackURLs(manifest.fallbackURLs); m_cacheBeingUpdated->setAllowsAllNetworkRequests(manifest.allowAllNetworkRequests); m_progressTotal = m_pendingEntries.size(); m_progressDone = 0; recalculateAvailableSpaceInQuota(); startLoadingEntry(); }
void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, const ResourceResponse& response) { #if ENABLE(INSPECTOR) DocumentLoader* loader = (handle == m_manifestHandle) ? 0 : m_frame->loader().documentLoader(); InspectorInstrumentationCookie cookie = InspectorInstrumentation::willReceiveResourceResponse(m_frame, m_currentResourceIdentifier, response); InspectorInstrumentation::didReceiveResourceResponse(cookie, m_currentResourceIdentifier, loader, response, 0); #endif if (handle == m_manifestHandle) { didReceiveManifestResponse(response); return; } ASSERT(handle == m_currentHandle); URL url(handle->firstRequest().url()); if (url.hasFragmentIdentifier()) url.removeFragmentIdentifier(); ASSERT(!m_currentResource); ASSERT(m_pendingEntries.contains(url)); unsigned type = m_pendingEntries.get(url); // If this is an initial cache attempt, we should not get master resources delivered here. if (!m_newestCache) ASSERT(!(type & ApplicationCacheResource::Master)); if (m_newestCache && response.httpStatusCode() == 304) { // Not modified. ApplicationCacheResource* newestCachedResource = m_newestCache->resourceForURL(url); if (newestCachedResource) { m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, newestCachedResource->response(), type, newestCachedResource->data(), newestCachedResource->path())); m_pendingEntries.remove(m_currentHandle->firstRequest().url()); m_currentHandle->cancel(); m_currentHandle = 0; // Load the next resource, if any. startLoadingEntry(); return; } // The server could return 304 for an unconditional request - in this case, we handle the response as a normal error. } if (response.httpStatusCode() / 100 != 2 || response.url() != m_currentHandle->firstRequest().url()) { if ((type & ApplicationCacheResource::Explicit) || (type & ApplicationCacheResource::Fallback)) { m_frame->document()->addConsoleMessage(AppCacheMessageSource, ErrorMessageLevel, "Application Cache update failed, because " + m_currentHandle->firstRequest().url().stringCenterEllipsizedToLength() + ((response.httpStatusCode() / 100 != 2) ? " could not be fetched." : " was redirected.")); // Note that cacheUpdateFailed() can cause the cache group to be deleted. cacheUpdateFailed(); } else if (response.httpStatusCode() == 404 || response.httpStatusCode() == 410) { // Skip this resource. It is dropped from the cache. m_currentHandle->cancel(); m_currentHandle = 0; m_pendingEntries.remove(url); // Load the next resource, if any. startLoadingEntry(); } else { // Copy the resource and its metadata from the newest application cache in cache group whose completeness flag is complete, and act // as if that was the fetched resource, ignoring the resource obtained from the network. ASSERT(m_newestCache); ApplicationCacheResource* newestCachedResource = m_newestCache->resourceForURL(handle->firstRequest().url()); ASSERT(newestCachedResource); m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, newestCachedResource->response(), type, newestCachedResource->data(), newestCachedResource->path())); m_pendingEntries.remove(m_currentHandle->firstRequest().url()); m_currentHandle->cancel(); m_currentHandle = 0; // Load the next resource, if any. startLoadingEntry(); } return; } m_currentResource = ApplicationCacheResource::create(url, response, type); }
void ApplicationCacheGroup::didFinishLoadingManifest() { bool isUpgradeAttempt = m_newestCache; if (!isUpgradeAttempt && !m_manifestResource) { // The server returned 304 Not Modified even though we didn't send a conditional request. cacheUpdateFailed(); return; } m_manifestHandle = 0; // Check if the manifest was not modified. if (isUpgradeAttempt) { ApplicationCacheResource* newestManifest = m_newestCache->manifestResource(); ASSERT(newestManifest); if (!m_manifestResource || // The resource will be null if HTTP response was 304 Not Modified. (newestManifest->data()->size() == m_manifestResource->data()->size() && !memcmp(newestManifest->data()->data(), m_manifestResource->data()->data(), newestManifest->data()->size()))) { m_completionType = NoUpdate; m_manifestResource = 0; deliverDelayedMainResources(); return; } } Manifest manifest; if (!parseManifest(m_manifestURL, m_manifestResource->data()->data(), m_manifestResource->data()->size(), manifest)) { cacheUpdateFailed(); return; } ASSERT(!m_cacheBeingUpdated); m_cacheBeingUpdated = ApplicationCache::create(); m_cacheBeingUpdated->setGroup(this); HashSet<DocumentLoader*>::const_iterator masterEnd = m_pendingMasterResourceLoaders.end(); for (HashSet<DocumentLoader*>::const_iterator iter = m_pendingMasterResourceLoaders.begin(); iter != masterEnd; ++iter) associateDocumentLoaderWithCache(*iter, m_cacheBeingUpdated.get()); // We have the manifest, now download the resources. setUpdateStatus(Downloading); postListenerTask(ApplicationCacheHost::DOWNLOADING_EVENT, m_associatedDocumentLoaders); ASSERT(m_pendingEntries.isEmpty()); if (isUpgradeAttempt) { ApplicationCache::ResourceMap::const_iterator end = m_newestCache->end(); for (ApplicationCache::ResourceMap::const_iterator it = m_newestCache->begin(); it != end; ++it) { unsigned type = it->second->type(); if (type & ApplicationCacheResource::Master) addEntry(it->first, type); } } HashSet<String>::const_iterator end = manifest.explicitURLs.end(); for (HashSet<String>::const_iterator it = manifest.explicitURLs.begin(); it != end; ++it) addEntry(*it, ApplicationCacheResource::Explicit); size_t fallbackCount = manifest.fallbackURLs.size(); for (size_t i = 0; i < fallbackCount; ++i) addEntry(manifest.fallbackURLs[i].second, ApplicationCacheResource::Fallback); m_cacheBeingUpdated->setOnlineWhitelist(manifest.onlineWhitelistedURLs); m_cacheBeingUpdated->setFallbackURLs(manifest.fallbackURLs); m_cacheBeingUpdated->setAllowsAllNetworkRequests(manifest.allowAllNetworkRequests); m_progressTotal = m_pendingEntries.size(); m_progressDone = 0; startLoadingEntry(); }
void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, const ResourceResponse& response) { #if ENABLE(INSPECTOR) if (Page* page = m_frame->page()) { if (handle == m_manifestHandle) { if (InspectorApplicationCacheAgent* applicationCacheAgent = page->inspectorController()->applicationCacheAgent()) applicationCacheAgent->didReceiveManifestResponse(m_currentResourceIdentifier, response); } else page->inspectorController()->didReceiveResponse(m_currentResourceIdentifier, response); } #endif if (handle == m_manifestHandle) { didReceiveManifestResponse(response); return; } ASSERT(handle == m_currentHandle); KURL url(handle->firstRequest().url()); if (url.hasFragmentIdentifier()) url.removeFragmentIdentifier(); ASSERT(!m_currentResource); ASSERT(m_pendingEntries.contains(url)); unsigned type = m_pendingEntries.get(url); // If this is an initial cache attempt, we should not get master resources delivered here. if (!m_newestCache) ASSERT(!(type & ApplicationCacheResource::Master)); if (m_newestCache && response.httpStatusCode() == 304) { // Not modified. ApplicationCacheResource* newestCachedResource = m_newestCache->resourceForURL(url); if (newestCachedResource) { m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, newestCachedResource->response(), type, newestCachedResource->data())); m_pendingEntries.remove(m_currentHandle->firstRequest().url()); m_currentHandle->cancel(); m_currentHandle = 0; // Load the next resource, if any. startLoadingEntry(); return; } // The server could return 304 for an unconditional request - in this case, we handle the response as a normal error. } if (response.httpStatusCode() / 100 != 2 || response.url() != m_currentHandle->firstRequest().url()) { if ((type & ApplicationCacheResource::Explicit) || (type & ApplicationCacheResource::Fallback)) { // Note that cacheUpdateFailed() can cause the cache group to be deleted. cacheUpdateFailed(); } else if (response.httpStatusCode() == 404 || response.httpStatusCode() == 410) { // Skip this resource. It is dropped from the cache. m_currentHandle->cancel(); m_currentHandle = 0; m_pendingEntries.remove(url); // Load the next resource, if any. startLoadingEntry(); } else { // Copy the resource and its metadata from the newest application cache in cache group whose completeness flag is complete, and act // as if that was the fetched resource, ignoring the resource obtained from the network. ASSERT(m_newestCache); ApplicationCacheResource* newestCachedResource = m_newestCache->resourceForURL(handle->firstRequest().url()); ASSERT(newestCachedResource); m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, newestCachedResource->response(), type, newestCachedResource->data())); m_pendingEntries.remove(m_currentHandle->firstRequest().url()); m_currentHandle->cancel(); m_currentHandle = 0; // Load the next resource, if any. startLoadingEntry(); } return; } m_currentResource = ApplicationCacheResource::create(url, response, type); }
void ApplicationCacheGroup::didFinishLoadingManifest() { bool isUpgradeAttempt = m_newestCache; if (!isUpgradeAttempt && !m_manifestResource) { // The server returned 304 Not Modified even though we didn't send a conditional request. m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, ASCIILiteral("Application Cache manifest could not be fetched because of an unexpected 304 Not Modified server response.")); cacheUpdateFailed(); return; } m_manifestHandle = nullptr; // Check if the manifest was not modified. if (isUpgradeAttempt) { ApplicationCacheResource* newestManifest = m_newestCache->manifestResource(); ASSERT(newestManifest); if (!m_manifestResource || // The resource will be null if HTTP response was 304 Not Modified. (newestManifest->data().size() == m_manifestResource->data().size() && !memcmp(newestManifest->data().data(), m_manifestResource->data().data(), newestManifest->data().size()))) { m_completionType = NoUpdate; m_manifestResource = nullptr; deliverDelayedMainResources(); return; } } Manifest manifest; if (!parseManifest(m_manifestURL, m_manifestResource->data().data(), m_manifestResource->data().size(), manifest)) { // At the time of this writing, lack of "CACHE MANIFEST" signature is the only reason for parseManifest to fail. m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, ASCIILiteral("Application Cache manifest could not be parsed. Does it start with CACHE MANIFEST?")); cacheUpdateFailed(); return; } ASSERT(!m_cacheBeingUpdated); m_cacheBeingUpdated = ApplicationCache::create(); m_cacheBeingUpdated->setGroup(this); for (auto& loader : m_pendingMasterResourceLoaders) associateDocumentLoaderWithCache(loader, m_cacheBeingUpdated.get()); // We have the manifest, now download the resources. setUpdateStatus(Downloading); postListenerTask(ApplicationCacheHost::DOWNLOADING_EVENT, m_associatedDocumentLoaders); ASSERT(m_pendingEntries.isEmpty()); if (isUpgradeAttempt) { for (const auto& urlAndResource : m_newestCache->resources()) { unsigned type = urlAndResource.value->type(); if (type & ApplicationCacheResource::Master) addEntry(urlAndResource.key, type); } } for (const auto& explicitURL : manifest.explicitURLs) addEntry(explicitURL, ApplicationCacheResource::Explicit); for (auto& fallbackURL : manifest.fallbackURLs) addEntry(fallbackURL.second, ApplicationCacheResource::Fallback); m_cacheBeingUpdated->setOnlineWhitelist(manifest.onlineWhitelistedURLs); m_cacheBeingUpdated->setFallbackURLs(manifest.fallbackURLs); m_cacheBeingUpdated->setAllowsAllNetworkRequests(manifest.allowAllNetworkRequests); m_progressTotal = m_pendingEntries.size(); m_progressDone = 0; recalculateAvailableSpaceInQuota(); startLoadingEntry(); }