diff options
Diffstat (limited to 'WebCore/loader/appcache')
-rw-r--r-- | WebCore/loader/appcache/ApplicationCache.cpp | 6 | ||||
-rw-r--r-- | WebCore/loader/appcache/ApplicationCacheGroup.cpp | 136 | ||||
-rw-r--r-- | WebCore/loader/appcache/ApplicationCacheGroup.h | 8 | ||||
-rw-r--r-- | WebCore/loader/appcache/ApplicationCacheResource.cpp | 4 | ||||
-rw-r--r-- | WebCore/loader/appcache/ApplicationCacheResource.h | 2 | ||||
-rw-r--r-- | WebCore/loader/appcache/DOMApplicationCache.cpp | 47 | ||||
-rw-r--r-- | WebCore/loader/appcache/DOMApplicationCache.h | 10 | ||||
-rw-r--r-- | WebCore/loader/appcache/ManifestParser.cpp | 9 |
8 files changed, 165 insertions, 57 deletions
diff --git a/WebCore/loader/appcache/ApplicationCache.cpp b/WebCore/loader/appcache/ApplicationCache.cpp index abe8b22..e411852 100644 --- a/WebCore/loader/appcache/ApplicationCache.cpp +++ b/WebCore/loader/appcache/ApplicationCache.cpp @@ -81,7 +81,7 @@ void ApplicationCache::addResource(PassRefPtr<ApplicationCacheResource> resource if (m_storageID) { ASSERT(!resource->storageID()); - ASSERT(resource->type() & (ApplicationCacheResource::Dynamic | ApplicationCacheResource::Implicit)); + ASSERT(resource->type() & (ApplicationCacheResource::Dynamic | ApplicationCacheResource::Master)); // Add the resource to the storage. cacheStorage().store(resource.get(), this); @@ -146,13 +146,13 @@ bool ApplicationCache::addDynamicEntry(const String& url) if (!equalIgnoringCase(m_group->manifestURL().protocol(), KURL(url).protocol())) return false; - // FIXME: Implement + // FIXME: Implement (be sure to respect private browsing state). return true; } void ApplicationCache::removeDynamicEntry(const String&) { - // FIXME: Implement + // FIXME: Implement (be sure to respect private browsing state). } void ApplicationCache::setOnlineWhitelist(const Vector<KURL>& onlineWhitelist) diff --git a/WebCore/loader/appcache/ApplicationCacheGroup.cpp b/WebCore/loader/appcache/ApplicationCacheGroup.cpp index 2367e79..1b16b50 100644 --- a/WebCore/loader/appcache/ApplicationCacheGroup.cpp +++ b/WebCore/loader/appcache/ApplicationCacheGroup.cpp @@ -154,7 +154,14 @@ void ApplicationCacheGroup::selectCache(Frame* frame, const KURL& manifestURL) // Check that the resource URL has the same scheme/host/port as the manifest URL. if (!protocolHostAndPortAreEqual(manifestURL, request.url())) return; - + + // Don't change anything on disk if private browsing is enabled. + if (!frame->settings() || frame->settings()->privateBrowsingEnabled()) { + postListenerTask(&DOMApplicationCache::callCheckingListener, documentLoader); + postListenerTask(&DOMApplicationCache::callErrorListener, documentLoader); + return; + } + ApplicationCacheGroup* group = cacheStorage().findOrCreateCacheGroup(manifestURL); documentLoader->setCandidateApplicationCacheGroup(group); @@ -184,7 +191,7 @@ void ApplicationCacheGroup::finishedLoadingMainResource(DocumentLoader* loader) { ASSERT(m_pendingMasterResourceLoaders.contains(loader)); ASSERT(m_completionType == None || m_pendingEntries.isEmpty()); - const KURL& url = loader->originalURL(); + const KURL& url = loader->url(); switch (m_completionType) { case None: @@ -195,12 +202,12 @@ void ApplicationCacheGroup::finishedLoadingMainResource(DocumentLoader* loader) associateDocumentLoaderWithCache(loader, m_newestCache.get()); if (ApplicationCacheResource* resource = m_newestCache->resourceForURL(url)) { - if (!(resource->type() & ApplicationCacheResource::Implicit)) { - resource->addType(ApplicationCacheResource::Implicit); + if (!(resource->type() & ApplicationCacheResource::Master)) { + resource->addType(ApplicationCacheResource::Master); ASSERT(!resource->storageID()); } } else - m_newestCache->addResource(ApplicationCacheResource::create(url, loader->response(), ApplicationCacheResource::Implicit, loader->mainResourceData())); + m_newestCache->addResource(ApplicationCacheResource::create(url, loader->response(), ApplicationCacheResource::Master, loader->mainResourceData())); break; case Failure: @@ -215,12 +222,12 @@ void ApplicationCacheGroup::finishedLoadingMainResource(DocumentLoader* loader) ASSERT(m_associatedDocumentLoaders.contains(loader)); if (ApplicationCacheResource* resource = m_cacheBeingUpdated->resourceForURL(url)) { - if (!(resource->type() & ApplicationCacheResource::Implicit)) { - resource->addType(ApplicationCacheResource::Implicit); + if (!(resource->type() & ApplicationCacheResource::Master)) { + resource->addType(ApplicationCacheResource::Master); ASSERT(!resource->storageID()); } } else - m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, loader->response(), ApplicationCacheResource::Implicit, loader->mainResourceData())); + 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; } @@ -369,6 +376,16 @@ void ApplicationCacheGroup::update(Frame* frame, ApplicationCacheUpdateOption up return; } + // Don't change anything on disk if private browsing is enabled. + if (!frame->settings() || frame->settings()->privateBrowsingEnabled()) { + ASSERT(m_pendingMasterResourceLoaders.isEmpty()); + ASSERT(m_pendingEntries.isEmpty()); + ASSERT(!m_cacheBeingUpdated); + postListenerTask(&DOMApplicationCache::callCheckingListener, frame->loader()->documentLoader()); + postListenerTask(&DOMApplicationCache::callNoUpdateListener, frame->loader()->documentLoader()); + return; + } + ASSERT(!m_frame); m_frame = frame; @@ -385,14 +402,29 @@ void ApplicationCacheGroup::update(Frame* frame, ApplicationCacheUpdateOption up ASSERT(m_completionType == None); // FIXME: Handle defer loading - - ResourceRequest request(m_manifestURL); + m_manifestHandle = createResourceHandle(m_manifestURL, m_newestCache ? m_newestCache->manifestResource() : 0); +} + +PassRefPtr<ResourceHandle> ApplicationCacheGroup::createResourceHandle(const KURL& url, ApplicationCacheResource* newestCachedResource) +{ + ResourceRequest request(url); m_frame->loader()->applyUserAgent(request); - // FIXME: Should ask to revalidate from origin. + request.setHTTPHeaderField("Cache-Control", "max-age=0"); + + if (newestCachedResource) { + const String& lastModified = newestCachedResource->response().httpHeaderField("Last-Modified"); + const String& eTag = newestCachedResource->response().httpHeaderField("ETag"); + if (!lastModified.isEmpty() || !eTag.isEmpty()) { + if (!lastModified.isEmpty()) + request.setHTTPHeaderField("If-Modified-Since", lastModified); + if (!eTag.isEmpty()) + request.setHTTPHeaderField("If-None-Match", eTag); + } + } - m_manifestHandle = ResourceHandle::create(request, this, m_frame, false, true, false); + return ResourceHandle::create(request, this, m_frame, false, true, false); } - + void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, const ResourceResponse& response) { if (handle == m_manifestHandle) { @@ -409,11 +441,24 @@ void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, const Res unsigned type = m_pendingEntries.get(url); - // If this is an initial cache attempt, we should not get implicit resources delivered here. + // If this is an initial cache attempt, we should not get master resources delivered here. if (!m_newestCache) - ASSERT(!(type & ApplicationCacheResource::Implicit)); + ASSERT(!(type & ApplicationCacheResource::Master)); + + if (m_newestCache && response.httpStatusCode() == 304) { // Not modified. + ApplicationCacheResource* newestCachedResource = m_newestCache->resourceForURL(handle->request().url()); + if (newestCachedResource) { + m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, newestCachedResource->response(), type, newestCachedResource->data())); + m_currentHandle->cancel(); + m_currentHandle = 0; + // Load the next resource, if any. + startLoadingEntry(); + return; + } + // The server could return 304 for an unconditional request - in this case, we handle the response as a normal error. + } - if (response.httpStatusCode() / 100 != 2 || response.url() != m_currentHandle->request().url()) { + if (response.httpStatusCode() / 100 != 2 || response.url() != m_currentHandle->request().url()) { if ((type & ApplicationCacheResource::Explicit) || (type & ApplicationCacheResource::Fallback)) { // Note that cacheUpdateFailed() can cause the cache group to be deleted. cacheUpdateFailed(); @@ -428,12 +473,12 @@ void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, const Res // Copy the resource and its metadata from the newest application cache in cache group whose completeness flag is complete, and act // as if that was the fetched resource, ignoring the resource obtained from the network. ASSERT(m_newestCache); - ApplicationCacheResource* resource = m_newestCache->resourceForURL(handle->request().url()); - ASSERT(resource); - m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(handle->request().url(), resource->response(), resource->type(), resource->data())); - // Load the next resource, if any. + ApplicationCacheResource* newestCachedResource = m_newestCache->resourceForURL(handle->request().url()); + ASSERT(newestCachedResource); + m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, newestCachedResource->response(), type, newestCachedResource->data())); m_currentHandle->cancel(); m_currentHandle = 0; + // Load the next resource, if any. startLoadingEntry(); } return; @@ -484,10 +529,11 @@ void ApplicationCacheGroup::didFail(ResourceHandle* handle, const ResourceError& } unsigned type = m_currentResource ? m_currentResource->type() : m_pendingEntries.get(handle->request().url()); + const KURL& url = handle->request().url(); - ASSERT(!m_currentResource || !m_pendingEntries.contains(handle->request().url())); + ASSERT(!m_currentResource || !m_pendingEntries.contains(url)); m_currentResource = 0; - m_pendingEntries.remove(handle->request().url()); + m_pendingEntries.remove(url); if ((type & ApplicationCacheResource::Explicit) || (type & ApplicationCacheResource::Fallback)) { // Note that cacheUpdateFailed() can cause the cache group to be deleted. @@ -496,9 +542,9 @@ void ApplicationCacheGroup::didFail(ResourceHandle* handle, const ResourceError& // Copy the resource and its metadata from the newest application cache in cache group whose completeness flag is complete, and act // as if that was the fetched resource, ignoring the resource obtained from the network. ASSERT(m_newestCache); - ApplicationCacheResource* resource = m_newestCache->resourceForURL(handle->request().url()); - ASSERT(resource); - m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(handle->request().url(), resource->response(), resource->type(), resource->data())); + ApplicationCacheResource* newestCachedResource = m_newestCache->resourceForURL(url); + ASSERT(newestCachedResource); + m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, newestCachedResource->response(), type, newestCachedResource->data())); // Load the next resource, if any. startLoadingEntry(); } @@ -514,6 +560,9 @@ void ApplicationCacheGroup::didReceiveManifestResponse(const ResourceResponse& r return; } + if (response.httpStatusCode() == 304) + return; + if (response.httpStatusCode() / 100 != 2 || response.url() != m_manifestHandle->request().url() || !equalIgnoringCase(response.mimeType(), "text/cache-manifest")) { cacheUpdateFailed(); return; @@ -525,28 +574,29 @@ void ApplicationCacheGroup::didReceiveManifestResponse(const ResourceResponse& r void ApplicationCacheGroup::didReceiveManifestData(const char* data, int length) { - ASSERT(m_manifestResource); - m_manifestResource->data()->append(data, length); + if (m_manifestResource) + m_manifestResource->data()->append(data, length); } void ApplicationCacheGroup::didFinishLoadingManifest() { - if (!m_manifestResource) { + bool isUpgradeAttempt = m_newestCache; + + if (!isUpgradeAttempt && !m_manifestResource) { + // The server returned 304 Not Modified even though we didn't send a conditional request. cacheUpdateFailed(); return; } - bool isUpgradeAttempt = m_newestCache; - m_manifestHandle = 0; - // Check if the manifest is byte-for-byte identical. + // Check if the manifest was not modified. if (isUpgradeAttempt) { ApplicationCacheResource* newestManifest = m_newestCache->manifestResource(); ASSERT(newestManifest); - if (newestManifest->data()->size() == m_manifestResource->data()->size() && - !memcmp(newestManifest->data()->data(), m_manifestResource->data()->data(), newestManifest->data()->size())) { + 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())) { m_completionType = NoUpdate; m_manifestResource = 0; @@ -581,7 +631,7 @@ void ApplicationCacheGroup::didFinishLoadingManifest() ApplicationCache::ResourceMap::const_iterator end = m_newestCache->end(); for (ApplicationCache::ResourceMap::const_iterator it = m_newestCache->begin(); it != end; ++it) { unsigned type = it->second->type(); - if (type & (ApplicationCacheResource::Implicit | ApplicationCacheResource::Dynamic)) + if (type & (ApplicationCacheResource::Master | ApplicationCacheResource::Dynamic)) addEntry(it->first, type); } } @@ -657,7 +707,11 @@ void ApplicationCacheGroup::checkIfLoadIsComplete() case NoUpdate: ASSERT(isUpgradeAttempt); ASSERT(!m_cacheBeingUpdated); - ASSERT(m_storageID); + + // The storage could have been manually emptied by the user. + if (!m_storageID) + cacheStorage().storeNewestCache(this); + postListenerTask(&DOMApplicationCache::callNoUpdateListener, m_associatedDocumentLoaders); break; case Failure: @@ -707,15 +761,9 @@ void ApplicationCacheGroup::startLoadingEntry() postListenerTask(&DOMApplicationCache::callProgressListener, m_associatedDocumentLoaders); - // FIXME: If this is an upgrade attempt, the newest cache should be used as an HTTP cache. - ASSERT(!m_currentHandle); - ResourceRequest request(it->first); - m_frame->loader()->applyUserAgent(request); - // FIXME: Should ask to revalidate from origin. - - m_currentHandle = ResourceHandle::create(request, this, m_frame, false, true, false); + m_currentHandle = createResourceHandle(KURL(it->first), m_newestCache ? m_newestCache->resourceForURL(it->first) : 0); } void ApplicationCacheGroup::deliverDelayedMainResources() @@ -743,10 +791,10 @@ void ApplicationCacheGroup::addEntry(const String& url, unsigned type) { ASSERT(m_cacheBeingUpdated); - // Don't add the URL if we already have an implicit resource in the cache + // 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)) { - ASSERT(resource->type() & ApplicationCacheResource::Implicit); + ASSERT(resource->type() & ApplicationCacheResource::Master); ASSERT(!m_frame->loader()->documentLoader()->isLoadingMainResource()); resource->addType(type); diff --git a/WebCore/loader/appcache/ApplicationCacheGroup.h b/WebCore/loader/appcache/ApplicationCacheGroup.h index e4b2d3e..aebf0ab 100644 --- a/WebCore/loader/appcache/ApplicationCacheGroup.h +++ b/WebCore/loader/appcache/ApplicationCacheGroup.h @@ -92,9 +92,11 @@ public: private: typedef void (DOMApplicationCache::*ListenerFunction)(); - void postListenerTask(ListenerFunction, const HashSet<DocumentLoader*>&); - void postListenerTask(ListenerFunction, const Vector<RefPtr<DocumentLoader> >& loaders); - void postListenerTask(ListenerFunction, DocumentLoader*); + static void postListenerTask(ListenerFunction, const HashSet<DocumentLoader*>&); + static void postListenerTask(ListenerFunction, const Vector<RefPtr<DocumentLoader> >& loaders); + static void postListenerTask(ListenerFunction, DocumentLoader*); + + PassRefPtr<ResourceHandle> createResourceHandle(const KURL&, ApplicationCacheResource* newestCachedResource); virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&); virtual void didReceiveData(ResourceHandle*, const char*, int, int lengthReceived); diff --git a/WebCore/loader/appcache/ApplicationCacheResource.cpp b/WebCore/loader/appcache/ApplicationCacheResource.cpp index d78cf7f..7c1241b 100644 --- a/WebCore/loader/appcache/ApplicationCacheResource.cpp +++ b/WebCore/loader/appcache/ApplicationCacheResource.cpp @@ -47,8 +47,8 @@ void ApplicationCacheResource::addType(unsigned type) #ifndef NDEBUG void ApplicationCacheResource::dumpType(unsigned type) { - if (type & Implicit) - printf("implicit "); + if (type & Master) + printf("master "); if (type & Manifest) printf("manifest "); if (type & Explicit) diff --git a/WebCore/loader/appcache/ApplicationCacheResource.h b/WebCore/loader/appcache/ApplicationCacheResource.h index 96f5a0e..28d8280 100644 --- a/WebCore/loader/appcache/ApplicationCacheResource.h +++ b/WebCore/loader/appcache/ApplicationCacheResource.h @@ -35,7 +35,7 @@ namespace WebCore { class ApplicationCacheResource : public SubstituteResource { public: enum Type { - Implicit = 1 << 0, + Master = 1 << 0, Manifest = 1 << 1, Explicit = 1 << 2, Foreign = 1 << 3, diff --git a/WebCore/loader/appcache/DOMApplicationCache.cpp b/WebCore/loader/appcache/DOMApplicationCache.cpp index 5bc4420..12d86a7 100644 --- a/WebCore/loader/appcache/DOMApplicationCache.cpp +++ b/WebCore/loader/appcache/DOMApplicationCache.cpp @@ -132,7 +132,7 @@ PassRefPtr<DOMStringList> DOMApplicationCache::items() Vector<String> result; if (ApplicationCache* cache = associatedCache()) { unsigned numEntries = cache->numDynamicEntries(); - result.reserveCapacity(numEntries); + result.reserveInitialCapacity(numEntries); for (unsigned i = 0; i < numEntries; ++i) result.append(cache->dynamicEntry(i)); } @@ -298,6 +298,51 @@ void DOMApplicationCache::callObsoleteListener() callListener(eventNames().obsoleteEvent, m_onObsoleteListener.get()); } +#if USE(V8) +RefPtr<EventListener>* DOMApplicationCache::getAttributeEventListenerStorage(const AtomicString& eventType) +{ + if (eventType == eventNames().checkingEvent) + return &m_onCheckingListener; + else if (eventType == eventNames().errorEvent) + return &m_onErrorListener; + else if (eventType == eventNames().noupdateEvent) + return &m_onNoUpdateListener; + else if (eventType == eventNames().downloadingEvent) + return &m_onDownloadingListener; + else if (eventType == eventNames().progressEvent) + return &m_onProgressListener; + else if (eventType == eventNames().updatereadyEvent) + return &m_onUpdateReadyListener; + else if (eventType == eventNames().cachedEvent) + return &m_onCachedListener; + else if (eventType == eventNames().obsoleteEvent) + return &m_onObsoleteListener; + else + return 0; +} + +EventListener* DOMApplicationCache::getAttributeEventListener(const AtomicString& eventType) +{ + RefPtr<EventListener>* storage = getAttributeEventListenerStorage(eventType); + ASSERT(storage); + return (*storage).get(); +} + +void DOMApplicationCache::setAttributeEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener) +{ + RefPtr<EventListener>* storage = getAttributeEventListenerStorage(eventType); + ASSERT(storage); + (*storage) = listener; +} + +void DOMApplicationCache::clearAttributeEventListener(const AtomicString& eventType) +{ + RefPtr<EventListener>* storage = getAttributeEventListenerStorage(eventType); + ASSERT(storage); + (*storage) = 0; +} +#endif + } // namespace WebCore #endif // ENABLE(OFFLINE_WEB_APPLICATIONS) diff --git a/WebCore/loader/appcache/DOMApplicationCache.h b/WebCore/loader/appcache/DOMApplicationCache.h index b76542d..57b37bc 100644 --- a/WebCore/loader/appcache/DOMApplicationCache.h +++ b/WebCore/loader/appcache/DOMApplicationCache.h @@ -115,6 +115,12 @@ public: void callUpdateReadyListener(); void callCachedListener(); void callObsoleteListener(); + +#if USE(V8) + EventListener* getAttributeEventListener(const AtomicString& eventType); + void setAttributeEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener); + void clearAttributeEventListener(const AtomicString& eventType); +#endif private: DOMApplicationCache(Frame*); @@ -125,6 +131,10 @@ private: ApplicationCache* associatedCache() const; bool swapCache(); + +#if USE(V8) + RefPtr<EventListener>* getAttributeEventListenerStorage(const AtomicString& eventType); +#endif RefPtr<EventListener> m_onCheckingListener; RefPtr<EventListener> m_onErrorListener; diff --git a/WebCore/loader/appcache/ManifestParser.cpp b/WebCore/loader/appcache/ManifestParser.cpp index a83303a..4169313 100644 --- a/WebCore/loader/appcache/ManifestParser.cpp +++ b/WebCore/loader/appcache/ManifestParser.cpp @@ -30,7 +30,7 @@ #include "CharacterNames.h" #include "KURL.h" -#include "TextEncoding.h" +#include "TextResourceDecoder.h" using namespace std; @@ -45,9 +45,12 @@ bool parseManifest(const KURL& manifestURL, const char* data, int length, Manife ASSERT(manifest.fallbackURLs.isEmpty()); Mode mode = Explicit; - String s = UTF8Encoding().decode(data, length); + + RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("text/cache-manifest", "UTF-8"); + String s = decoder->decode(data, length); + s += decoder->flush(); - // Look for the magic signature: "^\xFEFF?CACHE MANIFEST[ \t]?" (the BOM is removed by decode()). + // Look for the magic signature: "^\xFEFF?CACHE MANIFEST[ \t]?" (the BOM is removed by TextResourceDecoder). // Example: "CACHE MANIFEST #comment" is a valid signature. // Example: "CACHE MANIFEST;V2" is not. if (!s.startsWith("CACHE MANIFEST")) |