diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/loader/appcache | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/loader/appcache')
16 files changed, 1132 insertions, 1310 deletions
diff --git a/Source/WebCore/loader/appcache/ApplicationCache.cpp b/Source/WebCore/loader/appcache/ApplicationCache.cpp index 983becc21..a95ed2cac 100644 --- a/Source/WebCore/loader/appcache/ApplicationCache.cpp +++ b/Source/WebCore/loader/appcache/ApplicationCache.cpp @@ -30,7 +30,6 @@ #include "ApplicationCacheResource.h" #include "ApplicationCacheStorage.h" #include "ResourceRequest.h" -#include "SecurityOrigin.h" #include <algorithm> #include <stdio.h> #include <wtf/text/CString.h> @@ -43,17 +42,13 @@ static inline bool fallbackURLLongerThan(const std::pair<URL, URL>& lhs, const s } ApplicationCache::ApplicationCache() - : m_group(0) - , m_manifest(0) - , m_estimatedSizeInStorage(0) - , m_storageID(0) { } ApplicationCache::~ApplicationCache() { - if (m_group && !m_group->isCopy()) - m_group->cacheDestroyed(this); + if (m_group) + m_group->cacheDestroyed(*this); } void ApplicationCache::setGroup(ApplicationCacheGroup* group) @@ -62,59 +57,41 @@ void ApplicationCache::setGroup(ApplicationCacheGroup* group) m_group = group; } -bool ApplicationCache::isComplete() const +bool ApplicationCache::isComplete() { - return !m_group->cacheIsBeingUpdated(this); + return m_group && m_group->cacheIsComplete(*this); } -void ApplicationCache::setManifestResource(PassRefPtr<ApplicationCacheResource> manifest) +void ApplicationCache::setManifestResource(Ref<ApplicationCacheResource>&& manifest) { - ASSERT(manifest); ASSERT(!m_manifest); ASSERT(manifest->type() & ApplicationCacheResource::Manifest); - - m_manifest = manifest.get(); - - addResource(manifest); + + m_manifest = manifest.ptr(); + + addResource(WTFMove(manifest)); } -void ApplicationCache::addResource(PassRefPtr<ApplicationCacheResource> resource) +void ApplicationCache::addResource(Ref<ApplicationCacheResource>&& resource) { - ASSERT(resource); - - const String& url = resource->url(); - + auto& url = resource->url(); + + ASSERT(!URL(ParsedURLString, url).hasFragmentIdentifier()); ASSERT(!m_resources.contains(url)); - + if (m_storageID) { ASSERT(!resource->storageID()); ASSERT(resource->type() & ApplicationCacheResource::Master); - + // Add the resource to the storage. - cacheStorage().store(resource.get(), this); + m_group->storage().store(resource.ptr(), this); } m_estimatedSizeInStorage += resource->estimatedSizeInStorage(); - m_resources.set(url, resource); + m_resources.set(url, WTFMove(resource)); } -unsigned ApplicationCache::removeResource(const String& url) -{ - HashMap<String, RefPtr<ApplicationCacheResource>>::iterator it = m_resources.find(url); - if (it == m_resources.end()) - return 0; - - // The resource exists, get its type so we can return it. - unsigned type = it->value->type(); - - m_estimatedSizeInStorage -= it->value->estimatedSizeInStorage(); - - m_resources.remove(it); - - return type; -} - ApplicationCacheResource* ApplicationCache::resourceForURL(const String& url) { ASSERT(!URL(ParsedURLString, url).hasFragmentIdentifier()); @@ -123,25 +100,17 @@ ApplicationCacheResource* ApplicationCache::resourceForURL(const String& url) bool ApplicationCache::requestIsHTTPOrHTTPSGet(const ResourceRequest& request) { - if (!request.url().protocolIsInHTTPFamily()) - return false; - - if (!equalIgnoringCase(request.httpMethod(), "GET")) - return false; - - return true; -} + return request.url().protocolIsInHTTPFamily() && equalLettersIgnoringASCIICase(request.httpMethod(), "get"); +} ApplicationCacheResource* ApplicationCache::resourceForRequest(const ResourceRequest& request) { // We only care about HTTP/HTTPS GET requests. if (!requestIsHTTPOrHTTPSGet(request)) - return 0; + return nullptr; URL url(request.url()); - if (url.hasFragmentIdentifier()) - url.removeFragmentIdentifier(); - + url.removeFragmentIdentifier(); return resourceForURL(url); } @@ -153,9 +122,8 @@ void ApplicationCache::setOnlineWhitelist(const Vector<URL>& onlineWhitelist) bool ApplicationCache::isURLInOnlineWhitelist(const URL& url) { - size_t whitelistSize = m_onlineWhitelist.size(); - for (size_t i = 0; i < whitelistSize; ++i) { - if (protocolHostAndPortAreEqual(url, m_onlineWhitelist[i]) && url.string().startsWith(m_onlineWhitelist[i].string())) + for (auto& whitelistURL : m_onlineWhitelist) { + if (protocolHostAndPortAreEqual(url, whitelistURL) && url.string().startsWith(whitelistURL.string())) return true; } return false; @@ -171,11 +139,10 @@ void ApplicationCache::setFallbackURLs(const FallbackURLVector& fallbackURLs) bool ApplicationCache::urlMatchesFallbackNamespace(const URL& url, URL* fallbackURL) { - size_t fallbackCount = m_fallbackURLs.size(); - for (size_t i = 0; i < fallbackCount; ++i) { - if (protocolHostAndPortAreEqual(url, m_fallbackURLs[i].first) && url.string().startsWith(m_fallbackURLs[i].first.string())) { + for (auto& fallback : m_fallbackURLs) { + if (protocolHostAndPortAreEqual(url, fallback.first) && url.string().startsWith(fallback.first.string())) { if (fallbackURL) - *fallbackURL = m_fallbackURLs[i].second; + *fallbackURL = fallback.second; return true; } } @@ -190,43 +157,12 @@ void ApplicationCache::clearStorageID() resource->clearStorageID(); } -void ApplicationCache::deleteCacheForOrigin(SecurityOrigin* origin) -{ - Vector<URL> urls; - if (!cacheStorage().manifestURLs(&urls)) { - LOG_ERROR("Failed to retrieve ApplicationCache manifest URLs"); - return; - } - - URL originURL(URL(), origin->toString()); - - size_t count = urls.size(); - for (size_t i = 0; i < count; ++i) { - if (protocolHostAndPortAreEqual(urls[i], originURL)) { - ApplicationCacheGroup* group = cacheStorage().findInMemoryCacheGroup(urls[i]); - if (group) - group->makeObsolete(); - else - cacheStorage().deleteCacheGroup(urls[i]); - } - } -} - -int64_t ApplicationCache::diskUsageForOrigin(SecurityOrigin* origin) -{ - int64_t usage = 0; - cacheStorage().calculateUsageForOrigin(origin, usage); - return usage; -} - #ifndef NDEBUG void ApplicationCache::dump() { - HashMap<String, RefPtr<ApplicationCacheResource>>::const_iterator end = m_resources.end(); - - for (HashMap<String, RefPtr<ApplicationCacheResource>>::const_iterator it = m_resources.begin(); it != end; ++it) { - printf("%s ", it->key.ascii().data()); - ApplicationCacheResource::dumpType(it->value->type()); + for (const auto& urlAndResource : m_resources) { + printf("%s ", urlAndResource.key.utf8().data()); + ApplicationCacheResource::dumpType(urlAndResource.value->type()); } } #endif diff --git a/Source/WebCore/loader/appcache/ApplicationCache.h b/Source/WebCore/loader/appcache/ApplicationCache.h index 680635def..5df5f6017 100644 --- a/Source/WebCore/loader/appcache/ApplicationCache.h +++ b/Source/WebCore/loader/appcache/ApplicationCache.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008-2017 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,45 +23,35 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ApplicationCache_h -#define ApplicationCache_h +#pragma once #include <wtf/HashMap.h> -#include <wtf/HashSet.h> -#include <wtf/PassRefPtr.h> -#include <wtf/RefCounted.h> #include <wtf/text/StringHash.h> -#include <wtf/text/WTFString.h> namespace WebCore { class ApplicationCacheGroup; class ApplicationCacheResource; -class DocumentLoader; -class URL; class ResourceRequest; -class SecurityOrigin; +class URL; -typedef Vector<std::pair<URL, URL>> FallbackURLVector; +using FallbackURLVector = Vector<std::pair<URL, URL>>; class ApplicationCache : public RefCounted<ApplicationCache> { public: - static PassRefPtr<ApplicationCache> create() { return adoptRef(new ApplicationCache); } - - static void deleteCacheForOrigin(SecurityOrigin*); - + static Ref<ApplicationCache> create() { return adoptRef(*new ApplicationCache); } + ~ApplicationCache(); - void addResource(PassRefPtr<ApplicationCacheResource> resource); - unsigned removeResource(const String& url); - - void setManifestResource(PassRefPtr<ApplicationCacheResource> manifest); + void addResource(Ref<ApplicationCacheResource>&&); + + void setManifestResource(Ref<ApplicationCacheResource>&&); ApplicationCacheResource* manifestResource() const { return m_manifest; } - + void setGroup(ApplicationCacheGroup*); ApplicationCacheGroup* group() const { return m_group; } - bool isComplete() const; + bool isComplete(); ApplicationCacheResource* resourceForRequest(const ResourceRequest&); ApplicationCacheResource* resourceForURL(const String& url); @@ -74,45 +64,39 @@ public: void setFallbackURLs(const FallbackURLVector&); const FallbackURLVector& fallbackURLs() const { return m_fallbackURLs; } - bool urlMatchesFallbackNamespace(const URL&, URL* fallbackURL = 0); - + bool urlMatchesFallbackNamespace(const URL&, URL* fallbackURL = nullptr); + #ifndef NDEBUG void dump(); #endif - typedef HashMap<String, RefPtr<ApplicationCacheResource>> ResourceMap; - ResourceMap::const_iterator begin() const { return m_resources.begin(); } - ResourceMap::const_iterator end() const { return m_resources.end(); } - + using ResourceMap = HashMap<String, RefPtr<ApplicationCacheResource>>; + const ResourceMap& resources() const { return m_resources; } + void setStorageID(unsigned storageID) { m_storageID = storageID; } unsigned storageID() const { return m_storageID; } void clearStorageID(); - + static bool requestIsHTTPOrHTTPSGet(const ResourceRequest&); - static int64_t diskUsageForOrigin(SecurityOrigin*); - int64_t estimatedSizeInStorage() const { return m_estimatedSizeInStorage; } private: ApplicationCache(); - - ApplicationCacheGroup* m_group; + + ApplicationCacheGroup* m_group { nullptr }; ResourceMap m_resources; - ApplicationCacheResource* m_manifest; + ApplicationCacheResource* m_manifest { nullptr }; - bool m_allowAllNetworkRequests; + bool m_allowAllNetworkRequests { false }; Vector<URL> m_onlineWhitelist; FallbackURLVector m_fallbackURLs; // The total size of the resources belonging to this Application Cache instance. - // This is an estimation of the size this Application Cache occupies in the - // database file. - int64_t m_estimatedSizeInStorage; + // This is an estimation of the size this Application Cache occupies in the database file. + int64_t m_estimatedSizeInStorage { 0 }; - unsigned m_storageID; + unsigned m_storageID { 0 }; }; } // namespace WebCore - -#endif // ApplicationCache_h diff --git a/Source/WebCore/loader/appcache/ApplicationCacheAllInOne.cpp b/Source/WebCore/loader/appcache/ApplicationCacheAllInOne.cpp new file mode 100644 index 000000000..73eaf7214 --- /dev/null +++ b/Source/WebCore/loader/appcache/ApplicationCacheAllInOne.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2012 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. + */ + +// This all-in-one cpp file cuts down on template bloat to allow us to build our Windows release build. + +#include "ApplicationCache.cpp" +#include "ApplicationCacheGroup.cpp" +#include "ApplicationCacheHost.cpp" +#include "ApplicationCacheResource.cpp" +#include "ApplicationCacheStorage.cpp" diff --git a/Source/WebCore/loader/appcache/ApplicationCacheGroup.cpp b/Source/WebCore/loader/appcache/ApplicationCacheGroup.cpp index 8e67597a6..9f9ab000c 100644 --- a/Source/WebCore/loader/appcache/ApplicationCacheGroup.cpp +++ b/Source/WebCore/loader/appcache/ApplicationCacheGroup.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved. + * Copyright (C) 2008-2017 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -20,7 +20,7 @@ * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" @@ -32,161 +32,151 @@ #include "ApplicationCacheStorage.h" #include "Chrome.h" #include "ChromeClient.h" -#include "Console.h" #include "DOMApplicationCache.h" -#include "DOMWindow.h" #include "DocumentLoader.h" +#include "EventNames.h" #include "Frame.h" #include "FrameLoader.h" #include "FrameLoaderClient.h" +#include "HTTPHeaderNames.h" #include "InspectorInstrumentation.h" #include "ManifestParser.h" #include "Page.h" -#include "ResourceBuffer.h" +#include "ProgressTracker.h" #include "ResourceHandle.h" -#include "ScriptProfile.h" #include "SecurityOrigin.h" #include "Settings.h" #include <wtf/HashMap.h> #include <wtf/MainThread.h> -#if ENABLE(INSPECTOR) -#include "ProgressTracker.h" -#endif - namespace WebCore { -ApplicationCacheGroup::ApplicationCacheGroup(const URL& manifestURL, bool isCopy) - : m_manifestURL(manifestURL) +ApplicationCacheGroup::ApplicationCacheGroup(Ref<ApplicationCacheStorage>&& storage, const URL& manifestURL) + : m_storage(WTFMove(storage)) + , m_manifestURL(manifestURL) , m_origin(SecurityOrigin::create(manifestURL)) - , m_updateStatus(Idle) - , m_downloadingPendingMasterResourceLoadersCount(0) - , m_progressTotal(0) - , m_progressDone(0) - , m_frame(0) - , m_storageID(0) - , m_isObsolete(false) - , m_completionType(None) - , m_isCopy(isCopy) - , m_calledReachedMaxAppCacheSize(false) , m_availableSpaceInQuota(ApplicationCacheStorage::unknownQuota()) - , m_originQuotaExceededPreviously(false) { } 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); + + m_storage->cacheGroupDestroyed(*this); } -ApplicationCache* ApplicationCacheGroup::cacheForMainRequest(const ResourceRequest& request, DocumentLoader*) +ApplicationCache* ApplicationCacheGroup::cacheForMainRequest(const ResourceRequest& request, DocumentLoader* documentLoader) { if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request)) - return 0; + return nullptr; URL url(request.url()); - if (url.hasFragmentIdentifier()) - url.removeFragmentIdentifier(); + url.removeFragmentIdentifier(); - if (ApplicationCacheGroup* group = cacheStorage().cacheGroupForURL(url)) { - ASSERT(group->newestCache()); - ASSERT(!group->isObsolete()); - - return group->newestCache(); - } - - return 0; + auto* page = documentLoader->frame() ? documentLoader->frame()->page() : nullptr; + if (!page || page->usesEphemeralSession()) + return nullptr; + + auto* group = page->applicationCacheStorage().cacheGroupForURL(url); + if (!group) + return nullptr; + + ASSERT(group->newestCache()); + ASSERT(!group->isObsolete()); + + return group->newestCache(); } -ApplicationCache* ApplicationCacheGroup::fallbackCacheForMainRequest(const ResourceRequest& request, DocumentLoader*) +ApplicationCache* ApplicationCacheGroup::fallbackCacheForMainRequest(const ResourceRequest& request, DocumentLoader* documentLoader) { if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request)) - return 0; + return nullptr; + + auto* frame = documentLoader->frame(); + if (!frame) + return nullptr; + + auto* page = frame->page(); + if (!page) + return nullptr; URL url(request.url()); - if (url.hasFragmentIdentifier()) - url.removeFragmentIdentifier(); + url.removeFragmentIdentifier(); - if (ApplicationCacheGroup* group = cacheStorage().fallbackCacheGroupForURL(url)) { - ASSERT(group->newestCache()); - ASSERT(!group->isObsolete()); + auto* group = page->applicationCacheStorage().fallbackCacheGroupForURL(url); + if (!group) + return nullptr; - return group->newestCache(); - } - - return 0; + ASSERT(group->newestCache()); + ASSERT(!group->isObsolete()); + + return group->newestCache(); } -void ApplicationCacheGroup::selectCache(Frame* frame, const URL& passedManifestURL) +void ApplicationCacheGroup::selectCache(Frame& frame, const URL& passedManifestURL) { - ASSERT(frame && frame->page()); - - if (!frame->settings().offlineWebApplicationCacheEnabled()) - return; + ASSERT(frame.document()); + ASSERT(frame.page()); + ASSERT(frame.loader().documentLoader()); - if (!frame->document()->securityOrigin()->canAccessApplicationCache(frame->tree().top().document()->securityOrigin())) + if (!frame.settings().offlineWebApplicationCacheEnabled()) return; - - DocumentLoader* documentLoader = frame->loader().documentLoader(); - ASSERT(!documentLoader->applicationCacheHost()->applicationCache()); + + auto& documentLoader = *frame.loader().documentLoader(); + ASSERT(!documentLoader.applicationCacheHost().applicationCache()); if (passedManifestURL.isNull()) { - selectCacheWithoutManifestURL(frame); + 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(eventNames().checkingEvent, documentLoader); + postListenerTask(eventNames().errorEvent, documentLoader); return; } URL manifestURL(passedManifestURL); - if (manifestURL.hasFragmentIdentifier()) - manifestURL.removeFragmentIdentifier(); + manifestURL.removeFragmentIdentifier(); - ApplicationCache* mainResourceCache = documentLoader->applicationCacheHost()->mainResourceApplicationCache(); + auto* mainResourceCache = documentLoader.applicationCacheHost().mainResourceApplicationCache(); if (mainResourceCache) { + ASSERT(mainResourceCache->group()); 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()->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); + URL resourceURL { documentLoader.responseURL() }; + resourceURL.removeFragmentIdentifier(); + + ASSERT(mainResourceCache->resourceForURL(resourceURL)); + auto& resource = *mainResourceCache->resourceForURL(resourceURL); + + bool inStorage = resource.storageID(); + resource.addType(ApplicationCacheResource::Foreign); if (inStorage) - cacheStorage().storeUpdatedType(resource, mainResourceCache); + 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()->securityOrigin(), documentLoader->url(), frame->loader().referrer()); + 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(); + auto& request = frame.loader().activeDocumentLoader()->request(); if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request)) return; @@ -195,49 +185,48 @@ void ApplicationCacheGroup::selectCache(Frame* frame, const URL& passedManifestU if (!protocolHostAndPortAreEqual(manifestURL, request.url())) return; - // Don't change anything on disk if private browsing is enabled. - if (frame->settings().privateBrowsingEnabled()) { - postListenerTask(ApplicationCacheHost::CHECKING_EVENT, documentLoader); - postListenerTask(ApplicationCacheHost::ERROR_EVENT, documentLoader); - return; - } - - ApplicationCacheGroup* group = cacheStorage().findOrCreateCacheGroup(manifestURL); + auto& group = *frame.page()->applicationCacheStorage().findOrCreateCacheGroup(manifestURL); - documentLoader->applicationCacheHost()->setCandidateApplicationCacheGroup(group); - group->m_pendingMasterResourceLoaders.add(documentLoader); - group->m_downloadingPendingMasterResourceLoadersCount++; + documentLoader.applicationCacheHost().setCandidateApplicationCacheGroup(&group); + group.m_pendingMasterResourceLoaders.add(&documentLoader); + group.m_downloadingPendingMasterResourceLoadersCount++; - ASSERT(!group->m_cacheBeingUpdated || group->m_updateStatus != Idle); - group->update(frame, ApplicationCacheUpdateWithBrowsingContext); + ASSERT(!group.m_cacheBeingUpdated || group.m_updateStatus != Idle); + group.update(frame, ApplicationCacheUpdateWithBrowsingContext); } -void ApplicationCacheGroup::selectCacheWithoutManifestURL(Frame* frame) +void ApplicationCacheGroup::selectCacheWithoutManifestURL(Frame& frame) { - if (!frame->settings().offlineWebApplicationCacheEnabled()) - return; - - if (!frame->document()->securityOrigin()->canAccessApplicationCache(frame->tree().top().document()->securityOrigin())) + if (!frame.settings().offlineWebApplicationCacheEnabled()) return; - DocumentLoader* documentLoader = frame->loader().documentLoader(); - ASSERT(!documentLoader->applicationCacheHost()->applicationCache()); + ASSERT(frame.document()); + ASSERT(frame.page()); + ASSERT(frame.loader().documentLoader()); + auto& documentLoader = *frame.loader().documentLoader(); + ASSERT(!documentLoader.applicationCacheHost().applicationCache()); - ApplicationCache* mainResourceCache = documentLoader->applicationCacheHost()->mainResourceApplicationCache(); + // 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(eventNames().checkingEvent, documentLoader); + postListenerTask(eventNames().errorEvent, documentLoader); + return; + } - if (mainResourceCache) { - mainResourceCache->group()->associateDocumentLoaderWithCache(documentLoader, mainResourceCache); - mainResourceCache->group()->update(frame, ApplicationCacheUpdateWithBrowsingContext); + if (auto* mainResourceCache = documentLoader.applicationCacheHost().mainResourceApplicationCache()) { + ASSERT(mainResourceCache->group()); + auto& group = *mainResourceCache->group(); + group.associateDocumentLoaderWithCache(&documentLoader, mainResourceCache); + group.update(frame, ApplicationCacheUpdateWithBrowsingContext); } } -void ApplicationCacheGroup::finishedLoadingMainResource(DocumentLoader* loader) +void ApplicationCacheGroup::finishedLoadingMainResource(DocumentLoader& loader) { - ASSERT(m_pendingMasterResourceLoaders.contains(loader)); + ASSERT(m_pendingMasterResourceLoaders.contains(&loader)); ASSERT(m_completionType == None || m_pendingEntries.isEmpty()); - URL url = loader->url(); - if (url.hasFragmentIdentifier()) - url.removeFragmentIdentifier(); + URL url = loader.url(); + url.removeFragmentIdentifier(); switch (m_completionType) { case None: @@ -245,39 +234,32 @@ void ApplicationCacheGroup::finishedLoadingMainResource(DocumentLoader* loader) return; case NoUpdate: ASSERT(!m_cacheBeingUpdated); - associateDocumentLoaderWithCache(loader, m_newestCache.get()); - - if (ApplicationCacheResource* resource = m_newestCache->resourceForURL(url)) { + associateDocumentLoaderWithCache(&loader, m_newestCache.get()); + if (auto* resource = m_newestCache->resourceForURL(url)) { if (!(resource->type() & ApplicationCacheResource::Master)) { resource->addType(ApplicationCacheResource::Master); ASSERT(!resource->storageID()); } - } else { - RefPtr<ResourceBuffer> buffer = loader->mainResourceData(); - m_newestCache->addResource(ApplicationCacheResource::create(url, loader->response(), ApplicationCacheResource::Master, buffer ? buffer->sharedBuffer() : 0)); - } - + } 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->applicationCacheHost()->setApplicationCache(0); // Will unset candidate, too. - m_associatedDocumentLoaders.remove(loader); - postListenerTask(ApplicationCacheHost::ERROR_EVENT, loader); + loader.applicationCacheHost().setApplicationCache(nullptr); // Will unset candidate, too. + m_associatedDocumentLoaders.remove(&loader); + postListenerTask(eventNames().errorEvent, loader); break; case Completed: - ASSERT(m_associatedDocumentLoaders.contains(loader)); - - if (ApplicationCacheResource* resource = m_cacheBeingUpdated->resourceForURL(url)) { + ASSERT(m_associatedDocumentLoaders.contains(&loader)); + if (auto* resource = m_cacheBeingUpdated->resourceForURL(url)) { if (!(resource->type() & ApplicationCacheResource::Master)) { resource->addType(ApplicationCacheResource::Master); ASSERT(!resource->storageID()); } - } else { - RefPtr<ResourceBuffer> buffer = loader->mainResourceData(); - m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, loader->response(), ApplicationCacheResource::Master, buffer ? buffer->sharedBuffer() : 0)); - } + } 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; } @@ -287,9 +269,9 @@ void ApplicationCacheGroup::finishedLoadingMainResource(DocumentLoader* loader) checkIfLoadIsComplete(); } -void ApplicationCacheGroup::failedLoadingMainResource(DocumentLoader* loader) +void ApplicationCacheGroup::failedLoadingMainResource(DocumentLoader& loader) { - ASSERT(m_pendingMasterResourceLoaders.contains(loader)); + ASSERT(m_pendingMasterResourceLoaders.contains(&loader)); ASSERT(m_completionType == None || m_pendingEntries.isEmpty()); switch (m_completionType) { @@ -298,32 +280,27 @@ void ApplicationCacheGroup::failedLoadingMainResource(DocumentLoader* loader) 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(ApplicationCacheHost::ERROR_EVENT, loader); - + postListenerTask(eventNames().errorEvent, loader); break; case Failure: // Cache update failed, too. ASSERT(!m_cacheBeingUpdated); // Already cleared out by stopLoading(). - ASSERT(!loader->applicationCacheHost()->applicationCache() || loader->applicationCacheHost()->applicationCache() == m_cacheBeingUpdated); - - loader->applicationCacheHost()->setApplicationCache(0); // Will unset candidate, too. - m_associatedDocumentLoaders.remove(loader); - postListenerTask(ApplicationCacheHost::ERROR_EVENT, loader); + ASSERT(!loader.applicationCacheHost().applicationCache() || loader.applicationCacheHost().applicationCache()->group() == this); + loader.applicationCacheHost().setApplicationCache(nullptr); // Will unset candidate, too. + m_associatedDocumentLoaders.remove(&loader); + postListenerTask(eventNames().errorEvent, 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->applicationCacheHost()->applicationCache() == m_cacheBeingUpdated); - ASSERT(!loader->applicationCacheHost()->candidateApplicationCacheGroup()); - m_associatedDocumentLoaders.remove(loader); - loader->applicationCacheHost()->setApplicationCache(0); - - postListenerTask(ApplicationCacheHost::ERROR_EVENT, loader); - + ASSERT(m_associatedDocumentLoaders.contains(&loader)); + ASSERT(loader.applicationCacheHost().applicationCache() == m_cacheBeingUpdated); + ASSERT(!loader.applicationCacheHost().candidateApplicationCacheGroup()); + m_associatedDocumentLoaders.remove(&loader); + loader.applicationCacheHost().setApplicationCache(nullptr); + postListenerTask(eventNames().errorEvent, loader); break; } @@ -338,10 +315,10 @@ void ApplicationCacheGroup::stopLoading() ASSERT(!m_currentHandle); ASSERT(m_manifestHandle->client() == this); - m_manifestHandle->setClient(0); + m_manifestHandle->clearClient(); m_manifestHandle->cancel(); - m_manifestHandle = 0; + m_manifestHandle = nullptr; } if (m_currentHandle) { @@ -349,23 +326,24 @@ void ApplicationCacheGroup::stopLoading() ASSERT(m_cacheBeingUpdated); ASSERT(m_currentHandle->client() == this); - m_currentHandle->setClient(0); + m_currentHandle->clearClient(); m_currentHandle->cancel(); - m_currentHandle = 0; + m_currentHandle = nullptr; } // FIXME: Resetting just a tiny part of the state in this function is confusing. Callers have to take care of a lot more. - m_cacheBeingUpdated = 0; + m_cacheBeingUpdated = nullptr; m_pendingEntries.clear(); } -void ApplicationCacheGroup::disassociateDocumentLoader(DocumentLoader* loader) +void ApplicationCacheGroup::disassociateDocumentLoader(DocumentLoader& loader) { - m_associatedDocumentLoaders.remove(loader); - m_pendingMasterResourceLoaders.remove(loader); + m_associatedDocumentLoaders.remove(&loader); + m_pendingMasterResourceLoaders.remove(&loader); - loader->applicationCacheHost()->setApplicationCache(0); // Will set candidate to 0, too. + if (auto* host = loader.applicationCacheHostUnlessBeingDestroyed()) + host->setApplicationCache(nullptr); // Will set candidate group to null, too. if (!m_associatedDocumentLoaders.isEmpty() || !m_pendingMasterResourceLoaders.isEmpty()) return; @@ -382,29 +360,29 @@ void ApplicationCacheGroup::disassociateDocumentLoader(DocumentLoader* loader) // Release our reference to the newest cache. This could cause us to be deleted. // Any ongoing updates will be stopped from destructor. - m_newestCache.release(); + m_newestCache = nullptr; } -void ApplicationCacheGroup::cacheDestroyed(ApplicationCache* cache) +void ApplicationCacheGroup::cacheDestroyed(ApplicationCache& cache) { - if (m_caches.remove(cache) && m_caches.isEmpty()) { + if (m_caches.remove(&cache) && m_caches.isEmpty()) { ASSERT(m_associatedDocumentLoaders.isEmpty()); ASSERT(m_pendingMasterResourceLoaders.isEmpty()); delete this; } } -void ApplicationCacheGroup::stopLoadingInFrame(Frame* frame) +void ApplicationCacheGroup::stopLoadingInFrame(Frame& frame) { - if (frame != m_frame) + if (&frame != m_frame) return; cacheUpdateFailed(); } -void ApplicationCacheGroup::setNewestCache(PassRefPtr<ApplicationCache> newestCache) +void ApplicationCacheGroup::setNewestCache(Ref<ApplicationCache>&& newestCache) { - m_newestCache = newestCache; + m_newestCache = WTFMove(newestCache); m_caches.add(m_newestCache.get()); m_newestCache->setGroup(this); @@ -416,40 +394,43 @@ void ApplicationCacheGroup::makeObsolete() return; m_isObsolete = true; - cacheStorage().cacheGroupMadeObsolete(this); + m_storage->cacheGroupMadeObsolete(*this); ASSERT(!m_storageID); } -void ApplicationCacheGroup::update(Frame* frame, ApplicationCacheUpdateOption updateOption) +void ApplicationCacheGroup::update(Frame& frame, ApplicationCacheUpdateOption updateOption) { + ASSERT(frame.loader().documentLoader()); + auto& documentLoader = *frame.loader().documentLoader(); + if (m_updateStatus == Checking || m_updateStatus == Downloading) { if (updateOption == ApplicationCacheUpdateWithBrowsingContext) { - postListenerTask(ApplicationCacheHost::CHECKING_EVENT, frame->loader().documentLoader()); + postListenerTask(eventNames().checkingEvent, documentLoader); if (m_updateStatus == Downloading) - postListenerTask(ApplicationCacheHost::DOWNLOADING_EVENT, frame->loader().documentLoader()); + postListenerTask(eventNames().downloadingEvent, documentLoader); } return; } - // Don't change anything on disk if private browsing is enabled. - if (frame->settings().privateBrowsingEnabled()) { + // Don't access anything on disk if private browsing is enabled. + if (frame.page()->usesEphemeralSession() || !frame.document()->securityOrigin().canAccessApplicationCache(frame.tree().top().document()->securityOrigin())) { ASSERT(m_pendingMasterResourceLoaders.isEmpty()); ASSERT(m_pendingEntries.isEmpty()); ASSERT(!m_cacheBeingUpdated); - postListenerTask(ApplicationCacheHost::CHECKING_EVENT, frame->loader().documentLoader()); - postListenerTask(ApplicationCacheHost::NOUPDATE_EVENT, frame->loader().documentLoader()); + postListenerTask(eventNames().checkingEvent, documentLoader); + postListenerTask(eventNames().errorEvent, documentLoader); return; } ASSERT(!m_frame); - m_frame = frame; + m_frame = &frame; setUpdateStatus(Checking); - postListenerTask(ApplicationCacheHost::CHECKING_EVENT, m_associatedDocumentLoaders); + postListenerTask(eventNames().checkingEvent, m_associatedDocumentLoaders); if (!m_newestCache) { ASSERT(updateOption == ApplicationCacheUpdateWithBrowsingContext); - postListenerTask(ApplicationCacheHost::CHECKING_EVENT, frame->loader().documentLoader()); + postListenerTask(eventNames().checkingEvent, documentLoader); } ASSERT(!m_manifestHandle); @@ -462,7 +443,7 @@ void ApplicationCacheGroup::update(Frame* frame, ApplicationCacheUpdateOption up m_manifestHandle = createResourceHandle(m_manifestURL, m_newestCache ? m_newestCache->manifestResource() : 0); } -void ApplicationCacheGroup::abort(Frame* frame) +void ApplicationCacheGroup::abort(Frame& frame) { if (m_updateStatus == Idle) return; @@ -471,56 +452,51 @@ void ApplicationCacheGroup::abort(Frame* frame) if (m_completionType != None) return; - frame->document()->addConsoleMessage(NetworkMessageSource, DebugMessageLevel, "Application Cache download process was aborted."); + frame.document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Debug, ASCIILiteral("Application Cache download process was aborted.")); cacheUpdateFailed(); } -PassRefPtr<ResourceHandle> ApplicationCacheGroup::createResourceHandle(const URL& url, ApplicationCacheResource* newestCachedResource) +RefPtr<ResourceHandle> ApplicationCacheGroup::createResourceHandle(const URL& url, ApplicationCacheResource* newestCachedResource) { ResourceRequest request(url); m_frame->loader().applyUserAgent(request); - request.setHTTPHeaderField("Cache-Control", "max-age=0"); + request.setHTTPHeaderField(HTTPHeaderName::CacheControl, "max-age=0"); if (newestCachedResource) { - const String& lastModified = newestCachedResource->response().httpHeaderField("Last-Modified"); - const String& eTag = newestCachedResource->response().httpHeaderField("ETag"); + const String& lastModified = newestCachedResource->response().httpHeaderField(HTTPHeaderName::LastModified); + const String& eTag = newestCachedResource->response().httpHeaderField(HTTPHeaderName::ETag); if (!lastModified.isEmpty() || !eTag.isEmpty()) { if (!lastModified.isEmpty()) - request.setHTTPHeaderField("If-Modified-Since", lastModified); + request.setHTTPHeaderField(HTTPHeaderName::IfModifiedSince, lastModified); if (!eTag.isEmpty()) - request.setHTTPHeaderField("If-None-Match", eTag); + request.setHTTPHeaderField(HTTPHeaderName::IfNoneMatch, eTag); } } RefPtr<ResourceHandle> handle = ResourceHandle::create(m_frame->loader().networkingContext(), request, this, false, true); -#if ENABLE(INSPECTOR) + // Because willSendRequest only gets called during redirects, we initialize // the identifier and the first willSendRequest here. m_currentResourceIdentifier = m_frame->page()->progress().createUniqueIdentifier(); ResourceResponse redirectResponse = ResourceResponse(); InspectorInstrumentation::willSendRequest(m_frame, m_currentResourceIdentifier, m_frame->loader().documentLoader(), request, redirectResponse); -#endif return handle; } -void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, const ResourceResponse& response) +void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, 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 + ASSERT(m_frame); + InspectorInstrumentation::didReceiveResourceResponse(*m_frame, m_currentResourceIdentifier, m_frame->loader().documentLoader(), response, nullptr); if (handle == m_manifestHandle) { didReceiveManifestResponse(response); return; } - + ASSERT(handle == m_currentHandle); URL url(handle->firstRequest().url()); - if (url.hasFragmentIdentifier()) - url.removeFragmentIdentifier(); + url.removeFragmentIdentifier(); ASSERT(!m_currentResource); ASSERT(m_pendingEntries.contains(url)); @@ -534,10 +510,10 @@ void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, const Res 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_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; + m_currentHandle = nullptr; // Load the next resource, if any. startLoadingEntry(); return; @@ -547,14 +523,14 @@ void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, const Res 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() + + m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, "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_currentHandle = nullptr; m_pendingEntries.remove(url); // Load the next resource, if any. startLoadingEntry(); @@ -564,10 +540,10 @@ void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, const Res 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_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; + m_currentHandle = nullptr; // Load the next resource, if any. startLoadingEntry(); } @@ -581,9 +557,7 @@ void ApplicationCacheGroup::didReceiveData(ResourceHandle* handle, const char* d { UNUSED_PARAM(encodedDataLength); -#if ENABLE(INSPECTOR) InspectorInstrumentation::didReceiveData(m_frame, m_currentResourceIdentifier, 0, length, 0); -#endif if (handle == m_manifestHandle) { didReceiveManifestData(data, length); @@ -593,16 +567,12 @@ void ApplicationCacheGroup::didReceiveData(ResourceHandle* handle, const char* d ASSERT(handle == m_currentHandle); ASSERT(m_currentResource); - m_currentResource->data()->append(data, length); + m_currentResource->data().append(data, length); } void ApplicationCacheGroup::didFinishLoading(ResourceHandle* handle, double finishTime) { -#if ENABLE(INSPECTOR) InspectorInstrumentation::didFinishLoading(m_frame, m_frame->loader().documentLoader(), m_currentResourceIdentifier, finishTime); -#else - UNUSED_PARAM(finishTime); -#endif if (handle == m_manifestHandle) { didFinishLoadingManifest(); @@ -616,8 +586,8 @@ void ApplicationCacheGroup::didFinishLoading(ResourceHandle* handle, double fini ASSERT(m_cacheBeingUpdated); - m_cacheBeingUpdated->addResource(m_currentResource.release()); - m_currentHandle = 0; + m_cacheBeingUpdated->addResource(m_currentResource.releaseNonNull()); + 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 @@ -625,8 +595,8 @@ void ApplicationCacheGroup::didFinishLoading(ResourceHandle* handle, double fini // 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 = 0; - m_frame->document()->addConsoleMessage(AppCacheMessageSource, ErrorMessageLevel, "Application Cache update failed, because size quota was exceeded."); + m_currentResource = nullptr; + m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, ASCIILiteral("Application Cache update failed, because size quota was exceeded.")); cacheUpdateFailed(); return; } @@ -637,11 +607,7 @@ void ApplicationCacheGroup::didFinishLoading(ResourceHandle* handle, double fini 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. @@ -653,15 +619,14 @@ void ApplicationCacheGroup::didFail(ResourceHandle* handle, const ResourceError& unsigned type = m_currentResource ? m_currentResource->type() : m_pendingEntries.get(handle->firstRequest().url()); URL url(handle->firstRequest().url()); - if (url.hasFragmentIdentifier()) - url.removeFragmentIdentifier(); + url.removeFragmentIdentifier(); ASSERT(!m_currentResource || !m_pendingEntries.contains(url)); - m_currentResource = 0; + m_currentResource = nullptr; 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."); + m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, "Application Cache update failed, because " + url.stringCenterEllipsizedToLength() + " could not be fetched."); // Note that cacheUpdateFailed() can cause the cache group to be deleted. cacheUpdateFailed(); } else { @@ -670,7 +635,7 @@ void ApplicationCacheGroup::didFail(ResourceHandle* handle, const ResourceError& ASSERT(m_newestCache); ApplicationCacheResource* newestCachedResource = m_newestCache->resourceForURL(url); ASSERT(newestCachedResource); - m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, newestCachedResource->response(), type, newestCachedResource->data(), newestCachedResource->path())); + m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, newestCachedResource->response(), type, &newestCachedResource->data(), newestCachedResource->path())); // Load the next resource, if any. startLoadingEntry(); } @@ -682,6 +647,8 @@ void ApplicationCacheGroup::didReceiveManifestResponse(const ResourceResponse& r ASSERT(m_manifestHandle); if (response.httpStatusCode() == 404 || response.httpStatusCode() == 410) { + InspectorInstrumentation::didFailLoading(m_frame, m_frame->loader().documentLoader(), m_currentResourceIdentifier, m_frame->loader().cancelledError(m_manifestHandle->firstRequest())); + m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, makeString("Application Cache manifest could not be fetched, because the manifest had a ", String::number(response.httpStatusCode()), " response.")); manifestNotFound(); return; } @@ -690,13 +657,15 @@ void ApplicationCacheGroup::didReceiveManifestResponse(const ResourceResponse& r return; if (response.httpStatusCode() / 100 != 2) { - m_frame->document()->addConsoleMessage(OtherMessageSource, ErrorMessageLevel, "Application Cache manifest could not be fetched."); + InspectorInstrumentation::didFailLoading(m_frame, m_frame->loader().documentLoader(), m_currentResourceIdentifier, m_frame->loader().cancelledError(m_manifestHandle->firstRequest())); + m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, makeString("Application Cache manifest could not be fetched, because the manifest had a ", String::number(response.httpStatusCode()), " response.")); cacheUpdateFailed(); return; } if (response.url() != m_manifestHandle->firstRequest().url()) { - m_frame->document()->addConsoleMessage(OtherMessageSource, ErrorMessageLevel, "Application Cache manifest could not be fetched, because a redirection was attempted."); + InspectorInstrumentation::didFailLoading(m_frame, m_frame->loader().documentLoader(), m_currentResourceIdentifier, m_frame->loader().cancelledError(m_manifestHandle->firstRequest())); + m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, ASCIILiteral("Application Cache manifest could not be fetched, because a redirection was attempted.")); cacheUpdateFailed(); return; } @@ -707,7 +676,7 @@ void ApplicationCacheGroup::didReceiveManifestResponse(const ResourceResponse& r void ApplicationCacheGroup::didReceiveManifestData(const char* data, int length) { if (m_manifestResource) - m_manifestResource->data()->append(data, length); + m_manifestResource->data().append(data, length); } void ApplicationCacheGroup::didFinishLoadingManifest() @@ -716,12 +685,12 @@ void ApplicationCacheGroup::didFinishLoadingManifest() 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."); + 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 = 0; + m_manifestHandle = nullptr; // Check if the manifest was not modified. if (isUpgradeAttempt) { @@ -729,10 +698,10 @@ void ApplicationCacheGroup::didFinishLoadingManifest() 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()))) { + (newestManifest->data().size() == m_manifestResource->data().size() && !memcmp(newestManifest->data().data(), m_manifestResource->data().data(), newestManifest->data().size()))) { m_completionType = NoUpdate; - m_manifestResource = 0; + m_manifestResource = nullptr; deliverDelayedMainResources(); return; @@ -740,9 +709,9 @@ void ApplicationCacheGroup::didFinishLoadingManifest() } Manifest manifest; - if (!parseManifest(m_manifestURL, m_manifestResource->data()->data(), m_manifestResource->data()->size(), 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?"); + m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, ASCIILiteral("Application Cache manifest could not be parsed. Does it start with CACHE MANIFEST?")); cacheUpdateFailed(); return; } @@ -751,19 +720,18 @@ void ApplicationCacheGroup::didFinishLoadingManifest() 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()); + 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); + postListenerTask(eventNames().downloadingEvent, m_associatedDocumentLoaders); ASSERT(m_pendingEntries.isEmpty()); if (isUpgradeAttempt) { - for (const auto& urlAndResource : *m_newestCache) { + for (const auto& urlAndResource : m_newestCache->resources()) { unsigned type = urlAndResource.value->type(); if (type & ApplicationCacheResource::Master) addEntry(urlAndResource.key, type); @@ -773,9 +741,8 @@ void ApplicationCacheGroup::didFinishLoadingManifest() for (const auto& explicitURL : manifest.explicitURLs) addEntry(explicitURL, ApplicationCacheResource::Explicit); - size_t fallbackCount = manifest.fallbackURLs.size(); - for (size_t i = 0; i < fallbackCount; ++i) - addEntry(manifest.fallbackURLs[i].second, ApplicationCacheResource::Fallback); + for (auto& fallbackURL : manifest.fallbackURLs) + addEntry(fallbackURL.second, ApplicationCacheResource::Fallback); m_cacheBeingUpdated->setOnlineWhitelist(manifest.onlineWhitelistedURLs); m_cacheBeingUpdated->setFallbackURLs(manifest.fallbackURLs); @@ -793,7 +760,7 @@ void ApplicationCacheGroup::didReachMaxAppCacheSize() { ASSERT(m_frame); ASSERT(m_cacheBeingUpdated); - m_frame->page()->chrome().client().reachedMaxAppCacheSize(cacheStorage().spaceNeeded(m_cacheBeingUpdated->estimatedSizeInStorage())); + m_frame->page()->chrome().client().reachedMaxAppCacheSize(m_frame->page()->applicationCacheStorage().spaceNeeded(m_cacheBeingUpdated->estimatedSizeInStorage())); m_calledReachedMaxAppCacheSize = true; checkIfLoadIsComplete(); } @@ -808,7 +775,7 @@ void ApplicationCacheGroup::didReachOriginQuota(int64_t totalSpaceNeeded) void ApplicationCacheGroup::cacheUpdateFailed() { stopLoading(); - m_manifestResource = 0; + m_manifestResource = nullptr; // Wait for master resource loads to finish. m_completionType = Failure; @@ -817,7 +784,7 @@ void ApplicationCacheGroup::cacheUpdateFailed() void ApplicationCacheGroup::recalculateAvailableSpaceInQuota() { - if (!cacheStorage().calculateRemainingSizeForOriginExcludingCache(m_origin.get(), m_newestCache.get(), m_availableSpaceInQuota)) { + if (!m_frame->page()->applicationCacheStorage().calculateRemainingSizeForOriginExcludingCache(m_origin, m_newestCache.get(), m_availableSpaceInQuota)) { // Failed to determine what is left in the quota. Fallback to allowing anything. m_availableSpaceInQuota = ApplicationCacheStorage::noQuota(); } @@ -827,27 +794,27 @@ void ApplicationCacheGroup::manifestNotFound() { makeObsolete(); - postListenerTask(ApplicationCacheHost::OBSOLETE_EVENT, m_associatedDocumentLoaders); - postListenerTask(ApplicationCacheHost::ERROR_EVENT, m_pendingMasterResourceLoaders); + postListenerTask(eventNames().obsoleteEvent, m_associatedDocumentLoaders); + postListenerTask(eventNames().errorEvent, m_pendingMasterResourceLoaders); stopLoading(); ASSERT(m_pendingEntries.isEmpty()); - m_manifestResource = 0; + m_manifestResource = nullptr; while (!m_pendingMasterResourceLoaders.isEmpty()) { HashSet<DocumentLoader*>::iterator it = m_pendingMasterResourceLoaders.begin(); - ASSERT((*it)->applicationCacheHost()->candidateApplicationCacheGroup() == this); - ASSERT(!(*it)->applicationCacheHost()->applicationCache()); - (*it)->applicationCacheHost()->setCandidateApplicationCacheGroup(0); + ASSERT((*it)->applicationCacheHost().candidateApplicationCacheGroup() == this); + ASSERT(!(*it)->applicationCacheHost().applicationCache()); + (*it)->applicationCacheHost().setCandidateApplicationCacheGroup(nullptr); m_pendingMasterResourceLoaders.remove(it); } m_downloadingPendingMasterResourceLoadersCount = 0; setUpdateStatus(Idle); - m_frame = 0; - + m_frame = nullptr; + if (m_caches.isEmpty()) { ASSERT(m_associatedDocumentLoaders.isEmpty()); ASSERT(!m_cacheBeingUpdated); @@ -874,13 +841,13 @@ void ApplicationCacheGroup::checkIfLoadIsComplete() // The storage could have been manually emptied by the user. if (!m_storageID) - cacheStorage().storeNewestCache(this); + m_storage->storeNewestCache(*this); - postListenerTask(ApplicationCacheHost::NOUPDATE_EVENT, m_associatedDocumentLoaders); + postListenerTask(eventNames().noupdateEvent, m_associatedDocumentLoaders); break; case Failure: ASSERT(!m_cacheBeingUpdated); - postListenerTask(ApplicationCacheHost::ERROR_EVENT, m_associatedDocumentLoaders); + postListenerTask(eventNames().errorEvent, m_associatedDocumentLoaders); if (m_caches.isEmpty()) { ASSERT(m_associatedDocumentLoaders.isEmpty()); delete this; @@ -892,14 +859,14 @@ void ApplicationCacheGroup::checkIfLoadIsComplete() ASSERT(m_cacheBeingUpdated); if (m_manifestResource) - m_cacheBeingUpdated->setManifestResource(m_manifestResource.release()); + m_cacheBeingUpdated->setManifestResource(m_manifestResource.releaseNonNull()); else { // We can get here as a result of retrying the Complete step, following // a failure of the cache storage to save the newest cache due to hitting // the maximum size. In such a case, m_manifestResource may be 0, as // the manifest was already set on the newest cache object. ASSERT(m_cacheBeingUpdated->manifestResource()); - ASSERT(cacheStorage().isMaximumSizeReached()); + ASSERT(m_storage->isMaximumSizeReached()); ASSERT(m_calledReachedMaxAppCacheSize); } @@ -908,22 +875,22 @@ void ApplicationCacheGroup::checkIfLoadIsComplete() // If we exceeded the origin quota while downloading we can request a quota // increase now, before we attempt to store the cache. int64_t totalSpaceNeeded; - if (!cacheStorage().checkOriginQuota(this, oldNewestCache.get(), m_cacheBeingUpdated.get(), totalSpaceNeeded)) + if (!m_storage->checkOriginQuota(this, oldNewestCache.get(), m_cacheBeingUpdated.get(), totalSpaceNeeded)) didReachOriginQuota(totalSpaceNeeded); ApplicationCacheStorage::FailureReason failureReason; - setNewestCache(m_cacheBeingUpdated.release()); - if (cacheStorage().storeNewestCache(this, oldNewestCache.get(), failureReason)) { + setNewestCache(m_cacheBeingUpdated.releaseNonNull()); + if (m_storage->storeNewestCache(*this, oldNewestCache.get(), failureReason)) { // New cache stored, now remove the old cache. if (oldNewestCache) - cacheStorage().remove(oldNewestCache.get()); + m_storage->remove(oldNewestCache.get()); // Fire the final progress event. ASSERT(m_progressDone == m_progressTotal); - postListenerTask(ApplicationCacheHost::PROGRESS_EVENT, m_progressTotal, m_progressDone, m_associatedDocumentLoaders); + postListenerTask(eventNames().progressEvent, m_progressTotal, m_progressDone, m_associatedDocumentLoaders); // Fire the success event. - postListenerTask(isUpgradeAttempt ? ApplicationCacheHost::UPDATEREADY_EVENT : ApplicationCacheHost::CACHED_EVENT, m_associatedDocumentLoaders); + postListenerTask(isUpgradeAttempt ? eventNames().updatereadyEvent : eventNames().cachedEvent, m_associatedDocumentLoaders); // It is clear that the origin quota was not reached, so clear the flag if it was set. m_originQuotaExceededPreviously = false; } else { @@ -931,7 +898,7 @@ void ApplicationCacheGroup::checkIfLoadIsComplete() // We ran out of space for this origin. Fall down to the normal error handling // after recording this state. m_originQuotaExceededPreviously = true; - m_frame->document()->addConsoleMessage(OtherMessageSource, ErrorMessageLevel, "Application Cache update failed, because size quota was exceeded."); + m_frame->document()->addConsoleMessage(MessageSource::AppCache, MessageLevel::Error, ASCIILiteral("Application Cache update failed, because size quota was exceeded.")); } if (failureReason == ApplicationCacheStorage::TotalQuotaReached && !m_calledReachedMaxAppCacheSize) { @@ -943,11 +910,9 @@ void ApplicationCacheGroup::checkIfLoadIsComplete() // save the new cache. // Save a reference to the new cache. - m_cacheBeingUpdated = m_newestCache.release(); - if (oldNewestCache) { - // Reinstate the oldNewestCache. - setNewestCache(oldNewestCache.release()); - } + m_cacheBeingUpdated = WTFMove(m_newestCache); + if (oldNewestCache) + setNewestCache(oldNewestCache.releaseNonNull()); scheduleReachedMaxAppCacheSizeCallback(); return; } @@ -955,7 +920,7 @@ void ApplicationCacheGroup::checkIfLoadIsComplete() // Run the "cache failure steps" // Fire the error events to all pending master entries, as well any other cache hosts // currently associated with a cache in this group. - postListenerTask(ApplicationCacheHost::ERROR_EVENT, m_associatedDocumentLoaders); + postListenerTask(eventNames().errorEvent, m_associatedDocumentLoaders); // Disassociate the pending master entries from the failed new cache. Note that // all other loaders in the m_associatedDocumentLoaders are still associated with // some other cache in this group. They are not associated with the failed new cache. @@ -963,14 +928,13 @@ void ApplicationCacheGroup::checkIfLoadIsComplete() // Need to copy loaders, because the cache group may be destroyed at the end of iteration. Vector<DocumentLoader*> loaders; copyToVector(m_pendingMasterResourceLoaders, loaders); - size_t count = loaders.size(); - for (size_t i = 0; i != count; ++i) - disassociateDocumentLoader(loaders[i]); // This can delete this group. + for (auto& loader : loaders) + disassociateDocumentLoader(*loader); // This can delete this group. // Reinstate the oldNewestCache, if there was one. if (oldNewestCache) { // This will discard the failed new cache. - setNewestCache(oldNewestCache.release()); + setNewestCache(oldNewestCache.releaseNonNull()); } else { // We must have been deleted by the last call to disassociateDocumentLoader(). return; @@ -984,7 +948,7 @@ void ApplicationCacheGroup::checkIfLoadIsComplete() m_pendingMasterResourceLoaders.clear(); m_completionType = None; setUpdateStatus(Idle); - m_frame = 0; + m_frame = nullptr; m_availableSpaceInQuota = ApplicationCacheStorage::unknownQuota(); m_calledReachedMaxAppCacheSize = false; } @@ -999,14 +963,13 @@ void ApplicationCacheGroup::startLoadingEntry() return; } - EntryMap::const_iterator it = m_pendingEntries.begin(); + auto firstPendingEntryURL = m_pendingEntries.begin()->key; - postListenerTask(ApplicationCacheHost::PROGRESS_EVENT, m_progressTotal, m_progressDone, m_associatedDocumentLoaders); + postListenerTask(eventNames().progressEvent, m_progressTotal, m_progressDone, m_associatedDocumentLoaders); m_progressDone++; ASSERT(!m_currentHandle); - - m_currentHandle = createResourceHandle(URL(ParsedURLString, it->key), m_newestCache ? m_newestCache->resourceForURL(it->key) : 0); + m_currentHandle = createResourceHandle(URL(ParsedURLString, firstPendingEntryURL), m_newestCache ? m_newestCache->resourceForURL(firstPendingEntryURL) : 0); } void ApplicationCacheGroup::deliverDelayedMainResources() @@ -1014,19 +977,15 @@ void ApplicationCacheGroup::deliverDelayedMainResources() // Need to copy loaders, because the cache group may be destroyed at the end of iteration. Vector<DocumentLoader*> loaders; copyToVector(m_pendingMasterResourceLoaders, loaders); - size_t count = loaders.size(); - for (size_t i = 0; i != count; ++i) { - DocumentLoader* loader = loaders[i]; + for (auto* loader : loaders) { if (loader->isLoadingMainResource()) continue; - - const ResourceError& error = loader->mainDocumentError(); - if (error.isNull()) - finishedLoadingMainResource(loader); + if (loader->mainDocumentError().isNull()) + finishedLoadingMainResource(*loader); else - failedLoadingMainResource(loader); + failedLoadingMainResource(*loader); } - if (!count) + if (loaders.isEmpty()) checkIfLoadIsComplete(); } @@ -1034,13 +993,12 @@ void ApplicationCacheGroup::addEntry(const String& url, unsigned type) { ASSERT(m_cacheBeingUpdated); ASSERT(!URL(ParsedURLString, url).hasFragmentIdentifier()); - + // Don't add the URL if we already have an master resource in the cache // (i.e., the main resource finished loading before the manifest). - if (ApplicationCacheResource* resource = m_cacheBeingUpdated->resourceForURL(url)) { + if (auto* resource = m_cacheBeingUpdated->resourceForURL(url)) { ASSERT(resource->type() & ApplicationCacheResource::Master); ASSERT(!m_frame->loader().documentLoader()->isLoadingMainResource()); - resource->addType(type); return; } @@ -1051,11 +1009,8 @@ void ApplicationCacheGroup::addEntry(const String& url, unsigned type) m_manifestResource->addType(type); return; } - - EntryMap::AddResult result = m_pendingEntries.add(url, type); - - if (!result.isNewEntry) - result.iterator->value |= type; + + m_pendingEntries.add(url, type).iterator->value |= type; } void ApplicationCacheGroup::associateDocumentLoaderWithCache(DocumentLoader* loader, ApplicationCache* cache) @@ -1066,90 +1021,64 @@ void ApplicationCacheGroup::associateDocumentLoaderWithCache(DocumentLoader* loa ASSERT(!m_isObsolete); - loader->applicationCacheHost()->setApplicationCache(cache); + loader->applicationCacheHost().setApplicationCache(cache); ASSERT(!m_associatedDocumentLoaders.contains(loader)); m_associatedDocumentLoaders.add(loader); } -class ChromeClientCallbackTimer: public TimerBase { +class ChromeClientCallbackTimer final : public TimerBase { public: - ChromeClientCallbackTimer(ApplicationCacheGroup* cacheGroup) - : m_cacheGroup(cacheGroup) + ChromeClientCallbackTimer(ApplicationCacheGroup& group) + : m_group(group) { } private: - virtual void fired() override + void fired() final { - m_cacheGroup->didReachMaxAppCacheSize(); + m_group.didReachMaxAppCacheSize(); delete this; } - // Note that there is no need to use a RefPtr here. The ApplicationCacheGroup instance is guaranteed - // to be alive when the timer fires since invoking the ChromeClient callback is part of its normal + + // Note that there is no need to use a Ref here. The ApplicationCacheGroup instance is guaranteed + // to be alive when the timer fires since invoking the callback is part of its normal // update machinery and nothing can yet cause it to get deleted. - ApplicationCacheGroup* m_cacheGroup; + ApplicationCacheGroup& m_group; }; void ApplicationCacheGroup::scheduleReachedMaxAppCacheSizeCallback() { ASSERT(isMainThread()); - ChromeClientCallbackTimer* timer = new ChromeClientCallbackTimer(this); + auto* timer = new ChromeClientCallbackTimer(*this); timer->startOneShot(0); // The timer will delete itself once it fires. } -class CallCacheListenerTask : public ScriptExecutionContext::Task { -public: - static PassOwnPtr<CallCacheListenerTask> create(PassRefPtr<DocumentLoader> loader, ApplicationCacheHost::EventID eventID, int progressTotal, int progressDone) - { - return adoptPtr(new CallCacheListenerTask(loader, eventID, progressTotal, progressDone)); - } - - virtual void performTask(ScriptExecutionContext* context) override - { - - ASSERT_UNUSED(context, context->isDocument()); - Frame* frame = m_documentLoader->frame(); - if (!frame) - return; - - ASSERT(frame->loader().documentLoader() == m_documentLoader.get()); - - m_documentLoader->applicationCacheHost()->notifyDOMApplicationCache(m_eventID, m_progressTotal, m_progressDone); - } - -private: - CallCacheListenerTask(PassRefPtr<DocumentLoader> loader, ApplicationCacheHost::EventID eventID, int progressTotal, int progressDone) - : m_documentLoader(loader) - , m_eventID(eventID) - , m_progressTotal(progressTotal) - , m_progressDone(progressDone) - { - } - - RefPtr<DocumentLoader> m_documentLoader; - ApplicationCacheHost::EventID m_eventID; - int m_progressTotal; - int m_progressDone; -}; - -void ApplicationCacheGroup::postListenerTask(ApplicationCacheHost::EventID eventID, int progressTotal, int progressDone, const HashSet<DocumentLoader*>& loaderSet) +void ApplicationCacheGroup::postListenerTask(const AtomicString& eventType, int progressTotal, int progressDone, const HashSet<DocumentLoader*>& loaderSet) { - HashSet<DocumentLoader*>::const_iterator loaderSetEnd = loaderSet.end(); - for (HashSet<DocumentLoader*>::const_iterator iter = loaderSet.begin(); iter != loaderSetEnd; ++iter) - postListenerTask(eventID, progressTotal, progressDone, *iter); + for (auto& loader : loaderSet) + postListenerTask(eventType, progressTotal, progressDone, *loader); } -void ApplicationCacheGroup::postListenerTask(ApplicationCacheHost::EventID eventID, int progressTotal, int progressDone, DocumentLoader* loader) +void ApplicationCacheGroup::postListenerTask(const AtomicString& eventType, int progressTotal, int progressDone, DocumentLoader& loader) { - Frame* frame = loader->frame(); + auto* frame = loader.frame(); if (!frame) return; - ASSERT(frame->loader().documentLoader() == loader); + ASSERT(frame->loader().documentLoader() == &loader); + + RefPtr<DocumentLoader> protectedLoader(&loader); + frame->document()->postTask([protectedLoader, &eventType, progressTotal, progressDone] (ScriptExecutionContext& context) { + ASSERT_UNUSED(context, context.isDocument()); + auto* frame = protectedLoader->frame(); + if (!frame) + return; - frame->document()->postTask(CallCacheListenerTask::create(loader, eventID, progressTotal, progressDone)); + ASSERT(frame->loader().documentLoader() == protectedLoader); + protectedLoader->applicationCacheHost().notifyDOMApplicationCache(eventType, progressTotal, progressDone); + }); } void ApplicationCacheGroup::setUpdateStatus(UpdateStatus status) @@ -1160,8 +1089,7 @@ void ApplicationCacheGroup::setUpdateStatus(UpdateStatus status) void ApplicationCacheGroup::clearStorageID() { m_storageID = 0; - - for (const auto& cache : m_caches) + for (auto& cache : m_caches) cache->clearStorageID(); } diff --git a/Source/WebCore/loader/appcache/ApplicationCacheGroup.h b/Source/WebCore/loader/appcache/ApplicationCacheGroup.h index e1fb198ed..ceb83dfc6 100644 --- a/Source/WebCore/loader/appcache/ApplicationCacheGroup.h +++ b/Source/WebCore/loader/appcache/ApplicationCacheGroup.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved. + * Copyright (C) 2008-2017 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,13 +23,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ApplicationCacheGroup_h -#define ApplicationCacheGroup_h +#pragma once #include "DOMApplicationCache.h" #include "URL.h" #include "ResourceHandleClient.h" -#include "SharedBuffer.h" #include <wtf/Noncopyable.h> #include <wtf/HashMap.h> #include <wtf/HashSet.h> @@ -39,6 +37,7 @@ namespace WebCore { class ApplicationCache; class ApplicationCacheResource; +class ApplicationCacheStorage; class Document; class DocumentLoader; class Frame; @@ -50,10 +49,11 @@ enum ApplicationCacheUpdateOption { ApplicationCacheUpdateWithoutBrowsingContext }; -class ApplicationCacheGroup : ResourceHandleClient { - WTF_MAKE_NONCOPYABLE(ApplicationCacheGroup); WTF_MAKE_FAST_ALLOCATED; +class ApplicationCacheGroup final : private ResourceHandleClient { + WTF_MAKE_NONCOPYABLE(ApplicationCacheGroup); + WTF_MAKE_FAST_ALLOCATED; public: - ApplicationCacheGroup(const URL& manifestURL, bool isCopy = false); + explicit ApplicationCacheGroup(Ref<ApplicationCacheStorage>&&, const URL& manifestURL); virtual ~ApplicationCacheGroup(); enum UpdateStatus { Idle, Checking, Downloading }; @@ -61,11 +61,12 @@ public: static ApplicationCache* cacheForMainRequest(const ResourceRequest&, DocumentLoader*); static ApplicationCache* fallbackCacheForMainRequest(const ResourceRequest&, DocumentLoader*); - static void selectCache(Frame*, const URL& manifestURL); - static void selectCacheWithoutManifestURL(Frame*); - + static void selectCache(Frame&, const URL& manifestURL); + static void selectCacheWithoutManifestURL(Frame&); + + ApplicationCacheStorage& storage() { return m_storage; } const URL& manifestURL() const { return m_manifestURL; } - const SecurityOrigin* origin() const { return m_origin.get(); } + const SecurityOrigin& origin() const { return m_origin.get(); } UpdateStatus updateStatus() const { return m_updateStatus; } void setUpdateStatus(UpdateStatus status); @@ -73,46 +74,44 @@ public: unsigned storageID() const { return m_storageID; } void clearStorageID(); - void update(Frame*, ApplicationCacheUpdateOption); // FIXME: Frame should not be needed when updating without browsing context. - void cacheDestroyed(ApplicationCache*); + void update(Frame&, ApplicationCacheUpdateOption); // FIXME: Frame should not be needed when updating without browsing context. + void cacheDestroyed(ApplicationCache&); - void abort(Frame*); + void abort(Frame&); - bool cacheIsBeingUpdated(const ApplicationCache* cache) const { return cache == m_cacheBeingUpdated; } + bool cacheIsComplete(ApplicationCache& cache) { return m_caches.contains(&cache); } - void stopLoadingInFrame(Frame*); + void stopLoadingInFrame(Frame&); ApplicationCache* newestCache() const { return m_newestCache.get(); } - void setNewestCache(PassRefPtr<ApplicationCache>); + void setNewestCache(Ref<ApplicationCache>&&); void makeObsolete(); bool isObsolete() const { return m_isObsolete; } - void finishedLoadingMainResource(DocumentLoader*); - void failedLoadingMainResource(DocumentLoader*); - - void disassociateDocumentLoader(DocumentLoader*); + void finishedLoadingMainResource(DocumentLoader&); + void failedLoadingMainResource(DocumentLoader&); - bool isCopy() const { return m_isCopy; } + void disassociateDocumentLoader(DocumentLoader&); private: - static void postListenerTask(ApplicationCacheHost::EventID id, const HashSet<DocumentLoader*>& set) { postListenerTask(id, 0, 0, set); } - static void postListenerTask(ApplicationCacheHost::EventID id, DocumentLoader* loader) { postListenerTask(id, 0, 0, loader); } - static void postListenerTask(ApplicationCacheHost::EventID, int progressTotal, int progressDone, const HashSet<DocumentLoader*>&); - static void postListenerTask(ApplicationCacheHost::EventID, int progressTotal, int progressDone, DocumentLoader*); + static void postListenerTask(const AtomicString& eventType, const HashSet<DocumentLoader*>& set) { postListenerTask(eventType, 0, 0, set); } + static void postListenerTask(const AtomicString& eventType, DocumentLoader& loader) { postListenerTask(eventType, 0, 0, loader); } + static void postListenerTask(const AtomicString& eventType, int progressTotal, int progressDone, const HashSet<DocumentLoader*>&); + static void postListenerTask(const AtomicString& eventType, int progressTotal, int progressDone, DocumentLoader&); void scheduleReachedMaxAppCacheSizeCallback(); - PassRefPtr<ResourceHandle> createResourceHandle(const URL&, ApplicationCacheResource* newestCachedResource); + RefPtr<ResourceHandle> createResourceHandle(const URL&, ApplicationCacheResource* newestCachedResource); // For normal resource loading, WebKit client is asked about each resource individually. Since application cache does not belong to any particular document, // the existing client callback cannot be used, so assume that any client that enables application cache also wants it to use credential storage. - virtual bool shouldUseCredentialStorage(ResourceHandle*) override { return true; } + bool shouldUseCredentialStorage(ResourceHandle*) override { return true; } - virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&) override; - virtual void didReceiveData(ResourceHandle*, const char*, unsigned length, int encodedDataLength) override; - virtual void didFinishLoading(ResourceHandle*, double finishTime) override; - virtual void didFail(ResourceHandle*, const ResourceError&) override; + void didReceiveResponse(ResourceHandle*, ResourceResponse&&) override; + void didReceiveData(ResourceHandle*, const char*, unsigned length, int encodedDataLength) override; + void didFinishLoading(ResourceHandle*, double finishTime) override; + void didFail(ResourceHandle*, const ResourceError&) override; void didReceiveManifestResponse(const ResourceResponse&); void didReceiveManifestData(const char*, int); @@ -132,10 +131,12 @@ private: void associateDocumentLoaderWithCache(DocumentLoader*, ApplicationCache*); void stopLoading(); - + + Ref<ApplicationCacheStorage> m_storage; + URL m_manifestURL; - RefPtr<SecurityOrigin> m_origin; - UpdateStatus m_updateStatus; + Ref<SecurityOrigin> m_origin; + UpdateStatus m_updateStatus { Idle }; // This is the newest complete cache in the group. RefPtr<ApplicationCache> m_newestCache; @@ -150,26 +151,25 @@ private: // List of pending master entries, used during the update process to ensure that new master entries are cached. HashSet<DocumentLoader*> m_pendingMasterResourceLoaders; // How many of the above pending master entries have not yet finished downloading. - int m_downloadingPendingMasterResourceLoadersCount; + int m_downloadingPendingMasterResourceLoadersCount { 0 }; // These are all the document loaders that are associated with a cache in this group. HashSet<DocumentLoader*> m_associatedDocumentLoaders; // The URLs and types of pending cache entries. - typedef HashMap<String, unsigned> EntryMap; - EntryMap m_pendingEntries; + HashMap<String, unsigned> m_pendingEntries; // The total number of items to be processed to update the cache group and the number that have been done. - int m_progressTotal; - int m_progressDone; + int m_progressTotal { 0 }; + int m_progressDone { 0 }; // Frame used for fetching resources when updating. // FIXME: An update started by a particular frame should not stop if it is destroyed, but there are other frames associated with the same cache group. - Frame* m_frame; + Frame* m_frame { nullptr }; // An obsolete cache group is never stored, but the opposite is not true - storing may fail for multiple reasons, such as exceeding disk quota. - unsigned m_storageID; - bool m_isObsolete; + unsigned m_storageID { 0 }; + bool m_isObsolete { false }; // During update, this is used to handle asynchronously arriving results. enum CompletionType { @@ -178,32 +178,24 @@ private: Failure, Completed }; - CompletionType m_completionType; - - // Whether this cache group is a copy that's only used for transferring the cache to another file. - bool m_isCopy; + CompletionType m_completionType { None }; // This flag is set immediately after the ChromeClient::reachedMaxAppCacheSize() callback is invoked as a result of the storage layer failing to save a cache // due to reaching the maximum size of the application cache database file. This flag is used by ApplicationCacheGroup::checkIfLoadIsComplete() to decide // the course of action in case of this failure (i.e. call the ChromeClient callback or run the failure steps). - bool m_calledReachedMaxAppCacheSize; + bool m_calledReachedMaxAppCacheSize { false }; RefPtr<ResourceHandle> m_currentHandle; RefPtr<ApplicationCacheResource> m_currentResource; - -#if ENABLE(INSPECTOR) unsigned long m_currentResourceIdentifier; -#endif RefPtr<ApplicationCacheResource> m_manifestResource; RefPtr<ResourceHandle> m_manifestHandle; int64_t m_availableSpaceInQuota; - bool m_originQuotaExceededPreviously; + bool m_originQuotaExceededPreviously { false }; friend class ChromeClientCallbackTimer; }; } // namespace WebCore - -#endif // ApplicationCacheGroup_h diff --git a/Source/WebCore/loader/appcache/ApplicationCacheHost.cpp b/Source/WebCore/loader/appcache/ApplicationCacheHost.cpp index 9cc3f8d85..9114699c8 100644 --- a/Source/WebCore/loader/appcache/ApplicationCacheHost.cpp +++ b/Source/WebCore/loader/appcache/ApplicationCacheHost.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved. + * Copyright (C) 2008-2016 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,33 +29,33 @@ #include "ApplicationCache.h" #include "ApplicationCacheGroup.h" #include "ApplicationCacheResource.h" +#include "ContentSecurityPolicy.h" #include "DocumentLoader.h" #include "DOMApplicationCache.h" +#include "EventNames.h" +#include "FileSystem.h" #include "Frame.h" #include "FrameLoader.h" #include "FrameLoaderClient.h" #include "InspectorInstrumentation.h" +#include "MainFrame.h" +#include "Page.h" #include "ProgressEvent.h" #include "ResourceHandle.h" -#include "ResourceLoader.h" #include "ResourceRequest.h" #include "Settings.h" +#include "SubresourceLoader.h" namespace WebCore { -ApplicationCacheHost::ApplicationCacheHost(DocumentLoader* documentLoader) - : m_domApplicationCache(0) - , m_documentLoader(documentLoader) - , m_defersEvents(true) - , m_candidateApplicationCacheGroup(0) +ApplicationCacheHost::ApplicationCacheHost(DocumentLoader& documentLoader) + : m_documentLoader(documentLoader) { - ASSERT(m_documentLoader); } ApplicationCacheHost::~ApplicationCacheHost() { ASSERT(!m_applicationCache || !m_candidateApplicationCacheGroup || m_applicationCache->group() == m_candidateApplicationCacheGroup); - if (m_applicationCache) m_applicationCache->group()->disassociateDocumentLoader(m_documentLoader); else if (m_candidateApplicationCacheGroup) @@ -64,31 +64,41 @@ ApplicationCacheHost::~ApplicationCacheHost() void ApplicationCacheHost::selectCacheWithoutManifest() { - ApplicationCacheGroup::selectCacheWithoutManifestURL(m_documentLoader->frame()); + ASSERT(m_documentLoader.frame()); + ApplicationCacheGroup::selectCacheWithoutManifestURL(*m_documentLoader.frame()); } void ApplicationCacheHost::selectCacheWithManifest(const URL& manifestURL) { - ApplicationCacheGroup::selectCache(m_documentLoader->frame(), manifestURL); + ASSERT(m_documentLoader.frame()); + ApplicationCacheGroup::selectCache(*m_documentLoader.frame(), manifestURL); } void ApplicationCacheHost::maybeLoadMainResource(ResourceRequest& request, SubstituteData& substituteData) { // Check if this request should be loaded from the application cache - if (!substituteData.isValid() && isApplicationCacheEnabled()) { + if (!substituteData.isValid() && isApplicationCacheEnabled() && !isApplicationCacheBlockedForRequest(request)) { ASSERT(!m_mainResourceApplicationCache); - m_mainResourceApplicationCache = ApplicationCacheGroup::cacheForMainRequest(request, m_documentLoader); + m_mainResourceApplicationCache = ApplicationCacheGroup::cacheForMainRequest(request, &m_documentLoader); if (m_mainResourceApplicationCache) { // Get the resource from the application cache. By definition, cacheForMainRequest() returns a cache that contains the resource. ApplicationCacheResource* resource = m_mainResourceApplicationCache->resourceForRequest(request); - substituteData = SubstituteData(resource->data(), - resource->response().mimeType(), - resource->response().textEncodingName(), - URL(), + + // ApplicationCache resources have fragment identifiers stripped off of their URLs, + // but we'll need to restore that for the SubstituteData. + ResourceResponse responseToUse = resource->response(); + if (request.url().hasFragmentIdentifier()) { + URL url = responseToUse.url(); + url.setFragmentIdentifier(request.url().fragmentIdentifier()); + responseToUse.setURL(url); + } + + substituteData = SubstituteData(&resource->data(), URL(), - SubstituteData::ShouldRevealToSessionHistory); + responseToUse, + SubstituteData::SessionHistoryVisibility::Visible); } } } @@ -103,10 +113,10 @@ bool ApplicationCacheHost::maybeLoadFallbackForMainResponse(const ResourceReques { if (r.httpStatusCode() / 100 == 4 || r.httpStatusCode() / 100 == 5) { ASSERT(!m_mainResourceApplicationCache); - if (isApplicationCacheEnabled()) { - m_mainResourceApplicationCache = ApplicationCacheGroup::fallbackCacheForMainRequest(request, documentLoader()); + if (isApplicationCacheEnabled() && !isApplicationCacheBlockedForRequest(request)) { + m_mainResourceApplicationCache = ApplicationCacheGroup::fallbackCacheForMainRequest(request, &m_documentLoader); - if (scheduleLoadFallbackResourceFromApplicationCache(documentLoader()->mainResourceLoader(), m_mainResourceApplicationCache.get())) + if (scheduleLoadFallbackResourceFromApplicationCache(m_documentLoader.mainResourceLoader(), m_mainResourceApplicationCache.get())) return true; } } @@ -117,10 +127,10 @@ bool ApplicationCacheHost::maybeLoadFallbackForMainError(const ResourceRequest& { if (!error.isCancellation()) { ASSERT(!m_mainResourceApplicationCache); - if (isApplicationCacheEnabled()) { - m_mainResourceApplicationCache = ApplicationCacheGroup::fallbackCacheForMainRequest(request, m_documentLoader); + if (isApplicationCacheEnabled() && !isApplicationCacheBlockedForRequest(request)) { + m_mainResourceApplicationCache = ApplicationCacheGroup::fallbackCacheForMainRequest(request, &m_documentLoader); - if (scheduleLoadFallbackResourceFromApplicationCache(documentLoader()->mainResourceLoader(), m_mainResourceApplicationCache.get())) + if (scheduleLoadFallbackResourceFromApplicationCache(m_documentLoader.mainResourceLoader(), m_mainResourceApplicationCache.get())) return true; } } @@ -129,12 +139,11 @@ bool ApplicationCacheHost::maybeLoadFallbackForMainError(const ResourceRequest& void ApplicationCacheHost::mainResourceDataReceived(const char*, int, long long, bool) { - // This method is here to facilitate alternate implemetations of this interface by the host browser. } void ApplicationCacheHost::failedLoadingMainResource() { - ApplicationCacheGroup* group = m_candidateApplicationCacheGroup; + auto* group = m_candidateApplicationCacheGroup; if (!group && m_applicationCache) { if (mainResourceApplicationCache()) { // Even when the main resource is being loaded from an application cache, loading can fail if aborted. @@ -149,7 +158,7 @@ void ApplicationCacheHost::failedLoadingMainResource() void ApplicationCacheHost::finishedLoadingMainResource() { - ApplicationCacheGroup* group = candidateApplicationCacheGroup(); + auto* group = candidateApplicationCacheGroup(); if (!group && applicationCache() && !mainResourceApplicationCache()) group = applicationCache()->group(); @@ -157,9 +166,9 @@ void ApplicationCacheHost::finishedLoadingMainResource() group->finishedLoadingMainResource(m_documentLoader); } -bool ApplicationCacheHost::maybeLoadResource(ResourceLoader* loader, ResourceRequest& request, const URL& originalURL) +bool ApplicationCacheHost::maybeLoadResource(ResourceLoader& loader, const ResourceRequest& request, const URL& originalURL) { - if (!isApplicationCacheEnabled()) + if (!isApplicationCacheEnabled() && !isApplicationCacheBlockedForRequest(request)) return false; if (request.url() != originalURL) @@ -168,33 +177,33 @@ bool ApplicationCacheHost::maybeLoadResource(ResourceLoader* loader, ResourceReq ApplicationCacheResource* resource; if (!shouldLoadResourceFromApplicationCache(request, resource)) return false; - - m_documentLoader->m_pendingSubstituteResources.set(loader, resource); - m_documentLoader->deliverSubstituteResourcesAfterDelay(); - + + m_documentLoader.scheduleSubstituteResourceLoad(loader, *resource); return true; } bool ApplicationCacheHost::maybeLoadFallbackForRedirect(ResourceLoader* resourceLoader, ResourceRequest& request, const ResourceResponse& redirectResponse) { - if (!redirectResponse.isNull() && !protocolHostAndPortAreEqual(request.url(), redirectResponse.url())) + if (!redirectResponse.isNull() && !protocolHostAndPortAreEqual(request.url(), redirectResponse.url())) { if (scheduleLoadFallbackResourceFromApplicationCache(resourceLoader)) return true; + } return false; } bool ApplicationCacheHost::maybeLoadFallbackForResponse(ResourceLoader* resourceLoader, const ResourceResponse& response) { - if (response.httpStatusCode() / 100 == 4 || response.httpStatusCode() / 100 == 5) + if (response.httpStatusCode() / 100 == 4 || response.httpStatusCode() / 100 == 5) { if (scheduleLoadFallbackResourceFromApplicationCache(resourceLoader)) return true; + } return false; } bool ApplicationCacheHost::maybeLoadFallbackForError(ResourceLoader* resourceLoader, const ResourceError& error) { if (!error.isCancellation()) { - if (resourceLoader == m_documentLoader->mainResourceLoader()) + if (resourceLoader == m_documentLoader.mainResourceLoader()) return maybeLoadFallbackForMainError(resourceLoader->request(), error); if (scheduleLoadFallbackResourceFromApplicationCache(resourceLoader)) return true; @@ -202,22 +211,51 @@ bool ApplicationCacheHost::maybeLoadFallbackForError(ResourceLoader* resourceLoa return false; } -bool ApplicationCacheHost::maybeLoadSynchronously(ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data) +URL ApplicationCacheHost::createFileURL(const String& path) +{ + // FIXME: Can we just use fileURLWithFileSystemPath instead? + + // fileURLWithFileSystemPath function is not suitable because URL::setPath uses encodeWithURLEscapeSequences, which it notes + // does not correctly escape '#' and '?'. This function works for our purposes because + // app cache media files are always created with encodeForFileName(createCanonicalUUIDString()). + +#if USE(CF) && PLATFORM(WIN) + URL url(adoptCF(CFURLCreateWithFileSystemPath(0, path.createCFString().get(), kCFURLWindowsPathStyle, false)).get()); +#else + URL url; + url.setProtocol(ASCIILiteral("file")); + url.setPath(path); +#endif + return url; +} + +static inline RefPtr<SharedBuffer> bufferFromResource(ApplicationCacheResource& resource) +{ + // FIXME: Clients probably do not need a copy of the SharedBuffer. + // Remove the call to copy() once we ensure SharedBuffer will not be modified. + if (resource.path().isEmpty()) + return resource.data().copy(); + return SharedBuffer::createWithContentsOfFile(resource.path()); +} + +bool ApplicationCacheHost::maybeLoadSynchronously(ResourceRequest& request, ResourceError& error, ResourceResponse& response, RefPtr<SharedBuffer>& data) { ApplicationCacheResource* resource; - if (shouldLoadResourceFromApplicationCache(request, resource)) { - if (resource) { - response = resource->response(); - data.append(resource->data()->data(), resource->data()->size()); - } else { - error = documentLoader()->frameLoader()->client().cannotShowURLError(request); - } + if (!shouldLoadResourceFromApplicationCache(request, resource)) + return false; + + auto responseData = resource ? bufferFromResource(*resource) : nullptr; + if (!responseData) { + error = m_documentLoader.frameLoader()->client().cannotShowURLError(request); return true; } - return false; + + response = resource->response(); + data = WTFMove(responseData); + return true; } -void ApplicationCacheHost::maybeLoadFallbackSynchronously(const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data) +void ApplicationCacheHost::maybeLoadFallbackSynchronously(const ResourceRequest& request, ResourceError& error, ResourceResponse& response, RefPtr<SharedBuffer>& data) { // If normal loading results in a redirect to a resource with another origin (indicative of a captive portal), or a 4xx or 5xx status code or equivalent, // or if there were network errors (but not if the user canceled the download), then instead get, from the cache, the resource of the fallback entry @@ -228,8 +266,9 @@ void ApplicationCacheHost::maybeLoadFallbackSynchronously(const ResourceRequest& ApplicationCacheResource* resource; if (getApplicationCacheFallbackResource(request, resource)) { response = resource->response(); - data.clear(); - data.append(resource->data()->data(), resource->data()->size()); + // FIXME: Clients proably do not need a copy of the SharedBuffer. + // Remove the call to copy() once we ensure SharedBuffer will not be modified. + data = resource->data().copy(); } } } @@ -245,20 +284,21 @@ void ApplicationCacheHost::setDOMApplicationCache(DOMApplicationCache* domApplic m_domApplicationCache = domApplicationCache; } -void ApplicationCacheHost::notifyDOMApplicationCache(EventID id, int total, int done) +void ApplicationCacheHost::notifyDOMApplicationCache(const AtomicString& eventType, int total, int done) { - if (id != PROGRESS_EVENT) - InspectorInstrumentation::updateApplicationCacheStatus(m_documentLoader->frame()); + if (eventType != eventNames().progressEvent) + InspectorInstrumentation::updateApplicationCacheStatus(m_documentLoader.frame()); if (m_defersEvents) { // Event dispatching is deferred until document.onload has fired. - m_deferredEvents.append(DeferredEvent(id, total, done)); + m_deferredEvents.append({ eventType, total, done }); return; } - dispatchDOMEvent(id, total, done); + + dispatchDOMEvent(eventType, total, done); } -void ApplicationCacheHost::stopLoadingInFrame(Frame* frame) +void ApplicationCacheHost::stopLoadingInFrame(Frame& frame) { ASSERT(!m_applicationCache || !m_candidateApplicationCacheGroup || m_applicationCache->group() == m_candidateApplicationCacheGroup); @@ -270,56 +310,69 @@ void ApplicationCacheHost::stopLoadingInFrame(Frame* frame) void ApplicationCacheHost::stopDeferringEvents() { - RefPtr<DocumentLoader> protect(documentLoader()); - for (unsigned i = 0; i < m_deferredEvents.size(); ++i) { - const DeferredEvent& deferred = m_deferredEvents[i]; - dispatchDOMEvent(deferred.eventID, deferred.progressTotal, deferred.progressDone); + Ref<DocumentLoader> protect(m_documentLoader); + + // Note, do not cache the size in a local variable. + // This code needs to properly handle the case where more events are added to + // m_deferredEvents while iterating it. This is why we don't use a modern for loop. + for (size_t i = 0; i < m_deferredEvents.size(); ++i) { + auto& event = m_deferredEvents[i]; + dispatchDOMEvent(event.eventType, event.progressTotal, event.progressDone); } + m_deferredEvents.clear(); m_defersEvents = false; } -#if ENABLE(INSPECTOR) -void ApplicationCacheHost::fillResourceList(ResourceInfoList* resources) +Vector<ApplicationCacheHost::ResourceInfo> ApplicationCacheHost::resourceList() { - ApplicationCache* cache = applicationCache(); + Vector<ResourceInfo> result; + + auto* cache = applicationCache(); if (!cache || !cache->isComplete()) - return; - - for (const auto& urlAndResource : *cache) { - RefPtr<ApplicationCacheResource> resource = urlAndResource.value; - unsigned type = resource->type(); - bool isMaster = type & ApplicationCacheResource::Master; + return result; + + result.reserveInitialCapacity(cache->resources().size()); + + for (auto& urlAndResource : cache->resources()) { + ASSERT(urlAndResource.value); + auto& resource = *urlAndResource.value; + + unsigned type = resource.type(); + bool isMaster = type & ApplicationCacheResource::Master; bool isManifest = type & ApplicationCacheResource::Manifest; bool isExplicit = type & ApplicationCacheResource::Explicit; - bool isForeign = type & ApplicationCacheResource::Foreign; + bool isForeign = type & ApplicationCacheResource::Foreign; bool isFallback = type & ApplicationCacheResource::Fallback; - resources->append(ResourceInfo(resource->url(), isMaster, isManifest, isFallback, isForeign, isExplicit, resource->estimatedSizeInStorage())); + + result.uncheckedAppend({ resource.url(), isMaster, isManifest, isFallback, isForeign, isExplicit, resource.estimatedSizeInStorage() }); } + + return result; } - + ApplicationCacheHost::CacheInfo ApplicationCacheHost::applicationCacheInfo() { - ApplicationCache* cache = applicationCache(); + auto* cache = applicationCache(); if (!cache || !cache->isComplete()) - return CacheInfo(URL(), 0, 0, 0); - + return { { }, 0, 0, 0 }; + // FIXME: Add "Creation Time" and "Update Time" to Application Caches. - return CacheInfo(cache->manifestResource()->url(), 0, 0, cache->estimatedSizeInStorage()); + return { cache->manifestResource()->url(), 0, 0, cache->estimatedSizeInStorage() }; } -#endif -void ApplicationCacheHost::dispatchDOMEvent(EventID id, int total, int done) +static Ref<Event> createApplicationCacheEvent(const AtomicString& eventType, int total, int done) { - if (m_domApplicationCache) { - const AtomicString& eventType = DOMApplicationCache::toEventType(id); - RefPtr<Event> event; - if (id == PROGRESS_EVENT) - event = ProgressEvent::create(eventType, true, done, total); - else - event = Event::create(eventType, false, false); - m_domApplicationCache->dispatchEvent(event, ASSERT_NO_EXCEPTION); - } + if (eventType == eventNames().progressEvent) + return ProgressEvent::create(eventType, true, done, total); + return Event::create(eventType, false, false); +} + +void ApplicationCacheHost::dispatchDOMEvent(const AtomicString& eventType, int total, int done) +{ + if (!m_domApplicationCache) + return; + m_domApplicationCache->dispatchEvent(createApplicationCacheEvent(eventType, total, done)); } void ApplicationCacheHost::setCandidateApplicationCacheGroup(ApplicationCacheGroup* group) @@ -328,25 +381,30 @@ void ApplicationCacheHost::setCandidateApplicationCacheGroup(ApplicationCacheGro m_candidateApplicationCacheGroup = group; } -void ApplicationCacheHost::setApplicationCache(PassRefPtr<ApplicationCache> applicationCache) +void ApplicationCacheHost::setApplicationCache(RefPtr<ApplicationCache>&& applicationCache) { if (m_candidateApplicationCacheGroup) { ASSERT(!m_applicationCache); - m_candidateApplicationCacheGroup = 0; + m_candidateApplicationCacheGroup = nullptr; } - - m_applicationCache = applicationCache; + m_applicationCache = WTFMove(applicationCache); } -bool ApplicationCacheHost::shouldLoadResourceFromApplicationCache(const ResourceRequest& request, ApplicationCacheResource*& resource) +bool ApplicationCacheHost::shouldLoadResourceFromApplicationCache(const ResourceRequest& originalRequest, ApplicationCacheResource*& resource) { - ApplicationCache* cache = applicationCache(); + auto* cache = applicationCache(); if (!cache || !cache->isComplete()) return false; + ResourceRequest request(originalRequest); + if (auto* loaderFrame = m_documentLoader.frame()) { + if (auto* 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) || !equalIgnoringCase(request.url().protocol(), cache->manifestResource()->url().protocol())) + 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 @@ -385,45 +443,40 @@ bool ApplicationCacheHost::getApplicationCacheFallbackResource(const ResourceReq resource = cache->resourceForURL(fallbackURL); ASSERT(resource); - return true; } bool ApplicationCacheHost::scheduleLoadFallbackResourceFromApplicationCache(ResourceLoader* loader, ApplicationCache* cache) { - if (!isApplicationCacheEnabled()) + if (!isApplicationCacheEnabled() && !isApplicationCacheBlockedForRequest(loader->request())) return false; ApplicationCacheResource* resource; if (!getApplicationCacheFallbackResource(loader->request(), resource, cache)) return false; - m_documentLoader->m_pendingSubstituteResources.set(loader, resource); - m_documentLoader->deliverSubstituteResourcesAfterDelay(); - - loader->handle()->cancel(); - + loader->willSwitchToSubstituteResource(); + m_documentLoader.scheduleSubstituteResourceLoad(*loader, *resource); return true; } ApplicationCacheHost::Status ApplicationCacheHost::status() const { - ApplicationCache* cache = applicationCache(); + auto* cache = applicationCache(); if (!cache) return UNCACHED; switch (cache->group()->updateStatus()) { - case ApplicationCacheGroup::Checking: - return CHECKING; - case ApplicationCacheGroup::Downloading: - return DOWNLOADING; - case ApplicationCacheGroup::Idle: { - if (cache->group()->isObsolete()) - return OBSOLETE; - if (cache != cache->group()->newestCache()) - return UPDATEREADY; - return IDLE; - } + case ApplicationCacheGroup::Checking: + return CHECKING; + case ApplicationCacheGroup::Downloading: + return DOWNLOADING; + case ApplicationCacheGroup::Idle: + if (cache->group()->isObsolete()) + return OBSOLETE; + if (cache != cache->group()->newestCache()) + return UPDATEREADY; + return IDLE; } ASSERT_NOT_REACHED(); @@ -432,16 +485,19 @@ ApplicationCacheHost::Status ApplicationCacheHost::status() const bool ApplicationCacheHost::update() { - ApplicationCache* cache = applicationCache(); + auto* cache = applicationCache(); if (!cache) return false; - cache->group()->update(m_documentLoader->frame(), ApplicationCacheUpdateWithoutBrowsingContext); + auto* frame = m_documentLoader.frame(); + if (!frame) + return false; + cache->group()->update(*frame, ApplicationCacheUpdateWithoutBrowsingContext); return true; } bool ApplicationCacheHost::swapCache() { - ApplicationCache* cache = applicationCache(); + auto* cache = applicationCache(); if (!cache) return false; @@ -452,31 +508,40 @@ bool ApplicationCacheHost::swapCache() } // If there is no newer cache, raise an INVALID_STATE_ERR exception. - ApplicationCache* newestCache = cache->group()->newestCache(); + auto* newestCache = cache->group()->newestCache(); if (cache == newestCache) return false; ASSERT(cache->group() == newestCache->group()); setApplicationCache(newestCache); - InspectorInstrumentation::updateApplicationCacheStatus(m_documentLoader->frame()); + InspectorInstrumentation::updateApplicationCacheStatus(m_documentLoader.frame()); return true; } void ApplicationCacheHost::abort() { - ApplicationCacheGroup* cacheGroup = candidateApplicationCacheGroup(); - if (cacheGroup) - cacheGroup->abort(m_documentLoader->frame()); - else { - ApplicationCache* cache = applicationCache(); - if (cache) - cache->group()->abort(m_documentLoader->frame()); - } + auto* frame = m_documentLoader.frame(); + if (!frame) + return; + if (auto* cacheGroup = candidateApplicationCacheGroup()) + cacheGroup->abort(*frame); + else if (auto* cache = applicationCache()) + cache->group()->abort(*frame); } bool ApplicationCacheHost::isApplicationCacheEnabled() { - return m_documentLoader->frame() && m_documentLoader->frame()->settings().offlineWebApplicationCacheEnabled(); + return m_documentLoader.frame() && m_documentLoader.frame()->settings().offlineWebApplicationCacheEnabled() && !m_documentLoader.frame()->page()->usesEphemeralSession(); +} + +bool ApplicationCacheHost::isApplicationCacheBlockedForRequest(const ResourceRequest& request) +{ + auto* frame = m_documentLoader.frame(); + if (!frame) + return false; + if (frame->isMainFrame()) + return false; + return !SecurityOrigin::create(request.url())->canAccessApplicationCache(frame->document()->topOrigin()); } } // namespace WebCore diff --git a/Source/WebCore/loader/appcache/ApplicationCacheHost.h b/Source/WebCore/loader/appcache/ApplicationCacheHost.h index f6e0d0b94..2bfdc62f9 100644 --- a/Source/WebCore/loader/appcache/ApplicationCacheHost.h +++ b/Source/WebCore/loader/appcache/ApplicationCacheHost.h @@ -1,6 +1,7 @@ /* - * Copyright (c) 2009, Google Inc. All rights reserved. - * + * Copyright (c) 2009, Google Inc. All rights reserved. + * Copyright (c) 2017 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: @@ -28,172 +29,138 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ApplicationCacheHost_h -#define ApplicationCacheHost_h +#pragma once #include "URL.h" #include <wtf/Deque.h> -#include <wtf/OwnPtr.h> -#include <wtf/PassRefPtr.h> -#include <wtf/RefPtr.h> #include <wtf/Vector.h> namespace WebCore { - class DOMApplicationCache; - class DocumentLoader; - class Frame; - class ResourceLoader; - class ResourceError; - class ResourceRequest; - class ResourceResponse; - class SubstituteData; - class ApplicationCache; - class ApplicationCacheGroup; - class ApplicationCacheResource; - class ApplicationCacheStorage; - - class ApplicationCacheHost { - WTF_MAKE_NONCOPYABLE(ApplicationCacheHost); WTF_MAKE_FAST_ALLOCATED; - public: - // The Status numeric values are specified in the HTML5 spec. - enum Status { - UNCACHED = 0, - IDLE = 1, - CHECKING = 2, - DOWNLOADING = 3, - UPDATEREADY = 4, - OBSOLETE = 5 - }; - - enum EventID { - CHECKING_EVENT = 0, - ERROR_EVENT, - NOUPDATE_EVENT, - DOWNLOADING_EVENT, - PROGRESS_EVENT, - UPDATEREADY_EVENT, - CACHED_EVENT, - OBSOLETE_EVENT // Must remain the last value, this is used to size arrays. - }; - -#if ENABLE(INSPECTOR) - struct CacheInfo { - CacheInfo(const URL& manifest, double creationTime, double updateTime, long long size) - : m_manifest(manifest) - , m_creationTime(creationTime) - , m_updateTime(updateTime) - , m_size(size) { } - URL m_manifest; - double m_creationTime; - double m_updateTime; - long long m_size; - }; - - struct ResourceInfo { - ResourceInfo(const URL& resource, bool isMaster, bool isManifest, bool isFallback, bool isForeign, bool isExplicit, long long size) - : m_resource(resource) - , m_isMaster(isMaster) - , m_isManifest(isManifest) - , m_isFallback(isFallback) - , m_isForeign(isForeign) - , m_isExplicit(isExplicit) - , m_size(size) { } - URL m_resource; - bool m_isMaster; - bool m_isManifest; - bool m_isFallback; - bool m_isForeign; - bool m_isExplicit; - long long m_size; - }; - - typedef Vector<ResourceInfo> ResourceInfoList; -#endif - - ApplicationCacheHost(DocumentLoader*); - ~ApplicationCacheHost(); - - void selectCacheWithoutManifest(); - void selectCacheWithManifest(const URL& manifestURL); - - void maybeLoadMainResource(ResourceRequest&, SubstituteData&); - void maybeLoadMainResourceForRedirect(ResourceRequest&, SubstituteData&); - bool maybeLoadFallbackForMainResponse(const ResourceRequest&, const ResourceResponse&); - void mainResourceDataReceived(const char* data, int length, long long encodedDataLength, bool allAtOnce); - void finishedLoadingMainResource(); - void failedLoadingMainResource(); - - bool maybeLoadResource(ResourceLoader*, ResourceRequest&, const URL& originalURL); - bool maybeLoadFallbackForRedirect(ResourceLoader*, ResourceRequest&, const ResourceResponse&); - bool maybeLoadFallbackForResponse(ResourceLoader*, const ResourceResponse&); - bool maybeLoadFallbackForError(ResourceLoader*, const ResourceError&); - - bool maybeLoadSynchronously(ResourceRequest&, ResourceError&, ResourceResponse&, Vector<char>& data); - void maybeLoadFallbackSynchronously(const ResourceRequest&, ResourceError&, ResourceResponse&, Vector<char>& data); - - bool canCacheInPageCache(); - - Status status() const; - bool update(); - bool swapCache(); - void abort(); - - void setDOMApplicationCache(DOMApplicationCache*); - void notifyDOMApplicationCache(EventID, int progressTotal, int progressDone); - - void stopLoadingInFrame(Frame*); - - void stopDeferringEvents(); // Also raises the events that have been queued up. - -#if ENABLE(INSPECTOR) - void fillResourceList(ResourceInfoList*); - CacheInfo applicationCacheInfo(); -#endif - - bool shouldLoadResourceFromApplicationCache(const ResourceRequest&, ApplicationCacheResource*&); - bool getApplicationCacheFallbackResource(const ResourceRequest&, ApplicationCacheResource*&, ApplicationCache* = 0); - - private: - bool isApplicationCacheEnabled(); - DocumentLoader* documentLoader() const { return m_documentLoader; } - - struct DeferredEvent { - EventID eventID; - int progressTotal; - int progressDone; - DeferredEvent(EventID id, int total, int done) : eventID(id), progressTotal(total), progressDone(done) { } - }; - - DOMApplicationCache* m_domApplicationCache; - DocumentLoader* m_documentLoader; - bool m_defersEvents; // Events are deferred until after document onload. - Vector<DeferredEvent> m_deferredEvents; - - void dispatchDOMEvent(EventID, int progressTotal, int progressDone); - - friend class ApplicationCacheGroup; - friend class ApplicationCacheStorage; - - bool scheduleLoadFallbackResourceFromApplicationCache(ResourceLoader*, ApplicationCache* = 0); - void setCandidateApplicationCacheGroup(ApplicationCacheGroup* group); - ApplicationCacheGroup* candidateApplicationCacheGroup() const { return m_candidateApplicationCacheGroup; } - void setApplicationCache(PassRefPtr<ApplicationCache> applicationCache); - ApplicationCache* applicationCache() const { return m_applicationCache.get(); } - ApplicationCache* mainResourceApplicationCache() const { return m_mainResourceApplicationCache.get(); } - bool maybeLoadFallbackForMainError(const ResourceRequest&, const ResourceError&); - - - // The application cache that the document loader is associated with (if any). - RefPtr<ApplicationCache> m_applicationCache; - - // Before an application cache has finished loading, this will be the candidate application - // group that the document loader is associated with. - ApplicationCacheGroup* m_candidateApplicationCacheGroup; - - // This is the application cache the main resource was loaded from (if any). - RefPtr<ApplicationCache> m_mainResourceApplicationCache; + +class ApplicationCache; +class ApplicationCacheGroup; +class ApplicationCacheResource; +class ApplicationCacheStorage; +class DOMApplicationCache; +class DocumentLoader; +class Frame; +class ResourceError; +class ResourceLoader; +class ResourceRequest; +class ResourceResponse; +class SharedBuffer; +class SubstituteData; + +class ApplicationCacheHost { + WTF_MAKE_NONCOPYABLE(ApplicationCacheHost); WTF_MAKE_FAST_ALLOCATED; +public: + // The Status numeric values are specified in the HTML5 spec. + enum Status { + UNCACHED = 0, + IDLE = 1, + CHECKING = 2, + DOWNLOADING = 3, + UPDATEREADY = 4, + OBSOLETE = 5 }; -} // namespace WebCore + struct CacheInfo { + URL manifest; + double creationTime; + double updateTime; + long long size; + }; + + struct ResourceInfo { + URL resource; + bool isMaster; + bool isManifest; + bool isFallback; + bool isForeign; + bool isExplicit; + long long size; + }; + + explicit ApplicationCacheHost(DocumentLoader&); + ~ApplicationCacheHost(); + + static URL createFileURL(const String&); + + void selectCacheWithoutManifest(); + void selectCacheWithManifest(const URL& manifestURL); + + void maybeLoadMainResource(ResourceRequest&, SubstituteData&); + void maybeLoadMainResourceForRedirect(ResourceRequest&, SubstituteData&); + bool maybeLoadFallbackForMainResponse(const ResourceRequest&, const ResourceResponse&); + void mainResourceDataReceived(const char* data, int length, long long encodedDataLength, bool allAtOnce); + void finishedLoadingMainResource(); + void failedLoadingMainResource(); + + WEBCORE_EXPORT bool maybeLoadResource(ResourceLoader&, const ResourceRequest&, const URL& originalURL); + WEBCORE_EXPORT bool maybeLoadFallbackForRedirect(ResourceLoader*, ResourceRequest&, const ResourceResponse&); + WEBCORE_EXPORT bool maybeLoadFallbackForResponse(ResourceLoader*, const ResourceResponse&); + WEBCORE_EXPORT bool maybeLoadFallbackForError(ResourceLoader*, const ResourceError&); + + bool maybeLoadSynchronously(ResourceRequest&, ResourceError&, ResourceResponse&, RefPtr<SharedBuffer>&); + void maybeLoadFallbackSynchronously(const ResourceRequest&, ResourceError&, ResourceResponse&, RefPtr<SharedBuffer>&); + + bool canCacheInPageCache(); + + Status status() const; + bool update(); + bool swapCache(); + void abort(); + + void setDOMApplicationCache(DOMApplicationCache*); + void notifyDOMApplicationCache(const AtomicString& eventType, int progressTotal, int progressDone); + + void stopLoadingInFrame(Frame&); -#endif // ApplicationCacheHost_h + void stopDeferringEvents(); // Also raises the events that have been queued up. + + Vector<ResourceInfo> resourceList(); + CacheInfo applicationCacheInfo(); + + bool shouldLoadResourceFromApplicationCache(const ResourceRequest&, ApplicationCacheResource*&); + bool getApplicationCacheFallbackResource(const ResourceRequest&, ApplicationCacheResource*&, ApplicationCache* = nullptr); + +private: + friend class ApplicationCacheGroup; + + struct DeferredEvent { + AtomicString eventType; + int progressTotal; + int progressDone; + }; + + bool isApplicationCacheEnabled(); + bool isApplicationCacheBlockedForRequest(const ResourceRequest&); + + void dispatchDOMEvent(const AtomicString& eventType, int progressTotal, int progressDone); + + bool scheduleLoadFallbackResourceFromApplicationCache(ResourceLoader*, ApplicationCache* = nullptr); + void setCandidateApplicationCacheGroup(ApplicationCacheGroup*); + ApplicationCacheGroup* candidateApplicationCacheGroup() const { return m_candidateApplicationCacheGroup; } + void setApplicationCache(RefPtr<ApplicationCache>&&); + ApplicationCache* applicationCache() const { return m_applicationCache.get(); } + ApplicationCache* mainResourceApplicationCache() const { return m_mainResourceApplicationCache.get(); } + bool maybeLoadFallbackForMainError(const ResourceRequest&, const ResourceError&); + + DOMApplicationCache* m_domApplicationCache { nullptr }; + DocumentLoader& m_documentLoader; + + bool m_defersEvents { true }; // Events are deferred until after document onload. + Vector<DeferredEvent> m_deferredEvents; + + // The application cache that the document loader is associated with (if any). + RefPtr<ApplicationCache> m_applicationCache; + + // Before an application cache has finished loading, this will be the candidate application + // group that the document loader is associated with. + ApplicationCacheGroup* m_candidateApplicationCacheGroup { nullptr }; + + // This is the application cache the main resource was loaded from (if any). + RefPtr<ApplicationCache> m_mainResourceApplicationCache; +}; + +} // namespace WebCore diff --git a/Source/WebCore/loader/appcache/ApplicationCacheResource.cpp b/Source/WebCore/loader/appcache/ApplicationCacheResource.cpp index 2d9a8f1e6..f854a7212 100644 --- a/Source/WebCore/loader/appcache/ApplicationCacheResource.cpp +++ b/Source/WebCore/loader/appcache/ApplicationCacheResource.cpp @@ -29,8 +29,8 @@ namespace WebCore { -ApplicationCacheResource::ApplicationCacheResource(const URL& url, const ResourceResponse& response, unsigned type, PassRefPtr<SharedBuffer> data, const String& path) - : SubstituteResource(url, response, data) +ApplicationCacheResource::ApplicationCacheResource(const URL& url, const ResourceResponse& response, unsigned type, Ref<SharedBuffer>&& data, const String& path) + : SubstituteResource(url, response, WTFMove(data)) , m_type(type) , m_storageID(0) , m_estimatedSizeInStorage(0) @@ -38,6 +38,11 @@ ApplicationCacheResource::ApplicationCacheResource(const URL& url, const Resourc { } +void ApplicationCacheResource::deliver(ResourceLoader& loader) +{ + loader.deliverResponseAndData(response(), m_path.isEmpty() ? data().copy() : SharedBuffer::createWithContentsOfFile(m_path)); +} + void ApplicationCacheResource::addType(unsigned type) { // Caller should take care of storing the new type in database. @@ -49,8 +54,7 @@ int64_t ApplicationCacheResource::estimatedSizeInStorage() if (m_estimatedSizeInStorage) return m_estimatedSizeInStorage; - if (data()) - m_estimatedSizeInStorage = data()->size(); + m_estimatedSizeInStorage = data().size(); for (const auto& headerField : response().httpHeaderFields()) m_estimatedSizeInStorage += (headerField.key.length() + headerField.value.length() + 2) * sizeof(UChar); diff --git a/Source/WebCore/loader/appcache/ApplicationCacheResource.h b/Source/WebCore/loader/appcache/ApplicationCacheResource.h index d8d3f1aa0..a39613fa3 100644 --- a/Source/WebCore/loader/appcache/ApplicationCacheResource.h +++ b/Source/WebCore/loader/appcache/ApplicationCacheResource.h @@ -23,8 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ApplicationCacheResource_h -#define ApplicationCacheResource_h +#pragma once #include "SubstituteResource.h" @@ -40,10 +39,12 @@ public: Fallback = 1 << 4 }; - static PassRefPtr<ApplicationCacheResource> create(const URL& url, const ResourceResponse& response, unsigned type, PassRefPtr<SharedBuffer> buffer = SharedBuffer::create(), const String& path = String()) + static Ref<ApplicationCacheResource> create(const URL& url, const ResourceResponse& response, unsigned type, RefPtr<SharedBuffer> buffer = SharedBuffer::create(), const String& path = String()) { ASSERT(!url.hasFragmentIdentifier()); - return adoptRef(new ApplicationCacheResource(url, response, type, buffer, path)); + if (!buffer) + buffer = SharedBuffer::create(); + return adoptRef(*new ApplicationCacheResource(url, response, type, buffer.releaseNonNull(), path)); } unsigned type() const { return m_type; } @@ -62,7 +63,9 @@ public: #endif private: - ApplicationCacheResource(const URL&, const ResourceResponse&, unsigned type, PassRefPtr<SharedBuffer>, const String& path); + ApplicationCacheResource(const URL&, const ResourceResponse&, unsigned type, Ref<SharedBuffer>&&, const String& path); + + void deliver(ResourceLoader&) override; unsigned m_type; unsigned m_storageID; @@ -71,5 +74,3 @@ private: }; } // namespace WebCore - -#endif // ApplicationCacheResource_h diff --git a/Source/WebCore/loader/appcache/ApplicationCacheStorage.cpp b/Source/WebCore/loader/appcache/ApplicationCacheStorage.cpp index e5751ac59..b6b9d7a7c 100644 --- a/Source/WebCore/loader/appcache/ApplicationCacheStorage.cpp +++ b/Source/WebCore/loader/appcache/ApplicationCacheStorage.cpp @@ -31,13 +31,14 @@ #include "ApplicationCacheHost.h" #include "ApplicationCacheResource.h" #include "FileSystem.h" -#include "NotImplemented.h" #include "SQLiteDatabaseTracker.h" #include "SQLiteStatement.h" #include "SQLiteTransaction.h" #include "SecurityOrigin.h" +#include "SecurityOriginData.h" #include "URL.h" #include "UUID.h" +#include <wtf/NeverDestroyed.h> #include <wtf/StdLibExtras.h> #include <wtf/StringExtras.h> #include <wtf/text/CString.h> @@ -45,16 +46,13 @@ namespace WebCore { -static const char flatFileSubdirectory[] = "ApplicationCache"; - template <class T> class StorageIDJournal { public: ~StorageIDJournal() { - size_t size = m_records.size(); - for (size_t i = 0; i < size; ++i) - m_records[i].restore(); + for (auto& record : m_records) + record.restore(); } void add(T* resource, unsigned storageID) @@ -70,7 +68,7 @@ public: private: class Record { public: - Record() : m_resource(0), m_storageID(0) { } + Record() : m_resource(nullptr), m_storageID(0) { } Record(T* resource, unsigned storageID) : m_resource(resource), m_storageID(storageID) { } void restore() @@ -105,59 +103,55 @@ ApplicationCacheGroup* ApplicationCacheStorage::loadCacheGroup(const URL& manife openDatabase(false); if (!m_database.isOpen()) - return 0; + return nullptr; SQLiteStatement statement(m_database, "SELECT id, manifestURL, newestCache FROM CacheGroups WHERE newestCache IS NOT NULL AND manifestURL=?"); - if (statement.prepare() != SQLResultOk) - return 0; + if (statement.prepare() != SQLITE_OK) + return nullptr; statement.bindText(1, manifestURL); int result = statement.step(); - if (result == SQLResultDone) - return 0; + if (result == SQLITE_DONE) + return nullptr; - if (result != SQLResultRow) { + if (result != SQLITE_ROW) { LOG_ERROR("Could not load cache group, error \"%s\"", m_database.lastErrorMsg()); - return 0; + return nullptr; } unsigned newestCacheStorageID = static_cast<unsigned>(statement.getColumnInt64(2)); - RefPtr<ApplicationCache> cache = loadCache(newestCacheStorageID); + auto cache = loadCache(newestCacheStorageID); if (!cache) - return 0; + return nullptr; - ApplicationCacheGroup* group = new ApplicationCacheGroup(manifestURL); - - group->setStorageID(static_cast<unsigned>(statement.getColumnInt64(0))); - group->setNewestCache(cache.release()); - - return group; + auto& group = *new ApplicationCacheGroup(*this, manifestURL); + group.setStorageID(static_cast<unsigned>(statement.getColumnInt64(0))); + group.setNewestCache(cache.releaseNonNull()); + return &group; } ApplicationCacheGroup* ApplicationCacheStorage::findOrCreateCacheGroup(const URL& manifestURL) { ASSERT(!manifestURL.hasFragmentIdentifier()); - CacheGroupMap::AddResult result = m_cachesInMemory.add(manifestURL, nullptr); - + auto result = m_cachesInMemory.add(manifestURL, nullptr); if (!result.isNewEntry) { ASSERT(result.iterator->value); return result.iterator->value; } // Look up the group in the database - ApplicationCacheGroup* group = loadCacheGroup(manifestURL); + auto* group = loadCacheGroup(manifestURL); // If the group was not found we need to create it if (!group) { - group = new ApplicationCacheGroup(manifestURL); + group = new ApplicationCacheGroup(*this, manifestURL); m_cacheHostSet.add(urlHostHash(manifestURL)); } - + result.iterator->value = group; - return group; } @@ -185,10 +179,10 @@ void ApplicationCacheStorage::loadManifestHostHashes() // Fetch the host hashes. SQLiteStatement statement(m_database, "SELECT manifestHostHash FROM CacheGroups"); - if (statement.prepare() != SQLResultOk) + if (statement.prepare() != SQLITE_OK) return; - while (statement.step() == SQLResultRow) + while (statement.step() == SQLITE_ROW) m_cacheHostSet.add(static_cast<unsigned>(statement.getColumnInt64(0))); } @@ -200,7 +194,7 @@ ApplicationCacheGroup* ApplicationCacheStorage::cacheGroupForURL(const URL& url) // Hash the host name and see if there's a manifest with the same host. if (!m_cacheHostSet.contains(urlHostHash(url))) - return 0; + return nullptr; // Check if a cache already exists in memory. for (const auto& group : m_cachesInMemory.values()) { @@ -220,17 +214,17 @@ ApplicationCacheGroup* ApplicationCacheStorage::cacheGroupForURL(const URL& url) } if (!m_database.isOpen()) - return 0; + return nullptr; SQLiteTransactionInProgressAutoCounter transactionCounter; // Check the database. Look for all cache groups with a newest cache. SQLiteStatement statement(m_database, "SELECT id, manifestURL, newestCache FROM CacheGroups WHERE newestCache IS NOT NULL"); - if (statement.prepare() != SQLResultOk) - return 0; + if (statement.prepare() != SQLITE_OK) + return nullptr; int result; - while ((result = statement.step()) == SQLResultRow) { + while ((result = statement.step()) == SQLITE_ROW) { URL manifestURL = URL(ParsedURLString, statement.getColumnText(1)); if (m_cachesInMemory.contains(manifestURL)) @@ -242,30 +236,28 @@ ApplicationCacheGroup* ApplicationCacheStorage::cacheGroupForURL(const URL& url) // We found a cache group that matches. Now check if the newest cache has a resource with // a matching URL. unsigned newestCacheID = static_cast<unsigned>(statement.getColumnInt64(2)); - RefPtr<ApplicationCache> cache = loadCache(newestCacheID); + auto cache = loadCache(newestCacheID); if (!cache) continue; - ApplicationCacheResource* resource = cache->resourceForURL(url); + auto* resource = cache->resourceForURL(url); if (!resource) continue; if (resource->type() & ApplicationCacheResource::Foreign) continue; - ApplicationCacheGroup* group = new ApplicationCacheGroup(manifestURL); - - group->setStorageID(static_cast<unsigned>(statement.getColumnInt64(0))); - group->setNewestCache(cache.release()); - - m_cachesInMemory.set(group->manifestURL(), group); - - return group; + auto& group = *new ApplicationCacheGroup(*this, manifestURL); + group.setStorageID(static_cast<unsigned>(statement.getColumnInt64(0))); + group.setNewestCache(cache.releaseNonNull()); + m_cachesInMemory.set(group.manifestURL(), &group); + + return &group; } - if (result != SQLResultDone) + if (result != SQLITE_DONE) LOG_ERROR("Could not load cache group, error \"%s\"", m_database.lastErrorMsg()); - return 0; + return nullptr; } ApplicationCacheGroup* ApplicationCacheStorage::fallbackCacheGroupForURL(const URL& url) @@ -275,10 +267,7 @@ ApplicationCacheGroup* ApplicationCacheStorage::fallbackCacheGroupForURL(const U ASSERT(!url.hasFragmentIdentifier()); // Check if an appropriate cache already exists in memory. - CacheGroupMap::const_iterator end = m_cachesInMemory.end(); - for (CacheGroupMap::const_iterator it = m_cachesInMemory.begin(); it != end; ++it) { - ApplicationCacheGroup* group = it->value; - + for (auto* group : m_cachesInMemory.values()) { ASSERT(!group->isObsolete()); if (ApplicationCache* cache = group->newestCache()) { @@ -294,15 +283,15 @@ ApplicationCacheGroup* ApplicationCacheStorage::fallbackCacheGroupForURL(const U } if (!m_database.isOpen()) - return 0; + return nullptr; // Check the database. Look for all cache groups with a newest cache. SQLiteStatement statement(m_database, "SELECT id, manifestURL, newestCache FROM CacheGroups WHERE newestCache IS NOT NULL"); - if (statement.prepare() != SQLResultOk) - return 0; + if (statement.prepare() != SQLITE_OK) + return nullptr; int result; - while ((result = statement.step()) == SQLResultRow) { + while ((result = statement.step()) == SQLITE_ROW) { URL manifestURL = URL(ParsedURLString, statement.getColumnText(1)); if (m_cachesInMemory.contains(manifestURL)) @@ -315,7 +304,7 @@ ApplicationCacheGroup* ApplicationCacheStorage::fallbackCacheGroupForURL(const U // We found a cache group that matches. Now check if the newest cache has a resource with // a matching fallback namespace. unsigned newestCacheID = static_cast<unsigned>(statement.getColumnInt64(2)); - RefPtr<ApplicationCache> cache = loadCache(newestCacheID); + auto cache = loadCache(newestCacheID); URL fallbackURL; if (cache->isURLInOnlineWhitelist(url)) @@ -325,57 +314,48 @@ ApplicationCacheGroup* ApplicationCacheStorage::fallbackCacheGroupForURL(const U if (cache->resourceForURL(fallbackURL)->type() & ApplicationCacheResource::Foreign) continue; - ApplicationCacheGroup* group = new ApplicationCacheGroup(manifestURL); - - group->setStorageID(static_cast<unsigned>(statement.getColumnInt64(0))); - group->setNewestCache(cache.release()); - - m_cachesInMemory.set(group->manifestURL(), group); - - return group; + auto& group = *new ApplicationCacheGroup(*this, manifestURL); + group.setStorageID(static_cast<unsigned>(statement.getColumnInt64(0))); + group.setNewestCache(cache.releaseNonNull()); + + m_cachesInMemory.set(group.manifestURL(), &group); + + return &group; } - if (result != SQLResultDone) + if (result != SQLITE_DONE) LOG_ERROR("Could not load cache group, error \"%s\"", m_database.lastErrorMsg()); - return 0; + return nullptr; } -void ApplicationCacheStorage::cacheGroupDestroyed(ApplicationCacheGroup* group) +void ApplicationCacheStorage::cacheGroupDestroyed(ApplicationCacheGroup& group) { - if (group->isObsolete()) { - ASSERT(!group->storageID()); - ASSERT(m_cachesInMemory.get(group->manifestURL()) != group); + if (group.isObsolete()) { + ASSERT(!group.storageID()); + ASSERT(m_cachesInMemory.get(group.manifestURL()) != &group); return; } - ASSERT(m_cachesInMemory.get(group->manifestURL()) == group); + ASSERT(m_cachesInMemory.get(group.manifestURL()) == &group); - m_cachesInMemory.remove(group->manifestURL()); + m_cachesInMemory.remove(group.manifestURL()); // If the cache group is half-created, we don't want it in the saved set (as it is not stored in database). - if (!group->storageID()) - m_cacheHostSet.remove(urlHostHash(group->manifestURL())); + if (!group.storageID()) + m_cacheHostSet.remove(urlHostHash(group.manifestURL())); } -void ApplicationCacheStorage::cacheGroupMadeObsolete(ApplicationCacheGroup* group) +void ApplicationCacheStorage::cacheGroupMadeObsolete(ApplicationCacheGroup& group) { - ASSERT(m_cachesInMemory.get(group->manifestURL()) == group); - ASSERT(m_cacheHostSet.contains(urlHostHash(group->manifestURL()))); + ASSERT(m_cachesInMemory.get(group.manifestURL()) == &group); + ASSERT(m_cacheHostSet.contains(urlHostHash(group.manifestURL()))); - if (ApplicationCache* newestCache = group->newestCache()) + if (auto* newestCache = group.newestCache()) remove(newestCache); - m_cachesInMemory.remove(group->manifestURL()); - m_cacheHostSet.remove(urlHostHash(group->manifestURL())); -} - -void ApplicationCacheStorage::setCacheDirectory(const String& cacheDirectory) -{ - ASSERT(m_cacheDirectory.isNull()); - ASSERT(!cacheDirectory.isNull()); - - m_cacheDirectory = cacheDirectory; + m_cachesInMemory.remove(group.manifestURL()); + m_cacheHostSet.remove(urlHostHash(group.manifestURL())); } const String& ApplicationCacheStorage::cacheDirectory() const @@ -441,7 +421,7 @@ void ApplicationCacheStorage::setDefaultOriginQuota(int64_t quota) m_defaultOriginQuota = quota; } -bool ApplicationCacheStorage::calculateQuotaForOrigin(const SecurityOrigin* origin, int64_t& quota) +bool ApplicationCacheStorage::calculateQuotaForOrigin(const SecurityOrigin& origin, int64_t& quota) { SQLiteTransactionInProgressAutoCounter transactionCounter; @@ -449,14 +429,14 @@ bool ApplicationCacheStorage::calculateQuotaForOrigin(const SecurityOrigin* orig // Using the count to determine if a record existed or not is a safe way to determine // if a quota of 0 is real, from the record, or from null. SQLiteStatement statement(m_database, "SELECT COUNT(quota), quota FROM Origins WHERE origin=?"); - if (statement.prepare() != SQLResultOk) + if (statement.prepare() != SQLITE_OK) return false; - statement.bindText(1, origin->databaseIdentifier()); + statement.bindText(1, SecurityOriginData::fromSecurityOrigin(origin).databaseIdentifier()); int result = statement.step(); // Return the quota, or if it was null the default. - if (result == SQLResultRow) { + if (result == SQLITE_ROW) { bool wasNoRecord = statement.getColumnInt64(0) == 0; quota = wasNoRecord ? m_defaultOriginQuota : statement.getColumnInt64(1); return true; @@ -477,13 +457,13 @@ bool ApplicationCacheStorage::calculateUsageForOrigin(const SecurityOrigin* orig " INNER JOIN Origins ON CacheGroups.origin = Origins.origin" " INNER JOIN Caches ON CacheGroups.id = Caches.cacheGroup" " WHERE Origins.origin=?"); - if (statement.prepare() != SQLResultOk) + if (statement.prepare() != SQLITE_OK) return false; - statement.bindText(1, origin->databaseIdentifier()); + statement.bindText(1, SecurityOriginData::fromSecurityOrigin(*origin).databaseIdentifier()); int result = statement.step(); - if (result == SQLResultRow) { + if (result == SQLITE_ROW) { usage = statement.getColumnInt64(0); return true; } @@ -492,7 +472,7 @@ bool ApplicationCacheStorage::calculateUsageForOrigin(const SecurityOrigin* orig return false; } -bool ApplicationCacheStorage::calculateRemainingSizeForOriginExcludingCache(const SecurityOrigin* origin, ApplicationCache* cache, int64_t& remainingSize) +bool ApplicationCacheStorage::calculateRemainingSizeForOriginExcludingCache(const SecurityOrigin& origin, ApplicationCache* cache, int64_t& remainingSize) { SQLiteTransactionInProgressAutoCounter transactionCounter; @@ -520,17 +500,17 @@ bool ApplicationCacheStorage::calculateRemainingSizeForOriginExcludingCache(cons } SQLiteStatement statement(m_database, query); - if (statement.prepare() != SQLResultOk) + if (statement.prepare() != SQLITE_OK) return false; - statement.bindText(1, origin->databaseIdentifier()); + statement.bindText(1, SecurityOriginData::fromSecurityOrigin(origin).databaseIdentifier()); if (excludingCacheIdentifier != 0) statement.bindInt64(2, excludingCacheIdentifier); int result = statement.step(); // If the count was 0 that then we have to query the origin table directly // for its quota. Otherwise we can use the calculated value. - if (result == SQLResultRow) { + if (result == SQLITE_ROW) { int64_t numberOfCaches = statement.getColumnInt64(0); if (numberOfCaches == 0) calculateQuotaForOrigin(origin, remainingSize); @@ -555,11 +535,11 @@ bool ApplicationCacheStorage::storeUpdatedQuotaForOrigin(const SecurityOrigin* o return false; SQLiteStatement updateStatement(m_database, "UPDATE Origins SET quota=? WHERE origin=?"); - if (updateStatement.prepare() != SQLResultOk) + if (updateStatement.prepare() != SQLITE_OK) return false; updateStatement.bindInt64(1, quota); - updateStatement.bindText(2, origin->databaseIdentifier()); + updateStatement.bindText(2, SecurityOriginData::fromSecurityOrigin(*origin).databaseIdentifier()); return executeStatement(updateStatement); } @@ -590,7 +570,9 @@ void ApplicationCacheStorage::verifySchemaVersion() if (version == schemaVersion) return; - deleteTables(); + // Version will be 0 if we just created an empty file. Trying to delete tables would cause errors, because they don't exist yet. + if (version) + deleteTables(); // Update user version. SQLiteTransaction setDatabaseVersion(m_database); @@ -601,7 +583,7 @@ void ApplicationCacheStorage::verifySchemaVersion() ASSERT_UNUSED(unusedNumBytes, static_cast<int>(sizeof(userVersionSQL)) >= unusedNumBytes); SQLiteStatement statement(m_database, userVersionSQL); - if (statement.prepare() != SQLResultOk) + if (statement.prepare() != SQLITE_OK) return; executeStatement(statement); @@ -701,19 +683,19 @@ bool ApplicationCacheStorage::store(ApplicationCacheGroup* group, GroupStorageID deleteCacheGroupRecord(group->manifestURL()); SQLiteStatement statement(m_database, "INSERT INTO CacheGroups (manifestHostHash, manifestURL, origin) VALUES (?, ?, ?)"); - if (statement.prepare() != SQLResultOk) + if (statement.prepare() != SQLITE_OK) return false; statement.bindInt64(1, urlHostHash(group->manifestURL())); statement.bindText(2, group->manifestURL()); - statement.bindText(3, group->origin()->databaseIdentifier()); + statement.bindText(3, SecurityOriginData::fromSecurityOrigin(group->origin()).databaseIdentifier()); if (!executeStatement(statement)) return false; unsigned groupStorageID = static_cast<unsigned>(m_database.lastInsertRowID()); - if (!ensureOriginRecord(group->origin())) + if (!ensureOriginRecord(&group->origin())) return false; group->setStorageID(groupStorageID); @@ -729,7 +711,7 @@ bool ApplicationCacheStorage::store(ApplicationCache* cache, ResourceStorageIDJo ASSERT(storageIDJournal); SQLiteStatement statement(m_database, "INSERT INTO Caches (cacheGroup, size) VALUES (?, ?)"); - if (statement.prepare() != SQLResultOk) + if (statement.prepare() != SQLITE_OK) return false; statement.bindInt64(1, cache->group()->storageID()); @@ -741,28 +723,24 @@ bool ApplicationCacheStorage::store(ApplicationCache* cache, ResourceStorageIDJo unsigned cacheStorageID = static_cast<unsigned>(m_database.lastInsertRowID()); // Store all resources - { - ApplicationCache::ResourceMap::const_iterator end = cache->end(); - for (ApplicationCache::ResourceMap::const_iterator it = cache->begin(); it != end; ++it) { - unsigned oldStorageID = it->value->storageID(); - if (!store(it->value.get(), cacheStorageID)) - return false; + for (auto& resource : cache->resources().values()) { + unsigned oldStorageID = resource->storageID(); + if (!store(resource.get(), cacheStorageID)) + return false; - // Storing the resource succeeded. Log its old storageID in case - // it needs to be restored later. - storageIDJournal->add(it->value.get(), oldStorageID); - } + // Storing the resource succeeded. Log its old storageID in case + // it needs to be restored later. + storageIDJournal->add(resource.get(), oldStorageID); } // Store the online whitelist const Vector<URL>& onlineWhitelist = cache->onlineWhitelist(); { - size_t whitelistSize = onlineWhitelist.size(); - for (size_t i = 0; i < whitelistSize; ++i) { + for (auto& whitelistURL : onlineWhitelist) { SQLiteStatement statement(m_database, "INSERT INTO CacheWhitelistURLs (url, cache) VALUES (?, ?)"); statement.prepare(); - statement.bindText(1, onlineWhitelist[i]); + statement.bindText(1, whitelistURL); statement.bindInt64(2, cacheStorageID); if (!executeStatement(statement)) @@ -785,13 +763,12 @@ bool ApplicationCacheStorage::store(ApplicationCache* cache, ResourceStorageIDJo // Store fallback URLs. const FallbackURLVector& fallbackURLs = cache->fallbackURLs(); { - size_t fallbackCount = fallbackURLs.size(); - for (size_t i = 0; i < fallbackCount; ++i) { + for (auto& fallbackURL : fallbackURLs) { SQLiteStatement statement(m_database, "INSERT INTO FallbackURLs (namespace, fallbackURL, cache) VALUES (?, ?, ?)"); statement.prepare(); - statement.bindText(1, fallbackURLs[i].first); - statement.bindText(2, fallbackURLs[i].second); + statement.bindText(1, fallbackURL.first); + statement.bindText(2, fallbackURL.second); statement.bindInt64(3, cacheStorageID); if (!executeStatement(statement)) @@ -817,7 +794,7 @@ bool ApplicationCacheStorage::store(ApplicationCacheResource* resource, unsigned // First, insert the data SQLiteStatement dataStatement(m_database, "INSERT INTO CacheResourceData (data, path) VALUES (?, ?)"); - if (dataStatement.prepare() != SQLResultOk) + if (dataStatement.prepare() != SQLITE_OK) return false; @@ -827,12 +804,12 @@ bool ApplicationCacheStorage::store(ApplicationCacheResource* resource, unsigned else if (shouldStoreResourceAsFlatFile(resource)) { // First, check to see if creating the flat file would violate the maximum total quota. We don't need // to check the per-origin quota here, as it was already checked in storeNewestCache(). - if (m_database.totalSize() + flatFileAreaSize() + resource->data()->size() > m_maximumSize) { + if (m_database.totalSize() + flatFileAreaSize() + resource->data().size() > m_maximumSize) { m_isMaximumSizeReached = true; return false; } - String flatFileDirectory = pathByAppendingComponent(m_cacheDirectory, flatFileSubdirectory); + String flatFileDirectory = pathByAppendingComponent(m_cacheDirectory, m_flatFileSubdirectoryName); makeAllDirectories(flatFileDirectory); String extension; @@ -850,8 +827,8 @@ bool ApplicationCacheStorage::store(ApplicationCacheResource* resource, unsigned resource->setPath(fullPath); dataStatement.bindText(2, path); } else { - if (resource->data()->size()) - dataStatement.bindBlob(1, resource->data()->data(), resource->data()->size()); + if (resource->data().size()) + dataStatement.bindBlob(1, resource->data().data(), resource->data().size()); } if (!dataStatement.executeCommand()) { @@ -869,18 +846,17 @@ bool ApplicationCacheStorage::store(ApplicationCacheResource* resource, unsigned // Serialize the headers StringBuilder stringBuilder; - HTTPHeaderMap::const_iterator end = resource->response().httpHeaderFields().end(); - for (HTTPHeaderMap::const_iterator it = resource->response().httpHeaderFields().begin(); it!= end; ++it) { - stringBuilder.append(it->key); + for (const auto& header : resource->response().httpHeaderFields()) { + stringBuilder.append(header.key); stringBuilder.append(':'); - stringBuilder.append(it->value); + stringBuilder.append(header.value); stringBuilder.append('\n'); } String headers = stringBuilder.toString(); SQLiteStatement resourceStatement(m_database, "INSERT INTO CacheResources (url, statusCode, responseURL, headers, data, mimeType, textEncodingName) VALUES (?, ?, ?, ?, ?, ?, ?)"); - if (resourceStatement.prepare() != SQLResultOk) + if (resourceStatement.prepare() != SQLITE_OK) return false; // The same ApplicationCacheResource are used in ApplicationCacheResource::size() @@ -901,7 +877,7 @@ bool ApplicationCacheStorage::store(ApplicationCacheResource* resource, unsigned // Finally, insert the cache entry SQLiteStatement entryStatement(m_database, "INSERT INTO CacheEntries (cache, type, resource) VALUES (?, ?, ?)"); - if (entryStatement.prepare() != SQLResultOk) + if (entryStatement.prepare() != SQLITE_OK) return false; entryStatement.bindInt64(1, cacheStorageID); @@ -915,7 +891,7 @@ bool ApplicationCacheStorage::store(ApplicationCacheResource* resource, unsigned // release the resource's data and free up a potentially large amount // of memory: if (!fullPath.isEmpty()) - resource->data()->clear(); + resource->data().clear(); resource->setStorageID(resourceId); return true; @@ -930,7 +906,7 @@ bool ApplicationCacheStorage::storeUpdatedType(ApplicationCacheResource* resourc // First, insert the data SQLiteStatement entryStatement(m_database, "UPDATE CacheEntries SET type=? WHERE resource=?"); - if (entryStatement.prepare() != SQLResultOk) + if (entryStatement.prepare() != SQLITE_OK) return false; entryStatement.bindInt64(1, resource->type()); @@ -963,7 +939,7 @@ bool ApplicationCacheStorage::store(ApplicationCacheResource* resource, Applicat // A resource was added to the cache. Update the total data size for the cache. SQLiteStatement sizeUpdateStatement(m_database, "UPDATE Caches SET size=size+? WHERE id=?"); - if (sizeUpdateStatement.prepare() != SQLResultOk) + if (sizeUpdateStatement.prepare() != SQLITE_OK) return false; sizeUpdateStatement.bindInt64(1, resource->estimatedSizeInStorage()); @@ -980,10 +956,10 @@ bool ApplicationCacheStorage::ensureOriginRecord(const SecurityOrigin* origin) { ASSERT(SQLiteDatabaseTracker::hasTransactionInProgress()); SQLiteStatement insertOriginStatement(m_database, "INSERT INTO Origins (origin, quota) VALUES (?, ?)"); - if (insertOriginStatement.prepare() != SQLResultOk) + if (insertOriginStatement.prepare() != SQLITE_OK) return false; - insertOriginStatement.bindText(1, origin->databaseIdentifier()); + insertOriginStatement.bindText(1, SecurityOriginData::fromSecurityOrigin(*origin).databaseIdentifier()); insertOriginStatement.bindInt64(2, m_defaultOriginQuota); if (!executeStatement(insertOriginStatement)) return false; @@ -995,7 +971,7 @@ bool ApplicationCacheStorage::checkOriginQuota(ApplicationCacheGroup* group, App { // Check if the oldCache with the newCache would reach the per-origin quota. int64_t remainingSpaceInOrigin; - const SecurityOrigin* origin = group->origin(); + auto& origin = group->origin(); if (calculateRemainingSizeForOriginExcludingCache(origin, oldCache, remainingSpaceInOrigin)) { if (remainingSpaceInOrigin < newCache->estimatedSizeInStorage()) { int64_t quota; @@ -1013,7 +989,7 @@ bool ApplicationCacheStorage::checkOriginQuota(ApplicationCacheGroup* group, App return true; } -bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup* group, ApplicationCache* oldCache, FailureReason& failureReason) +bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup& group, ApplicationCache* oldCache, FailureReason& failureReason) { openDatabase(true); @@ -1029,24 +1005,24 @@ bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup* group, App // Check if this would reach the per-origin quota. int64_t totalSpaceNeededIgnored; - if (!checkOriginQuota(group, oldCache, group->newestCache(), totalSpaceNeededIgnored)) { + if (!checkOriginQuota(&group, oldCache, group.newestCache(), totalSpaceNeededIgnored)) { failureReason = OriginQuotaReached; return false; } GroupStorageIDJournal groupStorageIDJournal; - if (!group->storageID()) { + if (!group.storageID()) { // Store the group - if (!store(group, &groupStorageIDJournal)) { + if (!store(&group, &groupStorageIDJournal)) { checkForMaxSizeReached(); failureReason = isMaximumSizeReached() ? TotalQuotaReached : DiskOrOperationFailure; return false; } } - ASSERT(group->newestCache()); - ASSERT(!group->isObsolete()); - ASSERT(!group->newestCache()->storageID()); + ASSERT(group.newestCache()); + ASSERT(!group.isObsolete()); + ASSERT(!group.newestCache()->storageID()); // Log the storageID changes to the in-memory resource objects. The journal // object will roll them back automatically in case a database operation @@ -1054,7 +1030,7 @@ bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup* group, App ResourceStorageIDJournal resourceStorageIDJournal; // Store the newest cache - if (!store(group->newestCache(), &resourceStorageIDJournal)) { + if (!store(group.newestCache(), &resourceStorageIDJournal)) { checkForMaxSizeReached(); failureReason = isMaximumSizeReached() ? TotalQuotaReached : DiskOrOperationFailure; return false; @@ -1063,13 +1039,13 @@ bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup* group, App // Update the newest cache in the group. SQLiteStatement statement(m_database, "UPDATE CacheGroups SET newestCache=? WHERE id=?"); - if (statement.prepare() != SQLResultOk) { + if (statement.prepare() != SQLITE_OK) { failureReason = DiskOrOperationFailure; return false; } - statement.bindInt64(1, group->newestCache()->storageID()); - statement.bindInt64(2, group->storageID()); + statement.bindInt64(1, group.newestCache()->storageID()); + statement.bindInt64(2, group.storageID()); if (!executeStatement(statement)) { failureReason = DiskOrOperationFailure; @@ -1082,22 +1058,24 @@ bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup* group, App return true; } -bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup* group) +bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup& group) { // Ignore the reason for failing, just attempt the store. FailureReason ignoredFailureReason; - return storeNewestCache(group, 0, ignoredFailureReason); + return storeNewestCache(group, nullptr, ignoredFailureReason); } -template <typename CharacterType> -static inline void parseHeader(const CharacterType* header, size_t headerLength, ResourceResponse& response) +template<typename CharacterType> +static inline void parseHeader(const CharacterType* header, unsigned headerLength, ResourceResponse& response) { - size_t pos = find(header, headerLength, ':'); - ASSERT(pos != notFound); - - AtomicString headerName = AtomicString(header, pos); - String headerValue = String(header + pos + 1, headerLength - pos - 1); - + ASSERT(find(header, headerLength, ':') != notFound); + unsigned colonPosition = find(header, headerLength, ':'); + + // Save memory by putting the header names into atomic strings so each is stored only once, + // even though the setHTTPHeaderField function does not require an atomic string. + AtomicString headerName { header, colonPosition }; + String headerValue { header + colonPosition + 1, headerLength - colonPosition - 1 }; + response.setHTTPHeaderField(headerName, headerValue); } @@ -1124,25 +1102,25 @@ static inline void parseHeaders(const String& headers, ResourceResponse& respons } } -PassRefPtr<ApplicationCache> ApplicationCacheStorage::loadCache(unsigned storageID) +RefPtr<ApplicationCache> ApplicationCacheStorage::loadCache(unsigned storageID) { ASSERT(SQLiteDatabaseTracker::hasTransactionInProgress()); SQLiteStatement cacheStatement(m_database, "SELECT url, statusCode, type, mimeType, textEncodingName, headers, CacheResourceData.data, CacheResourceData.path FROM CacheEntries INNER JOIN CacheResources ON CacheEntries.resource=CacheResources.id " "INNER JOIN CacheResourceData ON CacheResourceData.id=CacheResources.data WHERE CacheEntries.cache=?"); - if (cacheStatement.prepare() != SQLResultOk) { + if (cacheStatement.prepare() != SQLITE_OK) { LOG_ERROR("Could not prepare cache statement, error \"%s\"", m_database.lastErrorMsg()); - return 0; + return nullptr; } cacheStatement.bindInt64(1, storageID); - RefPtr<ApplicationCache> cache = ApplicationCache::create(); + auto cache = ApplicationCache::create(); - String flatFileDirectory = pathByAppendingComponent(m_cacheDirectory, flatFileSubdirectory); + String flatFileDirectory = pathByAppendingComponent(m_cacheDirectory, m_flatFileSubdirectoryName); int result; - while ((result = cacheStatement.step()) == SQLResultRow) { + while ((result = cacheStatement.step()) == SQLITE_ROW) { URL url(ParsedURLString, cacheStatement.getColumnText(0)); int httpStatusCode = cacheStatement.getColumnInt(1); @@ -1152,7 +1130,7 @@ PassRefPtr<ApplicationCache> ApplicationCacheStorage::loadCache(unsigned storage Vector<char> blob; cacheStatement.getColumnBlobAsVector(6, blob); - RefPtr<SharedBuffer> data = SharedBuffer::adoptVector(blob); + auto data = SharedBuffer::adoptVector(blob); String path = cacheStatement.getColumnText(7); long long size = 0; @@ -1166,21 +1144,21 @@ PassRefPtr<ApplicationCache> ApplicationCacheStorage::loadCache(unsigned storage String mimeType = cacheStatement.getColumnText(3); String textEncodingName = cacheStatement.getColumnText(4); - ResourceResponse response(url, mimeType, size, textEncodingName, ""); + ResourceResponse response(url, mimeType, size, textEncodingName); response.setHTTPStatusCode(httpStatusCode); String headers = cacheStatement.getColumnText(5); parseHeaders(headers, response); - RefPtr<ApplicationCacheResource> resource = ApplicationCacheResource::create(url, response, type, data.release(), path); + auto resource = ApplicationCacheResource::create(url, response, type, WTFMove(data), path); if (type & ApplicationCacheResource::Manifest) - cache->setManifestResource(resource.release()); + cache->setManifestResource(WTFMove(resource)); else - cache->addResource(resource.release()); + cache->addResource(WTFMove(resource)); } - if (result != SQLResultDone) + if (result != SQLITE_DONE) LOG_ERROR("Could not load cache resources, error \"%s\"", m_database.lastErrorMsg()); if (!cache->manifestResource()) { @@ -1190,52 +1168,52 @@ PassRefPtr<ApplicationCache> ApplicationCacheStorage::loadCache(unsigned storage // Load the online whitelist SQLiteStatement whitelistStatement(m_database, "SELECT url FROM CacheWhitelistURLs WHERE cache=?"); - if (whitelistStatement.prepare() != SQLResultOk) - return 0; + if (whitelistStatement.prepare() != SQLITE_OK) + return nullptr; whitelistStatement.bindInt64(1, storageID); Vector<URL> whitelist; - while ((result = whitelistStatement.step()) == SQLResultRow) + while ((result = whitelistStatement.step()) == SQLITE_ROW) whitelist.append(URL(ParsedURLString, whitelistStatement.getColumnText(0))); - if (result != SQLResultDone) + if (result != SQLITE_DONE) LOG_ERROR("Could not load cache online whitelist, error \"%s\"", m_database.lastErrorMsg()); cache->setOnlineWhitelist(whitelist); // Load online whitelist wildcard flag. SQLiteStatement whitelistWildcardStatement(m_database, "SELECT wildcard FROM CacheAllowsAllNetworkRequests WHERE cache=?"); - if (whitelistWildcardStatement.prepare() != SQLResultOk) - return 0; + if (whitelistWildcardStatement.prepare() != SQLITE_OK) + return nullptr; whitelistWildcardStatement.bindInt64(1, storageID); result = whitelistWildcardStatement.step(); - if (result != SQLResultRow) + if (result != SQLITE_ROW) LOG_ERROR("Could not load cache online whitelist wildcard flag, error \"%s\"", m_database.lastErrorMsg()); cache->setAllowsAllNetworkRequests(whitelistWildcardStatement.getColumnInt64(0)); - if (whitelistWildcardStatement.step() != SQLResultDone) + if (whitelistWildcardStatement.step() != SQLITE_DONE) LOG_ERROR("Too many rows for online whitelist wildcard flag"); // Load fallback URLs. SQLiteStatement fallbackStatement(m_database, "SELECT namespace, fallbackURL FROM FallbackURLs WHERE cache=?"); - if (fallbackStatement.prepare() != SQLResultOk) - return 0; + if (fallbackStatement.prepare() != SQLITE_OK) + return nullptr; fallbackStatement.bindInt64(1, storageID); FallbackURLVector fallbackURLs; - while ((result = fallbackStatement.step()) == SQLResultRow) + while ((result = fallbackStatement.step()) == SQLITE_ROW) fallbackURLs.append(std::make_pair(URL(ParsedURLString, fallbackStatement.getColumnText(0)), URL(ParsedURLString, fallbackStatement.getColumnText(1)))); - if (result != SQLResultDone) + if (result != SQLITE_DONE) LOG_ERROR("Could not load fallback URLs, error \"%s\"", m_database.lastErrorMsg()); cache->setFallbackURLs(fallbackURLs); cache->setStorageID(storageID); - return cache.release(); + return WTFMove(cache); } void ApplicationCacheStorage::remove(ApplicationCache* cache) @@ -1254,7 +1232,7 @@ void ApplicationCacheStorage::remove(ApplicationCache* cache) // All associated data will be deleted by database triggers. SQLiteStatement statement(m_database, "DELETE FROM Caches WHERE id=?"); - if (statement.prepare() != SQLResultOk) + if (statement.prepare() != SQLITE_OK) return; statement.bindInt64(1, cache->storageID()); @@ -1265,7 +1243,7 @@ void ApplicationCacheStorage::remove(ApplicationCache* cache) if (cache->group()->newestCache() == cache) { // Currently, there are no triggers on the cache group, which is why the cache had to be removed separately above. SQLiteStatement groupStatement(m_database, "DELETE FROM CacheGroups WHERE id=?"); - if (groupStatement.prepare() != SQLResultOk) + if (groupStatement.prepare() != SQLITE_OK) return; groupStatement.bindInt64(1, cache->group()->storageID()); @@ -1294,10 +1272,9 @@ void ApplicationCacheStorage::empty() // Clear the storage IDs for the caches in memory. // The caches will still work, but cached resources will not be saved to disk // until a cache update process has been initiated. - CacheGroupMap::const_iterator end = m_cachesInMemory.end(); - for (CacheGroupMap::const_iterator it = m_cachesInMemory.begin(); it != end; ++it) - it->value->clearStorageID(); - + for (auto* group : m_cachesInMemory.values()) + group->clearStorageID(); + checkForDeletedResources(); } @@ -1313,7 +1290,7 @@ bool ApplicationCacheStorage::shouldStoreResourceAsFlatFile(ApplicationCacheReso || resource->response().mimeType().startsWith("video/", false); } -bool ApplicationCacheStorage::writeDataToUniqueFileInDirectory(SharedBuffer* data, const String& directory, String& path, const String& fileExtension) +bool ApplicationCacheStorage::writeDataToUniqueFileInDirectory(SharedBuffer& data, const String& directory, String& path, const String& fileExtension) { String fullPath; @@ -1332,10 +1309,10 @@ bool ApplicationCacheStorage::writeDataToUniqueFileInDirectory(SharedBuffer* dat if (!handle) return false; - int64_t writtenBytes = writeToFile(handle, data->data(), data->size()); + int64_t writtenBytes = writeToFile(handle, data.data(), data.size()); closeFile(handle); - if (writtenBytes != static_cast<int64_t>(data->size())) { + if (writtenBytes != static_cast<int64_t>(data.size())) { deleteFile(fullPath); return false; } @@ -1343,45 +1320,7 @@ bool ApplicationCacheStorage::writeDataToUniqueFileInDirectory(SharedBuffer* dat return true; } -bool ApplicationCacheStorage::storeCopyOfCache(const String& cacheDirectory, ApplicationCacheHost* cacheHost) -{ - SQLiteTransactionInProgressAutoCounter transactionCounter; - - ApplicationCache* cache = cacheHost->applicationCache(); - if (!cache) - return true; - - // Create a new cache. - RefPtr<ApplicationCache> cacheCopy = ApplicationCache::create(); - - cacheCopy->setOnlineWhitelist(cache->onlineWhitelist()); - cacheCopy->setFallbackURLs(cache->fallbackURLs()); - - // Traverse the cache and add copies of all resources. - ApplicationCache::ResourceMap::const_iterator end = cache->end(); - for (ApplicationCache::ResourceMap::const_iterator it = cache->begin(); it != end; ++it) { - ApplicationCacheResource* resource = it->value.get(); - - RefPtr<ApplicationCacheResource> resourceCopy = ApplicationCacheResource::create(resource->url(), resource->response(), resource->type(), resource->data(), resource->path()); - - cacheCopy->addResource(resourceCopy.release()); - } - - // Now create a new cache group. - OwnPtr<ApplicationCacheGroup> groupCopy(adoptPtr(new ApplicationCacheGroup(cache->group()->manifestURL(), true))); - - groupCopy->setNewestCache(cacheCopy); - - ApplicationCacheStorage copyStorage; - copyStorage.setCacheDirectory(cacheDirectory); - - // Empty the cache in case something was there before. - copyStorage.empty(); - - return copyStorage.storeNewestCache(groupCopy.get()); -} - -bool ApplicationCacheStorage::manifestURLs(Vector<URL>* urls) +bool ApplicationCacheStorage::getManifestURLs(Vector<URL>* urls) { SQLiteTransactionInProgressAutoCounter transactionCounter; @@ -1392,10 +1331,10 @@ bool ApplicationCacheStorage::manifestURLs(Vector<URL>* urls) SQLiteStatement selectURLs(m_database, "SELECT manifestURL FROM CacheGroups"); - if (selectURLs.prepare() != SQLResultOk) + if (selectURLs.prepare() != SQLITE_OK) return false; - while (selectURLs.step() == SQLResultRow) + while (selectURLs.step() == SQLITE_ROW) urls->append(URL(ParsedURLString, selectURLs.getColumnText(0))); return true; @@ -1411,16 +1350,16 @@ bool ApplicationCacheStorage::cacheGroupSize(const String& manifestURL, int64_t* return false; SQLiteStatement statement(m_database, "SELECT sum(Caches.size) FROM Caches INNER JOIN CacheGroups ON Caches.cacheGroup=CacheGroups.id WHERE CacheGroups.manifestURL=?"); - if (statement.prepare() != SQLResultOk) + if (statement.prepare() != SQLITE_OK) return false; statement.bindText(1, manifestURL); int result = statement.step(); - if (result == SQLResultDone) + if (result == SQLITE_DONE) return false; - if (result != SQLResultRow) { + if (result != SQLITE_ROW) { LOG_ERROR("Could not get the size of the cache group, error \"%s\"", m_database.lastErrorMsg()); return false; } @@ -1433,23 +1372,23 @@ bool ApplicationCacheStorage::deleteCacheGroupRecord(const String& manifestURL) { ASSERT(SQLiteDatabaseTracker::hasTransactionInProgress()); SQLiteStatement idStatement(m_database, "SELECT id FROM CacheGroups WHERE manifestURL=?"); - if (idStatement.prepare() != SQLResultOk) + if (idStatement.prepare() != SQLITE_OK) return false; idStatement.bindText(1, manifestURL); int result = idStatement.step(); - if (result != SQLResultRow) + if (result != SQLITE_ROW) return false; int64_t groupId = idStatement.getColumnInt64(0); SQLiteStatement cacheStatement(m_database, "DELETE FROM Caches WHERE cacheGroup=?"); - if (cacheStatement.prepare() != SQLResultOk) + if (cacheStatement.prepare() != SQLITE_OK) return false; SQLiteStatement groupStatement(m_database, "DELETE FROM CacheGroups WHERE id=?"); - if (groupStatement.prepare() != SQLResultOk) + if (groupStatement.prepare() != SQLITE_OK) return false; cacheStatement.bindInt64(1, groupId); @@ -1464,10 +1403,11 @@ bool ApplicationCacheStorage::deleteCacheGroup(const String& manifestURL) SQLiteTransactionInProgressAutoCounter transactionCounter; SQLiteTransaction deleteTransaction(m_database); + // Check to see if the group is in memory. - ApplicationCacheGroup* group = m_cachesInMemory.get(manifestURL); + auto* group = m_cachesInMemory.get(manifestURL); if (group) - cacheGroupMadeObsolete(group); + cacheGroupMadeObsolete(*group); else { // The cache group is not in memory, so remove it from the disk. openDatabase(false); @@ -1480,9 +1420,9 @@ bool ApplicationCacheStorage::deleteCacheGroup(const String& manifestURL) } deleteTransaction.commit(); - + checkForDeletedResources(); - + return true; } @@ -1499,7 +1439,7 @@ void ApplicationCacheStorage::vacuumDatabaseFile() void ApplicationCacheStorage::checkForMaxSizeReached() { - if (m_database.lastError() == SQLResultFull) + if (m_database.lastError() == SQLITE_FULL) m_isMaximumSizeReached = true; } @@ -1516,10 +1456,10 @@ void ApplicationCacheStorage::checkForDeletedResources() "ON DeletedCacheResources.path = CacheResourceData.path " "WHERE (SELECT DeletedCacheResources.path == CacheResourceData.path) IS NULL"); - if (selectPaths.prepare() != SQLResultOk) + if (selectPaths.prepare() != SQLITE_OK) return; - if (selectPaths.step() != SQLResultRow) + if (selectPaths.step() != SQLITE_ROW) return; do { @@ -1527,7 +1467,7 @@ void ApplicationCacheStorage::checkForDeletedResources() if (path.isEmpty()) continue; - String flatFileDirectory = pathByAppendingComponent(m_cacheDirectory, flatFileSubdirectory); + String flatFileDirectory = pathByAppendingComponent(m_cacheDirectory, m_flatFileSubdirectoryName); String fullPath = pathByAppendingComponent(flatFileDirectory, path); // Don't exit the flatFileDirectory! This should only happen if the "path" entry contains a directory @@ -1536,7 +1476,7 @@ void ApplicationCacheStorage::checkForDeletedResources() continue; deleteFile(fullPath); - } while (selectPaths.step() == SQLResultRow); + } while (selectPaths.step() == SQLITE_ROW); executeSQLCommand("DELETE FROM DeletedCacheResources"); } @@ -1549,14 +1489,14 @@ long long ApplicationCacheStorage::flatFileAreaSize() SQLiteStatement selectPaths(m_database, "SELECT path FROM CacheResourceData WHERE path NOT NULL"); - if (selectPaths.prepare() != SQLResultOk) { + if (selectPaths.prepare() != SQLITE_OK) { LOG_ERROR("Could not load flat file cache resource data, error \"%s\"", m_database.lastErrorMsg()); return 0; } long long totalSize = 0; - String flatFileDirectory = pathByAppendingComponent(m_cacheDirectory, flatFileSubdirectory); - while (selectPaths.step() == SQLResultRow) { + String flatFileDirectory = pathByAppendingComponent(m_cacheDirectory, m_flatFileSubdirectoryName); + while (selectPaths.step() == SQLITE_ROW) { String path = selectPaths.getColumnText(0); String fullPath = pathByAppendingComponent(flatFileDirectory, path); long long pathSize = 0; @@ -1571,18 +1511,12 @@ long long ApplicationCacheStorage::flatFileAreaSize() void ApplicationCacheStorage::getOriginsWithCache(HashSet<RefPtr<SecurityOrigin>>& origins) { Vector<URL> urls; - if (!manifestURLs(&urls)) { - LOG_ERROR("Failed to retrieve ApplicationCache manifest URLs"); - return; - } + getManifestURLs(&urls); // Multiple manifest URLs might share the same SecurityOrigin, so we might be creating extra, wasted origins here. // The current schema doesn't allow for a more efficient way of building this list. - size_t count = urls.size(); - for (size_t i = 0; i < count; ++i) { - RefPtr<SecurityOrigin> origin = SecurityOrigin::create(urls[i]); - origins.add(origin); - } + for (auto& url : urls) + origins.add(SecurityOrigin::create(url)); } void ApplicationCacheStorage::deleteAllEntries() @@ -1591,18 +1525,57 @@ void ApplicationCacheStorage::deleteAllEntries() vacuumDatabaseFile(); } -ApplicationCacheStorage::ApplicationCacheStorage() - : m_maximumSize(ApplicationCacheStorage::noQuota()) +void ApplicationCacheStorage::deleteAllCaches() +{ + HashSet<RefPtr<SecurityOrigin>> origins; + + getOriginsWithCache(origins); + for (auto& origin : origins) + deleteCacheForOrigin(*origin); + + vacuumDatabaseFile(); +} + +void ApplicationCacheStorage::deleteCacheForOrigin(const SecurityOrigin& securityOrigin) +{ + Vector<URL> urls; + if (!getManifestURLs(&urls)) { + LOG_ERROR("Failed to retrieve ApplicationCache manifest URLs"); + return; + } + + URL originURL(URL(), securityOrigin.toString()); + + for (const auto& url : urls) { + if (!protocolHostAndPortAreEqual(url, originURL)) + continue; + + if (auto* group = findInMemoryCacheGroup(url)) + group->makeObsolete(); + else + deleteCacheGroup(url); + } +} + +int64_t ApplicationCacheStorage::diskUsageForOrigin(const SecurityOrigin& securityOrigin) +{ + int64_t usage = 0; + calculateUsageForOrigin(&securityOrigin, usage); + return usage; +} + +ApplicationCacheStorage::ApplicationCacheStorage(const String& cacheDirectory, const String& flatFileSubdirectoryName) + : m_cacheDirectory(cacheDirectory) + , m_flatFileSubdirectoryName(flatFileSubdirectoryName) + , m_maximumSize(ApplicationCacheStorage::noQuota()) , m_isMaximumSizeReached(false) , m_defaultOriginQuota(ApplicationCacheStorage::noQuota()) { } -ApplicationCacheStorage& cacheStorage() +Ref<ApplicationCacheStorage> ApplicationCacheStorage::create(const String& cacheDirectory, const String& flatFileSubdirectoryName) { - DEFINE_STATIC_LOCAL(ApplicationCacheStorage, storage, ()); - - return storage; + return adoptRef(*new ApplicationCacheStorage(cacheDirectory, flatFileSubdirectoryName)); } -} // namespace WebCore +} diff --git a/Source/WebCore/loader/appcache/ApplicationCacheStorage.h b/Source/WebCore/loader/appcache/ApplicationCacheStorage.h index 76eaa3ecf..9d17a1bcd 100644 --- a/Source/WebCore/loader/appcache/ApplicationCacheStorage.h +++ b/Source/WebCore/loader/appcache/ApplicationCacheStorage.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2010, 2011 Apple Inc. All Rights Reserved. + * Copyright (C) 2008-2017 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,8 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ApplicationCacheStorage_h -#define ApplicationCacheStorage_h +#pragma once #include "SecurityOriginHash.h" #include "SQLiteDatabase.h" @@ -42,10 +41,9 @@ class ApplicationCacheResource; class URL; class SecurityOrigin; class SharedBuffer; -template <class T> class StorageIDJournal; +template<typename> class StorageIDJournal; -class ApplicationCacheStorage { - WTF_MAKE_NONCOPYABLE(ApplicationCacheStorage); WTF_MAKE_FAST_ALLOCATED; +class ApplicationCacheStorage : public RefCounted<ApplicationCacheStorage> { public: enum FailureReason { OriginQuotaReached, @@ -53,20 +51,21 @@ public: DiskOrOperationFailure }; - void setCacheDirectory(const String&); + WEBCORE_EXPORT static Ref<ApplicationCacheStorage> create(const String& cacheDirectory, const String& flatFileSubdirectoryName); + const String& cacheDirectory() const; - void setMaximumSize(int64_t size); - int64_t maximumSize() const; + WEBCORE_EXPORT void setMaximumSize(int64_t size); + WEBCORE_EXPORT int64_t maximumSize() const; bool isMaximumSizeReached() const; int64_t spaceNeeded(int64_t cacheToSave); int64_t defaultOriginQuota() const { return m_defaultOriginQuota; } - void setDefaultOriginQuota(int64_t quota); - bool calculateUsageForOrigin(const SecurityOrigin*, int64_t& usage); - bool calculateQuotaForOrigin(const SecurityOrigin*, int64_t& quota); - bool calculateRemainingSizeForOriginExcludingCache(const SecurityOrigin*, ApplicationCache*, int64_t& remainingSize); - bool storeUpdatedQuotaForOrigin(const SecurityOrigin*, int64_t quota); + WEBCORE_EXPORT void setDefaultOriginQuota(int64_t quota); + WEBCORE_EXPORT bool calculateUsageForOrigin(const SecurityOrigin*, int64_t& usage); + WEBCORE_EXPORT bool calculateQuotaForOrigin(const SecurityOrigin&, int64_t& quota); + bool calculateRemainingSizeForOriginExcludingCache(const SecurityOrigin&, ApplicationCache*, int64_t& remainingSize); + WEBCORE_EXPORT bool storeUpdatedQuotaForOrigin(const SecurityOrigin*, int64_t quota); bool checkOriginQuota(ApplicationCacheGroup*, ApplicationCache* oldCache, ApplicationCache* newCache, int64_t& totalSpaceNeeded); ApplicationCacheGroup* cacheGroupForURL(const URL&); // Cache to load a main resource from. @@ -74,38 +73,47 @@ public: ApplicationCacheGroup* findOrCreateCacheGroup(const URL& manifestURL); ApplicationCacheGroup* findInMemoryCacheGroup(const URL& manifestURL) const; - void cacheGroupDestroyed(ApplicationCacheGroup*); - void cacheGroupMadeObsolete(ApplicationCacheGroup*); - - bool storeNewestCache(ApplicationCacheGroup*, ApplicationCache* oldCache, FailureReason& failureReason); - bool storeNewestCache(ApplicationCacheGroup*); // Updates the cache group, but doesn't remove old cache. + void cacheGroupDestroyed(ApplicationCacheGroup&); + void cacheGroupMadeObsolete(ApplicationCacheGroup&); + + bool storeNewestCache(ApplicationCacheGroup&, ApplicationCache* oldCache, FailureReason&); + bool storeNewestCache(ApplicationCacheGroup&); // Updates the cache group, but doesn't remove old cache. bool store(ApplicationCacheResource*, ApplicationCache*); bool storeUpdatedType(ApplicationCacheResource*, ApplicationCache*); // Removes the group if the cache to be removed is the newest one (so, storeNewestCache() needs to be called beforehand when updating). void remove(ApplicationCache*); - - void empty(); - - static bool storeCopyOfCache(const String& cacheDirectory, ApplicationCacheHost*); - bool manifestURLs(Vector<URL>* urls); + WEBCORE_EXPORT void empty(); + + bool getManifestURLs(Vector<URL>* urls); bool cacheGroupSize(const String& manifestURL, int64_t* size); bool deleteCacheGroup(const String& manifestURL); - void vacuumDatabaseFile(); + WEBCORE_EXPORT void vacuumDatabaseFile(); + + WEBCORE_EXPORT void getOriginsWithCache(HashSet<RefPtr<SecurityOrigin>, SecurityOriginHash>&); + WEBCORE_EXPORT void deleteAllEntries(); + + // FIXME: This should be consolidated with deleteAllEntries(). + WEBCORE_EXPORT void deleteAllCaches(); + + // FIXME: This should be consolidated with deleteCacheGroup(). + WEBCORE_EXPORT void deleteCacheForOrigin(const SecurityOrigin&); - void getOriginsWithCache(HashSet<RefPtr<SecurityOrigin>, SecurityOriginHash>&); - void deleteAllEntries(); + // FIXME: This should be consolidated with calculateUsageForOrigin(). + WEBCORE_EXPORT int64_t diskUsageForOrigin(const SecurityOrigin&); static int64_t unknownQuota() { return -1; } static int64_t noQuota() { return std::numeric_limits<int64_t>::max(); } + private: - ApplicationCacheStorage(); - PassRefPtr<ApplicationCache> loadCache(unsigned storageID); + ApplicationCacheStorage(const String& cacheDirectory, const String& flatFileSubdirectoryName); + + RefPtr<ApplicationCache> loadCache(unsigned storageID); ApplicationCacheGroup* loadCacheGroup(const URL& manifestURL); - typedef StorageIDJournal<ApplicationCacheResource> ResourceStorageIDJournal; - typedef StorageIDJournal<ApplicationCacheGroup> GroupStorageIDJournal; + using ResourceStorageIDJournal = StorageIDJournal<ApplicationCacheResource>; + using GroupStorageIDJournal = StorageIDJournal<ApplicationCacheGroup>; bool store(ApplicationCacheGroup*, GroupStorageIDJournal*); bool store(ApplicationCache*, ResourceStorageIDJournal*); @@ -115,7 +123,7 @@ private: bool ensureOriginRecord(const SecurityOrigin*); bool shouldStoreResourceAsFlatFile(ApplicationCacheResource*); void deleteTables(); - bool writeDataToUniqueFileInDirectory(SharedBuffer*, const String& directory, String& outFilename, const String& fileExtension); + bool writeDataToUniqueFileInDirectory(SharedBuffer&, const String& directory, String& outFilename, const String& fileExtension); void loadManifestHostHashes(); @@ -129,8 +137,9 @@ private: void checkForMaxSizeReached(); void checkForDeletedResources(); long long flatFileAreaSize(); - - String m_cacheDirectory; + + const String m_cacheDirectory; + const String m_flatFileSubdirectoryName; String m_cacheFile; int64_t m_maximumSize; @@ -144,14 +153,9 @@ private: // we keep a hash set of the hosts of the manifest URLs of all non-obsolete cache groups. HashCountedSet<unsigned, AlreadyHashed> m_cacheHostSet; - typedef HashMap<String, ApplicationCacheGroup*> CacheGroupMap; - CacheGroupMap m_cachesInMemory; // Excludes obsolete cache groups. + HashMap<String, ApplicationCacheGroup*> m_cachesInMemory; // Excludes obsolete cache groups. - friend ApplicationCacheStorage& cacheStorage(); + friend class WTF::NeverDestroyed<ApplicationCacheStorage>; }; - -ApplicationCacheStorage& cacheStorage(); - -} // namespace WebCore -#endif // ApplicationCacheStorage_h +} // namespace WebCore diff --git a/Source/WebCore/loader/appcache/DOMApplicationCache.cpp b/Source/WebCore/loader/appcache/DOMApplicationCache.cpp index 56437a80d..ed8fad8f6 100644 --- a/Source/WebCore/loader/appcache/DOMApplicationCache.cpp +++ b/Source/WebCore/loader/appcache/DOMApplicationCache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved. + * Copyright (C) 2008-2017 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,110 +29,84 @@ #include "ApplicationCacheHost.h" #include "Document.h" #include "DocumentLoader.h" -#include "Event.h" -#include "EventException.h" -#include "EventListener.h" -#include "EventNames.h" #include "ExceptionCode.h" #include "Frame.h" -#include "FrameLoader.h" namespace WebCore { -DOMApplicationCache::DOMApplicationCache(Frame* frame) - : DOMWindowProperty(frame) +DOMApplicationCache::DOMApplicationCache(Frame& frame) + : DOMWindowProperty(&frame) { - ApplicationCacheHost* cacheHost = applicationCacheHost(); - if (cacheHost) - cacheHost->setDOMApplicationCache(this); + if (auto* host = applicationCacheHost()) + host->setDOMApplicationCache(this); } -void DOMApplicationCache::disconnectFrameForPageCache() +void DOMApplicationCache::disconnectFrameForDocumentSuspension() { - if (ApplicationCacheHost* cacheHost = applicationCacheHost()) - cacheHost->setDOMApplicationCache(0); - DOMWindowProperty::disconnectFrameForPageCache(); + if (auto* host = applicationCacheHost()) + host->setDOMApplicationCache(nullptr); + DOMWindowProperty::disconnectFrameForDocumentSuspension(); } -void DOMApplicationCache::reconnectFrameFromPageCache(Frame* frame) +void DOMApplicationCache::reconnectFrameFromDocumentSuspension(Frame* frame) { - DOMWindowProperty::reconnectFrameFromPageCache(frame); - if (ApplicationCacheHost* cacheHost = applicationCacheHost()) - cacheHost->setDOMApplicationCache(this); + DOMWindowProperty::reconnectFrameFromDocumentSuspension(frame); + if (auto* host = applicationCacheHost()) + host->setDOMApplicationCache(this); } void DOMApplicationCache::willDestroyGlobalObjectInFrame() { - if (ApplicationCacheHost* cacheHost = applicationCacheHost()) - cacheHost->setDOMApplicationCache(0); + if (auto* host = applicationCacheHost()) + host->setDOMApplicationCache(nullptr); DOMWindowProperty::willDestroyGlobalObjectInFrame(); } ApplicationCacheHost* DOMApplicationCache::applicationCacheHost() const { - if (!m_frame || !m_frame->loader().documentLoader()) - return 0; - return m_frame->loader().documentLoader()->applicationCacheHost(); + if (!m_frame) + return nullptr; + auto* documentLoader = m_frame->loader().documentLoader(); + if (!documentLoader) + return nullptr; + return &documentLoader->applicationCacheHost(); } unsigned short DOMApplicationCache::status() const { - ApplicationCacheHost* cacheHost = applicationCacheHost(); - if (!cacheHost) + auto* host = applicationCacheHost(); + if (!host) return ApplicationCacheHost::UNCACHED; - return cacheHost->status(); + return host->status(); } -void DOMApplicationCache::update(ExceptionCode& ec) +ExceptionOr<void> DOMApplicationCache::update() { - ApplicationCacheHost* cacheHost = applicationCacheHost(); - if (!cacheHost || !cacheHost->update()) - ec = INVALID_STATE_ERR; + auto* host = applicationCacheHost(); + if (!host || !host->update()) + return Exception { INVALID_STATE_ERR }; + return { }; } -void DOMApplicationCache::swapCache(ExceptionCode& ec) +ExceptionOr<void> DOMApplicationCache::swapCache() { - ApplicationCacheHost* cacheHost = applicationCacheHost(); - if (!cacheHost || !cacheHost->swapCache()) - ec = INVALID_STATE_ERR; + auto* host = applicationCacheHost(); + if (!host || !host->swapCache()) + return Exception { INVALID_STATE_ERR }; + return { }; } void DOMApplicationCache::abort() { - ApplicationCacheHost* cacheHost = applicationCacheHost(); - if (cacheHost) - cacheHost->abort(); + if (auto* host = applicationCacheHost()) + host->abort(); } ScriptExecutionContext* DOMApplicationCache::scriptExecutionContext() const { - if (m_frame) - return m_frame->document(); - return 0; -} - -const AtomicString& DOMApplicationCache::toEventType(ApplicationCacheHost::EventID id) -{ - switch (id) { - case ApplicationCacheHost::CHECKING_EVENT: - return eventNames().checkingEvent; - case ApplicationCacheHost::ERROR_EVENT: - return eventNames().errorEvent; - case ApplicationCacheHost::NOUPDATE_EVENT: - return eventNames().noupdateEvent; - case ApplicationCacheHost::DOWNLOADING_EVENT: - return eventNames().downloadingEvent; - case ApplicationCacheHost::PROGRESS_EVENT: - return eventNames().progressEvent; - case ApplicationCacheHost::UPDATEREADY_EVENT: - return eventNames().updatereadyEvent; - case ApplicationCacheHost::CACHED_EVENT: - return eventNames().cachedEvent; - case ApplicationCacheHost::OBSOLETE_EVENT: - return eventNames().obsoleteEvent; - } - ASSERT_NOT_REACHED(); - return eventNames().errorEvent; + if (!m_frame) + return nullptr; + return m_frame->document(); } } // namespace WebCore diff --git a/Source/WebCore/loader/appcache/DOMApplicationCache.h b/Source/WebCore/loader/appcache/DOMApplicationCache.h index 910cb7502..cf6d2a9d9 100644 --- a/Source/WebCore/loader/appcache/DOMApplicationCache.h +++ b/Source/WebCore/loader/appcache/DOMApplicationCache.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved. + * Copyright (C) 2008-2017 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,68 +23,43 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef DOMApplicationCache_h -#define DOMApplicationCache_h +#pragma once -#include "ApplicationCacheHost.h" #include "DOMWindowProperty.h" -#include "EventNames.h" #include "EventTarget.h" -#include "ScriptWrappable.h" -#include <wtf/Forward.h> -#include <wtf/HashMap.h> -#include <wtf/PassRefPtr.h> -#include <wtf/RefCounted.h> -#include <wtf/Vector.h> -#include <wtf/text/AtomicStringHash.h> namespace WebCore { +class ApplicationCacheHost; class Frame; -class URL; -class DOMApplicationCache final : public ScriptWrappable, public RefCounted<DOMApplicationCache>, public EventTargetWithInlineData, public DOMWindowProperty { +class DOMApplicationCache final : public RefCounted<DOMApplicationCache>, public EventTargetWithInlineData, public DOMWindowProperty { public: - static PassRefPtr<DOMApplicationCache> create(Frame* frame) { return adoptRef(new DOMApplicationCache(frame)); } + static Ref<DOMApplicationCache> create(Frame& frame) { return adoptRef(*new DOMApplicationCache(frame)); } virtual ~DOMApplicationCache() { ASSERT(!m_frame); } - virtual void disconnectFrameForPageCache() override; - virtual void reconnectFrameFromPageCache(Frame*) override; - virtual void willDestroyGlobalObjectInFrame() override; - unsigned short status() const; - void update(ExceptionCode&); - void swapCache(ExceptionCode&); + ExceptionOr<void> update(); + ExceptionOr<void> swapCache(); void abort(); - using RefCounted<DOMApplicationCache>::ref; - using RefCounted<DOMApplicationCache>::deref; - - // Explicitly named attribute event listener helpers - - DEFINE_ATTRIBUTE_EVENT_LISTENER(checking); - DEFINE_ATTRIBUTE_EVENT_LISTENER(error); - DEFINE_ATTRIBUTE_EVENT_LISTENER(noupdate); - DEFINE_ATTRIBUTE_EVENT_LISTENER(downloading); - DEFINE_ATTRIBUTE_EVENT_LISTENER(progress); - DEFINE_ATTRIBUTE_EVENT_LISTENER(updateready); - DEFINE_ATTRIBUTE_EVENT_LISTENER(cached); - DEFINE_ATTRIBUTE_EVENT_LISTENER(obsolete); + using RefCounted::ref; + using RefCounted::deref; - virtual EventTargetInterface eventTargetInterface() const override { return DOMApplicationCacheEventTargetInterfaceType; } - virtual ScriptExecutionContext* scriptExecutionContext() const override; +private: + explicit DOMApplicationCache(Frame&); - static const AtomicString& toEventType(ApplicationCacheHost::EventID id); + void refEventTarget() final { ref(); } + void derefEventTarget() final { deref(); } -private: - explicit DOMApplicationCache(Frame*); + EventTargetInterface eventTargetInterface() const final { return DOMApplicationCacheEventTargetInterfaceType; } + ScriptExecutionContext* scriptExecutionContext() const final; - virtual void refEventTarget() override { ref(); } - virtual void derefEventTarget() override { deref(); } + void disconnectFrameForDocumentSuspension() final; + void reconnectFrameFromDocumentSuspension(Frame*) final; + void willDestroyGlobalObjectInFrame() final; ApplicationCacheHost* applicationCacheHost() const; }; } // namespace WebCore - -#endif // DOMApplicationCache_h diff --git a/Source/WebCore/loader/appcache/DOMApplicationCache.idl b/Source/WebCore/loader/appcache/DOMApplicationCache.idl index 9622c128b..1799f2e38 100644 --- a/Source/WebCore/loader/appcache/DOMApplicationCache.idl +++ b/Source/WebCore/loader/appcache/DOMApplicationCache.idl @@ -24,11 +24,10 @@ */ [ - NoInterfaceObject, - EventTarget, DoNotCheckConstants, GenerateIsReachable=ImplFrame, -] interface DOMApplicationCache { + InterfaceName=ApplicationCache, +] interface DOMApplicationCache : EventTarget { // update status const unsigned short UNCACHED = 0; const unsigned short IDLE = 1; @@ -38,27 +37,17 @@ const unsigned short OBSOLETE = 5; readonly attribute unsigned short status; - [RaisesException] void update(); - [RaisesException] void swapCache(); + [MayThrowException] void update(); + [MayThrowException] void swapCache(); void abort(); - // events - attribute EventListener onchecking; - attribute EventListener onerror; - attribute EventListener onnoupdate; - attribute EventListener ondownloading; - attribute EventListener onprogress; - attribute EventListener onupdateready; - attribute EventListener oncached; - attribute EventListener onobsolete; - - // EventTarget interface - void addEventListener(DOMString type, - EventListener listener, - optional boolean useCapture); - void removeEventListener(DOMString type, - EventListener listener, - optional boolean useCapture); - [RaisesException] boolean dispatchEvent(Event evt); + attribute EventHandler onchecking; + attribute EventHandler onerror; + attribute EventHandler onnoupdate; + attribute EventHandler ondownloading; + attribute EventHandler onprogress; + attribute EventHandler onupdateready; + attribute EventHandler oncached; + attribute EventHandler onobsolete; }; diff --git a/Source/WebCore/loader/appcache/ManifestParser.cpp b/Source/WebCore/loader/appcache/ManifestParser.cpp index a47aa150e..5c151359d 100644 --- a/Source/WebCore/loader/appcache/ManifestParser.cpp +++ b/Source/WebCore/loader/appcache/ManifestParser.cpp @@ -28,6 +28,7 @@ #include "TextResourceDecoder.h" #include "URL.h" +#include <wtf/text/StringView.h> #include <wtf/unicode/CharacterNames.h> namespace WebCore { @@ -43,9 +44,7 @@ bool parseManifest(const URL& manifestURL, const char* data, int length, Manifes Mode mode = Explicit; - RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("text/cache-manifest", "UTF-8"); - String s = decoder->decode(data, length); - s.append(decoder->flush()); + String s = TextResourceDecoder::create("text/cache-manifest", "UTF-8")->decodeAndFlush(data, length); // Look for the magic signature: "^\xFEFF?CACHE MANIFEST[ \t]?" (the BOM is removed by TextResourceDecoder). // Example: "CACHE MANIFEST #comment" is a valid signature. @@ -53,8 +52,10 @@ bool parseManifest(const URL& manifestURL, const char* data, int length, Manifes if (!s.startsWith("CACHE MANIFEST")) return false; - const UChar* end = s.deprecatedCharacters() + s.length(); - const UChar* p = s.deprecatedCharacters() + 14; // "CACHE MANIFEST" is 14 characters. + StringView manifestAfterSignature = StringView(s).substring(14); // "CACHE MANIFEST" is 14 characters. + auto upconvertedCharacters = manifestAfterSignature.upconvertedCharacters(); + const UChar* p = upconvertedCharacters; + const UChar* end = p + manifestAfterSignature.length(); if (p < end && *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r') return false; @@ -99,28 +100,28 @@ bool parseManifest(const URL& manifestURL, const char* data, int length, Manifes else if (mode == Unknown) continue; else if (mode == Explicit || mode == OnlineWhitelist) { - const UChar* p = line.deprecatedCharacters(); + auto upconvertedLineCharacters = StringView(line).upconvertedCharacters(); + const UChar* p = upconvertedLineCharacters; const UChar* lineEnd = p + line.length(); // Look for whitespace separating the URL from subsequent ignored tokens. while (p < lineEnd && *p != '\t' && *p != ' ') p++; - if (mode == OnlineWhitelist && p - line.deprecatedCharacters() == 1 && *line.deprecatedCharacters() == '*') { + if (mode == OnlineWhitelist && p - upconvertedLineCharacters == 1 && line[0] == '*') { // Wildcard was found. manifest.allowAllNetworkRequests = true; continue; } - URL url(manifestURL, String(line.deprecatedCharacters(), p - line.deprecatedCharacters())); + URL url(manifestURL, line.substring(0, p - upconvertedLineCharacters)); if (!url.isValid()) continue; - if (url.hasFragmentIdentifier()) - url.removeFragmentIdentifier(); + url.removeFragmentIdentifier(); - if (!equalIgnoringCase(url.protocol(), manifestURL.protocol())) + if (!equalIgnoringASCIICase(url.protocol(), manifestURL.protocol())) continue; if (mode == Explicit && manifestURL.protocolIs("https") && !protocolHostAndPortAreEqual(manifestURL, url)) @@ -132,7 +133,8 @@ bool parseManifest(const URL& manifestURL, const char* data, int length, Manifes manifest.onlineWhitelistedURLs.append(url); } else if (mode == Fallback) { - const UChar* p = line.deprecatedCharacters(); + auto upconvertedLineCharacters = StringView(line).upconvertedCharacters(); + const UChar* p = upconvertedLineCharacters; const UChar* lineEnd = p + line.length(); // Look for whitespace separating the two URLs @@ -144,11 +146,10 @@ bool parseManifest(const URL& manifestURL, const char* data, int length, Manifes continue; } - URL namespaceURL(manifestURL, String(line.deprecatedCharacters(), p - line.deprecatedCharacters())); + URL namespaceURL(manifestURL, line.substring(0, p - upconvertedLineCharacters)); if (!namespaceURL.isValid()) continue; - if (namespaceURL.hasFragmentIdentifier()) - namespaceURL.removeFragmentIdentifier(); + namespaceURL.removeFragmentIdentifier(); if (!protocolHostAndPortAreEqual(manifestURL, namespaceURL)) continue; @@ -165,8 +166,7 @@ bool parseManifest(const URL& manifestURL, const char* data, int length, Manifes URL fallbackURL(manifestURL, String(fallbackStart, p - fallbackStart)); if (!fallbackURL.isValid()) continue; - if (fallbackURL.hasFragmentIdentifier()) - fallbackURL.removeFragmentIdentifier(); + fallbackURL.removeFragmentIdentifier(); if (!protocolHostAndPortAreEqual(manifestURL, fallbackURL)) continue; diff --git a/Source/WebCore/loader/appcache/ManifestParser.h b/Source/WebCore/loader/appcache/ManifestParser.h index 28315dde6..b28249ebe 100644 --- a/Source/WebCore/loader/appcache/ManifestParser.h +++ b/Source/WebCore/loader/appcache/ManifestParser.h @@ -23,24 +23,22 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ManifestParser_h -#define ManifestParser_h +#pragma once #include "ApplicationCache.h" +#include <wtf/HashSet.h> namespace WebCore { - class URL; +class URL; - struct Manifest { - Vector<URL> onlineWhitelistedURLs; - HashSet<String> explicitURLs; - FallbackURLVector fallbackURLs; - bool allowAllNetworkRequests; // Wildcard found in NETWORK section. - }; +struct Manifest { + Vector<URL> onlineWhitelistedURLs; + HashSet<String> explicitURLs; + FallbackURLVector fallbackURLs; + bool allowAllNetworkRequests; // Wildcard found in NETWORK section. +}; - bool parseManifest(const URL& manifestURL, const char* data, int length, Manifest&); +bool parseManifest(const URL& manifestURL, const char* data, int length, Manifest&); -} - -#endif // ManifestParser_h +} // namespace WebCore |