bool ApplicationCacheHost::shouldLoadResourceFromApplicationCache(const ResourceRequest& originalRequest, ApplicationCacheResource*& resource)
{
    ApplicationCache* cache = applicationCache();
    if (!cache || !cache->isComplete())
        return false;

    ResourceRequest request(originalRequest);
    if (Frame* loaderFrame = m_documentLoader.frame()) {
        if (Document* 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) || !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
    // in the application cache, then get the resource from the cache (instead of fetching it).
    resource = cache->resourceForURL(request.url());

    // Resources that match fallback namespaces or online whitelist entries are fetched from the network,
    // unless they are also cached.
    if (!resource && (cache->allowsAllNetworkRequests() || cache->urlMatchesFallbackNamespace(request.url()) || cache->isURLInOnlineWhitelist(request.url())))
        return false;

    // Resources that are not present in the manifest will always fail to load (at least, after the
    // cache has been primed the first time), making the testing of offline applications simpler.
    return true;
}
unsigned DOMApplicationCache::length() const
{
    ApplicationCache* cache = associatedCache();
    if (!cache)
        return 0;
    
    return cache->numDynamicEntries();
}
bool ApplicationCacheHost::update()
{
    ApplicationCache* cache = applicationCache();
    if (!cache)
        return false;
    cache->group()->update(m_documentLoader->frame(), ApplicationCacheUpdateWithoutBrowsingContext);
    return true;
}
ApplicationCacheHost::CacheInfo ApplicationCacheHost::applicationCacheInfo()
{
    ApplicationCache* cache = applicationCache();
    if (!cache || !cache->isComplete())
        return CacheInfo(URL(), 0, 0, 0);
  
    // FIXME: Add "Creation Time" and "Update Time" to Application Caches.
    return CacheInfo(cache->manifestResource()->url(), 0, 0, cache->estimatedSizeInStorage());
}
void DOMApplicationCache::remove(const KURL& url, ExceptionCode& ec)
{
    ApplicationCache* cache = associatedCache();
    if (!cache) {
        ec = INVALID_STATE_ERR;
        return;
    }
    
    cache->removeDynamicEntry(url);
}
void DOMApplicationCache::update(ExceptionCode& ec)
{
    ApplicationCache* cache = associatedCache();
    if (!cache) {
        ec = INVALID_STATE_ERR;
        return;
    }
    
    cache->group()->update(m_frame);
}
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());
    }
}
String DOMApplicationCache::item(unsigned item, ExceptionCode& ec)
{
    ApplicationCache* cache = associatedCache();
    if (!cache) {
        ec = INVALID_STATE_ERR;
        return String();
    }

    if (item >= length()) {
        ec = INDEX_SIZE_ERR;
        return String();
    }
    
    return cache->dynamicEntry(item);
}
Beispiel #9
0
void ApplicationCacheGroup::selectCacheWithoutManifestURL(Frame* frame)
{
    if (!frame->settings()->offlineWebApplicationCacheEnabled())
        return;

    DocumentLoader* documentLoader = frame->loader()->documentLoader();
    ASSERT(!documentLoader->applicationCache());

    ApplicationCache* mainResourceCache = documentLoader->mainResourceApplicationCache();

    if (mainResourceCache) {
        mainResourceCache->group()->associateDocumentLoaderWithCache(documentLoader, mainResourceCache);
        mainResourceCache->group()->update(frame);
    }
}
void ApplicationCacheHost::fillResourceList(ResourceInfoList* resources)
{
    ApplicationCache* 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;
        bool isManifest = type & ApplicationCacheResource::Manifest;
        bool isExplicit = type & ApplicationCacheResource::Explicit;
        bool isForeign  = type & ApplicationCacheResource::Foreign;
        bool isFallback = type & ApplicationCacheResource::Fallback;
        resources->append(ResourceInfo(resource->url(), isMaster, isManifest, isFallback, isForeign, isExplicit, resource->estimatedSizeInStorage()));
    }
}
void ApplicationCacheHost::fillResourceList(ResourceInfoList* resources)
{
    ApplicationCache* cache = applicationCache();
    if (!cache || !cache->isComplete())
        return;
     
    ApplicationCache::ResourceMap::const_iterator end = cache->end();
    for (ApplicationCache::ResourceMap::const_iterator it = cache->begin(); it != end; ++it) {
        RefPtr<ApplicationCacheResource> resource = it->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 isFallback = type & ApplicationCacheResource::Fallback;
        resources->append(ResourceInfo(resource->url(), isMaster, isManifest, isFallback, isForeign, isExplicit, resource->estimatedSizeInStorage()));
    }
}
void DOMApplicationCache::add(const KURL& url, ExceptionCode& ec)
{
    ApplicationCache* cache = associatedCache();
    if (!cache) {
        ec = INVALID_STATE_ERR;
        return;
    }
 
    if (!url.isValid()) {
        ec = SYNTAX_ERR;
        return;
    }
        
    if (!cache->addDynamicEntry(url)) {
        // This should use the (currently not specified) security exceptions in HTML5 4.3.4
        ec = SECURITY_ERR;
    }
}
void ApplicationCacheGroup::selectCacheWithoutManifestURL(Frame* frame)
{
    if (!frame->settings().offlineWebApplicationCacheEnabled())
        return;

    if (!frame->document()->securityOrigin()->canAccessApplicationCache(frame->tree().top().document()->securityOrigin()))
        return;

    DocumentLoader* documentLoader = frame->loader().documentLoader();
    ASSERT(!documentLoader->applicationCacheHost()->applicationCache());

    ApplicationCache* mainResourceCache = documentLoader->applicationCacheHost()->mainResourceApplicationCache();

    if (mainResourceCache) {
        mainResourceCache->group()->associateDocumentLoaderWithCache(documentLoader, mainResourceCache);
        mainResourceCache->group()->update(frame, ApplicationCacheUpdateWithBrowsingContext);
    }
}
bool DOMApplicationCache::swapCache()
{
    if (!m_frame)
        return false;
    
    ApplicationCache* cache = m_frame->loader()->documentLoader()->applicationCache();
    if (!cache)
        return false;
    
    // Check if we already have the newest cache
    ApplicationCache* newestCache = cache->group()->newestCache();
    if (cache == newestCache)
        return false;
    
    ASSERT(cache->group() == newestCache->group());
    m_frame->loader()->documentLoader()->setApplicationCache(newestCache);
    
    return true;
}
Beispiel #15
0
bool DocumentLoader::shouldLoadResourceFromApplicationCache(const ResourceRequest& request, ApplicationCacheResource*& resource)
{
    ApplicationCache* cache = topLevelApplicationCache();    
    if (!cache)
        return false;
    
    // If the resource is not a HTTP/HTTPS GET, then abort
    if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request))
        return false;
    
    if (cache->isURLInOnlineWhitelist(request.url()))
        return false;
    
    resource = cache->resourceForURL(request.url());
    
    // Don't load foreign resources.
    if (resource && (resource->type() & ApplicationCacheResource::Foreign))
        resource = 0;
    
    return true;
}
bool ApplicationCacheStorage::storeCopyOfCache(const String& cacheDirectory, ApplicationCacheHost* cacheHost)
{
    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->second.get();
        
        RefPtr<ApplicationCacheResource> resourceCopy = ApplicationCacheResource::create(resource->url(), resource->response(), resource->type(), resource->data());
        
        cacheCopy->addResource(resourceCopy.release());
    }
    
    // Now create a new cache group.
    OwnPtr<ApplicationCacheGroup> groupCopy(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());
}
Beispiel #17
0
void ApplicationCacheGroup::selectCacheWithoutManifestURL(Frame* frame)
{
    if (!frame->settings().offlineWebApplicationCacheEnabled())
        return;

    DocumentLoader* documentLoader = frame->loader().documentLoader();
    ASSERT(!documentLoader->applicationCacheHost()->applicationCache());

    // 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;
    }

    ApplicationCache* mainResourceCache = documentLoader->applicationCacheHost()->mainResourceApplicationCache();

    if (mainResourceCache) {
        mainResourceCache->group()->associateDocumentLoaderWithCache(documentLoader, mainResourceCache);
        mainResourceCache->group()->update(frame, ApplicationCacheUpdateWithBrowsingContext);
    }
}
ApplicationCacheHost::Status ApplicationCacheHost::status() const
{
    ApplicationCache* 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;
        }
    }

    ASSERT_NOT_REACHED();
    return UNCACHED;
}
Beispiel #19
0
bool DocumentLoader::shouldLoadResourceFromApplicationCache(const ResourceRequest& request, ApplicationCacheResource*& resource)
{
    ApplicationCache* cache = applicationCache();
    if (!cache)
        return false;

    // If the resource is not a HTTP/HTTPS GET, then abort
    if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request))
        return false;

    // If the resource's URL is an master entry, the manifest, an explicit entry, a fallback entry, or a dynamic entry
    // in the application cache, then get the resource from the cache (instead of fetching it).
    resource = cache->resourceForURL(request.url());

    // Resources that match fallback namespaces or online whitelist entries are fetched from the network,
    // unless they are also cached.
    if (!resource && (cache->urlMatchesFallbackNamespace(request.url()) || cache->isURLInOnlineWhitelist(request.url())))
        return false;

    // Resources that are not present in the manifest will always fail to load (at least, after the
    // cache has been primed the first time), making the testing of offline applications simpler.
    return true;
}
unsigned short DOMApplicationCache::status() const
{
    ApplicationCache* cache = associatedCache();    
    if (!cache)
        return UNCACHED;
    
    switch (cache->group()->status()) {
        case ApplicationCacheGroup::Checking:
            return CHECKING;
        case ApplicationCacheGroup::Downloading:
            return DOWNLOADING;
        case ApplicationCacheGroup::Idle: {
            if (cache != cache->group()->newestCache())
                return UPDATEREADY;
            
            return IDLE;
        }
        default:
            ASSERT_NOT_REACHED();
    }
    
    return 0;
}
bool ApplicationCacheHost::swapCache()
{
    ApplicationCache* cache = applicationCache();
    if (!cache)
        return false;

    // If the group of application caches to which cache belongs has the lifecycle status obsolete, unassociate document from cache.
    if (cache->group()->isObsolete()) {
        cache->group()->disassociateDocumentLoader(m_documentLoader);
        return true;
    }

    // If there is no newer cache, raise an INVALID_STATE_ERR exception.
    ApplicationCache* newestCache = cache->group()->newestCache();
    if (cache == newestCache)
        return false;
    
    ASSERT(cache->group() == newestCache->group());
    setApplicationCache(newestCache);
    InspectorInstrumentation::updateApplicationCacheStatus(m_documentLoader->frame());
    return true;
}
Beispiel #22
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);
}
Beispiel #23
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);                
    }               
}