diff options
author | Steve Block <steveblock@google.com> | 2011-05-25 19:08:45 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2011-06-08 13:51:31 +0100 |
commit | 2bde8e466a4451c7319e3a072d118917957d6554 (patch) | |
tree | 28f4a1b869a513e565c7760d0e6a06e7cf1fe95a /Source/WebCore/loader/appcache | |
parent | 6939c99b71d9372d14a0c74a772108052e8c48c8 (diff) | |
download | external_webkit-2bde8e466a4451c7319e3a072d118917957d6554.zip external_webkit-2bde8e466a4451c7319e3a072d118917957d6554.tar.gz external_webkit-2bde8e466a4451c7319e3a072d118917957d6554.tar.bz2 |
Merge WebKit at r82507: Initial merge by git
Change-Id: I60ce9d780725b58b45e54165733a8ffee23b683e
Diffstat (limited to 'Source/WebCore/loader/appcache')
8 files changed, 248 insertions, 48 deletions
diff --git a/Source/WebCore/loader/appcache/ApplicationCache.cpp b/Source/WebCore/loader/appcache/ApplicationCache.cpp index 450fa10..f3479b4 100644 --- a/Source/WebCore/loader/appcache/ApplicationCache.cpp +++ b/Source/WebCore/loader/appcache/ApplicationCache.cpp @@ -32,6 +32,7 @@ #include "ApplicationCacheResource.h" #include "ApplicationCacheStorage.h" #include "ResourceRequest.h" +#include "SecurityOrigin.h" #include <wtf/text/CString.h> #include <stdio.h> @@ -182,7 +183,29 @@ void ApplicationCache::clearStorageID() ResourceMap::const_iterator end = m_resources.end(); for (ResourceMap::const_iterator it = m_resources.begin(); it != end; ++it) it->second->clearStorageID(); -} +} + +void ApplicationCache::deleteCacheForOrigin(SecurityOrigin* origin) +{ + Vector<KURL> urls; + if (!cacheStorage().manifestURLs(&urls)) { + LOG_ERROR("Failed to retrieve ApplicationCache manifest URLs"); + return; + } + + KURL originURL(KURL(), 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]); + } + } +} #ifndef NDEBUG void ApplicationCache::dump() diff --git a/Source/WebCore/loader/appcache/ApplicationCache.h b/Source/WebCore/loader/appcache/ApplicationCache.h index f073499..9d20361 100644 --- a/Source/WebCore/loader/appcache/ApplicationCache.h +++ b/Source/WebCore/loader/appcache/ApplicationCache.h @@ -42,12 +42,16 @@ class ApplicationCacheResource; class DocumentLoader; class KURL; class ResourceRequest; +class SecurityOrigin; typedef Vector<std::pair<KURL, KURL> > FallbackURLVector; class ApplicationCache : public RefCounted<ApplicationCache> { public: static PassRefPtr<ApplicationCache> create() { return adoptRef(new ApplicationCache); } + + static void deleteCacheForOrigin(SecurityOrigin*); + ~ApplicationCache(); void addResource(PassRefPtr<ApplicationCacheResource> resource); diff --git a/Source/WebCore/loader/appcache/ApplicationCacheGroup.cpp b/Source/WebCore/loader/appcache/ApplicationCacheGroup.cpp index 514ef19..aab8927 100644 --- a/Source/WebCore/loader/appcache/ApplicationCacheGroup.cpp +++ b/Source/WebCore/loader/appcache/ApplicationCacheGroup.cpp @@ -474,9 +474,8 @@ PassRefPtr<ResourceHandle> ApplicationCacheGroup::createResourceHandle(const KUR // Because willSendRequest only gets called during redirects, we initialize // the identifier and the first willSendRequest here. m_currentResourceIdentifier = m_frame->page()->progress()->createUniqueIdentifier(); - InspectorInstrumentation::identifierForInitialRequest(m_frame, m_currentResourceIdentifier, m_frame->loader()->documentLoader(), handle->firstRequest()); ResourceResponse redirectResponse = ResourceResponse(); - InspectorInstrumentation::willSendRequest(m_frame, m_currentResourceIdentifier, request, redirectResponse); + InspectorInstrumentation::willSendRequest(m_frame, m_currentResourceIdentifier, m_frame->loader()->documentLoader(), request, redirectResponse); #endif return handle; } @@ -512,7 +511,7 @@ 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())); + 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; @@ -540,7 +539,7 @@ 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())); + 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; @@ -555,8 +554,10 @@ void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, const Res void ApplicationCacheGroup::didReceiveData(ResourceHandle* handle, const char* data, int length, int lengthReceived) { + UNUSED_PARAM(lengthReceived); + #if ENABLE(INSPECTOR) - InspectorInstrumentation::didReceiveContentLength(m_frame, m_currentResourceIdentifier, lengthReceived); + InspectorInstrumentation::didReceiveContentLength(m_frame, m_currentResourceIdentifier, length, 0); #endif if (handle == m_manifestHandle) { @@ -642,7 +643,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())); + m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, newestCachedResource->response(), type, newestCachedResource->data(), newestCachedResource->path())); // Load the next resource, if any. startLoadingEntry(); } @@ -866,7 +867,7 @@ void ApplicationCacheGroup::checkIfLoadIsComplete() } ApplicationCacheStorage::FailureReason failureReason; - RefPtr<ApplicationCache> oldNewestCache = (m_newestCache == m_cacheBeingUpdated) ? 0 : m_newestCache; + RefPtr<ApplicationCache> oldNewestCache = (m_newestCache == m_cacheBeingUpdated) ? RefPtr<ApplicationCache>() : m_newestCache; setNewestCache(m_cacheBeingUpdated.release()); if (cacheStorage().storeNewestCache(this, oldNewestCache.get(), failureReason)) { // New cache stored, now remove the old cache. diff --git a/Source/WebCore/loader/appcache/ApplicationCacheHost.h b/Source/WebCore/loader/appcache/ApplicationCacheHost.h index a1f2841..56a5f57 100644 --- a/Source/WebCore/loader/appcache/ApplicationCacheHost.h +++ b/Source/WebCore/loader/appcache/ApplicationCacheHost.h @@ -156,6 +156,11 @@ namespace WebCore { CacheInfo applicationCacheInfo(); #endif +#if !PLATFORM(CHROMIUM) + bool shouldLoadResourceFromApplicationCache(const ResourceRequest&, ApplicationCacheResource*&); + bool getApplicationCacheFallbackResource(const ResourceRequest&, ApplicationCacheResource*&, ApplicationCache* = 0); +#endif + private: bool isApplicationCacheEnabled(); DocumentLoader* documentLoader() const { return m_documentLoader; } @@ -182,8 +187,6 @@ namespace WebCore { friend class ApplicationCacheStorage; bool scheduleLoadFallbackResourceFromApplicationCache(ResourceLoader*, ApplicationCache* = 0); - bool shouldLoadResourceFromApplicationCache(const ResourceRequest&, ApplicationCacheResource*&); - bool getApplicationCacheFallbackResource(const ResourceRequest&, ApplicationCacheResource*&, ApplicationCache* = 0); void setCandidateApplicationCacheGroup(ApplicationCacheGroup* group); ApplicationCacheGroup* candidateApplicationCacheGroup() const { return m_candidateApplicationCacheGroup; } void setApplicationCache(PassRefPtr<ApplicationCache> applicationCache); diff --git a/Source/WebCore/loader/appcache/ApplicationCacheResource.cpp b/Source/WebCore/loader/appcache/ApplicationCacheResource.cpp index 03c5c83..c0df573 100644 --- a/Source/WebCore/loader/appcache/ApplicationCacheResource.cpp +++ b/Source/WebCore/loader/appcache/ApplicationCacheResource.cpp @@ -31,11 +31,12 @@ namespace WebCore { -ApplicationCacheResource::ApplicationCacheResource(const KURL& url, const ResourceResponse& response, unsigned type, PassRefPtr<SharedBuffer> data) +ApplicationCacheResource::ApplicationCacheResource(const KURL& url, const ResourceResponse& response, unsigned type, PassRefPtr<SharedBuffer> data, const String& path) : SubstituteResource(url, response, data) , m_type(type) , m_storageID(0) , m_estimatedSizeInStorage(0) + , m_path(path) { } diff --git a/Source/WebCore/loader/appcache/ApplicationCacheResource.h b/Source/WebCore/loader/appcache/ApplicationCacheResource.h index 2ca7846..6633c6c 100644 --- a/Source/WebCore/loader/appcache/ApplicationCacheResource.h +++ b/Source/WebCore/loader/appcache/ApplicationCacheResource.h @@ -42,10 +42,10 @@ public: Fallback = 1 << 4 }; - static PassRefPtr<ApplicationCacheResource> create(const KURL& url, const ResourceResponse& response, unsigned type, PassRefPtr<SharedBuffer> buffer = SharedBuffer::create()) + static PassRefPtr<ApplicationCacheResource> create(const KURL& url, const ResourceResponse& response, unsigned type, PassRefPtr<SharedBuffer> buffer = SharedBuffer::create(), const String& path = String()) { ASSERT(!url.hasFragmentIdentifier()); - return adoptRef(new ApplicationCacheResource(url, response, type, buffer)); + return adoptRef(new ApplicationCacheResource(url, response, type, buffer, path)); } unsigned type() const { return m_type; } @@ -56,16 +56,20 @@ public: void clearStorageID() { m_storageID = 0; } int64_t estimatedSizeInStorage(); + const String& path() const { return m_path; } + void setPath(const String& path) { m_path = path; } + #ifndef NDEBUG static void dumpType(unsigned type); #endif private: - ApplicationCacheResource(const KURL& url, const ResourceResponse& response, unsigned type, PassRefPtr<SharedBuffer> buffer); + ApplicationCacheResource(const KURL&, const ResourceResponse&, unsigned type, PassRefPtr<SharedBuffer>, const String& path); unsigned m_type; unsigned m_storageID; int64_t m_estimatedSizeInStorage; + String m_path; }; } // namespace WebCore diff --git a/Source/WebCore/loader/appcache/ApplicationCacheStorage.cpp b/Source/WebCore/loader/appcache/ApplicationCacheStorage.cpp index 5c6937e..a126f8a 100644 --- a/Source/WebCore/loader/appcache/ApplicationCacheStorage.cpp +++ b/Source/WebCore/loader/appcache/ApplicationCacheStorage.cpp @@ -38,6 +38,7 @@ #include "SQLiteStatement.h" #include "SQLiteTransaction.h" #include "SecurityOrigin.h" +#include "UUID.h" #include <wtf/text/CString.h> #include <wtf/StdLibExtras.h> #include <wtf/StringExtras.h> @@ -46,6 +47,8 @@ using namespace std; namespace WebCore { +static const char flatFileSubdirectory[] = "ApplicationCache"; + template <class T> class StorageIDJournal { public: @@ -90,7 +93,7 @@ static unsigned urlHostHash(const KURL& url) unsigned hostStart = url.hostStart(); unsigned hostEnd = url.hostEnd(); - return AlreadyHashed::avoidDeletedValue(WTF::StringHasher::createHash(url.string().characters() + hostStart, hostEnd - hostStart)); + return AlreadyHashed::avoidDeletedValue(StringHasher::computeHash(url.string().characters() + hostStart, hostEnd - hostStart)); } ApplicationCacheGroup* ApplicationCacheStorage::loadCacheGroup(const KURL& manifestURL) @@ -153,6 +156,11 @@ ApplicationCacheGroup* ApplicationCacheStorage::findOrCreateCacheGroup(const KUR return group; } +ApplicationCacheGroup* ApplicationCacheStorage::findInMemoryCacheGroup(const KURL& manifestURL) const +{ + return m_cachesInMemory.get(manifestURL); +} + void ApplicationCacheStorage::loadManifestHostHashes() { static bool hasLoadedHashes = false; @@ -389,7 +397,7 @@ int64_t ApplicationCacheStorage::spaceNeeded(int64_t cacheToSave) if (!getFileSize(m_cacheFile, fileSize)) return 0; - int64_t currentSize = fileSize; + int64_t currentSize = fileSize + flatFileAreaSize(); // Determine the amount of free space we have available. int64_t totalAvailableSize = 0; @@ -555,7 +563,7 @@ bool ApplicationCacheStorage::executeSQLCommand(const String& sql) // Update the schemaVersion when the schema of any the Application Cache // SQLite tables changes. This allows the database to be rebuilt when // a new, incompatible change has been introduced to the database schema. -static const int schemaVersion = 6; +static const int schemaVersion = 7; void ApplicationCacheStorage::verifySchemaVersion() { @@ -563,7 +571,7 @@ void ApplicationCacheStorage::verifySchemaVersion() if (version == schemaVersion) return; - m_database.clearAllTables(); + deleteTables(); // Update user version. SQLiteTransaction setDatabaseVersion(m_database); @@ -613,7 +621,8 @@ void ApplicationCacheStorage::openDatabase(bool createIfDoesNotExist) executeSQLCommand("CREATE TABLE IF NOT EXISTS CacheEntries (cache INTEGER NOT NULL ON CONFLICT FAIL, type INTEGER, resource INTEGER NOT NULL)"); executeSQLCommand("CREATE TABLE IF NOT EXISTS CacheResources (id INTEGER PRIMARY KEY AUTOINCREMENT, url TEXT NOT NULL ON CONFLICT FAIL, " "statusCode INTEGER NOT NULL, responseURL TEXT NOT NULL, mimeType TEXT, textEncodingName TEXT, headers TEXT, data INTEGER NOT NULL ON CONFLICT FAIL)"); - executeSQLCommand("CREATE TABLE IF NOT EXISTS CacheResourceData (id INTEGER PRIMARY KEY AUTOINCREMENT, data BLOB)"); + executeSQLCommand("CREATE TABLE IF NOT EXISTS CacheResourceData (id INTEGER PRIMARY KEY AUTOINCREMENT, data BLOB, path TEXT)"); + executeSQLCommand("CREATE TABLE IF NOT EXISTS DeletedCacheResources (id INTEGER PRIMARY KEY AUTOINCREMENT, path TEXT)"); executeSQLCommand("CREATE TABLE IF NOT EXISTS Origins (origin TEXT UNIQUE ON CONFLICT IGNORE, quota INTEGER NOT NULL ON CONFLICT FAIL)"); // When a cache is deleted, all its entries and its whitelist should be deleted. @@ -636,6 +645,15 @@ void ApplicationCacheStorage::openDatabase(bool createIfDoesNotExist) " FOR EACH ROW BEGIN" " DELETE FROM CacheResourceData WHERE id = OLD.data;" " END"); + + // When a cache resource is deleted, if it contains a non-empty path, that path should + // be added to the DeletedCacheResources table so the flat file at that path can + // be deleted at a later time. + executeSQLCommand("CREATE TRIGGER IF NOT EXISTS CacheResourceDataDeleted AFTER DELETE ON CacheResourceData" + " FOR EACH ROW" + " WHEN OLD.path NOT NULL BEGIN" + " INSERT INTO DeletedCacheResources (path) values (OLD.path);" + " END"); } bool ApplicationCacheStorage::executeStatement(SQLiteStatement& statement) @@ -767,15 +785,43 @@ bool ApplicationCacheStorage::store(ApplicationCacheResource* resource, unsigned return false; // First, insert the data - SQLiteStatement dataStatement(m_database, "INSERT INTO CacheResourceData (data) VALUES (?)"); + SQLiteStatement dataStatement(m_database, "INSERT INTO CacheResourceData (data, path) VALUES (?, ?)"); if (dataStatement.prepare() != SQLResultOk) return false; - if (resource->data()->size()) - dataStatement.bindBlob(1, resource->data()->data(), resource->data()->size()); + + String fullPath; + if (!resource->path().isEmpty()) + dataStatement.bindText(2, pathGetFileName(resource->path())); + 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) { + m_isMaximumSizeReached = true; + return false; + } + + String flatFileDirectory = pathByAppendingComponent(m_cacheDirectory, flatFileSubdirectory); + makeAllDirectories(flatFileDirectory); + String path; + if (!writeDataToUniqueFileInDirectory(resource->data(), flatFileDirectory, path)) + return false; + + fullPath = pathByAppendingComponent(flatFileDirectory, path); + resource->setPath(fullPath); + dataStatement.bindText(2, path); + } else { + if (resource->data()->size()) + dataStatement.bindBlob(1, resource->data()->data(), resource->data()->size()); + } - if (!dataStatement.executeCommand()) + if (!dataStatement.executeCommand()) { + // Clean up the file which we may have written to: + if (!fullPath.isEmpty()) + deleteFile(fullPath); + return false; + } unsigned dataId = static_cast<unsigned>(m_database.lastInsertRowID()); @@ -826,6 +872,12 @@ bool ApplicationCacheStorage::store(ApplicationCacheResource* resource, unsigned if (!executeStatement(entryStatement)) return false; + // Did we successfully write the resource data to a file? If so, + // release the resource's data and free up a potentially large amount + // of memory: + if (!fullPath.isEmpty()) + resource->data()->clear(); + resource->setStorageID(resourceId); return true; } @@ -856,7 +908,7 @@ bool ApplicationCacheStorage::store(ApplicationCacheResource* resource, Applicat return false; m_isMaximumSizeReached = false; - m_database.setMaximumSize(m_maximumSize); + m_database.setMaximumSize(m_maximumSize - flatFileAreaSize()); SQLiteTransaction storeResourceTransaction(m_database); storeResourceTransaction.begin(); @@ -903,7 +955,7 @@ bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup* group, App return false; m_isMaximumSizeReached = false; - m_database.setMaximumSize(m_maximumSize); + m_database.setMaximumSize(m_maximumSize - flatFileAreaSize()); SQLiteTransaction storeCacheTransaction(m_database); @@ -1003,7 +1055,7 @@ static inline void parseHeaders(const String& headers, ResourceResponse& respons PassRefPtr<ApplicationCache> ApplicationCacheStorage::loadCache(unsigned storageID) { SQLiteStatement cacheStatement(m_database, - "SELECT url, type, mimeType, textEncodingName, headers, CacheResourceData.data FROM CacheEntries INNER JOIN CacheResources ON CacheEntries.resource=CacheResources.id " + "SELECT url, 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) { LOG_ERROR("Could not prepare cache statement, error \"%s\"", m_database.lastErrorMsg()); @@ -1013,7 +1065,9 @@ PassRefPtr<ApplicationCache> ApplicationCacheStorage::loadCache(unsigned storage cacheStatement.bindInt64(1, storageID); RefPtr<ApplicationCache> cache = ApplicationCache::create(); - + + String flatFileDirectory = pathByAppendingComponent(m_cacheDirectory, flatFileSubdirectory); + int result; while ((result = cacheStatement.step()) == SQLResultRow) { KURL url(ParsedURLString, cacheStatement.getColumnText(0)); @@ -1025,15 +1079,24 @@ PassRefPtr<ApplicationCache> ApplicationCacheStorage::loadCache(unsigned storage RefPtr<SharedBuffer> data = SharedBuffer::adoptVector(blob); + String path = cacheStatement.getColumnText(6); + long long size = 0; + if (path.isEmpty()) + size = data->size(); + else { + path = pathByAppendingComponent(flatFileDirectory, path); + getFileSize(path, size); + } + String mimeType = cacheStatement.getColumnText(2); String textEncodingName = cacheStatement.getColumnText(3); - ResourceResponse response(url, mimeType, data->size(), textEncodingName, ""); + ResourceResponse response(url, mimeType, size, textEncodingName, ""); String headers = cacheStatement.getColumnText(4); parseHeaders(headers, response); - RefPtr<ApplicationCacheResource> resource = ApplicationCacheResource::create(url, response, type, data.release()); + RefPtr<ApplicationCacheResource> resource = ApplicationCacheResource::create(url, response, type, data.release(), path); if (type & ApplicationCacheResource::Manifest) cache->setManifestResource(resource.release()); @@ -1127,6 +1190,8 @@ void ApplicationCacheStorage::remove(ApplicationCache* cache) cache->group()->clearStorageID(); } + + checkForDeletedResources(); } void ApplicationCacheStorage::empty() @@ -1147,7 +1212,51 @@ void ApplicationCacheStorage::empty() CacheGroupMap::const_iterator end = m_cachesInMemory.end(); for (CacheGroupMap::const_iterator it = m_cachesInMemory.begin(); it != end; ++it) it->second->clearStorageID(); -} + + checkForDeletedResources(); +} + +void ApplicationCacheStorage::deleteTables() +{ + empty(); + m_database.clearAllTables(); +} + +bool ApplicationCacheStorage::shouldStoreResourceAsFlatFile(ApplicationCacheResource* resource) +{ + return resource->response().mimeType().startsWith("audio/", false) + || resource->response().mimeType().startsWith("video/", false); +} + +bool ApplicationCacheStorage::writeDataToUniqueFileInDirectory(SharedBuffer* data, const String& directory, String& path) +{ + String fullPath; + + do { + path = encodeForFileName(createCanonicalUUIDString()); + // Guard against the above function being called on a platform which does not implement + // createCanonicalUUIDString(). + ASSERT(!path.isEmpty()); + if (path.isEmpty()) + return false; + + fullPath = pathByAppendingComponent(directory, path); + } while (directoryName(fullPath) != directory || fileExists(fullPath)); + + PlatformFileHandle handle = openFile(fullPath, OpenForWrite); + if (!handle) + return false; + + int64_t writtenBytes = writeToFile(handle, data->data(), data->size()); + closeFile(handle); + + if (writtenBytes != static_cast<int64_t>(data->size())) { + deleteFile(fullPath); + return false; + } + + return true; +} bool ApplicationCacheStorage::storeCopyOfCache(const String& cacheDirectory, ApplicationCacheHost* cacheHost) { @@ -1166,7 +1275,7 @@ bool ApplicationCacheStorage::storeCopyOfCache(const String& cacheDirectory, App for (ApplicationCache::ResourceMap::const_iterator it = cache->begin(); it != end; ++it) { ApplicationCacheResource* resource = it->second.get(); - RefPtr<ApplicationCacheResource> resourceCopy = ApplicationCacheResource::create(resource->url(), resource->response(), resource->type(), resource->data()); + RefPtr<ApplicationCacheResource> resourceCopy = ApplicationCacheResource::create(resource->url(), resource->response(), resource->type(), resource->data(), resource->path()); cacheCopy->addResource(resourceCopy.release()); } @@ -1274,6 +1383,9 @@ bool ApplicationCacheStorage::deleteCacheGroup(const String& manifestURL) } deleteTransaction.commit(); + + checkForDeletedResources(); + return true; } @@ -1291,25 +1403,73 @@ void ApplicationCacheStorage::checkForMaxSizeReached() if (m_database.lastError() == SQLResultFull) m_isMaximumSizeReached = true; } - -void ApplicationCacheStorage::getOriginsWithCache(HashSet<RefPtr<SecurityOrigin>, SecurityOriginHash>& origins) + +void ApplicationCacheStorage::checkForDeletedResources() { - Vector<KURL> urls; - if (!manifestURLs(&urls)) { - LOG_ERROR("Failed to retrieve ApplicationCache manifest URLs"); + openDatabase(false); + if (!m_database.isOpen()) return; + + // Select only the paths in DeletedCacheResources that do not also appear in CacheResourceData: + SQLiteStatement selectPaths(m_database, "SELECT DeletedCacheResources.path " + "FROM DeletedCacheResources " + "LEFT JOIN CacheResourceData " + "ON DeletedCacheResources.path = CacheResourceData.path " + "WHERE (SELECT DeletedCacheResources.path == CacheResourceData.path) IS NULL"); + + if (selectPaths.prepare() != SQLResultOk) + return; + + if (selectPaths.step() != SQLResultRow) + return; + + do { + String path = selectPaths.getColumnText(0); + if (path.isEmpty()) + continue; + + String flatFileDirectory = pathByAppendingComponent(m_cacheDirectory, flatFileSubdirectory); + String fullPath = pathByAppendingComponent(flatFileDirectory, path); + + // Don't exit the flatFileDirectory! This should only happen if the "path" entry contains a directory + // component, but protect against it regardless. + if (directoryName(fullPath) != flatFileDirectory) + continue; + + deleteFile(fullPath); + } while (selectPaths.step() == SQLResultRow); + + executeSQLCommand("DELETE FROM DeletedCacheResources"); +} + +long long ApplicationCacheStorage::flatFileAreaSize() +{ + openDatabase(false); + if (!m_database.isOpen()) + return 0; + + SQLiteStatement selectPaths(m_database, "SELECT path FROM CacheResourceData WHERE path NOT NULL"); + + if (selectPaths.prepare() != SQLResultOk) { + LOG_ERROR("Could not load flat file cache resource data, error \"%s\"", m_database.lastErrorMsg()); + return 0; } - // 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); + long long totalSize = 0; + String flatFileDirectory = pathByAppendingComponent(m_cacheDirectory, flatFileSubdirectory); + while (selectPaths.step() == SQLResultRow) { + String path = selectPaths.getColumnText(0); + String fullPath = pathByAppendingComponent(flatFileDirectory, path); + long long pathSize = 0; + if (!getFileSize(fullPath, pathSize)) + continue; + totalSize += pathSize; } + + return totalSize; } -void ApplicationCacheStorage::deleteEntriesForOrigin(SecurityOrigin* origin) +void ApplicationCacheStorage::getOriginsWithCache(HashSet<RefPtr<SecurityOrigin>, SecurityOriginHash>& origins) { Vector<KURL> urls; if (!manifestURLs(&urls)) { @@ -1318,12 +1478,11 @@ void ApplicationCacheStorage::deleteEntriesForOrigin(SecurityOrigin* origin) } // 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 deleting by origin. + // 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> manifestOrigin = SecurityOrigin::create(urls[i]); - if (manifestOrigin->isSameSchemeHostPort(origin)) - deleteCacheGroup(urls[i]); + RefPtr<SecurityOrigin> origin = SecurityOrigin::create(urls[i]); + origins.add(origin); } } diff --git a/Source/WebCore/loader/appcache/ApplicationCacheStorage.h b/Source/WebCore/loader/appcache/ApplicationCacheStorage.h index f283670..3136b52 100644 --- a/Source/WebCore/loader/appcache/ApplicationCacheStorage.h +++ b/Source/WebCore/loader/appcache/ApplicationCacheStorage.h @@ -74,6 +74,7 @@ public: ApplicationCacheGroup* fallbackCacheGroupForURL(const KURL&); // Cache that has a fallback entry to load a main resource from if normal loading fails. ApplicationCacheGroup* findOrCreateCacheGroup(const KURL& manifestURL); + ApplicationCacheGroup* findInMemoryCacheGroup(const KURL& manifestURL) const; void cacheGroupDestroyed(ApplicationCacheGroup*); void cacheGroupMadeObsolete(ApplicationCacheGroup*); @@ -95,7 +96,6 @@ public: void vacuumDatabaseFile(); void getOriginsWithCache(HashSet<RefPtr<SecurityOrigin>, SecurityOriginHash>&); - void deleteEntriesForOrigin(SecurityOrigin*); void deleteAllEntries(); static int64_t unknownQuota() { return -1; } @@ -113,6 +113,9 @@ private: bool store(ApplicationCacheResource*, unsigned cacheStorageID); bool ensureOriginRecord(const SecurityOrigin*); + bool shouldStoreResourceAsFlatFile(ApplicationCacheResource*); + void deleteTables(); + bool writeDataToUniqueFileInDirectory(SharedBuffer*, const String& directory, String& outFilename); void loadManifestHostHashes(); @@ -124,6 +127,8 @@ private: bool executeSQLCommand(const String&); void checkForMaxSizeReached(); + void checkForDeletedResources(); + long long flatFileAreaSize(); String m_cacheDirectory; String m_cacheFile; |