summaryrefslogtreecommitdiffstats
path: root/WebCore/loader/appcache
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/loader/appcache')
-rw-r--r--WebCore/loader/appcache/ApplicationCache.cpp6
-rw-r--r--WebCore/loader/appcache/ApplicationCacheGroup.cpp136
-rw-r--r--WebCore/loader/appcache/ApplicationCacheGroup.h8
-rw-r--r--WebCore/loader/appcache/ApplicationCacheResource.cpp4
-rw-r--r--WebCore/loader/appcache/ApplicationCacheResource.h2
-rw-r--r--WebCore/loader/appcache/DOMApplicationCache.cpp47
-rw-r--r--WebCore/loader/appcache/DOMApplicationCache.h10
-rw-r--r--WebCore/loader/appcache/ManifestParser.cpp9
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"))