Пример #1
0
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;
}    
Пример #2
0
void MainResourceLoader::didFinishLoading()
{
    // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred.
    // See <rdar://problem/6304600> for more details.
#if !PLATFORM(CF)
    ASSERT(shouldLoadAsEmptyDocument(frameLoader()->activeDocumentLoader()->url()) || !defersLoading());
#endif
    
    // The additional processing can do anything including possibly removing the last
    // reference to this object.
    RefPtr<MainResourceLoader> protect(this);

#if ENABLE(OFFLINE_WEB_APPLICATIONS)
    RefPtr<DocumentLoader> dl = documentLoader();
#endif

    frameLoader()->finishedLoading();
    ResourceLoader::didFinishLoading();
    
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
    ApplicationCacheGroup* group = dl->candidateApplicationCacheGroup();
    if (!group && dl->applicationCache() && !dl->mainResourceApplicationCache())
        group = dl->applicationCache()->group();
    
    if (group)
        group->finishedLoadingMainResource(dl.get());
#endif
}
Пример #3
0
void ApplicationCacheHost::finishedLoadingMainResource()
{
    ApplicationCacheGroup* group = candidateApplicationCacheGroup();
    if (!group && applicationCache() && !mainResourceApplicationCache())
        group = applicationCache()->group();
    
    if (group)
        group->finishedLoadingMainResource(m_documentLoader);
}
Пример #4
0
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());
    }
}
Пример #5
0
void ApplicationCacheHost::failedLoadingMainResource()
{
    ApplicationCacheGroup* group = m_candidateApplicationCacheGroup;
    if (!group && m_applicationCache) {
        ASSERT(!mainResourceApplicationCache()); // If the main resource were loaded from a cache, it wouldn't fail.
        group = m_applicationCache->group();
    }
    
    if (group)
        group->failedLoadingMainResource(m_documentLoader);
}
Пример #6
0
void ApplicationCacheHost::failedLoadingMainResource()
{
    ApplicationCacheGroup* 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.
            return;
        }
        group = m_applicationCache->group();
    }
    
    if (group)
        group->failedLoadingMainResource(m_documentLoader);
}
Пример #7
0
void DocumentLoader::mainReceivedError(const ResourceError& error, bool isComplete)
{
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
    ApplicationCacheGroup* group = m_candidateApplicationCacheGroup;
    if (!group && m_applicationCache && !mainResourceApplicationCache())
        group = m_applicationCache->group();
    
    if (group)
        group->failedLoadingMainResource(this);
#endif
    
    if (!frameLoader())
        return;
    setMainDocumentError(error);
    if (isComplete)
        frameLoader()->mainReceivedCompleteError(this, error);
}
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]);
        }
    }
}
Пример #9
0
void DocumentLoader::mainReceivedError(const ResourceError& error, bool isComplete)
{
    ASSERT(!error.isNull());

#if ENABLE(OFFLINE_WEB_APPLICATIONS)
    ApplicationCacheGroup* group = m_candidateApplicationCacheGroup;
    if (!group && m_applicationCache) {
        ASSERT(!mainResourceApplicationCache()); // If the main resource were loaded from a cache, it wouldn't fail.
        group = m_applicationCache->group();
    }
    
    if (group)
        group->failedLoadingMainResource(this);
#endif
    
    if (!frameLoader())
        return;
    setMainDocumentError(error);
    if (isComplete)
        frameLoader()->mainReceivedCompleteError(this, error);
}
Пример #10
0
void ApplicationCacheGroup::selectCache(Frame* frame, const KURL& manifestURL)
{
    ASSERT(frame && frame->page());
    
    if (!frame->settings()->offlineWebApplicationCacheEnabled())
        return;
    
    DocumentLoader* documentLoader = frame->loader()->documentLoader();
    ASSERT(!documentLoader->applicationCache());

    if (manifestURL.isNull()) {
        selectCacheWithoutManifestURL(frame);        
        return;
    }
    
    ApplicationCache* mainResourceCache = documentLoader->mainResourceApplicationCache();
    
    if (mainResourceCache) {
        if (manifestURL == mainResourceCache->group()->m_manifestURL) {
            mainResourceCache->group()->associateDocumentLoaderWithCache(documentLoader, mainResourceCache);
            mainResourceCache->group()->update(frame);
        } else {
            // The main resource was loaded from cache, so the cache must have an entry for it. Mark it as foreign.
            ApplicationCacheResource* resource = mainResourceCache->resourceForURL(documentLoader->url());
            bool inStorage = resource->storageID();
            resource->addType(ApplicationCacheResource::Foreign);
            if (inStorage)
                cacheStorage().storeUpdatedType(resource, mainResourceCache);

            // Restart the current navigation from the top of the navigation algorithm, undoing any changes that were made
            // as part of the initial load.
            // The navigation will not result in the same resource being loaded, because "foreign" entries are never picked during navigation.
            frame->loader()->scheduleLocationChange(documentLoader->url(), frame->loader()->referrer(), true);
        }
        
        return;
    }
    
    // The resource was loaded from the network, check if it is a HTTP/HTTPS GET.    
    const ResourceRequest& request = frame->loader()->activeDocumentLoader()->request();

    if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request)) {
        selectCacheWithoutManifestURL(frame);
        return;
    }

    // Check that the resource URL has the same scheme/host/port as the manifest URL.
    if (!protocolHostAndPortAreEqual(manifestURL, request.url())) {
        selectCacheWithoutManifestURL(frame);
        return;
    }
            
    ApplicationCacheGroup* group = cacheStorage().findOrCreateCacheGroup(manifestURL);
            
    if (ApplicationCache* cache = group->newestCache()) {
        ASSERT(cache->manifestResource());
                
        group->associateDocumentLoaderWithCache(frame->loader()->documentLoader(), cache);
              
        if (!frame->loader()->documentLoader()->isLoadingMainResource())
            group->finishedLoadingMainResource(frame->loader()->documentLoader());

        group->update(frame);
    } else {
        bool isUpdating = group->m_cacheBeingUpdated;
                
        if (!isUpdating)
            group->m_cacheBeingUpdated = ApplicationCache::create();
        documentLoader->setCandidateApplicationCacheGroup(group);
        group->m_cacheCandidates.add(documentLoader);

        const KURL& url = frame->loader()->documentLoader()->originalURL();
                
        unsigned type = 0;

        // If the resource has already been downloaded, remove it so that it will be replaced with the implicit resource
        if (isUpdating)
            type = group->m_cacheBeingUpdated->removeResource(url);
               
        // Add the main resource URL as an implicit entry.
        group->addEntry(url, type | ApplicationCacheResource::Implicit);

        if (!frame->loader()->documentLoader()->isLoadingMainResource())
            group->finishedLoadingMainResource(frame->loader()->documentLoader());
                
        if (!isUpdating)
            group->update(frame);                
    }               
}
Пример #11
0
ApplicationCacheGroup* ApplicationCacheStorage::fallbackCacheGroupForURL(const KURL& url)
{
    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->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(ParsedURLString, 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;
}
Пример #12
0
ApplicationCacheGroup* ApplicationCacheStorage::cacheGroupForURL(const KURL& url)
{
    ASSERT(!url.hasFragmentIdentifier());
    
    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(ParsedURLString, 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);
        if (!cache)
            continue;

        ApplicationCacheResource* resource = cache->resourceForURL(url);
        if (!resource)
            continue;
        if (resource->type() & ApplicationCacheResource::Foreign)
            continue;

#if OS(OLYMPIA)
        ApplicationCacheGroup* group = new ApplicationCacheGroup(this, manifestURL);
#else
        ApplicationCacheGroup* group = new ApplicationCacheGroup(manifestURL);
#endif
        
        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;
}
Пример #13
0
void ApplicationCacheGroup::selectCache(Frame* frame, const URL& passedManifestURL)
{
    ASSERT(frame && frame->page());
    
    if (!frame->settings().offlineWebApplicationCacheEnabled())
        return;
    
    DocumentLoader* documentLoader = frame->loader().documentLoader();
    ASSERT(!documentLoader->applicationCacheHost()->applicationCache());

    if (passedManifestURL.isNull()) {
        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(ApplicationCacheHost::CHECKING_EVENT, documentLoader);
        postListenerTask(ApplicationCacheHost::ERROR_EVENT, documentLoader);
        return;
    }

    URL manifestURL(passedManifestURL);
    if (manifestURL.hasFragmentIdentifier())
        manifestURL.removeFragmentIdentifier();

    ApplicationCache* mainResourceCache = documentLoader->applicationCacheHost()->mainResourceApplicationCache();
    
    if (mainResourceCache) {
        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()->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);
            if (inStorage)
                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(), 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();

    if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request))
        return;

    // Check that the resource URL has the same scheme/host/port as the manifest URL.
    if (!protocolHostAndPortAreEqual(manifestURL, request.url()))
        return;

    ApplicationCacheGroup* group = frame->page()->applicationCacheStorage().findOrCreateCacheGroup(manifestURL);

    documentLoader->applicationCacheHost()->setCandidateApplicationCacheGroup(group);
    group->m_pendingMasterResourceLoaders.add(documentLoader);
    group->m_downloadingPendingMasterResourceLoadersCount++;

    ASSERT(!group->m_cacheBeingUpdated || group->m_updateStatus != Idle);
    group->update(frame, ApplicationCacheUpdateWithBrowsingContext);
}