summaryrefslogtreecommitdiffstats
path: root/WebCore/loader
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-05 14:34:32 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-05 14:34:32 -0800
commit635860845790a19bf50bbc51ba8fb66a96dde068 (patch)
treeef6ad9ff73a5b57f65249d4232a202fa77e6a140 /WebCore/loader
parent8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2 (diff)
downloadexternal_webkit-635860845790a19bf50bbc51ba8fb66a96dde068.zip
external_webkit-635860845790a19bf50bbc51ba8fb66a96dde068.tar.gz
external_webkit-635860845790a19bf50bbc51ba8fb66a96dde068.tar.bz2
auto import from //depot/cupcake/@136594
Diffstat (limited to 'WebCore/loader')
-rw-r--r--WebCore/loader/Cache.cpp183
-rw-r--r--WebCore/loader/Cache.h8
-rw-r--r--WebCore/loader/CachePolicy.h2
-rw-r--r--WebCore/loader/CachedCSSStyleSheet.cpp35
-rw-r--r--WebCore/loader/CachedCSSStyleSheet.h12
-rw-r--r--WebCore/loader/CachedFont.cpp2
-rw-r--r--WebCore/loader/CachedImage.cpp43
-rw-r--r--WebCore/loader/CachedImage.h4
-rw-r--r--WebCore/loader/CachedResource.cpp98
-rw-r--r--WebCore/loader/CachedResource.h20
-rw-r--r--WebCore/loader/CachedResourceClient.h8
-rw-r--r--WebCore/loader/CachedResourceClientWalker.cpp4
-rw-r--r--WebCore/loader/CachedResourceClientWalker.h4
-rw-r--r--WebCore/loader/CachedScript.cpp42
-rw-r--r--WebCore/loader/CachedScript.h13
-rw-r--r--WebCore/loader/CachedXBLDocument.cpp4
-rw-r--r--WebCore/loader/CachedXBLDocument.h4
-rw-r--r--WebCore/loader/CachedXSLStyleSheet.cpp4
-rw-r--r--WebCore/loader/CachedXSLStyleSheet.h4
-rw-r--r--WebCore/loader/DocLoader.cpp81
-rw-r--r--WebCore/loader/DocLoader.h13
-rw-r--r--WebCore/loader/DocumentLoader.cpp114
-rw-r--r--WebCore/loader/DocumentLoader.h43
-rw-r--r--WebCore/loader/DocumentThreadableLoader.cpp129
-rw-r--r--WebCore/loader/DocumentThreadableLoader.h78
-rw-r--r--WebCore/loader/EmptyClients.h112
-rw-r--r--WebCore/loader/FTPDirectoryDocument.cpp23
-rw-r--r--WebCore/loader/FrameLoader.cpp921
-rw-r--r--WebCore/loader/FrameLoader.h110
-rw-r--r--WebCore/loader/FrameLoaderClient.cpp92
-rw-r--r--WebCore/loader/FrameLoaderClient.h22
-rw-r--r--WebCore/loader/FrameLoaderTypes.h6
-rw-r--r--WebCore/loader/ImageDocument.cpp13
-rw-r--r--WebCore/loader/ImageLoader.cpp20
-rw-r--r--WebCore/loader/ImageLoader.h10
-rw-r--r--WebCore/loader/MainResourceLoader.cpp53
-rw-r--r--WebCore/loader/MediaDocument.cpp7
-rw-r--r--WebCore/loader/NavigationAction.cpp2
-rw-r--r--WebCore/loader/PluginDocument.cpp7
-rw-r--r--WebCore/loader/ProgressTracker.cpp2
-rw-r--r--WebCore/loader/ResourceLoader.cpp44
-rw-r--r--WebCore/loader/ResourceLoader.h10
-rw-r--r--WebCore/loader/SubresourceLoader.cpp26
-rw-r--r--WebCore/loader/SubresourceLoader.h25
-rw-r--r--WebCore/loader/SubresourceLoaderClient.h7
-rw-r--r--WebCore/loader/TextDocument.cpp2
-rw-r--r--WebCore/loader/TextResourceDecoder.cpp3
-rw-r--r--WebCore/loader/ThreadableLoader.cpp62
-rw-r--r--WebCore/loader/ThreadableLoader.h75
-rw-r--r--WebCore/loader/ThreadableLoaderClient.h56
-rw-r--r--WebCore/loader/appcache/ApplicationCache.cpp50
-rw-r--r--WebCore/loader/appcache/ApplicationCache.h34
-rw-r--r--WebCore/loader/appcache/ApplicationCacheGroup.cpp702
-rw-r--r--WebCore/loader/appcache/ApplicationCacheGroup.h76
-rw-r--r--WebCore/loader/appcache/ApplicationCacheResource.cpp6
-rw-r--r--WebCore/loader/appcache/ApplicationCacheResource.h3
-rw-r--r--WebCore/loader/appcache/ApplicationCacheStorage.cpp271
-rw-r--r--WebCore/loader/appcache/ApplicationCacheStorage.h18
-rw-r--r--WebCore/loader/appcache/DOMApplicationCache.cpp71
-rw-r--r--WebCore/loader/appcache/DOMApplicationCache.h13
-rw-r--r--WebCore/loader/appcache/DOMApplicationCache.idl12
-rw-r--r--WebCore/loader/appcache/ManifestParser.cpp79
-rw-r--r--WebCore/loader/appcache/ManifestParser.h19
-rw-r--r--WebCore/loader/archive/ArchiveFactory.cpp10
-rw-r--r--WebCore/loader/archive/cf/LegacyWebArchive.cpp72
-rw-r--r--WebCore/loader/icon/IconDatabase.cpp14
-rw-r--r--WebCore/loader/icon/IconDatabaseClient.h3
-rw-r--r--WebCore/loader/icon/IconFetcher.cpp20
-rw-r--r--WebCore/loader/icon/IconLoader.cpp16
-rw-r--r--WebCore/loader/icon/IconRecord.cpp3
-rw-r--r--WebCore/loader/loader.cpp33
-rw-r--r--WebCore/loader/loader.h24
-rw-r--r--WebCore/loader/mac/DocumentLoaderMac.cpp5
-rw-r--r--WebCore/loader/mac/ResourceLoaderMac.mm2
74 files changed, 2885 insertions, 1333 deletions
diff --git a/WebCore/loader/Cache.cpp b/WebCore/loader/Cache.cpp
index 7d30e5f..212fca3 100644
--- a/WebCore/loader/Cache.cpp
+++ b/WebCore/loader/Cache.cpp
@@ -37,8 +37,8 @@
#include "FrameView.h"
#include "Image.h"
#include "ResourceHandle.h"
-#include "SystemTime.h"
#include <stdio.h>
+#include <wtf/CurrentTime.h>
using namespace std;
@@ -95,7 +95,7 @@ static CachedResource* createResource(CachedResource::Type type, const KURL& url
return 0;
}
-CachedResource* Cache::requestResource(DocLoader* docLoader, CachedResource::Type type, const KURL& url, const String& charset, bool isPreload)
+CachedResource* Cache::requestResource(DocLoader* docLoader, CachedResource::Type type, const KURL& url, const String& charset, bool requestIsPreload)
{
// FIXME: Do we really need to special-case an empty URL?
// Would it be better to just go on with the cache code and let it fail later?
@@ -103,25 +103,19 @@ CachedResource* Cache::requestResource(DocLoader* docLoader, CachedResource::Typ
return 0;
// Look up the resource in our map.
- CachedResource* resource = m_resources.get(url.string());
-
- if (resource) {
- if (isPreload && !resource->isPreloaded())
- return 0;
- if (FrameLoader::restrictAccessToLocal() && !FrameLoader::canLoad(url, String(), docLoader->doc())) {
- Document* doc = docLoader->doc();
- if(doc && !isPreload)
- FrameLoader::reportLocalLoadFailed(doc->frame(), resource->url());
- return 0;
- }
- } else {
- if (FrameLoader::restrictAccessToLocal() && !FrameLoader::canLoad(url, String(), docLoader->doc())) {
- Document* doc = docLoader->doc();
- if(doc && !isPreload)
- FrameLoader::reportLocalLoadFailed(doc->frame(), url.string());
- return 0;
- }
-
+ CachedResource* resource = resourceForURL(url.string());
+
+ if (resource && requestIsPreload && !resource->isPreloaded())
+ return 0;
+
+ if (FrameLoader::restrictAccessToLocal() && !FrameLoader::canLoad(url, String(), docLoader->doc())) {
+ Document* doc = docLoader->doc();
+ if (doc && !requestIsPreload)
+ FrameLoader::reportLocalLoadFailed(doc->frame(), url.string());
+ return 0;
+ }
+
+ if (!resource) {
// The resource does not exist. Create it.
resource = createResource(type, url, charset);
ASSERT(resource);
@@ -169,7 +163,7 @@ CachedResource* Cache::requestResource(DocLoader* docLoader, CachedResource::Typ
CachedCSSStyleSheet* Cache::requestUserCSSStyleSheet(DocLoader* docLoader, const String& url, const String& charset)
{
CachedCSSStyleSheet* userSheet;
- if (CachedResource* existing = m_resources.get(url)) {
+ if (CachedResource* existing = resourceForURL(url)) {
if (existing->type() != CachedResource::CSSStyleSheet)
return 0;
userSheet = static_cast<CachedCSSStyleSheet*>(existing);
@@ -248,7 +242,13 @@ void Cache::revalidationFailed(CachedResource* revalidatingResource)
CachedResource* Cache::resourceForURL(const String& url)
{
- return m_resources.get(url);
+ CachedResource* resource = m_resources.get(url);
+ if (resource && !resource->makePurgeable(false)) {
+ ASSERT(!resource->hasClients());
+ evict(resource);
+ return 0;
+ }
+ return resource;
}
unsigned Cache::deadCapacity() const
@@ -278,7 +278,7 @@ void Cache::pruneLiveResources()
unsigned targetSize = static_cast<unsigned>(capacity * cTargetPrunePercentage); // Cut by a percentage to avoid immediately pruning again.
double currentTime = FrameView::currentPaintTimeStamp();
if (!currentTime) // In case prune is called directly, outside of a Frame paint.
- currentTime = WebCore::currentTime();
+ currentTime = WTF::currentTime();
// Destroy any decoded data in live objects that we can.
// Start from the tail, since this is the least recently accessed of the objects.
@@ -315,6 +315,25 @@ void Cache::pruneDeadResources()
unsigned targetSize = static_cast<unsigned>(capacity * cTargetPrunePercentage); // Cut by a percentage to avoid immediately pruning again.
int size = m_allResources.size();
+
+ if (!m_inPruneDeadResources) {
+ // See if we have any purged resources we can evict.
+ for (int i = 0; i < size; i++) {
+ CachedResource* current = m_allResources[i].m_tail;
+ while (current) {
+ CachedResource* prev = current->m_prevInAllResourcesList;
+ if (current->wasPurged()) {
+ ASSERT(!current->hasClients());
+ ASSERT(!current->isPreloaded());
+ evict(current);
+ }
+ current = prev;
+ }
+ }
+ if (targetSize && m_deadSize <= targetSize)
+ return;
+ }
+
bool canShrinkLRULists = true;
m_inPruneDeadResources = true;
for (int i = size - 1; i >= 0; i--) {
@@ -324,7 +343,7 @@ void Cache::pruneDeadResources()
// First flush all the decoded data in this queue.
while (current) {
CachedResource* prev = current->m_prevInAllResourcesList;
- if (!current->hasClients() && !current->isPreloaded() && current->isLoaded() && current->decodedSize()) {
+ if (!current->hasClients() && !current->isPreloaded() && current->isLoaded()) {
// Destroy our decoded data. This will remove us from
// m_liveDecodedResources, and possibly move us to a differnt
// LRU list in m_allResources.
@@ -382,6 +401,15 @@ void Cache::evict(CachedResource* resource)
// The resource may have already been removed by someone other than our caller,
// who needed a fresh copy for a reload. See <http://bugs.webkit.org/show_bug.cgi?id=12479#c6>.
if (resource->inCache()) {
+ if (!resource->isCacheValidator()) {
+ // Notify all doc loaders that might be observing this object still that it has been
+ // extracted from the set of resources.
+ // No need to do this for cache validator resources, they are replaced automatically by using CachedResourceHandles.
+ HashSet<DocLoader*>::iterator end = m_docLoaders.end();
+ for (HashSet<DocLoader*>::iterator itr = m_docLoaders.begin(); itr != end; ++itr)
+ (*itr)->removeCachedResource(resource);
+ }
+
// Remove from the resource map.
m_resources.remove(resource->url());
resource->setInCache(false);
@@ -389,12 +417,6 @@ void Cache::evict(CachedResource* resource)
// Remove from the appropriate LRU list.
removeFromLRUList(resource);
removeFromLiveDecodedResourcesList(resource);
-
- // Notify all doc loaders that might be observing this object still that it has been
- // extracted from the set of resources.
- HashSet<DocLoader*>::iterator end = m_docLoaders.end();
- for (HashSet<DocLoader*>::iterator itr = m_docLoaders.begin(); itr != end; ++itr)
- (*itr)->removeCachedResource(resource);
// Subtract from our size totals.
int delta = -static_cast<int>(resource->size());
@@ -534,6 +556,10 @@ void Cache::resourceAccessed(CachedResource* resource)
// the queue will possibly change.
removeFromLRUList(resource);
+ // If this is the first time the resource has been accessed, adjust the size of the cache to account for its initial size.
+ if (!resource->accessCount())
+ adjustSize(resource->hasClients(), resource->size());
+
// Add to our access count.
resource->increaseAccessCount();
@@ -631,60 +657,52 @@ void Cache::adjustSize(bool live, int delta)
}
}
+void Cache::TypeStatistic::addResource(CachedResource* o)
+{
+ bool purged = o->wasPurged();
+ bool purgeable = o->isPurgeable() && !purged;
+ int pageSize = (o->encodedSize() + o->overheadSize() + 4095) & ~4095;
+ count++;
+ size += purged ? 0 : o->size();
+ liveSize += o->hasClients() ? o->size() : 0;
+ decodedSize += o->decodedSize();
+ purgeableSize += purgeable ? pageSize : 0;
+ purgedSize += purged ? pageSize : 0;
+}
+
Cache::Statistics Cache::getStatistics()
{
Statistics stats;
CachedResourceMap::iterator e = m_resources.end();
for (CachedResourceMap::iterator i = m_resources.begin(); i != e; ++i) {
- CachedResource *o = i->second;
- switch (o->type()) {
- case CachedResource::ImageResource:
- stats.images.count++;
- stats.images.size += o->size();
- stats.images.liveSize += o->hasClients() ? o->size() : 0;
- stats.images.decodedSize += o->decodedSize();
- break;
-
- case CachedResource::CSSStyleSheet:
- stats.cssStyleSheets.count++;
- stats.cssStyleSheets.size += o->size();
- stats.cssStyleSheets.liveSize += o->hasClients() ? o->size() : 0;
- stats.cssStyleSheets.decodedSize += o->decodedSize();
- break;
-
- case CachedResource::Script:
- stats.scripts.count++;
- stats.scripts.size += o->size();
- stats.scripts.liveSize += o->hasClients() ? o->size() : 0;
- stats.scripts.decodedSize += o->decodedSize();
- break;
+ CachedResource* resource = i->second;
+ switch (resource->type()) {
+ case CachedResource::ImageResource:
+ stats.images.addResource(resource);
+ break;
+ case CachedResource::CSSStyleSheet:
+ stats.cssStyleSheets.addResource(resource);
+ break;
+ case CachedResource::Script:
+ stats.scripts.addResource(resource);
+ break;
#if ENABLE(XSLT)
- case CachedResource::XSLStyleSheet:
- stats.xslStyleSheets.count++;
- stats.xslStyleSheets.size += o->size();
- stats.xslStyleSheets.liveSize += o->hasClients() ? o->size() : 0;
- stats.xslStyleSheets.decodedSize += o->decodedSize();
- break;
+ case CachedResource::XSLStyleSheet:
+ stats.xslStyleSheets.addResource(resource);
+ break;
#endif
- case CachedResource::FontResource:
- stats.fonts.count++;
- stats.fonts.size += o->size();
- stats.fonts.liveSize += o->hasClients() ? o->size() : 0;
- stats.fonts.decodedSize += o->decodedSize();
- break;
+ case CachedResource::FontResource:
+ stats.fonts.addResource(resource);
+ break;
#if ENABLE(XBL)
- case CachedResource::XBL:
- stats.xblDocs.count++;
- stats.xblDocs.size += o->size();
- stats.xblDocs.liveSize += o->hasClients() ? o->size() : 0;
- stats.xblDocs.decodedSize += o->decodedSize();
- break;
+ case CachedResource::XBL:
+ stats.xblDocs.addResource(resource)
+ break;
#endif
- default:
- break;
+ default:
+ break;
}
}
-
return stats;
}
@@ -703,6 +721,21 @@ void Cache::setDisabled(bool disabled)
}
#ifndef NDEBUG
+void Cache::dumpStats()
+{
+ Statistics s = getStatistics();
+ printf("%-11s %-11s %-11s %-11s %-11s %-11s %-11s\n", "", "Count", "Size", "LiveSize", "DecodedSize", "PurgeableSize", "PurgedSize");
+ printf("%-11s %-11s %-11s %-11s %-11s %-11s %-11s\n", "-----------", "-----------", "-----------", "-----------", "-----------", "-----------", "-----------");
+ printf("%-11s %11d %11d %11d %11d %11d %11d\n", "Images", s.images.count, s.images.size, s.images.liveSize, s.images.decodedSize, s.images.purgeableSize, s.images.purgedSize);
+ printf("%-11s %11d %11d %11d %11d %11d %11d\n", "CSS", s.cssStyleSheets.count, s.cssStyleSheets.size, s.cssStyleSheets.liveSize, s.cssStyleSheets.decodedSize, s.cssStyleSheets.purgeableSize, s.cssStyleSheets.purgedSize);
+#if ENABLE(XSLT)
+ printf("%-11s %11d %11d %11d %11d %11d %11d\n", "XSL", s.xslStyleSheets.count, s.xslStyleSheets.size, s.xslStyleSheets.liveSize, s.xslStyleSheets.decodedSize, s.xslStyleSheets.purgeableSize, s.xslStyleSheets.purgedSize);
+#endif
+ printf("%-11s %11d %11d %11d %11d %11d %11d\n", "JavaScript", s.scripts.count, s.scripts.size, s.scripts.liveSize, s.scripts.decodedSize, s.scripts.purgeableSize, s.scripts.purgedSize);
+ printf("%-11s %11d %11d %11d %11d %11d %11d\n", "Fonts", s.fonts.count, s.fonts.size, s.fonts.liveSize, s.fonts.decodedSize, s.fonts.purgeableSize, s.fonts.purgedSize);
+ printf("%-11s %-11s %-11s %-11s %-11s %-11s %-11s\n\n", "-----------", "-----------", "-----------", "-----------", "-----------", "-----------", "-----------");
+}
+
void Cache::dumpLRULists(bool includeLive) const
{
printf("LRU-SP lists in eviction order (Kilobytes decoded, Kilobytes encoded, Access count, Referenced):\n");
@@ -714,7 +747,7 @@ void Cache::dumpLRULists(bool includeLive) const
while (current) {
CachedResource* prev = current->m_prevInAllResourcesList;
if (includeLive || !current->hasClients())
- printf("(%.1fK, %.1fK, %uA, %dR); ", current->decodedSize() / 1024.0f, current->encodedSize() / 1024.0f, current->accessCount(), current->hasClients());
+ printf("(%.1fK, %.1fK, %uA, %dR); ", current->decodedSize() / 1024.0f, (current->encodedSize() + current->overheadSize()) / 1024.0f, current->accessCount(), current->hasClients());
current = prev;
}
}
diff --git a/WebCore/loader/Cache.h b/WebCore/loader/Cache.h
index ec0ea0e..9d81dc6 100644
--- a/WebCore/loader/Cache.h
+++ b/WebCore/loader/Cache.h
@@ -1,6 +1,4 @@
/*
- This file is part of the KDE libraries
-
Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
Copyright (C) 2001 Dirk Mueller <mueller@kde.org>
Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
@@ -74,7 +72,10 @@ public:
int size;
int liveSize;
int decodedSize;
- TypeStatistic() : count(0), size(0), liveSize(0), decodedSize(0) { }
+ int purgeableSize;
+ int purgedSize;
+ TypeStatistic() : count(0), size(0), liveSize(0), decodedSize(0), purgeableSize(0), purgedSize(0) { }
+ void addResource(CachedResource*);
};
struct Statistics {
@@ -165,6 +166,7 @@ private:
LRUList* lruListFor(CachedResource*);
void resourceAccessed(CachedResource*);
#ifndef NDEBUG
+ void dumpStats();
void dumpLRULists(bool includeLive) const;
#endif
diff --git a/WebCore/loader/CachePolicy.h b/WebCore/loader/CachePolicy.h
index 16af78a..93f92b1 100644
--- a/WebCore/loader/CachePolicy.h
+++ b/WebCore/loader/CachePolicy.h
@@ -31,7 +31,7 @@ namespace WebCore {
enum CachePolicy {
CachePolicyCache,
CachePolicyVerify,
- CachePolicyRefresh,
+ CachePolicyRevalidate,
CachePolicyReload
};
diff --git a/WebCore/loader/CachedCSSStyleSheet.cpp b/WebCore/loader/CachedCSSStyleSheet.cpp
index 9059f25..10d566e 100644
--- a/WebCore/loader/CachedCSSStyleSheet.cpp
+++ b/WebCore/loader/CachedCSSStyleSheet.cpp
@@ -55,6 +55,12 @@ void CachedCSSStyleSheet::addClient(CachedResourceClient *c)
if (!m_loading)
c->setCSSStyleSheet(m_url, m_decoder->encoding().name(), this);
}
+
+void CachedCSSStyleSheet::allClientsRemoved()
+{
+ if (isSafeToMakePurgeable())
+ makePurgeable(true);
+}
void CachedCSSStyleSheet::setEncoding(const String& chs)
{
@@ -65,6 +71,22 @@ String CachedCSSStyleSheet::encoding() const
{
return m_decoder->encoding().name();
}
+
+const String CachedCSSStyleSheet::sheetText(bool enforceMIMEType) const
+{
+ ASSERT(!isPurgeable());
+
+ if (!m_data || m_data->isEmpty() || !canUseSheet(enforceMIMEType))
+ return String();
+
+ if (!m_decodedSheetText.isNull())
+ return m_decodedSheetText;
+
+ // Don't cache the decoded text, regenerating is cheap and it can use quite a bit of memory
+ String sheetText = m_decoder->decode(m_data->data(), m_data->size());
+ sheetText += m_decoder->flush();
+ return sheetText;
+}
void CachedCSSStyleSheet::data(PassRefPtr<SharedBuffer> data, bool allDataReceived)
{
@@ -73,16 +95,15 @@ void CachedCSSStyleSheet::data(PassRefPtr<SharedBuffer> data, bool allDataReceiv
m_data = data;
setEncodedSize(m_data.get() ? m_data->size() : 0);
- if (m_data.get()) {
- m_sheet = m_decoder->decode(m_data->data(), encodedSize());
- m_sheet += m_decoder->flush();
-#ifdef ANDROID_FIX // FIXME Newer webkit makes decode temporary; remove on webkit update
- // report decoded size too
- setDecodedSize(m_sheet.length() * sizeof(UChar));
-#endif
+ // Decode the data to find out the encoding and keep the sheet text around during checkNotify()
+ if (m_data) {
+ m_decodedSheetText = m_decoder->decode(m_data->data(), m_data->size());
+ m_decodedSheetText += m_decoder->flush();
}
m_loading = false;
checkNotify();
+ // Clear the decoded text as it is unlikely to be needed immediately again and is cheap to regenerate.
+ m_decodedSheetText = String();
}
void CachedCSSStyleSheet::checkNotify()
diff --git a/WebCore/loader/CachedCSSStyleSheet.h b/WebCore/loader/CachedCSSStyleSheet.h
index b9129ba..fa0b31a 100644
--- a/WebCore/loader/CachedCSSStyleSheet.h
+++ b/WebCore/loader/CachedCSSStyleSheet.h
@@ -1,10 +1,8 @@
/*
- This file is part of the KDE libraries
-
Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
Copyright (C) 2001 Dirk Mueller <mueller@kde.org>
Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
+ Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -42,10 +40,12 @@ namespace WebCore {
CachedCSSStyleSheet(const String& URL, const String& charset);
virtual ~CachedCSSStyleSheet();
- const String sheetText(bool enforceMIMEType = true) const { return canUseSheet(enforceMIMEType) ? m_sheet : ""; }
+ const String sheetText(bool enforceMIMEType = true) const;
virtual void addClient(CachedResourceClient*);
-
+
+ virtual void allClientsRemoved();
+
virtual void setEncoding(const String&);
virtual String encoding() const;
virtual void data(PassRefPtr<SharedBuffer> data, bool allDataReceived);
@@ -59,8 +59,8 @@ namespace WebCore {
bool canUseSheet(bool enforceMIMEType) const;
protected:
- String m_sheet;
RefPtr<TextResourceDecoder> m_decoder;
+ String m_decodedSheetText;
};
}
diff --git a/WebCore/loader/CachedFont.cpp b/WebCore/loader/CachedFont.cpp
index 20479ef..0cbdc32 100644
--- a/WebCore/loader/CachedFont.cpp
+++ b/WebCore/loader/CachedFont.cpp
@@ -65,7 +65,7 @@ CachedFont::~CachedFont()
#endif
}
-void CachedFont::load(DocLoader* docLoader)
+void CachedFont::load(DocLoader*)
{
// Don't load the file yet. Wait for an access before triggering the load.
m_loading = true;
diff --git a/WebCore/loader/CachedImage.cpp b/WebCore/loader/CachedImage.cpp
index 3327c38..5e06eb4 100644
--- a/WebCore/loader/CachedImage.cpp
+++ b/WebCore/loader/CachedImage.cpp
@@ -33,7 +33,8 @@
#include "FrameView.h"
#include "Request.h"
#include "Settings.h"
-#include "SystemTime.h"
+#include <wtf/CurrentTime.h>
+#include <wtf/StdLibExtras.h>
#include <wtf/Vector.h>
#if PLATFORM(CG)
@@ -93,8 +94,13 @@ void CachedImage::addClient(CachedResourceClient* c)
if (m_decodedDataDeletionTimer.isActive())
m_decodedDataDeletionTimer.stop();
+
+ if (m_data && !m_image && !m_errorOccurred) {
+ createImage();
+ m_image->setData(m_data, true);
+ }
- if (m_image && !m_image->rect().isEmpty())
+ if (m_image && !m_image->isNull())
c->imageChanged(this);
if (!m_loading)
@@ -111,20 +117,20 @@ void CachedImage::allClientsRemoved()
static Image* brokenImage()
{
- static RefPtr<Image> brokenImage;
- if (!brokenImage)
- brokenImage = Image::loadPlatformResource("missingImage");
+ DEFINE_STATIC_LOCAL(RefPtr<Image>, brokenImage, (Image::loadPlatformResource("missingImage")));
return brokenImage.get();
}
static Image* nullImage()
{
- static RefPtr<BitmapImage> nullImage = BitmapImage::create();
+ DEFINE_STATIC_LOCAL(RefPtr<BitmapImage>, nullImage, (BitmapImage::create()));
return nullImage.get();
}
Image* CachedImage::image() const
{
+ ASSERT(!isPurgeable());
+
if (m_errorOccurred)
return brokenImage();
@@ -166,6 +172,8 @@ bool CachedImage::imageHasRelativeHeight() const
IntSize CachedImage::imageSize(float multiplier) const
{
+ ASSERT(!isPurgeable());
+
if (!m_image)
return IntSize();
if (multiplier == 1.0f)
@@ -185,6 +193,8 @@ IntSize CachedImage::imageSize(float multiplier) const
IntRect CachedImage::imageRect(float multiplier) const
{
+ ASSERT(!isPurgeable());
+
if (!m_image)
return IntRect();
if (multiplier == 1.0f || (!m_image->hasRelativeWidth() && !m_image->hasRelativeHeight()))
@@ -210,11 +220,11 @@ IntRect CachedImage::imageRect(float multiplier) const
return IntRect(x, y, width, height);
}
-void CachedImage::notifyObservers()
+void CachedImage::notifyObservers(const IntRect* changeRect)
{
CachedResourceClientWalker w(m_clients);
while (CachedResourceClient* c = w.next())
- c->imageChanged(this);
+ c->imageChanged(this, changeRect);
}
void CachedImage::clear()
@@ -284,6 +294,8 @@ void CachedImage::data(PassRefPtr<SharedBuffer> data, bool allDataReceived)
return;
}
+ // It would be nice to only redraw the decoded band of the image, but with the current design
+ // (decoding delayed until painting) that seems hard.
notifyObservers();
if (m_image)
@@ -317,7 +329,14 @@ void CachedImage::checkNotify()
void CachedImage::destroyDecodedData()
{
- if (m_image && !m_errorOccurred)
+ bool canDeleteImage = !m_image || (m_image->hasOneRef() && m_image->isBitmapImage());
+ if (isSafeToMakePurgeable() && canDeleteImage && !m_loading) {
+ // Image refs the data buffer so we should not make it purgeable while the image is alive.
+ // Invoking addClient() will reconstruct the image object.
+ m_image = 0;
+ setDecodedSize(0);
+ makePurgeable(true);
+ } else if (m_image && !m_errorOccurred)
m_image->destroyDecodedData();
}
@@ -361,4 +380,10 @@ void CachedImage::animationAdvanced(const Image* image)
notifyObservers();
}
+void CachedImage::changedInRect(const Image* image, const IntRect& rect)
+{
+ if (image == m_image)
+ notifyObservers(&rect);
+}
+
} //namespace WebCore
diff --git a/WebCore/loader/CachedImage.h b/WebCore/loader/CachedImage.h
index f24e2fb..9c3442f 100644
--- a/WebCore/loader/CachedImage.h
+++ b/WebCore/loader/CachedImage.h
@@ -85,11 +85,13 @@ public:
virtual bool shouldPauseAnimation(const Image*);
virtual void animationAdvanced(const Image*);
+ virtual void changedInRect(const Image*, const IntRect&);
private:
void createImage();
size_t maximumDecodedImageSize();
- void notifyObservers();
+ // If not null, changeRect is the changed part of the image.
+ void notifyObservers(const IntRect* changeRect = 0);
void decodedDataDeletionTimerFired(Timer<CachedImage>*);
RefPtr<Image> m_image;
diff --git a/WebCore/loader/CachedResource.cpp b/WebCore/loader/CachedResource.cpp
index 6d0af9b..f5ce737 100644
--- a/WebCore/loader/CachedResource.cpp
+++ b/WebCore/loader/CachedResource.cpp
@@ -3,7 +3,7 @@
Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -30,8 +30,8 @@
#include "Frame.h"
#include "FrameLoader.h"
#include "KURL.h"
+#include "PurgeableBuffer.h"
#include "Request.h"
-#include "SystemTime.h"
#include <wtf/RefCountedLeakCounter.h>
#include <wtf/Vector.h>
@@ -120,13 +120,13 @@ bool CachedResource::isExpired() const
time_t now = time(0);
return difftime(now, m_expirationDate) >= 0;
}
-
+
void CachedResource::setResponse(const ResourceResponse& response)
{
m_response = response;
m_expirationDate = response.expirationDate();
}
-
+
void CachedResource::setRequest(Request* request)
{
if (request && !m_request)
@@ -138,6 +138,8 @@ void CachedResource::setRequest(Request* request)
void CachedResource::addClient(CachedResourceClient *c)
{
+ ASSERT(!isPurgeable());
+
if (m_preloadResult == PreloadNotReferenced) {
if (isLoaded())
m_preloadResult = PreloadReferencedWhileComplete;
@@ -305,12 +307,90 @@ bool CachedResource::canUseCacheValidator() const
bool CachedResource::mustRevalidate(CachePolicy cachePolicy) const
{
if (m_loading)
- return false;
- String cacheControl = m_response.httpHeaderField("Cache-Control");
- // FIXME: It would be better to tokenize the field.
+ return false;
+
+ // FIXME: Also look at max-age, min-fresh, max-stale in Cache-Control
if (cachePolicy == CachePolicyCache)
- return !cacheControl.isEmpty() && (cacheControl.contains("no-cache", false) || (isExpired() && cacheControl.contains("must-revalidate", false)));
- return isExpired() || cacheControl.contains("no-cache", false);
+ return m_response.cacheControlContainsNoCache() || (isExpired() && m_response.cacheControlContainsMustRevalidate());
+ return isExpired() || m_response.cacheControlContainsNoCache();
+}
+
+bool CachedResource::isSafeToMakePurgeable() const
+{
+ return !hasClients() && !m_isBeingRevalidated && !m_resourceToRevalidate;
+}
+
+bool CachedResource::makePurgeable(bool purgeable)
+{
+ if (purgeable) {
+ ASSERT(isSafeToMakePurgeable());
+
+ if (m_purgeableData) {
+ ASSERT(!m_data);
+ return true;
+ }
+ if (!m_data)
+ return false;
+
+ // Should not make buffer purgeable if it has refs othen than this since we don't want two copies.
+ if (!m_data->hasOneRef())
+ return false;
+
+ // Purgeable buffers are allocated in multiples of the page size (4KB in common CPUs) so it does not make sense for very small buffers.
+ const size_t purgeableThreshold = 4 * 4096;
+ if (m_data->size() < purgeableThreshold)
+ return false;
+
+ if (m_data->hasPurgeableBuffer()) {
+ m_purgeableData.set(m_data->releasePurgeableBuffer());
+ } else {
+ m_purgeableData.set(PurgeableBuffer::create(m_data->data(), m_data->size()));
+ if (!m_purgeableData)
+ return false;
+ }
+
+ m_purgeableData->makePurgeable(true);
+ m_data.clear();
+ return true;
+ }
+
+ if (!m_purgeableData)
+ return true;
+ ASSERT(!m_data);
+ ASSERT(!hasClients());
+
+ if (!m_purgeableData->makePurgeable(false))
+ return false;
+
+ m_data = SharedBuffer::adoptPurgeableBuffer(m_purgeableData.release());
+ return true;
+}
+
+bool CachedResource::isPurgeable() const
+{
+ return m_purgeableData && m_purgeableData->isPurgeable();
+}
+
+bool CachedResource::wasPurged() const
+{
+ return m_purgeableData && m_purgeableData->wasPurged();
+}
+
+unsigned CachedResource::overheadSize() const
+{
+
+ // FIXME: Find some programmatic lighweight way to calculate response size, and size of the different CachedResource classes.
+ // This is a rough estimate of resource overhead based on stats collected from the stress test.
+ return sizeof(CachedResource) + 3648;
+
+ /* sizeof(CachedResource) +
+ 192 + // average size of m_url.
+ 384 + // average size of m_clients hash map.
+ 1280 * 2 + // average size of ResourceResponse. Doubled to account for the WebCore copy and the CF copy.
+ // Mostly due to the size of the hash maps, the Header Map strings and the URL.
+ 256 * 2 // Overhead from ResourceRequest, doubled to account for WebCore copy and CF copy.
+ // Mostly due to the URL and Header Map.
+ */
}
}
diff --git a/WebCore/loader/CachedResource.h b/WebCore/loader/CachedResource.h
index c56a889..63c250b 100644
--- a/WebCore/loader/CachedResource.h
+++ b/WebCore/loader/CachedResource.h
@@ -29,6 +29,7 @@
#include "SharedBuffer.h"
#include <wtf/HashCountedSet.h>
#include <wtf/HashSet.h>
+#include <wtf/OwnPtr.h>
#include <wtf/Vector.h>
#include <time.h>
@@ -38,13 +39,16 @@ class Cache;
class CachedResourceClient;
class CachedResourceHandleBase;
class DocLoader;
+class InspectorResource;
class Request;
+class PurgeableBuffer;
// A resource that is held in the cache. Classes who want to use this object should derive
// from CachedResourceClient, to get the function calls in case the requested data has arrived.
// This class also does the actual communication with the loader to obtain the resource from the network.
class CachedResource {
friend class Cache;
+ friend class InspectorResource;
public:
enum Type {
@@ -96,15 +100,16 @@ public:
PreloadResult preloadResult() const { return m_preloadResult; }
void setRequestedFromNetworkingLayer() { m_requestedFromNetworkingLayer = true; }
- virtual void allClientsRemoved() { };
+ virtual void allClientsRemoved() { }
unsigned count() const { return m_clients.size(); }
Status status() const { return m_status; }
- unsigned size() const { return encodedSize() + decodedSize(); }
+ unsigned size() const { return encodedSize() + decodedSize() + overheadSize(); }
unsigned encodedSize() const { return m_encodedSize; }
unsigned decodedSize() const { return m_decodedSize; }
+ unsigned overheadSize() const;
bool isLoaded() const { return !m_loading; }
void setLoading(bool b) { m_loading = b; }
@@ -129,7 +134,7 @@ public:
void setRequest(Request*);
- SharedBuffer* data() const { return m_data.get(); }
+ SharedBuffer* data() const { ASSERT(!m_purgeableData); return m_data.get(); }
void setResponse(const ResourceResponse&);
const ResourceResponse& response() const { return m_response; }
@@ -148,7 +153,7 @@ public:
bool errorOccurred() const { return m_errorOccurred; }
bool sendResourceLoadCallbacks() const { return m_sendResourceLoadCallbacks; }
- virtual void destroyDecodedData() {};
+ virtual void destroyDecodedData() { }
void setDocLoader(DocLoader* docLoader) { m_docLoader = docLoader; }
@@ -164,11 +169,17 @@ public:
bool isCacheValidator() const { return m_resourceToRevalidate; }
CachedResource* resourceToRevalidate() const { return m_resourceToRevalidate; }
+ bool isPurgeable() const;
+ bool wasPurged() const;
+
protected:
void setEncodedSize(unsigned);
void setDecodedSize(unsigned);
void didAccessDecodedData(double timeStamp);
+ bool makePurgeable(bool purgeable);
+ bool isSafeToMakePurgeable() const;
+
HashCountedSet<CachedResourceClient*> m_clients;
String m_url;
@@ -177,6 +188,7 @@ protected:
ResourceResponse m_response;
RefPtr<SharedBuffer> m_data;
+ OwnPtr<PurgeableBuffer> m_purgeableData;
Type m_type;
Status m_status;
diff --git a/WebCore/loader/CachedResourceClient.h b/WebCore/loader/CachedResourceClient.h
index 1d8d45e..2e0b15b 100644
--- a/WebCore/loader/CachedResourceClient.h
+++ b/WebCore/loader/CachedResourceClient.h
@@ -1,9 +1,7 @@
/*
- This file is part of the KDE libraries
-
Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
Copyright (C) 2001 Dirk Mueller <mueller@kde.org>
- Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
+ Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -56,8 +54,8 @@ namespace WebCore {
virtual ~CachedResourceClient() { }
// Called whenever a frame of an image changes, either because we got more data from the network or
- // because we are animating.
- virtual void imageChanged(CachedImage*) { };
+ // because we are animating. If not null, the IntRect is the changed rect of the image.
+ virtual void imageChanged(CachedImage*, const IntRect* = 0) { };
// Called to find out if this client wants to actually display the image. Used to tell when we
// can halt animation. Content nodes that hold image refs for example would not render the image,
diff --git a/WebCore/loader/CachedResourceClientWalker.cpp b/WebCore/loader/CachedResourceClientWalker.cpp
index 970b0e0..142a2a1 100644
--- a/WebCore/loader/CachedResourceClientWalker.cpp
+++ b/WebCore/loader/CachedResourceClientWalker.cpp
@@ -1,10 +1,8 @@
/*
- This file is part of the KDE libraries
-
Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
- Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
+ Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
diff --git a/WebCore/loader/CachedResourceClientWalker.h b/WebCore/loader/CachedResourceClientWalker.h
index 0bf98e4..d079584 100644
--- a/WebCore/loader/CachedResourceClientWalker.h
+++ b/WebCore/loader/CachedResourceClientWalker.h
@@ -1,9 +1,7 @@
/*
- This file is part of the KDE libraries
-
Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
Copyright (C) 2001 Dirk Mueller <mueller@kde.org>
- Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
+ Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
diff --git a/WebCore/loader/CachedScript.cpp b/WebCore/loader/CachedScript.cpp
index c8caea8..411521b 100644
--- a/WebCore/loader/CachedScript.cpp
+++ b/WebCore/loader/CachedScript.cpp
@@ -1,11 +1,9 @@
/*
- This file is part of the KDE libraries
-
Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
+ Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -38,6 +36,7 @@ namespace WebCore {
CachedScript::CachedScript(const String& url, const String& charset)
: CachedResource(url, Script)
, m_encoding(charset)
+ , m_decodedDataDeletionTimer(this, &CachedScript::decodedDataDeletionTimerFired)
{
// It's javascript we want.
// But some websites think their scripts are <some wrong mimetype here>
@@ -58,6 +57,11 @@ void CachedScript::addClient(CachedResourceClient* c)
c->notifyFinished(this);
}
+void CachedScript::allClientsRemoved()
+{
+ m_decodedDataDeletionTimer.startOneShot(0);
+}
+
void CachedScript::setEncoding(const String& chs)
{
TextEncoding encoding(chs);
@@ -70,6 +74,19 @@ String CachedScript::encoding() const
return m_encoding.name();
}
+const String& CachedScript::script()
+{
+ ASSERT(!isPurgeable());
+
+ if (!m_script && m_data) {
+ m_script = m_encoding.decode(m_data->data(), encodedSize());
+ setDecodedSize(m_script.length() * sizeof(UChar));
+ }
+
+ m_decodedDataDeletionTimer.startOneShot(0);
+ return m_script;
+}
+
void CachedScript::data(PassRefPtr<SharedBuffer> data, bool allDataReceived)
{
if (!allDataReceived)
@@ -77,12 +94,6 @@ void CachedScript::data(PassRefPtr<SharedBuffer> data, bool allDataReceived)
m_data = data;
setEncodedSize(m_data.get() ? m_data->size() : 0);
- if (m_data.get())
- m_script = m_encoding.decode(m_data->data(), encodedSize());
-#ifdef ANDROID_FIX // FIXME Newer webkit calls setDecodedSize in CachedScript::script(); remove on webkit update
- // report decoded size too
- setDecodedSize(m_script.length() * sizeof(UChar));
-#endif
m_loading = false;
checkNotify();
}
@@ -104,4 +115,17 @@ void CachedScript::error()
checkNotify();
}
+void CachedScript::destroyDecodedData()
+{
+ m_script = String();
+ setDecodedSize(0);
+ if (isSafeToMakePurgeable())
+ makePurgeable(true);
+}
+
+void CachedScript::decodedDataDeletionTimerFired(Timer<CachedScript>*)
+{
+ destroyDecodedData();
}
+
+} // namespace WebCore
diff --git a/WebCore/loader/CachedScript.h b/WebCore/loader/CachedScript.h
index 4580cfe..1715e06 100644
--- a/WebCore/loader/CachedScript.h
+++ b/WebCore/loader/CachedScript.h
@@ -1,10 +1,8 @@
/*
- This file is part of the KDE libraries
-
Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
Copyright (C) 2001 Dirk Mueller <mueller@kde.org>
Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
+ Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -30,6 +28,7 @@
#include "CachedResource.h"
#include "TextEncoding.h"
+#include "Timer.h"
namespace WebCore {
@@ -40,9 +39,10 @@ namespace WebCore {
CachedScript(const String& url, const String& charset);
virtual ~CachedScript();
- const String& script() const { return m_script; }
+ const String& script();
virtual void addClient(CachedResourceClient*);
+ virtual void allClientsRemoved();
virtual void setEncoding(const String&);
virtual String encoding() const;
@@ -53,9 +53,14 @@ namespace WebCore {
void checkNotify();
+ virtual void destroyDecodedData();
+
private:
+ void decodedDataDeletionTimerFired(Timer<CachedScript>*);
+
String m_script;
TextEncoding m_encoding;
+ Timer<CachedScript> m_decodedDataDeletionTimer;
};
}
diff --git a/WebCore/loader/CachedXBLDocument.cpp b/WebCore/loader/CachedXBLDocument.cpp
index 1ef3bae..0ff17f2 100644
--- a/WebCore/loader/CachedXBLDocument.cpp
+++ b/WebCore/loader/CachedXBLDocument.cpp
@@ -1,11 +1,9 @@
/*
- This file is part of the KDE libraries
-
Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
+ Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
diff --git a/WebCore/loader/CachedXBLDocument.h b/WebCore/loader/CachedXBLDocument.h
index a66a0cb..b92a255 100644
--- a/WebCore/loader/CachedXBLDocument.h
+++ b/WebCore/loader/CachedXBLDocument.h
@@ -1,10 +1,8 @@
/*
- This file is part of the KDE libraries
-
Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
Copyright (C) 2001 Dirk Mueller <mueller@kde.org>
Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
+ Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
diff --git a/WebCore/loader/CachedXSLStyleSheet.cpp b/WebCore/loader/CachedXSLStyleSheet.cpp
index 009b2af..f221664 100644
--- a/WebCore/loader/CachedXSLStyleSheet.cpp
+++ b/WebCore/loader/CachedXSLStyleSheet.cpp
@@ -1,11 +1,9 @@
/*
- This file is part of the KDE libraries
-
Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
+ Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
diff --git a/WebCore/loader/CachedXSLStyleSheet.h b/WebCore/loader/CachedXSLStyleSheet.h
index c5326fa..9eca098 100644
--- a/WebCore/loader/CachedXSLStyleSheet.h
+++ b/WebCore/loader/CachedXSLStyleSheet.h
@@ -1,10 +1,8 @@
/*
- This file is part of the KDE libraries
-
Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
Copyright (C) 2001 Dirk Mueller <mueller@kde.org>
Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
+ Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
diff --git a/WebCore/loader/DocLoader.cpp b/WebCore/loader/DocLoader.cpp
index 4dbc6a0..28bbde7 100644
--- a/WebCore/loader/DocLoader.cpp
+++ b/WebCore/loader/DocLoader.cpp
@@ -48,7 +48,6 @@ namespace WebCore {
DocLoader::DocLoader(Document* doc)
: m_cache(cache())
- , m_cachePolicy(CachePolicyVerify)
, m_doc(doc)
, m_requestCount(0)
#ifdef ANDROID_BLOCK_NETWORK_IMAGE
@@ -64,8 +63,8 @@ DocLoader::DocLoader(Document* doc)
DocLoader::~DocLoader()
{
clearPreloads();
- HashMap<String, CachedResource*>::iterator end = m_docResources.end();
- for (HashMap<String, CachedResource*>::iterator it = m_docResources.begin(); it != end; ++it)
+ DocumentResourceMap::iterator end = m_documentResources.end();
+ for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != end; ++it)
it->second->setDocLoader(0);
m_cache->removeDocLoader(this);
}
@@ -82,25 +81,36 @@ void DocLoader::checkForReload(const KURL& fullURL)
if (fullURL.isEmpty())
return;
+
+ if (m_reloadedURLs.contains(fullURL.string()))
+ return;
+
+ CachedResource* existing = cache()->resourceForURL(fullURL.string());
+ if (!existing || existing->isPreloaded())
+ return;
- if (m_cachePolicy == CachePolicyVerify || m_cachePolicy == CachePolicyCache) {
- if (!m_reloadedURLs.contains(fullURL.string())) {
- CachedResource* existing = cache()->resourceForURL(fullURL.string());
- if (existing && !existing->isPreloaded() && existing->mustRevalidate(m_cachePolicy)) {
- cache()->revalidateResource(existing, this);
- m_reloadedURLs.add(fullURL.string());
- }
- }
- } else if ((m_cachePolicy == CachePolicyReload) || (m_cachePolicy == CachePolicyRefresh)) {
- if (!m_reloadedURLs.contains(fullURL.string())) {
- CachedResource* existing = cache()->resourceForURL(fullURL.string());
- if (existing && !existing->isPreloaded()) {
- // FIXME: Use revalidateResource() to implement HTTP 1.1 "Specific end-to-end revalidation" for regular reloading
- cache()->remove(existing);
- m_reloadedURLs.add(fullURL.string());
- }
- }
+ switch (cachePolicy()) {
+ case CachePolicyVerify:
+ if (!existing->mustRevalidate(CachePolicyVerify))
+ return;
+ cache()->revalidateResource(existing, this);
+ break;
+ case CachePolicyCache:
+ if (!existing->mustRevalidate(CachePolicyCache))
+ return;
+ cache()->revalidateResource(existing, this);
+ break;
+ case CachePolicyReload:
+ cache()->remove(existing);
+ break;
+ case CachePolicyRevalidate:
+ cache()->revalidateResource(existing, this);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
}
+
+ m_reloadedURLs.add(fullURL.string());
}
CachedImage* DocLoader::requestImage(const String& url)
@@ -189,21 +199,18 @@ CachedResource* DocLoader::requestResource(CachedResource::Type type, const Stri
{
KURL fullURL = m_doc->completeURL(url);
- if (!canRequest(type, fullURL))
+ if (!fullURL.isValid() || !canRequest(type, fullURL))
return 0;
if (cache()->disabled()) {
- HashMap<String, CachedResource*>::iterator it = m_docResources.find(fullURL.string());
+ DocumentResourceMap::iterator it = m_documentResources.find(fullURL.string());
- if (it != m_docResources.end()) {
+ if (it != m_documentResources.end()) {
it->second->setDocLoader(0);
- m_docResources.remove(it);
+ m_documentResources.remove(it);
}
}
- if (frame() && frame()->loader()->isReloading())
- setCachePolicy(CachePolicyReload);
-
checkForReload(fullURL);
CachedResource* resource = cache()->requestResource(this, type, fullURL, charset, isPreload);
if (resource) {
@@ -212,7 +219,7 @@ CachedResource* DocLoader::requestResource(CachedResource::Type type, const Stri
if (!canRequest(type, KURL(resource->url())))
return 0;
- m_docResources.set(resource->url(), resource);
+ m_documentResources.set(resource->url(), resource);
checkCacheObjectStatus(resource);
}
return resource;
@@ -252,9 +259,9 @@ void DocLoader::setAutoLoadImages(bool enable)
if (!m_autoLoadImages)
return;
- HashMap<String, CachedResource*>::iterator end = m_docResources.end();
- for (HashMap<String, CachedResource*>::iterator it = m_docResources.begin(); it != end; ++it) {
- CachedResource* resource = it->second;
+ DocumentResourceMap::iterator end = m_documentResources.end();
+ for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != end; ++it) {
+ CachedResource* resource = it->second.get();
if (resource->type() == CachedResource::ImageResource) {
CachedImage* image = const_cast<CachedImage*>(static_cast<const CachedImage*>(resource));
#ifdef ANDROID_BLOCK_NETWORK_IMAGE
@@ -291,9 +298,9 @@ void DocLoader::setBlockNetworkImage(bool block)
if (!m_autoLoadImages || m_blockNetworkImage)
return;
- HashMap<String, CachedResource*>::iterator end = m_docResources.end();
- for (HashMap<String, CachedResource*>::iterator it = m_docResources.begin(); it != end; ++it) {
- CachedResource* resource = it->second;
+ DocumentResourceMap::iterator end = m_documentResources.end();
+ for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != end; ++it) {
+ CachedResource* resource = it->second.get();
if (resource->type() == CachedResource::ImageResource) {
CachedImage* image = const_cast<CachedImage*>(static_cast<const CachedImage*>(resource));
if (image->stillNeedsLoad())
@@ -303,14 +310,14 @@ void DocLoader::setBlockNetworkImage(bool block)
}
#endif
-void DocLoader::setCachePolicy(CachePolicy cachePolicy)
+CachePolicy DocLoader::cachePolicy() const
{
- m_cachePolicy = cachePolicy;
+ return frame() ? frame()->loader()->cachePolicy() : CachePolicyVerify;
}
void DocLoader::removeCachedResource(CachedResource* resource) const
{
- m_docResources.remove(resource->url());
+ m_documentResources.remove(resource->url());
}
void DocLoader::setLoadInProgress(bool load)
diff --git a/WebCore/loader/DocLoader.h b/WebCore/loader/DocLoader.h
index 407d85a..b87b622 100644
--- a/WebCore/loader/DocLoader.h
+++ b/WebCore/loader/DocLoader.h
@@ -26,6 +26,7 @@
#define DocLoader_h
#include "CachedResource.h"
+#include "CachedResourceHandle.h"
#include "CachePolicy.h"
#include "StringHash.h"
#include <wtf/HashMap.h>
@@ -70,8 +71,10 @@ public:
// Logs an access denied message to the console for the specified URL.
void printAccessDeniedMessage(const KURL& url) const;
- CachedResource* cachedResource(const String& url) const { return m_docResources.get(url); }
- const HashMap<String, CachedResource*>& allCachedResources() const { return m_docResources; }
+ CachedResource* cachedResource(const String& url) const { return m_documentResources.get(url).get(); }
+
+ typedef HashMap<String, CachedResourceHandle<CachedResource> > DocumentResourceMap;
+ const DocumentResourceMap& allCachedResources() const { return m_documentResources; }
bool autoLoadImages() const { return m_autoLoadImages; }
void setAutoLoadImages(bool);
@@ -82,8 +85,7 @@ public:
bool shouldBlockNetworkImage(const String& url) const;
#endif
- CachePolicy cachePolicy() const { return m_cachePolicy; }
- void setCachePolicy(CachePolicy);
+ CachePolicy cachePolicy() const;
Frame* frame() const; // Can be NULL
Document* doc() const { return m_doc; }
@@ -118,8 +120,7 @@ private:
Cache* m_cache;
HashSet<String> m_reloadedURLs;
- mutable HashMap<String, CachedResource*> m_docResources;
- CachePolicy m_cachePolicy;
+ mutable DocumentResourceMap m_documentResources;
Document* m_doc;
int m_requestCount;
diff --git a/WebCore/loader/DocumentLoader.cpp b/WebCore/loader/DocumentLoader.cpp
index d9d99ea..12be864 100644
--- a/WebCore/loader/DocumentLoader.cpp
+++ b/WebCore/loader/DocumentLoader.cpp
@@ -99,9 +99,6 @@ static inline String canonicalizedTitle(const String& title, Frame* frame)
continue;
buffer[builderIndex++] = ' ';
previousCharWasWS = true;
- } else if (c == '\\') {
- buffer[builderIndex++] = frame->backslashAsCurrencySymbol();
- previousCharWasWS = false;
} else {
buffer[builderIndex++] = c;
previousCharWasWS = false;
@@ -119,6 +116,11 @@ static inline String canonicalizedTitle(const String& title, Frame* frame)
return "";
buffer.shrink(builderIndex + 1);
+
+ // Replace the backslashes with currency symbols if the encoding requires it.
+ if (frame->document())
+ frame->document()->displayBufferModifiedByEncoding(buffer.characters(), buffer.length());
+
return String::adopt(buffer);
}
@@ -154,6 +156,7 @@ DocumentLoader::DocumentLoader(const ResourceRequest& req, const SubstituteData&
, m_loadingFromCachedPage(false)
, m_stopRecordingResponses(false)
, m_substituteResourceDeliveryTimer(this, &DocumentLoader::substituteResourceDeliveryTimerFired)
+ , m_urlForHistoryReflectsClientRedirect(false)
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
, m_candidateApplicationCacheGroup(0)
#endif
@@ -173,9 +176,9 @@ DocumentLoader::~DocumentLoader()
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
if (m_applicationCache)
- m_applicationCache->group()->documentLoaderDestroyed(this);
+ m_applicationCache->group()->disassociateDocumentLoader(this);
else if (m_candidateApplicationCacheGroup)
- m_candidateApplicationCacheGroup->documentLoaderDestroyed(this);
+ m_candidateApplicationCacheGroup->disassociateDocumentLoader(this);
#endif
}
@@ -257,10 +260,14 @@ void DocumentLoader::clearErrors()
void DocumentLoader::mainReceivedError(const ResourceError& error, bool isComplete)
{
+ ASSERT(!error.isNull());
+
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
ApplicationCacheGroup* group = m_candidateApplicationCacheGroup;
- if (!group && m_applicationCache && !mainResourceApplicationCache())
+ 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);
@@ -452,7 +459,9 @@ void DocumentLoader::setPrimaryLoadComplete(bool flag)
#endif
m_mainResourceLoader = 0;
}
- updateLoading();
+
+ if (this == frameLoader()->activeDocumentLoader())
+ updateLoading();
}
}
@@ -569,9 +578,9 @@ void DocumentLoader::getSubresources(Vector<PassRefPtr<ArchiveResource> >& subre
if (!document)
return;
- const HashMap<String, CachedResource*>& allResources = document->docLoader()->allCachedResources();
- HashMap<String, CachedResource*>::const_iterator end = allResources.end();
- for (HashMap<String, CachedResource*>::const_iterator it = allResources.begin(); it != end; ++it) {
+ const DocLoader::DocumentResourceMap& allResources = document->docLoader()->allCachedResources();
+ DocLoader::DocumentResourceMap::const_iterator end = allResources.end();
+ for (DocLoader::DocumentResourceMap::const_iterator it = allResources.begin(); it != end; ++it) {
RefPtr<ArchiveResource> subresource = this->subresource(KURL(it->second->url()));
if (subresource)
subresources.append(subresource.release());
@@ -696,6 +705,11 @@ KURL DocumentLoader::urlForHistory() const
return m_originalRequestCopy.url();
}
+bool DocumentLoader::urlForHistoryReflectsFailure() const
+{
+ return m_substituteData.isValid() || m_response.httpStatusCode() >= 400;
+}
+
void DocumentLoader::loadFromCachedPage(PassRefPtr<CachedPage> cachedPage)
{
LOG(PageCache, "WebCorePageCache: DocumentLoader %p loading from cached page %p", this, cachedPage.get());
@@ -805,7 +819,7 @@ bool DocumentLoader::startLoadingMainResource(unsigned long identifier)
// FIXME: Is there any way the extra fields could have not been added by now?
// If not, it would be great to remove this line of code.
- frameLoader()->addExtraFieldsToRequest(m_request, true, false);
+ frameLoader()->addExtraFieldsToMainResourceRequest(m_request);
if (!m_mainResourceLoader->load(m_request, m_substituteData)) {
// FIXME: If this should really be caught, we should just ASSERT this doesn't happen;
@@ -855,20 +869,6 @@ void DocumentLoader::setApplicationCache(PassRefPtr<ApplicationCache> applicatio
m_applicationCache = applicationCache;
}
-ApplicationCache* DocumentLoader::topLevelApplicationCache() const
-{
- if (!m_frame)
- return 0;
-
- if (m_applicationCache)
- return m_applicationCache.get();
-
- if (Page* page = m_frame->page())
- return page->mainFrame()->loader()->documentLoader()->applicationCache();
-
- return 0;
-}
-
ApplicationCache* DocumentLoader::mainResourceApplicationCache() const
{
if (m_mainResourceApplicationCache)
@@ -880,23 +880,49 @@ ApplicationCache* DocumentLoader::mainResourceApplicationCache() const
bool DocumentLoader::shouldLoadResourceFromApplicationCache(const ResourceRequest& request, ApplicationCacheResource*& resource)
{
- ApplicationCache* cache = topLevelApplicationCache();
- if (!cache)
+ ApplicationCache* cache = applicationCache();
+ if (!cache || !cache->isComplete())
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;
-
+
+ // 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;
+}
+
+bool DocumentLoader::getApplicationCacheFallbackResource(const ResourceRequest& request, ApplicationCacheResource*& resource, ApplicationCache* cache)
+{
+ if (!cache) {
+ cache = applicationCache();
+ if (!cache)
+ return false;
+ }
+ if (!cache->isComplete())
+ return false;
- // Don't load foreign resources.
- if (resource && (resource->type() & ApplicationCacheResource::Foreign))
- resource = 0;
-
+ // If the resource is not a HTTP/HTTPS GET, then abort
+ if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request))
+ return false;
+
+ KURL fallbackURL;
+ if (!cache->urlMatchesFallbackNamespace(request.url(), &fallbackURL))
+ return false;
+
+ resource = cache->resourceForURL(fallbackURL);
+ ASSERT(resource);
+
return true;
}
@@ -910,7 +936,6 @@ bool DocumentLoader::scheduleApplicationCacheLoad(ResourceLoader* loader, const
ApplicationCacheResource* resource;
if (!shouldLoadResourceFromApplicationCache(request, resource))
- // FIXME: Handle opportunistic caching namespaces
return false;
m_pendingSubstituteResources.set(loader, resource);
@@ -919,6 +944,21 @@ bool DocumentLoader::scheduleApplicationCacheLoad(ResourceLoader* loader, const
return true;
}
+bool DocumentLoader::scheduleLoadFallbackResourceFromApplicationCache(ResourceLoader* loader, const ResourceRequest& request, ApplicationCache* cache)
+{
+ if (!frameLoader()->frame()->settings() || !frameLoader()->frame()->settings()->offlineWebApplicationCacheEnabled())
+ return false;
+
+ ApplicationCacheResource* resource;
+ if (!getApplicationCacheFallbackResource(request, resource, cache))
+ return false;
+
+ m_pendingSubstituteResources.set(loader, resource);
+ deliverSubstituteResourcesAfterDelay();
+
+ return true;
+}
+
#endif // ENABLE(OFFLINE_WEB_APPLICATIONS)
}
diff --git a/WebCore/loader/DocumentLoader.h b/WebCore/loader/DocumentLoader.h
index aef4f49..85cceef 100644
--- a/WebCore/loader/DocumentLoader.h
+++ b/WebCore/loader/DocumentLoader.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 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
@@ -29,25 +29,18 @@
#ifndef DocumentLoader_h
#define DocumentLoader_h
-#include "IconDatabase.h"
#include "NavigationAction.h"
-#include <wtf/RefCounted.h>
-#include "PlatformString.h"
#include "ResourceError.h"
#include "ResourceRequest.h"
#include "ResourceResponse.h"
#include "SubstituteData.h"
-#include <wtf/HashSet.h>
-#include <wtf/RefPtr.h>
-#include <wtf/Vector.h>
+#include "Timer.h"
namespace WebCore {
-#if ENABLE(OFFLINE_WEB_APPLICATIONS)
class ApplicationCache;
class ApplicationCacheGroup;
class ApplicationCacheResource;
-#endif
#if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size
class Archive;
class ArchiveResource;
@@ -56,13 +49,10 @@ namespace WebCore {
class CachedPage;
class Frame;
class FrameLoader;
- class HistoryItem;
- class KURL;
class MainResourceLoader;
class ResourceLoader;
class SchedulePair;
class SharedBuffer;
- class SubstituteData;
class SubstituteResource;
typedef HashSet<RefPtr<ResourceLoader> > ResourceLoaderSet;
@@ -167,7 +157,12 @@ namespace WebCore {
void stopRecordingResponses();
const String& title() const { return m_pageTitle; }
+
KURL urlForHistory() const;
+ bool urlForHistoryReflectsFailure() const;
+ bool urlForHistoryReflectsServerRedirect() const { return urlForHistory() != url(); }
+ bool urlForHistoryReflectsClientRedirect() const { return m_urlForHistoryReflectsClientRedirect; }
+ void setURLForHistoryReflectsClientRedirect(bool b) { m_urlForHistoryReflectsClientRedirect = b; }
void loadFromCachedPage(PassRefPtr<CachedPage>);
void setLoadingFromCachedPage(bool loading) { m_loadingFromCachedPage = loading; }
@@ -198,16 +193,22 @@ namespace WebCore {
void setDeferMainResourceDataLoad(bool defer) { m_deferMainResourceDataLoad = defer; }
bool deferMainResourceDataLoad() const { return m_deferMainResourceDataLoad; }
+ void didTellClientAboutLoad(const String& url) { m_resourcesClientKnowsAbout.add(url); }
+ bool haveToldClientAboutLoad(const String& url) { return m_resourcesClientKnowsAbout.contains(url); }
+ void recordMemoryCacheLoadForFutureClientNotification(const String& url);
+ void takeMemoryCacheLoadsForClientNotification(Vector<String>& loads);
+
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
bool scheduleApplicationCacheLoad(ResourceLoader*, const ResourceRequest&, const KURL& originalURL);
+ bool scheduleLoadFallbackResourceFromApplicationCache(ResourceLoader*, const ResourceRequest&, ApplicationCache* = 0);
bool shouldLoadResourceFromApplicationCache(const ResourceRequest&, ApplicationCacheResource*&);
+ bool getApplicationCacheFallbackResource(const ResourceRequest&, ApplicationCacheResource*&, ApplicationCache* = 0);
void setCandidateApplicationCacheGroup(ApplicationCacheGroup* group);
ApplicationCacheGroup* candidateApplicationCacheGroup() const { return m_candidateApplicationCacheGroup; }
void setApplicationCache(PassRefPtr<ApplicationCache> applicationCache);
ApplicationCache* applicationCache() const { return m_applicationCache.get(); }
- ApplicationCache* topLevelApplicationCache() const;
ApplicationCache* mainResourceApplicationCache() const;
#endif
@@ -292,7 +293,12 @@ namespace WebCore {
OwnPtr<ArchiveResourceCollection> m_archiveResourceCollection;
RefPtr<SharedBuffer> m_parsedArchiveData;
#endif
+
+ HashSet<String> m_resourcesClientKnowsAbout;
+ Vector<String> m_resourcesLoadedFromMemoryCacheForClientNotification;
+ bool m_urlForHistoryReflectsClientRedirect;
+
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
// The application cache that the document loader is associated with (if any).
RefPtr<ApplicationCache> m_applicationCache;
@@ -306,6 +312,17 @@ namespace WebCore {
#endif
};
+ inline void DocumentLoader::recordMemoryCacheLoadForFutureClientNotification(const String& url)
+ {
+ m_resourcesLoadedFromMemoryCacheForClientNotification.append(url);
+ }
+
+ inline void DocumentLoader::takeMemoryCacheLoadsForClientNotification(Vector<String>& loadsSet)
+ {
+ loadsSet.swap(m_resourcesLoadedFromMemoryCacheForClientNotification);
+ m_resourcesLoadedFromMemoryCacheForClientNotification.clear();
+ }
+
}
#endif // DocumentLoader_h
diff --git a/WebCore/loader/DocumentThreadableLoader.cpp b/WebCore/loader/DocumentThreadableLoader.cpp
new file mode 100644
index 0000000..05f8667
--- /dev/null
+++ b/WebCore/loader/DocumentThreadableLoader.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2009, Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT
+ * OWNER 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 "DocumentThreadableLoader.h"
+
+#include "AuthenticationChallenge.h"
+#include "Document.h"
+#include "ResourceRequest.h"
+#include "SecurityOrigin.h"
+#include "SubresourceLoader.h"
+#include "ThreadableLoaderClient.h"
+
+namespace WebCore {
+
+PassRefPtr<DocumentThreadableLoader> DocumentThreadableLoader::create(Document* document, ThreadableLoaderClient* client, const ResourceRequest& request, LoadCallbacks callbacksSetting, ContentSniff contentSniff)
+{
+ RefPtr<DocumentThreadableLoader> loader = adoptRef(new DocumentThreadableLoader(document, client, request, callbacksSetting, contentSniff));
+ if (!loader->m_loader)
+ loader = 0;
+ return loader.release();
+}
+
+DocumentThreadableLoader::DocumentThreadableLoader(Document* document, ThreadableLoaderClient* client, const ResourceRequest& request, LoadCallbacks callbacksSetting, ContentSniff contentSniff)
+ : m_client(client)
+ , m_document(document)
+{
+ ASSERT(document);
+ ASSERT(client);
+ m_loader = SubresourceLoader::create(document->frame(), this, request, false, callbacksSetting == SendLoadCallbacks, contentSniff == SniffContent);
+}
+
+DocumentThreadableLoader::~DocumentThreadableLoader()
+{
+ if (m_loader)
+ m_loader->clearClient();
+}
+
+void DocumentThreadableLoader::cancel()
+{
+ if (!m_loader)
+ return;
+
+ m_loader->cancel();
+ m_loader->clearClient();
+ m_loader = 0;
+ m_client = 0;
+}
+
+void DocumentThreadableLoader::willSendRequest(SubresourceLoader*, ResourceRequest& request, const ResourceResponse&)
+{
+ ASSERT(m_client);
+
+ // FIXME: This needs to be fixed to follow the redirect correctly even for cross-domain requests.
+ if (!m_document->securityOrigin()->canRequest(request.url())) {
+ RefPtr<DocumentThreadableLoader> protect(this);
+ m_client->didFail();
+ cancel();
+ }
+}
+
+void DocumentThreadableLoader::didSendData(SubresourceLoader*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
+{
+ ASSERT(m_client);
+ m_client->didSendData(bytesSent, totalBytesToBeSent);
+}
+
+void DocumentThreadableLoader::didReceiveResponse(SubresourceLoader*, const ResourceResponse& response)
+{
+ ASSERT(m_client);
+ m_client->didReceiveResponse(response);
+}
+
+void DocumentThreadableLoader::didReceiveData(SubresourceLoader*, const char* data, int lengthReceived)
+{
+ ASSERT(m_client);
+ m_client->didReceiveData(data, lengthReceived);
+}
+
+void DocumentThreadableLoader::didFinishLoading(SubresourceLoader* loader)
+{
+ ASSERT(loader);
+ ASSERT(m_client);
+ m_client->didFinishLoading(loader->identifier());
+}
+
+void DocumentThreadableLoader::didFail(SubresourceLoader*, const ResourceError& error)
+{
+ ASSERT(m_client);
+ if (error.isCancellation())
+ m_client->didGetCancelled();
+ else
+ m_client->didFail();
+}
+
+void DocumentThreadableLoader::receivedCancellation(SubresourceLoader*, const AuthenticationChallenge& challenge)
+{
+ ASSERT(m_client);
+ m_client->didReceiveAuthenticationCancellation(challenge.failureResponse());
+}
+
+} // namespace WebCore
diff --git a/WebCore/loader/DocumentThreadableLoader.h b/WebCore/loader/DocumentThreadableLoader.h
new file mode 100644
index 0000000..d909091
--- /dev/null
+++ b/WebCore/loader/DocumentThreadableLoader.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2009, Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#ifndef DocumentThreadableLoader_h
+#define DocumentThreadableLoader_h
+
+#include "SubresourceLoaderClient.h"
+#include "ThreadableLoader.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+ class Document;
+ class ResourceRequest;
+ class ThreadableLoaderClient;
+
+ class DocumentThreadableLoader : public RefCounted<DocumentThreadableLoader>, public ThreadableLoader, private SubresourceLoaderClient {
+ public:
+ static PassRefPtr<DocumentThreadableLoader> create(Document*, ThreadableLoaderClient*, const ResourceRequest&, LoadCallbacks, ContentSniff);
+ virtual ~DocumentThreadableLoader();
+
+ virtual void cancel();
+
+ using RefCounted<DocumentThreadableLoader>::ref;
+ using RefCounted<DocumentThreadableLoader>::deref;
+
+ protected:
+ virtual void refThreadableLoader() { ref(); }
+ virtual void derefThreadableLoader() { deref(); }
+
+ private:
+ DocumentThreadableLoader(Document*, ThreadableLoaderClient*, const ResourceRequest&, LoadCallbacks, ContentSniff);
+ virtual void willSendRequest(SubresourceLoader*, ResourceRequest&, const ResourceResponse& redirectResponse);
+ virtual void didSendData(SubresourceLoader*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent);
+
+ virtual void didReceiveResponse(SubresourceLoader*, const ResourceResponse&);
+ virtual void didReceiveData(SubresourceLoader*, const char*, int lengthReceived);
+ virtual void didFinishLoading(SubresourceLoader*);
+ virtual void didFail(SubresourceLoader*, const ResourceError&);
+
+ virtual void receivedCancellation(SubresourceLoader*, const AuthenticationChallenge&);
+
+ RefPtr<SubresourceLoader> m_loader;
+ ThreadableLoaderClient* m_client;
+ Document* m_document;
+ };
+
+} // namespace WebCore
+
+#endif // DocumentThreadableLoader_h
diff --git a/WebCore/loader/EmptyClients.h b/WebCore/loader/EmptyClients.h
index 8cab747..1a412f7 100644
--- a/WebCore/loader/EmptyClients.h
+++ b/WebCore/loader/EmptyClients.h
@@ -92,16 +92,16 @@ public:
virtual void setResizable(bool) { }
- virtual void addMessageToConsole(const String& message, unsigned int lineNumber, const String& sourceID) { }
+ virtual void addMessageToConsole(const String&, unsigned, const String&) { }
virtual bool canRunBeforeUnloadConfirmPanel() { return false; }
- virtual bool runBeforeUnloadConfirmPanel(const String& message, Frame* frame) { return true; }
+ virtual bool runBeforeUnloadConfirmPanel(const String&, Frame*) { return true; }
virtual void closeWindowSoon() { }
virtual void runJavaScriptAlert(Frame*, const String&) { }
virtual bool runJavaScriptConfirm(Frame*, const String&) { return false; }
- virtual bool runJavaScriptPrompt(Frame*, const String& message, const String& defaultValue, String& result) { return false; }
+ virtual bool runJavaScriptPrompt(Frame*, const String&, const String&, String&) { return false; }
virtual bool shouldInterruptJavaScript() { return false; }
virtual void setStatusbarText(const String&) { }
@@ -110,16 +110,17 @@ public:
virtual IntRect windowResizerRect() const { return IntRect(); }
virtual void addToDirtyRegion(const IntRect&) { }
- virtual void scrollBackingStore(int dx, int dy, const IntRect& scrollViewRect, const IntRect& clipRect) { }
+ virtual void scrollBackingStore(int, int, const IntRect&, const IntRect&) { }
virtual void updateBackingStore() { }
- virtual void repaint(const IntRect&, bool contentChanged, bool immediate = false, bool repaintContentOnly = false) { }
- virtual void scroll(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect) { }
+ virtual void repaint(const IntRect&, bool, bool, bool) { }
+ virtual void scroll(const IntSize&, const IntRect&, const IntRect&) { }
virtual IntPoint screenToWindow(const IntPoint& p) const { return p; }
virtual IntRect windowToScreen(const IntRect& r) const { return r; }
virtual PlatformWidget platformWindow() const { return 0; }
+ virtual void contentsSizeChanged(Frame*, const IntSize&) const { }
- virtual void mouseDidMoveOverElement(const HitTestResult&, unsigned modifierFlags) { }
+ virtual void mouseDidMoveOverElement(const HitTestResult&, unsigned) { }
virtual void setToolTip(const String&) { }
@@ -128,6 +129,8 @@ public:
virtual void exceededDatabaseQuota(Frame*, const String&) { }
virtual void runOpenPanel(Frame*, PassRefPtr<FileChooser>) { }
+
+ virtual void formStateDidChange(const Node*) { }
};
class EmptyFrameLoaderClient : public FrameLoaderClient {
@@ -141,15 +144,6 @@ public:
virtual void forceLayout() { }
virtual void forceLayoutForNonHTML() { }
- virtual void updateHistoryForCommit() { }
-
- virtual void updateHistoryForBackForwardNavigation() { }
- virtual void updateHistoryForReload() { }
- virtual void updateHistoryForStandardLoad() { }
- virtual void updateHistoryForInternalLoad() { }
-
- virtual void updateHistoryAfterClientRedirect() { }
-
virtual void setCopiesOnScroll() { }
virtual void detachedFromParent2() { }
@@ -157,37 +151,39 @@ public:
virtual void download(ResourceHandle*, const ResourceRequest&, const ResourceRequest&, const ResourceResponse&) { }
- virtual void assignIdentifierToInitialRequest(unsigned long identifier, DocumentLoader*, const ResourceRequest&) { }
- virtual void dispatchWillSendRequest(DocumentLoader*, unsigned long identifier, ResourceRequest&, const ResourceResponse& redirectResponse) { }
- virtual void dispatchDidReceiveAuthenticationChallenge(DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&) { }
- virtual void dispatchDidCancelAuthenticationChallenge(DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&) { }
- virtual void dispatchDidReceiveResponse(DocumentLoader*, unsigned long identifier, const ResourceResponse&) { }
- virtual void dispatchDidReceiveContentLength(DocumentLoader*, unsigned long identifier, int lengthReceived) { }
- virtual void dispatchDidFinishLoading(DocumentLoader*, unsigned long identifier) { }
- virtual void dispatchDidFailLoading(DocumentLoader*, unsigned long identifier, const ResourceError&) { }
- virtual bool dispatchDidLoadResourceFromMemoryCache(DocumentLoader*, const ResourceRequest&, const ResourceResponse&, int length) { return false; }
+ virtual void assignIdentifierToInitialRequest(unsigned long, DocumentLoader*, const ResourceRequest&) { }
+ virtual bool shouldUseCredentialStorage(DocumentLoader*, unsigned long) { return false; }
+ virtual void dispatchWillSendRequest(DocumentLoader*, unsigned long, ResourceRequest&, const ResourceResponse&) { }
+ virtual void dispatchDidReceiveAuthenticationChallenge(DocumentLoader*, unsigned long, const AuthenticationChallenge&) { }
+ virtual void dispatchDidCancelAuthenticationChallenge(DocumentLoader*, unsigned long, const AuthenticationChallenge&) { }
+ virtual void dispatchDidReceiveResponse(DocumentLoader*, unsigned long, const ResourceResponse&) { }
+ virtual void dispatchDidReceiveContentLength(DocumentLoader*, unsigned long, int) { }
+ virtual void dispatchDidFinishLoading(DocumentLoader*, unsigned long) { }
+ virtual void dispatchDidFailLoading(DocumentLoader*, unsigned long, const ResourceError&) { }
+ virtual bool dispatchDidLoadResourceFromMemoryCache(DocumentLoader*, const ResourceRequest&, const ResourceResponse&, int) { return false; }
virtual void dispatchDidHandleOnloadEvents() { }
virtual void dispatchDidReceiveServerRedirectForProvisionalLoad() { }
virtual void dispatchDidCancelClientRedirect() { }
- virtual void dispatchWillPerformClientRedirect(const KURL&, double interval, double fireDate) { }
+ virtual void dispatchWillPerformClientRedirect(const KURL&, double, double) { }
virtual void dispatchDidChangeLocationWithinPage() { }
virtual void dispatchWillClose() { }
virtual void dispatchDidReceiveIcon() { }
virtual void dispatchDidStartProvisionalLoad() { }
- virtual void dispatchDidReceiveTitle(const String& title) { }
+ virtual void dispatchDidReceiveTitle(const String&) { }
virtual void dispatchDidCommitLoad() { }
virtual void dispatchDidFailProvisionalLoad(const ResourceError&) { }
virtual void dispatchDidFailLoad(const ResourceError&) { }
virtual void dispatchDidFinishDocumentLoad() { }
virtual void dispatchDidFinishLoad() { }
virtual void dispatchDidFirstLayout() { }
+ virtual void dispatchDidFirstVisuallyNonEmptyLayout() { }
virtual Frame* dispatchCreatePage() { return 0; }
virtual void dispatchShow() { }
- virtual void dispatchDecidePolicyForMIMEType(FramePolicyFunction, const String& MIMEType, const ResourceRequest&) { }
- virtual void dispatchDecidePolicyForNewWindowAction(FramePolicyFunction, const NavigationAction&, const ResourceRequest&, PassRefPtr<FormState>, const String& frameName) { }
+ virtual void dispatchDecidePolicyForMIMEType(FramePolicyFunction, const String&, const ResourceRequest&) { }
+ virtual void dispatchDecidePolicyForNewWindowAction(FramePolicyFunction, const NavigationAction&, const ResourceRequest&, PassRefPtr<FormState>, const String&) { }
virtual void dispatchDecidePolicyForNavigationAction(FramePolicyFunction, const NavigationAction&, const ResourceRequest&, PassRefPtr<FormState>) { }
virtual void cancelPolicyCheck() { }
@@ -227,48 +223,47 @@ public:
virtual bool shouldFallBack(const ResourceError&) { return false; }
virtual bool canHandleRequest(const ResourceRequest&) const { return false; }
- virtual bool canShowMIMEType(const String& MIMEType) const { return false; }
- virtual bool representationExistsForURLScheme(const String& URLScheme) const { return false; }
- virtual String generatedMIMETypeForURLScheme(const String& URLScheme) const { return ""; }
+ virtual bool canShowMIMEType(const String&) const { return false; }
+ virtual bool representationExistsForURLScheme(const String&) const { return false; }
+ virtual String generatedMIMETypeForURLScheme(const String&) const { return ""; }
virtual void frameLoadCompleted() { }
virtual void restoreViewState() { }
virtual void provisionalLoadStarted() { }
virtual bool shouldTreatURLAsSameAsCurrent(const KURL&) const { return false; }
- virtual void addHistoryItemForFragmentScroll() { }
virtual void didFinishLoad() { }
virtual void prepareForDataSourceReplacement() { }
virtual PassRefPtr<DocumentLoader> createDocumentLoader(const ResourceRequest& request, const SubstituteData& substituteData) { return DocumentLoader::create(request, substituteData); }
- virtual void setTitle(const String& title, const KURL&) { }
+ virtual void setTitle(const String&, const KURL&) { }
virtual String userAgent(const KURL&) { return ""; }
- virtual void savePlatformDataToCachedPage(CachedPage*) { }
- virtual void transitionToCommittedFromCachedPage(CachedPage*) { }
+ virtual void savePlatformDataToCachedFrame(CachedFrame*) { }
+ virtual void transitionToCommittedFromCachedFrame(CachedFrame*) { }
virtual void transitionToCommittedForNewPage() { }
- virtual void updateGlobalHistory(const KURL&) { }
+ virtual void updateGlobalHistory() { }
+ virtual void updateGlobalHistoryForRedirectWithoutHistoryItem() { }
virtual bool shouldGoToHistoryItem(HistoryItem*) const { return false; }
virtual void saveViewStateToItem(HistoryItem*) { }
virtual bool canCachePage() const { return false; }
- virtual PassRefPtr<Frame> createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement,
- const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight) { return 0; }
- virtual Widget* createPlugin(const IntSize&,Element*, const KURL&, const Vector<String>&, const Vector<String>&, const String&, bool) { return 0; }
+ virtual PassRefPtr<Frame> createFrame(const KURL&, const String&, HTMLFrameOwnerElement*, const String&, bool, int, int) { return 0; }
+ virtual Widget* createPlugin(const IntSize&, Element*, const KURL&, const Vector<String>&, const Vector<String>&, const String&, bool) { return 0; }
virtual Widget* createJavaAppletWidget(const IntSize&, Element*, const KURL&, const Vector<String>&, const Vector<String>&) { return 0; }
- virtual ObjectContentType objectContentType(const KURL& url, const String& mimeType) { return ObjectContentType(); }
+ virtual ObjectContentType objectContentType(const KURL&, const String&) { return ObjectContentType(); }
virtual String overrideMediaType() const { return String(); }
- virtual void redirectDataToPlugin(Widget*) {}
- virtual void windowObjectCleared() {}
- virtual void didPerformFirstNavigation() const {}
+ virtual void redirectDataToPlugin(Widget*) { }
+ virtual void windowObjectCleared() { }
+ virtual void didPerformFirstNavigation() const { }
- virtual void registerForIconNotification(bool listen) {}
+ virtual void registerForIconNotification(bool) { }
#if PLATFORM(MAC)
- virtual NSCachedURLResponse* willCacheResponse(DocumentLoader*, unsigned long identifier, NSCachedURLResponse* response) const { return response; }
+ virtual NSCachedURLResponse* willCacheResponse(DocumentLoader*, unsigned long, NSCachedURLResponse* response) const { return response; }
#endif
};
@@ -281,6 +276,7 @@ public:
virtual bool shouldDeleteRange(Range*) { return false; }
virtual bool shouldShowDeleteInterface(HTMLElement*) { return false; }
virtual bool smartInsertDeleteEnabled() { return false; }
+ virtual bool isSelectTrailingWhitespaceEnabled() { return false; }
virtual bool isContinuousSpellCheckingEnabled() { return false; }
virtual void toggleContinuousSpellChecking() { }
virtual bool isGrammarCheckingEnabled() { return false; }
@@ -295,7 +291,7 @@ public:
virtual bool shouldInsertNode(Node*, Range*, EditorInsertAction) { return false; }
// virtual bool shouldInsertNode(Node*, Range* replacingRange, WebViewInsertAction) { return false; }
virtual bool shouldInsertText(const String&, Range*, EditorInsertAction) { return false; }
- virtual bool shouldChangeSelectedRange(Range* fromRange, Range* toRange, EAffinity, bool stillSelecting) { return false; }
+ virtual bool shouldChangeSelectedRange(Range*, Range*, EAffinity, bool) { return false; }
virtual bool shouldApplyStyle(CSSStyleDeclaration*, Range*) { return false; }
virtual bool shouldMoveRangeAfterDelete(Range*, Range*) { return false; }
@@ -342,14 +338,14 @@ public:
#endif
virtual void ignoreWordInSpellDocument(const String&) { }
virtual void learnWord(const String&) { }
- virtual void checkSpellingOfString(const UChar*, int length, int* misspellingLocation, int* misspellingLength) { }
- virtual void checkGrammarOfString(const UChar*, int length, Vector<GrammarDetail>&, int* badGrammarLocation, int* badGrammarLength) { }
+ virtual void checkSpellingOfString(const UChar*, int, int*, int*) { }
+ virtual void checkGrammarOfString(const UChar*, int, Vector<GrammarDetail>&, int*, int*) { }
virtual void updateSpellingUIWithGrammarString(const String&, const GrammarDetail&) { }
virtual void updateSpellingUIWithMisspelledWord(const String&) { }
- virtual void showSpellingUI(bool show) { }
+ virtual void showSpellingUI(bool) { }
virtual bool spellingUIIsShowing() { return false; }
- virtual void getGuessesForWord(const String&, Vector<String>& guesses) { }
- virtual void setInputMethodState(bool enabled) { }
+ virtual void getGuessesForWord(const String&, Vector<String>&) { }
+ virtual void setInputMethodState(bool) { }
};
@@ -362,7 +358,7 @@ public:
virtual PlatformMenuDescription getCustomMenuFromDefaultItems(ContextMenu*) { return 0; }
virtual void contextMenuItemSelected(ContextMenuItem*, const ContextMenu*) { }
- virtual void downloadURL(const KURL& url) { }
+ virtual void downloadURL(const KURL&) { }
virtual void copyImageToClipboard(const HitTestResult&) { }
virtual void searchWithGoogle(const Frame*) { }
virtual void lookUpInDictionary(Frame*) { }
@@ -382,7 +378,7 @@ public:
virtual DragDestinationAction actionMaskForDrag(DragData*) { return DragDestinationActionNone; }
virtual DragSourceAction dragSourceActionMaskForPoint(const IntPoint&) { return DragSourceActionNone; }
virtual void startDrag(DragImageRef, const IntPoint&, const IntPoint&, Clipboard*, Frame*, bool) { }
- virtual DragImageRef createDragImageForLink(KURL&, const String& label, Frame*) { return 0; }
+ virtual DragImageRef createDragImageForLink(KURL&, const String&, Frame*) { return 0; }
virtual void dragControllerDestroyed() { }
};
@@ -406,11 +402,11 @@ public:
virtual void highlight(Node*) { }
virtual void hideHighlight() { }
- virtual void inspectedURLChanged(const String& newURL) { }
+ virtual void inspectedURLChanged(const String&) { }
- virtual void populateSetting(const String& key, InspectorController::Setting&) { }
- virtual void storeSetting(const String& key, const InspectorController::Setting&) { }
- virtual void removeSetting(const String& key) { }
+ virtual void populateSetting(const String&, InspectorController::Setting&) { }
+ virtual void storeSetting(const String&, const InspectorController::Setting&) { }
+ virtual void removeSetting(const String&) { }
};
}
diff --git a/WebCore/loader/FTPDirectoryDocument.cpp b/WebCore/loader/FTPDirectoryDocument.cpp
index 0a7e91e..08ef896 100644
--- a/WebCore/loader/FTPDirectoryDocument.cpp
+++ b/WebCore/loader/FTPDirectoryDocument.cpp
@@ -38,6 +38,7 @@
#include "Settings.h"
#include "SharedBuffer.h"
#include "Text.h"
+#include <wtf/StdLibExtras.h>
#if PLATFORM(QT)
#include <QDateTime>
@@ -323,20 +324,22 @@ void FTPDirectoryTokenizer::parseAndAppendOneLine(const String& inputLine)
appendEntry(filename, processFilesizeString(result.fileSize, result.type == FTPDirectoryEntry), processFileDateString(result.modifiedTime), result.type == FTPDirectoryEntry);
}
+static inline PassRefPtr<SharedBuffer> createTemplateDocumentData(Settings* settings)
+{
+ RefPtr<SharedBuffer> buffer = 0;
+ if (settings)
+ buffer = SharedBuffer::createWithContentsOfFile(settings->ftpDirectoryTemplatePath());
+ if (buffer)
+ LOG(FTP, "Loaded FTPDirectoryTemplate of length %i\n", buffer->size());
+ return buffer.release();
+}
+
bool FTPDirectoryTokenizer::loadDocumentTemplate()
{
- static RefPtr<SharedBuffer> templateDocumentData;
+ DEFINE_STATIC_LOCAL(RefPtr<SharedBuffer>, templateDocumentData, (createTemplateDocumentData(m_doc->settings())));
// FIXME: Instead of storing the data, we'd rather actually parse the template data into the template Document once,
// store that document, then "copy" it whenever we get an FTP directory listing. There are complexities with this
// approach that make it worth putting this off.
-
- if (!templateDocumentData) {
- Settings* settings = m_doc->settings();
- if (settings)
- templateDocumentData = SharedBuffer::createWithContentsOfFile(settings->ftpDirectoryTemplatePath());
- if (templateDocumentData)
- LOG(FTP, "Loaded FTPDirectoryTemplate of length %i\n", templateDocumentData->size());
- }
if (!templateDocumentData) {
LOG_ERROR("Could not load templateData");
@@ -396,7 +399,7 @@ void FTPDirectoryTokenizer::createBasicDocument()
bodyElement->appendChild(m_tableElement, ec);
}
-bool FTPDirectoryTokenizer::write(const SegmentedString& s, bool appendData)
+bool FTPDirectoryTokenizer::write(const SegmentedString& s, bool /*appendData*/)
{
// Make sure we have the table element to append to by loading the template set in the pref, or
// creating a very basic document with the appropriate table
diff --git a/WebCore/loader/FrameLoader.cpp b/WebCore/loader/FrameLoader.cpp
index 0285a8c..adaea61 100644
--- a/WebCore/loader/FrameLoader.cpp
+++ b/WebCore/loader/FrameLoader.cpp
@@ -1,6 +1,7 @@
/*
- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -53,9 +54,9 @@
#include "Frame.h"
#include "FrameLoadRequest.h"
#include "FrameLoaderClient.h"
-#include "FramePrivate.h"
#include "FrameTree.h"
#include "FrameView.h"
+#include "HTMLAnchorElement.h"
#include "HTMLFormElement.h"
#include "HTMLFrameElement.h"
#include "HTMLNames.h"
@@ -72,24 +73,25 @@
#include "PageCache.h"
#include "PageGroup.h"
#include "PluginData.h"
+#include "PluginDocument.h"
#include "ProgressTracker.h"
#include "RenderPart.h"
-#include "RenderWidget.h"
#include "RenderView.h"
+#include "RenderWidget.h"
#include "ResourceHandle.h"
#include "ResourceRequest.h"
+#include "ScriptController.h"
+#include "ScriptSourceCode.h"
+#include "ScriptValue.h"
#include "SecurityOrigin.h"
#include "SegmentedString.h"
#include "Settings.h"
-#include "SystemTime.h"
#include "TextResourceDecoder.h"
#include "WindowFeatures.h"
#include "XMLHttpRequest.h"
#include "XMLTokenizer.h"
-#include "JSDOMBinding.h"
-#include "ScriptController.h"
-#include <runtime/JSLock.h>
-#include <runtime/JSObject.h>
+#include <wtf/CurrentTime.h>
+#include <wtf/StdLibExtras.h>
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
#include "ApplicationCache.h"
@@ -108,10 +110,9 @@
#ifdef ANDROID_INSTRUMENT
#include "TimeCounter.h"
+#include "RenderArena.h"
#endif
-using namespace JSC;
-
namespace WebCore {
#if ENABLE(SVG)
@@ -123,26 +124,33 @@ using namespace HTMLNames;
const unsigned int cMaxPendingSourceLengthInLowBandwidthDisplay = 128 * 1024;
#endif
+typedef HashSet<String, CaseFoldingHash> LocalSchemesMap;
+
struct FormSubmission {
+ FormSubmission(const char* action, const String& url, PassRefPtr<FormData> formData,
+ const String& target, const String& contentType, const String& boundary,
+ PassRefPtr<Event> event, bool lockHistory, bool lockBackForwardList)
+ : action(action)
+ , url(url)
+ , formData(formData)
+ , target(target)
+ , contentType(contentType)
+ , boundary(boundary)
+ , event(event)
+ , lockHistory(lockHistory)
+ , lockBackForwardList(lockBackForwardList)
+ {
+ }
+
const char* action;
String url;
- RefPtr<FormData> data;
+ RefPtr<FormData> formData;
String target;
String contentType;
String boundary;
RefPtr<Event> event;
-
- FormSubmission(const char* a, const String& u, PassRefPtr<FormData> d, const String& t,
- const String& ct, const String& b, PassRefPtr<Event> e)
- : action(a)
- , url(u)
- , data(d)
- , target(t)
- , contentType(ct)
- , boundary(b)
- , event(e)
- {
- }
+ bool lockHistory;
+ bool lockBackForwardList;
};
struct ScheduledRedirection {
@@ -153,28 +161,32 @@ struct ScheduledRedirection {
String referrer;
int historySteps;
bool lockHistory;
+ bool lockBackForwardList;
bool wasUserGesture;
+ bool wasRefresh;
- ScheduledRedirection(double redirectDelay, const String& redirectURL, bool redirectLockHistory, bool userGesture)
+ ScheduledRedirection(double delay, const String& url, bool lockHistory, bool lockBackForwardList, bool wasUserGesture, bool refresh)
: type(redirection)
- , delay(redirectDelay)
- , url(redirectURL)
+ , delay(delay)
+ , url(url)
, historySteps(0)
- , lockHistory(redirectLockHistory)
- , wasUserGesture(userGesture)
+ , lockHistory(lockHistory)
+ , lockBackForwardList(lockBackForwardList)
+ , wasUserGesture(wasUserGesture)
+ , wasRefresh(refresh)
{
}
- ScheduledRedirection(Type locationChangeType,
- const String& locationChangeURL, const String& locationChangeReferrer,
- bool locationChangeLockHistory, bool locationChangeWasUserGesture)
+ ScheduledRedirection(Type locationChangeType, const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool wasUserGesture, bool refresh)
: type(locationChangeType)
, delay(0)
- , url(locationChangeURL)
- , referrer(locationChangeReferrer)
+ , url(url)
+ , referrer(referrer)
, historySteps(0)
- , lockHistory(locationChangeLockHistory)
- , wasUserGesture(locationChangeWasUserGesture)
+ , lockHistory(lockHistory)
+ , lockBackForwardList(lockBackForwardList)
+ , wasUserGesture(wasUserGesture)
+ , wasRefresh(refresh)
{
}
@@ -184,6 +196,7 @@ struct ScheduledRedirection {
, historySteps(historyNavigationSteps)
, lockHistory(false)
, wasUserGesture(false)
+ , wasRefresh(false)
{
}
};
@@ -191,26 +204,14 @@ struct ScheduledRedirection {
static double storedTimeOfLastCompletedLoad;
static FrameLoader::LocalLoadPolicy localLoadPolicy = FrameLoader::AllowLocalLoadsForLocalOnly;
-static bool getString(JSValue* result, String& string)
-{
- if (!result)
- return false;
- JSLock lock(false);
- UString ustring;
- if (!result->getString(ustring))
- return false;
- string = ustring;
- return true;
-}
-
bool isBackForwardLoadType(FrameLoadType type)
{
switch (type) {
case FrameLoadTypeStandard:
case FrameLoadTypeReload:
- case FrameLoadTypeReloadAllowingStaleData:
+ case FrameLoadTypeReloadFromOrigin:
case FrameLoadTypeSame:
- case FrameLoadTypeRedirectWithLockedHistory:
+ case FrameLoadTypeRedirectWithLockedBackForwardList:
case FrameLoadTypeReplace:
return false;
case FrameLoadTypeBack:
@@ -244,7 +245,6 @@ FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client)
, m_sentRedirectNotification(false)
, m_inStopAllLoaders(false)
, m_navigationDuringLoad(false)
- , m_cachePolicy(CachePolicyVerify)
, m_isExecutingJavaScriptFormAction(false)
, m_isRunningScript(false)
, m_didCallImplicitClose(false)
@@ -273,6 +273,9 @@ FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client)
, m_finishedParsingDuringLowBandwidthDisplay(false)
, m_needToSwitchOutLowBandwidthDisplay(false)
#endif
+#if ENABLE(WML)
+ , m_forceReloadWmlDeck(false)
+#endif
{
}
@@ -292,7 +295,7 @@ void FrameLoader::init()
// this somewhat odd set of steps is needed to give the frame an initial empty document
m_isDisplayingInitialEmptyDocument = false;
m_creatingInitialEmptyDocument = true;
- setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(String("")), SubstituteData()).get());
+ setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(KURL("")), SubstituteData()).get());
setProvisionalDocumentLoader(m_policyDocumentLoader.get());
setState(FrameStateProvisional);
m_provisionalDocumentLoader->setResponse(ResourceResponse(KURL(), "text/html", 0, String(), String()));
@@ -322,7 +325,7 @@ Frame* FrameLoader::createWindow(FrameLoader* frameLoaderForFrameLookup, const F
Frame* frame = frameLoaderForFrameLookup->frame()->tree()->find(request.frameName());
if (frame && shouldAllowNavigation(frame)) {
if (!request.resourceRequest().url().isEmpty())
- frame->loader()->loadFrameRequestWithFormAndValues(request, false, 0, 0, HashMap<String, String>());
+ frame->loader()->loadFrameRequestWithFormAndValues(request, false, false, 0, 0, HashMap<String, String>());
if (Page* page = frame->page())
page->chrome()->focus();
created = false;
@@ -380,19 +383,17 @@ bool FrameLoader::canHandleRequest(const ResourceRequest& request)
return m_client->canHandleRequest(request);
}
-void FrameLoader::changeLocation(const String& url, const String& referrer, bool lockHistory, bool userGesture)
+void FrameLoader::changeLocation(const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool userGesture, bool refresh)
{
- changeLocation(completeURL(url), referrer, lockHistory, userGesture);
+ changeLocation(completeURL(url), referrer, lockHistory, lockBackForwardList, userGesture, refresh);
}
-void FrameLoader::changeLocation(const KURL& url, const String& referrer, bool lockHistory, bool userGesture)
+void FrameLoader::changeLocation(const KURL& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool userGesture, bool refresh)
{
RefPtr<Frame> protect(m_frame);
- ResourceRequestCachePolicy policy = (m_cachePolicy == CachePolicyReload) || (m_cachePolicy == CachePolicyRefresh)
- ? ReloadIgnoringCacheData : UseProtocolCachePolicy;
- ResourceRequest request(url, referrer, policy);
+ ResourceRequest request(url, referrer, refresh ? ReloadIgnoringCacheData : UseProtocolCachePolicy);
#ifdef ANDROID_USER_GESTURE
request.setUserGesture(userGesture);
#endif
@@ -400,20 +401,20 @@ void FrameLoader::changeLocation(const KURL& url, const String& referrer, bool l
if (executeIfJavaScriptURL(request.url(), userGesture))
return;
- urlSelected(request, "_self", 0, lockHistory, userGesture);
+ urlSelected(request, "_self", 0, lockHistory, lockBackForwardList, userGesture);
}
-void FrameLoader::urlSelected(const FrameLoadRequest& request, Event* event, bool lockHistory)
+void FrameLoader::urlSelected(const FrameLoadRequest& request, Event* event, bool lockHistory, bool lockBackForwardList)
{
FrameLoadRequest copy = request;
if (copy.resourceRequest().httpReferrer().isEmpty())
copy.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
addHTTPOriginIfNeeded(copy.resourceRequest(), outgoingOrigin());
- loadFrameRequestWithFormAndValues(copy, lockHistory, event, 0, HashMap<String, String>());
+ loadFrameRequestWithFormAndValues(copy, lockHistory, lockBackForwardList, event, 0, HashMap<String, String>());
}
-void FrameLoader::urlSelected(const ResourceRequest& request, const String& _target, Event* triggeringEvent, bool lockHistory, bool userGesture)
+void FrameLoader::urlSelected(const ResourceRequest& request, const String& _target, Event* triggeringEvent, bool lockHistory, bool lockBackForwardList, bool userGesture)
{
if (executeIfJavaScriptURL(request.url(), userGesture, false))
return;
@@ -427,7 +428,7 @@ void FrameLoader::urlSelected(const ResourceRequest& request, const String& _tar
frameRequest.setWasUserGesture(userGesture);
#endif
- urlSelected(frameRequest, triggeringEvent, lockHistory);
+ urlSelected(frameRequest, triggeringEvent, lockHistory, lockBackForwardList);
}
bool FrameLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String& urlString, const AtomicString& frameName)
@@ -444,14 +445,14 @@ bool FrameLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String
KURL scriptURL;
KURL url;
if (protocolIs(urlString, "javascript")) {
- scriptURL = KURL(urlString);
+ scriptURL = completeURL(urlString); // completeURL() encodes the URL.
url = blankURL();
} else
url = completeURL(urlString);
Frame* frame = ownerElement->contentFrame();
if (frame)
- frame->loader()->scheduleLocationChange(url.string(), m_outgoingReferrer, true, userGestureHint());
+ frame->loader()->scheduleLocationChange(url.string(), m_outgoingReferrer, true, true, userGestureHint());
else
frame = loadSubframe(ownerElement, url, frameName, m_outgoingReferrer);
@@ -518,13 +519,13 @@ void FrameLoader::submitFormAgain()
if (m_isRunningScript)
return;
OwnPtr<FormSubmission> form(m_deferredFormSubmission.release());
- if (form)
- submitForm(form->action, form->url, form->data, form->target,
- form->contentType, form->boundary, form->event.get());
+ if (!form)
+ return;
+ submitForm(form->action, form->url, form->formData, form->target, form->contentType, form->boundary, form->event.get(), form->lockHistory, form->lockBackForwardList);
}
void FrameLoader::submitForm(const char* action, const String& url, PassRefPtr<FormData> formData,
- const String& target, const String& contentType, const String& boundary, Event* event)
+ const String& target, const String& contentType, const String& boundary, Event* event, bool lockHistory, bool lockBackForwardList)
{
ASSERT(formData);
@@ -547,8 +548,7 @@ void FrameLoader::submitForm(const char* action, const String& url, PassRefPtr<F
if (m_isRunningScript) {
if (m_deferredFormSubmission)
return;
- m_deferredFormSubmission.set(new FormSubmission(action, url, formData, target,
- contentType, boundary, event));
+ m_deferredFormSubmission.set(new FormSubmission(action, url, formData, target, contentType, boundary, event, lockHistory, lockBackForwardList));
return;
}
@@ -592,7 +592,7 @@ void FrameLoader::submitForm(const char* action, const String& url, PassRefPtr<F
frameRequest.resourceRequest().setURL(u);
addHTTPOriginIfNeeded(frameRequest.resourceRequest(), outgoingOrigin());
- submitForm(frameRequest, event);
+ submitForm(frameRequest, event, lockHistory, lockBackForwardList);
}
void FrameLoader::stopLoading(bool sendUnload)
@@ -623,7 +623,6 @@ void FrameLoader::stopLoading(bool sendUnload)
m_isComplete = true; // to avoid calling completed() in finishedParsing() (David)
m_isLoadingMainResource = false;
m_didCallImplicitClose = true; // don't want that one either
- m_cachePolicy = CachePolicyVerify; // Why here?
if (m_frame->document() && m_frame->document()->parsing()) {
finishedParsing();
@@ -636,8 +635,6 @@ void FrameLoader::stopLoading(bool sendUnload)
if (DocLoader* docLoader = doc->docLoader())
cache()->loader()->cancelRequests(docLoader);
- doc->stopActiveDOMObjects();
-
#if ENABLE(DATABASE)
doc->stopDatabases();
#endif
@@ -769,10 +766,10 @@ bool FrameLoader::executeIfJavaScriptURL(const KURL& url, bool userGesture, bool
return false;
String script = decodeURLEscapeSequences(url.string().substring(strlen("javascript:")));
- JSValue* result = executeScript(script, userGesture);
+ ScriptValue result = executeScript(script, userGesture);
String scriptResult;
- if (!getString(result, scriptResult))
+ if (!result.getString(scriptResult))
return true;
SecurityOrigin* currentSecurityOrigin = 0;
@@ -791,20 +788,20 @@ bool FrameLoader::executeIfJavaScriptURL(const KURL& url, bool userGesture, bool
return true;
}
-JSValue* FrameLoader::executeScript(const String& script, bool forceUserGesture)
+ScriptValue FrameLoader::executeScript(const String& script, bool forceUserGesture)
{
- return executeScript(forceUserGesture ? String() : m_URL.string(), 1, script);
+ return executeScript(ScriptSourceCode(script, forceUserGesture ? KURL() : m_URL));
}
-JSValue* FrameLoader::executeScript(const String& url, int baseLine, const String& script)
+ScriptValue FrameLoader::executeScript(const ScriptSourceCode& sourceCode)
{
if (!m_frame->script()->isEnabled() || m_frame->script()->isPaused())
- return noValue();
+ return ScriptValue();
bool wasRunningScript = m_isRunningScript;
m_isRunningScript = true;
- JSValue* result = m_frame->script()->evaluate(url, baseLine, script);
+ ScriptValue result = m_frame->script()->evaluate(sourceCode);
if (!wasRunningScript) {
m_isRunningScript = false;
@@ -823,14 +820,11 @@ void FrameLoader::cancelAndClear()
closeURL();
clear(false);
+ m_frame->script()->updatePlatformScriptObjects();
}
void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects)
{
- // FIXME: Commenting out the below line causes <http://bugs.webkit.org/show_bug.cgi?id=11212>, but putting it
- // back causes a measurable performance regression which we will need to fix to restore the correct behavior
- // urlsBridgeKnowsAbout.clear();
-
m_frame->editor()->clear();
if (!m_needsClear)
@@ -839,6 +833,7 @@ void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects)
if (m_frame->document() && !m_frame->document()->inPageCache()) {
m_frame->document()->cancelParsing();
+ m_frame->document()->stopActiveDOMObjects();
if (m_frame->document()->attached()) {
m_frame->document()->willRemove();
m_frame->document()->detach();
@@ -895,7 +890,6 @@ void FrameLoader::receivedFirstData()
if (!ptitle.isNull())
m_client->dispatchDidReceiveTitle(ptitle);
- m_frame->document()->docLoader()->setCachePolicy(m_cachePolicy);
m_workingURL = KURL();
double delay;
@@ -936,6 +930,8 @@ void FrameLoader::begin(const KURL& url, bool dispatch, SecurityOrigin* origin)
bool resetScripting = !(m_isDisplayingInitialEmptyDocument && m_frame->document() && m_frame->document()->securityOrigin()->isSecureTransitionTo(url));
clear(resetScripting, resetScripting);
+ if (resetScripting)
+ m_frame->script()->updatePlatformScriptObjects();
if (dispatch)
dispatchWindowObjectAvailable();
@@ -952,7 +948,12 @@ void FrameLoader::begin(const KURL& url, bool dispatch, SecurityOrigin* origin)
m_outgoingReferrer = ref.string();
m_URL = url;
- RefPtr<Document> document = DOMImplementation::createDocument(m_responseMIMEType, m_frame, m_frame->inViewSourceMode());
+ RefPtr<Document> document;
+
+ if (!m_isDisplayingInitialEmptyDocument && m_client->shouldUsePluginDocument(m_responseMIMEType))
+ document = PluginDocument::create(m_frame);
+ else
+ document = DOMImplementation::createDocument(m_responseMIMEType, m_frame, m_frame->inViewSourceMode());
m_frame->setDocument(document);
document->setURL(m_URL);
@@ -1041,9 +1042,7 @@ void FrameLoader::write(const char* str, int len, bool flush)
#if USE(LOW_BANDWIDTH_DISPLAY)
if (m_frame->document()->inLowBandwidthDisplay())
- m_pendingSourceInLowBandwidthDisplay.append(decoded);
- else // reset policy which is changed in switchOutLowBandwidthDisplayIfReady()
- m_frame->document()->docLoader()->setCachePolicy(m_cachePolicy);
+ m_pendingSourceInLowBandwidthDisplay.append(decoded);
#endif
if (!m_receivedData) {
@@ -1132,7 +1131,7 @@ void FrameLoader::startIconLoader()
return;
// If we're not reloading and the icon database doesn't say to load now then bail before we actually start the load
- if (loadType() != FrameLoadTypeReload) {
+ if (loadType() != FrameLoadTypeReload && loadType() != FrameLoadTypeReloadFromOrigin) {
IconLoadDecision decision = iconDatabase()->loadDecisionForIconURL(urlString, m_documentLoader.get());
if (decision == IconLoadNo) {
LOG(IconDatabase, "FrameLoader::startIconLoader() - Told not to load this icon, committing iconURL %s to database for pageURL mapping", urlString.ascii().data());
@@ -1188,9 +1187,9 @@ bool FrameLoader::allowSubstituteDataAccessToLocal()
return localLoadPolicy != FrameLoader::AllowLocalLoadsForLocalOnly;
}
-static HashSet<String, CaseFoldingHash>& localSchemes()
+static LocalSchemesMap& localSchemes()
{
- static HashSet<String, CaseFoldingHash> localSchemes;
+ DEFINE_STATIC_LOCAL(LocalSchemesMap, localSchemes, ());
if (localSchemes.isEmpty()) {
localSchemes.add("file");
@@ -1223,26 +1222,22 @@ void FrameLoader::restoreDocumentState()
switch (loadType()) {
case FrameLoadTypeReload:
-#ifndef ANDROID_HISTORY_CLIENT
- case FrameLoadTypeReloadAllowingStaleData:
-#endif
+ case FrameLoadTypeReloadFromOrigin:
case FrameLoadTypeSame:
case FrameLoadTypeReplace:
break;
case FrameLoadTypeBack:
case FrameLoadTypeForward:
case FrameLoadTypeIndexedBackForward:
- case FrameLoadTypeRedirectWithLockedHistory:
+ case FrameLoadTypeRedirectWithLockedBackForwardList:
case FrameLoadTypeStandard:
-#ifdef ANDROID_HISTORY_CLIENT
- case FrameLoadTypeReloadAllowingStaleData:
-#endif
itemToRestore = m_currentHistoryItem.get();
}
if (!itemToRestore)
return;
-
+
+ LOG(Loading, "WebCoreLoading %s: restoring form state from %p", m_frame->tree()->name().string().utf8().data(), itemToRestore);
doc->setStateForNewFormElements(itemToRestore->documentState());
}
@@ -1274,6 +1269,8 @@ void FrameLoader::finishedParsing()
// Null-checking the FrameView indicates whether or not we're in the destructor.
RefPtr<Frame> protector = m_frame->view() ? m_frame : 0;
+ m_client->dispatchDidFinishDocumentLoad();
+
checkCompleted();
if (!m_frame->view())
@@ -1283,8 +1280,6 @@ void FrameLoader::finishedParsing()
// If not, remove them, relayout, and repaint.
m_frame->view()->restoreScrollbar();
- m_client->dispatchDidFinishDocumentLoad();
-
gotoAnchor();
}
@@ -1409,14 +1404,14 @@ void FrameLoader::scheduleHTTPRedirection(double delay, const String& url)
DocumentLoader* docLoader = activeDocumentLoader();
if (docLoader)
wasUserGesture = docLoader->request().userGesture();
- scheduleRedirection(new ScheduledRedirection(delay, url, delay <= 1, wasUserGesture));
+ scheduleRedirection(new ScheduledRedirection(delay, url, true, delay <= 1, wasUserGesture, false));
}
#else
- scheduleRedirection(new ScheduledRedirection(delay, url, delay <= 1, false));
+ scheduleRedirection(new ScheduledRedirection(delay, url, true, delay <= 1, false, false));
#endif
}
-void FrameLoader::scheduleLocationChange(const String& url, const String& referrer, bool lockHistory, bool wasUserGesture)
+void FrameLoader::scheduleLocationChange(const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool wasUserGesture)
{
if (!m_frame->page())
return;
@@ -1425,7 +1420,7 @@ void FrameLoader::scheduleLocationChange(const String& url, const String& referr
// fragment part, we don't need to schedule the location change.
KURL parsedURL(url);
if (parsedURL.hasRef() && equalIgnoringRef(m_URL, parsedURL)) {
- changeLocation(url, referrer, lockHistory, wasUserGesture);
+ changeLocation(url, referrer, lockHistory, lockBackForwardList, wasUserGesture);
return;
}
@@ -1444,7 +1439,7 @@ void FrameLoader::scheduleLocationChange(const String& url, const String& referr
ScheduledRedirection::Type type = duringLoad
? ScheduledRedirection::locationChangeDuringLoad : ScheduledRedirection::locationChange;
- scheduleRedirection(new ScheduledRedirection(type, url, referrer, lockHistory, wasUserGesture));
+ scheduleRedirection(new ScheduledRedirection(type, url, referrer, lockHistory, lockBackForwardList, wasUserGesture, false));
}
void FrameLoader::scheduleRefresh(bool wasUserGesture)
@@ -1464,8 +1459,7 @@ void FrameLoader::scheduleRefresh(bool wasUserGesture)
ScheduledRedirection::Type type = duringLoad
? ScheduledRedirection::locationChangeDuringLoad : ScheduledRedirection::locationChange;
- scheduleRedirection(new ScheduledRedirection(type, m_URL.string(), m_outgoingReferrer, true, wasUserGesture));
- m_cachePolicy = CachePolicyRefresh;
+ scheduleRedirection(new ScheduledRedirection(type, m_URL.string(), m_outgoingReferrer, true, true, wasUserGesture, true));
}
bool FrameLoader::isLocationChange(const ScheduledRedirection& redirection)
@@ -1549,12 +1543,12 @@ void FrameLoader::redirectionTimerFired(Timer<FrameLoader>*)
case ScheduledRedirection::locationChange:
case ScheduledRedirection::locationChangeDuringLoad:
changeLocation(redirection->url, redirection->referrer,
- redirection->lockHistory, redirection->wasUserGesture);
+ redirection->lockHistory, redirection->lockBackForwardList, redirection->wasUserGesture, redirection->wasRefresh);
return;
case ScheduledRedirection::historyNavigation:
if (redirection->historySteps == 0) {
// Special case for go(0) from a frame -> reload only the frame
- urlSelected(m_URL, "", 0, redirection->lockHistory, redirection->wasUserGesture);
+ urlSelected(m_URL, "", 0, redirection->lockHistory, redirection->lockBackForwardList, redirection->wasUserGesture);
return;
}
// go(i!=0) from a frame navigates into the history of the frame only,
@@ -1577,32 +1571,21 @@ void FrameLoader::loadURLIntoChildFrame(const KURL& url, const String& referer,
ASSERT(childFrame);
HistoryItem* parentItem = currentHistoryItem();
FrameLoadType loadType = this->loadType();
- FrameLoadType childLoadType = FrameLoadTypeRedirectWithLockedHistory;
+ FrameLoadType childLoadType = FrameLoadTypeRedirectWithLockedBackForwardList;
KURL workingURL = url;
// If we're moving in the backforward list, we might want to replace the content
// of this child frame with whatever was there at that point.
- // Reload will maintain the frame contents, LoadSame will not.
- if (parentItem && parentItem->children().size() &&
- (isBackForwardLoadType(loadType) || loadType == FrameLoadTypeReloadAllowingStaleData))
- {
+ if (parentItem && parentItem->children().size() && isBackForwardLoadType(loadType)) {
HistoryItem* childItem = parentItem->childItemWithName(childFrame->tree()->name());
if (childItem) {
// Use the original URL to ensure we get all the side-effects, such as
// onLoad handlers, of any redirects that happened. An example of where
// this is needed is Radar 3213556.
workingURL = KURL(childItem->originalURLString());
- // These behaviors implied by these loadTypes should apply to the child frames
childLoadType = loadType;
-
- if (isBackForwardLoadType(loadType)) {
- // For back/forward, remember this item so we can traverse any child items as child frames load
- childFrame->loader()->setProvisionalHistoryItem(childItem);
- } else {
- // For reload, just reinstall the current item, since a new child frame was created but we won't be creating a new BF item
- childFrame->loader()->setCurrentHistoryItem(childItem);
- }
+ childFrame->loader()->setProvisionalHistoryItem(childItem);
}
}
@@ -1614,9 +1597,9 @@ void FrameLoader::loadURLIntoChildFrame(const KURL& url, const String& referer,
else
#endif
#ifdef ANDROID_USER_GESTURE
- childFrame->loader()->loadURL(workingURL, referer, String(), childLoadType, 0, 0, false);
+ childFrame->loader()->loadURL(workingURL, referer, String(), false, childLoadType, 0, 0, false);
#else
- childFrame->loader()->loadURL(workingURL, referer, String(), childLoadType, 0, 0);
+ childFrame->loader()->loadURL(workingURL, referer, String(), false, childLoadType, 0, 0);
#endif
}
@@ -1664,9 +1647,7 @@ bool FrameLoader::gotoAnchor(const String& name)
m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(false);
- Node* anchorNode = m_frame->document()->getElementById(AtomicString(name));
- if (!anchorNode && !name.isEmpty())
- anchorNode = m_frame->document()->anchors()->namedItem(name, !m_frame->document()->inCompatMode());
+ Element* anchorNode = m_frame->document()->findAnchor(name);
#if ENABLE(SVG)
if (m_frame->document()->isSVGDocument()) {
@@ -1758,10 +1739,16 @@ bool FrameLoader::requestObject(RenderPart* renderer, const String& url, const A
bool FrameLoader::shouldUsePlugin(const KURL& url, const String& mimeType, bool hasFallback, bool& useFallback)
{
+ if (m_client->shouldUsePluginDocument(mimeType)) {
+ useFallback = false;
+ return true;
+ }
+
// Allow other plug-ins to win over QuickTime because if the user has installed a plug-in that
// can handle TIFF (which QuickTime can also handle) they probably intended to override QT.
if (m_frame->page() && (mimeType == "image/tiff" || mimeType == "image/tif" || mimeType == "image/x-tiff")) {
- String pluginName = m_frame->page()->pluginData()->pluginNameForMimeType(mimeType);
+ const PluginData* pluginData = m_frame->page()->pluginData();
+ String pluginName = pluginData ? pluginData->pluginNameForMimeType(mimeType) : String();
if (!pluginName.isEmpty() && !pluginName.contains("QuickTime", false))
return true;
}
@@ -1896,14 +1883,10 @@ void FrameLoader::provisionalLoadStarted()
bool FrameLoader::userGestureHint()
{
- Frame* rootFrame = m_frame;
- while (rootFrame->tree()->parent())
- rootFrame = rootFrame->tree()->parent();
-
- if (rootFrame->script()->isEnabled())
- return rootFrame->script()->processingUserGesture();
-
- return true; // If JavaScript is disabled, a user gesture must have initiated the navigation
+ Frame* frame = m_frame->tree()->top();
+ if (!frame->script()->isEnabled())
+ return true; // If JavaScript is disabled, a user gesture must have initiated the navigation.
+ return frame->script()->processingUserGesture(); // FIXME: Use pageIsProcessingUserGesture.
}
void FrameLoader::didNotOpenURL(const KURL& url)
@@ -1933,23 +1916,13 @@ void FrameLoader::addData(const char* bytes, int length)
write(bytes, length);
}
-bool FrameLoader::canCachePage()
-{
- // Cache the page, if possible.
- // Don't write to the cache if in the middle of a redirect, since we will want to
- // store the final page we end up on.
- // No point writing to the cache on a reload or loadSame, since we will just write
- // over it again when we leave that page.
- // FIXME: <rdar://problem/4886592> - We should work out the complexities of caching pages with frames as they
- // are the most interesting pages on the web, and often those that would benefit the most from caching!
- FrameLoadType loadType = this->loadType();
-
+bool FrameLoader::canCachePageContainingThisFrame()
+{
return m_documentLoader
&& m_documentLoader->mainDocumentError().isNull()
&& !m_frame->tree()->childCount()
- && !m_frame->tree()->parent()
- // FIXME: If we ever change this so that pages with plug-ins will be cached,
- // we need to make sure that we don't cache pages that have outstanding NPObjects
+ // FIXME: If we ever change this so that frames with plug-ins will be cached,
+ // we need to make sure that we don't cache frames that have outstanding NPObjects
// (objects created by the plug-in). Since there is no way to pause/resume a Netscape plug-in,
// they would need to be destroyed and then recreated, and there is no way that we can recreate
// the right NPObjects. See <rdar://problem/5197041> for more information.
@@ -1961,26 +1934,187 @@ bool FrameLoader::canCachePage()
&& !m_frame->document()->hasOpenDatabases()
#endif
&& !m_frame->document()->usingGeolocation()
- && m_frame->page()
- && m_frame->page()->backForwardList()->enabled()
- && m_frame->page()->backForwardList()->capacity() > 0
- && m_frame->page()->settings()->usesPageCache()
&& m_currentHistoryItem
&& !isQuickRedirectComing()
- && loadType != FrameLoadTypeReload
- && loadType != FrameLoadTypeReloadAllowingStaleData
- && loadType != FrameLoadTypeSame
&& !m_documentLoader->isLoadingInAPISense()
&& !m_documentLoader->isStopping()
+ && m_frame->document()->canSuspendActiveDOMObjects()
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
- // FIXME: We should investigating caching pages that have an associated
+ // FIXME: We should investigating caching frames that have an associated
// application cache. <rdar://problem/5917899> tracks that work.
&& !m_documentLoader->applicationCache()
&& !m_documentLoader->candidateApplicationCacheGroup()
#endif
+ && m_client->canCachePage()
;
}
+bool FrameLoader::canCachePage()
+{
+#ifndef NDEBUG
+ logCanCachePageDecision();
+#endif
+
+ // Cache the page, if possible.
+ // Don't write to the cache if in the middle of a redirect, since we will want to
+ // store the final page we end up on.
+ // No point writing to the cache on a reload or loadSame, since we will just write
+ // over it again when we leave that page.
+ // FIXME: <rdar://problem/4886592> - We should work out the complexities of caching pages with frames as they
+ // are the most interesting pages on the web, and often those that would benefit the most from caching!
+ FrameLoadType loadType = this->loadType();
+
+ return !m_frame->tree()->parent()
+ && canCachePageContainingThisFrame()
+ && m_frame->page()
+ && m_frame->page()->backForwardList()->enabled()
+ && m_frame->page()->backForwardList()->capacity() > 0
+ && m_frame->page()->settings()->usesPageCache()
+ && loadType != FrameLoadTypeReload
+ && loadType != FrameLoadTypeReloadFromOrigin
+ && loadType != FrameLoadTypeSame
+ ;
+}
+
+#ifndef NDEBUG
+static String& pageCacheLogPrefix(int indentLevel)
+{
+ static int previousIndent = -1;
+ DEFINE_STATIC_LOCAL(String, prefix, ());
+
+ if (indentLevel != previousIndent) {
+ previousIndent = indentLevel;
+ prefix.truncate(0);
+ for (int i = 0; i < previousIndent; ++i)
+ prefix += " ";
+ }
+
+ return prefix;
+}
+
+static void pageCacheLog(const String& prefix, const String& message)
+{
+ LOG(PageCache, "%s%s", prefix.utf8().data(), message.utf8().data());
+}
+
+#define PCLOG(...) pageCacheLog(pageCacheLogPrefix(indentLevel), String::format(__VA_ARGS__))
+
+void FrameLoader::logCanCachePageDecision()
+{
+ // Only bother logging for main frames that have actually loaded and have content.
+ if (m_creatingInitialEmptyDocument)
+ return;
+ KURL currentURL = m_documentLoader ? m_documentLoader->url() : KURL();
+ if (currentURL.isEmpty())
+ return;
+
+ int indentLevel = 0;
+ PCLOG("--------\n Determining if page can be cached:");
+
+ bool cannotCache = !logCanCacheFrameDecision(1);
+
+ FrameLoadType loadType = this->loadType();
+ do {
+ if (m_frame->tree()->parent())
+ { PCLOG(" -Frame has a parent frame"); cannotCache = true; }
+ if (!m_frame->page()) {
+ PCLOG(" -There is no Page object");
+ cannotCache = true;
+ break;
+ }
+ if (!m_frame->page()->backForwardList()->enabled())
+ { PCLOG(" -The back/forward list is disabled"); cannotCache = true; }
+ if (!(m_frame->page()->backForwardList()->capacity() > 0))
+ { PCLOG(" -The back/forward list has a 0 capacity"); cannotCache = true; }
+ if (!m_frame->page()->settings()->usesPageCache())
+ { PCLOG(" -Page settings says b/f cache disabled"); cannotCache = true; }
+ if (loadType == FrameLoadTypeReload)
+ { PCLOG(" -Load type is: Reload"); cannotCache = true; }
+ if (loadType == FrameLoadTypeReloadFromOrigin)
+ { PCLOG(" -Load type is: Reload from origin"); cannotCache = true; }
+ if (loadType == FrameLoadTypeSame)
+ { PCLOG(" -Load type is: Same"); cannotCache = true; }
+ } while (false);
+
+ PCLOG(cannotCache ? " Page CANNOT be cached\n--------" : " Page CAN be cached\n--------");
+}
+
+bool FrameLoader::logCanCacheFrameDecision(int indentLevel)
+{
+ // Only bother logging for frames that have actually loaded and have content.
+ if (m_creatingInitialEmptyDocument)
+ return false;
+ KURL currentURL = m_documentLoader ? m_documentLoader->url() : KURL();
+ if (currentURL.isEmpty())
+ return false;
+
+ PCLOG("+---");
+ KURL newURL = m_provisionalDocumentLoader ? m_provisionalDocumentLoader->url() : KURL();
+ if (!newURL.isEmpty())
+ PCLOG(" Determining if frame can be cached navigating from (%s) to (%s):", currentURL.string().utf8().data(), newURL.string().utf8().data());
+ else
+ PCLOG(" Determining if subframe with URL (%s) can be cached:", currentURL.string().utf8().data());
+
+ bool cannotCache = false;
+
+ do {
+ if (!m_documentLoader) {
+ PCLOG(" -There is no DocumentLoader object");
+ cannotCache = true;
+ break;
+ }
+ if (!m_documentLoader->mainDocumentError().isNull())
+ { PCLOG(" -Main document has an error"); cannotCache = true; }
+ if (m_frame->tree()->childCount())
+ { PCLOG(" -Frame has child frames"); cannotCache = true; }
+ if (m_containsPlugIns)
+ { PCLOG(" -Frame contains plugins"); cannotCache = true; }
+ if (m_URL.protocolIs("https"))
+ { PCLOG(" -Frame is HTTPS"); cannotCache = true; }
+ if (!m_frame->document()) {
+ PCLOG(" -There is no Document object");
+ cannotCache = true;
+ break;
+ }
+ if (m_frame->document()->hasWindowEventListener(eventNames().unloadEvent))
+ { PCLOG(" -Frame has an unload event listener"); cannotCache = true; }
+#if ENABLE(DATABASE)
+ if (m_frame->document()->hasOpenDatabases())
+ { PCLOG(" -Frame has open database handles"); cannotCache = true; }
+#endif
+ if (m_frame->document()->usingGeolocation())
+ { PCLOG(" -Frame uses Geolocation"); cannotCache = true; }
+ if (!m_currentHistoryItem)
+ { PCLOG(" -No current history item"); cannotCache = true; }
+ if (isQuickRedirectComing())
+ { PCLOG(" -Quick redirect is coming"); cannotCache = true; }
+ if (m_documentLoader->isLoadingInAPISense())
+ { PCLOG(" -DocumentLoader is still loading in API sense"); cannotCache = true; }
+ if (m_documentLoader->isStopping())
+ { PCLOG(" -DocumentLoader is in the middle of stopping"); cannotCache = true; }
+ if (!m_frame->document()->canSuspendActiveDOMObjects())
+ { PCLOG(" -The document cannot suspect its active DOM Objects"); cannotCache = true; }
+#if ENABLE(OFFLINE_WEB_APPLICATIONS)
+ if (m_documentLoader->applicationCache())
+ { PCLOG(" -The DocumentLoader has an active application cache"); cannotCache = true; }
+ if (m_documentLoader->candidateApplicationCacheGroup())
+ { PCLOG(" -The DocumentLoader has a candidateApplicationCacheGroup"); cannotCache = true; }
+#endif
+ if (!m_client->canCachePage())
+ { PCLOG(" -The client says this frame cannot be cached"); cannotCache = true; }
+ } while (false);
+
+ for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
+ if (!child->loader()->logCanCacheFrameDecision(indentLevel + 1))
+ cannotCache = true;
+
+ PCLOG(cannotCache ? " Frame CANNOT be cached" : " Frame CAN be cached");
+ PCLOG("+---");
+
+ return !cannotCache;
+}
+#endif
+
void FrameLoader::updatePolicyBaseURL()
{
if (m_frame->tree()->parent() && m_frame->tree()->parent()->document())
@@ -2047,7 +2181,7 @@ void FrameLoader::startRedirectionTimer()
clientRedirected(KURL(m_scheduledRedirection->url),
m_scheduledRedirection->delay,
currentTime() + m_redirectionTimer.nextFireInterval(),
- m_scheduledRedirection->lockHistory,
+ m_scheduledRedirection->lockBackForwardList,
m_isExecutingJavaScriptFormAction);
return;
case ScheduledRedirection::historyNavigation:
@@ -2120,18 +2254,22 @@ void FrameLoader::setupForReplaceByMIMEType(const String& newMIMEType)
activeDocumentLoader()->setupForReplaceByMIMEType(newMIMEType);
}
-void FrameLoader::loadFrameRequestWithFormState(const FrameLoadRequest& request, bool lockHistory, Event* event, PassRefPtr<FormState> prpFormState)
+void FrameLoader::loadFrameRequestWithFormAndValues(const FrameLoadRequest& request, bool lockHistory, bool lockBackForwardList, Event* event,
+ HTMLFormElement* submitForm, const HashMap<String, String>& formValues)
{
- RefPtr<FormState> formState = prpFormState;
+ RefPtr<FormState> formState;
+ if (submitForm)
+ formState = FormState::create(submitForm, formValues, m_frame);
+
KURL url = request.resourceRequest().url();
-
+
String referrer;
String argsReferrer = request.resourceRequest().httpReferrer();
if (!argsReferrer.isEmpty())
referrer = argsReferrer;
else
referrer = m_outgoingReferrer;
-
+
ASSERT(frame()->document());
if (url.protocolIs("file")) {
if (!canLoad(url, String(), frame()->document()) && !canLoad(url, referrer)) {
@@ -2143,51 +2281,38 @@ void FrameLoader::loadFrameRequestWithFormState(const FrameLoadRequest& request,
if (shouldHideReferrer(url, referrer))
referrer = String();
- Frame* targetFrame = findFrameForNavigation(request.frameName());
+ FrameLoadType loadType;
+ if (request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData)
+ loadType = FrameLoadTypeReload;
+ else if (lockBackForwardList)
+ loadType = FrameLoadTypeRedirectWithLockedBackForwardList;
+ else
+ loadType = FrameLoadTypeStandard;
- if (request.resourceRequest().httpMethod() != "POST") {
- FrameLoadType loadType;
- if (request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData)
- loadType = FrameLoadTypeReload;
- else if (lockHistory)
- loadType = FrameLoadTypeRedirectWithLockedHistory;
- else
- loadType = FrameLoadTypeStandard;
-
+ if (request.resourceRequest().httpMethod() == "POST")
#ifdef ANDROID_USER_GESTURE
- loadURL(request.resourceRequest().url(), referrer, request.frameName(), loadType,
- event, formState.release(), request.wasUserGesture());
+ loadPostRequest(request.resourceRequest(), referrer, request.frameName(), lockHistory, loadType, event, formState.release(), request.wasUserGesture());
#else
- loadURL(request.resourceRequest().url(), referrer, request.frameName(), loadType,
- event, formState.release());
+ loadPostRequest(request.resourceRequest(), referrer, request.frameName(), lockHistory, loadType, event, formState.release());
#endif
- } else
+ else
#ifdef ANDROID_USER_GESTURE
- loadPostRequest(request.resourceRequest(), referrer, request.frameName(), event, formState.release(), request.wasUserGesture());
+ loadURL(request.resourceRequest().url(), referrer, request.frameName(), lockHistory, loadType, event, formState.release(), request.wasUserGesture());
#else
- loadPostRequest(request.resourceRequest(), referrer, request.frameName(), event, formState.release());
+ loadURL(request.resourceRequest().url(), referrer, request.frameName(), lockHistory, loadType, event, formState.release());
#endif
+ Frame* targetFrame = findFrameForNavigation(request.frameName());
if (targetFrame && targetFrame != m_frame)
if (Page* page = targetFrame->page())
page->chrome()->focus();
}
-void FrameLoader::loadFrameRequestWithFormAndValues(const FrameLoadRequest& request, bool lockHistory, Event* event,
- HTMLFormElement* submitForm, const HashMap<String, String>& formValues)
-{
- RefPtr<FormState> formState;
- if (submitForm)
- formState = FormState::create(submitForm, formValues, m_frame);
-
- loadFrameRequestWithFormState(request, lockHistory, event, formState.release());
-}
-
#ifdef ANDROID_USER_GESTURE
-void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const String& frameName, FrameLoadType newLoadType,
+void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType newLoadType,
Event* event, PassRefPtr<FormState> prpFormState, bool userGesture)
#else
-void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const String& frameName, FrameLoadType newLoadType,
+void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType newLoadType,
Event* event, PassRefPtr<FormState> prpFormState)
#endif
{
@@ -2203,8 +2328,8 @@ void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const Stri
RefPtr<SecurityOrigin> referrerOrigin = SecurityOrigin::createFromString(referrer);
addHTTPOriginIfNeeded(request, referrerOrigin->toString());
}
- addExtraFieldsToRequest(request, true, event || isFormSubmission);
- if (newLoadType == FrameLoadTypeReload)
+ addExtraFieldsToRequest(request, newLoadType, true, event || isFormSubmission);
+ if (newLoadType == FrameLoadTypeReload || newLoadType == FrameLoadTypeReloadFromOrigin)
request.setCachePolicy(ReloadIgnoringCacheData);
ASSERT(newLoadType != FrameLoadTypeSame);
@@ -2214,9 +2339,9 @@ void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const Stri
if (!frameName.isEmpty()) {
if (Frame* targetFrame = findFrameForNavigation(frameName))
#ifdef ANDROID_USER_GESTURE
- targetFrame->loader()->loadURL(newURL, referrer, String(), newLoadType, event, formState, userGesture);
+ targetFrame->loader()->loadURL(newURL, referrer, String(), lockHistory, newLoadType, event, formState, userGesture);
#else
- targetFrame->loader()->loadURL(newURL, referrer, String(), newLoadType, event, formState);
+ targetFrame->loader()->loadURL(newURL, referrer, String(), lockHistory, newLoadType, event, formState);
#endif
else
checkNewWindowPolicy(action, request, formState, frameName);
@@ -2238,16 +2363,12 @@ void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const Stri
} else {
// must grab this now, since this load may stop the previous load and clear this flag
bool isRedirect = m_quickRedirectComing;
- loadWithNavigationAction(request, action, newLoadType, formState);
+ loadWithNavigationAction(request, action, lockHistory, newLoadType, formState);
if (isRedirect) {
m_quickRedirectComing = false;
if (m_provisionalDocumentLoader)
m_provisionalDocumentLoader->setIsClientRedirect(true);
-#ifdef ANDROID_HISTORY_CLIENT
- } else if (sameURL && (newLoadType != FrameLoadTypeReloadAllowingStaleData))
-#else
} else if (sameURL)
-#endif
// Example of this case are sites that reload the same URL with a different cookie
// driving the generated content, or a master frame with links that drive a target
// frame, where the user has clicked on the same link repeatedly.
@@ -2255,40 +2376,43 @@ void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const Stri
}
}
-void FrameLoader::load(const ResourceRequest& request)
+void FrameLoader::load(const ResourceRequest& request, bool lockHistory)
{
- load(request, SubstituteData());
+ load(request, SubstituteData(), lockHistory);
}
-void FrameLoader::load(const ResourceRequest& request, const SubstituteData& substituteData)
+void FrameLoader::load(const ResourceRequest& request, const SubstituteData& substituteData, bool lockHistory)
{
if (m_inStopAllLoaders)
return;
// FIXME: is this the right place to reset loadType? Perhaps this should be done after loading is finished or aborted.
m_loadType = FrameLoadTypeStandard;
- load(m_client->createDocumentLoader(request, substituteData).get());
+ RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, substituteData);
+ loader->setURLForHistoryReflectsClientRedirect(lockHistory);
+ load(loader.get());
}
-void FrameLoader::load(const ResourceRequest& request, const String& frameName)
+void FrameLoader::load(const ResourceRequest& request, const String& frameName, bool lockHistory)
{
if (frameName.isEmpty()) {
- load(request);
+ load(request, lockHistory);
return;
}
Frame* frame = findFrameForNavigation(frameName);
if (frame) {
- frame->loader()->load(request);
+ frame->loader()->load(request, lockHistory);
return;
}
checkNewWindowPolicy(NavigationAction(request.url(), NavigationTypeOther), request, 0, frameName);
}
-void FrameLoader::loadWithNavigationAction(const ResourceRequest& request, const NavigationAction& action, FrameLoadType type, PassRefPtr<FormState> formState)
+void FrameLoader::loadWithNavigationAction(const ResourceRequest& request, const NavigationAction& action, bool lockHistory, FrameLoadType type, PassRefPtr<FormState> formState)
{
RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, SubstituteData());
+ loader->setURLForHistoryReflectsClientRedirect(lockHistory);
loader->setTriggeringAction(action);
if (m_documentLoader)
@@ -2300,7 +2424,7 @@ void FrameLoader::loadWithNavigationAction(const ResourceRequest& request, const
void FrameLoader::load(DocumentLoader* newDocumentLoader)
{
ResourceRequest& r = newDocumentLoader->request();
- addExtraFieldsToRequest(r, true, false);
+ addExtraFieldsToMainResourceRequest(r);
FrameLoadType type;
if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->originalRequest().url())) {
@@ -2483,7 +2607,7 @@ bool FrameLoader::shouldReloadToHandleUnreachableURL(DocumentLoader* docLoader)
return compareDocumentLoader && unreachableURL == compareDocumentLoader->request().url();
}
-void FrameLoader::reloadAllowingStaleData(const String& encoding)
+void FrameLoader::reloadWithOverrideEncoding(const String& encoding)
{
if (!m_documentLoader)
return;
@@ -2500,25 +2624,25 @@ void FrameLoader::reloadAllowingStaleData(const String& encoding)
loader->setOverrideEncoding(encoding);
- loadWithDocumentLoader(loader.get(), FrameLoadTypeReloadAllowingStaleData, 0);
+ loadWithDocumentLoader(loader.get(), FrameLoadTypeReload, 0);
}
-void FrameLoader::reload()
+void FrameLoader::reload(bool endToEndReload)
{
if (!m_documentLoader)
return;
- ResourceRequest& initialRequest = m_documentLoader->request();
-
// If a window is created by javascript, its main frame can have an empty but non-nil URL.
// Reloading in this case will lose the current contents (see 4151001).
- if (initialRequest.url().isEmpty())
+ if (m_documentLoader->request().url().isEmpty())
return;
+ ResourceRequest initialRequest = m_documentLoader->request();
+
// Replace error-page URL with the URL we were trying to reach.
KURL unreachableURL = m_documentLoader->unreachableURL();
if (!unreachableURL.isEmpty())
- initialRequest = ResourceRequest(unreachableURL);
+ initialRequest.setURL(unreachableURL);
// Create a new document loader for the reload, this will become m_documentLoader eventually,
// but first it has to be the "policy" document loader, and then the "provisional" document loader.
@@ -2526,8 +2650,8 @@ void FrameLoader::reload()
ResourceRequest& request = loader->request();
+ // FIXME: We don't have a mechanism to revalidate the main resource without reloading at the moment.
request.setCachePolicy(ReloadIgnoringCacheData);
- request.setHTTPHeaderField("Cache-Control", "max-age=0");
// If we're about to re-post, set up action so the application can warn the user.
if (request.httpMethod() == "POST")
@@ -2535,7 +2659,7 @@ void FrameLoader::reload()
loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
- loadWithDocumentLoader(loader.get(), FrameLoadTypeReload, 0);
+ loadWithDocumentLoader(loader.get(), endToEndReload ? FrameLoadTypeReloadFromOrigin : FrameLoadTypeReload, 0);
}
static bool canAccessAncestor(const SecurityOrigin* activeSecurityOrigin, Frame* targetFrame)
@@ -2768,19 +2892,15 @@ void FrameLoader::commitProvisionalLoad(PassRefPtr<CachedPage> prpCachedPage)
{
RefPtr<CachedPage> cachedPage = prpCachedPage;
RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
-
+
+ LOG(Loading, "WebCoreLoading %s: About to commit provisional load from previous URL %s", m_frame->tree()->name().string().utf8().data(), m_URL.string().utf8().data());
+
// Check to see if we need to cache the page we are navigating away from into the back/forward cache.
// We are doing this here because we know for sure that a new page is about to be loaded.
- if (canCachePage() && m_client->canCachePage() && !m_currentHistoryItem->isInPageCache())
+ if (canCachePage() && !m_currentHistoryItem->isInPageCache()) {
+ if (Document* document = m_frame->document())
+ document->suspendActiveDOMObjects();
cachePageForHistoryItem(m_currentHistoryItem.get());
- else if (m_frame->page() && m_frame == m_frame->page()->mainFrame()) {
- // If the main frame installs a timeout late enough (for example in its onunload handler)
- // it could sometimes fire when transitioning to a non-HTML document representation (such as the Mac bookmarks view).
- // To avoid this, we clear all timeouts if the page is not to be cached in the back forward list.
- // Cached pages have their timers paused so they are fine.
- ScriptController* proxy = m_frame->script();
- if (proxy->haveWindowShell())
- proxy->windowShell()->window()->clearAllTimeouts();
}
if (m_loadType != FrameLoadTypeReplace)
@@ -2812,6 +2932,9 @@ void FrameLoader::commitProvisionalLoad(PassRefPtr<CachedPage> prpCachedPage)
didOpenURL(url);
}
+
+ LOG(Loading, "WebCoreLoading %s: Finished committing provisional load to URL %s", m_frame->tree()->name().string().utf8().data(), m_URL.string().utf8().data());
+
opened();
}
@@ -2862,7 +2985,7 @@ void FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage)
DocumentLoader* cachedDocumentLoader = cachedPage->documentLoader();
ASSERT(cachedDocumentLoader);
cachedDocumentLoader->setFrame(m_frame);
- m_client->transitionToCommittedFromCachedPage(cachedPage.get());
+ m_client->transitionToCommittedFromCachedFrame(cachedPage->cachedMainFrame());
} else
m_client->transitionToCommittedForNewPage();
@@ -2870,17 +2993,13 @@ void FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage)
break;
case FrameLoadTypeReload:
+ case FrameLoadTypeReloadFromOrigin:
case FrameLoadTypeSame:
case FrameLoadTypeReplace:
updateHistoryForReload();
m_client->transitionToCommittedForNewPage();
break;
- // FIXME - just get rid of this case, and merge FrameLoadTypeReloadAllowingStaleData with the above case
- case FrameLoadTypeReloadAllowingStaleData:
- m_client->transitionToCommittedForNewPage();
- break;
-
case FrameLoadTypeStandard:
updateHistoryForStandardLoad();
#ifndef BUILDING_ON_TIGER
@@ -2892,8 +3011,8 @@ void FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage)
m_client->transitionToCommittedForNewPage();
break;
- case FrameLoadTypeRedirectWithLockedHistory:
- updateHistoryForRedirectWithLockedHistory();
+ case FrameLoadTypeRedirectWithLockedBackForwardList:
+ updateHistoryForRedirectWithLockedBackForwardList();
m_client->transitionToCommittedForNewPage();
break;
@@ -2910,9 +3029,9 @@ void FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage)
if (m_creatingInitialEmptyDocument)
return;
-
- m_committedFirstRealDocumentLoad = true;
+ m_committedFirstRealDocumentLoad = true;
+
// For non-cached HTML pages, these methods are called in FrameLoader::begin.
if (cachedPage || !m_client->hasHTMLView()) {
dispatchDidCommitLoad();
@@ -2936,7 +3055,7 @@ void FrameLoader::clientRedirectCancelledOrFinished(bool cancelWithLoadInProgres
m_sentRedirectNotification = false;
}
-void FrameLoader::clientRedirected(const KURL& url, double seconds, double fireDate, bool lockHistory, bool isJavaScriptFormAction)
+void FrameLoader::clientRedirected(const KURL& url, double seconds, double fireDate, bool lockBackForwardList, bool isJavaScriptFormAction)
{
m_client->dispatchWillPerformClientRedirect(url, seconds, fireDate);
@@ -2947,11 +3066,24 @@ void FrameLoader::clientRedirected(const KURL& url, double seconds, double fireD
// If a "quick" redirect comes in an, we set a special mode so we treat the next
// load as part of the same navigation. If we don't have a document loader, we have
// no "original" load on which to base a redirect, so we treat the redirect as a normal load.
- m_quickRedirectComing = lockHistory && m_documentLoader && !isJavaScriptFormAction;
+ m_quickRedirectComing = lockBackForwardList && m_documentLoader && !isJavaScriptFormAction;
}
+#if ENABLE(WML)
+void FrameLoader::setForceReloadWmlDeck(bool reload)
+{
+ m_forceReloadWmlDeck = reload;
+}
+#endif
+
bool FrameLoader::shouldReload(const KURL& currentURL, const KURL& destinationURL)
{
+#if ENABLE(WML)
+ // As for WML deck, sometimes it's supposed to be reloaded even if the same URL with fragment
+ if (m_forceReloadWmlDeck)
+ return true;
+#endif
+
// This function implements the rule: "Don't reload if navigating by fragment within
// the same URL, but do reload if going to a new URL or to the same URL with no
// fragment identifier at all."
@@ -3022,6 +3154,7 @@ void FrameLoader::open(CachedPage& cachedPage)
m_frame->setView(view);
m_frame->setDocument(document);
+ m_frame->setDOMWindow(cachedPage.domWindow());
m_frame->domWindow()->setURL(document->url());
m_frame->domWindow()->setSecurityOrigin(document->securityOrigin());
@@ -3030,6 +3163,11 @@ void FrameLoader::open(CachedPage& cachedPage)
updatePolicyBaseURL();
cachedPage.restore(m_frame->page());
+ document->resumeActiveDOMObjects();
+
+ // It is necessary to update any platform script objects after restoring the
+ // cached page.
+ m_frame->script()->updatePlatformScriptObjects();
checkCompleted();
}
@@ -3170,6 +3308,26 @@ FrameLoadType FrameLoader::loadType() const
{
return m_loadType;
}
+
+CachePolicy FrameLoader::cachePolicy() const
+{
+ if (m_isComplete)
+ return CachePolicyVerify;
+
+ if (m_loadType == FrameLoadTypeReloadFromOrigin)
+ return CachePolicyReload;
+
+ if (Frame* parentFrame = m_frame->tree()->parent()) {
+ CachePolicy parentCachePolicy = parentFrame->loader()->cachePolicy();
+ if (parentCachePolicy != CachePolicyVerify)
+ return parentCachePolicy;
+ }
+
+ if (m_loadType == FrameLoadTypeReload)
+ return CachePolicyRevalidate;
+
+ return CachePolicyVerify;
+}
void FrameLoader::stopPolicyCheck()
{
@@ -3226,8 +3384,11 @@ void FrameLoader::checkLoadCompleteForThisFrame()
}
}
if (shouldReset && item)
- if (Page* page = m_frame->page())
+ if (Page* page = m_frame->page()) {
page->backForwardList()->goToItem(item.get());
+ Settings* settings = m_frame->settings();
+ page->setGlobalHistoryItem((!settings || settings->privateBrowsingEnabled()) ? 0 : item.get());
+ }
return;
}
@@ -3246,7 +3407,7 @@ void FrameLoader::checkLoadCompleteForThisFrame()
// If the user had a scroll point, scroll to it, overriding the anchor point if any.
if (Page* page = m_frame->page())
- if ((isBackForwardLoadType(m_loadType) || m_loadType == FrameLoadTypeReload) && page->backForwardList())
+ if ((isBackForwardLoadType(m_loadType) || m_loadType == FrameLoadTypeReload || m_loadType == FrameLoadTypeReloadFromOrigin) && page->backForwardList())
restoreScrollPositionAndViewState();
if (m_creatingInitialEmptyDocument || !m_committedFirstRealDocumentLoad)
@@ -3265,8 +3426,9 @@ void FrameLoader::checkLoadCompleteForThisFrame()
page->progress()->progressCompleted(m_frame);
#ifdef ANDROID_INSTRUMENT
- if (!m_frame->tree()->parent())
- android::TimeCounter::report(m_URL, cache()->getLiveSize(), cache()->getDeadSize());
+ if (!m_frame->tree()->parent() && m_frame->document()->renderArena())
+ android::TimeCounter::report(m_URL, cache()->getLiveSize(), cache()->getDeadSize(),
+ m_frame->document()->renderArena()->reportPoolSize());
#endif
return;
}
@@ -3334,6 +3496,11 @@ void FrameLoader::didFirstLayout()
m_client->dispatchDidFirstLayout();
}
+void FrameLoader::didFirstVisuallyNonEmptyLayout()
+{
+ m_client->dispatchDidFirstVisuallyNonEmptyLayout();
+}
+
void FrameLoader::frameLoadCompleted()
{
m_client->frameLoadCompleted();
@@ -3400,12 +3567,7 @@ int FrameLoader::numPendingOrLoadingRequests(bool recurse) const
return count;
}
-FrameLoaderClient* FrameLoader::client() const
-{
- return m_client;
-}
-
-void FrameLoader::submitForm(const FrameLoadRequest& request, Event* event)
+void FrameLoader::submitForm(const FrameLoadRequest& request, Event* event, bool lockHistory, bool lockBackForwardList)
{
// FIXME: We'd like to remove this altogether and fix the multiple form submission issue another way.
// We do not want to submit more than one form from the same page,
@@ -3424,8 +3586,7 @@ void FrameLoader::submitForm(const FrameLoadRequest& request, Event* event)
m_submittedFormURL = request.resourceRequest().url();
}
- // FIXME: We should probably call userGestureHint() to tell whether this form submission was the result of a user gesture.
- loadFrameRequestWithFormAndValues(request, false, event, m_formAboutToBeSubmitted.get(), m_formValuesAboutToBeSubmitted);
+ loadFrameRequestWithFormAndValues(request, lockHistory, lockBackForwardList, event, m_formAboutToBeSubmitted.get(), m_formValuesAboutToBeSubmitted);
clearRecordedFormValues();
}
@@ -3443,16 +3604,6 @@ void FrameLoader::tokenizerProcessedData()
checkCompleted();
}
-void FrameLoader::didTellClientAboutLoad(const String& url)
-{
- m_urlsClientKnowsAbout.add(url);
-}
-
-bool FrameLoader::haveToldClientAboutLoad(const String& url)
-{
- return m_urlsClientKnowsAbout.contains(url);
-}
-
void FrameLoader::handledOnloadEvents()
{
m_client->dispatchDidHandleOnloadEvents();
@@ -3461,6 +3612,8 @@ void FrameLoader::handledOnloadEvents()
void FrameLoader::frameDetached()
{
stopAllLoaders();
+ if (Document* document = m_frame->document())
+ document->stopActiveDOMObjects();
detachFromParent();
}
@@ -3487,19 +3640,33 @@ void FrameLoader::detachFromParent()
m_frame->pageDestroyed();
}
}
+
+void FrameLoader::addExtraFieldsToSubresourceRequest(ResourceRequest& request)
+{
+ addExtraFieldsToRequest(request, m_loadType, false, false);
+}
-void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, bool mainResource, bool alwaysFromRequest)
+void FrameLoader::addExtraFieldsToMainResourceRequest(ResourceRequest& request)
+{
+ addExtraFieldsToRequest(request, m_loadType, true, false);
+}
+
+void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, FrameLoadType loadType, bool mainResource, bool cookiePolicyURLFromRequest)
{
applyUserAgent(request);
- if (m_loadType == FrameLoadTypeReload) {
+ if (loadType == FrameLoadTypeReload) {
request.setCachePolicy(ReloadIgnoringCacheData);
request.setHTTPHeaderField("Cache-Control", "max-age=0");
+ } else if (loadType == FrameLoadTypeReloadFromOrigin) {
+ request.setCachePolicy(ReloadIgnoringCacheData);
+ request.setHTTPHeaderField("Cache-Control", "no-cache");
+ request.setHTTPHeaderField("Pragma", "no-cache");
}
// Don't set the cookie policy URL if it's already been set.
if (request.mainDocumentURL().isEmpty()) {
- if (mainResource && (isLoadingMainFrame() || alwaysFromRequest))
+ if (mainResource && (isLoadingMainFrame() || cookiePolicyURLFromRequest))
request.setMainDocumentURL(request.url());
else if (Page* page = m_frame->page())
request.setMainDocumentURL(page->mainFrame()->loader()->url());
@@ -3510,6 +3677,11 @@ void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, bool mainRes
// Make sure we send the Origin header.
addHTTPOriginIfNeeded(request, String());
+
+ // Always try UTF-8. If that fails, try frame encoding (if any) and then the default.
+ // For a newly opened frame with an empty URL, encoding() should not be used, because this methods asks decoder, which uses ISO-8859-1.
+ Settings* settings = m_frame->settings();
+ request.setResponseContentDispositionEncodingFallbackArray("UTF-8", m_URL.isEmpty() ? m_encoding : encoding(), settings ? settings->defaultTextEncodingName() : String());
}
void FrameLoader::addHTTPOriginIfNeeded(ResourceRequest& request, String origin)
@@ -3548,11 +3720,9 @@ void FrameLoader::committedLoad(DocumentLoader* loader, const char* data, int le
}
#ifdef ANDROID_USER_GESTURE
-void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String& referrer, const String& frameName,
- Event* event, PassRefPtr<FormState> prpFormState, bool userGesture)
+void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType loadType, Event* event, PassRefPtr<FormState> prpFormState, bool userGesture)
#else
-void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String& referrer, const String& frameName,
- Event* event, PassRefPtr<FormState> prpFormState)
+void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType loadType, Event* event, PassRefPtr<FormState> prpFormState)
#endif
{
RefPtr<FormState> formState = prpFormState;
@@ -3583,28 +3753,23 @@ void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String
workingResourceRequest.setHTTPMethod("POST");
workingResourceRequest.setHTTPBody(formData);
workingResourceRequest.setHTTPContentType(contentType);
- addExtraFieldsToRequest(workingResourceRequest, true, true);
+ addExtraFieldsToRequest(workingResourceRequest, loadType, true, true);
- NavigationAction action(url, FrameLoadTypeStandard, true, event);
+ NavigationAction action(url, loadType, true, event);
if (!frameName.isEmpty()) {
if (Frame* targetFrame = findFrameForNavigation(frameName))
- targetFrame->loader()->loadWithNavigationAction(workingResourceRequest, action, FrameLoadTypeStandard, formState.release());
+ targetFrame->loader()->loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, formState.release());
else
checkNewWindowPolicy(action, workingResourceRequest, formState.release(), frameName);
} else
- loadWithNavigationAction(workingResourceRequest, action, FrameLoadTypeStandard, formState.release());
-}
-
-bool FrameLoader::isReloading() const
-{
- return documentLoader()->request().cachePolicy() == ReloadIgnoringCacheData;
+ loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, formState.release());
}
void FrameLoader::loadEmptyDocumentSynchronously()
{
ResourceRequest request(KURL(""));
- load(request);
+ load(request, false);
}
unsigned long FrameLoader::loadResourceSynchronously(const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data)
@@ -3637,19 +3802,34 @@ unsigned long FrameLoader::loadResourceSynchronously(const ResourceRequest& requ
if (error.isNull()) {
ASSERT(!newRequest.isNull());
- didTellClientAboutLoad(newRequest.url().string());
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
ApplicationCacheResource* resource;
if (documentLoader()->shouldLoadResourceFromApplicationCache(newRequest, resource)) {
if (resource) {
response = resource->response();
- data.append(resource->data()->data(), resource->data()->size());
+ data.append(resource->data()->data(), resource->data()->size());
} else
error = cannotShowURLError(newRequest);
- } else
+ } else {
#endif
ResourceHandle::loadResourceSynchronously(newRequest, error, response, data, m_frame);
+
+#if ENABLE(OFFLINE_WEB_APPLICATIONS)
+ // If normal loading results in a redirect to a resource with another origin (indicative of a captive portal), or a 4xx or 5xx status code or equivalent,
+ // or if there were network errors (but not if the user canceled the download), then instead get, from the cache, the resource of the fallback entry
+ // corresponding to the matched namespace.
+ if ((!error.isNull() && !error.isCancellation())
+ || response.httpStatusCode() / 100 == 4 || response.httpStatusCode() / 100 == 5
+ || !protocolHostAndPortAreEqual(newRequest.url(), response.url())) {
+ if (documentLoader()->getApplicationCacheFallbackResource(newRequest, resource)) {
+ response = resource->response();
+ data.clear();
+ data.append(resource->data()->data(), resource->data()->size());
+ }
+ }
+ }
+#endif
}
sendRemainingDelegateMessages(identifier, response, data.size(), error);
@@ -3742,10 +3922,7 @@ void FrameLoader::callContinueFragmentScrollAfterNavigationPolicy(void* argument
void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequest& request, bool shouldContinue)
{
- // FIXME:
- // some functions check m_quickRedirectComing, and others check for
- // FrameLoadTypeRedirectWithLockedHistory.
- bool isRedirect = m_quickRedirectComing || m_policyLoadType == FrameLoadTypeRedirectWithLockedHistory;
+ bool isRedirect = m_quickRedirectComing || m_policyLoadType == FrameLoadTypeRedirectWithLockedBackForwardList;
m_quickRedirectComing = false;
if (!shouldContinue)
@@ -3793,6 +3970,7 @@ bool FrameLoader::shouldScrollToAnchor(bool isFormSubmission, FrameLoadType load
return !isFormSubmission
&& loadType != FrameLoadTypeReload
+ && loadType != FrameLoadTypeReloadFromOrigin
&& loadType != FrameLoadTypeSame
&& !shouldReload(this->url(), url)
// We don't want to just scroll if a link from within a
@@ -3937,7 +4115,7 @@ void FrameLoader::callContinueLoadAfterNavigationPolicy(void* argument,
loader->continueLoadAfterNavigationPolicy(request, formState, shouldContinue);
}
-void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue)
+void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, PassRefPtr<FormState> formState, bool shouldContinue)
{
// If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
// nil policyDataSource because loading the alternate page will have passed
@@ -3967,8 +4145,11 @@ void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest& reque
if ((isTargetItem || isLoadingMainFrame()) && isBackForwardLoadType(m_policyLoadType))
if (Page* page = m_frame->page()) {
Frame* mainFrame = page->mainFrame();
- if (HistoryItem* resetItem = mainFrame->loader()->m_currentHistoryItem.get())
+ if (HistoryItem* resetItem = mainFrame->loader()->m_currentHistoryItem.get()) {
page->backForwardList()->goToItem(resetItem);
+ Settings* settings = m_frame->settings();
+ page->setGlobalHistoryItem((!settings || settings->privateBrowsingEnabled()) ? 0 : resetItem);
+ }
}
return;
}
@@ -4021,7 +4202,7 @@ void FrameLoader::continueLoadAfterNewWindowPolicy(const ResourceRequest& reques
mainFrame->loader()->setOpenedByDOM();
mainFrame->loader()->m_client->dispatchShow();
mainFrame->loader()->setOpener(frame.get());
- mainFrame->loader()->loadWithNavigationAction(request, NavigationAction(), FrameLoadTypeStandard, formState);
+ mainFrame->loader()->loadWithNavigationAction(request, NavigationAction(), false, FrameLoadTypeStandard, formState);
}
void FrameLoader::sendRemainingDelegateMessages(unsigned long identifier, const ResourceResponse& response, int length, const ResourceError& error)
@@ -4061,29 +4242,31 @@ void FrameLoader::requestFromDelegate(ResourceRequest& request, unsigned long& i
void FrameLoader::loadedResourceFromMemoryCache(const CachedResource* resource)
{
- ResourceRequest request(resource->url());
- const ResourceResponse& response = resource->response();
- SharedBuffer* data = resource->data();
- int length = data ? data->size() : 0;
+ Page* page = m_frame->page();
+ if (!page)
+ return;
- if (Page* page = m_frame->page())
- page->inspectorController()->didLoadResourceFromMemoryCache(m_documentLoader.get(), request, response, length);
+ page->inspectorController()->didLoadResourceFromMemoryCache(m_documentLoader.get(), resource);
+
+ if (!resource->sendResourceLoadCallbacks() || m_documentLoader->haveToldClientAboutLoad(resource->url()))
+ return;
- if (!resource->sendResourceLoadCallbacks() || haveToldClientAboutLoad(resource->url()))
+ if (!page->areMemoryCacheClientCallsEnabled()) {
+ m_documentLoader->recordMemoryCacheLoadForFutureClientNotification(resource->url());
+ m_documentLoader->didTellClientAboutLoad(resource->url());
return;
+ }
- if (m_client->dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(), request, response, length)) {
- didTellClientAboutLoad(resource->url());
+ ResourceRequest request(resource->url());
+ if (m_client->dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(), request, resource->response(), resource->encodedSize())) {
+ m_documentLoader->didTellClientAboutLoad(resource->url());
return;
}
unsigned long identifier;
ResourceError error;
- ResourceRequest r(request);
- requestFromDelegate(r, identifier, error);
- sendRemainingDelegateMessages(identifier, response, length, error);
-
- didTellClientAboutLoad(resource->url());
+ requestFromDelegate(request, identifier, error);
+ sendRemainingDelegateMessages(identifier, resource->response(), resource->encodedSize(), error);
}
void FrameLoader::applyUserAgent(ResourceRequest& request)
@@ -4153,9 +4336,7 @@ void FrameLoader::cachePageForHistoryItem(HistoryItem* item)
{
if (Page* page = m_frame->page()) {
RefPtr<CachedPage> cachedPage = CachedPage::create(page);
- cachedPage->setTimeStampToNow();
- cachedPage->setDocumentLoader(documentLoader());
- m_client->savePlatformDataToCachedPage(cachedPage.get());
+ m_client->savePlatformDataToCachedFrame(cachedPage->cachedMainFrame());
pageCache()->add(item, cachedPage.release());
}
@@ -4185,7 +4366,7 @@ PassRefPtr<HistoryItem> FrameLoader::createHistoryItem(bool useOriginal)
if (useOriginal)
url = originalURL;
else if (docLoader)
- url = docLoader->requestURL();
+ url = docLoader->requestURL();
}
LOG(History, "WebCoreHistory: Creating item for %s", url.string().ascii().data());
@@ -4206,7 +4387,10 @@ PassRefPtr<HistoryItem> FrameLoader::createHistoryItem(bool useOriginal)
RefPtr<HistoryItem> item = HistoryItem::create(url, m_frame->tree()->name(), parent, title);
item->setOriginalURLString(originalURL.string());
-
+
+ if (!unreachableURL.isEmpty() || !docLoader || docLoader->response().httpStatusCode() >= 400)
+ item->setLastVisitWasFailure(true);
+
// Save form state if this is a POST
if (docLoader) {
if (useOriginal)
@@ -4390,7 +4574,11 @@ void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType)
// check for all that as an additional optimization.
// We also do not do anchor-style navigation if we're posting a form.
+#if ENABLE(WML)
+ if (!formData && urlsMatchItem(item) && !m_frame->document()->isWMLDocument()) {
+#else
if (!formData && urlsMatchItem(item)) {
+#endif
// Must do this maintenance here, since we don't go through a real page reload
saveScrollPositionAndViewStateToItem(m_currentHistoryItem.get());
@@ -4441,8 +4629,12 @@ void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType)
}
if (!inPageCache) {
+ bool addedExtraFields = false;
ResourceRequest request(itemURL);
+ if (!item->referrer().isNull())
+ request.setHTTPReferrer(item->referrer());
+
// If this was a repost that failed the page cache, we might try to repost the form.
NavigationAction action;
if (formData) {
@@ -4450,12 +4642,16 @@ void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType)
formData->generateFiles(m_frame->page()->chrome()->client());
request.setHTTPMethod("POST");
- request.setHTTPReferrer(item->formReferrer());
request.setHTTPBody(formData);
request.setHTTPContentType(item->formContentType());
- RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::createFromString(item->formReferrer());
+ RefPtr<SecurityOrigin> securityOrigin = SecurityOrigin::createFromString(item->referrer());
addHTTPOriginIfNeeded(request, securityOrigin->toString());
+ // Make sure to add extra fields to the request after the Origin header is added for the FormData case.
+ // See https://bugs.webkit.org/show_bug.cgi?id=22194 for more discussion.
+ addExtraFieldsToRequest(request, m_loadType, true, formData);
+ addedExtraFields = true;
+
// FIXME: Slight hack to test if the NSURL cache contains the page we're going to.
// We want to know this before talking to the policy delegate, since it affects whether
// we show the DoYouReallyWantToRepost nag.
@@ -4473,6 +4669,7 @@ void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType)
} else {
switch (loadType) {
case FrameLoadTypeReload:
+ case FrameLoadTypeReloadFromOrigin:
request.setCachePolicy(ReloadIgnoringCacheData);
break;
case FrameLoadTypeBack:
@@ -4482,21 +4679,20 @@ void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType)
request.setCachePolicy(ReturnCacheDataElseLoad);
break;
case FrameLoadTypeStandard:
- case FrameLoadTypeRedirectWithLockedHistory:
- // no-op: leave as protocol default
- // FIXME: I wonder if we ever hit this case
+ case FrameLoadTypeRedirectWithLockedBackForwardList:
break;
case FrameLoadTypeSame:
- case FrameLoadTypeReloadAllowingStaleData:
default:
ASSERT_NOT_REACHED();
}
action = NavigationAction(itemOriginalURL, loadType, false);
}
+
+ if (!addedExtraFields)
+ addExtraFieldsToRequest(request, m_loadType, true, formData);
- addExtraFieldsToRequest(request, true, formData);
- loadWithNavigationAction(request, action, loadType, 0);
+ loadWithNavigationAction(request, action, false, loadType, 0);
}
}
}
@@ -4542,6 +4738,8 @@ void FrameLoader::goToItem(HistoryItem* targetItem, FrameLoadType type)
BackForwardList* bfList = page->backForwardList();
HistoryItem* currentItem = bfList->currentItem();
bfList->goToItem(targetItem);
+ Settings* settings = m_frame->settings();
+ page->setGlobalHistoryItem((!settings || settings->privateBrowsingEnabled()) ? 0 : targetItem);
recursiveGoToItem(targetItem, currentItem, type);
}
@@ -4644,11 +4842,16 @@ void FrameLoader::updateHistoryForStandardLoad()
m_navigationDuringLoad = false;
}
+ bool didUpdateGlobalHistory = false;
if (!frameNavigationDuringLoad && !documentLoader()->isClientRedirect()) {
if (!historyURL.isEmpty()) {
addBackForwardItemClippedAtTarget(true);
- if (!needPrivacy)
- m_client->updateGlobalHistory(historyURL);
+ if (!needPrivacy) {
+ m_client->updateGlobalHistory();
+ didUpdateGlobalHistory = true;
+ }
+ if (Page* page = m_frame->page())
+ page->setGlobalHistoryItem(needPrivacy ? 0 : page->backForwardList()->currentItem());
}
} else if (documentLoader()->unreachableURL().isEmpty() && m_currentHistoryItem) {
m_currentHistoryItem->setURL(documentLoader()->url());
@@ -4658,6 +4861,9 @@ void FrameLoader::updateHistoryForStandardLoad()
if (!historyURL.isEmpty() && !needPrivacy) {
if (Page* page = m_frame->page())
page->group().addVisitedLink(historyURL);
+
+ if (!didUpdateGlobalHistory && !url().isEmpty())
+ m_client->updateGlobalHistoryForRedirectWithoutHistoryItem();
}
}
@@ -4706,7 +4912,7 @@ void FrameLoader::updateHistoryForReload()
if (m_currentHistoryItem) {
pageCache()->remove(m_currentHistoryItem.get());
- if (loadType() == FrameLoadTypeReload)
+ if (loadType() == FrameLoadTypeReload || loadType() == FrameLoadTypeReloadFromOrigin)
saveScrollPositionAndViewStateToItem(m_currentHistoryItem.get());
// Sometimes loading a page again leads to a different result because of cookies. Bugzilla 4072
@@ -4715,22 +4921,29 @@ void FrameLoader::updateHistoryForReload()
}
}
-void FrameLoader::updateHistoryForRedirectWithLockedHistory()
+void FrameLoader::updateHistoryForRedirectWithLockedBackForwardList()
{
#if !LOG_DISABLED
if (documentLoader())
- LOG(History, "WebCoreHistory: Updating History for internal load in frame %s", documentLoader()->title().utf8().data());
+ LOG(History, "WebCoreHistory: Updating History for redirect load in frame %s", documentLoader()->title().utf8().data());
#endif
Settings* settings = m_frame->settings();
bool needPrivacy = !settings || settings->privateBrowsingEnabled();
const KURL& historyURL = documentLoader()->urlForHistory();
+ bool didUpdateGlobalHistory = false;
if (documentLoader()->isClientRedirect()) {
if (!m_currentHistoryItem && !m_frame->tree()->parent()) {
- addBackForwardItemClippedAtTarget(true);
- if (!needPrivacy && !historyURL.isEmpty())
- m_client->updateGlobalHistory(historyURL);
+ if (!historyURL.isEmpty()) {
+ addBackForwardItemClippedAtTarget(true);
+ if (!needPrivacy) {
+ m_client->updateGlobalHistory();
+ didUpdateGlobalHistory = true;
+ }
+ if (Page* page = m_frame->page())
+ page->setGlobalHistoryItem(needPrivacy ? 0 : page->backForwardList()->currentItem());
+ }
}
if (m_currentHistoryItem) {
m_currentHistoryItem->setURL(documentLoader()->url());
@@ -4745,6 +4958,9 @@ void FrameLoader::updateHistoryForRedirectWithLockedHistory()
if (!historyURL.isEmpty() && !needPrivacy) {
if (Page* page = m_frame->page())
page->group().addVisitedLink(historyURL);
+
+ if (!didUpdateGlobalHistory && !url().isEmpty())
+ m_client->updateGlobalHistoryForRedirectWithoutHistoryItem();
}
}
@@ -4756,7 +4972,7 @@ void FrameLoader::updateHistoryForCommit()
#endif
FrameLoadType type = loadType();
if (isBackForwardLoadType(type) ||
- (type == FrameLoadTypeReload && !provisionalDocumentLoader()->unreachableURL().isEmpty())) {
+ ((type == FrameLoadTypeReload || type == FrameLoadTypeReloadFromOrigin) && !provisionalDocumentLoader()->unreachableURL().isEmpty())) {
// Once committed, we want to use current item for saving DocState, and
// the provisional item for restoring state.
// Note previousItem must be set before we close the URL, which will
@@ -4831,7 +5047,7 @@ void FrameLoader::setMainDocumentError(DocumentLoader* loader, const ResourceErr
m_client->setMainDocumentError(loader, error);
}
-void FrameLoader::mainReceivedCompleteError(DocumentLoader* loader, const ResourceError& error)
+void FrameLoader::mainReceivedCompleteError(DocumentLoader* loader, const ResourceError&)
{
loader->setPrimaryLoadComplete(true);
m_client->dispatchDidLoadMainResource(activeDocumentLoader());
@@ -4874,6 +5090,11 @@ void FrameLoader::didFinishLoad(ResourceLoader* loader)
dispatchDidFinishLoading(loader->documentLoader(), loader->identifier());
}
+bool FrameLoader::shouldUseCredentialStorage(ResourceLoader* loader)
+{
+ return m_client->shouldUseCredentialStorage(loader->documentLoader(), loader->identifier());
+}
+
void FrameLoader::didReceiveAuthenticationChallenge(ResourceLoader* loader, const AuthenticationChallenge& currentWebChallenge)
{
m_client->dispatchDidReceiveAuthenticationChallenge(loader->documentLoader(), loader->identifier(), currentWebChallenge);
@@ -5128,8 +5349,15 @@ void FrameLoader::dispatchAssignIdentifierToInitialRequest(unsigned long identif
void FrameLoader::dispatchWillSendRequest(DocumentLoader* loader, unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse)
{
+ StringImpl* oldRequestURL = request.url().string().impl();
+ m_documentLoader->didTellClientAboutLoad(request.url());
+
m_client->dispatchWillSendRequest(loader, identifier, request, redirectResponse);
+ // If the URL changed, then we want to put that new URL in the "did tell client" set too.
+ if (!request.isNull() && oldRequestURL != request.url().string().impl())
+ m_documentLoader->didTellClientAboutLoad(request.url());
+
if (Page* page = m_frame->page())
page->inspectorController()->willSendRequest(loader, identifier, request, redirectResponse);
}
@@ -5158,6 +5386,33 @@ void FrameLoader::dispatchDidFinishLoading(DocumentLoader* loader, unsigned long
page->inspectorController()->didFinishLoading(loader, identifier);
}
+void FrameLoader::tellClientAboutPastMemoryCacheLoads()
+{
+ ASSERT(m_frame->page());
+ ASSERT(m_frame->page()->areMemoryCacheClientCallsEnabled());
+
+ if (!m_documentLoader)
+ return;
+
+ Vector<String> pastLoads;
+ m_documentLoader->takeMemoryCacheLoadsForClientNotification(pastLoads);
+
+ size_t size = pastLoads.size();
+ for (size_t i = 0; i < size; ++i) {
+ CachedResource* resource = cache()->resourceForURL(pastLoads[i]);
+
+ // FIXME: These loads, loaded from cache, but now gone from the cache by the time
+ // Page::setMemoryCacheClientCallsEnabled(true) is called, will not be seen by the client.
+ // Consider if there's some efficient way of remembering enough to deliver this client call.
+ // We have the URL, but not the rest of the response or the length.
+ if (!resource)
+ continue;
+
+ ResourceRequest request(resource->url());
+ m_client->dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(), request, resource->response(), resource->encodedSize());
+ }
+}
+
#if USE(LOW_BANDWIDTH_DISPLAY)
bool FrameLoader::addLowBandwidthDisplayRequest(CachedResource* cache)
@@ -5255,8 +5510,6 @@ void FrameLoader::switchOutLowBandwidthDisplayIfReady()
// write decoded data to the new doc, similar to write()
if (m_pendingSourceInLowBandwidthDisplay.length()) {
- // set cachePolicy to Cache to use the loaded resource
- newDoc->docLoader()->setCachePolicy(CachePolicyCache);
if (m_decoder->encoding().usesVisualOrdering())
newDoc->setVisuallyOrdered();
newDoc->recalcStyle(Node::Force);
diff --git a/WebCore/loader/FrameLoader.h b/WebCore/loader/FrameLoader.h
index 47a56af..4650b03 100644
--- a/WebCore/loader/FrameLoader.h
+++ b/WebCore/loader/FrameLoader.h
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,20 +30,12 @@
#ifndef FrameLoader_h
#define FrameLoader_h
-#include "CachedResource.h"
#include "CachePolicy.h"
#include "FormState.h"
#include "FrameLoaderTypes.h"
-#include "KURL.h"
-#include "StringHash.h"
-#include "Timer.h"
-#include <wtf/Forward.h>
-#include <wtf/HashSet.h>
-#include <wtf/HashMap.h>
-#include <wtf/Noncopyable.h>
-#include <wtf/OwnPtr.h>
-#include <wtf/RefPtr.h>
#include "ResourceRequest.h"
+#include "Timer.h"
+
#if USE(LOW_BANDWIDTH_DISPLAY)
#include "CachedResourceClient.h"
#endif
@@ -51,10 +44,10 @@ namespace WebCore {
#if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size
class Archive;
- class ArchiveResource;
#endif
class AuthenticationChallenge;
class CachedPage;
+ class CachedResource;
class Document;
class DocumentLoader;
class Element;
@@ -68,13 +61,12 @@ namespace WebCore {
class IconLoader;
class IntSize;
class NavigationAction;
- class Node;
- class Page;
class RenderPart;
class ResourceError;
class ResourceLoader;
- class ResourceRequest;
class ResourceResponse;
+ class ScriptSourceCode;
+ class ScriptValue;
class SecurityOrigin;
class SharedBuffer;
class SubstituteData;
@@ -125,7 +117,7 @@ namespace WebCore {
class FrameLoader : Noncopyable
#if USE(LOW_BANDWIDTH_DISPLAY)
- , private CachedResourceClient
+ , private CachedResourceClient
#endif
{
public:
@@ -146,30 +138,30 @@ namespace WebCore {
void load(DocumentLoader*); // Calls loadWithDocumentLoader
void loadWithNavigationAction(const ResourceRequest&, const NavigationAction&, // Calls loadWithDocumentLoader()
- FrameLoadType, PassRefPtr<FormState>);
+ bool lockHistory, FrameLoadType, PassRefPtr<FormState>);
#ifdef ANDROID_USER_GESTURE
- void loadPostRequest(const ResourceRequest& inRequest, const String& referrer, // Called by loadFrameRequestWithFormAndValues(), calls loadWithNavigationAction
- const String& frameName, Event* event, PassRefPtr<FormState> prpFormState, bool userGesture);
+ void loadPostRequest(const ResourceRequest&, const String& referrer, // Called by loadFrameRequestWithFormAndValues(), calls loadWithNavigationAction
+ const String& frameName, bool lockHistory, FrameLoadType, Event*, PassRefPtr<FormState>, bool userGesture);
void loadURL(const KURL& newURL, const String& referrer, const String& frameName, // Called by loadFrameRequestWithFormAndValues(), calls loadWithNavigationAction or else dispatches to navigation policy delegate
- FrameLoadType, Event* event, PassRefPtr<FormState> prpFormState, bool userGesture);
+ bool lockHistory, FrameLoadType, Event*, PassRefPtr<FormState>, bool userGesture);
#else
- void loadPostRequest(const ResourceRequest& inRequest, const String& referrer, // Called by loadFrameRequestWithFormAndValues(), calls loadWithNavigationAction
- const String& frameName, Event* event, PassRefPtr<FormState> prpFormState);
+ void loadPostRequest(const ResourceRequest&, const String& referrer, // Called by loadFrameRequestWithFormAndValues(), calls loadWithNavigationAction
+ const String& frameName, bool lockHistory, FrameLoadType, Event*, PassRefPtr<FormState>);
void loadURL(const KURL& newURL, const String& referrer, const String& frameName, // Called by loadFrameRequestWithFormAndValues(), calls loadWithNavigationAction or else dispatches to navigation policy delegate
- FrameLoadType, Event* event, PassRefPtr<FormState> prpFormState);
+ bool lockHistory, FrameLoadType, Event*, PassRefPtr<FormState>);
#endif
+
void loadURLIntoChildFrame(const KURL&, const String& referer, Frame*);
- void loadFrameRequestWithFormState(const FrameLoadRequest&, bool lockHistory, Event*, PassRefPtr<FormState>);
- void loadFrameRequestWithFormAndValues(const FrameLoadRequest&, bool lockHistory, // Called by submitForm, calls loadPostRequest()
+ void loadFrameRequestWithFormAndValues(const FrameLoadRequest&, bool lockHistory, bool lockBackForwardList, // Called by submitForm, calls loadPostRequest()
Event*, HTMLFormElement*, const HashMap<String, String>& formValues);
- void load(const ResourceRequest&); // Called by WebFrame, calls (ResourceRequest, SubstituteData)
- void load(const ResourceRequest&, const SubstituteData&); // Called both by WebFrame and internally, calls (DocumentLoader*)
- void load(const ResourceRequest&, const String& frameName); // Called by WebPluginController
+ void load(const ResourceRequest&, bool lockHistory); // Called by WebFrame, calls (ResourceRequest, SubstituteData)
+ void load(const ResourceRequest&, const SubstituteData&, bool lockHistory); // Called both by WebFrame and internally, calls (DocumentLoader*)
+ void load(const ResourceRequest&, const String& frameName, bool lockHistory); // Called by WebPluginController
#if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size
void loadArchive(PassRefPtr<Archive> archive);
@@ -198,7 +190,6 @@ namespace WebCore {
bool frameHasLoaded() const;
int numPendingOrLoadingRequests(bool recurse) const;
- bool isReloading() const;
String referrer() const;
String outgoingReferrer() const;
String outgoingOrigin() const;
@@ -210,7 +201,8 @@ namespace WebCore {
DocumentLoader* provisionalDocumentLoader() const;
FrameState state() const;
static double timeOfLastCompletedLoad();
-
+
+ bool shouldUseCredentialStorage(ResourceLoader*);
void didReceiveAuthenticationChallenge(ResourceLoader*, const AuthenticationChallenge&);
void didCancelAuthenticationChallenge(ResourceLoader*, const AuthenticationChallenge&);
@@ -250,8 +242,8 @@ namespace WebCore {
void checkContentPolicy(const String& MIMEType, ContentPolicyDecisionFunction, void* argument);
void cancelContentPolicyCheck();
- void reload();
- void reloadAllowingStaleData(const String& overrideEncoding);
+ void reload(bool endToEndReload = false);
+ void reloadWithOverrideEncoding(const String& overrideEncoding);
void didReceiveServerRedirectForProvisionalLoadForFrame();
void finishedLoadingDocument(DocumentLoader*);
@@ -266,43 +258,52 @@ namespace WebCore {
void didChangeTitle(DocumentLoader*);
FrameLoadType loadType() const;
+ CachePolicy cachePolicy() const;
void didFirstLayout();
bool firstLayoutDone() const;
+ void didFirstVisuallyNonEmptyLayout();
+
void clientRedirectCancelledOrFinished(bool cancelWithLoadInProgress);
- void clientRedirected(const KURL&, double delay, double fireDate, bool lockHistory, bool isJavaScriptFormAction);
+ void clientRedirected(const KURL&, double delay, double fireDate, bool lockBackForwardList, bool isJavaScriptFormAction);
bool shouldReload(const KURL& currentURL, const KURL& destinationURL);
+#if ENABLE(WML)
+ void setForceReloadWmlDeck(bool);
+#endif
bool isQuickRedirectComing() const;
void sendRemainingDelegateMessages(unsigned long identifier, const ResourceResponse&, int length, const ResourceError&);
void requestFromDelegate(ResourceRequest&, unsigned long& identifier, ResourceError&);
void loadedResourceFromMemoryCache(const CachedResource*);
+ void tellClientAboutPastMemoryCacheLoads();
void recursiveCheckLoadComplete();
void checkLoadComplete();
void detachFromParent();
void detachChildren();
- void addExtraFieldsToRequest(ResourceRequest&, bool isMainResource, bool alwaysFromRequest);
+ void addExtraFieldsToSubresourceRequest(ResourceRequest&);
+ void addExtraFieldsToMainResourceRequest(ResourceRequest&);
+
static void addHTTPOriginIfNeeded(ResourceRequest&, String origin);
- FrameLoaderClient* client() const;
+ FrameLoaderClient* client() const { return m_client; }
void setDefersLoading(bool);
- void changeLocation(const String& url, const String& referrer, bool lockHistory = true, bool userGesture = false);
- void changeLocation(const KURL&, const String& referrer, bool lockHistory = true, bool userGesture = false);
- void urlSelected(const ResourceRequest&, const String& target, Event*, bool lockHistory, bool userGesture);
- void urlSelected(const FrameLoadRequest&, Event*, bool lockHistory);
+ void changeLocation(const String& url, const String& referrer, bool lockHistory = true, bool lockBackForwardList = true, bool userGesture = false, bool refresh = false);
+ void changeLocation(const KURL&, const String& referrer, bool lockHistory = true, bool lockBackForwardList = true, bool userGesture = false, bool refresh = false);
+ void urlSelected(const ResourceRequest&, const String& target, Event*, bool lockHistory, bool lockBackForwardList, bool userGesture);
+ void urlSelected(const FrameLoadRequest&, Event*, bool lockHistory, bool lockBackForwardList);
bool requestFrame(HTMLFrameOwnerElement*, const String& url, const AtomicString& frameName);
Frame* loadSubframe(HTMLFrameOwnerElement*, const KURL&, const String& name, const String& referrer);
- void submitForm(const char* action, const String& url, PassRefPtr<FormData>, const String& target, const String& contentType, const String& boundary, Event*);
+ void submitForm(const char* action, const String& url, PassRefPtr<FormData>, const String& target, const String& contentType, const String& boundary, Event*, bool lockHistory, bool lockBackForwardList);
void submitFormAgain();
- void submitForm(const FrameLoadRequest&, Event*);
+ void submitForm(const FrameLoadRequest&, Event*, bool lockHistory, bool lockBackForwardList);
void stop();
void stopLoading(bool sendUnload);
@@ -319,7 +320,7 @@ namespace WebCore {
bool isScheduledLocationChangePending() const { return m_scheduledRedirection && isLocationChange(*m_scheduledRedirection); }
void scheduleHTTPRedirection(double delay, const String& url);
- void scheduleLocationChange(const String& url, const String& referrer, bool lockHistory = true, bool userGesture = false);
+ void scheduleLocationChange(const String& url, const String& referrer, bool lockHistory = true, bool lockBackForwardList = true, bool userGesture = false);
void scheduleRefresh(bool userGesture = false);
void scheduleHistoryNavigation(int steps);
@@ -342,8 +343,8 @@ namespace WebCore {
// Returns true if url is a JavaScript URL.
bool executeIfJavaScriptURL(const KURL& url, bool userGesture = false, bool replaceDocument = true);
- JSC::JSValue* executeScript(const String& url, int baseLine, const String& script);
- JSC::JSValue* executeScript(const String& script, bool forceUserGesture = false);
+ ScriptValue executeScript(const ScriptSourceCode&);
+ ScriptValue executeScript(const String& script, bool forceUserGesture = false);
void gotoAnchor();
bool gotoAnchor(const String& name); // returns true if the anchor was found
@@ -406,9 +407,6 @@ namespace WebCore {
KURL completeURL(const String& url);
- void didTellClientAboutLoad(const String& url);
- bool haveToldClientAboutLoad(const String& url);
-
KURL originalRequestURL() const;
void cancelAndClear();
@@ -472,6 +470,12 @@ namespace WebCore {
PassRefPtr<HistoryItem> createHistoryItem(bool useOriginal);
PassRefPtr<HistoryItem> createHistoryItemTree(Frame* targetFrame, bool clipAtTarget);
+ bool canCachePageContainingThisFrame();
+#ifndef NDEBUG
+ void logCanCachePageDecision();
+ bool logCanCacheFrameDecision(int indentLevel);
+#endif
+
void addBackForwardItemClippedAtTarget(bool doClip);
void restoreScrollPositionAndViewState();
void saveDocumentState();
@@ -484,7 +488,7 @@ namespace WebCore {
void updateHistoryForBackForwardNavigation();
void updateHistoryForReload();
void updateHistoryForStandardLoad();
- void updateHistoryForRedirectWithLockedHistory();
+ void updateHistoryForRedirectWithLockedBackForwardList();
void updateHistoryForClientRedirect();
void updateHistoryForCommit();
void updateHistoryForAnchorScroll();
@@ -511,6 +515,8 @@ namespace WebCore {
void updatePolicyBaseURL();
void setPolicyBaseURL(const KURL&);
+
+ void addExtraFieldsToRequest(ResourceRequest&, FrameLoadType loadType, bool isMainResource, bool cookiePolicyURLFromRequest);
// Also not cool.
void stopLoadingSubframes();
@@ -618,10 +624,6 @@ namespace WebCore {
String m_outgoingReferrer;
- CachePolicy m_cachePolicy;
-
- HashSet<String> m_urlsClientKnowsAbout;
-
OwnPtr<FormSubmission> m_deferredFormSubmission;
bool m_isExecutingJavaScriptFormAction;
@@ -694,6 +696,10 @@ namespace WebCore {
String m_pendingSourceInLowBandwidthDisplay;
HashSet<CachedResource*> m_externalRequestsInLowBandwidthDisplay;
#endif
+
+#if ENABLE(WML)
+ bool m_forceReloadWmlDeck;
+#endif
};
}
diff --git a/WebCore/loader/FrameLoaderClient.cpp b/WebCore/loader/FrameLoaderClient.cpp
new file mode 100644
index 0000000..9610fd1
--- /dev/null
+++ b/WebCore/loader/FrameLoaderClient.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Holger Hans Peter Freyther
+ *
+ * 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 "FrameLoaderClient.h"
+
+#include "Color.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "HTMLFrameOwnerElement.h"
+#include "Page.h"
+#include "RenderPart.h"
+
+namespace WebCore {
+
+FrameLoaderClient::~FrameLoaderClient()
+{}
+
+void FrameLoaderClient::transitionToCommittedForNewPage(Frame* frame,
+ const IntSize& viewportSize,
+ const Color& backgroundColor, bool transparent,
+ const IntSize& fixedLayoutSize, bool useFixedLayout,
+ ScrollbarMode horizontalScrollbarMode, ScrollbarMode verticalScrollbarMode)
+{
+ ASSERT(frame);
+
+ Page* page = frame->page();
+ ASSERT(page);
+
+ bool isMainFrame = frame == page->mainFrame();
+
+ if (isMainFrame && frame->view())
+ frame->view()->setParentVisible(false);
+
+ frame->setView(0);
+
+ FrameView* frameView;
+ if (isMainFrame) {
+ frameView = new FrameView(frame, viewportSize);
+ frameView->setFixedLayoutSize(fixedLayoutSize);
+ frameView->setUseFixedLayout(useFixedLayout);
+ } else
+ frameView = new FrameView(frame);
+
+ frameView->setScrollbarModes(horizontalScrollbarMode, verticalScrollbarMode);
+ frameView->updateDefaultScrollbarState();
+
+ frame->setView(frameView);
+ // FrameViews are created with a ref count of 1. Release this ref since we've assigned it to frame.
+ frameView->deref();
+
+ if (backgroundColor.isValid())
+ frameView->updateBackgroundRecursively(backgroundColor, transparent);
+
+ if (isMainFrame)
+ frameView->setParentVisible(true);
+
+ if (frame->ownerRenderer())
+ frame->ownerRenderer()->setWidget(frameView);
+
+ if (HTMLFrameOwnerElement* owner = frame->ownerElement())
+ frame->view()->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff);
+}
+
+}
+
diff --git a/WebCore/loader/FrameLoaderClient.h b/WebCore/loader/FrameLoaderClient.h
index 6e2aba9..52dcfab 100644
--- a/WebCore/loader/FrameLoaderClient.h
+++ b/WebCore/loader/FrameLoaderClient.h
@@ -30,6 +30,7 @@
#define FrameLoaderClient_h
#include "FrameLoaderTypes.h"
+#include "ScrollTypes.h"
#include <wtf/Forward.h>
#include <wtf/Platform.h>
#include <wtf/Vector.h>
@@ -44,7 +45,8 @@ class NSView;
namespace WebCore {
class AuthenticationChallenge;
- class CachedPage;
+ class CachedFrame;
+ class Color;
class DocumentLoader;
class Element;
class FormState;
@@ -74,7 +76,7 @@ namespace WebCore {
class FrameLoaderClient {
public:
- virtual ~FrameLoaderClient() { }
+ virtual ~FrameLoaderClient();
virtual void frameLoaderDestroyed() = 0;
virtual bool hasWebView() const = 0; // mainly for assertions
@@ -93,6 +95,7 @@ namespace WebCore {
virtual void assignIdentifierToInitialRequest(unsigned long identifier, DocumentLoader*, const ResourceRequest&) = 0;
virtual void dispatchWillSendRequest(DocumentLoader*, unsigned long identifier, ResourceRequest&, const ResourceResponse& redirectResponse) = 0;
+ virtual bool shouldUseCredentialStorage(DocumentLoader*, unsigned long identifier) = 0;
virtual void dispatchDidReceiveAuthenticationChallenge(DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&) = 0;
virtual void dispatchDidCancelAuthenticationChallenge(DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&) = 0;
virtual void dispatchDidReceiveResponse(DocumentLoader*, unsigned long identifier, const ResourceResponse&) = 0;
@@ -116,6 +119,7 @@ namespace WebCore {
virtual void dispatchDidFinishDocumentLoad() = 0;
virtual void dispatchDidFinishLoad() = 0;
virtual void dispatchDidFirstLayout() = 0;
+ virtual void dispatchDidFirstVisuallyNonEmptyLayout() = 0;
virtual Frame* dispatchCreatePage() = 0;
virtual void dispatchShow() = 0;
@@ -150,7 +154,9 @@ namespace WebCore {
virtual void committedLoad(DocumentLoader*, const char*, int) = 0;
virtual void finishedLoading(DocumentLoader*) = 0;
- virtual void updateGlobalHistory(const KURL&) = 0;
+ virtual void updateGlobalHistory() = 0;
+ virtual void updateGlobalHistoryForRedirectWithoutHistoryItem() = 0;
+
virtual bool shouldGoToHistoryItem(HistoryItem*) const = 0;
#ifdef ANDROID_HISTORY_CLIENT
virtual void dispatchDidAddHistoryItem(HistoryItem*) const = 0;
@@ -186,8 +192,8 @@ namespace WebCore {
virtual String userAgent(const KURL&) = 0;
- virtual void savePlatformDataToCachedPage(CachedPage*) = 0;
- virtual void transitionToCommittedFromCachedPage(CachedPage*) = 0;
+ virtual void savePlatformDataToCachedFrame(CachedFrame*) = 0;
+ virtual void transitionToCommittedFromCachedFrame(CachedFrame*) = 0;
virtual void transitionToCommittedForNewPage() = 0;
virtual bool canCachePage() const = 0;
@@ -214,6 +220,12 @@ namespace WebCore {
#endif
virtual NSCachedURLResponse* willCacheResponse(DocumentLoader*, unsigned long identifier, NSCachedURLResponse*) const = 0;
#endif
+
+ virtual bool shouldUsePluginDocument(const String& /*mimeType*/) const { return false; }
+
+ protected:
+ static void transitionToCommittedForNewPage(Frame*, const IntSize&, const Color&, bool, const IntSize &, bool,
+ ScrollbarMode = ScrollbarAuto, ScrollbarMode = ScrollbarAuto);
};
} // namespace WebCore
diff --git a/WebCore/loader/FrameLoaderTypes.h b/WebCore/loader/FrameLoaderTypes.h
index 86d8a5b..4fe1176 100644
--- a/WebCore/loader/FrameLoaderTypes.h
+++ b/WebCore/loader/FrameLoaderTypes.h
@@ -51,10 +51,10 @@ namespace WebCore {
FrameLoadTypeForward,
FrameLoadTypeIndexedBackForward, // a multi-item hop in the backforward list
FrameLoadTypeReload,
- FrameLoadTypeReloadAllowingStaleData,
FrameLoadTypeSame, // user loads same URL again (but not reload button)
- FrameLoadTypeRedirectWithLockedHistory,
- FrameLoadTypeReplace
+ FrameLoadTypeRedirectWithLockedBackForwardList, // FIXME: Merge "lockBackForwardList", "lockHistory", "quickRedirect" and "clientRedirect" into a single concept of redirect.
+ FrameLoadTypeReplace,
+ FrameLoadTypeReloadFromOrigin
};
enum NavigationType {
diff --git a/WebCore/loader/ImageDocument.cpp b/WebCore/loader/ImageDocument.cpp
index 39b1db6..8f58179 100644
--- a/WebCore/loader/ImageDocument.cpp
+++ b/WebCore/loader/ImageDocument.cpp
@@ -76,7 +76,12 @@ private:
class ImageDocumentElement : public HTMLImageElement {
public:
- ImageDocumentElement(ImageDocument* doc) : HTMLImageElement(doc), m_imageDocument(doc) { }
+ ImageDocumentElement(ImageDocument* doc)
+ : HTMLImageElement(imgTag, doc)
+ , m_imageDocument(doc)
+ {
+ }
+
virtual ~ImageDocumentElement();
virtual void willMoveToNewOwnerDocument();
@@ -86,13 +91,13 @@ private:
// --------
-bool ImageTokenizer::write(const SegmentedString& s, bool appendData)
+bool ImageTokenizer::write(const SegmentedString&, bool)
{
ASSERT_NOT_REACHED();
return false;
}
-bool ImageTokenizer::writeRawData(const char* data, int len)
+bool ImageTokenizer::writeRawData(const char*, int)
{
CachedImage* cachedImage = m_doc->cachedImage();
cachedImage->data(m_doc->frame()->loader()->documentLoader()->mainResourceData(), false);
@@ -336,7 +341,7 @@ bool ImageDocument::shouldShrinkToFit() const
// --------
-void ImageEventListener::handleEvent(Event* event, bool isWindowEvent)
+void ImageEventListener::handleEvent(Event* event, bool)
{
if (event->type() == eventNames().resizeEvent)
m_doc->windowSizeChanged();
diff --git a/WebCore/loader/ImageLoader.cpp b/WebCore/loader/ImageLoader.cpp
index da159b4..43e08c0 100644
--- a/WebCore/loader/ImageLoader.cpp
+++ b/WebCore/loader/ImageLoader.cpp
@@ -49,6 +49,7 @@ ImageLoader::~ImageLoader()
void ImageLoader::setImage(CachedImage* newImage)
{
+ ASSERT(m_failedLoadURL.isEmpty());
CachedImage* oldImage = m_image.get();
if (newImage != oldImage) {
setLoadingImage(newImage);
@@ -86,6 +87,9 @@ void ImageLoader::updateFromElement()
AtomicString attr = elem->getAttribute(elem->imageSourceAttributeName());
+ if (attr == m_failedLoadURL)
+ return;
+
// Do not load any image if the 'src' attribute is missing or if it is
// an empty string referring to a local file. The latter condition is
// a quirk that preserves old behavior that Dashboard widgets
@@ -97,9 +101,13 @@ void ImageLoader::updateFromElement()
newImage = new CachedImage(sourceURI(attr));
newImage->setLoading(true);
newImage->setDocLoader(doc->docLoader());
- doc->docLoader()->m_docResources.set(newImage->url(), newImage);
+ doc->docLoader()->m_documentResources.set(newImage->url(), newImage);
} else
newImage = doc->docLoader()->requestImage(sourceURI(attr));
+
+ // If we do not have an image here, it means that a cross-site
+ // violation occurred.
+ m_failedLoadURL = !newImage ? attr : AtomicString();
}
CachedImage* oldImage = m_image.get();
@@ -119,8 +127,16 @@ void ImageLoader::updateFromElement()
}
}
-void ImageLoader::notifyFinished(CachedResource *image)
+void ImageLoader::updateFromElementIgnoringPreviousError()
+{
+ // Clear previous error.
+ m_failedLoadURL = AtomicString();
+ updateFromElement();
+}
+
+void ImageLoader::notifyFinished(CachedResource*)
{
+ ASSERT(m_failedLoadURL.isEmpty());
m_imageComplete = true;
Element* elem = element();
diff --git a/WebCore/loader/ImageLoader.h b/WebCore/loader/ImageLoader.h
index 39b5cc4..fc3a58a 100644
--- a/WebCore/loader/ImageLoader.h
+++ b/WebCore/loader/ImageLoader.h
@@ -1,6 +1,4 @@
/*
- * This file is part of the DOM implementation for KDE.
- *
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* Copyright (C) 2004 Apple Computer, Inc.
@@ -25,12 +23,12 @@
#ifndef ImageLoader_h
#define ImageLoader_h
+#include "AtomicString.h"
#include "CachedResourceClient.h"
#include "CachedResourceHandle.h"
namespace WebCore {
-class AtomicString;
class Element;
class ImageLoader : public CachedResourceClient {
@@ -40,6 +38,11 @@ public:
void updateFromElement();
+ // This method should be called after the 'src' attribute
+ // is set (even when it is not modified) to force the update
+ // and match Firefox and Opera.
+ void updateFromElementIgnoringPreviousError();
+
virtual void dispatchLoadEvent() = 0;
virtual String sourceURI(const AtomicString&) const = 0;
@@ -63,6 +66,7 @@ protected:
private:
Element* m_element;
CachedResourceHandle<CachedImage> m_image;
+ AtomicString m_failedLoadURL;
bool m_firedLoad : 1;
bool m_imageComplete : 1;
bool m_loadManually : 1;
diff --git a/WebCore/loader/MainResourceLoader.cpp b/WebCore/loader/MainResourceLoader.cpp
index 079bd79..325809b 100644
--- a/WebCore/loader/MainResourceLoader.cpp
+++ b/WebCore/loader/MainResourceLoader.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -119,7 +120,7 @@ void MainResourceLoader::callContinueAfterNavigationPolicy(void* argument, const
static_cast<MainResourceLoader*>(argument)->continueAfterNavigationPolicy(request, shouldContinue);
}
-void MainResourceLoader::continueAfterNavigationPolicy(const ResourceRequest& request, bool shouldContinue)
+void MainResourceLoader::continueAfterNavigationPolicy(const ResourceRequest&, bool shouldContinue)
{
if (!shouldContinue)
stopLoadingForPolicyChange();
@@ -208,6 +209,11 @@ void MainResourceLoader::continueAfterContentPolicy(PolicyAction contentPolicy,
}
case PolicyDownload:
+ // m_handle can be null, e.g. when loading a substitute resource from application cache.
+ if (!m_handle) {
+ receivedError(cannotShowURLError());
+ return;
+ }
frameLoader()->client()->download(m_handle.get(), request(), m_handle.get()->request(), r);
// It might have gone missing
if (frameLoader())
@@ -268,6 +274,18 @@ void MainResourceLoader::continueAfterContentPolicy(PolicyAction policy)
void MainResourceLoader::didReceiveResponse(const ResourceResponse& r)
{
+#if ENABLE(OFFLINE_WEB_APPLICATIONS)
+ if (r.httpStatusCode() / 100 == 4 || r.httpStatusCode() / 100 == 5) {
+ ASSERT(!m_applicationCache);
+ if (m_frame->settings() && m_frame->settings()->offlineWebApplicationCacheEnabled()) {
+ m_applicationCache = ApplicationCacheGroup::fallbackCacheForMainRequest(request(), documentLoader());
+
+ if (scheduleLoadFallbackResourceFromApplicationCache(m_applicationCache.get()))
+ return;
+ }
+ }
+#endif
+
// 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)
@@ -345,6 +363,18 @@ void MainResourceLoader::didFinishLoading()
void MainResourceLoader::didFail(const ResourceError& error)
{
+#if ENABLE(OFFLINE_WEB_APPLICATIONS)
+ if (!error.isCancellation()) {
+ ASSERT(!m_applicationCache);
+ if (m_frame->settings() && m_frame->settings()->offlineWebApplicationCacheEnabled()) {
+ m_applicationCache = ApplicationCacheGroup::fallbackCacheForMainRequest(request(), documentLoader());
+
+ if (scheduleLoadFallbackResourceFromApplicationCache(m_applicationCache.get()))
+ return;
+ }
+ }
+#endif
+
// 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)
@@ -432,21 +462,14 @@ bool MainResourceLoader::load(const ResourceRequest& r, const SubstituteData& su
if (!m_substituteData.isValid() && frameLoader()->frame()->settings() && frameLoader()->frame()->settings()->offlineWebApplicationCacheEnabled()) {
ASSERT(!m_applicationCache);
- if (Page* page = frameLoader()->frame()->page()) {
- if (frameLoader()->frame() == page->mainFrame())
- m_applicationCache = ApplicationCacheGroup::cacheForMainRequest(r, m_documentLoader.get());
- else
- m_applicationCache = frameLoader()->documentLoader()->topLevelApplicationCache();
- }
-
+ m_applicationCache = ApplicationCacheGroup::cacheForMainRequest(r, m_documentLoader.get());
+
if (m_applicationCache) {
- // Get the resource from the application cache.
- // FIXME: If the resource does not exist, the load should fail.
- if (ApplicationCacheResource* resource = m_applicationCache->resourceForRequest(r)) {
- m_substituteData = SubstituteData(resource->data(),
- resource->response().mimeType(),
- resource->response().textEncodingName(), KURL());
- }
+ // Get the resource from the application cache. By definition, cacheForMainRequest() returns a cache that contains the resource.
+ ApplicationCacheResource* resource = m_applicationCache->resourceForRequest(r);
+ m_substituteData = SubstituteData(resource->data(),
+ resource->response().mimeType(),
+ resource->response().textEncodingName(), KURL());
}
}
#endif
diff --git a/WebCore/loader/MediaDocument.cpp b/WebCore/loader/MediaDocument.cpp
index 5689457..8ed5b45 100644
--- a/WebCore/loader/MediaDocument.cpp
+++ b/WebCore/loader/MediaDocument.cpp
@@ -53,6 +53,7 @@ class MediaTokenizer : public Tokenizer {
public:
MediaTokenizer(Document* doc) : m_doc(doc), m_mediaElement(0) {}
+private:
virtual bool write(const SegmentedString&, bool appendData);
virtual void stopParsing();
virtual void finish();
@@ -62,12 +63,12 @@ public:
virtual bool writeRawData(const char* data, int len);
void createDocumentStructure();
-private:
+
Document* m_doc;
HTMLMediaElement* m_mediaElement;
};
-bool MediaTokenizer::write(const SegmentedString& s, bool appendData)
+bool MediaTokenizer::write(const SegmentedString&, bool)
{
ASSERT_NOT_REACHED();
return false;
@@ -103,7 +104,7 @@ void MediaTokenizer::createDocumentStructure()
frame->loader()->activeDocumentLoader()->mainResourceLoader()->setShouldBufferData(false);
}
-bool MediaTokenizer::writeRawData(const char* data, int len)
+bool MediaTokenizer::writeRawData(const char*, int)
{
ASSERT(!m_mediaElement);
if (m_mediaElement)
diff --git a/WebCore/loader/NavigationAction.cpp b/WebCore/loader/NavigationAction.cpp
index 6bd65ae..ed68e43 100644
--- a/WebCore/loader/NavigationAction.cpp
+++ b/WebCore/loader/NavigationAction.cpp
@@ -40,7 +40,7 @@ static NavigationType navigationType(FrameLoadType frameLoadType, bool isFormSub
return NavigationTypeFormSubmitted;
if (haveEvent)
return NavigationTypeLinkClicked;
- if (frameLoadType == FrameLoadTypeReload)
+ if (frameLoadType == FrameLoadTypeReload || frameLoadType == FrameLoadTypeReloadFromOrigin)
return NavigationTypeReload;
if (isBackForwardLoadType(frameLoadType))
return NavigationTypeBackForward;
diff --git a/WebCore/loader/PluginDocument.cpp b/WebCore/loader/PluginDocument.cpp
index 8be6ae2..42c801c 100644
--- a/WebCore/loader/PluginDocument.cpp
+++ b/WebCore/loader/PluginDocument.cpp
@@ -48,6 +48,7 @@ class PluginTokenizer : public Tokenizer {
public:
PluginTokenizer(Document* doc) : m_doc(doc), m_embedElement(0) {}
+private:
virtual bool write(const SegmentedString&, bool appendData);
virtual void stopParsing();
virtual void finish();
@@ -57,12 +58,12 @@ public:
virtual bool writeRawData(const char* data, int len);
void createDocumentStructure();
-private:
+
Document* m_doc;
HTMLEmbedElement* m_embedElement;
};
-bool PluginTokenizer::write(const SegmentedString& s, bool appendData)
+bool PluginTokenizer::write(const SegmentedString&, bool)
{
ASSERT_NOT_REACHED();
return false;
@@ -94,7 +95,7 @@ void PluginTokenizer::createDocumentStructure()
body->appendChild(embedElement, ec);
}
-bool PluginTokenizer::writeRawData(const char* data, int len)
+bool PluginTokenizer::writeRawData(const char*, int)
{
ASSERT(!m_embedElement);
if (m_embedElement)
diff --git a/WebCore/loader/ProgressTracker.cpp b/WebCore/loader/ProgressTracker.cpp
index 56aa976..38df80f 100644
--- a/WebCore/loader/ProgressTracker.cpp
+++ b/WebCore/loader/ProgressTracker.cpp
@@ -30,7 +30,7 @@
#include "FrameLoader.h"
#include "FrameLoaderClient.h"
#include "ResourceResponse.h"
-#include "SystemTime.h"
+#include <wtf/CurrentTime.h>
using std::min;
diff --git a/WebCore/loader/ResourceLoader.cpp b/WebCore/loader/ResourceLoader.cpp
index a6f90b3..4f55981 100644
--- a/WebCore/loader/ResourceLoader.cpp
+++ b/WebCore/loader/ResourceLoader.cpp
@@ -64,9 +64,6 @@ ResourceLoader::ResourceLoader(Frame* frame, bool sendResourceLoadCallbacks, boo
, m_shouldContentSniff(shouldContentSniff)
, m_shouldBufferData(true)
, m_defersLoading(frame->page()->defersLoading())
-#if ENABLE(OFFLINE_WEB_APPLICATIONS)
- , m_wasLoadedFromApplicationCache(false)
-#endif
{
}
@@ -124,10 +121,8 @@ bool ResourceLoader::load(const ResourceRequest& r)
#endif
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
- if (m_documentLoader->scheduleApplicationCacheLoad(this, clientRequest, r.url())) {
- m_wasLoadedFromApplicationCache = true;
+ if (m_documentLoader->scheduleApplicationCacheLoad(this, clientRequest, r.url()))
return true;
- }
#endif
if (m_defersLoading) {
@@ -197,6 +192,17 @@ void ResourceLoader::clearResourceData()
m_resourceData->clear();
}
+#if ENABLE(OFFLINE_WEB_APPLICATIONS)
+bool ResourceLoader::scheduleLoadFallbackResourceFromApplicationCache(ApplicationCache* cache)
+{
+ if (documentLoader()->scheduleLoadFallbackResourceFromApplicationCache(this, m_request, cache)) {
+ handle()->cancel();
+ return true;
+ }
+ return false;
+}
+#endif
+
void ResourceLoader::willSendRequest(ResourceRequest& request, const ResourceResponse& redirectResponse)
{
// Protect this in this delegate method since the additional processing can do
@@ -217,7 +223,7 @@ void ResourceLoader::willSendRequest(ResourceRequest& request, const ResourceRes
m_request = request;
}
-void ResourceLoader::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
+void ResourceLoader::didSendData(unsigned long long, unsigned long long)
{
}
@@ -377,6 +383,12 @@ ResourceError ResourceLoader::cannotShowURLError()
void ResourceLoader::willSendRequest(ResourceHandle*, ResourceRequest& request, const ResourceResponse& redirectResponse)
{
+#if ENABLE(OFFLINE_WEB_APPLICATIONS)
+ if (!redirectResponse.isNull() && !protocolHostAndPortAreEqual(request.url(), redirectResponse.url())) {
+ if (scheduleLoadFallbackResourceFromApplicationCache())
+ return;
+ }
+#endif
willSendRequest(request, redirectResponse);
}
@@ -387,6 +399,12 @@ void ResourceLoader::didSendData(ResourceHandle*, unsigned long long bytesSent,
void ResourceLoader::didReceiveResponse(ResourceHandle*, const ResourceResponse& response)
{
+#if ENABLE(OFFLINE_WEB_APPLICATIONS)
+ if (response.httpStatusCode() / 100 == 4 || response.httpStatusCode() / 100 == 5) {
+ if (scheduleLoadFallbackResourceFromApplicationCache())
+ return;
+ }
+#endif
didReceiveResponse(response);
}
@@ -402,6 +420,12 @@ void ResourceLoader::didFinishLoading(ResourceHandle*)
void ResourceLoader::didFail(ResourceHandle*, const ResourceError& error)
{
+#if ENABLE(OFFLINE_WEB_APPLICATIONS)
+ if (!error.isCancellation()) {
+ if (documentLoader()->scheduleLoadFallbackResourceFromApplicationCache(this, m_request))
+ return;
+ }
+#endif
didFail(error);
}
@@ -415,6 +439,12 @@ void ResourceLoader::cannotShowURL(ResourceHandle*)
didFail(cannotShowURLError());
}
+bool ResourceLoader::shouldUseCredentialStorage()
+{
+ RefPtr<ResourceLoader> protector(this);
+ return frameLoader()->shouldUseCredentialStorage(this);
+}
+
void ResourceLoader::didReceiveAuthenticationChallenge(const AuthenticationChallenge& challenge)
{
// Protect this in this delegate method since the additional processing can do
diff --git a/WebCore/loader/ResourceLoader.h b/WebCore/loader/ResourceLoader.h
index 722f5fc..c8cc208 100644
--- a/WebCore/loader/ResourceLoader.h
+++ b/WebCore/loader/ResourceLoader.h
@@ -40,6 +40,7 @@
namespace WebCore {
+ class ApplicationCache;
class DocumentLoader;
class Frame;
class FrameLoader;
@@ -82,6 +83,7 @@ namespace WebCore {
virtual void didFinishLoading();
virtual void didFail(const ResourceError&);
+ virtual bool shouldUseCredentialStorage();
virtual void didReceiveAuthenticationChallenge(const AuthenticationChallenge&);
void didCancelAuthenticationChallenge(const AuthenticationChallenge&);
virtual void receivedCancellation(const AuthenticationChallenge&);
@@ -96,6 +98,7 @@ namespace WebCore {
virtual void wasBlocked(ResourceHandle*);
virtual void cannotShowURL(ResourceHandle*);
virtual void willStopBufferingData(ResourceHandle*, const char* data, int length) { willStopBufferingData(data, length); }
+ virtual bool shouldUseCredentialStorage(ResourceHandle*) { return shouldUseCredentialStorage(); }
virtual void didReceiveAuthenticationChallenge(ResourceHandle*, const AuthenticationChallenge& challenge) { didReceiveAuthenticationChallenge(challenge); }
virtual void didCancelAuthenticationChallenge(ResourceHandle*, const AuthenticationChallenge& challenge) { didCancelAuthenticationChallenge(challenge); }
virtual void receivedCancellation(ResourceHandle*, const AuthenticationChallenge& challenge) { receivedCancellation(challenge); }
@@ -112,6 +115,10 @@ namespace WebCore {
protected:
ResourceLoader(Frame*, bool sendResourceLoadCallbacks, bool shouldContentSniff);
+#if ENABLE(OFFLINE_WEB_APPLICATIONS)
+ bool scheduleLoadFallbackResourceFromApplicationCache(ApplicationCache* = 0);
+#endif
+
virtual void didCancel(const ResourceError&);
void didFinishLoadingOnePart();
@@ -139,9 +146,6 @@ namespace WebCore {
bool m_shouldContentSniff;
bool m_shouldBufferData;
bool m_defersLoading;
-#if ENABLE(OFFLINE_WEB_APPLICATIONS)
- bool m_wasLoadedFromApplicationCache;
-#endif
ResourceRequest m_deferredRequest;
};
diff --git a/WebCore/loader/SubresourceLoader.cpp b/WebCore/loader/SubresourceLoader.cpp
index bff48b2..4a339ef 100644
--- a/WebCore/loader/SubresourceLoader.cpp
+++ b/WebCore/loader/SubresourceLoader.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 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
@@ -29,15 +29,11 @@
#include "config.h"
#include "SubresourceLoader.h"
-#include "Document.h"
#include "DocumentLoader.h"
#include "Frame.h"
#include "FrameLoader.h"
-#include "Logging.h"
#include "ResourceHandle.h"
-#include "ResourceRequest.h"
#include "SubresourceLoaderClient.h"
-#include "SharedBuffer.h"
#include <wtf/RefCountedLeakCounter.h>
namespace WebCore {
@@ -64,13 +60,6 @@ SubresourceLoader::~SubresourceLoader()
#endif
}
-bool SubresourceLoader::load(const ResourceRequest& r)
-{
- m_frame->loader()->didTellClientAboutLoad(r.url().string());
-
- return ResourceLoader::load(r);
-}
-
PassRefPtr<SubresourceLoader> SubresourceLoader::create(Frame* frame, SubresourceLoaderClient* client, const ResourceRequest& request, bool skipCanLoadCheck, bool sendResourceLoadCallbacks, bool shouldContentSniff)
{
if (!frame)
@@ -106,7 +95,7 @@ PassRefPtr<SubresourceLoader> SubresourceLoader::create(Frame* frame, Subresourc
else
newRequest.setCachePolicy(fl->originalRequest().cachePolicy());
- fl->addExtraFieldsToRequest(newRequest, false, false);
+ fl->addExtraFieldsToSubresourceRequest(newRequest);
RefPtr<SubresourceLoader> subloader(adoptRef(new SubresourceLoader(frame, client, sendResourceLoadCallbacks, shouldContentSniff)));
if (!subloader->load(newRequest))
@@ -237,6 +226,17 @@ void SubresourceLoader::didCancel(const ResourceError& error)
ResourceLoader::didCancel(error);
}
+bool SubresourceLoader::shouldUseCredentialStorage()
+{
+ RefPtr<SubresourceLoader> protect(this);
+
+ bool shouldUse;
+ if (m_client && m_client->getShouldUseCredentialStorage(this, shouldUse))
+ return shouldUse;
+
+ return ResourceLoader::shouldUseCredentialStorage();
+}
+
void SubresourceLoader::didReceiveAuthenticationChallenge(const AuthenticationChallenge& challenge)
{
RefPtr<SubresourceLoader> protect(this);
diff --git a/WebCore/loader/SubresourceLoader.h b/WebCore/loader/SubresourceLoader.h
index b5bd34a..1a94c73 100644
--- a/WebCore/loader/SubresourceLoader.h
+++ b/WebCore/loader/SubresourceLoader.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2005, 2006, 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
@@ -29,25 +29,22 @@
#ifndef SubresourceLoader_h
#define SubresourceLoader_h
-#include "ResourceHandleClient.h"
#include "ResourceLoader.h"
-#include <wtf/PassRefPtr.h>
namespace WebCore {
- class FormData;
- class String;
- class ResourceHandle;
class ResourceRequest;
class SubresourceLoaderClient;
class SubresourceLoader : public ResourceLoader {
public:
static PassRefPtr<SubresourceLoader> create(Frame*, SubresourceLoaderClient*, const ResourceRequest&, bool skipCanLoadCheck = false, bool sendResourceLoadCallbacks = true, bool shouldContentSniff = true);
-
- virtual ~SubresourceLoader();
- virtual bool load(const ResourceRequest&);
+ void clearClient() { m_client = 0; }
+
+ private:
+ SubresourceLoader(Frame*, SubresourceLoaderClient*, bool sendResourceLoadCallbacks, bool shouldContentSniff);
+ virtual ~SubresourceLoader();
virtual void willSendRequest(ResourceRequest&, const ResourceResponse& redirectResponse);
virtual void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent);
@@ -55,15 +52,11 @@ namespace WebCore {
virtual void didReceiveData(const char*, int, long long lengthReceived, bool allAtOnce);
virtual void didFinishLoading();
virtual void didFail(const ResourceError&);
+ virtual bool shouldUseCredentialStorage();
virtual void didReceiveAuthenticationChallenge(const AuthenticationChallenge&);
- virtual void receivedCancellation(const AuthenticationChallenge&);
-
- void clearClient() { m_client = 0; }
-
- private:
- SubresourceLoader(Frame*, SubresourceLoaderClient*, bool sendResourceLoadCallbacks, bool shouldContentSniff);
-
+ virtual void receivedCancellation(const AuthenticationChallenge&);
virtual void didCancel(const ResourceError&);
+
SubresourceLoaderClient* m_client;
bool m_loadingMultipartContent;
};
diff --git a/WebCore/loader/SubresourceLoaderClient.h b/WebCore/loader/SubresourceLoaderClient.h
index d2b9a12..76fde47 100644
--- a/WebCore/loader/SubresourceLoaderClient.h
+++ b/WebCore/loader/SubresourceLoaderClient.h
@@ -42,14 +42,15 @@ public:
virtual ~SubresourceLoaderClient() { }
// request may be modified
- virtual void willSendRequest(SubresourceLoader*, ResourceRequest&, const ResourceResponse& redirectResponse) { }
- virtual void didSendData(SubresourceLoader*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent) { }
+ virtual void willSendRequest(SubresourceLoader*, ResourceRequest&, const ResourceResponse& /*redirectResponse*/) { }
+ virtual void didSendData(SubresourceLoader*, unsigned long long /*bytesSent*/, unsigned long long /*totalBytesToBeSent*/) { }
virtual void didReceiveResponse(SubresourceLoader*, const ResourceResponse&) { }
- virtual void didReceiveData(SubresourceLoader*, const char*, int) { }
+ virtual void didReceiveData(SubresourceLoader*, const char*, int /*lengthReceived*/) { }
virtual void didFinishLoading(SubresourceLoader*) { }
virtual void didFail(SubresourceLoader*, const ResourceError&) { }
+ virtual bool getShouldUseCredentialStorage(SubresourceLoader*, bool& /*shouldUseCredentialStorage*/) { return false; }
virtual void didReceiveAuthenticationChallenge(SubresourceLoader*, const AuthenticationChallenge&) { }
virtual void receivedCancellation(SubresourceLoader*, const AuthenticationChallenge&) { }
diff --git a/WebCore/loader/TextDocument.cpp b/WebCore/loader/TextDocument.cpp
index 6b06ede..bd2c446 100644
--- a/WebCore/loader/TextDocument.cpp
+++ b/WebCore/loader/TextDocument.cpp
@@ -93,7 +93,7 @@ TextTokenizer::TextTokenizer(HTMLViewSourceDocument* doc)
m_dest = m_buffer;
}
-bool TextTokenizer::write(const SegmentedString& s, bool appendData)
+bool TextTokenizer::write(const SegmentedString& s, bool)
{
ExceptionCode ec;
diff --git a/WebCore/loader/TextResourceDecoder.cpp b/WebCore/loader/TextResourceDecoder.cpp
index 4a0caa0..f37d8f7 100644
--- a/WebCore/loader/TextResourceDecoder.cpp
+++ b/WebCore/loader/TextResourceDecoder.cpp
@@ -346,7 +346,7 @@ void TextResourceDecoder::setEncoding(const TextEncoding& encoding, EncodingSour
if (source == EncodingFromMetaTag && strcasecmp(encoding.name(), "x-user-defined") == 0)
m_decoder.reset("windows-1252");
else if (source == EncodingFromMetaTag || source == EncodingFromXMLHeader || source == EncodingFromCSSCharset)
- m_decoder.reset(encoding.closest8BitEquivalent());
+ m_decoder.reset(encoding.closestByteBasedEquivalent());
else
m_decoder.reset(encoding);
@@ -793,6 +793,7 @@ String TextResourceDecoder::flush()
{
String result = m_decoder.decode(m_buffer.data(), m_buffer.size(), true, m_contentType == XML, m_sawError);
m_buffer.clear();
+ m_decoder.reset(m_decoder.encoding());
return result;
}
diff --git a/WebCore/loader/ThreadableLoader.cpp b/WebCore/loader/ThreadableLoader.cpp
new file mode 100644
index 0000000..0f22fbe
--- /dev/null
+++ b/WebCore/loader/ThreadableLoader.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2009, Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT
+ * OWNER 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 "ThreadableLoader.h"
+
+#include "DocumentThreadableLoader.h"
+#include "Document.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "ScriptExecutionContext.h"
+
+namespace WebCore {
+
+PassRefPtr<ThreadableLoader> ThreadableLoader::create(ScriptExecutionContext* context, ThreadableLoaderClient* client, const ResourceRequest& request, LoadCallbacks callbacksSetting, ContentSniff contentSniff)
+{
+ ASSERT(client);
+ ASSERT(context);
+ ASSERT(context->isDocument());
+
+ return DocumentThreadableLoader::create(static_cast<Document*>(context), client, request, callbacksSetting, contentSniff);
+}
+
+unsigned long ThreadableLoader::loadResourceSynchronously(ScriptExecutionContext* context, const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data)
+{
+ ASSERT(context);
+ ASSERT(context->isDocument());
+
+ Document* document = static_cast<Document*>(context);
+ if (!document->frame())
+ return std::numeric_limits<unsigned long>::max();
+ return document->frame()->loader()->loadResourceSynchronously(request, error, response, data);
+}
+
+} // namespace WebCore
diff --git a/WebCore/loader/ThreadableLoader.h b/WebCore/loader/ThreadableLoader.h
new file mode 100644
index 0000000..e8ff058
--- /dev/null
+++ b/WebCore/loader/ThreadableLoader.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2009, Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#ifndef ThreadableLoader_h
+#define ThreadableLoader_h
+
+#include <wtf/Noncopyable.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+ class ResourceError;
+ class ResourceRequest;
+ class ResourceResponse;
+ class ScriptExecutionContext;
+ class ThreadableLoaderClient;
+
+ enum LoadCallbacks {
+ SendLoadCallbacks,
+ DoNotSendLoadCallbacks
+ };
+
+ enum ContentSniff {
+ SniffContent,
+ DoNotSniffContent
+ };
+
+ // Useful for doing loader operations from any thread (not threadsafe,
+ // just able to run on threads other than the main thread).
+ class ThreadableLoader : Noncopyable {
+ public:
+ static PassRefPtr<ThreadableLoader> create(ScriptExecutionContext*, ThreadableLoaderClient*, const ResourceRequest&, LoadCallbacks, ContentSniff);
+ static unsigned long loadResourceSynchronously(ScriptExecutionContext*, const ResourceRequest&, ResourceError&, ResourceResponse&, Vector<char>& data);
+
+ virtual void cancel() = 0;
+ void ref() { refThreadableLoader(); }
+ void deref() { derefThreadableLoader(); }
+
+ protected:
+ virtual ~ThreadableLoader() { }
+ virtual void refThreadableLoader() = 0;
+ virtual void derefThreadableLoader() = 0;
+ };
+
+} // namespace WebCore
+
+#endif // ThreadableLoader_h
diff --git a/WebCore/loader/ThreadableLoaderClient.h b/WebCore/loader/ThreadableLoaderClient.h
new file mode 100644
index 0000000..4fde404
--- /dev/null
+++ b/WebCore/loader/ThreadableLoaderClient.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2009, Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#ifndef ThreadableLoaderClient_h
+#define ThreadableLoaderClient_h
+
+namespace WebCore {
+
+ class ResourceResponse;
+
+ class ThreadableLoaderClient {
+ public:
+ virtual void didSendData(unsigned long long /*bytesSent*/, unsigned long long /*totalBytesToBeSent*/) { }
+
+ virtual void didReceiveResponse(const ResourceResponse&) { }
+ virtual void didReceiveData(const char*, int /*lengthReceived*/) { }
+ virtual void didFinishLoading(unsigned long /*identifer*/) { }
+ virtual void didFail() { }
+ virtual void didGetCancelled() { }
+
+ virtual void didReceiveAuthenticationCancellation(const ResourceResponse&) { }
+
+ protected:
+ virtual ~ThreadableLoaderClient() { }
+ };
+
+} // namespace WebCore
+
+#endif // ThreadableLoaderClient_h
diff --git a/WebCore/loader/appcache/ApplicationCache.cpp b/WebCore/loader/appcache/ApplicationCache.cpp
index d29eda8..abe8b22 100644
--- a/WebCore/loader/appcache/ApplicationCache.cpp
+++ b/WebCore/loader/appcache/ApplicationCache.cpp
@@ -51,10 +51,15 @@ ApplicationCache::~ApplicationCache()
void ApplicationCache::setGroup(ApplicationCacheGroup* group)
{
- ASSERT(!m_group);
+ ASSERT(!m_group || group == m_group);
m_group = group;
}
+bool ApplicationCache::isComplete() const
+{
+ return !m_group->cacheIsBeingUpdated(this);
+}
+
void ApplicationCache::setManifestResource(PassRefPtr<ApplicationCacheResource> manifest)
{
ASSERT(manifest);
@@ -76,6 +81,7 @@ void ApplicationCache::addResource(PassRefPtr<ApplicationCacheResource> resource
if (m_storageID) {
ASSERT(!resource->storageID());
+ ASSERT(resource->type() & (ApplicationCacheResource::Dynamic | ApplicationCacheResource::Implicit));
// Add the resource to the storage.
cacheStorage().store(resource.get(), this);
@@ -129,7 +135,7 @@ unsigned ApplicationCache::numDynamicEntries() const
return 0;
}
-String ApplicationCache::dynamicEntry(unsigned index) const
+String ApplicationCache::dynamicEntry(unsigned) const
{
// FIXME: Implement
return String();
@@ -137,20 +143,19 @@ String ApplicationCache::dynamicEntry(unsigned index) const
bool ApplicationCache::addDynamicEntry(const String& url)
{
- if (!equalIgnoringCase(m_group->manifestURL().protocol(),
- KURL(url).protocol()))
+ if (!equalIgnoringCase(m_group->manifestURL().protocol(), KURL(url).protocol()))
return false;
// FIXME: Implement
return true;
}
-void ApplicationCache::removeDynamicEntry(const String& url)
+void ApplicationCache::removeDynamicEntry(const String&)
{
// FIXME: Implement
}
-void ApplicationCache::setOnlineWhitelist(const HashSet<String>& onlineWhitelist)
+void ApplicationCache::setOnlineWhitelist(const Vector<KURL>& onlineWhitelist)
{
ASSERT(m_onlineWhitelist.isEmpty());
m_onlineWhitelist = onlineWhitelist;
@@ -158,14 +163,33 @@ void ApplicationCache::setOnlineWhitelist(const HashSet<String>& onlineWhitelist
bool ApplicationCache::isURLInOnlineWhitelist(const KURL& url)
{
- if (!url.hasRef())
- return m_onlineWhitelist.contains(url);
-
- KURL copy(url);
- copy.setRef(String());
- return m_onlineWhitelist.contains(copy);
+ size_t whitelistSize = m_onlineWhitelist.size();
+ for (size_t i = 0; i < whitelistSize; ++i) {
+ if (protocolHostAndPortAreEqual(url, m_onlineWhitelist[i]) && url.string().startsWith(m_onlineWhitelist[i].string()))
+ return true;
+ }
+ return false;
}
-
+
+void ApplicationCache::setFallbackURLs(const FallbackURLVector& fallbackURLs)
+{
+ ASSERT(m_fallbackURLs.isEmpty());
+ m_fallbackURLs = fallbackURLs;
+}
+
+bool ApplicationCache::urlMatchesFallbackNamespace(const KURL& url, KURL* fallbackURL)
+{
+ size_t fallbackCount = m_fallbackURLs.size();
+ for (size_t i = 0; i < fallbackCount; ++i) {
+ if (protocolHostAndPortAreEqual(url, m_fallbackURLs[i].first) && url.string().startsWith(m_fallbackURLs[i].first.string())) {
+ if (fallbackURL)
+ *fallbackURL = m_fallbackURLs[i].second;
+ return true;
+ }
+ }
+ return false;
+}
+
void ApplicationCache::clearStorageID()
{
m_storageID = 0;
diff --git a/WebCore/loader/appcache/ApplicationCache.h b/WebCore/loader/appcache/ApplicationCache.h
index e536cbe..77653f7 100644
--- a/WebCore/loader/appcache/ApplicationCache.h
+++ b/WebCore/loader/appcache/ApplicationCache.h
@@ -28,14 +28,13 @@
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
+#include "PlatformString.h"
+#include "StringHash.h"
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
-#include "StringHash.h"
-#include "PlatformString.h"
-
namespace WebCore {
class ApplicationCacheGroup;
@@ -43,7 +42,9 @@ class ApplicationCacheResource;
class DocumentLoader;
class KURL;
class ResourceRequest;
-
+
+typedef Vector<std::pair<KURL, KURL> > FallbackURLVector;
+
class ApplicationCache : public RefCounted<ApplicationCache> {
public:
static PassRefPtr<ApplicationCache> create() { return adoptRef(new ApplicationCache); }
@@ -57,7 +58,9 @@ public:
void setGroup(ApplicationCacheGroup*);
ApplicationCacheGroup* group() const { return m_group; }
-
+
+ bool isComplete() const;
+
ApplicationCacheResource* resourceForRequest(const ResourceRequest&);
ApplicationCacheResource* resourceForURL(const String& url);
@@ -67,9 +70,13 @@ public:
bool addDynamicEntry(const String& url);
void removeDynamicEntry(const String& url);
- void setOnlineWhitelist(const HashSet<String>& onlineWhitelist);
- const HashSet<String>& onlineWhitelist() const { return m_onlineWhitelist; }
- bool isURLInOnlineWhitelist(const KURL&);
+ void setOnlineWhitelist(const Vector<KURL>& onlineWhitelist);
+ const Vector<KURL>& onlineWhitelist() const { return m_onlineWhitelist; }
+ bool isURLInOnlineWhitelist(const KURL&); // There is an entry in online whitelist that has the same origin as the resource's URL and that is a prefix match for the resource's URL.
+
+ void setFallbackURLs(const FallbackURLVector&);
+ const FallbackURLVector& fallbackURLs() const { return m_fallbackURLs; }
+ bool urlMatchesFallbackNamespace(const KURL&, KURL* fallbackURL = 0);
#ifndef NDEBUG
void dump();
@@ -84,15 +91,20 @@ public:
void clearStorageID();
static bool requestIsHTTPOrHTTPSGet(const ResourceRequest&);
+
private:
ApplicationCache();
ApplicationCacheGroup* m_group;
ResourceMap m_resources;
ApplicationCacheResource* m_manifest;
-
- HashSet<String> m_onlineWhitelist;
-
+
+ Vector<KURL> m_onlineWhitelist;
+ FallbackURLVector m_fallbackURLs;
+
+ // While an update is in progress, changes in dynamic entries are queued for later execution.
+ Vector<std::pair<KURL, bool> > m_pendingDynamicEntryActions;
+
unsigned m_storageID;
};
diff --git a/WebCore/loader/appcache/ApplicationCacheGroup.cpp b/WebCore/loader/appcache/ApplicationCacheGroup.cpp
index ff26767..2367e79 100644
--- a/WebCore/loader/appcache/ApplicationCacheGroup.cpp
+++ b/WebCore/loader/appcache/ApplicationCacheGroup.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * 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
@@ -46,10 +46,11 @@ namespace WebCore {
ApplicationCacheGroup::ApplicationCacheGroup(const KURL& manifestURL, bool isCopy)
: m_manifestURL(manifestURL)
- , m_status(Idle)
- , m_savedNewestCachePointer(0)
+ , m_updateStatus(Idle)
, m_frame(0)
, m_storageID(0)
+ , m_isObsolete(false)
+ , m_completionType(None)
, m_isCopy(isCopy)
{
}
@@ -62,7 +63,7 @@ ApplicationCacheGroup::~ApplicationCacheGroup()
ASSERT(m_caches.contains(m_newestCache.get()));
ASSERT(!m_cacheBeingUpdated);
ASSERT(m_associatedDocumentLoaders.isEmpty());
- ASSERT(m_cacheCandidates.isEmpty());
+ ASSERT(m_pendingMasterResourceLoaders.isEmpty());
ASSERT(m_newestCache->group() == this);
return;
@@ -76,18 +77,14 @@ ApplicationCacheGroup::~ApplicationCacheGroup()
cacheStorage().cacheGroupDestroyed(this);
}
-ApplicationCache* ApplicationCacheGroup::cacheForMainRequest(const ResourceRequest& request, DocumentLoader* loader)
+ApplicationCache* ApplicationCacheGroup::cacheForMainRequest(const ResourceRequest& request, DocumentLoader*)
{
if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request))
return 0;
-
- ASSERT(loader->frame());
- ASSERT(loader->frame()->page());
- if (loader->frame() != loader->frame()->page()->mainFrame())
- return 0;
if (ApplicationCacheGroup* group = cacheStorage().cacheGroupForURL(request.url())) {
ASSERT(group->newestCache());
+ ASSERT(!group->isObsolete());
return group->newestCache();
}
@@ -95,6 +92,21 @@ ApplicationCache* ApplicationCacheGroup::cacheForMainRequest(const ResourceReque
return 0;
}
+ApplicationCache* ApplicationCacheGroup::fallbackCacheForMainRequest(const ResourceRequest& request, DocumentLoader*)
+{
+ if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request))
+ return 0;
+
+ if (ApplicationCacheGroup* group = cacheStorage().fallbackCacheGroupForURL(request.url())) {
+ ASSERT(group->newestCache());
+ ASSERT(!group->isObsolete());
+
+ return group->newestCache();
+ }
+
+ return 0;
+}
+
void ApplicationCacheGroup::selectCache(Frame* frame, const KURL& manifestURL)
{
ASSERT(frame && frame->page());
@@ -112,28 +124,22 @@ void ApplicationCacheGroup::selectCache(Frame* frame, const KURL& manifestURL)
ApplicationCache* mainResourceCache = documentLoader->mainResourceApplicationCache();
- // Check if the main resource is being loaded as part of navigation of the main frame
- bool isMainFrame = frame->page()->mainFrame() == frame;
-
- if (!isMainFrame) {
- if (mainResourceCache && manifestURL != mainResourceCache->group()->manifestURL()) {
- ApplicationCacheResource* resource = mainResourceCache->resourceForURL(documentLoader->originalURL());
- ASSERT(resource);
-
- resource->addType(ApplicationCacheResource::Foreign);
- }
-
- return;
- }
-
if (mainResourceCache) {
if (manifestURL == mainResourceCache->group()->m_manifestURL) {
mainResourceCache->group()->associateDocumentLoaderWithCache(documentLoader, mainResourceCache);
- mainResourceCache->group()->update(frame);
+ mainResourceCache->group()->update(frame, ApplicationCacheUpdateWithBrowsingContext);
} else {
- // FIXME: If the resource being loaded was loaded from an application cache and the URI of
- // that application cache's manifest is not the same as the manifest URI with which the algorithm was invoked
- // then we should "undo" the navigation.
+ // 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;
@@ -142,53 +148,20 @@ void ApplicationCacheGroup::selectCache(Frame* frame, const KURL& manifestURL)
// 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);
+ 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())) {
- selectCacheWithoutManifestURL(frame);
+ if (!protocolHostAndPortAreEqual(manifestURL, request.url()))
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);
- }
+
+ documentLoader->setCandidateApplicationCacheGroup(group);
+ group->m_pendingMasterResourceLoaders.add(documentLoader);
+
+ ASSERT(!group->m_cacheBeingUpdated || group->m_updateStatus != Idle);
+ group->update(frame, ApplicationCacheUpdateWithBrowsingContext);
}
void ApplicationCacheGroup::selectCacheWithoutManifestURL(Frame* frame)
@@ -200,54 +173,110 @@ void ApplicationCacheGroup::selectCacheWithoutManifestURL(Frame* frame)
ASSERT(!documentLoader->applicationCache());
ApplicationCache* mainResourceCache = documentLoader->mainResourceApplicationCache();
- bool isMainFrame = frame->page()->mainFrame() == frame;
- if (isMainFrame && mainResourceCache) {
+ if (mainResourceCache) {
mainResourceCache->group()->associateDocumentLoaderWithCache(documentLoader, mainResourceCache);
- mainResourceCache->group()->update(frame);
+ mainResourceCache->group()->update(frame, ApplicationCacheUpdateWithBrowsingContext);
}
}
void ApplicationCacheGroup::finishedLoadingMainResource(DocumentLoader* loader)
{
+ ASSERT(m_pendingMasterResourceLoaders.contains(loader));
+ ASSERT(m_completionType == None || m_pendingEntries.isEmpty());
const KURL& url = loader->originalURL();
-
- if (ApplicationCache* cache = loader->applicationCache()) {
- RefPtr<ApplicationCacheResource> resource = ApplicationCacheResource::create(url, loader->response(), ApplicationCacheResource::Implicit, loader->mainResourceData());
- cache->addResource(resource.release());
-
- if (!m_cacheBeingUpdated)
- return;
- }
-
- ASSERT(m_pendingEntries.contains(url));
-
- EntryMap::iterator it = m_pendingEntries.find(url);
- ASSERT(it->second & ApplicationCacheResource::Implicit);
- RefPtr<ApplicationCacheResource> resource = ApplicationCacheResource::create(url, loader->response(), it->second, loader->mainResourceData());
+ switch (m_completionType) {
+ case None:
+ // The main resource finished loading before the manifest was ready. It will be handled via dispatchMainResources() later.
+ return;
+ case NoUpdate:
+ ASSERT(!m_cacheBeingUpdated);
+ associateDocumentLoaderWithCache(loader, m_newestCache.get());
+
+ if (ApplicationCacheResource* resource = m_newestCache->resourceForURL(url)) {
+ if (!(resource->type() & ApplicationCacheResource::Implicit)) {
+ resource->addType(ApplicationCacheResource::Implicit);
+ ASSERT(!resource->storageID());
+ }
+ } else
+ m_newestCache->addResource(ApplicationCacheResource::create(url, loader->response(), ApplicationCacheResource::Implicit, loader->mainResourceData()));
+
+ break;
+ case Failure:
+ // Cache update has been a failure, so there is no reason to keep the document associated with the incomplete cache
+ // (its main resource was not cached yet, so it is likely that the application changed significantly server-side).
+ ASSERT(!m_cacheBeingUpdated); // Already cleared out by stopLoading().
+ loader->setApplicationCache(0); // Will unset candidate, too.
+ m_associatedDocumentLoaders.remove(loader);
+ postListenerTask(&DOMApplicationCache::callErrorListener, loader);
+ break;
+ case Completed:
+ ASSERT(m_associatedDocumentLoaders.contains(loader));
+
+ if (ApplicationCacheResource* resource = m_cacheBeingUpdated->resourceForURL(url)) {
+ if (!(resource->type() & ApplicationCacheResource::Implicit)) {
+ resource->addType(ApplicationCacheResource::Implicit);
+ ASSERT(!resource->storageID());
+ }
+ } else
+ m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, loader->response(), ApplicationCacheResource::Implicit, loader->mainResourceData()));
+ // The "cached" event will be posted to all associated documents once update is complete.
+ break;
+ }
- ASSERT(m_cacheBeingUpdated);
- m_cacheBeingUpdated->addResource(resource.release());
-
- m_pendingEntries.remove(it);
-
+ m_pendingMasterResourceLoaders.remove(loader);
checkIfLoadIsComplete();
}
void ApplicationCacheGroup::failedLoadingMainResource(DocumentLoader* loader)
{
- ASSERT(m_cacheCandidates.contains(loader) || m_associatedDocumentLoaders.contains(loader));
+ ASSERT(m_pendingMasterResourceLoaders.contains(loader));
+ ASSERT(m_completionType == None || m_pendingEntries.isEmpty());
- // Note that cacheUpdateFailed() can cause the cache group to be deleted.
- cacheUpdateFailed();
+ switch (m_completionType) {
+ case None:
+ // The main resource finished loading before the manifest was ready. It will be handled via dispatchMainResources() later.
+ return;
+ case NoUpdate:
+ ASSERT(!m_cacheBeingUpdated);
+
+ // The manifest didn't change, and we have a relevant cache - but the main resource download failed mid-way, so it cannot be stored to the cache,
+ // and the loader does not get associated to it. If there are other main resources being downloaded for this cache group, they may still succeed.
+ postListenerTask(&DOMApplicationCache::callErrorListener, loader);
+
+ break;
+ case Failure:
+ // Cache update failed, too.
+ ASSERT(!m_cacheBeingUpdated); // Already cleared out by stopLoading().
+ ASSERT(!loader->applicationCache() || loader->applicationCache() == m_cacheBeingUpdated);
+
+ loader->setApplicationCache(0); // Will unset candidate, too.
+ m_associatedDocumentLoaders.remove(loader);
+ postListenerTask(&DOMApplicationCache::callErrorListener, loader);
+ break;
+ case Completed:
+ // The cache manifest didn't list this main resource, and all cache entries were already updated successfully - but the main resource failed to load,
+ // so it cannot be stored to the cache. If there are other main resources being downloaded for this cache group, they may still succeed.
+ ASSERT(m_associatedDocumentLoaders.contains(loader));
+ ASSERT(loader->applicationCache() == m_cacheBeingUpdated);
+ ASSERT(!loader->candidateApplicationCacheGroup());
+ m_associatedDocumentLoaders.remove(loader);
+ loader->setApplicationCache(0);
+
+ postListenerTask(&DOMApplicationCache::callErrorListener, loader);
+
+ break;
+ }
+
+ m_pendingMasterResourceLoaders.remove(loader);
+ checkIfLoadIsComplete();
}
void ApplicationCacheGroup::stopLoading()
-{
+{
if (m_manifestHandle) {
ASSERT(!m_currentHandle);
- ASSERT(!m_cacheBeingUpdated);
m_manifestHandle->setClient(0);
m_manifestHandle->cancel();
@@ -264,91 +293,102 @@ void ApplicationCacheGroup::stopLoading()
}
m_cacheBeingUpdated = 0;
+ m_pendingEntries.clear();
}
-void ApplicationCacheGroup::documentLoaderDestroyed(DocumentLoader* loader)
+void ApplicationCacheGroup::disassociateDocumentLoader(DocumentLoader* loader)
{
HashSet<DocumentLoader*>::iterator it = m_associatedDocumentLoaders.find(loader);
-
- if (it != m_associatedDocumentLoaders.end()) {
- ASSERT(!m_cacheCandidates.contains(loader));
-
+ if (it != m_associatedDocumentLoaders.end())
m_associatedDocumentLoaders.remove(it);
- } else {
- ASSERT(m_cacheCandidates.contains(loader));
- m_cacheCandidates.remove(loader);
- }
-
- if (!m_associatedDocumentLoaders.isEmpty() || !m_cacheCandidates.isEmpty())
+
+ m_pendingMasterResourceLoaders.remove(loader);
+
+ loader->setApplicationCache(0); // Will set candidate to 0, too.
+
+ if (!m_associatedDocumentLoaders.isEmpty() || !m_pendingMasterResourceLoaders.isEmpty())
return;
-
- // We should only have the newest cache remaining, or there is an initial cache attempt in progress.
- ASSERT(m_caches.size() == 1 || m_cacheBeingUpdated);
-
- // If a cache update is in progress, stop it.
- if (m_caches.size() == 1) {
- ASSERT(m_caches.contains(m_newestCache.get()));
-
- // Release our reference to the newest cache.
- m_savedNewestCachePointer = m_newestCache.get();
-
- // This could cause us to be deleted.
- m_newestCache = 0;
-
+
+ if (m_caches.isEmpty()) {
+ // There is an initial cache attempt in progress.
+ ASSERT(!m_newestCache);
+ // Delete ourselves, causing the cache attempt to be stopped.
+ delete this;
return;
}
-
- // There is an initial cache attempt in progress
- ASSERT(m_cacheBeingUpdated);
- ASSERT(m_caches.size() == 0);
-
- // Delete ourselves, causing the cache attempt to be stopped.
- delete this;
-}
+
+ ASSERT(m_caches.contains(m_newestCache.get()));
+
+ // Release our reference to the newest cache. This could cause us to be deleted.
+ // Any ongoing updates will be stopped from destructor.
+ m_newestCache.release();
+}
void ApplicationCacheGroup::cacheDestroyed(ApplicationCache* cache)
{
- ASSERT(m_caches.contains(cache));
+ if (!m_caches.contains(cache))
+ return;
m_caches.remove(cache);
-
- if (cache != m_savedNewestCachePointer)
- cacheStorage().remove(cache);
- if (m_caches.isEmpty())
+ if (m_caches.isEmpty()) {
+ ASSERT(m_associatedDocumentLoaders.isEmpty());
+ ASSERT(m_pendingMasterResourceLoaders.isEmpty());
delete this;
+ }
}
void ApplicationCacheGroup::setNewestCache(PassRefPtr<ApplicationCache> newestCache)
-{
- ASSERT(!m_newestCache);
+{
ASSERT(!m_caches.contains(newestCache.get()));
- ASSERT(!newestCache->group());
-
- m_newestCache = newestCache;
+
+ m_newestCache = newestCache;
+
m_caches.add(m_newestCache.get());
m_newestCache->setGroup(this);
}
-void ApplicationCacheGroup::update(Frame* frame)
+void ApplicationCacheGroup::makeObsolete()
{
- if (m_status == Checking || m_status == Downloading)
+ if (isObsolete())
+ return;
+
+ m_isObsolete = true;
+ cacheStorage().cacheGroupMadeObsolete(this);
+ ASSERT(!m_storageID);
+}
+
+void ApplicationCacheGroup::update(Frame* frame, ApplicationCacheUpdateOption updateOption)
+{
+ if (m_updateStatus == Checking || m_updateStatus == Downloading) {
+ if (updateOption == ApplicationCacheUpdateWithBrowsingContext) {
+ postListenerTask(&DOMApplicationCache::callCheckingListener, frame->loader()->documentLoader());
+ if (m_updateStatus == Downloading)
+ postListenerTask(&DOMApplicationCache::callDownloadingListener, frame->loader()->documentLoader());
+ }
return;
+ }
ASSERT(!m_frame);
m_frame = frame;
- m_status = Checking;
+ m_updateStatus = Checking;
- callListenersOnAssociatedDocuments(&DOMApplicationCache::callCheckingListener);
+ postListenerTask(&DOMApplicationCache::callCheckingListener, m_associatedDocumentLoaders);
+ if (!m_newestCache) {
+ ASSERT(updateOption == ApplicationCacheUpdateWithBrowsingContext);
+ postListenerTask(&DOMApplicationCache::callCheckingListener, frame->loader()->documentLoader());
+ }
ASSERT(!m_manifestHandle);
ASSERT(!m_manifestResource);
-
+ ASSERT(m_completionType == None);
+
// FIXME: Handle defer loading
ResourceRequest request(m_manifestURL);
m_frame->loader()->applyUserAgent(request);
+ // FIXME: Should ask to revalidate from origin.
m_manifestHandle = ResourceHandle::create(request, this, m_frame, false, true, false);
}
@@ -361,14 +401,7 @@ void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, const Res
}
ASSERT(handle == m_currentHandle);
-
- int statusCode = response.httpStatusCode() / 100;
- if (statusCode == 4 || statusCode == 5) {
- // Note that cacheUpdateFailed() can cause the cache group to be deleted.
- cacheUpdateFailed();
- return;
- }
-
+
const KURL& url = handle->request().url();
ASSERT(!m_currentResource);
@@ -379,11 +412,37 @@ void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, const Res
// If this is an initial cache attempt, we should not get implicit resources delivered here.
if (!m_newestCache)
ASSERT(!(type & ApplicationCacheResource::Implicit));
+
+ 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();
+ } else if (response.httpStatusCode() == 404 || response.httpStatusCode() == 410) {
+ // Skip this resource. It is dropped from the cache.
+ m_currentHandle->cancel();
+ m_currentHandle = 0;
+ m_pendingEntries.remove(handle->request().url());
+ // Load the next resource, if any.
+ startLoadingEntry();
+ } else {
+ // 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.
+ m_currentHandle->cancel();
+ m_currentHandle = 0;
+ startLoadingEntry();
+ }
+ return;
+ }
m_currentResource = ApplicationCacheResource::create(url, response, type);
}
-void ApplicationCacheGroup::didReceiveData(ResourceHandle* handle, const char* data, int length, int lengthReceived)
+void ApplicationCacheGroup::didReceiveData(ResourceHandle* handle, const char* data, int length, int)
{
if (handle == m_manifestHandle) {
didReceiveManifestData(data, length);
@@ -413,38 +472,53 @@ void ApplicationCacheGroup::didFinishLoading(ResourceHandle* handle)
m_cacheBeingUpdated->addResource(m_currentResource.release());
m_currentHandle = 0;
- // Load the next file.
- if (!m_pendingEntries.isEmpty()) {
- startLoadingEntry();
- return;
- }
-
- checkIfLoadIsComplete();
+ // Load the next resource, if any.
+ startLoadingEntry();
}
void ApplicationCacheGroup::didFail(ResourceHandle* handle, const ResourceError&)
{
if (handle == m_manifestHandle) {
- didFailToLoadManifest();
+ cacheUpdateFailed();
return;
}
-
- // Note that cacheUpdateFailed() can cause the cache group to be deleted.
- cacheUpdateFailed();
+
+ unsigned type = m_currentResource ? m_currentResource->type() : m_pendingEntries.get(handle->request().url());
+
+ ASSERT(!m_currentResource || !m_pendingEntries.contains(handle->request().url()));
+ m_currentResource = 0;
+ m_pendingEntries.remove(handle->request().url());
+
+ if ((type & ApplicationCacheResource::Explicit) || (type & ApplicationCacheResource::Fallback)) {
+ // Note that cacheUpdateFailed() can cause the cache group to be deleted.
+ cacheUpdateFailed();
+ } else {
+ // 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.
+ startLoadingEntry();
+ }
}
void ApplicationCacheGroup::didReceiveManifestResponse(const ResourceResponse& response)
{
- int statusCode = response.httpStatusCode() / 100;
+ ASSERT(!m_manifestResource);
+ ASSERT(m_manifestHandle);
- if (statusCode == 4 || statusCode == 5 ||
- !equalIgnoringCase(response.mimeType(), "text/cache-manifest")) {
- didFailToLoadManifest();
+ if (response.httpStatusCode() == 404 || response.httpStatusCode() == 410) {
+ manifestNotFound();
return;
}
-
- ASSERT(!m_manifestResource);
- ASSERT(m_manifestHandle);
+
+ if (response.httpStatusCode() / 100 != 2 || response.url() != m_manifestHandle->request().url() || !equalIgnoringCase(response.mimeType(), "text/cache-manifest")) {
+ cacheUpdateFailed();
+ return;
+ }
+
m_manifestResource = ApplicationCacheResource::create(m_manifestHandle->request().url(), response,
ApplicationCacheResource::Manifest);
}
@@ -458,7 +532,7 @@ void ApplicationCacheGroup::didReceiveManifestData(const char* data, int length)
void ApplicationCacheGroup::didFinishLoadingManifest()
{
if (!m_manifestResource) {
- didFailToLoadManifest();
+ cacheUpdateFailed();
return;
}
@@ -473,47 +547,41 @@ void ApplicationCacheGroup::didFinishLoadingManifest()
if (newestManifest->data()->size() == m_manifestResource->data()->size() &&
!memcmp(newestManifest->data()->data(), m_manifestResource->data()->data(), newestManifest->data()->size())) {
-
- callListenersOnAssociatedDocuments(&DOMApplicationCache::callNoUpdateListener);
-
- m_status = Idle;
- m_frame = 0;
+
+ m_completionType = NoUpdate;
m_manifestResource = 0;
+ deliverDelayedMainResources();
+
return;
}
}
Manifest manifest;
if (!parseManifest(m_manifestURL, m_manifestResource->data()->data(), m_manifestResource->data()->size(), manifest)) {
- didFailToLoadManifest();
+ cacheUpdateFailed();
return;
}
-
- // FIXME: Add the opportunistic caching namespaces and their fallbacks.
-
+
+ ASSERT(!m_cacheBeingUpdated);
+ m_cacheBeingUpdated = ApplicationCache::create();
+ m_cacheBeingUpdated->setGroup(this);
+
+ HashSet<DocumentLoader*>::const_iterator masterEnd = m_pendingMasterResourceLoaders.end();
+ for (HashSet<DocumentLoader*>::const_iterator iter = m_pendingMasterResourceLoaders.begin(); iter != masterEnd; ++iter)
+ associateDocumentLoaderWithCache(*iter, m_cacheBeingUpdated.get());
+
// We have the manifest, now download the resources.
- m_status = Downloading;
+ m_updateStatus = Downloading;
- callListenersOnAssociatedDocuments(&DOMApplicationCache::callDownloadingListener);
+ postListenerTask(&DOMApplicationCache::callDownloadingListener, m_associatedDocumentLoaders);
+
+ ASSERT(m_pendingEntries.isEmpty());
-#ifndef NDEBUG
- // We should only have implicit entries.
- {
- EntryMap::const_iterator end = m_pendingEntries.end();
- for (EntryMap::const_iterator it = m_pendingEntries.begin(); it != end; ++it)
- ASSERT(it->second & ApplicationCacheResource::Implicit);
- }
-#endif
-
if (isUpgradeAttempt) {
- ASSERT(!m_cacheBeingUpdated);
-
- m_cacheBeingUpdated = ApplicationCache::create();
-
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::Opportunistic | ApplicationCacheResource::Implicit | ApplicationCacheResource::Dynamic))
+ if (type & (ApplicationCacheResource::Implicit | ApplicationCacheResource::Dynamic))
addEntry(it->first, type);
}
}
@@ -521,8 +589,13 @@ void ApplicationCacheGroup::didFinishLoadingManifest()
HashSet<String>::const_iterator end = manifest.explicitURLs.end();
for (HashSet<String>::const_iterator it = manifest.explicitURLs.begin(); it != end; ++it)
addEntry(*it, ApplicationCacheResource::Explicit);
+
+ size_t fallbackCount = manifest.fallbackURLs.size();
+ for (size_t i = 0; i < fallbackCount; ++i)
+ addEntry(manifest.fallbackURLs[i].second, ApplicationCacheResource::Fallback);
m_cacheBeingUpdated->setOnlineWhitelist(manifest.onlineWhitelistedURLs);
+ m_cacheBeingUpdated->setFallbackURLs(manifest.fallbackURLs);
startLoadingEntry();
}
@@ -530,82 +603,94 @@ void ApplicationCacheGroup::didFinishLoadingManifest()
void ApplicationCacheGroup::cacheUpdateFailed()
{
stopLoading();
-
- callListenersOnAssociatedDocuments(&DOMApplicationCache::callErrorListener);
+ m_manifestResource = 0;
- m_pendingEntries.clear();
+ // Wait for master resource loads to finish.
+ m_completionType = Failure;
+ deliverDelayedMainResources();
+}
+
+void ApplicationCacheGroup::manifestNotFound()
+{
+ makeObsolete();
+
+ postListenerTask(&DOMApplicationCache::callObsoleteListener, m_associatedDocumentLoaders);
+ postListenerTask(&DOMApplicationCache::callErrorListener, m_pendingMasterResourceLoaders);
+
+ stopLoading();
+
+ ASSERT(m_pendingEntries.isEmpty());
m_manifestResource = 0;
- while (!m_cacheCandidates.isEmpty()) {
- HashSet<DocumentLoader*>::iterator it = m_cacheCandidates.begin();
+ while (!m_pendingMasterResourceLoaders.isEmpty()) {
+ HashSet<DocumentLoader*>::iterator it = m_pendingMasterResourceLoaders.begin();
ASSERT((*it)->candidateApplicationCacheGroup() == this);
+ ASSERT(!(*it)->applicationCache());
(*it)->setCandidateApplicationCacheGroup(0);
- m_cacheCandidates.remove(it);
+ m_pendingMasterResourceLoaders.remove(it);
}
-
- m_status = Idle;
+
+ m_updateStatus = Idle;
m_frame = 0;
- // If there are no associated caches, delete ourselves
- if (m_associatedDocumentLoaders.isEmpty())
+ if (m_caches.isEmpty()) {
+ ASSERT(m_associatedDocumentLoaders.isEmpty());
+ ASSERT(!m_cacheBeingUpdated);
delete this;
-}
-
-
-void ApplicationCacheGroup::didFailToLoadManifest()
-{
- // Note that cacheUpdateFailed() can cause the cache group to be deleted.
- cacheUpdateFailed();
+ }
}
void ApplicationCacheGroup::checkIfLoadIsComplete()
{
- ASSERT(m_cacheBeingUpdated);
-
- if (m_manifestHandle)
+ if (m_manifestHandle || !m_pendingEntries.isEmpty() || !m_pendingMasterResourceLoaders.isEmpty())
return;
- if (!m_pendingEntries.isEmpty())
- return;
-
- // We're done
+ // We're done, all resources have finished downloading (successfully or not).
+
bool isUpgradeAttempt = m_newestCache;
-
- m_cacheBeingUpdated->setManifestResource(m_manifestResource.release());
-
- m_status = Idle;
- m_frame = 0;
-
- Vector<RefPtr<DocumentLoader> > documentLoaders;
-
- if (isUpgradeAttempt) {
- ASSERT(m_cacheCandidates.isEmpty());
-
- copyToVector(m_associatedDocumentLoaders, documentLoaders);
- } else {
- while (!m_cacheCandidates.isEmpty()) {
- HashSet<DocumentLoader*>::iterator it = m_cacheCandidates.begin();
-
- DocumentLoader* loader = *it;
- ASSERT(!loader->applicationCache());
- ASSERT(loader->candidateApplicationCacheGroup() == this);
-
- associateDocumentLoaderWithCache(loader, m_cacheBeingUpdated.get());
-
- documentLoaders.append(loader);
- m_cacheCandidates.remove(it);
+ switch (m_completionType) {
+ case None:
+ ASSERT_NOT_REACHED();
+ return;
+ case NoUpdate:
+ ASSERT(isUpgradeAttempt);
+ ASSERT(!m_cacheBeingUpdated);
+ ASSERT(m_storageID);
+ postListenerTask(&DOMApplicationCache::callNoUpdateListener, m_associatedDocumentLoaders);
+ break;
+ case Failure:
+ ASSERT(!m_cacheBeingUpdated);
+ postListenerTask(&DOMApplicationCache::callErrorListener, m_associatedDocumentLoaders);
+ if (m_caches.isEmpty()) {
+ ASSERT(m_associatedDocumentLoaders.isEmpty());
+ delete this;
+ return;
}
+ break;
+ case Completed: {
+ // FIXME: Fetch the resource from manifest URL again, and check whether it is identical to the one used for update (in case the application was upgraded server-side in the meanwhile). (<rdar://problem/6467625>)
+
+ ASSERT(m_cacheBeingUpdated);
+ m_cacheBeingUpdated->setManifestResource(m_manifestResource.release());
+
+ RefPtr<ApplicationCache> oldNewestCache = (m_newestCache == m_cacheBeingUpdated) ? 0 : m_newestCache;
+
+ setNewestCache(m_cacheBeingUpdated.release());
+ cacheStorage().storeNewestCache(this);
+
+ if (oldNewestCache)
+ cacheStorage().remove(oldNewestCache.get());
+
+ postListenerTask(isUpgradeAttempt ? &DOMApplicationCache::callUpdateReadyListener : &DOMApplicationCache::callCachedListener, m_associatedDocumentLoaders);
+ break;
}
-
- setNewestCache(m_cacheBeingUpdated.release());
-
- // Store the cache
- cacheStorage().storeNewestCache(this);
-
- callListeners(isUpgradeAttempt ? &DOMApplicationCache::callUpdateReadyListener : &DOMApplicationCache::callCachedListener,
- documentLoaders);
+ }
+
+ m_completionType = None;
+ m_updateStatus = Idle;
+ m_frame = 0;
}
void ApplicationCacheGroup::startLoadingEntry()
@@ -613,27 +698,14 @@ void ApplicationCacheGroup::startLoadingEntry()
ASSERT(m_cacheBeingUpdated);
if (m_pendingEntries.isEmpty()) {
- checkIfLoadIsComplete();
+ m_completionType = Completed;
+ deliverDelayedMainResources();
return;
}
EntryMap::const_iterator it = m_pendingEntries.begin();
- // If this is an initial cache attempt, we do not want to fetch any implicit entries,
- // since those are fed to us by the normal loader machinery.
- if (!m_newestCache) {
- // Get the first URL in the entry table that is not implicit
- EntryMap::const_iterator end = m_pendingEntries.end();
-
- while (it->second & ApplicationCacheResource::Implicit) {
- ++it;
-
- if (it == end)
- return;
- }
- }
-
- callListenersOnAssociatedDocuments(&DOMApplicationCache::callProgressListener);
+ postListenerTask(&DOMApplicationCache::callProgressListener, m_associatedDocumentLoaders);
// FIXME: If this is an upgrade attempt, the newest cache should be used as an HTTP cache.
@@ -641,24 +713,49 @@ void ApplicationCacheGroup::startLoadingEntry()
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);
}
+void ApplicationCacheGroup::deliverDelayedMainResources()
+{
+ // Need to copy loaders, because the cache group may be destroyed at the end of iteration.
+ Vector<DocumentLoader*> loaders;
+ copyToVector(m_pendingMasterResourceLoaders, loaders);
+ size_t count = loaders.size();
+ for (size_t i = 0; i != count; ++i) {
+ DocumentLoader* loader = loaders[i];
+ if (loader->isLoadingMainResource())
+ continue;
+
+ const ResourceError& error = loader->mainDocumentError();
+ if (error.isNull())
+ finishedLoadingMainResource(loader);
+ else
+ failedLoadingMainResource(loader);
+ }
+ if (!count)
+ checkIfLoadIsComplete();
+}
+
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
+ // (i.e., the main resource finished loading before the manifest).
if (ApplicationCacheResource* resource = m_cacheBeingUpdated->resourceForURL(url)) {
ASSERT(resource->type() & ApplicationCacheResource::Implicit);
+ ASSERT(!m_frame->loader()->documentLoader()->isLoadingMainResource());
resource->addType(type);
return;
}
// Don't add the URL if it's the same as the manifest URL.
- if (m_manifestResource && m_manifestResource->url() == url) {
+ ASSERT(m_manifestResource);
+ if (m_manifestResource->url() == url) {
m_manifestResource->addType(type);
return;
}
@@ -671,33 +768,60 @@ void ApplicationCacheGroup::addEntry(const String& url, unsigned type)
void ApplicationCacheGroup::associateDocumentLoaderWithCache(DocumentLoader* loader, ApplicationCache* cache)
{
+ // If teardown started already, revive the group.
+ if (!m_newestCache && !m_cacheBeingUpdated)
+ m_newestCache = cache;
+
+ ASSERT(!m_isObsolete);
+
loader->setApplicationCache(cache);
-
+
ASSERT(!m_associatedDocumentLoaders.contains(loader));
m_associatedDocumentLoaders.add(loader);
}
-void ApplicationCacheGroup::callListenersOnAssociatedDocuments(ListenerFunction listenerFunction)
-{
- Vector<RefPtr<DocumentLoader> > loaders;
- copyToVector(m_associatedDocumentLoaders, loaders);
+class CallCacheListenerTask : public ScriptExecutionContext::Task {
+ typedef void (DOMApplicationCache::*ListenerFunction)();
+public:
+ static PassRefPtr<CallCacheListenerTask> create(ListenerFunction listenerFunction)
+ {
+ return adoptRef(new CallCacheListenerTask(listenerFunction));
+ }
- callListeners(listenerFunction, loaders);
+ virtual void performTask(ScriptExecutionContext* context)
+ {
+ ASSERT(context->isDocument());
+ if (DOMWindow* window = static_cast<Document*>(context)->domWindow()) {
+ if (DOMApplicationCache* domCache = window->optionalApplicationCache())
+ (domCache->*m_listenerFunction)();
+ }
+ }
+
+private:
+ CallCacheListenerTask(ListenerFunction listenerFunction)
+ : m_listenerFunction(listenerFunction)
+ {
+ }
+
+ ListenerFunction m_listenerFunction;
+};
+
+void ApplicationCacheGroup::postListenerTask(ListenerFunction listenerFunction, const HashSet<DocumentLoader*>& loaderSet)
+{
+ HashSet<DocumentLoader*>::const_iterator loaderSetEnd = loaderSet.end();
+ for (HashSet<DocumentLoader*>::const_iterator iter = loaderSet.begin(); iter != loaderSetEnd; ++iter)
+ postListenerTask(listenerFunction, *iter);
}
-
-void ApplicationCacheGroup::callListeners(ListenerFunction listenerFunction, const Vector<RefPtr<DocumentLoader> >& loaders)
+
+void ApplicationCacheGroup::postListenerTask(ListenerFunction listenerFunction, DocumentLoader* loader)
{
- for (unsigned i = 0; i < loaders.size(); i++) {
- Frame* frame = loaders[i]->frame();
- if (!frame)
- continue;
-
- ASSERT(frame->loader()->documentLoader() == loaders[i]);
- DOMWindow* window = frame->domWindow();
-
- if (DOMApplicationCache* domCache = window->optionalApplicationCache())
- (domCache->*listenerFunction)();
- }
+ Frame* frame = loader->frame();
+ if (!frame)
+ return;
+
+ ASSERT(frame->loader()->documentLoader() == loader);
+
+ frame->document()->postTask(CallCacheListenerTask::create(listenerFunction));
}
void ApplicationCacheGroup::clearStorageID()
diff --git a/WebCore/loader/appcache/ApplicationCacheGroup.h b/WebCore/loader/appcache/ApplicationCacheGroup.h
index d5b7563..e4b2d3e 100644
--- a/WebCore/loader/appcache/ApplicationCacheGroup.h
+++ b/WebCore/loader/appcache/ApplicationCacheGroup.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * 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
@@ -47,43 +47,55 @@ class Document;
class DocumentLoader;
class Frame;
+enum ApplicationCacheUpdateOption {
+ ApplicationCacheUpdateWithBrowsingContext,
+ ApplicationCacheUpdateWithoutBrowsingContext
+};
+
class ApplicationCacheGroup : Noncopyable, ResourceHandleClient {
public:
ApplicationCacheGroup(const KURL& manifestURL, bool isCopy = false);
~ApplicationCacheGroup();
- enum Status { Idle, Checking, Downloading };
+ enum UpdateStatus { Idle, Checking, Downloading };
static ApplicationCache* cacheForMainRequest(const ResourceRequest&, DocumentLoader*);
+ static ApplicationCache* fallbackCacheForMainRequest(const ResourceRequest&, DocumentLoader*);
static void selectCache(Frame*, const KURL& manifestURL);
static void selectCacheWithoutManifestURL(Frame*);
const KURL& manifestURL() const { return m_manifestURL; }
- Status status() const { return m_status; }
-
+ UpdateStatus updateStatus() const { return m_updateStatus; }
+
void setStorageID(unsigned storageID) { m_storageID = storageID; }
unsigned storageID() const { return m_storageID; }
void clearStorageID();
- void update(Frame*);
+ void update(Frame*, ApplicationCacheUpdateOption); // FIXME: Frame should not bee needed when updating witout browsing context.
void cacheDestroyed(ApplicationCache*);
-
+
+ bool cacheIsBeingUpdated(const ApplicationCache* cache) const { return cache == m_cacheBeingUpdated; }
+
ApplicationCache* newestCache() const { return m_newestCache.get(); }
- ApplicationCache* savedNewestCachePointer() const { return m_savedNewestCachePointer; }
-
+ void setNewestCache(PassRefPtr<ApplicationCache>);
+
+ void makeObsolete();
+ bool isObsolete() const { return m_isObsolete; }
+
void finishedLoadingMainResource(DocumentLoader*);
void failedLoadingMainResource(DocumentLoader*);
- void documentLoaderDestroyed(DocumentLoader*);
- void setNewestCache(PassRefPtr<ApplicationCache> newestCache);
+ void disassociateDocumentLoader(DocumentLoader*);
bool isCopy() const { return m_isCopy; }
+
private:
typedef void (DOMApplicationCache::*ListenerFunction)();
- void callListenersOnAssociatedDocuments(ListenerFunction);
- void callListeners(ListenerFunction, const Vector<RefPtr<DocumentLoader> >& loaders);
-
+ void postListenerTask(ListenerFunction, const HashSet<DocumentLoader*>&);
+ void postListenerTask(ListenerFunction, const Vector<RefPtr<DocumentLoader> >& loaders);
+ void postListenerTask(ListenerFunction, DocumentLoader*);
+
virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&);
virtual void didReceiveData(ResourceHandle*, const char*, int, int lengthReceived);
virtual void didFinishLoading(ResourceHandle*);
@@ -92,11 +104,12 @@ private:
void didReceiveManifestResponse(const ResourceResponse&);
void didReceiveManifestData(const char*, int);
void didFinishLoadingManifest();
- void didFailToLoadManifest();
void startLoadingEntry();
+ void deliverDelayedMainResources();
void checkIfLoadIsComplete();
void cacheUpdateFailed();
+ void manifestNotFound();
void addEntry(const String&, unsigned type);
@@ -105,36 +118,45 @@ private:
void stopLoading();
KURL m_manifestURL;
- Status m_status;
+ UpdateStatus m_updateStatus;
- // This is the newest cache in the group.
+ // This is the newest complete cache in the group.
RefPtr<ApplicationCache> m_newestCache;
- // During tear-down we save the pointer to the newest cache to prevent reference cycles.
- ApplicationCache* m_savedNewestCachePointer;
-
- // The caches in this cache group.
+ // All complete caches in this cache group.
HashSet<ApplicationCache*> m_caches;
- // The cache being updated (if any).
+ // The cache being updated (if any). Note that cache updating does not immediately create a new
+ // ApplicationCache object, so this may be null even when update status is not Idle.
RefPtr<ApplicationCache> m_cacheBeingUpdated;
- // When a cache group does not yet have a complete cache, this contains the document loaders
- // that should be associated with the cache once it has been downloaded.
- HashSet<DocumentLoader*> m_cacheCandidates;
+ // List of pending master entries, used during the update process to ensure that new master entries are cached.
+ HashSet<DocumentLoader*> m_pendingMasterResourceLoaders;
// These are all the document loaders that are associated with a cache in this group.
HashSet<DocumentLoader*> m_associatedDocumentLoaders;
-
+
// The URLs and types of pending cache entries.
typedef HashMap<String, unsigned> EntryMap;
EntryMap m_pendingEntries;
- // Frame used for fetching resources when updating
+ // Frame used for fetching resources when updating.
+ // FIXME: An update started by a particular frame should not stop if it is destroyed, but there are other frames associated with the same cache group.
Frame* m_frame;
+ // An obsolete cache group is never stored, but the opposite is not true - storing may fail for multiple reasons, such as exceeding disk quota.
unsigned m_storageID;
-
+ bool m_isObsolete;
+
+ // During update, this is used to handle asynchronously arriving results.
+ enum CompletionType {
+ None,
+ NoUpdate,
+ Failure,
+ Completed
+ };
+ CompletionType m_completionType;
+
// Whether this cache group is a copy that's only used for transferring the cache to another file.
bool m_isCopy;
diff --git a/WebCore/loader/appcache/ApplicationCacheResource.cpp b/WebCore/loader/appcache/ApplicationCacheResource.cpp
index ee82ff5..d78cf7f 100644
--- a/WebCore/loader/appcache/ApplicationCacheResource.cpp
+++ b/WebCore/loader/appcache/ApplicationCacheResource.cpp
@@ -39,8 +39,8 @@ ApplicationCacheResource::ApplicationCacheResource(const KURL& url, const Resour
}
void ApplicationCacheResource::addType(unsigned type)
-{
- ASSERT(!m_storageID);
+{
+ // Caller should take care of storing the new type in database.
m_type |= type;
}
@@ -57,8 +57,6 @@ void ApplicationCacheResource::dumpType(unsigned type)
printf("foreign ");
if (type & Fallback)
printf("fallback ");
- if (type & Opportunistic)
- printf("opportunistic ");
if (type & Dynamic)
printf("dynamic ");
diff --git a/WebCore/loader/appcache/ApplicationCacheResource.h b/WebCore/loader/appcache/ApplicationCacheResource.h
index 1d7b853..96f5a0e 100644
--- a/WebCore/loader/appcache/ApplicationCacheResource.h
+++ b/WebCore/loader/appcache/ApplicationCacheResource.h
@@ -40,8 +40,7 @@ public:
Explicit = 1 << 2,
Foreign = 1 << 3,
Fallback = 1 << 4,
- Opportunistic = 1 << 5,
- Dynamic = 1 << 6
+ Dynamic = 1 << 5
};
static PassRefPtr<ApplicationCacheResource> create(const KURL& url, const ResourceResponse& response, unsigned type, PassRefPtr<SharedBuffer> buffer = SharedBuffer::create())
diff --git a/WebCore/loader/appcache/ApplicationCacheStorage.cpp b/WebCore/loader/appcache/ApplicationCacheStorage.cpp
index 910d00c..791df22 100644
--- a/WebCore/loader/appcache/ApplicationCacheStorage.cpp
+++ b/WebCore/loader/appcache/ApplicationCacheStorage.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * 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
@@ -31,11 +31,15 @@
#include "ApplicationCache.h"
#include "ApplicationCacheGroup.h"
#include "ApplicationCacheResource.h"
-#include "FileSystem.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 {
@@ -68,7 +72,7 @@ ApplicationCacheGroup* ApplicationCacheStorage::loadCacheGroup(const KURL& manif
return 0;
}
- unsigned newestCacheStorageID = (unsigned)statement.getColumnInt64(2);
+ unsigned newestCacheStorageID = static_cast<unsigned>(statement.getColumnInt64(2));
RefPtr<ApplicationCache> cache = loadCache(newestCacheStorageID);
if (!cache)
@@ -76,7 +80,7 @@ ApplicationCacheGroup* ApplicationCacheStorage::loadCacheGroup(const KURL& manif
ApplicationCacheGroup* group = new ApplicationCacheGroup(manifestURL);
- group->setStorageID((unsigned)statement.getColumnInt64(0));
+ group->setStorageID(static_cast<unsigned>(statement.getColumnInt64(0)));
group->setNewestCache(cache.release());
return group;
@@ -128,7 +132,7 @@ void ApplicationCacheStorage::loadManifestHostHashes()
int result;
while ((result = statement.step()) == SQLResultRow)
- m_cacheHostSet.add((unsigned)statement.getColumnInt64(0));
+ m_cacheHostSet.add(static_cast<unsigned>(statement.getColumnInt64(0)));
}
ApplicationCacheGroup* ApplicationCacheStorage::cacheGroupForURL(const KURL& url)
@@ -143,13 +147,19 @@ ApplicationCacheGroup* ApplicationCacheStorage::cacheGroupForURL(const KURL& url
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()) {
- if (cache->resourceForURL(url))
- return group;
+ ApplicationCacheResource* resource = cache->resourceForURL(url);
+ if (!resource)
+ continue;
+ if (resource->type() & ApplicationCacheResource::Foreign)
+ continue;
+ return group;
}
}
@@ -165,23 +175,93 @@ ApplicationCacheGroup* ApplicationCacheStorage::cacheGroupForURL(const KURL& url
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 = (unsigned)statement.getColumnInt64(2);
+ 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);
- if (!cache->resourceForURL(url))
+ KURL fallbackURL;
+ if (!cache->urlMatchesFallbackNamespace(url, &fallbackURL))
+ continue;
+ if (cache->resourceForURL(fallbackURL)->type() & ApplicationCacheResource::Foreign)
continue;
ApplicationCacheGroup* group = new ApplicationCacheGroup(manifestURL);
- group->setStorageID((unsigned)statement.getColumnInt64(0));
+ group->setStorageID(static_cast<unsigned>(statement.getColumnInt64(0)));
group->setNewestCache(cache.release());
- ASSERT(!m_cachesInMemory.contains(manifestURL));
m_cachesInMemory.set(group->manifestURL(), group);
return group;
@@ -195,15 +275,33 @@ ApplicationCacheGroup* ApplicationCacheStorage::cacheGroupForURL(const KURL& url
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 is half-created, we don't want it in the saved set.
- if (!group->savedNewestCachePointer())
+ // 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());
@@ -212,6 +310,12 @@ void ApplicationCacheStorage::setCacheDirectory(const String& cacheDirectory)
m_cacheDirectory = cacheDirectory;
}
+const String& ApplicationCacheStorage::cacheDirectory() const
+{
+ return m_cacheDirectory;
+}
+
+
bool ApplicationCacheStorage::executeSQLCommand(const String& sql)
{
ASSERT(m_database.isOpen());
@@ -224,30 +328,30 @@ bool ApplicationCacheStorage::executeSQLCommand(const String& sql)
return result;
}
-static const int SchemaVersion = 2;
+static const int schemaVersion = 3;
void ApplicationCacheStorage::verifySchemaVersion()
{
- if (m_database.tableExists("SchemaVersion")) {
- int version = SQLiteStatement(m_database, "SELECT version from SchemaVersion").getColumnInt(0);
-
- if (version == SchemaVersion)
- return;
- }
-
+ int version = SQLiteStatement(m_database, "PRAGMA user_version").getColumnInt(0);
+ if (version == schemaVersion)
+ return;
+
m_database.clearAllTables();
- SQLiteTransaction createSchemaVersionTable(m_database);
- createSchemaVersionTable.begin();
+ // Update user version.
+ SQLiteTransaction setDatabaseVersion(m_database);
+ setDatabaseVersion.begin();
- executeSQLCommand("CREATE TABLE SchemaVersion (version INTEGER NOT NULL)");
- SQLiteStatement statement(m_database, "INSERT INTO SchemaVersion (version) VALUES (?)");
+ 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;
- statement.bindInt64(1, SchemaVersion);
executeStatement(statement);
- createSchemaVersionTable.commit();
+ setDatabaseVersion.commit();
}
void ApplicationCacheStorage::openDatabase(bool createIfDoesNotExist)
@@ -290,7 +394,13 @@ void ApplicationCacheStorage::openDatabase(bool createIfDoesNotExist)
" 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"
@@ -322,7 +432,7 @@ bool ApplicationCacheStorage::store(ApplicationCacheGroup* group)
if (!executeStatement(statement))
return false;
- group->setStorageID((unsigned)m_database.lastInsertRowID());
+ group->setStorageID(static_cast<unsigned>(m_database.lastInsertRowID()));
return true;
}
@@ -340,7 +450,7 @@ bool ApplicationCacheStorage::store(ApplicationCache* cache)
if (!executeStatement(statement))
return false;
- unsigned cacheStorageID = (unsigned)m_database.lastInsertRowID();
+ unsigned cacheStorageID = static_cast<unsigned>(m_database.lastInsertRowID());
// Store all resources
{
@@ -352,14 +462,14 @@ bool ApplicationCacheStorage::store(ApplicationCache* cache)
}
// Store the online whitelist
- const HashSet<String>& onlineWhitelist = cache->onlineWhitelist();
+ const Vector<KURL>& onlineWhitelist = cache->onlineWhitelist();
{
- HashSet<String>::const_iterator end = onlineWhitelist.end();
- for (HashSet<String>::const_iterator it = onlineWhitelist.begin(); it != end; ++it) {
+ size_t whitelistSize = onlineWhitelist.size();
+ for (size_t i = 0; i < whitelistSize; ++i) {
SQLiteStatement statement(m_database, "INSERT INTO CacheWhitelistURLs (url, cache) VALUES (?, ?)");
statement.prepare();
- statement.bindText(1, *it);
+ statement.bindText(1, onlineWhitelist[i]);
statement.bindInt64(2, cacheStorageID);
if (!executeStatement(statement))
@@ -367,6 +477,23 @@ bool ApplicationCacheStorage::store(ApplicationCache* cache)
}
}
+ // Store fallback URLs.
+ const FallbackURLVector& fallbackURLs = cache->fallbackURLs();
+ {
+ size_t fallbackCount = fallbackURLs.size();
+ for (size_t i = 0; i < fallbackCount; ++i) {
+ SQLiteStatement statement(m_database, "INSERT INTO FallbackURLs (namespace, fallbackURL, cache) VALUES (?, ?, ?)");
+ statement.prepare();
+
+ statement.bindText(1, fallbackURLs[i].first);
+ statement.bindText(2, fallbackURLs[i].second);
+ statement.bindInt64(3, cacheStorageID);
+
+ if (!executeStatement(statement))
+ return false;
+ }
+ }
+
cache->setStorageID(cacheStorageID);
return true;
}
@@ -389,7 +516,7 @@ bool ApplicationCacheStorage::store(ApplicationCacheResource* resource, unsigned
if (!dataStatement.executeCommand())
return false;
- unsigned dataId = (unsigned)m_database.lastInsertRowID();
+ unsigned dataId = static_cast<unsigned>(m_database.lastInsertRowID());
// Then, insert the resource
@@ -421,7 +548,7 @@ bool ApplicationCacheStorage::store(ApplicationCacheResource* resource, unsigned
if (!executeStatement(resourceStatement))
return false;
- unsigned resourceId = (unsigned)m_database.lastInsertRowID();
+ unsigned resourceId = static_cast<unsigned>(m_database.lastInsertRowID());
// Finally, insert the cache entry
SQLiteStatement entryStatement(m_database, "INSERT INTO CacheEntries (cache, type, resource) VALUES (?, ?, ?)");
@@ -439,6 +566,25 @@ bool ApplicationCacheStorage::store(ApplicationCacheResource* resource, unsigned
return true;
}
+bool ApplicationCacheStorage::storeUpdatedType(ApplicationCacheResource* resource, ApplicationCache* cache)
+{
+ ASSERT_UNUSED(cache, cache->storageID());
+ ASSERT(resource->storageID());
+
+ // FIXME: If the resource gained a Dynamic bit, it should be re-inserted at the end for correct order.
+ ASSERT(!(resource->type() & ApplicationCacheResource::Dynamic));
+
+ // First, insert the data
+ SQLiteStatement entryStatement(m_database, "UPDATE CacheEntries SET type=? WHERE resource=?");
+ if (entryStatement.prepare() != SQLResultOk)
+ return false;
+
+ entryStatement.bindInt64(1, resource->type());
+ entryStatement.bindInt64(2, resource->storageID());
+
+ return executeStatement(entryStatement);
+}
+
void ApplicationCacheStorage::store(ApplicationCacheResource* resource, ApplicationCache* cache)
{
ASSERT(cache->storageID());
@@ -469,6 +615,7 @@ bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup* group)
}
ASSERT(group->newestCache());
+ ASSERT(!group->isObsolete());
ASSERT(!group->newestCache()->storageID());
// Store the newest cache
@@ -496,7 +643,7 @@ static inline void parseHeader(const UChar* header, size_t headerLength, Resourc
int pos = find(header, headerLength, ':');
ASSERT(pos != -1);
- String headerName = String(header, pos);
+ AtomicString headerName = AtomicString(header, pos);
String headerValue = String(header + pos + 1, headerLength - pos - 1);
response.setHTTPHeaderField(headerName, headerValue);
@@ -536,7 +683,7 @@ PassRefPtr<ApplicationCache> ApplicationCacheStorage::loadCache(unsigned storage
while ((result = cacheStatement.step()) == SQLResultRow) {
KURL url(cacheStatement.getColumnText(0));
- unsigned type = (unsigned)cacheStatement.getColumnInt64(1);
+ unsigned type = static_cast<unsigned>(cacheStatement.getColumnInt64(1));
Vector<char> blob;
cacheStatement.getColumnBlobAsVector(5, blob);
@@ -568,14 +715,29 @@ PassRefPtr<ApplicationCache> ApplicationCacheStorage::loadCache(unsigned storage
return 0;
whitelistStatement.bindInt64(1, storageID);
- HashSet<String> whitelist;
+ Vector<KURL> whitelist;
while ((result = whitelistStatement.step()) == SQLResultRow)
- whitelist.add(whitelistStatement.getColumnText(0));
+ whitelist.append(whitelistStatement.getColumnText(0));
if (result != SQLResultDone)
LOG_ERROR("Could not load cache online whitelist, error \"%s\"", m_database.lastErrorMsg());
cache->setOnlineWhitelist(whitelist);
+
+ // Load fallback URLs.
+ SQLiteStatement fallbackStatement(m_database, "SELECT namespace, fallbackURL FROM FallbackURLs WHERE cache=?");
+ if (fallbackStatement.prepare() != SQLResultOk)
+ return 0;
+ fallbackStatement.bindInt64(1, storageID);
+
+ FallbackURLVector fallbackURLs;
+ while ((result = fallbackStatement.step()) == SQLResultRow)
+ fallbackURLs.append(make_pair(fallbackStatement.getColumnText(0), fallbackStatement.getColumnText(1)));
+
+ if (result != SQLResultDone)
+ LOG_ERROR("Could not load fallback URLs, error \"%s\"", m_database.lastErrorMsg());
+
+ cache->setFallbackURLs(fallbackURLs);
cache->setStorageID(storageID);
@@ -591,12 +753,30 @@ void ApplicationCacheStorage::remove(ApplicationCache* cache)
if (!m_database.isOpen())
return;
+ ASSERT(cache->group());
+ ASSERT(cache->group()->storageID());
+
+ // All associated data will be deleted by database triggers.
SQLiteStatement statement(m_database, "DELETE FROM Caches WHERE id=?");
if (statement.prepare() != SQLResultOk)
return;
statement.bindInt64(1, cache->storageID());
executeStatement(statement);
+
+ cache->clearStorageID();
+
+ if (cache->group()->newestCache() == cache) {
+ // Currently, there are no triggers on the cache group, which is why the cache had to be removed separately above.
+ SQLiteStatement groupStatement(m_database, "DELETE FROM CacheGroups WHERE id=?");
+ if (groupStatement.prepare() != SQLResultOk)
+ return;
+
+ groupStatement.bindInt64(1, cache->group()->storageID());
+ executeStatement(groupStatement);
+
+ cache->group()->clearStorageID();
+ }
}
void ApplicationCacheStorage::empty()
@@ -609,7 +789,6 @@ void ApplicationCacheStorage::empty()
// Clear cache groups, caches and cache resources.
executeSQLCommand("DELETE FROM CacheGroups");
executeSQLCommand("DELETE FROM Caches");
- executeSQLCommand("DELETE FROM CacheResources");
// Clear the storage IDs for the caches in memory.
// The caches will still work, but cached resources will not be saved to disk
@@ -623,10 +802,10 @@ bool ApplicationCacheStorage::storeCopyOfCache(const String& cacheDirectory, App
{
// Create a new cache.
RefPtr<ApplicationCache> cacheCopy = ApplicationCache::create();
-
- // Set the online whitelist
+
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) {
@@ -653,7 +832,7 @@ bool ApplicationCacheStorage::storeCopyOfCache(const String& cacheDirectory, App
ApplicationCacheStorage& cacheStorage()
{
- static ApplicationCacheStorage storage;
+ DEFINE_STATIC_LOCAL(ApplicationCacheStorage, storage, ());
return storage;
}
diff --git a/WebCore/loader/appcache/ApplicationCacheStorage.h b/WebCore/loader/appcache/ApplicationCacheStorage.h
index 6bd9ba1..a0eb4ee 100644
--- a/WebCore/loader/appcache/ApplicationCacheStorage.h
+++ b/WebCore/loader/appcache/ApplicationCacheStorage.h
@@ -44,20 +44,26 @@ class KURL;
class ApplicationCacheStorage {
public:
void setCacheDirectory(const String&);
+ const String& cacheDirectory() const;
- ApplicationCacheGroup* cacheGroupForURL(const KURL&);
+ ApplicationCacheGroup* cacheGroupForURL(const KURL&); // Cache to load a main resource from.
+ ApplicationCacheGroup* fallbackCacheGroupForURL(const KURL&); // Cache that has a fallback entry to load a main resource from if normal loading fails.
ApplicationCacheGroup* findOrCreateCacheGroup(const KURL& manifestURL);
void cacheGroupDestroyed(ApplicationCacheGroup*);
+ void cacheGroupMadeObsolete(ApplicationCacheGroup*);
- bool storeNewestCache(ApplicationCacheGroup*);
+ bool storeNewestCache(ApplicationCacheGroup*); // Updates the cache group, but doesn't remove old cache.
void store(ApplicationCacheResource*, ApplicationCache*);
+ bool storeUpdatedType(ApplicationCacheResource*, ApplicationCache*);
+ // Removes the group if the cache to be removed is the newest one (so, storeNewestCache() needs to be called beforehand when updating).
void remove(ApplicationCache*);
void empty();
static bool storeCopyOfCache(const String& cacheDirectory, ApplicationCache*);
+
private:
PassRefPtr<ApplicationCache> loadCache(unsigned storageID);
ApplicationCacheGroup* loadCacheGroup(const KURL& manifestURL);
@@ -78,13 +84,13 @@ private:
String m_cacheDirectory;
SQLiteDatabase m_database;
-
- // In order to quickly determinate if a given resource exists in an application cache,
- // we keep a hash set of the hosts of the manifest URLs of all cache groups.
+
+ // In order to quickly determine if a given resource exists in an application cache,
+ // we keep a hash set of the hosts of the manifest URLs of all non-obsolete cache groups.
HashCountedSet<unsigned, AlreadyHashed> m_cacheHostSet;
typedef HashMap<String, ApplicationCacheGroup*> CacheGroupMap;
- CacheGroupMap m_cachesInMemory;
+ CacheGroupMap m_cachesInMemory; // Excludes obsolete cache groups.
};
ApplicationCacheStorage& cacheStorage();
diff --git a/WebCore/loader/appcache/DOMApplicationCache.cpp b/WebCore/loader/appcache/DOMApplicationCache.cpp
index f872a50..5bc4420 100644
--- a/WebCore/loader/appcache/DOMApplicationCache.cpp
+++ b/WebCore/loader/appcache/DOMApplicationCache.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * 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
@@ -30,6 +30,7 @@
#include "ApplicationCache.h"
#include "ApplicationCacheGroup.h"
+#include "ApplicationCacheResource.h"
#include "DocumentLoader.h"
#include "Event.h"
#include "EventException.h"
@@ -37,6 +38,7 @@
#include "EventNames.h"
#include "Frame.h"
#include "FrameLoader.h"
+#include "StaticStringList.h"
namespace WebCore {
@@ -55,7 +57,7 @@ ApplicationCache* DOMApplicationCache::associatedCache() const
if (!m_frame)
return 0;
- return m_frame->loader()->documentLoader()->topLevelApplicationCache();
+ return m_frame->loader()->documentLoader()->applicationCache();
}
unsigned short DOMApplicationCache::status() const
@@ -63,22 +65,22 @@ unsigned short DOMApplicationCache::status() const
ApplicationCache* cache = associatedCache();
if (!cache)
return UNCACHED;
-
- switch (cache->group()->status()) {
+
+ 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;
}
- default:
- ASSERT_NOT_REACHED();
}
-
+
+ ASSERT_NOT_REACHED();
return 0;
}
@@ -90,7 +92,7 @@ void DOMApplicationCache::update(ExceptionCode& ec)
return;
}
- cache->group()->update(m_frame);
+ cache->group()->update(m_frame, ApplicationCacheUpdateWithoutBrowsingContext);
}
bool DOMApplicationCache::swapCache()
@@ -101,8 +103,14 @@ bool DOMApplicationCache::swapCache()
ApplicationCache* cache = m_frame->loader()->documentLoader()->applicationCache();
if (!cache)
return false;
-
- // Check if we already have the newest cache
+
+ // 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_frame->loader()->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;
@@ -119,29 +127,33 @@ void DOMApplicationCache::swapCache(ExceptionCode& ec)
ec = INVALID_STATE_ERR;
}
-unsigned DOMApplicationCache::length() const
+PassRefPtr<DOMStringList> DOMApplicationCache::items()
{
- ApplicationCache* cache = associatedCache();
- if (!cache)
- return 0;
-
- return cache->numDynamicEntries();
+ Vector<String> result;
+ if (ApplicationCache* cache = associatedCache()) {
+ unsigned numEntries = cache->numDynamicEntries();
+ result.reserveCapacity(numEntries);
+ for (unsigned i = 0; i < numEntries; ++i)
+ result.append(cache->dynamicEntry(i));
+ }
+ return StaticStringList::adopt(result);
}
-
-String DOMApplicationCache::item(unsigned item, ExceptionCode& ec)
+
+bool DOMApplicationCache::hasItem(const KURL& url, ExceptionCode& ec)
{
ApplicationCache* cache = associatedCache();
if (!cache) {
ec = INVALID_STATE_ERR;
- return String();
+ return false;
}
- if (item >= length()) {
- ec = INDEX_SIZE_ERR;
- return String();
+ if (!url.isValid()) {
+ ec = SYNTAX_ERR;
+ return false;
}
-
- return cache->dynamicEntry(item);
+
+ ApplicationCacheResource* resource = cache->resourceForURL(url.string());
+ return resource && (resource->type() & ApplicationCacheResource::Dynamic);
}
void DOMApplicationCache::add(const KURL& url, ExceptionCode& ec)
@@ -198,7 +210,7 @@ void DOMApplicationCache::addEventListener(const AtomicString& eventType, PassRe
}
}
-void DOMApplicationCache::removeEventListener(const AtomicString& eventType, EventListener* eventListener, bool useCapture)
+void DOMApplicationCache::removeEventListener(const AtomicString& eventType, EventListener* eventListener, bool)
{
EventListenersMap::iterator iter = m_eventListeners.find(eventType);
if (iter == m_eventListeners.end())
@@ -215,7 +227,7 @@ void DOMApplicationCache::removeEventListener(const AtomicString& eventType, Eve
bool DOMApplicationCache::dispatchEvent(PassRefPtr<Event> event, ExceptionCode& ec)
{
- if (event->type().isEmpty()) {
+ if (!event || event->type().isEmpty()) {
ec = EventException::UNSPECIFIED_EVENT_TYPE_ERR;
return true;
}
@@ -281,6 +293,11 @@ void DOMApplicationCache::callCachedListener()
callListener(eventNames().cachedEvent, m_onCachedListener.get());
}
+void DOMApplicationCache::callObsoleteListener()
+{
+ callListener(eventNames().obsoleteEvent, m_onObsoleteListener.get());
+}
+
} // namespace WebCore
#endif // ENABLE(OFFLINE_WEB_APPLICATIONS)
diff --git a/WebCore/loader/appcache/DOMApplicationCache.h b/WebCore/loader/appcache/DOMApplicationCache.h
index 30c0b7e..b76542d 100644
--- a/WebCore/loader/appcache/DOMApplicationCache.h
+++ b/WebCore/loader/appcache/DOMApplicationCache.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * 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
@@ -40,6 +40,7 @@ namespace WebCore {
class ApplicationCache;
class AtomicStringImpl;
+class DOMStringList;
class Frame;
class KURL;
class String;
@@ -55,6 +56,7 @@ public:
CHECKING = 2,
DOWNLOADING = 3,
UPDATEREADY = 4,
+ OBSOLETE = 5
};
unsigned short status() const;
@@ -62,8 +64,8 @@ public:
void update(ExceptionCode&);
void swapCache(ExceptionCode&);
- unsigned length() const;
- String item(unsigned item, ExceptionCode&);
+ PassRefPtr<DOMStringList> items();
+ bool hasItem(const KURL&, ExceptionCode&);
void add(const KURL&, ExceptionCode&);
void remove(const KURL&, ExceptionCode&);
@@ -99,6 +101,9 @@ public:
void setOncached(PassRefPtr<EventListener> eventListener) { m_onCachedListener = eventListener; }
EventListener* oncached() const { return m_onCachedListener.get(); }
+ void setOnobsolete(PassRefPtr<EventListener> eventListener) { m_onObsoleteListener = eventListener; }
+ EventListener* onobsolete() const { return m_onObsoleteListener.get(); }
+
virtual ScriptExecutionContext* scriptExecutionContext() const;
DOMApplicationCache* toDOMApplicationCache() { return this; }
@@ -109,6 +114,7 @@ public:
void callProgressListener();
void callUpdateReadyListener();
void callCachedListener();
+ void callObsoleteListener();
private:
DOMApplicationCache(Frame*);
@@ -127,6 +133,7 @@ private:
RefPtr<EventListener> m_onProgressListener;
RefPtr<EventListener> m_onUpdateReadyListener;
RefPtr<EventListener> m_onCachedListener;
+ RefPtr<EventListener> m_onObsoleteListener;
EventListenersMap m_eventListeners;
diff --git a/WebCore/loader/appcache/DOMApplicationCache.idl b/WebCore/loader/appcache/DOMApplicationCache.idl
index 94326f3..4cf8f3a 100644
--- a/WebCore/loader/appcache/DOMApplicationCache.idl
+++ b/WebCore/loader/appcache/DOMApplicationCache.idl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * 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
@@ -35,21 +35,24 @@ module offline {
const unsigned short CHECKING = 2;
const unsigned short DOWNLOADING = 3;
const unsigned short UPDATEREADY = 4;
+ const unsigned short OBSOLETE = 5;
readonly attribute unsigned short status;
void update()
raises(DOMException);
void swapCache()
raises(DOMException);
-
+
+#if ENABLE_APPLICATION_CAHE_DYNAMIC_ENTRIES
// dynamic entries
- readonly attribute unsigned long length;
- DOMString item(in [IsIndex] unsigned long index)
+ readonly attribute DOMStringList items;
+ [Custom] boolean hasItem(in DOMString url)
raises(DOMException);
[Custom] void add(in DOMString uri)
raises(DOMException);
[Custom] void remove(in DOMString uri)
raises(DOMException);
+#endif
// events
attribute EventListener onchecking;
@@ -59,6 +62,7 @@ module offline {
attribute EventListener onprogress;
attribute EventListener onupdateready;
attribute EventListener oncached;
+ attribute EventListener onobsolete;
// EventTarget interface
[Custom] void addEventListener(in DOMString type,
diff --git a/WebCore/loader/appcache/ManifestParser.cpp b/WebCore/loader/appcache/ManifestParser.cpp
index 778d22d..a83303a 100644
--- a/WebCore/loader/appcache/ManifestParser.cpp
+++ b/WebCore/loader/appcache/ManifestParser.cpp
@@ -32,9 +32,11 @@
#include "KURL.h"
#include "TextEncoding.h"
+using namespace std;
+
namespace WebCore {
-enum Mode { Explicit, Fallback, OnlineWhitelist };
+enum Mode { Explicit, Fallback, OnlineWhitelist, Unknown };
bool parseManifest(const KURL& manifestURL, const char* data, int length, Manifest& manifest)
{
@@ -45,34 +47,22 @@ bool parseManifest(const KURL& manifestURL, const char* data, int length, Manife
Mode mode = Explicit;
String s = UTF8Encoding().decode(data, length);
- if (s.isEmpty())
- return false;
-
- // Replace nulls with U+FFFD REPLACEMENT CHARACTER
- s.replace(0, replacementCharacter);
-
- // Look for the magic signature
- if (!s.startsWith("CACHE MANIFEST")) {
- // The magic signature was not found.
+ // Look for the magic signature: "^\xFEFF?CACHE MANIFEST[ \t]?" (the BOM is removed by decode()).
+ // Example: "CACHE MANIFEST #comment" is a valid signature.
+ // Example: "CACHE MANIFEST;V2" is not.
+ if (!s.startsWith("CACHE MANIFEST"))
return false;
- }
const UChar* end = s.characters() + s.length();
const UChar* p = s.characters() + 14; // "CACHE MANIFEST" is 14 characters.
-
- while (p < end) {
- // Skip whitespace
- if (*p == ' ' || *p == '\t') {
- p++;
- } else
- break;
- }
-
- if (p < end && *p != '\n' && *p != '\r') {
- // The magic signature was invalid
+
+ if (p < end && *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r')
return false;
- }
-
+
+ // Skip to the end of the line.
+ while (p < end && *p != '\r' && *p != '\n')
+ p++;
+
while (1) {
// Skip whitespace
while (p < end && (*p == '\n' || *p == '\r' || *p == ' ' || *p == '\t'))
@@ -104,8 +94,19 @@ bool parseManifest(const KURL& manifestURL, const char* data, int length, Manife
mode = Fallback;
else if (line == "NETWORK:")
mode = OnlineWhitelist;
+ else if (line.endsWith(":"))
+ mode = Unknown;
+ else if (mode == Unknown)
+ continue;
else if (mode == Explicit || mode == OnlineWhitelist) {
- KURL url(manifestURL, line);
+ const UChar* p = line.characters();
+ const UChar* lineEnd = p + line.length();
+
+ // Look for whitespace separating the URL from subsequent ignored tokens.
+ while (p < lineEnd && *p != '\t' && *p != ' ')
+ p++;
+
+ KURL url(manifestURL, String(line.characters(), p - line.characters()));
if (!url.isValid())
continue;
@@ -119,11 +120,11 @@ bool parseManifest(const KURL& manifestURL, const char* data, int length, Manife
if (mode == Explicit)
manifest.explicitURLs.add(url.string());
else
- manifest.onlineWhitelistedURLs.add(url.string());
+ manifest.onlineWhitelistedURLs.append(url);
} else if (mode == Fallback) {
- const UChar *p = line.characters();
- const UChar *lineEnd = p + line.length();
+ const UChar* p = line.characters();
+ const UChar* lineEnd = p + line.length();
// Look for whitespace separating the two URLs
while (p < lineEnd && *p != '\t' && *p != ' ')
@@ -137,23 +138,31 @@ bool parseManifest(const KURL& manifestURL, const char* data, int length, Manife
KURL namespaceURL(manifestURL, String(line.characters(), p - line.characters()));
if (!namespaceURL.isValid())
continue;
-
- // Check that the namespace URL has the same scheme/host/port as the manifest URL.
+ if (namespaceURL.hasRef())
+ namespaceURL.setRef(String());
+
if (!protocolHostAndPortAreEqual(manifestURL, namespaceURL))
continue;
+ // Skip whitespace separating fallback namespace from URL.
while (p < lineEnd && (*p == '\t' || *p == ' '))
p++;
- KURL fallbackURL(String(p, line.length() - (p - line.characters())));
+ // Look for whitespace separating the URL from subsequent ignored tokens.
+ const UChar* fallbackStart = p;
+ while (p < lineEnd && *p != '\t' && *p != ' ')
+ p++;
+ KURL fallbackURL(manifestURL, String(fallbackStart, p - fallbackStart));
if (!fallbackURL.isValid())
continue;
-
- if (!equalIgnoringCase(fallbackURL.protocol(), manifestURL.protocol()))
+ if (fallbackURL.hasRef())
+ fallbackURL.setRef(String());
+
+ if (!protocolHostAndPortAreEqual(manifestURL, fallbackURL))
continue;
-
- manifest.fallbackURLs.add(namespaceURL, fallbackURL);
+
+ manifest.fallbackURLs.append(make_pair(namespaceURL, fallbackURL));
} else
ASSERT_NOT_REACHED();
}
diff --git a/WebCore/loader/appcache/ManifestParser.h b/WebCore/loader/appcache/ManifestParser.h
index f4fe31a..c03cf27 100644
--- a/WebCore/loader/appcache/ManifestParser.h
+++ b/WebCore/loader/appcache/ManifestParser.h
@@ -28,22 +28,19 @@
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
-#include <wtf/HashMap.h>
-#include <wtf/HashSet.h>
-#include "StringHash.h"
-#include "PlatformString.h"
+#include "ApplicationCache.h"
namespace WebCore {
-class KURL;
+ class KURL;
-struct Manifest {
- HashSet<String> onlineWhitelistedURLs;
- HashSet<String> explicitURLs;
- HashMap<String, String> fallbackURLs;
-};
+ struct Manifest {
+ Vector<KURL> onlineWhitelistedURLs;
+ HashSet<String> explicitURLs;
+ FallbackURLVector fallbackURLs;
+ };
-bool parseManifest(const KURL& manifestURL, const char* data, int length, Manifest&);
+ bool parseManifest(const KURL& manifestURL, const char* data, int length, Manifest&);
}
diff --git a/WebCore/loader/archive/ArchiveFactory.cpp b/WebCore/loader/archive/ArchiveFactory.cpp
index c42b5df..1322dbb 100644
--- a/WebCore/loader/archive/ArchiveFactory.cpp
+++ b/WebCore/loader/archive/ArchiveFactory.cpp
@@ -37,10 +37,12 @@
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
+#include <wtf/StdLibExtras.h>
namespace WebCore {
typedef PassRefPtr<Archive> RawDataCreationFunction(SharedBuffer*);
+typedef HashMap<String, RawDataCreationFunction*, CaseFoldingHash> ArchiveMIMETypesMap;
// The create functions in the archive classes return PassRefPtr to concrete subclasses
// of Archive. This adaptor makes the functions have a uniform return type.
@@ -49,9 +51,9 @@ template <typename ArchiveClass> static PassRefPtr<Archive> archiveFactoryCreate
return ArchiveClass::create(buffer);
}
-static HashMap<String, RawDataCreationFunction*, CaseFoldingHash>& archiveMIMETypes()
+static ArchiveMIMETypesMap& archiveMIMETypes()
{
- static HashMap<String, RawDataCreationFunction*, CaseFoldingHash> mimeTypes;
+ DEFINE_STATIC_LOCAL(ArchiveMIMETypesMap, mimeTypes, ());
static bool initialized = false;
if (initialized)
@@ -79,8 +81,8 @@ PassRefPtr<Archive> ArchiveFactory::create(SharedBuffer* data, const String& mim
void ArchiveFactory::registerKnownArchiveMIMETypes()
{
HashSet<String>& mimeTypes = MIMETypeRegistry::getSupportedNonImageMIMETypes();
- HashMap<String, RawDataCreationFunction*, CaseFoldingHash>::iterator i = archiveMIMETypes().begin();
- HashMap<String, RawDataCreationFunction*, CaseFoldingHash>::iterator end = archiveMIMETypes().end();
+ ArchiveMIMETypesMap::iterator i = archiveMIMETypes().begin();
+ ArchiveMIMETypesMap::iterator end = archiveMIMETypes().end();
for (; i != end; ++i)
mimeTypes.add(i->first);
diff --git a/WebCore/loader/archive/cf/LegacyWebArchive.cpp b/WebCore/loader/archive/cf/LegacyWebArchive.cpp
index 9d99588..b00d93c 100644
--- a/WebCore/loader/archive/cf/LegacyWebArchive.cpp
+++ b/WebCore/loader/archive/cf/LegacyWebArchive.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * 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
@@ -30,6 +30,7 @@
#include "LegacyWebArchive.h"
#include "CString.h"
+#include "Cache.h"
#include "Document.h"
#include "DocumentLoader.h"
#include "Frame.h"
@@ -37,14 +38,15 @@
#include "FrameTree.h"
#include "HTMLFrameOwnerElement.h"
#include "HTMLNames.h"
-#include "KURL.h"
+#include "IconDatabase.h"
+#include "KURLHash.h"
#include "Logging.h"
#include "markup.h"
#include "Node.h"
#include "Range.h"
#include "SelectionController.h"
#include "SharedBuffer.h"
-
+#include <wtf/ListHashSet.h>
#include <wtf/RetainPtr.h>
namespace WebCore {
@@ -374,15 +376,21 @@ RetainPtr<CFDataRef> LegacyWebArchive::rawDataRepresentation()
LOG(Archives, "LegacyWebArchive - Failed to create property list for archive, returning no data");
return 0;
}
-
- // FIXME: On Mac, WebArchives have been written out as Binary Property Lists until this change.
- // Unless we jump through CFWriteStream hoops, they'll now be textual XML data. Is this okay?
- RetainPtr<CFDataRef> plistData(AdoptCF, CFPropertyListCreateXMLData(0, propertyList.get()));
+
+ RetainPtr<CFWriteStreamRef> stream(AdoptCF, CFWriteStreamCreateWithAllocatedBuffers(0, 0));
+
+ CFWriteStreamOpen(stream.get());
+ CFPropertyListWriteToStream(propertyList.get(), stream.get(), kCFPropertyListBinaryFormat_v1_0, 0);
+
+ RetainPtr<CFDataRef> plistData(AdoptCF, static_cast<CFDataRef>(CFWriteStreamCopyProperty(stream.get(), kCFStreamPropertyDataWritten)));
+
+ CFWriteStreamClose(stream.get());
+
if (!plistData) {
LOG(Archives, "LegacyWebArchive - Failed to convert property list into raw data, returning no data");
return 0;
}
-
+
return plistData;
}
@@ -488,7 +496,7 @@ PassRefPtr<LegacyWebArchive> LegacyWebArchive::create(const String& markupString
Vector<PassRefPtr<LegacyWebArchive> > subframeArchives;
Vector<PassRefPtr<ArchiveResource> > subresources;
- HashSet<String> uniqueSubresources;
+ HashSet<KURL> uniqueSubresources;
Vector<Node*>::iterator it = nodes.begin();
Vector<Node*>::iterator end = nodes.end();
@@ -508,24 +516,50 @@ PassRefPtr<LegacyWebArchive> LegacyWebArchive::create(const String& markupString
else
LOG_ERROR("Unabled to archive subframe %s", childFrame->tree()->name().string().utf8().data());
} else {
- Vector<KURL> subresourceURLs;
+ ListHashSet<KURL> subresourceURLs;
(*it)->getSubresourceURLs(subresourceURLs);
DocumentLoader* documentLoader = frame->loader()->documentLoader();
- for (unsigned i = 0; i < subresourceURLs.size(); ++i) {
- if (uniqueSubresources.contains(subresourceURLs[i].string()))
+ ListHashSet<KURL>::iterator iterEnd = subresourceURLs.end();
+ for (ListHashSet<KURL>::iterator iter = subresourceURLs.begin(); iter != iterEnd; ++iter) {
+ const KURL& subresourceURL = *iter;
+ if (uniqueSubresources.contains(subresourceURL))
continue;
- uniqueSubresources.add(subresourceURLs[i].string());
- RefPtr<ArchiveResource> resource = documentLoader->subresource(subresourceURLs[i]);
- if (resource)
+
+ uniqueSubresources.add(subresourceURL);
+
+ RefPtr<ArchiveResource> resource = documentLoader->subresource(subresourceURL);
+ if (resource) {
subresources.append(resource.release());
- else
- // FIXME: should do something better than spew to console here
- LOG_ERROR("Failed to archive subresource for %s", subresourceURLs[i].string().utf8().data());
+ continue;
+ }
+
+ CachedResource *cachedResource = cache()->resourceForURL(subresourceURL);
+ if (cachedResource) {
+ resource = ArchiveResource::create(cachedResource->data(), subresourceURL, cachedResource->response());
+ if (resource) {
+ subresources.append(resource.release());
+ continue;
+ }
+ }
+
+ // FIXME: should do something better than spew to console here
+ LOG_ERROR("Failed to archive subresource for %s", subresourceURL.string().utf8().data());
}
}
}
-
+
+ // Add favicon if one exists for this page
+ if (iconDatabase() && iconDatabase()->isEnabled()) {
+ const String& iconURL = iconDatabase()->iconURLForPageURL(responseURL);
+ if (!iconURL.isEmpty() && iconDatabase()->iconDataKnownForIconURL(iconURL)) {
+ if (Image* iconImage = iconDatabase()->iconForPageURL(responseURL, IntSize(16, 16))) {
+ RefPtr<ArchiveResource> resource = ArchiveResource::create(iconImage->data(), KURL(iconURL), "image/x-icon", "", "");
+ subresources.append(resource.release());
+ }
+ }
+ }
+
return create(mainResource, subresources, subframeArchives);
}
diff --git a/WebCore/loader/icon/IconDatabase.cpp b/WebCore/loader/icon/IconDatabase.cpp
index 72e57fe..5705f7a 100644
--- a/WebCore/loader/icon/IconDatabase.cpp
+++ b/WebCore/loader/icon/IconDatabase.cpp
@@ -40,9 +40,10 @@
#include "PageURLRecord.h"
#include "SQLiteStatement.h"
#include "SQLiteTransaction.h"
-#include "SystemTime.h"
#include <runtime/InitializeThreading.h>
+#include <wtf/CurrentTime.h>
#include <wtf/MainThread.h>
+#include <wtf/StdLibExtras.h>
#if PLATFORM(WIN_OS)
#include <windows.h>
@@ -56,8 +57,6 @@
#include <pthread.h>
#endif
-#include <errno.h>
-
// For methods that are meant to support API from the main thread - should not be called internally
#define ASSERT_NOT_SYNC_THREAD() ASSERT(!m_syncThreadRunning || !IS_ICON_SYNC_THREAD())
@@ -180,6 +179,9 @@ void IconDatabase::close()
m_syncThreadRunning = false;
m_threadTerminationRequested = false;
m_removeIconsRequested = false;
+
+ m_syncDB.close();
+ ASSERT(!isOpen());
}
void IconDatabase::removeAllIcons()
@@ -385,7 +387,7 @@ static inline void loadDefaultIconRecord(IconRecord* defaultIconRecord)
0x00, 0x00, 0x01, 0x52, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0A,
0xFC, 0x80, 0x00, 0x00, 0x27, 0x10, 0x00, 0x0A, 0xFC, 0x80, 0x00, 0x00, 0x27, 0x10 };
- static RefPtr<SharedBuffer> defaultIconBuffer(SharedBuffer::create(defaultIconData, sizeof(defaultIconData)));
+ DEFINE_STATIC_LOCAL(RefPtr<SharedBuffer>, defaultIconBuffer, (SharedBuffer::create(defaultIconData, sizeof(defaultIconData))));
defaultIconRecord->setImageData(defaultIconBuffer);
}
#endif
@@ -855,7 +857,7 @@ String IconDatabase::databasePath() const
String IconDatabase::defaultDatabaseFilename()
{
- static String defaultDatabaseFilename = "WebpageIcons.db";
+ DEFINE_STATIC_LOCAL(String, defaultDatabaseFilename, ("WebpageIcons.db"));
return defaultDatabaseFilename.copy();
}
@@ -1359,7 +1361,7 @@ void* IconDatabase::syncThreadMainLoop()
bool didWrite = writeToDatabase();
if (shouldStopThreadActivity())
break;
-
+
didAnyWork = readFromDatabase();
if (shouldStopThreadActivity())
break;
diff --git a/WebCore/loader/icon/IconDatabaseClient.h b/WebCore/loader/icon/IconDatabaseClient.h
index e642895..8806406 100644
--- a/WebCore/loader/icon/IconDatabaseClient.h
+++ b/WebCore/loader/icon/IconDatabaseClient.h
@@ -41,8 +41,9 @@ public:
virtual ~IconDatabaseClient() { }
virtual bool performImport() { return true; }
virtual void dispatchDidRemoveAllIcons() { }
- virtual void dispatchDidAddIconForPageURL(const String& pageURL) { }
+ virtual void dispatchDidAddIconForPageURL(const String& /*pageURL*/) { }
};
} // namespace WebCore
+
#endif
diff --git a/WebCore/loader/icon/IconFetcher.cpp b/WebCore/loader/icon/IconFetcher.cpp
index efa7e14..69eeb7c 100644
--- a/WebCore/loader/icon/IconFetcher.cpp
+++ b/WebCore/loader/icon/IconFetcher.cpp
@@ -26,16 +26,12 @@
#include "config.h"
#include "IconFetcher.h"
-#include "Document.h"
#include "Frame.h"
#include "HTMLHeadElement.h"
#include "HTMLLinkElement.h"
#include "HTMLNames.h"
-#include "MIMETypeRegistry.h"
#include "ResourceHandle.h"
#include "ResourceRequest.h"
-#include "SharedBuffer.h"
-#include <wtf/PassRefPtr.h>
namespace WebCore {
@@ -164,7 +160,7 @@ void IconFetcher::cancel()
if (m_handle)
m_handle->cancel();
}
-
+
PassRefPtr<SharedBuffer> IconFetcher::createIcon()
{
ASSERT(!m_entries.isEmpty());
@@ -172,8 +168,7 @@ PassRefPtr<SharedBuffer> IconFetcher::createIcon()
// For now, just return the data of the first entry.
return m_entries.first().buffer();
}
-
-
+
void IconFetcher::loadEntry()
{
ASSERT(m_currentEntry < m_entries.size());
@@ -191,7 +186,7 @@ void IconFetcher::loadFailed()
void IconFetcher::didReceiveResponse(ResourceHandle* handle, const ResourceResponse& response)
{
- ASSERT(m_handle == handle);
+ ASSERT_UNUSED(handle, m_handle == handle);
int statusCode = response.httpStatusCode() / 100;
if (statusCode == 4 || statusCode == 5) {
@@ -200,16 +195,16 @@ void IconFetcher::didReceiveResponse(ResourceHandle* handle, const ResourceRespo
}
}
-void IconFetcher::didReceiveData(ResourceHandle* handle, const char* data, int length, int lengthReceived)
+void IconFetcher::didReceiveData(ResourceHandle* handle, const char* data, int length, int)
{
- ASSERT(m_handle == handle);
+ ASSERT_UNUSED(handle, m_handle == handle);
m_entries[m_currentEntry].buffer()->append(data, length);
}
void IconFetcher::didFinishLoading(ResourceHandle* handle)
{
- ASSERT(m_handle == handle);
+ ASSERT_UNUSED(handle, m_handle == handle);
if (m_currentEntry == m_entries.size() - 1) {
// We finished loading, create the icon
@@ -227,10 +222,9 @@ void IconFetcher::didFinishLoading(ResourceHandle* handle)
void IconFetcher::didFail(ResourceHandle* handle, const ResourceError&)
{
- ASSERT(m_handle == handle);
+ ASSERT_UNUSED(handle, m_handle == handle);
loadFailed();
}
-
} // namespace WebCore
diff --git a/WebCore/loader/icon/IconLoader.cpp b/WebCore/loader/icon/IconLoader.cpp
index 4337f51..b7bf115 100644
--- a/WebCore/loader/icon/IconLoader.cpp
+++ b/WebCore/loader/icon/IconLoader.cpp
@@ -36,6 +36,7 @@
#include "ResourceResponse.h"
#include "ResourceRequest.h"
#include "SubresourceLoader.h"
+#include <wtf/UnusedParam.h>
using namespace std;
@@ -101,9 +102,13 @@ void IconLoader::didReceiveResponse(SubresourceLoader* resourceLoader, const Res
}
}
-void IconLoader::didReceiveData(SubresourceLoader* loader, const char*, int size)
+void IconLoader::didReceiveData(SubresourceLoader* unusedLoader, const char*, int unusedSize)
{
- LOG(IconDatabase, "IconLoader::didReceiveData() - Loader %p, number of bytes %i", loader, size);
+#if LOG_DISABLED
+ UNUSED_PARAM(unusedLoader);
+ UNUSED_PARAM(unusedSize);
+#endif
+ LOG(IconDatabase, "IconLoader::didReceiveData() - Loader %p, number of bytes %i", unusedLoader, unusedSize);
}
void IconLoader::didFail(SubresourceLoader* resourceLoader, const ResourceError&)
@@ -121,7 +126,7 @@ void IconLoader::didFail(SubresourceLoader* resourceLoader, const ResourceError&
}
}
-void IconLoader::didReceiveAuthenticationChallenge(SubresourceLoader* resourceLoader, const AuthenticationChallenge& challenge)
+void IconLoader::didReceiveAuthenticationChallenge(SubresourceLoader*, const AuthenticationChallenge&)
{
// We don't ever want to prompt for authentication just for a site icon, so
// implement this method to cancel the resource load
@@ -153,9 +158,12 @@ void IconLoader::finishLoading(const KURL& iconURL, PassRefPtr<SharedBuffer> dat
// <rdar://problem/5463392> tracks that enhancement
if (!iconURL.isEmpty() && m_loadIsInProgress) {
- iconDatabase()->setIconDataForIconURL(data, iconURL.string());
LOG(IconDatabase, "IconLoader::finishLoading() - Committing iconURL %s to database", iconURL.string().ascii().data());
m_frame->loader()->commitIconURLToIconDatabase(iconURL);
+ // Setting the icon data only after committing to the database ensures that the data is
+ // kept in memory (so it does not have to be read from the database asynchronously), since
+ // there is a page URL referencing it.
+ iconDatabase()->setIconDataForIconURL(data, iconURL.string());
m_frame->loader()->client()->dispatchDidReceiveIcon();
}
diff --git a/WebCore/loader/icon/IconRecord.cpp b/WebCore/loader/icon/IconRecord.cpp
index f070cc9..ffea318 100644
--- a/WebCore/loader/icon/IconRecord.cpp
+++ b/WebCore/loader/icon/IconRecord.cpp
@@ -34,7 +34,6 @@
#include "Logging.h"
#include "SQLiteStatement.h"
#include "SQLiteTransaction.h"
-#include "SystemTime.h"
#include <limits.h>
@@ -53,7 +52,7 @@ IconRecord::~IconRecord()
LOG(IconDatabase, "Destroying IconRecord for icon url %s", m_iconURL.ascii().data());
}
-Image* IconRecord::image(const IntSize& size)
+Image* IconRecord::image(const IntSize&)
{
// FIXME rdar://4680377 - For size right now, we are returning our one and only image and the Bridge
// is resizing it in place. We need to actually store all the original representations here and return a native
diff --git a/WebCore/loader/loader.cpp b/WebCore/loader/loader.cpp
index 6221a6a..22fb158 100644
--- a/WebCore/loader/loader.cpp
+++ b/WebCore/loader/loader.cpp
@@ -181,7 +181,7 @@ void Loader::cancelRequests(DocLoader* docLoader)
Loader::Host::Host(const AtomicString& name, unsigned maxRequestsInFlight)
: m_name(name)
, m_maxRequestsInFlight(maxRequestsInFlight)
- , m_processingResource(false)
+ , m_numResourcesProcessing(0)
{
}
@@ -252,7 +252,8 @@ void Loader::Host::servePendingRequests(RequestQueue& requestsPending, bool& ser
const String& lastModified = resourceToRevalidate->response().httpHeaderField("Last-Modified");
const String& eTag = resourceToRevalidate->response().httpHeaderField("ETag");
if (!lastModified.isEmpty() || !eTag.isEmpty()) {
- if (docLoader->cachePolicy() == CachePolicyReload || docLoader->cachePolicy() == CachePolicyRefresh)
+ ASSERT(docLoader->cachePolicy() != CachePolicyReload);
+ if (docLoader->cachePolicy() == CachePolicyRevalidate)
resourceRequest.setHTTPHeaderField("Cache-Control", "max-age=0");
if (!lastModified.isEmpty())
resourceRequest.setHTTPHeaderField("If-Modified-Since", lastModified);
@@ -285,7 +286,7 @@ void Loader::Host::didFinishLoading(SubresourceLoader* loader)
if (i == m_requestsLoading.end())
return;
- m_processingResource = true;
+ ProcessingResource processingResource(this);
Request* request = i->second;
m_requestsLoading.remove(i);
@@ -315,8 +316,6 @@ void Loader::Host::didFinishLoading(SubresourceLoader* loader)
printf("HOST %s COUNT %d RECEIVED %s\n", u.host().latin1().data(), m_requestsLoading.size(), resource->url().latin1().data());
#endif
servePendingRequests();
-
- m_processingResource = false;
}
void Loader::Host::didFail(SubresourceLoader* loader, const ResourceError&)
@@ -332,7 +331,7 @@ void Loader::Host::didFail(SubresourceLoader* loader, bool cancelled)
if (i == m_requestsLoading.end())
return;
- m_processingResource = true;
+ ProcessingResource processingResource(this);
Request* request = i->second;
m_requestsLoading.remove(i);
@@ -359,8 +358,6 @@ void Loader::Host::didFail(SubresourceLoader* loader, bool cancelled)
docLoader->checkForPendingPreloads();
servePendingRequests();
-
- m_processingResource = false;
}
void Loader::Host::didReceiveResponse(SubresourceLoader* loader, const ResourceResponse& response)
@@ -382,6 +379,7 @@ void Loader::Host::didReceiveResponse(SubresourceLoader* loader, const ResourceR
if (response.httpStatusCode() == 304) {
// 304 Not modified / Use local copy
m_requestsLoading.remove(loader);
+ loader->clearClient();
request->docLoader()->decrementRequestCount();
// Existing resource is ok, just use it updating the expiration time.
@@ -398,16 +396,16 @@ void Loader::Host::didReceiveResponse(SubresourceLoader* loader, const ResourceR
// Did not get 304 response, continue as a regular resource load.
cache()->revalidationFailed(resource);
}
-
+
resource->setResponse(response);
-
+
String encoding = response.textEncodingName();
if (!encoding.isNull())
- request->cachedResource()->setEncoding(encoding);
+ resource->setEncoding(encoding);
if (request->isMultipart()) {
- ASSERT(request->cachedResource()->isImage());
- static_cast<CachedImage*>(request->cachedResource())->clear();
+ ASSERT(resource->isImage());
+ static_cast<CachedImage*>(resource)->clear();
if (request->docLoader()->frame())
request->docLoader()->frame()->loader()->checkCompleted();
} else if (response.isMultipart()) {
@@ -415,10 +413,10 @@ void Loader::Host::didReceiveResponse(SubresourceLoader* loader, const ResourceR
// We don't count multiParts in a DocLoader's request count
request->docLoader()->decrementRequestCount();
-
+
// If we get a multipart response, we must have a handle
ASSERT(loader->handle());
- if (!request->cachedResource()->isImage())
+ if (!resource->isImage())
loader->handle()->cancel();
}
}
@@ -435,12 +433,11 @@ void Loader::Host::didReceiveData(SubresourceLoader* loader, const char* data, i
if (resource->errorOccurred())
return;
- m_processingResource = true;
+ ProcessingResource processingResource(this);
if (resource->response().httpStatusCode() / 100 == 4) {
// Treat a 4xx response like a network error.
resource->error();
- m_processingResource = false;
return;
}
@@ -452,8 +449,6 @@ void Loader::Host::didReceiveData(SubresourceLoader* loader, const char* data, i
resource->data(copiedData.release(), true);
} else if (request->isIncremental())
resource->data(loader->resourceData(), false);
-
- m_processingResource = false;
}
void Loader::Host::cancelPendingRequests(RequestQueue& requestsPending, DocLoader* docLoader)
diff --git a/WebCore/loader/loader.h b/WebCore/loader/loader.h
index c51374c..19c3fda 100644
--- a/WebCore/loader/loader.h
+++ b/WebCore/loader/loader.h
@@ -65,9 +65,27 @@ namespace WebCore {
void servePendingRequests(Priority minimumPriority = Low);
void cancelRequests(DocLoader*);
bool hasRequests() const;
- bool processingResource() const { return m_processingResource; }
-
+
+ bool processingResource() const { return m_numResourcesProcessing != 0; }
+
private:
+ class ProcessingResource {
+ public:
+ ProcessingResource(Host* host)
+ : m_host(host)
+ {
+ m_host->m_numResourcesProcessing++;
+ }
+
+ ~ProcessingResource()
+ {
+ m_host->m_numResourcesProcessing--;
+ }
+
+ private:
+ Host* m_host;
+ };
+
virtual void didReceiveResponse(SubresourceLoader*, const ResourceResponse&);
virtual void didReceiveData(SubresourceLoader*, const char*, int);
virtual void didFinishLoading(SubresourceLoader*);
@@ -83,7 +101,7 @@ namespace WebCore {
RequestMap m_requestsLoading;
const AtomicString m_name;
const int m_maxRequestsInFlight;
- bool m_processingResource;
+ int m_numResourcesProcessing;
};
typedef HashMap<AtomicStringImpl*, Host*> HostMap;
HostMap m_hosts;
diff --git a/WebCore/loader/mac/DocumentLoaderMac.cpp b/WebCore/loader/mac/DocumentLoaderMac.cpp
index 05c6e26..8cc40d2 100644
--- a/WebCore/loader/mac/DocumentLoaderMac.cpp
+++ b/WebCore/loader/mac/DocumentLoaderMac.cpp
@@ -31,6 +31,7 @@
#include "MainResourceLoader.h"
#include "ResourceHandle.h"
#include "ResourceLoader.h"
+#include <wtf/UnusedParam.h>
namespace WebCore {
@@ -62,6 +63,8 @@ void DocumentLoader::schedule(SchedulePair* pair)
scheduleAll(m_subresourceLoaders, pair);
scheduleAll(m_plugInStreamLoaders, pair);
scheduleAll(m_multipartSubresourceLoaders, pair);
+#else
+ UNUSED_PARAM(pair);
#endif
}
@@ -73,6 +76,8 @@ void DocumentLoader::unschedule(SchedulePair* pair)
unscheduleAll(m_subresourceLoaders, pair);
unscheduleAll(m_plugInStreamLoaders, pair);
unscheduleAll(m_multipartSubresourceLoaders, pair);
+#else
+ UNUSED_PARAM(pair);
#endif
}
diff --git a/WebCore/loader/mac/ResourceLoaderMac.mm b/WebCore/loader/mac/ResourceLoaderMac.mm
index 9769ac9..d6ee923 100644
--- a/WebCore/loader/mac/ResourceLoaderMac.mm
+++ b/WebCore/loader/mac/ResourceLoaderMac.mm
@@ -35,7 +35,7 @@
namespace WebCore {
-NSCachedURLResponse* ResourceLoader::willCacheResponse(ResourceHandle* handle, NSCachedURLResponse* response)
+NSCachedURLResponse* ResourceLoader::willCacheResponse(ResourceHandle*, NSCachedURLResponse* response)
{
return frameLoader()->client()->willCacheResponse(documentLoader(), identifier(), response);
}