From 0bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5 Mon Sep 17 00:00:00 2001 From: Ben Murdoch Date: Tue, 11 Aug 2009 17:01:47 +0100 Subject: Merge in WebKit r47029. --- WebCore/loader/Cache.h | 2 +- WebCore/loader/CachedCSSStyleSheet.cpp | 4 +- WebCore/loader/CachedCSSStyleSheet.h | 2 +- WebCore/loader/CachedFont.cpp | 20 +- WebCore/loader/CachedFont.h | 2 +- WebCore/loader/CachedImage.cpp | 4 +- WebCore/loader/CachedImage.h | 2 +- WebCore/loader/CachedResource.cpp | 54 ++- WebCore/loader/CachedResource.h | 7 +- WebCore/loader/CachedScript.cpp | 3 +- WebCore/loader/CachedScript.h | 2 +- WebCore/loader/CachedXSLStyleSheet.cpp | 6 +- WebCore/loader/CachedXSLStyleSheet.h | 2 +- WebCore/loader/CrossOriginPreflightResultCache.h | 4 +- WebCore/loader/DocLoader.cpp | 2 +- WebCore/loader/DocumentLoader.cpp | 137 +------- WebCore/loader/DocumentLoader.h | 30 +- WebCore/loader/DocumentThreadableLoader.cpp | 15 +- WebCore/loader/DocumentThreadableLoader.h | 6 +- WebCore/loader/EmptyClients.h | 26 +- WebCore/loader/FrameLoader.cpp | 302 ++++++++-------- WebCore/loader/FrameLoader.h | 27 +- WebCore/loader/FrameLoaderClient.h | 17 +- WebCore/loader/FrameLoaderTypes.h | 7 +- WebCore/loader/MainResourceLoader.cpp | 60 +--- WebCore/loader/MainResourceLoader.h | 12 - WebCore/loader/PlaceholderDocument.cpp | 47 +++ WebCore/loader/PlaceholderDocument.h | 48 +++ WebCore/loader/PluginDocument.cpp | 6 +- WebCore/loader/ProgressTracker.h | 2 +- WebCore/loader/ResourceLoader.cpp | 32 +- WebCore/loader/ResourceLoader.h | 8 +- WebCore/loader/TextDocument.cpp | 2 + WebCore/loader/TextResourceDecoder.cpp | 6 +- WebCore/loader/ThreadableLoader.cpp | 8 +- WebCore/loader/ThreadableLoader.h | 10 +- WebCore/loader/WorkerThreadableLoader.cpp | 16 +- WebCore/loader/WorkerThreadableLoader.h | 12 +- WebCore/loader/appcache/ApplicationCache.cpp | 33 +- WebCore/loader/appcache/ApplicationCache.h | 12 +- WebCore/loader/appcache/ApplicationCacheGroup.cpp | 202 +++++++---- WebCore/loader/appcache/ApplicationCacheGroup.h | 10 +- WebCore/loader/appcache/ApplicationCacheHost.cpp | 381 +++++++++++++++++++++ WebCore/loader/appcache/ApplicationCacheHost.h | 152 ++++++++ .../loader/appcache/ApplicationCacheResource.cpp | 2 - WebCore/loader/appcache/ApplicationCacheResource.h | 4 +- .../loader/appcache/ApplicationCacheStorage.cpp | 189 +++++++++- WebCore/loader/appcache/ApplicationCacheStorage.h | 3 +- WebCore/loader/appcache/DOMApplicationCache.cpp | 208 ++++------- WebCore/loader/appcache/DOMApplicationCache.h | 88 +++-- WebCore/loader/appcache/DOMApplicationCache.idl | 11 - WebCore/loader/appcache/ManifestParser.cpp | 12 +- WebCore/loader/archive/ArchiveResourceCollection.h | 2 +- WebCore/loader/icon/IconDatabase.cpp | 4 + WebCore/loader/icon/IconDatabase.h | 6 +- WebCore/loader/icon/IconDatabaseNone.cpp | 21 ++ WebCore/loader/icon/IconLoader.h | 2 +- WebCore/loader/icon/PageURLRecord.h | 2 +- WebCore/loader/icon/wince/IconDatabaseWince.cpp | 81 +++++ WebCore/loader/loader.cpp | 52 ++- WebCore/loader/loader.h | 11 +- 61 files changed, 1601 insertions(+), 839 deletions(-) create mode 100644 WebCore/loader/PlaceholderDocument.cpp create mode 100644 WebCore/loader/PlaceholderDocument.h create mode 100644 WebCore/loader/appcache/ApplicationCacheHost.cpp create mode 100644 WebCore/loader/appcache/ApplicationCacheHost.h create mode 100644 WebCore/loader/icon/wince/IconDatabaseWince.cpp (limited to 'WebCore/loader') diff --git a/WebCore/loader/Cache.h b/WebCore/loader/Cache.h index 9d81dc6..68be2d6 100644 --- a/WebCore/loader/Cache.h +++ b/WebCore/loader/Cache.h @@ -55,7 +55,7 @@ class KURL; // -------|-----+++++++++++++++| // -------|-----+++++++++++++++|+++++ -class Cache : Noncopyable { +class Cache : public Noncopyable { public: friend Cache* cache(); diff --git a/WebCore/loader/CachedCSSStyleSheet.cpp b/WebCore/loader/CachedCSSStyleSheet.cpp index 11d1213..4c466fa 100644 --- a/WebCore/loader/CachedCSSStyleSheet.cpp +++ b/WebCore/loader/CachedCSSStyleSheet.cpp @@ -49,10 +49,8 @@ CachedCSSStyleSheet::~CachedCSSStyleSheet() { } -void CachedCSSStyleSheet::addClient(CachedResourceClient *c) +void CachedCSSStyleSheet::didAddClient(CachedResourceClient *c) { - CachedResource::addClient(c); - if (!m_loading) c->setCSSStyleSheet(m_url, m_decoder->encoding().name(), this); } diff --git a/WebCore/loader/CachedCSSStyleSheet.h b/WebCore/loader/CachedCSSStyleSheet.h index fa0b31a..e782f2e 100644 --- a/WebCore/loader/CachedCSSStyleSheet.h +++ b/WebCore/loader/CachedCSSStyleSheet.h @@ -42,7 +42,7 @@ namespace WebCore { const String sheetText(bool enforceMIMEType = true) const; - virtual void addClient(CachedResourceClient*); + virtual void didAddClient(CachedResourceClient*); virtual void allClientsRemoved(); diff --git a/WebCore/loader/CachedFont.cpp b/WebCore/loader/CachedFont.cpp index 922fc91..7edaf4b 100644 --- a/WebCore/loader/CachedFont.cpp +++ b/WebCore/loader/CachedFont.cpp @@ -31,7 +31,11 @@ #include "CachedResourceClientWalker.h" #include "DOMImplementation.h" #include "FontPlatformData.h" +#ifdef MANUAL_MERGE_REQUIRED #if PLATFORM(CG) || PLATFORM(QT) || PLATFORM(GTK) || (PLATFORM(CHROMIUM) && PLATFORM(WIN_OS)) || PLATFORM(SGL) +#else // MANUAL_MERGE_REQUIRED +#if PLATFORM(CG) || PLATFORM(QT) || PLATFORM(GTK) || (PLATFORM(CHROMIUM) && (PLATFORM(WIN_OS) || PLATFORM(LINUX))) +#endif // MANUAL_MERGE_REQUIRED #include "FontCustomPlatformData.h" #endif #include "TextResourceDecoder.h" @@ -60,7 +64,7 @@ CachedFont::CachedFont(const String &url) CachedFont::~CachedFont() { -#if PLATFORM(CG) || PLATFORM(QT) || PLATFORM(GTK) || (PLATFORM(CHROMIUM) && PLATFORM(WIN_OS)) +#if PLATFORM(CG) || PLATFORM(QT) || PLATFORM(GTK) || (PLATFORM(CHROMIUM) && (PLATFORM(WIN_OS) || PLATFORM(LINUX))) delete m_fontData; #endif } @@ -71,10 +75,8 @@ void CachedFont::load(DocLoader*) m_loading = true; } -void CachedFont::addClient(CachedResourceClient* c) +void CachedFont::didAddClient(CachedResourceClient* c) { - CachedResource::addClient(c); - if (!m_loading) c->fontLoaded(this); } @@ -100,7 +102,11 @@ void CachedFont::beginLoadIfNeeded(DocLoader* dl) bool CachedFont::ensureCustomFontData() { +#ifdef MANUAL_MERGE_REQUIRED #if PLATFORM(CG) || PLATFORM(QT) || PLATFORM(GTK) || (PLATFORM(CHROMIUM) && PLATFORM(WIN_OS)) || PLATFORM(SGL) +#else // MANUAL_MERGE_REQUIRED +#if PLATFORM(CG) || PLATFORM(QT) || PLATFORM(GTK) || (PLATFORM(CHROMIUM) && (PLATFORM(WIN_OS) || PLATFORM(LINUX))) +#endif // MANUAL_MERGE_REQUIRED #if ENABLE(SVG_FONTS) ASSERT(!m_isSVGFont); #endif @@ -119,7 +125,11 @@ FontPlatformData CachedFont::platformDataFromCustomData(float size, bool bold, b if (m_externalSVGDocument) return FontPlatformData(size, bold, italic); #endif +#ifdef MANUAL_MERGE_REQUIRED #if PLATFORM(CG) || PLATFORM(QT) || PLATFORM(GTK) || (PLATFORM(CHROMIUM) && PLATFORM(WIN_OS)) || PLATFORM(SGL) +#else // MANUAL_MERGE_REQUIRED +#if PLATFORM(CG) || PLATFORM(QT) || PLATFORM(GTK) || (PLATFORM(CHROMIUM) && (PLATFORM(WIN_OS) || PLATFORM(LINUX))) +#endif // MANUAL_MERGE_REQUIRED ASSERT(m_fontData); return m_fontData->fontPlatformData(static_cast(size), bold, italic, renderingMode); #else @@ -175,7 +185,7 @@ SVGFontElement* CachedFont::getSVGFontById(const String& fontName) const void CachedFont::allClientsRemoved() { -#if PLATFORM(CG) || PLATFORM(QT) || PLATFORM(GTK) || (PLATFORM(CHROMIUM) && PLATFORM(WIN_OS)) +#if PLATFORM(CG) || PLATFORM(QT) || PLATFORM(GTK) || (PLATFORM(CHROMIUM) && (PLATFORM(WIN_OS) || PLATFORM(LINUX))) if (m_fontData) { delete m_fontData; m_fontData = 0; diff --git a/WebCore/loader/CachedFont.h b/WebCore/loader/CachedFont.h index e4414c6..05b28f3 100644 --- a/WebCore/loader/CachedFont.h +++ b/WebCore/loader/CachedFont.h @@ -51,7 +51,7 @@ public: virtual void load(DocLoader* docLoader); - virtual void addClient(CachedResourceClient*); + virtual void didAddClient(CachedResourceClient*); virtual void data(PassRefPtr data, bool allDataReceived); virtual void error(); diff --git a/WebCore/loader/CachedImage.cpp b/WebCore/loader/CachedImage.cpp index eac02dc..a91f126 100644 --- a/WebCore/loader/CachedImage.cpp +++ b/WebCore/loader/CachedImage.cpp @@ -90,10 +90,8 @@ void CachedImage::load(DocLoader* docLoader) m_loading = false; } -void CachedImage::addClient(CachedResourceClient* c) +void CachedImage::didAddClient(CachedResourceClient* c) { - CachedResource::addClient(c); - if (m_decodedDataDeletionTimer.isActive()) m_decodedDataDeletionTimer.stop(); diff --git a/WebCore/loader/CachedImage.h b/WebCore/loader/CachedImage.h index 22a3774..2aa35ac 100644 --- a/WebCore/loader/CachedImage.h +++ b/WebCore/loader/CachedImage.h @@ -60,7 +60,7 @@ public: IntSize imageSize(float multiplier) const; // returns the size of the complete image. IntRect imageRect(float multiplier) const; // The size of the currently decoded portion of the image. - virtual void addClient(CachedResourceClient*); + virtual void didAddClient(CachedResourceClient*); virtual void allClientsRemoved(); virtual void destroyDecodedData(); diff --git a/WebCore/loader/CachedResource.cpp b/WebCore/loader/CachedResource.cpp index a2eaa2c..478873f 100644 --- a/WebCore/loader/CachedResource.cpp +++ b/WebCore/loader/CachedResource.cpp @@ -173,7 +173,13 @@ void CachedResource::setRequest(Request* request) delete this; } -void CachedResource::addClient(CachedResourceClient *c) +void CachedResource::addClient(CachedResourceClient* client) +{ + addClientToSet(client); + didAddClient(client); +} + +void CachedResource::addClientToSet(CachedResourceClient* client) { ASSERT(!isPurgeable()); @@ -187,21 +193,28 @@ void CachedResource::addClient(CachedResourceClient *c) } if (!hasClients() && inCache()) cache()->addToLiveResourcesSize(this); - m_clients.add(c); + m_clients.add(client); } -void CachedResource::removeClient(CachedResourceClient *c) +void CachedResource::removeClient(CachedResourceClient* client) { - ASSERT(m_clients.contains(c)); - m_clients.remove(c); + ASSERT(m_clients.contains(client)); + m_clients.remove(client); + if (canDelete() && !inCache()) delete this; else if (!hasClients() && inCache()) { cache()->removeFromLiveResourcesSize(this); cache()->removeFromLiveDecodedResourcesList(this); allClientsRemoved(); - cache()->prune(); + if (response().cacheControlContainsNoStore()) { + // RFC2616 14.9.2: + // "no-store: ...MUST make a best-effort attempt to remove the information from volatile storage as promptly as possible" + cache()->remove(this); + } else + cache()->prune(); } + // This object may be dead here. } void CachedResource::deleteIfPossible() @@ -330,10 +343,15 @@ void CachedResource::switchClientsToRevalidatedResource() } // Equivalent of calling removeClient() for all clients m_clients.clear(); - + unsigned moveCount = clientsToMove.size(); for (unsigned n = 0; n < moveCount; ++n) - m_resourceToRevalidate->addClient(clientsToMove[n]); + m_resourceToRevalidate->addClientToSet(clientsToMove[n]); + for (unsigned n = 0; n < moveCount; ++n) { + // Calling didAddClient for a client may end up removing another client. In that case it won't be in the set anymore. + if (m_resourceToRevalidate->m_clients.contains(clientsToMove[n])) + m_resourceToRevalidate->didAddClient(clientsToMove[n]); + } } void CachedResource::updateResponseAfterRevalidation(const ResourceResponse& validatingResponse) @@ -355,18 +373,32 @@ void CachedResource::updateResponseAfterRevalidation(const ResourceResponse& val bool CachedResource::canUseCacheValidator() const { - return !m_loading && (!m_response.httpHeaderField("Last-Modified").isEmpty() || !m_response.httpHeaderField("ETag").isEmpty()); + if (m_loading || m_errorOccurred) + return false; + + if (m_response.cacheControlContainsNoStore()) + return false; + + DEFINE_STATIC_LOCAL(const AtomicString, lastModifiedHeader, ("last-modified")); + DEFINE_STATIC_LOCAL(const AtomicString, eTagHeader, ("etag")); + return !m_response.httpHeaderField(lastModifiedHeader).isEmpty() || !m_response.httpHeaderField(eTagHeader).isEmpty(); } bool CachedResource::mustRevalidate(CachePolicy cachePolicy) const { + if (m_errorOccurred) + return true; + if (m_loading) return false; + + if (m_response.cacheControlContainsNoCache() || m_response.cacheControlContainsNoStore()) + return true; if (cachePolicy == CachePolicyCache) - return m_response.cacheControlContainsNoCache() || (isExpired() && m_response.cacheControlContainsMustRevalidate()); + return m_response.cacheControlContainsMustRevalidate() && isExpired(); - return isExpired() || m_response.cacheControlContainsNoCache(); + return isExpired(); } bool CachedResource::isSafeToMakePurgeable() const diff --git a/WebCore/loader/CachedResource.h b/WebCore/loader/CachedResource.h index 16cce26..babdf89 100644 --- a/WebCore/loader/CachedResource.h +++ b/WebCore/loader/CachedResource.h @@ -87,7 +87,7 @@ public: const String &url() const { return m_url; } Type type() const { return m_type; } - virtual void addClient(CachedResourceClient*); + void addClient(CachedResourceClient*); void removeClient(CachedResourceClient*); bool hasClients() const { return !m_clients.isEmpty(); } void deleteIfPossible(); @@ -100,7 +100,8 @@ public: }; PreloadResult preloadResult() const { return m_preloadResult; } void setRequestedFromNetworkingLayer() { m_requestedFromNetworkingLayer = true; } - + + virtual void didAddClient(CachedResourceClient*) = 0; virtual void allClientsRemoved() { } unsigned count() const { return m_clients.size(); } @@ -204,6 +205,8 @@ protected: bool m_errorOccurred; private: + void addClientToSet(CachedResourceClient*); + // These are called by the friendly Cache only void setResourceToRevalidate(CachedResource*); void switchClientsToRevalidatedResource(); diff --git a/WebCore/loader/CachedScript.cpp b/WebCore/loader/CachedScript.cpp index ebf0898..31483d6 100644 --- a/WebCore/loader/CachedScript.cpp +++ b/WebCore/loader/CachedScript.cpp @@ -49,9 +49,8 @@ CachedScript::~CachedScript() { } -void CachedScript::addClient(CachedResourceClient* c) +void CachedScript::didAddClient(CachedResourceClient* c) { - CachedResource::addClient(c); if (!m_loading) c->notifyFinished(this); } diff --git a/WebCore/loader/CachedScript.h b/WebCore/loader/CachedScript.h index e1c3ee0..13afa89 100644 --- a/WebCore/loader/CachedScript.h +++ b/WebCore/loader/CachedScript.h @@ -41,7 +41,7 @@ namespace WebCore { const String& script(); - virtual void addClient(CachedResourceClient*); + virtual void didAddClient(CachedResourceClient*); virtual void allClientsRemoved(); virtual void setEncoding(const String&); diff --git a/WebCore/loader/CachedXSLStyleSheet.cpp b/WebCore/loader/CachedXSLStyleSheet.cpp index f221664..5da0abf 100644 --- a/WebCore/loader/CachedXSLStyleSheet.cpp +++ b/WebCore/loader/CachedXSLStyleSheet.cpp @@ -45,10 +45,8 @@ CachedXSLStyleSheet::CachedXSLStyleSheet(const String &url) setAccept("text/xml, application/xml, application/xhtml+xml, text/xsl, application/rss+xml, application/atom+xml"); } -void CachedXSLStyleSheet::addClient(CachedResourceClient *c) -{ - CachedResource::addClient(c); - +void CachedXSLStyleSheet::didAddClient(CachedResourceClient* c) +{ if (!m_loading) c->setXSLStyleSheet(m_url, m_sheet); } diff --git a/WebCore/loader/CachedXSLStyleSheet.h b/WebCore/loader/CachedXSLStyleSheet.h index 9eca098..b6b0585 100644 --- a/WebCore/loader/CachedXSLStyleSheet.h +++ b/WebCore/loader/CachedXSLStyleSheet.h @@ -41,7 +41,7 @@ namespace WebCore { const String& sheet() const { return m_sheet; } - virtual void addClient(CachedResourceClient*); + virtual void didAddClient(CachedResourceClient*); virtual void setEncoding(const String&); virtual String encoding() const; diff --git a/WebCore/loader/CrossOriginPreflightResultCache.h b/WebCore/loader/CrossOriginPreflightResultCache.h index 39c3cd1..f71d1c8 100644 --- a/WebCore/loader/CrossOriginPreflightResultCache.h +++ b/WebCore/loader/CrossOriginPreflightResultCache.h @@ -32,7 +32,7 @@ namespace WebCore { class HTTPHeaderMap; class ResourceResponse; - class CrossOriginPreflightResultCacheItem : Noncopyable { + class CrossOriginPreflightResultCacheItem : public Noncopyable { public: CrossOriginPreflightResultCacheItem(bool credentials) : m_absoluteExpiryTime(0) @@ -57,7 +57,7 @@ namespace WebCore { HeadersSet m_headers; }; - class CrossOriginPreflightResultCache : Noncopyable { + class CrossOriginPreflightResultCache : public Noncopyable { public: static CrossOriginPreflightResultCache& shared(); diff --git a/WebCore/loader/DocLoader.cpp b/WebCore/loader/DocLoader.cpp index 7b62074..9c11a88 100644 --- a/WebCore/loader/DocLoader.cpp +++ b/WebCore/loader/DocLoader.cpp @@ -254,7 +254,7 @@ void DocLoader::printAccessDeniedMessage(const KURL& url) const m_doc->url().string().utf8().data()); // FIXME: provide a real line number and source URL. - frame()->domWindow()->console()->addMessage(OtherMessageSource, ErrorMessageLevel, message, 1, String()); + frame()->domWindow()->console()->addMessage(OtherMessageSource, LogMessageType, ErrorMessageLevel, message, 1, String()); } void DocLoader::setAutoLoadImages(bool enable) diff --git a/WebCore/loader/DocumentLoader.cpp b/WebCore/loader/DocumentLoader.cpp index ffc61df..ddab04f 100644 --- a/WebCore/loader/DocumentLoader.cpp +++ b/WebCore/loader/DocumentLoader.cpp @@ -29,12 +29,16 @@ #include "config.h" #include "DocumentLoader.h" +#ifdef MANUAL_MERGE_REQUIRED #if ENABLE(OFFLINE_WEB_APPLICATIONS) #include "ApplicationCache.h" #include "ApplicationCacheGroup.h" #include "ApplicationCacheResource.h" #endif #if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size +#else // MANUAL_MERGE_REQUIRED +#include "ApplicationCacheHost.h" +#endif // MANUAL_MERGE_REQUIRED #include "ArchiveFactory.h" #include "ArchiveResourceCollection.h" #else @@ -157,7 +161,7 @@ DocumentLoader::DocumentLoader(const ResourceRequest& req, const SubstituteData& , m_substituteResourceDeliveryTimer(this, &DocumentLoader::substituteResourceDeliveryTimerFired) , m_didCreateGlobalHistoryEntry(false) #if ENABLE(OFFLINE_WEB_APPLICATIONS) - , m_candidateApplicationCacheGroup(0) + , m_applicationCacheHost(new ApplicationCacheHost(this)) #endif { } @@ -172,13 +176,6 @@ FrameLoader* DocumentLoader::frameLoader() const DocumentLoader::~DocumentLoader() { ASSERT(!m_frame || frameLoader()->activeDocumentLoader() != this || !frameLoader()->isLoading()); - -#if ENABLE(OFFLINE_WEB_APPLICATIONS) - if (m_applicationCache) - m_applicationCache->group()->disassociateDocumentLoader(this); - else if (m_candidateApplicationCacheGroup) - m_candidateApplicationCacheGroup->disassociateDocumentLoader(this); -#endif } PassRefPtr DocumentLoader::mainResourceData() const @@ -262,14 +259,7 @@ void DocumentLoader::mainReceivedError(const ResourceError& error, bool isComple ASSERT(!error.isNull()); #if ENABLE(OFFLINE_WEB_APPLICATIONS) - ApplicationCacheGroup* group = m_candidateApplicationCacheGroup; - if (!group && m_applicationCache) { - ASSERT(!mainResourceApplicationCache()); // If the main resource were loaded from a cache, it wouldn't fail. - group = m_applicationCache->group(); - } - - if (group) - group->failedLoadingMainResource(this); + m_applicationCacheHost->failedLoadingMainResource(); #endif if (!frameLoader()) @@ -436,6 +426,9 @@ void DocumentLoader::attachToFrame() void DocumentLoader::detachFromFrame() { ASSERT(m_frame); +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + m_applicationCacheHost->setDOMApplicationCache(0); +#endif m_frame = 0; } @@ -457,9 +450,6 @@ void DocumentLoader::setPrimaryLoadComplete(bool flag) if (flag) { if (m_mainResourceLoader) { m_mainResourceData = m_mainResourceLoader->resourceData(); -#if ENABLE(OFFLINE_WEB_APPLICATIONS) - m_mainResourceApplicationCache = m_mainResourceLoader->applicationCache(); -#endif m_mainResourceLoader = 0; } @@ -857,113 +847,4 @@ void DocumentLoader::iconLoadDecisionAvailable() m_frame->loader()->iconLoadDecisionAvailable(); } -#if ENABLE(OFFLINE_WEB_APPLICATIONS) -void DocumentLoader::setCandidateApplicationCacheGroup(ApplicationCacheGroup* group) -{ - ASSERT(!m_applicationCache); - m_candidateApplicationCacheGroup = group; -} - -void DocumentLoader::setApplicationCache(PassRefPtr applicationCache) -{ - if (m_candidateApplicationCacheGroup) { - ASSERT(!m_applicationCache); - m_candidateApplicationCacheGroup = 0; - } - - m_applicationCache = applicationCache; -} - -ApplicationCache* DocumentLoader::mainResourceApplicationCache() const -{ - if (m_mainResourceApplicationCache) - return m_mainResourceApplicationCache.get(); - if (m_mainResourceLoader) - return m_mainResourceLoader->applicationCache(); - return 0; -} - -bool DocumentLoader::shouldLoadResourceFromApplicationCache(const ResourceRequest& request, ApplicationCacheResource*& resource) -{ - 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 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; - - // 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; -} - -bool DocumentLoader::scheduleApplicationCacheLoad(ResourceLoader* loader, const ResourceRequest& request, const KURL& originalURL) -{ - if (!frameLoader()->frame()->settings() || !frameLoader()->frame()->settings()->offlineWebApplicationCacheEnabled()) - return false; - - if (request.url() != originalURL) - return false; - - ApplicationCacheResource* resource; - if (!shouldLoadResourceFromApplicationCache(request, resource)) - return false; - - m_pendingSubstituteResources.set(loader, resource); - deliverSubstituteResourcesAfterDelay(); - - 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 4493e22..e4cf2c7 100644 --- a/WebCore/loader/DocumentLoader.h +++ b/WebCore/loader/DocumentLoader.h @@ -38,10 +38,14 @@ namespace WebCore { +#ifdef MANUAL_MERGE_REQUIRED class ApplicationCache; class ApplicationCacheGroup; class ApplicationCacheResource; #if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size +#else // MANUAL_MERGE_REQUIRED + class ApplicationCacheHost; +#endif // MANUAL_MERGE_REQUIRED class Archive; class ArchiveResource; class ArchiveResourceCollection; @@ -211,18 +215,7 @@ namespace WebCore { void takeMemoryCacheLoadsForClientNotification(Vector& 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() const { return m_applicationCache.get(); } - - ApplicationCache* mainResourceApplicationCache() const; + ApplicationCacheHost* applicationCacheHost() const { return m_applicationCacheHost.get(); } #endif protected: @@ -312,16 +305,9 @@ namespace WebCore { String m_clientRedirectSourceForHistory; bool m_didCreateGlobalHistoryEntry; -#if ENABLE(OFFLINE_WEB_APPLICATIONS) - // The application cache that the document loader is associated with (if any). - RefPtr m_applicationCache; - - // Before an application cache has finished loading, this will be the candidate application - // group that the document loader is associated with. - ApplicationCacheGroup* m_candidateApplicationCacheGroup; - - // Once the main resource has finished loading, this is the application cache it was loaded from (if any). - RefPtr m_mainResourceApplicationCache; +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + friend class ApplicationCacheHost; // for substitute resource delivery + OwnPtr m_applicationCacheHost; #endif }; diff --git a/WebCore/loader/DocumentThreadableLoader.cpp b/WebCore/loader/DocumentThreadableLoader.cpp index 0de62ce..dd5ca76 100644 --- a/WebCore/loader/DocumentThreadableLoader.cpp +++ b/WebCore/loader/DocumentThreadableLoader.cpp @@ -77,26 +77,26 @@ void DocumentThreadableLoader::loadResourceSynchronously(Document* document, con client.didFinishLoading(identifier); } -PassRefPtr DocumentThreadableLoader::create(Document* document, ThreadableLoaderClient* client, const ResourceRequest& request, LoadCallbacks callbacksSetting, ContentSniff contentSniff, StoredCredentials storedCredentials, RedirectOriginCheck redirectOriginCheck) +PassRefPtr DocumentThreadableLoader::create(Document* document, ThreadableLoaderClient* client, const ResourceRequest& request, LoadCallbacks callbacksSetting, ContentSniff contentSniff, StoredCredentials storedCredentials, CrossOriginRedirectPolicy crossOriginRedirectPolicy) { ASSERT(document); - RefPtr loader = adoptRef(new DocumentThreadableLoader(document, client, request, callbacksSetting, contentSniff, storedCredentials, redirectOriginCheck)); + RefPtr loader = adoptRef(new DocumentThreadableLoader(document, client, request, callbacksSetting, contentSniff, storedCredentials, crossOriginRedirectPolicy)); if (!loader->m_loader) loader = 0; return loader.release(); } -DocumentThreadableLoader::DocumentThreadableLoader(Document* document, ThreadableLoaderClient* client, const ResourceRequest& request, LoadCallbacks callbacksSetting, ContentSniff contentSniff, StoredCredentials storedCredentials, RedirectOriginCheck redirectOriginCheck) +DocumentThreadableLoader::DocumentThreadableLoader(Document* document, ThreadableLoaderClient* client, const ResourceRequest& request, LoadCallbacks callbacksSetting, ContentSniff contentSniff, StoredCredentials storedCredentials, CrossOriginRedirectPolicy crossOriginRedirectPolicy) : m_client(client) , m_document(document) , m_allowStoredCredentials(storedCredentials == AllowStoredCredentials) , m_sameOriginRequest(document->securityOrigin()->canRequest(request.url())) - , m_checkRedirectOrigin(redirectOriginCheck == RequireSameRedirectOrigin) + , m_denyCrossOriginRedirect(crossOriginRedirectPolicy == DenyCrossOriginRedirect) { ASSERT(document); ASSERT(client); ASSERT(storedCredentials == AllowStoredCredentials || storedCredentials == DoNotAllowStoredCredentials); - ASSERT(redirectOriginCheck == RequireSameRedirectOrigin || redirectOriginCheck == AllowDifferentRedirectOrigin); + ASSERT(crossOriginRedirectPolicy == DenyCrossOriginRedirect || crossOriginRedirectPolicy == AllowCrossOriginRedirect); m_loader = SubresourceLoader::create(document->frame(), this, request, false, callbacksSetting == SendLoadCallbacks, contentSniff == SniffContent); } @@ -123,7 +123,7 @@ void DocumentThreadableLoader::willSendRequest(SubresourceLoader* loader, Resour ASSERT_UNUSED(loader, loader == m_loader); // FIXME: This needs to be fixed to follow the redirect correctly even for cross-domain requests. - if (m_checkRedirectOrigin && !m_document->securityOrigin()->canRequest(request.url())) { + if (m_denyCrossOriginRedirect && !m_document->securityOrigin()->canRequest(request.url())) { RefPtr protect(this); m_client->didFailRedirectCheck(); request = ResourceRequest(); @@ -164,7 +164,8 @@ void DocumentThreadableLoader::didFinishLoading(SubresourceLoader* loader) void DocumentThreadableLoader::didFail(SubresourceLoader* loader, const ResourceError& error) { ASSERT(m_client); - ASSERT_UNUSED(loader, loader == m_loader); + // m_loader may be null if we arrive here via SubresourceLoader::create in the ctor + ASSERT_UNUSED(loader, loader == m_loader || !m_loader); m_client->didFail(error); } diff --git a/WebCore/loader/DocumentThreadableLoader.h b/WebCore/loader/DocumentThreadableLoader.h index 079c725..465475f 100644 --- a/WebCore/loader/DocumentThreadableLoader.h +++ b/WebCore/loader/DocumentThreadableLoader.h @@ -45,7 +45,7 @@ namespace WebCore { class DocumentThreadableLoader : public RefCounted, public ThreadableLoader, private SubresourceLoaderClient { public: static void loadResourceSynchronously(Document*, const ResourceRequest&, ThreadableLoaderClient&, StoredCredentials); - static PassRefPtr create(Document*, ThreadableLoaderClient*, const ResourceRequest&, LoadCallbacks, ContentSniff, StoredCredentials, RedirectOriginCheck); + static PassRefPtr create(Document*, ThreadableLoaderClient*, const ResourceRequest&, LoadCallbacks, ContentSniff, StoredCredentials, CrossOriginRedirectPolicy); virtual ~DocumentThreadableLoader(); virtual void cancel(); @@ -58,7 +58,7 @@ namespace WebCore { virtual void derefThreadableLoader() { deref(); } private: - DocumentThreadableLoader(Document*, ThreadableLoaderClient*, const ResourceRequest&, LoadCallbacks, ContentSniff, StoredCredentials, RedirectOriginCheck); + DocumentThreadableLoader(Document*, ThreadableLoaderClient*, const ResourceRequest&, LoadCallbacks, ContentSniff, StoredCredentials, CrossOriginRedirectPolicy); virtual void willSendRequest(SubresourceLoader*, ResourceRequest&, const ResourceResponse& redirectResponse); virtual void didSendData(SubresourceLoader*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent); @@ -76,7 +76,7 @@ namespace WebCore { Document* m_document; bool m_allowStoredCredentials; bool m_sameOriginRequest; - bool m_checkRedirectOrigin; + bool m_denyCrossOriginRedirect; }; } // namespace WebCore diff --git a/WebCore/loader/EmptyClients.h b/WebCore/loader/EmptyClients.h index f93a878..3f70c43 100644 --- a/WebCore/loader/EmptyClients.h +++ b/WebCore/loader/EmptyClients.h @@ -95,7 +95,7 @@ public: virtual void setResizable(bool) { } - virtual void addMessageToConsole(MessageSource, MessageLevel, const String&, unsigned, const String&) { } + virtual void addMessageToConsole(MessageSource, MessageType, MessageLevel, const String&, unsigned, const String&) { } virtual bool canRunBeforeUnloadConfirmPanel() { return false; } virtual bool runBeforeUnloadConfirmPanel(const String&, Frame*) { return true; } @@ -125,7 +125,7 @@ public: virtual void mouseDidMoveOverElement(const HitTestResult&, unsigned) { } - virtual void setToolTip(const String&) { } + virtual void setToolTip(const String&, TextDirection) { } virtual void print(Frame*) { } @@ -141,6 +141,9 @@ public: virtual void formStateDidChange(const Node*) { } + virtual void formDidFocus(const Node*) { } + virtual void formDidBlur(const Node*) { } + virtual PassOwnPtr createHTMLParserQuirks() { return 0; } virtual bool setCursor(PlatformCursorHandle) { return false; } @@ -148,6 +151,12 @@ public: virtual void scrollRectIntoView(const IntRect&, const ScrollView*) const {} virtual void requestGeolocationPermissionForFrame(Frame*, Geolocation*) {} + +#if USE(ACCELERATED_COMPOSITING) + virtual void attachRootGraphicsLayer(Frame*, GraphicsLayer*) {}; + virtual void setNeedsOneShotDrawingSynchronization() {}; + virtual void scheduleCompositingLayerSync() {}; +#endif }; class EmptyFrameLoaderClient : public FrameLoaderClient { @@ -273,8 +282,8 @@ public: virtual bool canCachePage() const { return false; } virtual PassRefPtr createFrame(const KURL&, const String&, HTMLFrameOwnerElement*, const String&, bool, int, int) { return 0; } - virtual Widget* createPlugin(const IntSize&, HTMLPlugInElement*, const KURL&, const Vector&, const Vector&, const String&, bool) { return 0; } - virtual Widget* createJavaAppletWidget(const IntSize&, HTMLAppletElement*, const KURL&, const Vector&, const Vector&) { return 0; } + virtual PassRefPtr createPlugin(const IntSize&, HTMLPlugInElement*, const KURL&, const Vector&, const Vector&, const String&, bool) { return 0; } + virtual PassRefPtr createJavaAppletWidget(const IntSize&, HTMLAppletElement*, const KURL&, const Vector&, const Vector&) { return 0; } virtual ObjectContentType objectContentType(const KURL&, const String&) { return ObjectContentType(); } virtual String overrideMediaType() const { return String(); } @@ -286,6 +295,12 @@ public: virtual void registerForIconNotification(bool) { } +#if USE(V8) + virtual void didCreateScriptContextForFrame() { } + virtual void didDestroyScriptContextForFrame() { } + virtual void didCreateIsolatedScriptContext() { } +#endif + #if PLATFORM(MAC) virtual NSCachedURLResponse* willCacheResponse(DocumentLoader*, unsigned long, NSCachedURLResponse* response) const { return response; } #endif @@ -411,6 +426,7 @@ public: virtual void copyImageToClipboard(const HitTestResult&) { } virtual void searchWithGoogle(const Frame*) { } virtual void lookUpInDictionary(Frame*) { } + virtual bool isSpeaking() { return false; } virtual void speak(const String&) { } virtual void stopSpeaking() { } @@ -458,6 +474,8 @@ public: virtual void populateSetting(const String&, InspectorController::Setting&) { } virtual void storeSetting(const String&, const InspectorController::Setting&) { } virtual void removeSetting(const String&) { } + + virtual void inspectorWindowObjectCleared() { } }; } diff --git a/WebCore/loader/FrameLoader.cpp b/WebCore/loader/FrameLoader.cpp index af0fdad..bffe8af 100644 --- a/WebCore/loader/FrameLoader.cpp +++ b/WebCore/loader/FrameLoader.cpp @@ -31,7 +31,11 @@ #include "config.h" #include "FrameLoader.h" +#ifdef MANUAL_MERGE_REQUIRED #if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size +#else // MANUAL_MERGE_REQUIRED +#include "ApplicationCacheHost.h" +#endif // MANUAL_MERGE_REQUIRED #include "Archive.h" #include "ArchiveFactory.h" #endif @@ -56,7 +60,6 @@ #include "FrameLoaderClient.h" #include "FrameTree.h" #include "FrameView.h" -#include "HTMLAnchorElement.h" #include "HTMLAppletElement.h" #include "HTMLFormElement.h" #include "HTMLFrameElement.h" @@ -73,6 +76,7 @@ #include "Page.h" #include "PageCache.h" #include "PageGroup.h" +#include "PlaceholderDocument.h" #include "PluginData.h" #include "PluginDocument.h" #include "ProgressTracker.h" @@ -92,13 +96,10 @@ #include "WindowFeatures.h" #include "XMLHttpRequest.h" #include "XMLTokenizer.h" +#include "XSSAuditor.h" #include #include -#if ENABLE(OFFLINE_WEB_APPLICATIONS) -#include "ApplicationCache.h" -#include "ApplicationCacheResource.h" -#endif #if ENABLE(SVG) #include "SVGDocument.h" @@ -126,35 +127,6 @@ using namespace SVGNames; #endif using namespace HTMLNames; -typedef HashSet URLSchemesMap; - -static URLSchemesMap& localSchemes() -{ - DEFINE_STATIC_LOCAL(URLSchemesMap, localSchemes, ()); - - if (localSchemes.isEmpty()) { - localSchemes.add("file"); -#if PLATFORM(MAC) - localSchemes.add("applewebdata"); -#endif -#if PLATFORM(QT) - localSchemes.add("qrc"); -#endif - } - - return localSchemes; -} - -static URLSchemesMap& noAccessSchemes() -{ - DEFINE_STATIC_LOCAL(URLSchemesMap, noAccessSchemes, ()); - - if (noAccessSchemes.isEmpty()) - noAccessSchemes.add("data"); - - return noAccessSchemes; -} - struct ScheduledRedirection { enum Type { redirection, locationChange, historyNavigation, formSubmission }; @@ -252,6 +224,7 @@ bool isBackForwardLoadType(FrameLoadType type) case FrameLoadTypeReplace: return false; case FrameLoadTypeBack: + case FrameLoadTypeBackWMLDeckNotAccessible: case FrameLoadTypeForward: case FrameLoadTypeIndexedBackForward: return true; @@ -310,9 +283,6 @@ FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client) #ifndef NDEBUG , m_didDispatchDidCommitLoad(false) #endif -#if ENABLE(WML) - , m_forceReloadWmlDeck(false) -#endif { } @@ -463,7 +433,7 @@ bool FrameLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String Frame* frame = ownerElement->contentFrame(); if (frame) - frame->loader()->scheduleLocationChange(url.string(), m_outgoingReferrer, true, true, userGestureHint()); + frame->loader()->scheduleLocationChange(url.string(), m_outgoingReferrer, true, true, isProcessingUserGesture()); else frame = loadSubframe(ownerElement, url, frameName, m_outgoingReferrer); @@ -506,7 +476,7 @@ Frame* FrameLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL RenderObject* renderer = ownerElement->renderer(); FrameView* view = frame->view(); if (renderer && renderer->isWidget() && view) - static_cast(renderer)->setWidget(view); + toRenderWidget(renderer)->setWidget(view); checkCallImplicitClose(); @@ -526,7 +496,7 @@ Frame* FrameLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL void FrameLoader::submitForm(const char* action, const String& url, PassRefPtr formData, const String& target, const String& contentType, const String& boundary, - bool lockHistory, bool lockBackForwardList, PassRefPtr event, PassRefPtr formState) + bool lockHistory, PassRefPtr event, PassRefPtr formState) { ASSERT(action); ASSERT(strcmp(action, "GET") == 0 || strcmp(action, "POST") == 0); @@ -598,6 +568,7 @@ void FrameLoader::submitForm(const char* action, const String& url, PassRefPtrloader()->scheduleFormSubmission(frameRequest, lockHistory, lockBackForwardList, event, formState); +#else // MANUAL_MERGE_REQUIRED + targetFrame->loader()->scheduleFormSubmission(frameRequest, lockHistory, event, formState); +#endif // MANUAL_MERGE_REQUIRED } void FrameLoader::stopLoading(bool sendUnload, DatabasePolicy databasePolicy) @@ -780,15 +754,16 @@ bool FrameLoader::executeIfJavaScriptURL(const KURL& url, bool userGesture, bool if (m_frame->page() && !m_frame->page()->javaScriptURLsAreAllowed()) return true; - String script = decodeURLEscapeSequences(url.string().substring(strlen("javascript:"))); + const int javascriptSchemeLength = sizeof("javascript:") - 1; + + String script = decodeURLEscapeSequences(url.string().substring(javascriptSchemeLength)); ScriptValue result = executeScript(script, userGesture); String scriptResult; if (!result.getString(scriptResult)) return true; - SecurityOrigin* currentSecurityOrigin = 0; - currentSecurityOrigin = m_frame->document()->securityOrigin(); + SecurityOrigin* currentSecurityOrigin = m_frame->document()->securityOrigin(); // FIXME: We should always replace the document, but doing so // synchronously can cause crashes: @@ -949,6 +924,8 @@ void FrameLoader::begin(const KURL& url, bool dispatch, SecurityOrigin* origin) // Create a new document before clearing the frame, because it may need to inherit an aliased security context. if (!m_isDisplayingInitialEmptyDocument && m_client->shouldUsePluginDocument(m_responseMIMEType)) document = PluginDocument::create(m_frame); + else if (!m_client->hasHTMLView()) + document = PlaceholderDocument::create(m_frame); else document = DOMImplementation::createDocument(m_responseMIMEType, m_frame, m_frame->inViewSourceMode()); @@ -966,7 +943,7 @@ void FrameLoader::begin(const KURL& url, bool dispatch, SecurityOrigin* origin) KURL ref(url); ref.setUser(String()); ref.setPass(String()); - ref.setRef(String()); + ref.removeFragmentIdentifier(); m_outgoingReferrer = ref.string(); m_URL = url; @@ -1007,8 +984,8 @@ void FrameLoader::begin(const KURL& url, bool dispatch, SecurityOrigin* origin) restoreDocumentState(); document->implicitOpen(); - - if (m_frame->view()) + + if (m_frame->view() && m_client->hasHTMLView()) m_frame->view()->setContentsSize(IntSize()); } @@ -1170,6 +1147,12 @@ void FrameLoader::startIconLoader() } } + // People who want to avoid loading images generally want to avoid loading all images. + // Now that we've accounted for URL mapping, avoid starting the network load if images aren't set to display automatically. + Settings* settings = m_frame->settings(); + if (settings && !settings->loadsImagesAutomatically()) + return; + // This is either a reload or the icon database said "yes, load the icon", so kick off the load! if (!m_iconLoader) m_iconLoader.set(IconLoader::create(m_frame).release()); @@ -1213,6 +1196,7 @@ void FrameLoader::restoreDocumentState() case FrameLoadTypeReplace: break; case FrameLoadTypeBack: + case FrameLoadTypeBackWMLDeckNotAccessible: case FrameLoadTypeForward: case FrameLoadTypeIndexedBackForward: case FrameLoadTypeRedirectWithLockedBackForwardList: @@ -1233,16 +1217,16 @@ void FrameLoader::gotoAnchor() // OTOH If CSS target was set previously, we want to set it to 0, recalc // and possibly repaint because :target pseudo class may have been // set (see bug 11321). - if (!m_URL.hasRef() && !m_frame->document()->cssTarget()) + if (!m_URL.hasFragmentIdentifier() && !m_frame->document()->cssTarget()) return; - String ref = m_URL.ref(); - if (gotoAnchor(ref)) + String fragmentIdentifier = m_URL.fragmentIdentifier(); + if (gotoAnchor(fragmentIdentifier)) return; // Try again after decoding the ref, based on the document's encoding. if (m_decoder) - gotoAnchor(decodeURLEscapeSequences(ref, m_decoder->encoding())); + gotoAnchor(decodeURLEscapeSequences(fragmentIdentifier, m_decoder->encoding())); } void FrameLoader::finishedParsing() @@ -1378,6 +1362,20 @@ void FrameLoader::scheduleHTTPRedirection(double delay, const String& url) scheduleRedirection(new ScheduledRedirection(delay, url, true, delay <= 1, false, false)); } +static bool mustLockBackForwardList(Frame* targetFrame) +{ + // Navigation of a subframe during loading of an ancestor frame does not create a new back/forward item. + // The definition of "during load" is any time before all handlers for the load event have been run. + // See https://bugs.webkit.org/show_bug.cgi?id=14957 for the original motivation for this. + + for (Frame* ancestor = targetFrame->tree()->parent(); ancestor; ancestor = ancestor->tree()->parent()) { + Document* document = ancestor->document(); + if (!ancestor->loader()->isComplete() || document && document->processingLoadEvent()) + return true; + } + return false; +} + void FrameLoader::scheduleLocationChange(const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool wasUserGesture) { if (!m_frame->page()) @@ -1386,10 +1384,12 @@ void FrameLoader::scheduleLocationChange(const String& url, const String& referr if (url.isEmpty()) return; + lockBackForwardList = lockBackForwardList || mustLockBackForwardList(m_frame); + // If the URL we're going to navigate to is the same as the current one, except for the // fragment part, we don't need to schedule the location change. KURL parsedURL(url); - if (parsedURL.hasRef() && equalIgnoringRef(m_URL, parsedURL)) { + if (parsedURL.hasFragmentIdentifier() && equalIgnoringFragmentIdentifier(m_URL, parsedURL)) { changeLocation(completeURL(url), referrer, lockHistory, lockBackForwardList, wasUserGesture); return; } @@ -1402,7 +1402,7 @@ void FrameLoader::scheduleLocationChange(const String& url, const String& referr } void FrameLoader::scheduleFormSubmission(const FrameLoadRequest& frameRequest, - bool lockHistory, bool lockBackForwardList, PassRefPtr event, PassRefPtr formState) + bool lockHistory, PassRefPtr event, PassRefPtr formState) { ASSERT(m_frame->page()); ASSERT(!frameRequest.isEmpty()); @@ -1414,7 +1414,7 @@ void FrameLoader::scheduleFormSubmission(const FrameLoadRequest& frameRequest, // This may happen when a frame changes the location of another frame. bool duringLoad = !m_committedFirstRealDocumentLoad; - scheduleRedirection(new ScheduledRedirection(frameRequest, lockHistory, lockBackForwardList, event, formState, duringLoad)); + scheduleRedirection(new ScheduledRedirection(frameRequest, lockHistory, mustLockBackForwardList(m_frame), event, formState, duringLoad)); } void FrameLoader::scheduleRefresh(bool wasUserGesture) @@ -1632,6 +1632,7 @@ bool FrameLoader::gotoAnchor(const String& name) if (!anchorNode && !(name.isEmpty() || equalIgnoringCase(name, "top"))) return false; +#ifdef MANUAL_MERGE_REQUIRED // We need to update the layout before scrolling, otherwise we could // really mess things up if an anchor scroll comes at a bad moment. m_frame->document()->updateStyleIfNeeded(); @@ -1660,6 +1661,10 @@ bool FrameLoader::gotoAnchor(const String& name) #ifdef ANDROID_SCROLL_ON_GOTO_ANCHOR android::WebFrame::getWebFrame(m_frame)->setUserInitiatedClick(false); #endif +#else // MANUAL_MERGE_REQUIRED + if (FrameView* view = m_frame->view()) + view->maintainScrollPositionAtAnchor(anchorNode ? static_cast(anchorNode) : m_frame->document()); +#endif // MANUAL_MERGE_REQUIRED return true; } @@ -1669,6 +1674,11 @@ bool FrameLoader::requestObject(RenderPart* renderer, const String& url, const A { if (url.isEmpty() && mimeType.isEmpty()) return false; + + if (!m_frame->script()->xssAuditor()->canLoadObject(url)) { + // It is unsafe to honor the request for this object. + return false; + } KURL completedURL; if (!url.isEmpty()) @@ -1733,7 +1743,7 @@ static HTMLPlugInElement* toPlugInElement(Node* node) bool FrameLoader::loadPlugin(RenderPart* renderer, const KURL& url, const String& mimeType, const Vector& paramNames, const Vector& paramValues, bool useFallback) { - Widget* widget = 0; + RefPtr widget; if (renderer && !useFallback) { HTMLPlugInElement* element = toPlugInElement(renderer->node()); @@ -1819,7 +1829,7 @@ void FrameLoader::provisionalLoadStarted() m_client->provisionalLoadStarted(); } -bool FrameLoader::userGestureHint() +bool FrameLoader::isProcessingUserGesture() { Frame* frame = m_frame->tree()->top(); if (!frame->script()->isEnabled()) @@ -1848,6 +1858,17 @@ void FrameLoader::addData(const char* bytes, int length) write(bytes, length); } +#if ENABLE(WML) +static inline bool frameContainsWMLContent(Frame* frame) +{ + Document* document = frame ? frame->document() : 0; + if (!document) + return false; + + return document->containsWMLContent() || document->isWMLDocument(); +} +#endif + bool FrameLoader::canCachePageContainingThisFrame() { return m_documentLoader @@ -1873,8 +1894,10 @@ bool FrameLoader::canCachePageContainingThisFrame() #if ENABLE(OFFLINE_WEB_APPLICATIONS) // FIXME: We should investigating caching frames that have an associated // application cache. tracks that work. - && !m_documentLoader->applicationCache() - && !m_documentLoader->candidateApplicationCacheGroup() + && m_documentLoader->applicationCacheHost()->canCacheInPageCache() +#endif +#if ENABLE(WML) + && !frameContainsWMLContent(m_frame) #endif && m_client->canCachePage() ; @@ -2021,10 +2044,8 @@ bool FrameLoader::logCanCacheFrameDecision(int indentLevel) 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; } + if (!m_documentLoader->applicationCacheHost()->canCacheInPageCache()) + { PCLOG(" -The DocumentLoader uses an application cache"); cannotCache = true; } #endif if (!m_client->canCachePage()) { PCLOG(" -The client says this frame cannot be cached"); cannotCache = true; } @@ -2056,10 +2077,39 @@ void FrameLoader::setFirstPartyForCookies(const KURL& url) child->loader()->setFirstPartyForCookies(url); } +class HashChangeEventTask : public ScriptExecutionContext::Task { +public: + static PassRefPtr create(PassRefPtr document) + { + return adoptRef(new HashChangeEventTask(document)); + } + + virtual void performTask(ScriptExecutionContext* context) + { + ASSERT_UNUSED(context, context->isDocument()); + m_document->dispatchWindowEvent(eventNames().hashchangeEvent, false, false); + } + +private: + HashChangeEventTask(PassRefPtr document) + : m_document(document) + { + ASSERT(m_document); + } + + RefPtr m_document; +}; + // This does the same kind of work that didOpenURL does, except it relies on the fact // that a higher level already checked that the URLs match and the scrolling is the right thing to do. void FrameLoader::scrollToAnchor(const KURL& url) { + ASSERT(equalIgnoringFragmentIdentifier(url, m_URL)); + if (equalIgnoringFragmentIdentifier(url, m_URL) && !equalIgnoringNullity(url.fragmentIdentifier(), m_URL.fragmentIdentifier())) { + Document* currentDocument = frame()->document(); + currentDocument->postTask(HashChangeEventTask::create(currentDocument)); + } + m_URL = url; updateHistoryForAnchorScroll(); @@ -2162,7 +2212,7 @@ void FrameLoader::completed() if (Frame* parent = m_frame->tree()->parent()) parent->loader()->checkCompleted(); if (m_frame->view()) - m_frame->view()->setLockedToAnchor(false); + m_frame->view()->maintainScrollPositionAtAnchor(0); } void FrameLoader::started() @@ -2224,7 +2274,7 @@ void FrameLoader::loadFrameRequest(const FrameLoadRequest& request, bool lockHis referrer = m_outgoingReferrer; ASSERT(frame()->document()); - if (shouldTreatURLAsLocal(url.string()) && !isFeedWithNestedProtocolInHTTPFamily(url)) { + if (SecurityOrigin::shouldTreatURLAsLocal(url.string()) && !isFeedWithNestedProtocolInHTTPFamily(url)) { if (!canLoad(url, String(), frame()->document()) && !canLoad(url, referrer)) { FrameLoader::reportLocalLoadFailed(m_frame, url.string()); return; @@ -2439,7 +2489,7 @@ bool FrameLoader::canLoad(const KURL& url, const String& referrer, const Documen bool FrameLoader::canLoad(const KURL& url, const String& referrer, const SecurityOrigin* securityOrigin) { // We can always load any URL that isn't considered local (e.g. http URLs). - if (!shouldTreatURLAsLocal(url.string())) + if (!SecurityOrigin::shouldTreatURLAsLocal(url.string())) return true; // If we were provided a document, we let its local file policy dictate the result, @@ -2447,7 +2497,7 @@ bool FrameLoader::canLoad(const KURL& url, const String& referrer, const Securit if (securityOrigin) return securityOrigin->canLoadLocalResources(); if (!referrer.isEmpty()) - return shouldTreatURLAsLocal(referrer); + return SecurityOrigin::shouldTreatURLAsLocal(referrer); return false; } @@ -2457,7 +2507,7 @@ void FrameLoader::reportLocalLoadFailed(Frame* frame, const String& url) if (!frame) return; - frame->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, "Not allowed to load local resource: " + url, 0, String()); + frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, "Not allowed to load local resource: " + url, 0, String()); } bool FrameLoader::shouldHideReferrer(const KURL& url, const String& referrer) @@ -2674,7 +2724,7 @@ bool FrameLoader::shouldAllowNavigation(Frame* targetFrame) const targetDocument->url().string().utf8().data(), activeDocument->url().string().utf8().data()); // FIXME: should we print to the console of the activeFrame as well? - targetFrame->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, message, 1, String()); + targetFrame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, 1, String()); } return false; @@ -2933,6 +2983,7 @@ void FrameLoader::transitionToCommitted(PassRefPtr cachedPage) switch (m_loadType) { case FrameLoadTypeForward: case FrameLoadTypeBack: + case FrameLoadTypeBackWMLDeckNotAccessible: case FrameLoadTypeIndexedBackForward: if (Page* page = m_frame->page()) if (page->backForwardList()) { @@ -2990,10 +3041,12 @@ void FrameLoader::transitionToCommitted(PassRefPtr cachedPage) m_committedFirstRealDocumentLoad = true; - // For non-cached HTML pages, these methods are called in FrameLoader::begin. - if (cachedPage || !m_client->hasHTMLView()) { - dispatchDidCommitLoad(); - + if (!m_client->hasHTMLView()) + receivedFirstData(); + else if (cachedPage) { + // For non-cached HTML pages, these methods are called in receivedFirstData(). + dispatchDidCommitLoad(); + // If we have a title let the WebView know about it. if (!ptitle.isNull()) m_client->dispatchDidReceiveTitle(ptitle); @@ -3028,27 +3081,20 @@ void FrameLoader::clientRedirected(const KURL& url, double seconds, double fireD m_quickRedirectComing = lockBackForwardList && m_documentLoader && !m_isExecutingJavaScriptFormAction; } -#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) + // All WML decks are supposed to be reloaded, even within the same URL fragment + if (frameContainsWMLContent(m_frame)) 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." - if (!destinationURL.hasRef()) + if (!destinationURL.hasFragmentIdentifier()) return true; - return !equalIgnoringRef(currentURL, destinationURL); + return !equalIgnoringFragmentIdentifier(currentURL, destinationURL); } void FrameLoader::closeOldDataSources() @@ -3083,6 +3129,7 @@ void FrameLoader::open(CachedPage& cachedPage) } open(*cachedPage.cachedMainFrame()); + cachedPage.restore(m_frame->page()); checkCompleted(); } @@ -3753,30 +3800,11 @@ unsigned long FrameLoader::loadResourceSynchronously(const ResourceRequest& requ ASSERT(!newRequest.isNull()); #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()); - } else - error = cannotShowURLError(newRequest); - } else { + if (!documentLoader()->applicationCacheHost()->maybeLoadSynchronously(newRequest, error, response, data)) { #endif ResourceHandle::loadResourceSynchronously(newRequest, storedCredentials, 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()); - } - } + documentLoader()->applicationCacheHost()->maybeLoadFallbackSynchronously(newRequest, error, response, data); } #endif } @@ -4505,7 +4533,8 @@ void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType) bool shouldScroll = !formData && !(m_currentHistoryItem && m_currentHistoryItem->formData()) && urlsMatchItem(item); #if ENABLE(WML) - if (m_frame->document()->isWMLDocument()) + // All WML decks should go through the real load mechanism, not the scroll-to-anchor code + if (frameContainsWMLContent(m_frame)) shouldScroll = false; #endif @@ -4591,7 +4620,7 @@ void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType) // have the item vanish when we try to use it in the ensuing nav. This should be // extremely rare, but in that case the user will get an error on the navigation. - if (ResourceHandle::willLoadFromCache(request)) + if (ResourceHandle::willLoadFromCache(request, m_frame)) action = NavigationAction(itemURL, loadType, false); else { request.setCachePolicy(ReloadIgnoringCacheData); @@ -4604,6 +4633,7 @@ void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType) request.setCachePolicy(ReloadIgnoringCacheData); break; case FrameLoadTypeBack: + case FrameLoadTypeBackWMLDeckNotAccessible: case FrameLoadTypeForward: case FrameLoadTypeIndexedBackForward: if (itemURL.protocol() != "https") @@ -4632,7 +4662,7 @@ void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType) bool FrameLoader::urlsMatchItem(HistoryItem* item) const { const KURL& currentURL = documentLoader()->url(); - if (!equalIgnoringRef(currentURL, item->url())) + if (!equalIgnoringFragmentIdentifier(currentURL, item->url())) return false; const HistoryItemVector& childItems = item->children(); @@ -5130,7 +5160,7 @@ void FrameLoader::dispatchWindowObjectAvailable() } } -Widget* FrameLoader::createJavaAppletWidget(const IntSize& size, HTMLAppletElement* element, const HashMap& args) +PassRefPtr FrameLoader::createJavaAppletWidget(const IntSize& size, HTMLAppletElement* element, const HashMap& args) { String baseURLString; String codeBaseURLString; @@ -5158,7 +5188,7 @@ Widget* FrameLoader::createJavaAppletWidget(const IntSize& size, HTMLAppletEleme baseURLString = m_frame->document()->baseURL().string(); KURL baseURL = completeURL(baseURLString); - Widget* widget = m_client->createJavaAppletWidget(size, element, baseURL, paramNames, paramValues); + RefPtr widget = m_client->createJavaAppletWidget(size, element, baseURL, paramNames, paramValues); if (!widget) return 0; @@ -5170,8 +5200,7 @@ void FrameLoader::didChangeTitle(DocumentLoader* loader) { m_client->didChangeTitle(loader); - // The title doesn't get communicated to the WebView until we are committed. - if (loader->isCommitted()) { + if (loader == m_documentLoader) { // Must update the entries in the back-forward list too. if (m_currentHistoryItem) m_currentHistoryItem->setTitle(loader->title()); @@ -5182,59 +5211,6 @@ void FrameLoader::didChangeTitle(DocumentLoader* loader) } } -void FrameLoader::registerURLSchemeAsLocal(const String& scheme) -{ - localSchemes().add(scheme); -} - -bool FrameLoader::shouldTreatURLAsLocal(const String& url) -{ - // This avoids an allocation of another String and the HashSet contains() - // call for the file: and http: schemes. - if (url.length() >= 5) { - const UChar* s = url.characters(); - if (s[0] == 'h' && s[1] == 't' && s[2] == 't' && s[3] == 'p' && s[4] == ':') - return false; - if (s[0] == 'f' && s[1] == 'i' && s[2] == 'l' && s[3] == 'e' && s[4] == ':') - return true; - } - - int loc = url.find(':'); - if (loc == -1) - return false; - - String scheme = url.left(loc); - return localSchemes().contains(scheme); -} - -bool FrameLoader::shouldTreatURLSchemeAsLocal(const String& scheme) -{ - // This avoids an allocation of another String and the HashSet contains() - // call for the file: and http: schemes. - if (scheme.length() == 4) { - const UChar* s = scheme.characters(); - if (s[0] == 'h' && s[1] == 't' && s[2] == 't' && s[3] == 'p') - return false; - if (s[0] == 'f' && s[1] == 'i' && s[2] == 'l' && s[3] == 'e') - return true; - } - - if (scheme.isEmpty()) - return false; - - return localSchemes().contains(scheme); -} - -void FrameLoader::registerURLSchemeAsNoAccess(const String& scheme) -{ - noAccessSchemes().add(scheme); -} - -bool FrameLoader::shouldTreatURLSchemeAsNoAccess(const String& scheme) -{ - return noAccessSchemes().contains(scheme); -} - void FrameLoader::dispatchDidCommitLoad() { if (m_creatingInitialEmptyDocument) diff --git a/WebCore/loader/FrameLoader.h b/WebCore/loader/FrameLoader.h index 6a63382..5a8ee91 100644 --- a/WebCore/loader/FrameLoader.h +++ b/WebCore/loader/FrameLoader.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. - * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) + * Copyright (C) 2008, 2009 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 @@ -113,7 +113,7 @@ namespace WebCore { void* m_argument; }; - class FrameLoader : Noncopyable { + class FrameLoader : public Noncopyable { public: FrameLoader(Frame*, FrameLoaderClient*); ~FrameLoader(); @@ -241,10 +241,6 @@ namespace WebCore { void didFirstVisuallyNonEmptyLayout(); -#if ENABLE(WML) - void setForceReloadWmlDeck(bool); -#endif - void loadedResourceFromMemoryCache(const CachedResource*); void tellClientAboutPastMemoryCacheLoads(); @@ -266,7 +262,7 @@ namespace WebCore { void submitForm(const char* action, const String& url, PassRefPtr, const String& target, const String& contentType, const String& boundary, - bool lockHistory, bool lockBackForwardList, PassRefPtr, PassRefPtr); + bool lockHistory, PassRefPtr, PassRefPtr); void stop(); void stopLoading(bool sendUnload, DatabasePolicy = DatabasePolicyStop); @@ -310,7 +306,7 @@ namespace WebCore { void handledOnloadEvents(); String userAgent(const KURL&) const; - Widget* createJavaAppletWidget(const IntSize&, HTMLAppletElement*, const HashMap& args); + PassRefPtr createJavaAppletWidget(const IntSize&, HTMLAppletElement*, const HashMap& args); void dispatchWindowObjectAvailable(); void dispatchDocumentElementAvailable(); @@ -321,7 +317,7 @@ namespace WebCore { bool openedByDOM() const; void setOpenedByDOM(); - bool userGestureHint(); + bool isProcessingUserGesture(); void resetMultipleFormSubmissionProtection(); @@ -370,13 +366,6 @@ namespace WebCore { static bool restrictAccessToLocal(); static bool allowSubstituteDataAccessToLocal(); - static void registerURLSchemeAsLocal(const String&); - static bool shouldTreatURLAsLocal(const String&); - static bool shouldTreatURLSchemeAsLocal(const String&); - - static void registerURLSchemeAsNoAccess(const String&); - static bool shouldTreatURLSchemeAsNoAccess(const String&); - bool committingFirstRealLoad() const { return !m_creatingInitialEmptyDocument && !m_committedFirstRealDocumentLoad; } void iconLoadDecisionAvailable(); @@ -504,7 +493,7 @@ namespace WebCore { void dispatchDidFinishLoading(DocumentLoader*, unsigned long identifier); static bool isLocationChange(const ScheduledRedirection&); - void scheduleFormSubmission(const FrameLoadRequest&, bool lockHistory, bool lockBackForwardList, PassRefPtr, PassRefPtr); + void scheduleFormSubmission(const FrameLoadRequest&, bool lockHistory, PassRefPtr, PassRefPtr); void loadWithDocumentLoader(DocumentLoader*, FrameLoadType, PassRefPtr); // Calls continueLoadAfterNavigationPolicy void load(DocumentLoader*); // Calls loadWithDocumentLoader @@ -637,10 +626,6 @@ namespace WebCore { #ifndef NDEBUG bool m_didDispatchDidCommitLoad; #endif - -#if ENABLE(WML) - bool m_forceReloadWmlDeck; -#endif }; } // namespace WebCore diff --git a/WebCore/loader/FrameLoaderClient.h b/WebCore/loader/FrameLoaderClient.h index e64dee9..db38f01 100644 --- a/WebCore/loader/FrameLoaderClient.h +++ b/WebCore/loader/FrameLoaderClient.h @@ -59,6 +59,7 @@ namespace WebCore { class IntSize; class KURL; class NavigationAction; + class PluginView; class ResourceError; class ResourceHandle; class ResourceLoader; @@ -209,10 +210,12 @@ namespace WebCore { virtual PassRefPtr createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement, const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight) = 0; - virtual Widget* createPlugin(const IntSize&, HTMLPlugInElement*, const KURL&, const Vector&, const Vector&, const String&, bool loadManually) = 0; + virtual PassRefPtr createPlugin(const IntSize&, HTMLPlugInElement*, const KURL&, const Vector&, const Vector&, const String&, bool loadManually) = 0; virtual void redirectDataToPlugin(Widget* pluginWidget) = 0; - - virtual Widget* createJavaAppletWidget(const IntSize&, HTMLAppletElement*, const KURL& baseURL, const Vector& paramNames, const Vector& paramValues) = 0; + + virtual PassRefPtr createJavaAppletWidget(const IntSize&, HTMLAppletElement*, const KURL& baseURL, const Vector& paramNames, const Vector& paramValues) = 0; + + virtual void dispatchDidFailToStartPlugin(const PluginView*) const { } virtual ObjectContentType objectContentType(const KURL& url, const String& mimeType) = 0; virtual String overrideMediaType() const = 0; @@ -220,7 +223,13 @@ namespace WebCore { virtual void windowObjectCleared() = 0; virtual void documentElementAvailable() = 0; virtual void didPerformFirstNavigation() const = 0; // "Navigation" here means a transition from one page to another that ends up in the back/forward list. - + +#if USE(V8) + virtual void didCreateScriptContextForFrame() = 0; + virtual void didDestroyScriptContextForFrame() = 0; + virtual void didCreateIsolatedScriptContext() = 0; +#endif + virtual void registerForIconNotification(bool listen = true) = 0; #ifdef ANDROID_APPLE_TOUCH_ICON virtual void dispatchDidReceiveTouchIconURL(const String& url) = 0; diff --git a/WebCore/loader/FrameLoaderTypes.h b/WebCore/loader/FrameLoaderTypes.h index c264b47..940bb7f 100644 --- a/WebCore/loader/FrameLoaderTypes.h +++ b/WebCore/loader/FrameLoaderTypes.h @@ -45,16 +45,19 @@ namespace WebCore { PolicyIgnore, }; + // NOTE: Keep in sync with WebKit/mac/WebView/WebFramePrivate.h and WebKit/win/Interfaces/IWebFramePrivate.idl enum FrameLoadType { FrameLoadTypeStandard, FrameLoadTypeBack, FrameLoadTypeForward, FrameLoadTypeIndexedBackForward, // a multi-item hop in the backforward list FrameLoadTypeReload, - FrameLoadTypeSame, // user loads same URL again (but not reload button) + // Skipped value: 'FrameLoadTypeReloadAllowingStaleData', still present in mac/win public API. Ready to be reused + FrameLoadTypeSame = FrameLoadTypeReload + 2, // user loads same URL again (but not reload button) FrameLoadTypeRedirectWithLockedBackForwardList, // FIXME: Merge "lockBackForwardList", "lockHistory", "quickRedirect" and "clientRedirect" into a single concept of redirect. FrameLoadTypeReplace, - FrameLoadTypeReloadFromOrigin + FrameLoadTypeReloadFromOrigin, + FrameLoadTypeBackWMLDeckNotAccessible }; enum NavigationType { diff --git a/WebCore/loader/MainResourceLoader.cpp b/WebCore/loader/MainResourceLoader.cpp index 39e5b90..6c843e9 100644 --- a/WebCore/loader/MainResourceLoader.cpp +++ b/WebCore/loader/MainResourceLoader.cpp @@ -30,6 +30,7 @@ #include "config.h" #include "MainResourceLoader.h" +#include "ApplicationCacheHost.h" #include "DocumentLoader.h" #include "FormState.h" #include "Frame.h" @@ -41,12 +42,6 @@ #include "ResourceHandle.h" #include "Settings.h" -#if ENABLE(OFFLINE_WEB_APPLICATIONS) -#include "ApplicationCache.h" -#include "ApplicationCacheGroup.h" -#include "ApplicationCacheResource.h" -#endif - // FIXME: More that is in common with SubresourceLoader should move up into ResourceLoader. namespace WebCore { @@ -283,15 +278,8 @@ 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; - } - } + if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForMainResponse(request(), r)) + return; #endif HTTPHeaderMap::const_iterator it = r.httpHeaderFields().find(AtomicString("x-frame-options")); @@ -353,6 +341,10 @@ void MainResourceLoader::didReceiveData(const char* data, int length, long long ASSERT(!defersLoading()); #endif + #if ENABLE(OFFLINE_WEB_APPLICATIONS) + documentLoader()->applicationCacheHost()->mainResourceDataReceived(data, length, lengthReceived, allAtOnce); +#endif + // The additional processing can do anything including possibly removing the last // reference to this object; one example of this is 3266216. RefPtr protect(this); @@ -380,27 +372,15 @@ void MainResourceLoader::didFinishLoading() ResourceLoader::didFinishLoading(); #if ENABLE(OFFLINE_WEB_APPLICATIONS) - ApplicationCacheGroup* group = dl->candidateApplicationCacheGroup(); - if (!group && dl->applicationCache() && !dl->mainResourceApplicationCache()) - group = dl->applicationCache()->group(); - - if (group) - group->finishedLoadingMainResource(dl.get()); + dl->applicationCacheHost()->finishedLoadingMainResource(); #endif } 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; - } - } + if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForMainError(request(), error)) + return; #endif // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred. @@ -495,27 +475,15 @@ bool MainResourceLoader::load(const ResourceRequest& r, const SubstituteData& su m_substituteData = substituteData; + ResourceRequest request(r); + #if ENABLE(OFFLINE_WEB_APPLICATIONS) - // Check if this request should be loaded from the application cache - if (!m_substituteData.isValid() && frameLoader()->frame()->settings() && frameLoader()->frame()->settings()->offlineWebApplicationCacheEnabled()) { - ASSERT(!m_applicationCache); - - m_applicationCache = ApplicationCacheGroup::cacheForMainRequest(r, m_documentLoader.get()); - - if (m_applicationCache) { - // 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()); - } - } + documentLoader()->applicationCacheHost()->maybeLoadMainResource(request, m_substituteData); #endif - ResourceRequest request(r); bool defer = defersLoading(); if (defer) { - bool shouldLoadEmpty = shouldLoadAsEmptyDocument(r.url()); + bool shouldLoadEmpty = shouldLoadAsEmptyDocument(request.url()); if (shouldLoadEmpty) defer = false; } diff --git a/WebCore/loader/MainResourceLoader.h b/WebCore/loader/MainResourceLoader.h index d9ce2f9..d3f411b 100644 --- a/WebCore/loader/MainResourceLoader.h +++ b/WebCore/loader/MainResourceLoader.h @@ -39,9 +39,6 @@ namespace WebCore { -#if ENABLE(OFFLINE_WEB_APPLICATIONS) - class ApplicationCache; -#endif class FormState; struct ResourceRequest; @@ -71,10 +68,6 @@ namespace WebCore { bool isLoadingMultipartContent() const { return m_loadingMultipartContent; } -#if ENABLE(OFFLINE_WEB_APPLICATIONS) - ApplicationCache* applicationCache() const { return m_applicationCache.get(); } -#endif - private: MainResourceLoader(Frame*); @@ -105,11 +98,6 @@ namespace WebCore { MainResourceLoaderTimer m_dataLoadTimer; -#if ENABLE(OFFLINE_WEB_APPLICATIONS) - // The application cache that the main resource was loaded from (if any). - RefPtr m_applicationCache; -#endif - bool m_loadingMultipartContent; bool m_waitingForContentPolicy; }; diff --git a/WebCore/loader/PlaceholderDocument.cpp b/WebCore/loader/PlaceholderDocument.cpp new file mode 100644 index 0000000..e071aa8 --- /dev/null +++ b/WebCore/loader/PlaceholderDocument.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 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 + * 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. 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 "PlaceholderDocument.h" + +#include "CSSStyleSelector.h" +#include "StyleSheetList.h" + +namespace WebCore { + +void PlaceholderDocument::attach() +{ + ASSERT(!attached()); + + if (!styleSelector()) { + RefPtr styleSheetList = StyleSheetList::create(this); + setStyleSelector(new CSSStyleSelector(this, userStyleSheet(), styleSheetList.get(), 0, true, false)); + } + + // Skipping Document::attach(). + ContainerNode::attach(); +} + +} // namespace WebCore diff --git a/WebCore/loader/PlaceholderDocument.h b/WebCore/loader/PlaceholderDocument.h new file mode 100644 index 0000000..c542370 --- /dev/null +++ b/WebCore/loader/PlaceholderDocument.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 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 + * 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. 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 PlaceholderDocument_h +#define PlaceholderDocument_h + +#include "Document.h" + +namespace WebCore { + +class PlaceholderDocument : public Document { +public: + static PassRefPtr create(Frame* frame) + { + return new PlaceholderDocument(frame); + } + + virtual void attach(); + +private: + PlaceholderDocument(Frame* frame) : Document(frame, false) { } +}; + +} // namespace WebCore + +#endif // PlaceholderDocument_h diff --git a/WebCore/loader/PluginDocument.cpp b/WebCore/loader/PluginDocument.cpp index 373126f..3500c98 100644 --- a/WebCore/loader/PluginDocument.cpp +++ b/WebCore/loader/PluginDocument.cpp @@ -106,12 +106,12 @@ bool PluginTokenizer::writeRawData(const char*, int) Settings* settings = frame->settings(); if (settings && settings->arePluginsEnabled()) { m_doc->updateLayout(); - - if (RenderWidget* renderer = static_cast(m_embedElement->renderer())) { + + if (RenderWidget* renderer = toRenderWidget(m_embedElement->renderer())) { frame->loader()->client()->redirectDataToPlugin(renderer->widget()); frame->loader()->activeDocumentLoader()->mainResourceLoader()->setShouldBufferData(false); } - + finish(); } } diff --git a/WebCore/loader/ProgressTracker.h b/WebCore/loader/ProgressTracker.h index b8d4532..744e101 100644 --- a/WebCore/loader/ProgressTracker.h +++ b/WebCore/loader/ProgressTracker.h @@ -36,7 +36,7 @@ class Frame; class ResourceResponse; struct ProgressItem; -class ProgressTracker : Noncopyable { +class ProgressTracker : public Noncopyable { public: ProgressTracker(); ~ProgressTracker(); diff --git a/WebCore/loader/ResourceLoader.cpp b/WebCore/loader/ResourceLoader.cpp index 4f55981..5ad181b 100644 --- a/WebCore/loader/ResourceLoader.cpp +++ b/WebCore/loader/ResourceLoader.cpp @@ -30,6 +30,7 @@ #include "config.h" #include "ResourceLoader.h" +#include "ApplicationCacheHost.h" #include "DocumentLoader.h" #include "Frame.h" #include "FrameLoader.h" @@ -121,7 +122,7 @@ bool ResourceLoader::load(const ResourceRequest& r) #endif #if ENABLE(OFFLINE_WEB_APPLICATIONS) - if (m_documentLoader->scheduleApplicationCacheLoad(this, clientRequest, r.url())) + if (m_documentLoader->applicationCacheHost()->maybeLoadResource(this, clientRequest, r.url())) return true; #endif @@ -192,17 +193,6 @@ 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 @@ -384,10 +374,8 @@ 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; - } + if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForRedirect(this, request, redirectResponse)) + return; #endif willSendRequest(request, redirectResponse); } @@ -400,10 +388,8 @@ 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; - } + if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForResponse(this, response)) + return; #endif didReceiveResponse(response); } @@ -421,10 +407,8 @@ 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; - } + if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForError(this, error)) + return; #endif didFail(error); } diff --git a/WebCore/loader/ResourceLoader.h b/WebCore/loader/ResourceLoader.h index d3e7b80..5239289 100644 --- a/WebCore/loader/ResourceLoader.h +++ b/WebCore/loader/ResourceLoader.h @@ -40,7 +40,7 @@ namespace WebCore { - class ApplicationCache; + class ApplicationCacheHost; class DocumentLoader; class Frame; class FrameLoader; @@ -119,7 +119,7 @@ namespace WebCore { ResourceLoader(Frame*, bool sendResourceLoadCallbacks, bool shouldContentSniff); #if ENABLE(OFFLINE_WEB_APPLICATIONS) - bool scheduleLoadFallbackResourceFromApplicationCache(ApplicationCache* = 0); + friend class ApplicationCacheHost; // for access to request() #endif virtual void didCancel(const ResourceError&); @@ -133,13 +133,13 @@ namespace WebCore { RefPtr m_handle; RefPtr m_frame; RefPtr m_documentLoader; - ResourceResponse m_response; + ResourceResponse m_response; private: ResourceRequest m_request; RefPtr m_resourceData; - unsigned long m_identifier; + unsigned long m_identifier; bool m_reachedTerminalState; bool m_cancelled; diff --git a/WebCore/loader/TextDocument.cpp b/WebCore/loader/TextDocument.cpp index 0d86c1b..a3d7061 100644 --- a/WebCore/loader/TextDocument.cpp +++ b/WebCore/loader/TextDocument.cpp @@ -162,6 +162,8 @@ void TextTokenizer::write(const SegmentedString& s, bool) void TextTokenizer::finish() { + if (!m_preElement) + write(SegmentedString(), true); // Create document structure for an empty text document. m_preElement = 0; fastFree(m_buffer); m_buffer = 0; diff --git a/WebCore/loader/TextResourceDecoder.cpp b/WebCore/loader/TextResourceDecoder.cpp index ee81326..db68441 100644 --- a/WebCore/loader/TextResourceDecoder.cpp +++ b/WebCore/loader/TextResourceDecoder.cpp @@ -509,11 +509,13 @@ bool TextResourceDecoder::checkForCSSCharset(const char* data, size_t len, bool& static inline void skipComment(const char*& ptr, const char* pEnd) { const char* p = ptr; + if (p == pEnd) + return; // Allow ; other browsers do. if (*p == '>') { p++; } else { - while (p != pEnd) { + while (p + 2 < pEnd) { if (*p == '-') { // This is the real end of comment, "-->". if (p[1] == '-' && p[2] == '>') { @@ -521,7 +523,7 @@ static inline void skipComment(const char*& ptr, const char* pEnd) break; } // This is the incorrect end of comment that other browsers allow, "--!>". - if (p[1] == '-' && p[2] == '!' && p[3] == '>') { + if (p + 3 < pEnd && p[1] == '-' && p[2] == '!' && p[3] == '>') { p += 4; break; } diff --git a/WebCore/loader/ThreadableLoader.cpp b/WebCore/loader/ThreadableLoader.cpp index 7b9c6c6..b174af7 100644 --- a/WebCore/loader/ThreadableLoader.cpp +++ b/WebCore/loader/ThreadableLoader.cpp @@ -40,18 +40,18 @@ namespace WebCore { -PassRefPtr ThreadableLoader::create(ScriptExecutionContext* context, ThreadableLoaderClient* client, const ResourceRequest& request, LoadCallbacks callbacksSetting, ContentSniff contentSniff, StoredCredentials storedCredentials, RedirectOriginCheck redirectOriginCheck) +PassRefPtr ThreadableLoader::create(ScriptExecutionContext* context, ThreadableLoaderClient* client, const ResourceRequest& request, LoadCallbacks callbacksSetting, ContentSniff contentSniff, StoredCredentials storedCredentials, CrossOriginRedirectPolicy crossOriginRedirectPolicy) { ASSERT(client); ASSERT(context); #if ENABLE(WORKERS) if (context->isWorkerContext()) - return WorkerThreadableLoader::create(static_cast(context), client, WorkerRunLoop::defaultMode(), request, callbacksSetting, contentSniff, storedCredentials, redirectOriginCheck); + return WorkerThreadableLoader::create(static_cast(context), client, WorkerRunLoop::defaultMode(), request, callbacksSetting, contentSniff, storedCredentials, crossOriginRedirectPolicy); #endif // ENABLE(WORKERS) ASSERT(context->isDocument()); - return DocumentThreadableLoader::create(static_cast(context), client, request, callbacksSetting, contentSniff, storedCredentials, redirectOriginCheck); + return DocumentThreadableLoader::create(static_cast(context), client, request, callbacksSetting, contentSniff, storedCredentials, crossOriginRedirectPolicy); } void ThreadableLoader::loadResourceSynchronously(ScriptExecutionContext* context, const ResourceRequest& request, ThreadableLoaderClient& client, StoredCredentials storedCredentials) @@ -60,7 +60,7 @@ void ThreadableLoader::loadResourceSynchronously(ScriptExecutionContext* context #if ENABLE(WORKERS) if (context->isWorkerContext()) { - WorkerThreadableLoader::loadResourceSynchronously(static_cast(context), request, client, storedCredentials, RequireSameRedirectOrigin); + WorkerThreadableLoader::loadResourceSynchronously(static_cast(context), request, client, storedCredentials, DenyCrossOriginRedirect); return; } #endif // ENABLE(WORKERS) diff --git a/WebCore/loader/ThreadableLoader.h b/WebCore/loader/ThreadableLoader.h index 0a4c4e3..1ac12cb 100644 --- a/WebCore/loader/ThreadableLoader.h +++ b/WebCore/loader/ThreadableLoader.h @@ -58,17 +58,17 @@ namespace WebCore { DoNotAllowStoredCredentials }; - enum RedirectOriginCheck { - RequireSameRedirectOrigin, - AllowDifferentRedirectOrigin + enum CrossOriginRedirectPolicy { + DenyCrossOriginRedirect, + AllowCrossOriginRedirect }; // Useful for doing loader operations from any thread (not threadsafe, // just able to run on threads other than the main thread). - class ThreadableLoader : Noncopyable { + class ThreadableLoader : public Noncopyable { public: static void loadResourceSynchronously(ScriptExecutionContext*, const ResourceRequest&, ThreadableLoaderClient&, StoredCredentials); - static PassRefPtr create(ScriptExecutionContext*, ThreadableLoaderClient*, const ResourceRequest&, LoadCallbacks, ContentSniff, StoredCredentials, RedirectOriginCheck); + static PassRefPtr create(ScriptExecutionContext*, ThreadableLoaderClient*, const ResourceRequest&, LoadCallbacks, ContentSniff, StoredCredentials, CrossOriginRedirectPolicy); virtual void cancel() = 0; void ref() { refThreadableLoader(); } diff --git a/WebCore/loader/WorkerThreadableLoader.cpp b/WebCore/loader/WorkerThreadableLoader.cpp index 8153ad8..4d12b8d 100644 --- a/WebCore/loader/WorkerThreadableLoader.cpp +++ b/WebCore/loader/WorkerThreadableLoader.cpp @@ -54,10 +54,10 @@ namespace WebCore { static const char loadResourceSynchronouslyMode[] = "loadResourceSynchronouslyMode"; WorkerThreadableLoader::WorkerThreadableLoader(WorkerContext* workerContext, ThreadableLoaderClient* client, const String& taskMode, const ResourceRequest& request, LoadCallbacks callbacksSetting, - ContentSniff contentSniff, StoredCredentials storedCredentials, RedirectOriginCheck redirectOriginCheck) + ContentSniff contentSniff, StoredCredentials storedCredentials, CrossOriginRedirectPolicy crossOriginRedirectPolicy) : m_workerContext(workerContext) , m_workerClientWrapper(ThreadableLoaderClientWrapper::create(client)) - , m_bridge(*(new MainThreadBridge(m_workerClientWrapper, m_workerContext->thread()->workerLoaderProxy(), taskMode, request, callbacksSetting, contentSniff, storedCredentials, redirectOriginCheck))) + , m_bridge(*(new MainThreadBridge(m_workerClientWrapper, m_workerContext->thread()->workerLoaderProxy(), taskMode, request, callbacksSetting, contentSniff, storedCredentials, crossOriginRedirectPolicy))) { } @@ -66,7 +66,7 @@ WorkerThreadableLoader::~WorkerThreadableLoader() m_bridge.destroy(); } -void WorkerThreadableLoader::loadResourceSynchronously(WorkerContext* workerContext, const ResourceRequest& request, ThreadableLoaderClient& client, StoredCredentials storedCredentials, RedirectOriginCheck redirectOriginCheck) +void WorkerThreadableLoader::loadResourceSynchronously(WorkerContext* workerContext, const ResourceRequest& request, ThreadableLoaderClient& client, StoredCredentials storedCredentials, CrossOriginRedirectPolicy crossOriginRedirectPolicy) { WorkerRunLoop& runLoop = workerContext->thread()->runLoop(); @@ -75,7 +75,7 @@ void WorkerThreadableLoader::loadResourceSynchronously(WorkerContext* workerCont mode.append(String::number(runLoop.createUniqueId())); ContentSniff contentSniff = request.url().isLocalFile() ? SniffContent : DoNotSniffContent; - RefPtr loader = WorkerThreadableLoader::create(workerContext, &client, mode, request, DoNotSendLoadCallbacks, contentSniff, storedCredentials, redirectOriginCheck); + RefPtr loader = WorkerThreadableLoader::create(workerContext, &client, mode, request, DoNotSendLoadCallbacks, contentSniff, storedCredentials, crossOriginRedirectPolicy); MessageQueueWaitResult result = MessageQueueMessageReceived; while (!loader->done() && result != MessageQueueTerminated) @@ -92,20 +92,20 @@ void WorkerThreadableLoader::cancel() WorkerThreadableLoader::MainThreadBridge::MainThreadBridge(PassRefPtr workerClientWrapper, WorkerLoaderProxy& loaderProxy, const String& taskMode, const ResourceRequest& request, LoadCallbacks callbacksSetting, ContentSniff contentSniff, StoredCredentials storedCredentials, - RedirectOriginCheck redirectOriginCheck) + CrossOriginRedirectPolicy crossOriginRedirectPolicy) : m_workerClientWrapper(workerClientWrapper) , m_loaderProxy(loaderProxy) , m_taskMode(taskMode.copy()) { ASSERT(m_workerClientWrapper.get()); - m_loaderProxy.postTaskToLoader(createCallbackTask(&MainThreadBridge::mainThreadCreateLoader, this, request, callbacksSetting, contentSniff, storedCredentials, redirectOriginCheck)); + m_loaderProxy.postTaskToLoader(createCallbackTask(&MainThreadBridge::mainThreadCreateLoader, this, request, callbacksSetting, contentSniff, storedCredentials, crossOriginRedirectPolicy)); } WorkerThreadableLoader::MainThreadBridge::~MainThreadBridge() { } -void WorkerThreadableLoader::MainThreadBridge::mainThreadCreateLoader(ScriptExecutionContext* context, MainThreadBridge* thisPtr, auto_ptr requestData, LoadCallbacks callbacksSetting, ContentSniff contentSniff, StoredCredentials storedCredentials, RedirectOriginCheck redirectOriginCheck) +void WorkerThreadableLoader::MainThreadBridge::mainThreadCreateLoader(ScriptExecutionContext* context, MainThreadBridge* thisPtr, auto_ptr requestData, LoadCallbacks callbacksSetting, ContentSniff contentSniff, StoredCredentials storedCredentials, CrossOriginRedirectPolicy crossOriginRedirectPolicy) { ASSERT(isMainThread()); ASSERT(context->isDocument()); @@ -117,7 +117,7 @@ void WorkerThreadableLoader::MainThreadBridge::mainThreadCreateLoader(ScriptExec // FIXME: If the a site requests a local resource, then this will return a non-zero value but the sync path // will return a 0 value. Either this should return 0 or the other code path should do a callback with // a failure. - thisPtr->m_mainThreadLoader = ThreadableLoader::create(context, thisPtr, *request, callbacksSetting, contentSniff, storedCredentials, redirectOriginCheck); + thisPtr->m_mainThreadLoader = ThreadableLoader::create(context, thisPtr, *request, callbacksSetting, contentSniff, storedCredentials, crossOriginRedirectPolicy); ASSERT(thisPtr->m_mainThreadLoader); } diff --git a/WebCore/loader/WorkerThreadableLoader.h b/WebCore/loader/WorkerThreadableLoader.h index a36bedf..8b11b70 100644 --- a/WebCore/loader/WorkerThreadableLoader.h +++ b/WebCore/loader/WorkerThreadableLoader.h @@ -55,10 +55,10 @@ namespace WebCore { class WorkerThreadableLoader : public RefCounted, public ThreadableLoader { public: - static void loadResourceSynchronously(WorkerContext*, const ResourceRequest&, ThreadableLoaderClient&, StoredCredentials, RedirectOriginCheck); - static PassRefPtr create(WorkerContext* workerContext, ThreadableLoaderClient* client, const String& taskMode, const ResourceRequest& request, LoadCallbacks callbacksSetting, ContentSniff contentSniff, StoredCredentials storedCredentials, RedirectOriginCheck redirectOriginCheck) + static void loadResourceSynchronously(WorkerContext*, const ResourceRequest&, ThreadableLoaderClient&, StoredCredentials, CrossOriginRedirectPolicy); + static PassRefPtr create(WorkerContext* workerContext, ThreadableLoaderClient* client, const String& taskMode, const ResourceRequest& request, LoadCallbacks callbacksSetting, ContentSniff contentSniff, StoredCredentials storedCredentials, CrossOriginRedirectPolicy crossOriginRedirectPolicy) { - return adoptRef(new WorkerThreadableLoader(workerContext, client, taskMode, request, callbacksSetting, contentSniff, storedCredentials, redirectOriginCheck)); + return adoptRef(new WorkerThreadableLoader(workerContext, client, taskMode, request, callbacksSetting, contentSniff, storedCredentials, crossOriginRedirectPolicy)); } ~WorkerThreadableLoader(); @@ -97,7 +97,7 @@ namespace WebCore { class MainThreadBridge : ThreadableLoaderClient { public: // All executed on the worker context's thread. - MainThreadBridge(PassRefPtr, WorkerLoaderProxy&, const String& taskMode, const ResourceRequest&, LoadCallbacks, ContentSniff, StoredCredentials, RedirectOriginCheck); + MainThreadBridge(PassRefPtr, WorkerLoaderProxy&, const String& taskMode, const ResourceRequest&, LoadCallbacks, ContentSniff, StoredCredentials, CrossOriginRedirectPolicy); void cancel(); void destroy(); @@ -109,7 +109,7 @@ namespace WebCore { static void mainThreadDestroy(ScriptExecutionContext*, MainThreadBridge*); ~MainThreadBridge(); - static void mainThreadCreateLoader(ScriptExecutionContext*, MainThreadBridge*, std::auto_ptr, LoadCallbacks, ContentSniff, StoredCredentials, RedirectOriginCheck); + static void mainThreadCreateLoader(ScriptExecutionContext*, MainThreadBridge*, std::auto_ptr, LoadCallbacks, ContentSniff, StoredCredentials, CrossOriginRedirectPolicy); static void mainThreadCancel(ScriptExecutionContext*, MainThreadBridge*); virtual void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent); virtual void didReceiveResponse(const ResourceResponse&); @@ -133,7 +133,7 @@ namespace WebCore { String m_taskMode; }; - WorkerThreadableLoader(WorkerContext*, ThreadableLoaderClient*, const String& taskMode, const ResourceRequest&, LoadCallbacks, ContentSniff, StoredCredentials, RedirectOriginCheck); + WorkerThreadableLoader(WorkerContext*, ThreadableLoaderClient*, const String& taskMode, const ResourceRequest&, LoadCallbacks, ContentSniff, StoredCredentials, CrossOriginRedirectPolicy); RefPtr m_workerContext; RefPtr m_workerClientWrapper; diff --git a/WebCore/loader/appcache/ApplicationCache.cpp b/WebCore/loader/appcache/ApplicationCache.cpp index 3c29d68..34dace4 100644 --- a/WebCore/loader/appcache/ApplicationCache.cpp +++ b/WebCore/loader/appcache/ApplicationCache.cpp @@ -82,7 +82,7 @@ void ApplicationCache::addResource(PassRefPtr resource if (m_storageID) { ASSERT(!resource->storageID()); - ASSERT(resource->type() & (ApplicationCacheResource::Dynamic | ApplicationCacheResource::Master)); + ASSERT(resource->type() & ApplicationCacheResource::Master); // Add the resource to the storage. cacheStorage().store(resource.get(), this); @@ -111,6 +111,7 @@ unsigned ApplicationCache::removeResource(const String& url) ApplicationCacheResource* ApplicationCache::resourceForURL(const String& url) { + ASSERT(!KURL(url).hasFragmentIdentifier()); return m_resources.get(url).get(); } @@ -130,34 +131,12 @@ ApplicationCacheResource* ApplicationCache::resourceForRequest(const ResourceReq // We only care about HTTP/HTTPS GET requests. if (!requestIsHTTPOrHTTPSGet(request)) return false; - - return resourceForURL(request.url()); -} -unsigned ApplicationCache::numDynamicEntries() const -{ - // FIXME: Implement - return 0; -} - -String ApplicationCache::dynamicEntry(unsigned) const -{ - // FIXME: Implement - return String(); -} - -bool ApplicationCache::addDynamicEntry(const String& url) -{ - if (!equalIgnoringCase(m_group->manifestURL().protocol(), KURL(url).protocol())) - return false; + KURL url(request.url()); + if (url.hasFragmentIdentifier()) + url.removeFragmentIdentifier(); - // FIXME: Implement (be sure to respect private browsing state). - return true; -} - -void ApplicationCache::removeDynamicEntry(const String&) -{ - // FIXME: Implement (be sure to respect private browsing state). + return resourceForURL(url); } void ApplicationCache::setOnlineWhitelist(const Vector& onlineWhitelist) diff --git a/WebCore/loader/appcache/ApplicationCache.h b/WebCore/loader/appcache/ApplicationCache.h index 4566471..d718cd7 100644 --- a/WebCore/loader/appcache/ApplicationCache.h +++ b/WebCore/loader/appcache/ApplicationCache.h @@ -65,12 +65,6 @@ public: ApplicationCacheResource* resourceForRequest(const ResourceRequest&); ApplicationCacheResource* resourceForURL(const String& url); - unsigned numDynamicEntries() const; - String dynamicEntry(unsigned index) const; - - bool addDynamicEntry(const String& url); - void removeDynamicEntry(const String& url); - void setOnlineWhitelist(const Vector& onlineWhitelist); const Vector& 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. @@ -105,8 +99,10 @@ private: Vector m_onlineWhitelist; FallbackURLVector m_fallbackURLs; - // While an update is in progress, changes in dynamic entries are queued for later execution. - Vector > m_pendingDynamicEntryActions; + // The total size of the resources belonging to this Application Cache instance. + // This is an estimation of the size this Application Cache occupies in the + // database file. + int64_t m_estimatedSizeInStorage; // The total size of the resources belonging to this Application Cache instance. // This is an estimation of the size this Application Cache occupies in the diff --git a/WebCore/loader/appcache/ApplicationCacheGroup.cpp b/WebCore/loader/appcache/ApplicationCacheGroup.cpp index 735e3a3..739118f 100644 --- a/WebCore/loader/appcache/ApplicationCacheGroup.cpp +++ b/WebCore/loader/appcache/ApplicationCacheGroup.cpp @@ -29,6 +29,7 @@ #if ENABLE(OFFLINE_WEB_APPLICATIONS) #include "ApplicationCache.h" +#include "ApplicationCacheHost.h" #include "ApplicationCacheResource.h" #include "ApplicationCacheStorage.h" #include "ChromeClient.h" @@ -85,7 +86,11 @@ ApplicationCache* ApplicationCacheGroup::cacheForMainRequest(const ResourceReque if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request)) return 0; - if (ApplicationCacheGroup* group = cacheStorage().cacheGroupForURL(request.url())) { + KURL url(request.url()); + if (url.hasFragmentIdentifier()) + url.removeFragmentIdentifier(); + + if (ApplicationCacheGroup* group = cacheStorage().cacheGroupForURL(url)) { ASSERT(group->newestCache()); ASSERT(!group->isObsolete()); @@ -100,7 +105,11 @@ ApplicationCache* ApplicationCacheGroup::fallbackCacheForMainRequest(const Resou if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request)) return 0; - if (ApplicationCacheGroup* group = cacheStorage().fallbackCacheGroupForURL(request.url())) { + KURL url(request.url()); + if (url.hasFragmentIdentifier()) + url.removeFragmentIdentifier(); + + if (ApplicationCacheGroup* group = cacheStorage().fallbackCacheGroupForURL(url)) { ASSERT(group->newestCache()); ASSERT(!group->isObsolete()); @@ -110,7 +119,7 @@ ApplicationCache* ApplicationCacheGroup::fallbackCacheForMainRequest(const Resou return 0; } -void ApplicationCacheGroup::selectCache(Frame* frame, const KURL& manifestURL) +void ApplicationCacheGroup::selectCache(Frame* frame, const KURL& passedManifestURL) { ASSERT(frame && frame->page()); @@ -118,14 +127,18 @@ void ApplicationCacheGroup::selectCache(Frame* frame, const KURL& manifestURL) return; DocumentLoader* documentLoader = frame->loader()->documentLoader(); - ASSERT(!documentLoader->applicationCache()); + ASSERT(!documentLoader->applicationCacheHost()->applicationCache()); - if (manifestURL.isNull()) { + if (passedManifestURL.isNull()) { selectCacheWithoutManifestURL(frame); return; } - - ApplicationCache* mainResourceCache = documentLoader->mainResourceApplicationCache(); + + KURL manifestURL(passedManifestURL); + if (manifestURL.hasFragmentIdentifier()) + manifestURL.removeFragmentIdentifier(); + + ApplicationCache* mainResourceCache = documentLoader->applicationCacheHost()->mainResourceApplicationCache(); if (mainResourceCache) { if (manifestURL == mainResourceCache->group()->m_manifestURL) { @@ -133,7 +146,10 @@ void ApplicationCacheGroup::selectCache(Frame* frame, const KURL& manifestURL) mainResourceCache->group()->update(frame, ApplicationCacheUpdateWithBrowsingContext); } else { // The main resource was loaded from cache, so the cache must have an entry for it. Mark it as foreign. - ApplicationCacheResource* resource = mainResourceCache->resourceForURL(documentLoader->url()); + KURL documentURL(documentLoader->url()); + if (documentURL.hasFragmentIdentifier()) + documentURL.removeFragmentIdentifier(); + ApplicationCacheResource* resource = mainResourceCache->resourceForURL(documentURL); bool inStorage = resource->storageID(); resource->addType(ApplicationCacheResource::Foreign); if (inStorage) @@ -160,14 +176,14 @@ void ApplicationCacheGroup::selectCache(Frame* frame, const KURL& manifestURL) // Don't change anything on disk if private browsing is enabled. if (!frame->settings() || frame->settings()->privateBrowsingEnabled()) { - postListenerTask(&DOMApplicationCache::callCheckingListener, documentLoader); - postListenerTask(&DOMApplicationCache::callErrorListener, documentLoader); + postListenerTask(ApplicationCacheHost::CHECKING_EVENT, documentLoader); + postListenerTask(ApplicationCacheHost::ERROR_EVENT, documentLoader); return; } ApplicationCacheGroup* group = cacheStorage().findOrCreateCacheGroup(manifestURL); - documentLoader->setCandidateApplicationCacheGroup(group); + documentLoader->applicationCacheHost()->setCandidateApplicationCacheGroup(group); group->m_pendingMasterResourceLoaders.add(documentLoader); group->m_downloadingPendingMasterResourceLoadersCount++; @@ -181,9 +197,9 @@ void ApplicationCacheGroup::selectCacheWithoutManifestURL(Frame* frame) return; DocumentLoader* documentLoader = frame->loader()->documentLoader(); - ASSERT(!documentLoader->applicationCache()); + ASSERT(!documentLoader->applicationCacheHost()->applicationCache()); - ApplicationCache* mainResourceCache = documentLoader->mainResourceApplicationCache(); + ApplicationCache* mainResourceCache = documentLoader->applicationCacheHost()->mainResourceApplicationCache(); if (mainResourceCache) { mainResourceCache->group()->associateDocumentLoaderWithCache(documentLoader, mainResourceCache); @@ -195,7 +211,9 @@ void ApplicationCacheGroup::finishedLoadingMainResource(DocumentLoader* loader) { ASSERT(m_pendingMasterResourceLoaders.contains(loader)); ASSERT(m_completionType == None || m_pendingEntries.isEmpty()); - const KURL& url = loader->url(); + KURL url = loader->url(); + if (url.hasFragmentIdentifier()) + url.removeFragmentIdentifier(); switch (m_completionType) { case None: @@ -218,9 +236,9 @@ void ApplicationCacheGroup::finishedLoadingMainResource(DocumentLoader* loader) // 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. + loader->applicationCacheHost()->setApplicationCache(0); // Will unset candidate, too. m_associatedDocumentLoaders.remove(loader); - postListenerTask(&DOMApplicationCache::callErrorListener, loader); + postListenerTask(ApplicationCacheHost::ERROR_EVENT, loader); break; case Completed: ASSERT(m_associatedDocumentLoaders.contains(loader)); @@ -254,28 +272,28 @@ void ApplicationCacheGroup::failedLoadingMainResource(DocumentLoader* loader) // 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); + postListenerTask(ApplicationCacheHost::ERROR_EVENT, loader); break; case Failure: // Cache update failed, too. ASSERT(!m_cacheBeingUpdated); // Already cleared out by stopLoading(). - ASSERT(!loader->applicationCache() || loader->applicationCache() == m_cacheBeingUpdated); + ASSERT(!loader->applicationCacheHost()->applicationCache() || loader->applicationCacheHost()->applicationCache() == m_cacheBeingUpdated); - loader->setApplicationCache(0); // Will unset candidate, too. + loader->applicationCacheHost()->setApplicationCache(0); // Will unset candidate, too. m_associatedDocumentLoaders.remove(loader); - postListenerTask(&DOMApplicationCache::callErrorListener, loader); + postListenerTask(ApplicationCacheHost::ERROR_EVENT, 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()); + ASSERT(loader->applicationCacheHost()->applicationCache() == m_cacheBeingUpdated); + ASSERT(!loader->applicationCacheHost()->candidateApplicationCacheGroup()); m_associatedDocumentLoaders.remove(loader); - loader->setApplicationCache(0); + loader->applicationCacheHost()->setApplicationCache(0); - postListenerTask(&DOMApplicationCache::callErrorListener, loader); + postListenerTask(ApplicationCacheHost::ERROR_EVENT, loader); break; } @@ -315,7 +333,7 @@ void ApplicationCacheGroup::disassociateDocumentLoader(DocumentLoader* loader) m_pendingMasterResourceLoaders.remove(loader); - loader->setApplicationCache(0); // Will set candidate to 0, too. + loader->applicationCacheHost()->setApplicationCache(0); // Will set candidate to 0, too. if (!m_associatedDocumentLoaders.isEmpty() || !m_pendingMasterResourceLoaders.isEmpty()) return; @@ -371,9 +389,9 @@ void ApplicationCacheGroup::update(Frame* frame, ApplicationCacheUpdateOption up { if (m_updateStatus == Checking || m_updateStatus == Downloading) { if (updateOption == ApplicationCacheUpdateWithBrowsingContext) { - postListenerTask(&DOMApplicationCache::callCheckingListener, frame->loader()->documentLoader()); + postListenerTask(ApplicationCacheHost::CHECKING_EVENT, frame->loader()->documentLoader()); if (m_updateStatus == Downloading) - postListenerTask(&DOMApplicationCache::callDownloadingListener, frame->loader()->documentLoader()); + postListenerTask(ApplicationCacheHost::DOWNLOADING_EVENT, frame->loader()->documentLoader()); } return; } @@ -383,8 +401,8 @@ void ApplicationCacheGroup::update(Frame* frame, ApplicationCacheUpdateOption up ASSERT(m_pendingMasterResourceLoaders.isEmpty()); ASSERT(m_pendingEntries.isEmpty()); ASSERT(!m_cacheBeingUpdated); - postListenerTask(&DOMApplicationCache::callCheckingListener, frame->loader()->documentLoader()); - postListenerTask(&DOMApplicationCache::callNoUpdateListener, frame->loader()->documentLoader()); + postListenerTask(ApplicationCacheHost::CHECKING_EVENT, frame->loader()->documentLoader()); + postListenerTask(ApplicationCacheHost::NOUPDATE_EVENT, frame->loader()->documentLoader()); return; } @@ -393,10 +411,10 @@ void ApplicationCacheGroup::update(Frame* frame, ApplicationCacheUpdateOption up m_updateStatus = Checking; - postListenerTask(&DOMApplicationCache::callCheckingListener, m_associatedDocumentLoaders); + postListenerTask(ApplicationCacheHost::CHECKING_EVENT, m_associatedDocumentLoaders); if (!m_newestCache) { ASSERT(updateOption == ApplicationCacheUpdateWithBrowsingContext); - postListenerTask(&DOMApplicationCache::callCheckingListener, frame->loader()->documentLoader()); + postListenerTask(ApplicationCacheHost::CHECKING_EVENT, frame->loader()->documentLoader()); } ASSERT(!m_manifestHandle); @@ -436,7 +454,9 @@ void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, const Res ASSERT(handle == m_currentHandle); - const KURL& url = handle->request().url(); + KURL url(handle->request().url()); + if (url.hasFragmentIdentifier()) + url.removeFragmentIdentifier(); ASSERT(!m_currentResource); ASSERT(m_pendingEntries.contains(url)); @@ -448,9 +468,10 @@ void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, const Res ASSERT(!(type & ApplicationCacheResource::Master)); if (m_newestCache && response.httpStatusCode() == 304) { // Not modified. - ApplicationCacheResource* newestCachedResource = m_newestCache->resourceForURL(handle->request().url()); + ApplicationCacheResource* newestCachedResource = m_newestCache->resourceForURL(url); if (newestCachedResource) { m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, newestCachedResource->response(), type, newestCachedResource->data())); + m_pendingEntries.remove(m_currentHandle->request().url()); m_currentHandle->cancel(); m_currentHandle = 0; // Load the next resource, if any. @@ -468,7 +489,7 @@ void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, const Res // Skip this resource. It is dropped from the cache. m_currentHandle->cancel(); m_currentHandle = 0; - m_pendingEntries.remove(handle->request().url()); + m_pendingEntries.remove(url); // Load the next resource, if any. startLoadingEntry(); } else { @@ -478,6 +499,7 @@ void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, const Res ApplicationCacheResource* newestCachedResource = m_newestCache->resourceForURL(handle->request().url()); ASSERT(newestCachedResource); m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, newestCachedResource->response(), type, newestCachedResource->data())); + m_pendingEntries.remove(m_currentHandle->request().url()); m_currentHandle->cancel(); m_currentHandle = 0; // Load the next resource, if any. @@ -531,7 +553,9 @@ void ApplicationCacheGroup::didFail(ResourceHandle* handle, const ResourceError& } unsigned type = m_currentResource ? m_currentResource->type() : m_pendingEntries.get(handle->request().url()); - const KURL& url = handle->request().url(); + KURL url(handle->request().url()); + if (url.hasFragmentIdentifier()) + url.removeFragmentIdentifier(); ASSERT(!m_currentResource || !m_pendingEntries.contains(url)); m_currentResource = 0; @@ -625,7 +649,7 @@ void ApplicationCacheGroup::didFinishLoadingManifest() // We have the manifest, now download the resources. m_updateStatus = Downloading; - postListenerTask(&DOMApplicationCache::callDownloadingListener, m_associatedDocumentLoaders); + postListenerTask(ApplicationCacheHost::DOWNLOADING_EVENT, m_associatedDocumentLoaders); ASSERT(m_pendingEntries.isEmpty()); @@ -633,7 +657,7 @@ void ApplicationCacheGroup::didFinishLoadingManifest() ApplicationCache::ResourceMap::const_iterator end = m_newestCache->end(); for (ApplicationCache::ResourceMap::const_iterator it = m_newestCache->begin(); it != end; ++it) { unsigned type = it->second->type(); - if (type & (ApplicationCacheResource::Master | ApplicationCacheResource::Dynamic)) + if (type & ApplicationCacheResource::Master) addEntry(it->first, type); } } @@ -675,8 +699,8 @@ void ApplicationCacheGroup::manifestNotFound() { makeObsolete(); - postListenerTask(&DOMApplicationCache::callObsoleteListener, m_associatedDocumentLoaders); - postListenerTask(&DOMApplicationCache::callErrorListener, m_pendingMasterResourceLoaders); + postListenerTask(ApplicationCacheHost::OBSOLETE_EVENT, m_associatedDocumentLoaders); + postListenerTask(ApplicationCacheHost::ERROR_EVENT, m_pendingMasterResourceLoaders); stopLoading(); @@ -686,9 +710,9 @@ void ApplicationCacheGroup::manifestNotFound() while (!m_pendingMasterResourceLoaders.isEmpty()) { HashSet::iterator it = m_pendingMasterResourceLoaders.begin(); - ASSERT((*it)->candidateApplicationCacheGroup() == this); - ASSERT(!(*it)->applicationCache()); - (*it)->setCandidateApplicationCacheGroup(0); + ASSERT((*it)->applicationCacheHost()->candidateApplicationCacheGroup() == this); + ASSERT(!(*it)->applicationCacheHost()->applicationCache()); + (*it)->applicationCacheHost()->setCandidateApplicationCacheGroup(0); m_pendingMasterResourceLoaders.remove(it); } @@ -724,11 +748,11 @@ void ApplicationCacheGroup::checkIfLoadIsComplete() if (!m_storageID) cacheStorage().storeNewestCache(this); - postListenerTask(&DOMApplicationCache::callNoUpdateListener, m_associatedDocumentLoaders); + postListenerTask(ApplicationCacheHost::NOUPDATE_EVENT, m_associatedDocumentLoaders); break; case Failure: ASSERT(!m_cacheBeingUpdated); - postListenerTask(&DOMApplicationCache::callErrorListener, m_associatedDocumentLoaders); + postListenerTask(ApplicationCacheHost::ERROR_EVENT, m_associatedDocumentLoaders); if (m_caches.isEmpty()) { ASSERT(m_associatedDocumentLoaders.isEmpty()); delete this; @@ -752,6 +776,7 @@ void ApplicationCacheGroup::checkIfLoadIsComplete() RefPtr oldNewestCache = (m_newestCache == m_cacheBeingUpdated) ? 0 : m_newestCache; setNewestCache(m_cacheBeingUpdated.release()); +#ifdef MANUAL_MERGE_REQUIRED if (cacheStorage().storeNewestCache(this)) { // New cache stored, now remove the old cache. if (oldNewestCache) @@ -796,6 +821,55 @@ void ApplicationCacheGroup::checkIfLoadIsComplete() } } } +#else // MANUAL_MERGE_REQUIRED + if (cacheStorage().storeNewestCache(this)) { + // New cache stored, now remove the old cache. + if (oldNewestCache) + cacheStorage().remove(oldNewestCache.get()); + // Fire the success events. + postListenerTask(isUpgradeAttempt ? ApplicationCacheHost::UPDATEREADY_EVENT : ApplicationCacheHost::CACHED_EVENT, m_associatedDocumentLoaders); + } else { + if (cacheStorage().isMaximumSizeReached() && !m_calledReachedMaxAppCacheSize) { + // We ran out of space. All the changes in the cache storage have + // been rolled back. We roll back to the previous state in here, + // as well, call the chrome client asynchronously and retry to + // save the new cache. + + // Save a reference to the new cache. + m_cacheBeingUpdated = m_newestCache.release(); + if (oldNewestCache) { + // Reinstate the oldNewestCache. + setNewestCache(oldNewestCache.release()); + } + scheduleReachedMaxAppCacheSizeCallback(); + return; + } else { + // Run the "cache failure steps" + // Fire the error events to all pending master entries, as well any other cache hosts + // currently associated with a cache in this group. + postListenerTask(ApplicationCacheHost::ERROR_EVENT, m_associatedDocumentLoaders); + // Disassociate the pending master entries from the failed new cache. Note that + // all other loaders in the m_associatedDocumentLoaders are still associated with + // some other cache in this group. They are not associated with the failed new cache. + + // Need to copy loaders, because the cache group may be destroyed at the end of iteration. + Vector loaders; + copyToVector(m_pendingMasterResourceLoaders, loaders); + size_t count = loaders.size(); + for (size_t i = 0; i != count; ++i) + disassociateDocumentLoader(loaders[i]); // This can delete this group. + + // Reinstate the oldNewestCache, if there was one. + if (oldNewestCache) { + // This will discard the failed new cache. + setNewestCache(oldNewestCache.release()); + } else { + // We must have been deleted by the last call to disassociateDocumentLoader(). + return; + } + } + } +#endif // MANUAL_MERGE_REQUIRED break; } } @@ -820,7 +894,7 @@ void ApplicationCacheGroup::startLoadingEntry() EntryMap::const_iterator it = m_pendingEntries.begin(); - postListenerTask(&DOMApplicationCache::callProgressListener, m_associatedDocumentLoaders); + postListenerTask(ApplicationCacheHost::PROGRESS_EVENT, m_associatedDocumentLoaders); ASSERT(!m_currentHandle); @@ -851,6 +925,7 @@ void ApplicationCacheGroup::deliverDelayedMainResources() void ApplicationCacheGroup::addEntry(const String& url, unsigned type) { ASSERT(m_cacheBeingUpdated); + ASSERT(!KURL(url).hasFragmentIdentifier()); // Don't add the URL if we already have an master resource in the cache // (i.e., the main resource finished loading before the manifest). @@ -883,7 +958,7 @@ void ApplicationCacheGroup::associateDocumentLoaderWithCache(DocumentLoader* loa ASSERT(!m_isObsolete); - loader->setApplicationCache(cache); + loader->applicationCacheHost()->setApplicationCache(cache); ASSERT(!m_associatedDocumentLoaders.contains(loader)); m_associatedDocumentLoaders.add(loader); @@ -917,39 +992,44 @@ void ApplicationCacheGroup::scheduleReachedMaxAppCacheSizeCallback() } class CallCacheListenerTask : public ScriptExecutionContext::Task { - typedef void (DOMApplicationCache::*ListenerFunction)(); public: - static PassRefPtr create(ListenerFunction listenerFunction) + static PassRefPtr create(PassRefPtr loader, ApplicationCacheHost::EventID eventID) { - return adoptRef(new CallCacheListenerTask(listenerFunction)); + return adoptRef(new CallCacheListenerTask(loader, eventID)); } virtual void performTask(ScriptExecutionContext* context) { - ASSERT(context->isDocument()); - if (DOMWindow* window = static_cast(context)->domWindow()) { - if (DOMApplicationCache* domCache = window->optionalApplicationCache()) - (domCache->*m_listenerFunction)(); - } + + ASSERT_UNUSED(context, context->isDocument()); + Frame* frame = m_documentLoader->frame(); + if (!frame) + return; + + ASSERT(frame->loader()->documentLoader() == m_documentLoader.get()); + + m_documentLoader->applicationCacheHost()->notifyEventListener(m_eventID); } private: - CallCacheListenerTask(ListenerFunction listenerFunction) - : m_listenerFunction(listenerFunction) + CallCacheListenerTask(PassRefPtr loader, ApplicationCacheHost::EventID eventID) + : m_documentLoader(loader) + , m_eventID(eventID) { } - ListenerFunction m_listenerFunction; + RefPtr m_documentLoader; + ApplicationCacheHost::EventID m_eventID; }; -void ApplicationCacheGroup::postListenerTask(ListenerFunction listenerFunction, const HashSet& loaderSet) +void ApplicationCacheGroup::postListenerTask(ApplicationCacheHost::EventID eventID, const HashSet& loaderSet) { HashSet::const_iterator loaderSetEnd = loaderSet.end(); for (HashSet::const_iterator iter = loaderSet.begin(); iter != loaderSetEnd; ++iter) - postListenerTask(listenerFunction, *iter); + postListenerTask(eventID, *iter); } -void ApplicationCacheGroup::postListenerTask(ListenerFunction listenerFunction, DocumentLoader* loader) +void ApplicationCacheGroup::postListenerTask(ApplicationCacheHost::EventID eventID, DocumentLoader* loader) { Frame* frame = loader->frame(); if (!frame) @@ -957,7 +1037,7 @@ void ApplicationCacheGroup::postListenerTask(ListenerFunction listenerFunction, ASSERT(frame->loader()->documentLoader() == loader); - frame->document()->postTask(CallCacheListenerTask::create(listenerFunction)); + frame->document()->postTask(CallCacheListenerTask::create(loader, eventID)); } void ApplicationCacheGroup::clearStorageID() diff --git a/WebCore/loader/appcache/ApplicationCacheGroup.h b/WebCore/loader/appcache/ApplicationCacheGroup.h index 281dadf..7fa8f33 100644 --- a/WebCore/loader/appcache/ApplicationCacheGroup.h +++ b/WebCore/loader/appcache/ApplicationCacheGroup.h @@ -32,6 +32,7 @@ #include #include +#include "DOMApplicationCache.h" #include "KURL.h" #include "PlatformString.h" #include "ResourceHandle.h" @@ -42,7 +43,6 @@ namespace WebCore { class ApplicationCache; class ApplicationCacheResource; -class DOMApplicationCache; class Document; class DocumentLoader; class Frame; @@ -52,7 +52,7 @@ enum ApplicationCacheUpdateOption { ApplicationCacheUpdateWithoutBrowsingContext }; -class ApplicationCacheGroup : Noncopyable, ResourceHandleClient { +class ApplicationCacheGroup : public Noncopyable, ResourceHandleClient { public: ApplicationCacheGroup(const KURL& manifestURL, bool isCopy = false); ~ApplicationCacheGroup(); @@ -91,11 +91,17 @@ public: bool isCopy() const { return m_isCopy; } private: +#ifdef MANUAL_MERGE_REQUIRED typedef void (DOMApplicationCache::*ListenerFunction)(); static void postListenerTask(ListenerFunction, const HashSet&); static void postListenerTask(ListenerFunction, const Vector >& loaders); static void postListenerTask(ListenerFunction, DocumentLoader*); void scheduleReachedMaxAppCacheSizeCallback(); +#else // MANUAL_MERGE_REQUIRED + static void postListenerTask(ApplicationCacheHost::EventID, const HashSet&); + static void postListenerTask(ApplicationCacheHost::EventID, DocumentLoader*); + void scheduleReachedMaxAppCacheSizeCallback(); +#endif // MANUAL_MERGE_REQUIRED PassRefPtr createResourceHandle(const KURL&, ApplicationCacheResource* newestCachedResource); diff --git a/WebCore/loader/appcache/ApplicationCacheHost.cpp b/WebCore/loader/appcache/ApplicationCacheHost.cpp new file mode 100644 index 0000000..b0c9e74 --- /dev/null +++ b/WebCore/loader/appcache/ApplicationCacheHost.cpp @@ -0,0 +1,381 @@ +/* + * 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 + * 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. 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 "ApplicationCacheHost.h" + +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + +#include "ApplicationCache.h" +#include "ApplicationCacheGroup.h" +#include "ApplicationCacheResource.h" +#include "DocumentLoader.h" +#include "DOMApplicationCache.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameLoaderClient.h" +#include "MainResourceLoader.h" +#include "ResourceLoader.h" +#include "ResourceRequest.h" +#include "Settings.h" + +namespace WebCore { + +ApplicationCacheHost::ApplicationCacheHost(DocumentLoader* documentLoader) + : m_domApplicationCache(0) + , m_documentLoader(documentLoader) + , m_candidateApplicationCacheGroup(0) +{ + ASSERT(m_documentLoader); +} + +ApplicationCacheHost::~ApplicationCacheHost() +{ + if (m_applicationCache) + m_applicationCache->group()->disassociateDocumentLoader(m_documentLoader); + else if (m_candidateApplicationCacheGroup) + m_candidateApplicationCacheGroup->disassociateDocumentLoader(m_documentLoader); +} + +void ApplicationCacheHost::selectCacheWithoutManifest() +{ + ApplicationCacheGroup::selectCacheWithoutManifestURL(m_documentLoader->frame()); +} + +void ApplicationCacheHost::selectCacheWithManifest(const KURL& manifestURL) +{ + ApplicationCacheGroup::selectCache(m_documentLoader->frame(), manifestURL); +} + +void ApplicationCacheHost::maybeLoadMainResource(ResourceRequest& request, SubstituteData& substituteData) +{ + // Check if this request should be loaded from the application cache + if (!substituteData.isValid() && isApplicationCacheEnabled()) { + ASSERT(!m_mainResourceApplicationCache); + + m_mainResourceApplicationCache = ApplicationCacheGroup::cacheForMainRequest(request, m_documentLoader); + + if (m_mainResourceApplicationCache) { + // Get the resource from the application cache. By definition, cacheForMainRequest() returns a cache that contains the resource. + ApplicationCacheResource* resource = m_mainResourceApplicationCache->resourceForRequest(request); + substituteData = SubstituteData(resource->data(), + resource->response().mimeType(), + resource->response().textEncodingName(), KURL()); + } + } +} + +bool ApplicationCacheHost::maybeLoadFallbackForMainResponse(const ResourceRequest& request, const ResourceResponse& r) +{ + if (r.httpStatusCode() / 100 == 4 || r.httpStatusCode() / 100 == 5) { + ASSERT(!m_mainResourceApplicationCache); + if (isApplicationCacheEnabled()) { + m_mainResourceApplicationCache = ApplicationCacheGroup::fallbackCacheForMainRequest(request, documentLoader()); + + if (scheduleLoadFallbackResourceFromApplicationCache(documentLoader()->mainResourceLoader(), m_mainResourceApplicationCache.get())) + return true; + } + } + return false; +} + +bool ApplicationCacheHost::maybeLoadFallbackForMainError(const ResourceRequest& request, const ResourceError& error) +{ + if (!error.isCancellation()) { + ASSERT(!m_mainResourceApplicationCache); + if (isApplicationCacheEnabled()) { + m_mainResourceApplicationCache = ApplicationCacheGroup::fallbackCacheForMainRequest(request, m_documentLoader); + + if (scheduleLoadFallbackResourceFromApplicationCache(documentLoader()->mainResourceLoader(), m_mainResourceApplicationCache.get())) + return true; + } + } + return false; +} + +void ApplicationCacheHost::mainResourceDataReceived(const char*, int, long long, bool) +{ + // This method is here to facilitate alternate implemetations of this interface by the host browser. +} + +void ApplicationCacheHost::failedLoadingMainResource() +{ + ApplicationCacheGroup* group = m_candidateApplicationCacheGroup; + if (!group && m_applicationCache) { + ASSERT(!mainResourceApplicationCache()); // If the main resource were loaded from a cache, it wouldn't fail. + group = m_applicationCache->group(); + } + + if (group) + group->failedLoadingMainResource(m_documentLoader); +} + +void ApplicationCacheHost::finishedLoadingMainResource() +{ + ApplicationCacheGroup* group = candidateApplicationCacheGroup(); + if (!group && applicationCache() && !mainResourceApplicationCache()) + group = applicationCache()->group(); + + if (group) + group->finishedLoadingMainResource(m_documentLoader); +} + +bool ApplicationCacheHost::maybeLoadResource(ResourceLoader* loader, ResourceRequest& request, const KURL& originalURL) +{ + if (!isApplicationCacheEnabled()) + return false; + + if (request.url() != originalURL) + return false; + + ApplicationCacheResource* resource; + if (!shouldLoadResourceFromApplicationCache(request, resource)) + return false; + + m_documentLoader->m_pendingSubstituteResources.set(loader, resource); + m_documentLoader->deliverSubstituteResourcesAfterDelay(); + + return true; +} + +bool ApplicationCacheHost::maybeLoadFallbackForRedirect(ResourceLoader* resourceLoader, ResourceRequest& request, const ResourceResponse& redirectResponse) +{ + if (!redirectResponse.isNull() && !protocolHostAndPortAreEqual(request.url(), redirectResponse.url())) + if (scheduleLoadFallbackResourceFromApplicationCache(resourceLoader)) + return true; + return false; +} + +bool ApplicationCacheHost::maybeLoadFallbackForResponse(ResourceLoader* resourceLoader, const ResourceResponse& response) +{ + if (response.httpStatusCode() / 100 == 4 || response.httpStatusCode() / 100 == 5) + if (scheduleLoadFallbackResourceFromApplicationCache(resourceLoader)) + return true; + return false; +} + +bool ApplicationCacheHost::maybeLoadFallbackForError(ResourceLoader* resourceLoader, const ResourceError& error) +{ + if (!error.isCancellation()) + if (scheduleLoadFallbackResourceFromApplicationCache(resourceLoader)) + return true; + return false; +} + +bool ApplicationCacheHost::maybeLoadSynchronously(ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector& data) +{ + ApplicationCacheResource* resource; + if (shouldLoadResourceFromApplicationCache(request, resource)) { + if (resource) { + response = resource->response(); + data.append(resource->data()->data(), resource->data()->size()); + } else { + error = documentLoader()->frameLoader()->client()->cannotShowURLError(request); + } + return true; + } + return false; +} + +void ApplicationCacheHost::maybeLoadFallbackSynchronously(const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector& data) +{ + // 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(request.url(), response.url())) { + ApplicationCacheResource* resource; + if (getApplicationCacheFallbackResource(request, resource)) { + response = resource->response(); + data.clear(); + data.append(resource->data()->data(), resource->data()->size()); + } + } +} + +bool ApplicationCacheHost::canCacheInPageCache() const +{ + return !applicationCache() && !candidateApplicationCacheGroup(); +} + +void ApplicationCacheHost::setDOMApplicationCache(DOMApplicationCache* domApplicationCache) +{ + ASSERT(!m_domApplicationCache || !domApplicationCache); + m_domApplicationCache = domApplicationCache; +} + +void ApplicationCacheHost::notifyEventListener(EventID id) +{ + if (m_domApplicationCache) + m_domApplicationCache->callEventListener(id); +} + +void ApplicationCacheHost::setCandidateApplicationCacheGroup(ApplicationCacheGroup* group) +{ + ASSERT(!m_applicationCache); + m_candidateApplicationCacheGroup = group; +} + +void ApplicationCacheHost::setApplicationCache(PassRefPtr applicationCache) +{ + if (m_candidateApplicationCacheGroup) { + ASSERT(!m_applicationCache); + m_candidateApplicationCacheGroup = 0; + } + + m_applicationCache = applicationCache; +} + +bool ApplicationCacheHost::shouldLoadResourceFromApplicationCache(const ResourceRequest& request, ApplicationCacheResource*& resource) +{ + 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 the resource's URL is an master entry, the manifest, an explicit entry, or a fallback entry + // in the application cache, then get the resource from the cache (instead of fetching it). + resource = cache->resourceForURL(request.url()); + + // Resources that match fallback namespaces or online whitelist entries are fetched from the network, + // unless they are also cached. + if (!resource && (cache->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 ApplicationCacheHost::getApplicationCacheFallbackResource(const ResourceRequest& request, ApplicationCacheResource*& resource, ApplicationCache* cache) +{ + if (!cache) { + cache = applicationCache(); + if (!cache) + return false; + } + if (!cache->isComplete()) + return false; + + // 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; +} + +bool ApplicationCacheHost::scheduleLoadFallbackResourceFromApplicationCache(ResourceLoader* loader, ApplicationCache* cache) +{ + if (!isApplicationCacheEnabled()) + return false; + + ApplicationCacheResource* resource; + if (!getApplicationCacheFallbackResource(loader->request(), resource, cache)) + return false; + + m_documentLoader->m_pendingSubstituteResources.set(loader, resource); + m_documentLoader->deliverSubstituteResourcesAfterDelay(); + + loader->handle()->cancel(); + + return true; +} + +ApplicationCacheHost::Status ApplicationCacheHost::status() const +{ + ApplicationCache* cache = applicationCache(); + if (!cache) + return UNCACHED; + + switch (cache->group()->updateStatus()) { + case ApplicationCacheGroup::Checking: + return CHECKING; + case ApplicationCacheGroup::Downloading: + return DOWNLOADING; + case ApplicationCacheGroup::Idle: { + if (cache->group()->isObsolete()) + return OBSOLETE; + if (cache != cache->group()->newestCache()) + return UPDATEREADY; + return IDLE; + } + } + + ASSERT_NOT_REACHED(); + return UNCACHED; +} + +bool ApplicationCacheHost::update() +{ + ApplicationCache* cache = applicationCache(); + if (!cache) + return false; + cache->group()->update(m_documentLoader->frame(), ApplicationCacheUpdateWithoutBrowsingContext); + return true; +} + +bool ApplicationCacheHost::swapCache() +{ + ApplicationCache* cache = applicationCache(); + if (!cache) + return false; + + // If the group of application caches to which cache belongs has the lifecycle status obsolete, unassociate document from cache. + if (cache->group()->isObsolete()) { + cache->group()->disassociateDocumentLoader(m_documentLoader); + return true; + } + + // If there is no newer cache, raise an INVALID_STATE_ERR exception. + ApplicationCache* newestCache = cache->group()->newestCache(); + if (cache == newestCache) + return false; + + ASSERT(cache->group() == newestCache->group()); + setApplicationCache(newestCache); + + return true; +} + +bool ApplicationCacheHost::isApplicationCacheEnabled() +{ + return m_documentLoader->frame()->settings() + && m_documentLoader->frame()->settings()->offlineWebApplicationCacheEnabled(); +} + +} // namespace WebCore + +#endif // ENABLE(OFFLINE_WEB_APPLICATIONS) diff --git a/WebCore/loader/appcache/ApplicationCacheHost.h b/WebCore/loader/appcache/ApplicationCacheHost.h new file mode 100644 index 0000000..cb68862 --- /dev/null +++ b/WebCore/loader/appcache/ApplicationCacheHost.h @@ -0,0 +1,152 @@ +/* + * 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 ApplicationCacheHost_h +#define ApplicationCacheHost_h + +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + +#include +#include +#include +#include + +namespace WebCore { + + class DOMApplicationCache; + class DocumentLoader; + class KURL; + class ResourceLoader; + class ResourceError; + struct ResourceRequest; + class ResourceResponse; + class SubstituteData; +#if PLATFORM(CHROMIUM) + class ApplicationCacheHostInternal; +#else + class ApplicationCache; + class ApplicationCacheGroup; + class ApplicationCacheResource; + class ApplicationCacheStorage; +#endif + + class ApplicationCacheHost { + public: + // The Status numeric values are specified in the HTML5 spec. + enum Status { + UNCACHED = 0, + IDLE = 1, + CHECKING = 2, + DOWNLOADING = 3, + UPDATEREADY = 4, + OBSOLETE = 5 + }; + + enum EventID { + CHECKING_EVENT = 0, + ERROR_EVENT, + NOUPDATE_EVENT, + DOWNLOADING_EVENT, + PROGRESS_EVENT, + UPDATEREADY_EVENT, + CACHED_EVENT, + OBSOLETE_EVENT // Must remain the last value, this is used to size arrays. + }; + + ApplicationCacheHost(DocumentLoader*); + ~ApplicationCacheHost(); + + void selectCacheWithoutManifest(); + void selectCacheWithManifest(const KURL& manifestURL); + + void maybeLoadMainResource(ResourceRequest&, SubstituteData&); + bool maybeLoadFallbackForMainResponse(const ResourceRequest&, const ResourceResponse&); + bool maybeLoadFallbackForMainError(const ResourceRequest&, const ResourceError&); + void mainResourceDataReceived(const char* data, int length, long long lengthReceived, bool allAtOnce); + void finishedLoadingMainResource(); + void failedLoadingMainResource(); + + bool maybeLoadResource(ResourceLoader*, ResourceRequest&, const KURL& originalURL); + bool maybeLoadFallbackForRedirect(ResourceLoader*, ResourceRequest&, const ResourceResponse&); + bool maybeLoadFallbackForResponse(ResourceLoader*, const ResourceResponse&); + bool maybeLoadFallbackForError(ResourceLoader*, const ResourceError&); + + bool maybeLoadSynchronously(ResourceRequest&, ResourceError&, ResourceResponse&, Vector& data); + void maybeLoadFallbackSynchronously(const ResourceRequest&, ResourceError&, ResourceResponse&, Vector& data); + + bool canCacheInPageCache() const; + + Status status() const; + bool update(); + bool swapCache(); + + void setDOMApplicationCache(DOMApplicationCache* domApplicationCache); + void notifyEventListener(EventID id); + + private: + bool isApplicationCacheEnabled(); + DocumentLoader* documentLoader() { return m_documentLoader; } + + DOMApplicationCache* m_domApplicationCache; + DocumentLoader* m_documentLoader; + +#if PLATFORM(CHROMIUM) + friend class ApplicationCacheHostInternal; + OwnPtr m_internal; +#else + friend class ApplicationCacheGroup; + friend class ApplicationCacheStorage; + + bool scheduleLoadFallbackResourceFromApplicationCache(ResourceLoader*, 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() const { return m_applicationCache.get(); } + ApplicationCache* mainResourceApplicationCache() const { return m_mainResourceApplicationCache.get(); } + + + // The application cache that the document loader is associated with (if any). + RefPtr m_applicationCache; + + // Before an application cache has finished loading, this will be the candidate application + // group that the document loader is associated with. + ApplicationCacheGroup* m_candidateApplicationCacheGroup; + + // This is the application cache the main resource was loaded from (if any). + RefPtr m_mainResourceApplicationCache; +#endif + }; + +} // namespace WebCore + +#endif // ENABLE(OFFLINE_WEB_APPLICATIONS) +#endif // ApplicationCacheHost_h diff --git a/WebCore/loader/appcache/ApplicationCacheResource.cpp b/WebCore/loader/appcache/ApplicationCacheResource.cpp index 90e65ad..03c5c83 100644 --- a/WebCore/loader/appcache/ApplicationCacheResource.cpp +++ b/WebCore/loader/appcache/ApplicationCacheResource.cpp @@ -80,8 +80,6 @@ void ApplicationCacheResource::dumpType(unsigned type) printf("foreign "); if (type & Fallback) printf("fallback "); - if (type & Dynamic) - printf("dynamic "); printf("\n"); } diff --git a/WebCore/loader/appcache/ApplicationCacheResource.h b/WebCore/loader/appcache/ApplicationCacheResource.h index 53fdd1d..2ca7846 100644 --- a/WebCore/loader/appcache/ApplicationCacheResource.h +++ b/WebCore/loader/appcache/ApplicationCacheResource.h @@ -39,12 +39,12 @@ public: Manifest = 1 << 1, Explicit = 1 << 2, Foreign = 1 << 3, - Fallback = 1 << 4, - Dynamic = 1 << 5 + Fallback = 1 << 4 }; static PassRefPtr create(const KURL& url, const ResourceResponse& response, unsigned type, PassRefPtr buffer = SharedBuffer::create()) { + ASSERT(!url.hasFragmentIdentifier()); return adoptRef(new ApplicationCacheResource(url, response, type, buffer)); } diff --git a/WebCore/loader/appcache/ApplicationCacheStorage.cpp b/WebCore/loader/appcache/ApplicationCacheStorage.cpp index a1dad15..e081f5d 100644 --- a/WebCore/loader/appcache/ApplicationCacheStorage.cpp +++ b/WebCore/loader/appcache/ApplicationCacheStorage.cpp @@ -29,6 +29,7 @@ #if ENABLE(OFFLINE_WEB_APPLICATIONS) #include "ApplicationCache.h" +#include "ApplicationCacheHost.h" #include "ApplicationCacheGroup.h" #include "ApplicationCacheResource.h" #include "CString.h" @@ -127,11 +128,12 @@ ApplicationCacheGroup* ApplicationCacheStorage::loadCacheGroup(const KURL& manif ApplicationCacheGroup* ApplicationCacheStorage::findOrCreateCacheGroup(const KURL& manifestURL) { + ASSERT(!manifestURL.hasFragmentIdentifier()); + std::pair result = m_cachesInMemory.add(manifestURL, 0); if (!result.second) { ASSERT(result.first->second); - return result.first->second; } @@ -176,6 +178,8 @@ void ApplicationCacheStorage::loadManifestHostHashes() ApplicationCacheGroup* ApplicationCacheStorage::cacheGroupForURL(const KURL& url) { + ASSERT(!url.hasFragmentIdentifier()); + loadManifestHostHashes(); // Hash the host name and see if there's a manifest with the same host. @@ -251,6 +255,8 @@ ApplicationCacheGroup* ApplicationCacheStorage::cacheGroupForURL(const KURL& url ApplicationCacheGroup* ApplicationCacheStorage::fallbackCacheGroupForURL(const KURL& url) { + ASSERT(!url.hasFragmentIdentifier()); + // Check if an appropriate cache already exists in memory. CacheGroupMap::const_iterator end = m_cachesInMemory.end(); for (CacheGroupMap::const_iterator it = m_cachesInMemory.begin(); it != end; ++it) { @@ -356,6 +362,7 @@ const String& ApplicationCacheStorage::cacheDirectory() const return m_cacheDirectory; } +#ifdef MANUAL_MERGE_REQUIRED void ApplicationCacheStorage::setMaximumSize(int64_t size) { m_maximumSize = size; @@ -406,6 +413,60 @@ int64_t ApplicationCacheStorage::spaceNeeded(int64_t cacheToSave) ASSERT(spaceNeeded); return spaceNeeded; } +#else // MANUAL_MERGE_REQUIRED +void ApplicationCacheStorage::setMaximumSize(int64_t size) +{ + m_maximumSize = size; +} + +int64_t ApplicationCacheStorage::maximumSize() const +{ + return m_maximumSize; +} + +bool ApplicationCacheStorage::isMaximumSizeReached() const +{ + return m_isMaximumSizeReached; +} + +int64_t ApplicationCacheStorage::spaceNeeded(int64_t cacheToSave) +{ + int64_t spaceNeeded = 0; + long long fileSize = 0; + if (!getFileSize(m_cacheFile, fileSize)) + return 0; + + int64_t currentSize = fileSize; + + // Determine the amount of free space we have available. + int64_t totalAvailableSize = 0; + if (m_maximumSize < currentSize) { + // The max size is smaller than the actual size of the app cache file. + // This can happen if the client previously imposed a larger max size + // value and the app cache file has already grown beyond the current + // max size value. + // The amount of free space is just the amount of free space inside + // the database file. Note that this is always 0 if SQLite is compiled + // with AUTO_VACUUM = 1. + totalAvailableSize = m_database.freeSpaceSize(); + } else { + // The max size is the same or larger than the current size. + // The amount of free space available is the amount of free space + // inside the database file plus the amount we can grow until we hit + // the max size. + totalAvailableSize = (m_maximumSize - currentSize) + m_database.freeSpaceSize(); + } + + // The space needed to be freed in order to accomodate the failed cache is + // the size of the failed cache minus any already available free space. + spaceNeeded = cacheToSave - totalAvailableSize; + // The space needed value must be positive (or else the total already + // available free space would be larger than the size of the failed cache and + // saving of the cache should have never failed). + ASSERT(spaceNeeded); + return spaceNeeded; +} +#endif // MANUAL_MERGE_REQUIRED bool ApplicationCacheStorage::executeSQLCommand(const String& sql) { @@ -674,9 +735,6 @@ bool ApplicationCacheStorage::storeUpdatedType(ApplicationCacheResource* resourc 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) @@ -933,8 +991,12 @@ void ApplicationCacheStorage::empty() it->second->clearStorageID(); } -bool ApplicationCacheStorage::storeCopyOfCache(const String& cacheDirectory, ApplicationCache* cache) +bool ApplicationCacheStorage::storeCopyOfCache(const String& cacheDirectory, ApplicationCacheHost* cacheHost) { + ApplicationCache* cache = cacheHost->applicationCache(); + if (!cache) + return true; + // Create a new cache. RefPtr cacheCopy = ApplicationCache::create(); @@ -964,6 +1026,118 @@ bool ApplicationCacheStorage::storeCopyOfCache(const String& cacheDirectory, App return copyStorage.storeNewestCache(groupCopy.get()); } +#ifdef MANUAL_MERGE_REQUIRED + +bool ApplicationCacheStorage::manifestURLs(Vector* urls) +{ + ASSERT(urls); + openDatabase(false); + if (!m_database.isOpen()) + return false; + + SQLiteStatement selectURLs(m_database, "SELECT manifestURL FROM CacheGroups"); + + if (selectURLs.prepare() != SQLResultOk) + return false; + + while (selectURLs.step() == SQLResultRow) + urls->append(selectURLs.getColumnText(0)); + + return true; +} + +bool ApplicationCacheStorage::cacheGroupSize(const String& manifestURL, int64_t* size) +{ + ASSERT(size); + openDatabase(false); + if (!m_database.isOpen()) + return false; + + SQLiteStatement statement(m_database, "SELECT sum(Caches.size) FROM Caches INNER JOIN CacheGroups ON Caches.cacheGroup=CacheGroups.id WHERE CacheGroups.manifestURL=?"); + if (statement.prepare() != SQLResultOk) + return false; + + statement.bindText(1, manifestURL); + + int result = statement.step(); + if (result == SQLResultDone) + return false; + + if (result != SQLResultRow) { + LOG_ERROR("Could not get the size of the cache group, error \"%s\"", m_database.lastErrorMsg()); + return false; + } + + *size = statement.getColumnInt64(0); + return true; +} + +bool ApplicationCacheStorage::deleteCacheGroup(const String& manifestURL) +{ + SQLiteTransaction deleteTransaction(m_database); + // Check to see if the group is in memory. + ApplicationCacheGroup* group = m_cachesInMemory.get(manifestURL); + if (group) + cacheGroupMadeObsolete(group); + else { + // The cache group is not in memory, so remove it from the disk. + openDatabase(false); + if (!m_database.isOpen()) + return false; + + SQLiteStatement idStatement(m_database, "SELECT id FROM CacheGroups WHERE manifestURL=?"); + if (idStatement.prepare() != SQLResultOk) + return false; + + idStatement.bindText(1, manifestURL); + + int result = idStatement.step(); + if (result == SQLResultDone) + return false; + + if (result != SQLResultRow) { + LOG_ERROR("Could not load cache group id, error \"%s\"", m_database.lastErrorMsg()); + return false; + } + + int64_t groupId = idStatement.getColumnInt64(0); + + SQLiteStatement cacheStatement(m_database, "DELETE FROM Caches WHERE cacheGroup=?"); + if (cacheStatement.prepare() != SQLResultOk) + return false; + + SQLiteStatement groupStatement(m_database, "DELETE FROM CacheGroups WHERE id=?"); + if (groupStatement.prepare() != SQLResultOk) + return false; + + cacheStatement.bindInt64(1, groupId); + executeStatement(cacheStatement); + groupStatement.bindInt64(1, groupId); + executeStatement(groupStatement); + } + + deleteTransaction.commit(); + return true; +} + +void ApplicationCacheStorage::vacuumDatabaseFile() +{ + m_database.runVacuumCommand(); +} + +void ApplicationCacheStorage::checkForMaxSizeReached() +{ + if (m_database.lastError() == SQLResultFull) + m_isMaximumSizeReached = true; +} + +ApplicationCacheStorage::ApplicationCacheStorage() + : m_maximumSize(INT_MAX) + , m_isMaximumSizeReached(false) +{ +} + +#else // MANUAL_MERGE_REQUIRED bool ApplicationCacheStorage::manifestURLs(Vector* urls) { @@ -1059,6 +1233,10 @@ bool ApplicationCacheStorage::deleteCacheGroup(const String& manifestURL) void ApplicationCacheStorage::vacuumDatabaseFile() { + openDatabase(false); + if (!m_database.isOpen()) + return; + m_database.runVacuumCommand(); } @@ -1074,6 +1252,7 @@ ApplicationCacheStorage::ApplicationCacheStorage() { } +#endif // MANUAL_MERGE_REQUIRED ApplicationCacheStorage& cacheStorage() { DEFINE_STATIC_LOCAL(ApplicationCacheStorage, storage, ()); diff --git a/WebCore/loader/appcache/ApplicationCacheStorage.h b/WebCore/loader/appcache/ApplicationCacheStorage.h index c6d687e..1348aa9 100644 --- a/WebCore/loader/appcache/ApplicationCacheStorage.h +++ b/WebCore/loader/appcache/ApplicationCacheStorage.h @@ -37,6 +37,7 @@ namespace WebCore { class ApplicationCache; +class ApplicationCacheHost; class ApplicationCacheGroup; class ApplicationCacheResource; class KURL; @@ -69,7 +70,7 @@ public: void empty(); - static bool storeCopyOfCache(const String& cacheDirectory, ApplicationCache*); + static bool storeCopyOfCache(const String& cacheDirectory, ApplicationCacheHost*); bool manifestURLs(Vector* urls); bool cacheGroupSize(const String& manifestURL, int64_t* size); diff --git a/WebCore/loader/appcache/DOMApplicationCache.cpp b/WebCore/loader/appcache/DOMApplicationCache.cpp index 12d86a7..109ac1a 100644 --- a/WebCore/loader/appcache/DOMApplicationCache.cpp +++ b/WebCore/loader/appcache/DOMApplicationCache.cpp @@ -28,9 +28,7 @@ #if ENABLE(OFFLINE_WEB_APPLICATIONS) -#include "ApplicationCache.h" -#include "ApplicationCacheGroup.h" -#include "ApplicationCacheResource.h" +#include "ApplicationCacheHost.h" #include "DocumentLoader.h" #include "Event.h" #include "EventException.h" @@ -38,87 +36,52 @@ #include "EventNames.h" #include "Frame.h" #include "FrameLoader.h" -#include "StaticStringList.h" namespace WebCore { DOMApplicationCache::DOMApplicationCache(Frame* frame) : m_frame(frame) { + ASSERT(applicationCacheHost()); + applicationCacheHost()->setDOMApplicationCache(this); } void DOMApplicationCache::disconnectFrame() { + ApplicationCacheHost* cacheHost = applicationCacheHost(); + if (cacheHost) + cacheHost->setDOMApplicationCache(0); m_frame = 0; } -ApplicationCache* DOMApplicationCache::associatedCache() const +ApplicationCacheHost* DOMApplicationCache::applicationCacheHost() const { - if (!m_frame) + if (!m_frame || !m_frame->loader()->documentLoader()) return 0; - - return m_frame->loader()->documentLoader()->applicationCache(); + return m_frame->loader()->documentLoader()->applicationCacheHost(); } unsigned short DOMApplicationCache::status() const { - ApplicationCache* cache = associatedCache(); - if (!cache) - return UNCACHED; - - switch (cache->group()->updateStatus()) { - case ApplicationCacheGroup::Checking: - return CHECKING; - case ApplicationCacheGroup::Downloading: - return DOWNLOADING; - case ApplicationCacheGroup::Idle: { - if (cache->group()->isObsolete()) - return OBSOLETE; - if (cache != cache->group()->newestCache()) - return UPDATEREADY; - return IDLE; - } - } - - ASSERT_NOT_REACHED(); - return 0; + ApplicationCacheHost* cacheHost = applicationCacheHost(); + if (!cacheHost) + return ApplicationCacheHost::UNCACHED; + return cacheHost->status(); } void DOMApplicationCache::update(ExceptionCode& ec) { - ApplicationCache* cache = associatedCache(); - if (!cache) { + ApplicationCacheHost* cacheHost = applicationCacheHost(); + if (!cacheHost || !cacheHost->update()) ec = INVALID_STATE_ERR; - return; - } - - cache->group()->update(m_frame, ApplicationCacheUpdateWithoutBrowsingContext); } bool DOMApplicationCache::swapCache() { - if (!m_frame) - return false; - - ApplicationCache* cache = m_frame->loader()->documentLoader()->applicationCache(); - if (!cache) + ApplicationCacheHost* cacheHost = applicationCacheHost(); + if (!cacheHost) return false; - - // If the group of application caches to which cache belongs has the lifecycle status obsolete, unassociate document from cache. - if (cache->group()->isObsolete()) { - cache->group()->disassociateDocumentLoader(m_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; - - ASSERT(cache->group() == newestCache->group()); - m_frame->loader()->documentLoader()->setApplicationCache(newestCache); - - return true; + return cacheHost->swapCache(); } void DOMApplicationCache::swapCache(ExceptionCode& ec) @@ -127,65 +90,6 @@ void DOMApplicationCache::swapCache(ExceptionCode& ec) ec = INVALID_STATE_ERR; } -PassRefPtr DOMApplicationCache::items() -{ - Vector result; - if (ApplicationCache* cache = associatedCache()) { - unsigned numEntries = cache->numDynamicEntries(); - result.reserveInitialCapacity(numEntries); - for (unsigned i = 0; i < numEntries; ++i) - result.append(cache->dynamicEntry(i)); - } - return StaticStringList::adopt(result); -} - -bool DOMApplicationCache::hasItem(const KURL& url, ExceptionCode& ec) -{ - ApplicationCache* cache = associatedCache(); - if (!cache) { - ec = INVALID_STATE_ERR; - return false; - } - - if (!url.isValid()) { - ec = SYNTAX_ERR; - return false; - } - - ApplicationCacheResource* resource = cache->resourceForURL(url.string()); - return resource && (resource->type() & ApplicationCacheResource::Dynamic); -} - -void DOMApplicationCache::add(const KURL& url, ExceptionCode& ec) -{ - ApplicationCache* cache = associatedCache(); - if (!cache) { - ec = INVALID_STATE_ERR; - return; - } - - if (!url.isValid()) { - ec = SYNTAX_ERR; - return; - } - - if (!cache->addDynamicEntry(url)) { - // This should use the (currently not specified) security exceptions in HTML5 4.3.4 - ec = SECURITY_ERR; - } -} - -void DOMApplicationCache::remove(const KURL& url, ExceptionCode& ec) -{ - ApplicationCache* cache = associatedCache(); - if (!cache) { - ec = INVALID_STATE_ERR; - return; - } - - cache->removeDynamicEntry(url); -} - ScriptExecutionContext* DOMApplicationCache::scriptExecutionContext() const { return m_frame->document(); @@ -231,7 +135,7 @@ bool DOMApplicationCache::dispatchEvent(PassRefPtr event, ExceptionCode& ec = EventException::UNSPECIFIED_EVENT_TYPE_ERR; return true; } - + ListenerVector listenersCopy = m_eventListeners.get(event->type()); for (ListenerVector::const_iterator listenerIter = listenersCopy.begin(); listenerIter != listenersCopy.end(); ++listenerIter) { event->setTarget(this); @@ -258,45 +162,53 @@ void DOMApplicationCache::callListener(const AtomicString& eventType, EventListe ASSERT(!ec); } -void DOMApplicationCache::callCheckingListener() +const AtomicString& DOMApplicationCache::toEventType(ApplicationCacheHost::EventID id) { - callListener(eventNames().checkingEvent, m_onCheckingListener.get()); -} - -void DOMApplicationCache::callErrorListener() -{ - callListener(eventNames().errorEvent, m_onErrorListener.get()); -} - -void DOMApplicationCache::callNoUpdateListener() -{ - callListener(eventNames().noupdateEvent, m_onNoUpdateListener.get()); -} - -void DOMApplicationCache::callDownloadingListener() -{ - callListener(eventNames().downloadingEvent, m_onDownloadingListener.get()); -} - -void DOMApplicationCache::callProgressListener() -{ - callListener(eventNames().progressEvent, m_onProgressListener.get()); -} - -void DOMApplicationCache::callUpdateReadyListener() -{ - callListener(eventNames().updatereadyEvent, m_onUpdateReadyListener.get()); + switch (id) { + case ApplicationCacheHost::CHECKING_EVENT: + return eventNames().checkingEvent; + case ApplicationCacheHost::ERROR_EVENT: + return eventNames().errorEvent; + case ApplicationCacheHost::NOUPDATE_EVENT: + return eventNames().noupdateEvent; + case ApplicationCacheHost::DOWNLOADING_EVENT: + return eventNames().downloadingEvent; + case ApplicationCacheHost::PROGRESS_EVENT: + return eventNames().progressEvent; + case ApplicationCacheHost::UPDATEREADY_EVENT: + return eventNames().updatereadyEvent; + case ApplicationCacheHost::CACHED_EVENT: + return eventNames().cachedEvent; + case ApplicationCacheHost::OBSOLETE_EVENT: + return eventNames().obsoleteEvent; + } + ASSERT_NOT_REACHED(); + return eventNames().errorEvent; } -void DOMApplicationCache::callCachedListener() +ApplicationCacheHost::EventID DOMApplicationCache::toEventID(const AtomicString& eventType) { - callListener(eventNames().cachedEvent, m_onCachedListener.get()); + if (eventType == eventNames().checkingEvent) + return ApplicationCacheHost::CHECKING_EVENT; + if (eventType == eventNames().errorEvent) + return ApplicationCacheHost::ERROR_EVENT; + if (eventType == eventNames().noupdateEvent) + return ApplicationCacheHost::NOUPDATE_EVENT; + if (eventType == eventNames().downloadingEvent) + return ApplicationCacheHost::DOWNLOADING_EVENT; + if (eventType == eventNames().progressEvent) + return ApplicationCacheHost::PROGRESS_EVENT; + if (eventType == eventNames().updatereadyEvent) + return ApplicationCacheHost::UPDATEREADY_EVENT; + if (eventType == eventNames().cachedEvent) + return ApplicationCacheHost::CACHED_EVENT; + if (eventType == eventNames().obsoleteEvent) + return ApplicationCacheHost::OBSOLETE_EVENT; + + ASSERT_NOT_REACHED(); + return ApplicationCacheHost::ERROR_EVENT; } -void DOMApplicationCache::callObsoleteListener() -{ - callListener(eventNames().obsoleteEvent, m_onObsoleteListener.get()); -} #if USE(V8) RefPtr* DOMApplicationCache::getAttributeEventListenerStorage(const AtomicString& eventType) diff --git a/WebCore/loader/appcache/DOMApplicationCache.h b/WebCore/loader/appcache/DOMApplicationCache.h index 57b37bc..ade0fcf 100644 --- a/WebCore/loader/appcache/DOMApplicationCache.h +++ b/WebCore/loader/appcache/DOMApplicationCache.h @@ -28,6 +28,7 @@ #if ENABLE(OFFLINE_WEB_APPLICATIONS) +#include "ApplicationCacheHost.h" #include "AtomicStringHash.h" #include "EventTarget.h" #include "EventListener.h" @@ -38,41 +39,34 @@ namespace WebCore { -class ApplicationCache; class AtomicStringImpl; -class DOMStringList; class Frame; class KURL; class String; - + class DOMApplicationCache : public RefCounted, public EventTarget { public: static PassRefPtr create(Frame* frame) { return adoptRef(new DOMApplicationCache(frame)); } - void disconnectFrame(); + ~DOMApplicationCache() { ASSERT(!m_frame); } - enum Status { - UNCACHED = 0, - IDLE = 1, - CHECKING = 2, - DOWNLOADING = 3, - UPDATEREADY = 4, - OBSOLETE = 5 - }; + void disconnectFrame(); unsigned short status() const; - void update(ExceptionCode&); void swapCache(ExceptionCode&); - - PassRefPtr items(); - bool hasItem(const KURL&, ExceptionCode&); - void add(const KURL&, ExceptionCode&); - void remove(const KURL&, ExceptionCode&); + + // Event listener attributes by EventID + + void setAttributeEventListener(ApplicationCacheHost::EventID id, PassRefPtr eventListener) { m_attributeEventListeners[id] = eventListener; } + EventListener* getAttributeEventListener(ApplicationCacheHost::EventID id) const { return m_attributeEventListeners[id].get(); } + void clearAttributeEventListener(ApplicationCacheHost::EventID id) { m_attributeEventListeners[id] = 0; } + void callEventListener(ApplicationCacheHost::EventID id) { callListener(toEventType(id), getAttributeEventListener(id)); } + + // EventTarget impl virtual void addEventListener(const AtomicString& eventType, PassRefPtr, bool useCapture); virtual void removeEventListener(const AtomicString& eventType, EventListener*, bool useCapture); virtual bool dispatchEvent(PassRefPtr, ExceptionCode&); - typedef Vector > ListenerVector; typedef HashMap EventListenersMap; EventListenersMap& eventListeners() { return m_eventListeners; } @@ -80,33 +74,36 @@ public: using RefCounted::ref; using RefCounted::deref; - void setOnchecking(PassRefPtr eventListener) { m_onCheckingListener = eventListener; } - EventListener* onchecking() const { return m_onCheckingListener.get(); } + // Explicitly named attribute event listener helpers - void setOnerror(PassRefPtr eventListener) { m_onErrorListener = eventListener; } - EventListener* onerror() const { return m_onErrorListener.get(); } + void setOnchecking(PassRefPtr listener) { setAttributeEventListener(ApplicationCacheHost::CHECKING_EVENT, listener); } + EventListener* onchecking() const { return getAttributeEventListener(ApplicationCacheHost::CHECKING_EVENT); } - void setOnnoupdate(PassRefPtr eventListener) { m_onNoUpdateListener = eventListener; } - EventListener* onnoupdate() const { return m_onNoUpdateListener.get(); } + void setOnerror(PassRefPtr listener) { setAttributeEventListener(ApplicationCacheHost::ERROR_EVENT, listener);} + EventListener* onerror() const { return getAttributeEventListener(ApplicationCacheHost::ERROR_EVENT); } - void setOndownloading(PassRefPtr eventListener) { m_onDownloadingListener = eventListener; } - EventListener* ondownloading() const { return m_onDownloadingListener.get(); } - - void setOnprogress(PassRefPtr eventListener) { m_onProgressListener = eventListener; } - EventListener* onprogress() const { return m_onProgressListener.get(); } + void setOnnoupdate(PassRefPtr listener) { setAttributeEventListener(ApplicationCacheHost::NOUPDATE_EVENT, listener); } + EventListener* onnoupdate() const { return getAttributeEventListener(ApplicationCacheHost::NOUPDATE_EVENT); } + + void setOndownloading(PassRefPtr listener) { setAttributeEventListener(ApplicationCacheHost::DOWNLOADING_EVENT, listener); } + EventListener* ondownloading() const { return getAttributeEventListener(ApplicationCacheHost::DOWNLOADING_EVENT); } + + void setOnprogress(PassRefPtr listener) { setAttributeEventListener(ApplicationCacheHost::PROGRESS_EVENT, listener); } + EventListener* onprogress() const { return getAttributeEventListener(ApplicationCacheHost::PROGRESS_EVENT); } - void setOnupdateready(PassRefPtr eventListener) { m_onUpdateReadyListener = eventListener; } - EventListener* onupdateready() const { return m_onUpdateReadyListener.get(); } + void setOnupdateready(PassRefPtr listener) { setAttributeEventListener(ApplicationCacheHost::UPDATEREADY_EVENT, listener); } + EventListener* onupdateready() const { return getAttributeEventListener(ApplicationCacheHost::UPDATEREADY_EVENT); } - void setOncached(PassRefPtr eventListener) { m_onCachedListener = eventListener; } - EventListener* oncached() const { return m_onCachedListener.get(); } + void setOncached(PassRefPtr listener) { setAttributeEventListener(ApplicationCacheHost::CACHED_EVENT, listener); } + EventListener* oncached() const { return getAttributeEventListener(ApplicationCacheHost::CACHED_EVENT); } - void setOnobsolete(PassRefPtr eventListener) { m_onObsoleteListener = eventListener; } - EventListener* onobsolete() const { return m_onObsoleteListener.get(); } + void setOnobsolete(PassRefPtr listener) { setAttributeEventListener(ApplicationCacheHost::OBSOLETE_EVENT, listener); } + EventListener* onobsolete() const { return getAttributeEventListener(ApplicationCacheHost::OBSOLETE_EVENT); } virtual ScriptExecutionContext* scriptExecutionContext() const; DOMApplicationCache* toDOMApplicationCache() { return this; } +#ifdef MANUAL_MERGE_REQUIRED void callCheckingListener(); void callErrorListener(); void callNoUpdateListener(); @@ -122,29 +119,28 @@ public: void clearAttributeEventListener(const AtomicString& eventType); #endif +#else // MANUAL_MERGE_REQUIRED + static const AtomicString& toEventType(ApplicationCacheHost::EventID id); + static ApplicationCacheHost::EventID toEventID(const AtomicString& eventType); + +#endif // MANUAL_MERGE_REQUIRED private: DOMApplicationCache(Frame*); + void callListener(const AtomicString& eventType, EventListener*); virtual void refEventTarget() { ref(); } virtual void derefEventTarget() { deref(); } - ApplicationCache* associatedCache() const; + ApplicationCacheHost* applicationCacheHost() const; bool swapCache(); #if USE(V8) RefPtr* getAttributeEventListenerStorage(const AtomicString& eventType); #endif - RefPtr m_onCheckingListener; - RefPtr m_onErrorListener; - RefPtr m_onNoUpdateListener; - RefPtr m_onDownloadingListener; - RefPtr m_onProgressListener; - RefPtr m_onUpdateReadyListener; - RefPtr m_onCachedListener; - RefPtr m_onObsoleteListener; - + RefPtr m_attributeEventListeners[ApplicationCacheHost::OBSOLETE_EVENT + 1]; + EventListenersMap m_eventListeners; Frame* m_frame; diff --git a/WebCore/loader/appcache/DOMApplicationCache.idl b/WebCore/loader/appcache/DOMApplicationCache.idl index 1156c9c..ebc1d19 100644 --- a/WebCore/loader/appcache/DOMApplicationCache.idl +++ b/WebCore/loader/appcache/DOMApplicationCache.idl @@ -43,17 +43,6 @@ module offline { void swapCache() raises(DOMException); -#if defined(ENABLE_APPLICATION_CACHE_DYNAMIC_ENTRIES) && ENABLE_APPLICATION_CACHE_DYNAMIC_ENTRIES - // dynamic entries - 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; attribute EventListener onerror; diff --git a/WebCore/loader/appcache/ManifestParser.cpp b/WebCore/loader/appcache/ManifestParser.cpp index 4169313..a2df825 100644 --- a/WebCore/loader/appcache/ManifestParser.cpp +++ b/WebCore/loader/appcache/ManifestParser.cpp @@ -114,8 +114,8 @@ bool parseManifest(const KURL& manifestURL, const char* data, int length, Manife if (!url.isValid()) continue; - if (url.hasRef()) - url.setRef(String()); + if (url.hasFragmentIdentifier()) + url.removeFragmentIdentifier(); if (!equalIgnoringCase(url.protocol(), manifestURL.protocol())) continue; @@ -141,8 +141,8 @@ bool parseManifest(const KURL& manifestURL, const char* data, int length, Manife KURL namespaceURL(manifestURL, String(line.characters(), p - line.characters())); if (!namespaceURL.isValid()) continue; - if (namespaceURL.hasRef()) - namespaceURL.setRef(String()); + if (namespaceURL.hasFragmentIdentifier()) + namespaceURL.removeFragmentIdentifier(); if (!protocolHostAndPortAreEqual(manifestURL, namespaceURL)) continue; @@ -159,8 +159,8 @@ bool parseManifest(const KURL& manifestURL, const char* data, int length, Manife KURL fallbackURL(manifestURL, String(fallbackStart, p - fallbackStart)); if (!fallbackURL.isValid()) continue; - if (fallbackURL.hasRef()) - fallbackURL.setRef(String()); + if (fallbackURL.hasFragmentIdentifier()) + fallbackURL.removeFragmentIdentifier(); if (!protocolHostAndPortAreEqual(manifestURL, fallbackURL)) continue; diff --git a/WebCore/loader/archive/ArchiveResourceCollection.h b/WebCore/loader/archive/ArchiveResourceCollection.h index f898a8d..9d630d1 100644 --- a/WebCore/loader/archive/ArchiveResourceCollection.h +++ b/WebCore/loader/archive/ArchiveResourceCollection.h @@ -39,7 +39,7 @@ namespace WebCore { -class ArchiveResourceCollection : Noncopyable { +class ArchiveResourceCollection : public Noncopyable { public: ArchiveResourceCollection(); diff --git a/WebCore/loader/icon/IconDatabase.cpp b/WebCore/loader/icon/IconDatabase.cpp index 1f49c88..a6c2a66 100644 --- a/WebCore/loader/icon/IconDatabase.cpp +++ b/WebCore/loader/icon/IconDatabase.cpp @@ -27,6 +27,8 @@ #include "config.h" #include "IconDatabase.h" +#if ENABLE(ICONDATABASE) + #include "AutodrainedPool.h" #include "DocumentLoader.h" #include "FileSystem.h" @@ -2080,3 +2082,5 @@ void IconDatabase::writeIconSnapshotToSQLDatabase(const IconSnapshot& snapshot) } } // namespace WebCore + +#endif // ENABLE(ICONDATABASE) diff --git a/WebCore/loader/icon/IconDatabase.h b/WebCore/loader/icon/IconDatabase.h index 40f641a..44ef22a 100644 --- a/WebCore/loader/icon/IconDatabase.h +++ b/WebCore/loader/icon/IconDatabase.h @@ -62,7 +62,7 @@ enum IconLoadDecision { IconLoadUnknown }; -class IconDatabase : Noncopyable { +class IconDatabase : public Noncopyable { // *** Main Thread Only *** public: @@ -165,6 +165,7 @@ private: HashSet m_pageURLsPendingImport; HashSet m_pageURLsInterestedInIcons; HashSet m_iconsPendingReading; +#endif // ENABLE(ICONDATABASE) // *** Sync Thread Only *** public: @@ -174,6 +175,7 @@ public: bool shouldStopThreadActivity() const; +#if ENABLE(ICONDATABASE) private: static void* iconDatabaseSyncThreadStart(void *); void* iconDatabaseSyncThread(); @@ -238,4 +240,4 @@ IconDatabase* iconDatabase(); } // namespace WebCore -#endif +#endif // IconDatabase_h diff --git a/WebCore/loader/icon/IconDatabaseNone.cpp b/WebCore/loader/icon/IconDatabaseNone.cpp index a7fb88d..03a7964 100644 --- a/WebCore/loader/icon/IconDatabaseNone.cpp +++ b/WebCore/loader/icon/IconDatabaseNone.cpp @@ -26,6 +26,8 @@ #include "config.h" #include "IconDatabase.h" +#if !ENABLE(ICONDATABASE) + #include "PlatformString.h" #include "SharedBuffer.h" #include @@ -194,4 +196,23 @@ void IconDatabase::setClient(IconDatabaseClient*) { } +// ************************ +// *** Sync Thread Only *** +// ************************ + +void IconDatabase::importIconURLForPageURL(const String&, const String&) +{ +} + +void IconDatabase::importIconDataForIconURL(PassRefPtr, const String&) +{ +} + +bool IconDatabase::shouldStopThreadActivity() const +{ + return true; +} + } // namespace WebCore + +#endif // !ENABLE(ICONDATABASE) diff --git a/WebCore/loader/icon/IconLoader.h b/WebCore/loader/icon/IconLoader.h index a7194d8..7b96ed8 100644 --- a/WebCore/loader/icon/IconLoader.h +++ b/WebCore/loader/icon/IconLoader.h @@ -38,7 +38,7 @@ class Frame; class KURL; class SharedBuffer; -class IconLoader : private SubresourceLoaderClient, Noncopyable { +class IconLoader : private SubresourceLoaderClient, public Noncopyable { public: static std::auto_ptr create(Frame*); ~IconLoader(); diff --git a/WebCore/loader/icon/PageURLRecord.h b/WebCore/loader/icon/PageURLRecord.h index bc52f5b..f7ccb8f 100644 --- a/WebCore/loader/icon/PageURLRecord.h +++ b/WebCore/loader/icon/PageURLRecord.h @@ -51,7 +51,7 @@ public: String iconURL; }; -class PageURLRecord : Noncopyable { +class PageURLRecord : public Noncopyable { public: PageURLRecord(const String& pageURL); ~PageURLRecord(); diff --git a/WebCore/loader/icon/wince/IconDatabaseWince.cpp b/WebCore/loader/icon/wince/IconDatabaseWince.cpp new file mode 100644 index 0000000..e6d686c --- /dev/null +++ b/WebCore/loader/icon/wince/IconDatabaseWince.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2007-2009 Torch Mobile Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "IconDatabase.h" + +#include "AutodrainedPool.h" +#include "CString.h" +#include "DocumentLoader.h" +#include "FileSystem.h" +#include "IconDatabaseClient.h" +#include "IconRecord.h" +#include "Image.h" + +namespace WebCore { + +// Function to obtain the global icon database. +IconDatabase* iconDatabase() { return 0; } + +IconDatabase::IconDatabase() {} +IconDatabase::~IconDatabase() {} + +void IconDatabase::setClient(IconDatabaseClient*) {} + +bool IconDatabase::open(const String& path) { return false; } +void IconDatabase::close() {} + +void IconDatabase::removeAllIcons() {} + +Image* IconDatabase::iconForPageURL(const String&, const IntSize&) { return 0; } +void IconDatabase::readIconForPageURLFromDisk(const String&) {} +String IconDatabase::iconURLForPageURL(const String&) { return String(); } +Image* IconDatabase::defaultIcon(const IntSize&) { return 0;} + +void IconDatabase::retainIconForPageURL(const String&) {} +void IconDatabase::releaseIconForPageURL(const String&) {} + +void IconDatabase::setIconDataForIconURL(PassRefPtr data, const String&) {} +void IconDatabase::setIconURLForPageURL(const String& iconURL, const String& pageURL) {} + +IconLoadDecision IconDatabase::loadDecisionForIconURL(const String&, DocumentLoader*) { return IconLoadNo; } +bool IconDatabase::iconDataKnownForIconURL(const String&) { return false; } + +void IconDatabase::setEnabled(bool enabled) {} +bool IconDatabase::isEnabled() const { return false; } + +void IconDatabase::setPrivateBrowsingEnabled(bool flag) {} +bool IconDatabase::isPrivateBrowsingEnabled() const { return false; } + +void IconDatabase::delayDatabaseCleanup() {} +void IconDatabase::allowDatabaseCleanup() {} +void IconDatabase::checkIntegrityBeforeOpening() {} + +// Support for WebCoreStatistics in WebKit +size_t IconDatabase::pageURLMappingCount() { return 0; } +size_t IconDatabase::retainedPageURLCount() {return 0; } +size_t IconDatabase::iconRecordCount() { return 0; } +size_t IconDatabase::iconRecordCountWithData() { return 0; } + +bool IconDatabase::isOpen() const { return false; } +String IconDatabase::databasePath() const { return String(); } +String IconDatabase::defaultDatabaseFilename() { return String(); } + +} // namespace WebCore diff --git a/WebCore/loader/loader.cpp b/WebCore/loader/loader.cpp index ed82e94..65d15a5 100644 --- a/WebCore/loader/loader.cpp +++ b/WebCore/loader/loader.cpp @@ -178,6 +178,35 @@ void Loader::resumePendingRequests() scheduleServePendingRequests(); } +void Loader::nonCacheRequestInFlight(const KURL& url) +{ + if (!url.protocolInHTTPFamily()) + return; + + AtomicString hostName = url.host(); + RefPtr host = m_hosts.get(hostName.impl()); + if (!host) { + host = Host::create(hostName, maxRequestsInFlightPerHost); + m_hosts.add(hostName.impl(), host); + } + + host->nonCacheRequestInFlight(); +} + +void Loader::nonCacheRequestComplete(const KURL& url) +{ + if (!url.protocolInHTTPFamily()) + return; + + AtomicString hostName = url.host(); + RefPtr host = m_hosts.get(hostName.impl()); + ASSERT(host); + if (!host) + return; + + host->nonCacheRequestComplete(); +} + void Loader::cancelRequests(DocLoader* docLoader) { docLoader->clearPendingPreloads(); @@ -206,6 +235,7 @@ Loader::Host::Host(const AtomicString& name, unsigned maxRequestsInFlight) : m_name(name) , m_maxRequestsInFlight(maxRequestsInFlight) , m_numResourcesProcessing(0) + , m_nonCachedRequestsInFlight(0) { } @@ -221,6 +251,17 @@ void Loader::Host::addRequest(Request* request, Priority priority) m_requestsPending[priority].append(request); } +void Loader::Host::nonCacheRequestInFlight() +{ + ++m_nonCachedRequestsInFlight; +} + +void Loader::Host::nonCacheRequestComplete() +{ + --m_nonCachedRequestsInFlight; + ASSERT(m_nonCachedRequestsInFlight >= 0); +} + bool Loader::Host::hasRequests() const { if (!m_requestsLoading.isEmpty()) @@ -248,11 +289,12 @@ void Loader::Host::servePendingRequests(RequestQueue& requestsPending, bool& ser Request* request = requestsPending.first(); DocLoader* docLoader = request->docLoader(); bool resourceIsCacheValidator = request->cachedResource()->isCacheValidator(); - // If the document is fully parsed and there are no pending stylesheets there won't be any more - // resources that we would want to push to the front of the queue. Just hand off the remaining resources - // to the networking layer. - bool parsedAndStylesheetsKnown = !docLoader->doc()->parsing() && docLoader->doc()->haveStylesheetsLoaded(); - if (!parsedAndStylesheetsKnown && !resourceIsCacheValidator && m_requestsLoading.size() >= m_maxRequestsInFlight) { + + // For named hosts - which are only http(s) hosts - we should always enforce the connection limit. + // For non-named hosts - everything but http(s) - we should only enforce the limit if the document isn't done parsing + // and we don't know all stylesheets yet. + bool shouldLimitRequests = !m_name.isNull() || docLoader->doc()->parsing() || !docLoader->doc()->haveStylesheetsLoaded(); + if (shouldLimitRequests && m_requestsLoading.size() + m_nonCachedRequestsInFlight >= m_maxRequestsInFlight) { serveLowerPriority = false; return; } diff --git a/WebCore/loader/loader.h b/WebCore/loader/loader.h index c5b9416..d0a526f 100644 --- a/WebCore/loader/loader.h +++ b/WebCore/loader/loader.h @@ -35,9 +35,10 @@ namespace WebCore { class CachedResource; class DocLoader; + class KURL; class Request; - class Loader : Noncopyable { + class Loader : public Noncopyable { public: Loader(); ~Loader(); @@ -52,6 +53,9 @@ namespace WebCore { bool isSuspendingPendingRequests() { return m_isSuspendingPendingRequests; } void suspendPendingRequests(); void resumePendingRequests(); + + void nonCacheRequestInFlight(const KURL&); + void nonCacheRequestComplete(const KURL&); private: Priority determinePriority(const CachedResource*) const; @@ -69,11 +73,13 @@ namespace WebCore { const AtomicString& name() const { return m_name; } void addRequest(Request*, Priority); + void nonCacheRequestInFlight(); + void nonCacheRequestComplete(); void servePendingRequests(Priority minimumPriority = Low); void cancelRequests(DocLoader*); bool hasRequests() const; - bool processingResource() const { return m_numResourcesProcessing != 0; } + bool processingResource() const { return m_numResourcesProcessing != 0 || m_nonCachedRequestsInFlight !=0; } private: Host(const AtomicString&, unsigned); @@ -94,6 +100,7 @@ namespace WebCore { const AtomicString m_name; const int m_maxRequestsInFlight; int m_numResourcesProcessing; + int m_nonCachedRequestsInFlight; }; typedef HashMap > HostMap; HostMap m_hosts; -- cgit v1.1