📄 applicationcachegroup.cpp
字号:
/* * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "config.h"#include "ApplicationCacheGroup.h"#if ENABLE(OFFLINE_WEB_APPLICATIONS)#include "ApplicationCache.h"#include "ApplicationCacheResource.h"#include "ApplicationCacheStorage.h"#include "DocumentLoader.h"#include "DOMApplicationCache.h"#include "DOMWindow.h"#include "Frame.h"#include "FrameLoader.h"#include "MainResourceLoader.h"#include "ManifestParser.h"#include "Page.h"#include "Settings.h"#include <wtf/HashMap.h>namespace WebCore {ApplicationCacheGroup::ApplicationCacheGroup(const KURL& manifestURL, bool isCopy) : m_manifestURL(manifestURL) , m_updateStatus(Idle) , m_frame(0) , m_storageID(0) , m_isObsolete(false) , m_completionType(None) , m_isCopy(isCopy){}ApplicationCacheGroup::~ApplicationCacheGroup(){ if (m_isCopy) { ASSERT(m_newestCache); ASSERT(m_caches.size() == 1); ASSERT(m_caches.contains(m_newestCache.get())); ASSERT(!m_cacheBeingUpdated); ASSERT(m_associatedDocumentLoaders.isEmpty()); ASSERT(m_pendingMasterResourceLoaders.isEmpty()); ASSERT(m_newestCache->group() == this); return; } ASSERT(!m_newestCache); ASSERT(m_caches.isEmpty()); stopLoading(); cacheStorage().cacheGroupDestroyed(this);} ApplicationCache* ApplicationCacheGroup::cacheForMainRequest(const ResourceRequest& request, DocumentLoader*){ if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request)) return 0; if (ApplicationCacheGroup* group = cacheStorage().cacheGroupForURL(request.url())) { ASSERT(group->newestCache()); ASSERT(!group->isObsolete()); return group->newestCache(); } return 0;} ApplicationCache* ApplicationCacheGroup::fallbackCacheForMainRequest(const ResourceRequest& request, DocumentLoader*){ if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request)) return 0; if (ApplicationCacheGroup* group = cacheStorage().fallbackCacheGroupForURL(request.url())) { ASSERT(group->newestCache()); ASSERT(!group->isObsolete()); return group->newestCache(); } return 0;}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, ApplicationCacheUpdateWithBrowsingContext); } 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)) return; // Check that the resource URL has the same scheme/host/port as the manifest URL. if (!protocolHostAndPortAreEqual(manifestURL, request.url())) return; // Don't change anything on disk if private browsing is enabled. if (!frame->settings() || frame->settings()->privateBrowsingEnabled()) { postListenerTask(&DOMApplicationCache::callCheckingListener, documentLoader); postListenerTask(&DOMApplicationCache::callErrorListener, documentLoader); return; } ApplicationCacheGroup* group = cacheStorage().findOrCreateCacheGroup(manifestURL); documentLoader->setCandidateApplicationCacheGroup(group); group->m_pendingMasterResourceLoaders.add(documentLoader); ASSERT(!group->m_cacheBeingUpdated || group->m_updateStatus != Idle); group->update(frame, ApplicationCacheUpdateWithBrowsingContext);}void ApplicationCacheGroup::selectCacheWithoutManifestURL(Frame* frame){ if (!frame->settings()->offlineWebApplicationCacheEnabled()) return; DocumentLoader* documentLoader = frame->loader()->documentLoader(); ASSERT(!documentLoader->applicationCache()); ApplicationCache* mainResourceCache = documentLoader->mainResourceApplicationCache(); if (mainResourceCache) { mainResourceCache->group()->associateDocumentLoaderWithCache(documentLoader, mainResourceCache); mainResourceCache->group()->update(frame, ApplicationCacheUpdateWithBrowsingContext); }}void ApplicationCacheGroup::finishedLoadingMainResource(DocumentLoader* loader){ ASSERT(m_pendingMasterResourceLoaders.contains(loader)); ASSERT(m_completionType == None || m_pendingEntries.isEmpty()); const KURL& url = loader->url(); switch (m_completionType) { case None: // The main resource finished loading before the manifest was ready. It will be handled via dispatchMainResources() later. return; case NoUpdate: ASSERT(!m_cacheBeingUpdated); associateDocumentLoaderWithCache(loader, m_newestCache.get()); if (ApplicationCacheResource* resource = m_newestCache->resourceForURL(url)) { if (!(resource->type() & ApplicationCacheResource::Master)) { resource->addType(ApplicationCacheResource::Master); ASSERT(!resource->storageID()); } } else m_newestCache->addResource(ApplicationCacheResource::create(url, loader->response(), ApplicationCacheResource::Master, loader->mainResourceData())); break; case Failure: // Cache update has been a failure, so there is no reason to keep the document associated with the incomplete cache // (its main resource was not cached yet, so it is likely that the application changed significantly server-side). ASSERT(!m_cacheBeingUpdated); // Already cleared out by stopLoading(). loader->setApplicationCache(0); // Will unset candidate, too. m_associatedDocumentLoaders.remove(loader); postListenerTask(&DOMApplicationCache::callErrorListener, loader); break; case Completed: ASSERT(m_associatedDocumentLoaders.contains(loader)); if (ApplicationCacheResource* resource = m_cacheBeingUpdated->resourceForURL(url)) { if (!(resource->type() & ApplicationCacheResource::Master)) { resource->addType(ApplicationCacheResource::Master); ASSERT(!resource->storageID()); } } else m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, loader->response(), ApplicationCacheResource::Master, loader->mainResourceData())); // The "cached" event will be posted to all associated documents once update is complete. break; } m_pendingMasterResourceLoaders.remove(loader); checkIfLoadIsComplete();}void ApplicationCacheGroup::failedLoadingMainResource(DocumentLoader* loader){ ASSERT(m_pendingMasterResourceLoaders.contains(loader)); ASSERT(m_completionType == None || m_pendingEntries.isEmpty()); switch (m_completionType) { case None: // The main resource finished loading before the manifest was ready. It will be handled via dispatchMainResources() later. return; case NoUpdate: ASSERT(!m_cacheBeingUpdated); // The manifest didn't change, and we have a relevant cache - but the main resource download failed mid-way, so it cannot be stored to the cache, // and the loader does not get associated to it. If there are other main resources being downloaded for this cache group, they may still succeed. postListenerTask(&DOMApplicationCache::callErrorListener, loader); break; case Failure: // Cache update failed, too. ASSERT(!m_cacheBeingUpdated); // Already cleared out by stopLoading(). ASSERT(!loader->applicationCache() || loader->applicationCache() == m_cacheBeingUpdated); loader->setApplicationCache(0); // Will unset candidate, too. m_associatedDocumentLoaders.remove(loader); postListenerTask(&DOMApplicationCache::callErrorListener, loader); break; case Completed: // The cache manifest didn't list this main resource, and all cache entries were already updated successfully - but the main resource failed to load, // so it cannot be stored to the cache. If there are other main resources being downloaded for this cache group, they may still succeed. ASSERT(m_associatedDocumentLoaders.contains(loader)); ASSERT(loader->applicationCache() == m_cacheBeingUpdated); ASSERT(!loader->candidateApplicationCacheGroup()); m_associatedDocumentLoaders.remove(loader); loader->setApplicationCache(0); postListenerTask(&DOMApplicationCache::callErrorListener, loader); break; } m_pendingMasterResourceLoaders.remove(loader); checkIfLoadIsComplete();}void ApplicationCacheGroup::stopLoading(){ if (m_manifestHandle) { ASSERT(!m_currentHandle); m_manifestHandle->setClient(0); m_manifestHandle->cancel(); m_manifestHandle = 0; } if (m_currentHandle) { ASSERT(!m_manifestHandle); ASSERT(m_cacheBeingUpdated);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -