⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 applicationcachestorage.cpp

📁 linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自WebKit
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  */#include "config.h"#include "ApplicationCacheStorage.h"#if ENABLE(OFFLINE_WEB_APPLICATIONS)#include "ApplicationCache.h"#include "ApplicationCacheGroup.h"#include "ApplicationCacheResource.h"#include "CString.h"#include "FileSystem.h"#include "KURL.h"#include "SQLiteStatement.h"#include "SQLiteTransaction.h"#include <wtf/StdLibExtras.h>#include <wtf/StringExtras.h>using namespace std;namespace WebCore {static unsigned urlHostHash(const KURL& url){    unsigned hostStart = url.hostStart();    unsigned hostEnd = url.hostEnd();        return AlreadyHashed::avoidDeletedValue(StringImpl::computeHash(url.string().characters() + hostStart, hostEnd - hostStart));}ApplicationCacheGroup* ApplicationCacheStorage::loadCacheGroup(const KURL& manifestURL){    openDatabase(false);    if (!m_database.isOpen())        return 0;    SQLiteStatement statement(m_database, "SELECT id, manifestURL, newestCache FROM CacheGroups WHERE newestCache IS NOT NULL AND manifestURL=?");    if (statement.prepare() != SQLResultOk)        return 0;        statement.bindText(1, manifestURL);       int result = statement.step();    if (result == SQLResultDone)        return 0;        if (result != SQLResultRow) {        LOG_ERROR("Could not load cache group, error \"%s\"", m_database.lastErrorMsg());        return 0;    }        unsigned newestCacheStorageID = static_cast<unsigned>(statement.getColumnInt64(2));    RefPtr<ApplicationCache> cache = loadCache(newestCacheStorageID);    if (!cache)        return 0;            ApplicationCacheGroup* group = new ApplicationCacheGroup(manifestURL);          group->setStorageID(static_cast<unsigned>(statement.getColumnInt64(0)));    group->setNewestCache(cache.release());    return group;}    ApplicationCacheGroup* ApplicationCacheStorage::findOrCreateCacheGroup(const KURL& manifestURL){    std::pair<CacheGroupMap::iterator, bool> result = m_cachesInMemory.add(manifestURL, 0);        if (!result.second) {        ASSERT(result.first->second);                return result.first->second;    }    // Look up the group in the database    ApplicationCacheGroup* group = loadCacheGroup(manifestURL);        // If the group was not found we need to create it    if (!group) {        group = new ApplicationCacheGroup(manifestURL);        m_cacheHostSet.add(urlHostHash(manifestURL));    }        result.first->second = group;        return group;}void ApplicationCacheStorage::loadManifestHostHashes(){    static bool hasLoadedHashes = false;        if (hasLoadedHashes)        return;        // We set this flag to true before the database has been opened    // to avoid trying to open the database over and over if it doesn't exist.    hasLoadedHashes = true;        openDatabase(false);    if (!m_database.isOpen())        return;    // Fetch the host hashes.    SQLiteStatement statement(m_database, "SELECT manifestHostHash FROM CacheGroups");        if (statement.prepare() != SQLResultOk)        return;        int result;    while ((result = statement.step()) == SQLResultRow)        m_cacheHostSet.add(static_cast<unsigned>(statement.getColumnInt64(0)));}    ApplicationCacheGroup* ApplicationCacheStorage::cacheGroupForURL(const KURL& url){    loadManifestHostHashes();        // Hash the host name and see if there's a manifest with the same host.    if (!m_cacheHostSet.contains(urlHostHash(url)))        return 0;    // Check if a 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->second;        ASSERT(!group->isObsolete());        if (!protocolHostAndPortAreEqual(url, group->manifestURL()))            continue;                if (ApplicationCache* cache = group->newestCache()) {            ApplicationCacheResource* resource = cache->resourceForURL(url);            if (!resource)                continue;            if (resource->type() & ApplicationCacheResource::Foreign)                continue;            return group;        }    }        if (!m_database.isOpen())        return 0;            // 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;        int result;    while ((result = statement.step()) == SQLResultRow) {        KURL manifestURL = KURL(statement.getColumnText(1));        if (m_cachesInMemory.contains(manifestURL))            continue;        if (!protocolHostAndPortAreEqual(url, manifestURL))            continue;        // 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);        ApplicationCacheResource* 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;    }    if (result != SQLResultDone)        LOG_ERROR("Could not load cache group, error \"%s\"", m_database.lastErrorMsg());        return 0;}ApplicationCacheGroup* ApplicationCacheStorage::fallbackCacheGroupForURL(const KURL& url){    // 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->second;                ASSERT(!group->isObsolete());        if (ApplicationCache* cache = group->newestCache()) {            KURL fallbackURL;            if (!cache->urlMatchesFallbackNamespace(url, &fallbackURL))                continue;            if (cache->resourceForURL(fallbackURL)->type() & ApplicationCacheResource::Foreign)                continue;            return group;        }    }        if (!m_database.isOpen())        return 0;            // 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;        int result;    while ((result = statement.step()) == SQLResultRow) {        KURL manifestURL = KURL(statement.getColumnText(1));        if (m_cachesInMemory.contains(manifestURL))            continue;        // Fallback namespaces always have the same origin as manifest URL, so we can avoid loading caches that cannot match.        if (!protocolHostAndPortAreEqual(url, manifestURL))            continue;        // 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);        KURL fallbackURL;        if (!cache->urlMatchesFallbackNamespace(url, &fallbackURL))            continue;        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;    }    if (result != SQLResultDone)        LOG_ERROR("Could not load cache group, error \"%s\"", m_database.lastErrorMsg());        return 0;}void ApplicationCacheStorage::cacheGroupDestroyed(ApplicationCacheGroup* group){    if (group->isObsolete()) {        ASSERT(!group->storageID());        ASSERT(m_cachesInMemory.get(group->manifestURL()) != group);        return;    }    ASSERT(m_cachesInMemory.get(group->manifestURL()) == group);    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()));}void ApplicationCacheStorage::cacheGroupMadeObsolete(ApplicationCacheGroup* group){    ASSERT(m_cachesInMemory.get(group->manifestURL()) == group);    ASSERT(m_cacheHostSet.contains(urlHostHash(group->manifestURL())));    if (ApplicationCache* 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;}const String& ApplicationCacheStorage::cacheDirectory() const{    return m_cacheDirectory;}bool ApplicationCacheStorage::executeSQLCommand(const String& sql){    ASSERT(m_database.isOpen());        bool result = m_database.executeCommand(sql);    if (!result)        LOG_ERROR("Application Cache Storage: failed to execute statement \"%s\" error \"%s\"",                   sql.utf8().data(), m_database.lastErrorMsg());    return result;}static const int schemaVersion = 3;    void ApplicationCacheStorage::verifySchemaVersion(){    int version = SQLiteStatement(m_database, "PRAGMA user_version").getColumnInt(0);    if (version == schemaVersion)        return;    m_database.clearAllTables();    // Update user version.    SQLiteTransaction setDatabaseVersion(m_database);    setDatabaseVersion.begin();    char userVersionSQL[32];    int unusedNumBytes = snprintf(userVersionSQL, sizeof(userVersionSQL), "PRAGMA user_version=%d", schemaVersion);    ASSERT_UNUSED(unusedNumBytes, static_cast<int>(sizeof(userVersionSQL)) >= unusedNumBytes);    SQLiteStatement statement(m_database, userVersionSQL);    if (statement.prepare() != SQLResultOk)        return;        executeStatement(statement);    setDatabaseVersion.commit();}    void ApplicationCacheStorage::openDatabase(bool createIfDoesNotExist){    if (m_database.isOpen())        return;    // The cache directory should never be null, but if it for some weird reason is we bail out.    if (m_cacheDirectory.isNull())        return;        String applicationCachePath = pathByAppendingComponent(m_cacheDirectory, "ApplicationCache.db");    if (!createIfDoesNotExist && !fileExists(applicationCachePath))        return;    makeAllDirectories(m_cacheDirectory);    m_database.open(applicationCachePath);        if (!m_database.isOpen())        return;        verifySchemaVersion();        // Create tables    executeSQLCommand("CREATE TABLE IF NOT EXISTS CacheGroups (id INTEGER PRIMARY KEY AUTOINCREMENT, "                      "manifestHostHash INTEGER NOT NULL ON CONFLICT FAIL, manifestURL TEXT UNIQUE ON CONFLICT FAIL, newestCache INTEGER)");    executeSQLCommand("CREATE TABLE IF NOT EXISTS Caches (id INTEGER PRIMARY KEY AUTOINCREMENT, cacheGroup INTEGER)");    executeSQLCommand("CREATE TABLE IF NOT EXISTS CacheWhitelistURLs (url TEXT NOT NULL ON CONFLICT FAIL, cache INTEGER NOT NULL ON CONFLICT FAIL)");    executeSQLCommand("CREATE TABLE IF NOT EXISTS FallbackURLs (namespace TEXT NOT NULL ON CONFLICT FAIL, fallbackURL TEXT NOT NULL ON CONFLICT FAIL, "                      "cache INTEGER NOT NULL ON CONFLICT FAIL)");    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)");    // When a cache is deleted, all its entries and its whitelist should be deleted.    executeSQLCommand("CREATE TRIGGER IF NOT EXISTS CacheDeleted AFTER DELETE ON Caches"                      " FOR EACH ROW BEGIN"                      "  DELETE FROM CacheEntries WHERE cache = OLD.id;"                      "  DELETE FROM CacheWhitelistURLs WHERE cache = OLD.id;"                      "  DELETE FROM FallbackURLs WHERE cache = OLD.id;"                      " END");    // When a cache entry is deleted, its resource should also be deleted.    executeSQLCommand("CREATE TRIGGER IF NOT EXISTS CacheEntryDeleted AFTER DELETE ON CacheEntries"                      " FOR EACH ROW BEGIN"                      "  DELETE FROM CacheResources WHERE id = OLD.resource;"                      " END");    // When a cache resource is deleted, its data blob should also be deleted.    executeSQLCommand("CREATE TRIGGER IF NOT EXISTS CacheResourceDeleted AFTER DELETE ON CacheResources"                      " FOR EACH ROW BEGIN"                      "  DELETE FROM CacheResourceData WHERE id = OLD.data;"                      " END");}bool ApplicationCacheStorage::executeStatement(SQLiteStatement& statement){    bool result = statement.executeCommand();    if (!result)        LOG_ERROR("Application Cache Storage: failed to execute statement \"%s\" error \"%s\"",                   statement.query().utf8().data(), m_database.lastErrorMsg());        return result;}    bool ApplicationCacheStorage::store(ApplicationCacheGroup* group){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -