From 231d4e3152a9c27a73b6ac7badbe6be673aa3ddf Mon Sep 17 00:00:00 2001 From: Steve Block Date: Thu, 8 Oct 2009 17:19:54 +0100 Subject: Merge webkit.org at R49305 : Automatic merge by git. Change-Id: I8968561bc1bfd72b8923b7118d3728579c6dbcc7 --- WebCore/loader/Cache.cpp | 9 +- WebCore/loader/CachedFont.cpp | 15 +- WebCore/loader/CachedResource.cpp | 25 +- WebCore/loader/CachedResource.h | 9 +- WebCore/loader/CachedResourceClient.h | 4 +- WebCore/loader/CachedResourceHandle.h | 3 +- WebCore/loader/CrossOriginPreflightResultCache.cpp | 17 +- WebCore/loader/CrossOriginPreflightResultCache.h | 1 - WebCore/loader/DocLoader.cpp | 37 +- WebCore/loader/DocumentLoader.cpp | 15 +- WebCore/loader/DocumentLoader.h | 8 +- WebCore/loader/DocumentThreadableLoader.cpp | 245 ++++- WebCore/loader/DocumentThreadableLoader.h | 28 +- WebCore/loader/EmptyClients.h | 21 +- WebCore/loader/FTPDirectoryDocument.cpp | 8 +- WebCore/loader/FTPDirectoryDocument.h | 4 +- WebCore/loader/FTPDirectoryParser.cpp | 144 ++- WebCore/loader/FrameLoader.cpp | 1079 ++++++-------------- WebCore/loader/FrameLoader.h | 168 +-- WebCore/loader/FrameLoaderClient.h | 16 + WebCore/loader/FrameLoaderTypes.h | 6 + WebCore/loader/ImageDocument.cpp | 27 +- WebCore/loader/ImageDocument.h | 4 +- WebCore/loader/MainResourceLoader.cpp | 30 +- WebCore/loader/MediaDocument.cpp | 4 +- WebCore/loader/MediaDocument.h | 13 +- WebCore/loader/PlaceholderDocument.cpp | 2 +- WebCore/loader/PlaceholderDocument.h | 2 +- WebCore/loader/PluginDocument.cpp | 4 +- WebCore/loader/PluginDocument.h | 4 +- WebCore/loader/PolicyCallback.cpp | 133 +++ WebCore/loader/PolicyCallback.h | 80 ++ WebCore/loader/PolicyChecker.cpp | 197 ++++ WebCore/loader/PolicyChecker.h | 97 ++ WebCore/loader/RedirectScheduler.cpp | 374 +++++++ WebCore/loader/RedirectScheduler.h | 81 ++ WebCore/loader/ResourceLoader.cpp | 5 +- WebCore/loader/SubresourceLoader.cpp | 7 +- WebCore/loader/TextDocument.h | 4 +- WebCore/loader/TextResourceDecoder.cpp | 26 +- WebCore/loader/ThreadableLoader.cpp | 12 +- WebCore/loader/ThreadableLoader.h | 32 +- WebCore/loader/UserStyleSheetLoader.cpp | 62 -- WebCore/loader/UserStyleSheetLoader.h | 57 -- WebCore/loader/WorkerThreadableLoader.cpp | 22 +- WebCore/loader/WorkerThreadableLoader.h | 12 +- WebCore/loader/appcache/ApplicationCache.cpp | 5 +- WebCore/loader/appcache/ApplicationCache.h | 3 + WebCore/loader/appcache/ApplicationCacheGroup.cpp | 9 +- WebCore/loader/appcache/ApplicationCacheGroup.h | 4 + WebCore/loader/appcache/ApplicationCacheHost.cpp | 14 +- WebCore/loader/appcache/ApplicationCacheHost.h | 2 +- .../loader/appcache/ApplicationCacheStorage.cpp | 43 +- WebCore/loader/appcache/DOMApplicationCache.cpp | 115 +-- WebCore/loader/appcache/DOMApplicationCache.h | 59 +- WebCore/loader/appcache/DOMApplicationCache.idl | 2 +- WebCore/loader/appcache/ManifestParser.cpp | 9 +- WebCore/loader/appcache/ManifestParser.h | 1 + WebCore/loader/archive/cf/LegacyWebArchive.cpp | 6 +- WebCore/loader/icon/IconDatabase.cpp | 26 +- WebCore/loader/icon/IconDatabaseNone.cpp | 2 +- WebCore/loader/loader.cpp | 6 +- 62 files changed, 2005 insertions(+), 1454 deletions(-) create mode 100644 WebCore/loader/PolicyCallback.cpp create mode 100644 WebCore/loader/PolicyCallback.h create mode 100644 WebCore/loader/PolicyChecker.cpp create mode 100644 WebCore/loader/PolicyChecker.h create mode 100644 WebCore/loader/RedirectScheduler.cpp create mode 100644 WebCore/loader/RedirectScheduler.h delete mode 100644 WebCore/loader/UserStyleSheetLoader.cpp delete mode 100644 WebCore/loader/UserStyleSheetLoader.h (limited to 'WebCore/loader') diff --git a/WebCore/loader/Cache.cpp b/WebCore/loader/Cache.cpp index 6eeba77..1f28709 100644 --- a/WebCore/loader/Cache.cpp +++ b/WebCore/loader/Cache.cpp @@ -34,6 +34,7 @@ #include "FrameView.h" #include "Image.h" #include "ResourceHandle.h" +#include "SecurityOrigin.h" #include #include @@ -105,7 +106,7 @@ CachedResource* Cache::requestResource(DocLoader* docLoader, CachedResource::Typ if (resource && requestIsPreload && !resource->isPreloaded()) return 0; - if (FrameLoader::restrictAccessToLocal() && !FrameLoader::canLoad(url, String(), docLoader->doc())) { + if (SecurityOrigin::restrictAccessToLocal() && !SecurityOrigin::canLoad(url, String(), docLoader->doc())) { Document* doc = docLoader->doc(); if (doc && !requestIsPreload) FrameLoader::reportLocalLoadFailed(doc->frame(), url.string()); @@ -183,6 +184,7 @@ void Cache::revalidateResource(CachedResource* resource, DocLoader* docLoader) { ASSERT(resource); ASSERT(resource->inCache()); + ASSERT(resource == m_resources.get(resource->url())); ASSERT(!disabled()); if (resource->resourceToRevalidate()) return; @@ -191,7 +193,7 @@ void Cache::revalidateResource(CachedResource* resource, DocLoader* docLoader) return; } const String& url = resource->url(); - CachedResource* newResource = createResource(resource->type(), KURL(url), resource->encoding()); + CachedResource* newResource = createResource(resource->type(), KURL(ParsedURLString, url), resource->encoding()); newResource->setResourceToRevalidate(resource); evict(resource); m_resources.set(url, newResource); @@ -206,6 +208,7 @@ void Cache::revalidationSucceeded(CachedResource* revalidatingResource, const Re ASSERT(resource); ASSERT(!resource->inCache()); ASSERT(resource->isLoaded()); + ASSERT(revalidatingResource->inCache()); evict(revalidatingResource); @@ -352,7 +355,7 @@ void Cache::pruneDeadResources() current = m_allResources[i].m_tail; while (current) { CachedResource* prev = current->m_prevInAllResourcesList; - if (!current->hasClients() && !current->isPreloaded()) { + if (!current->hasClients() && !current->isPreloaded() && !current->isCacheValidator()) { evict(current); // If evict() caused pruneDeadResources() to be re-entered, bail out. This can happen when removing an // SVG CachedImage that has subresources. diff --git a/WebCore/loader/CachedFont.cpp b/WebCore/loader/CachedFont.cpp index dfb9dd8..9cf152d 100644 --- a/WebCore/loader/CachedFont.cpp +++ b/WebCore/loader/CachedFont.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2009 Torch Mobile, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,12 +27,16 @@ #include "config.h" #include "CachedFont.h" +#if PLATFORM(CG) || PLATFORM(QT) || PLATFORM(GTK) || (PLATFORM(CHROMIUM) && (PLATFORM(WIN_OS) || PLATFORM(LINUX))) || PLATFORM(HAIKU) || PLATFORM(WINCE) +#define STORE_FONT_CUSTOM_PLATFORM_DATA +#endif + #include "Cache.h" #include "CachedResourceClient.h" #include "CachedResourceClientWalker.h" #include "DOMImplementation.h" #include "FontPlatformData.h" -#if PLATFORM(CG) || PLATFORM(QT) || PLATFORM(GTK) || (PLATFORM(CHROMIUM) && (PLATFORM(WIN_OS) || PLATFORM(LINUX))) +#ifdef STORE_FONT_CUSTOM_PLATFORM_DATA #include "FontCustomPlatformData.h" #endif #include "TextResourceDecoder.h" @@ -60,7 +65,7 @@ CachedFont::CachedFont(const String &url) CachedFont::~CachedFont() { -#if PLATFORM(CG) || PLATFORM(QT) || PLATFORM(GTK) || (PLATFORM(CHROMIUM) && (PLATFORM(WIN_OS) || PLATFORM(LINUX))) +#ifdef STORE_FONT_CUSTOM_PLATFORM_DATA delete m_fontData; #endif } @@ -98,7 +103,7 @@ void CachedFont::beginLoadIfNeeded(DocLoader* dl) bool CachedFont::ensureCustomFontData() { -#if PLATFORM(CG) || PLATFORM(QT) || PLATFORM(GTK) || (PLATFORM(CHROMIUM) && (PLATFORM(WIN_OS) || PLATFORM(LINUX))) +#ifdef STORE_FONT_CUSTOM_PLATFORM_DATA #if ENABLE(SVG_FONTS) ASSERT(!m_isSVGFont); #endif @@ -117,7 +122,7 @@ FontPlatformData CachedFont::platformDataFromCustomData(float size, bool bold, b if (m_externalSVGDocument) return FontPlatformData(size, bold, italic); #endif -#if PLATFORM(CG) || PLATFORM(QT) || PLATFORM(GTK) || (PLATFORM(CHROMIUM) && (PLATFORM(WIN_OS) || PLATFORM(LINUX))) +#ifdef STORE_FONT_CUSTOM_PLATFORM_DATA ASSERT(m_fontData); return m_fontData->fontPlatformData(static_cast(size), bold, italic, renderingMode); #else @@ -173,7 +178,7 @@ SVGFontElement* CachedFont::getSVGFontById(const String& fontName) const void CachedFont::allClientsRemoved() { -#if PLATFORM(CG) || PLATFORM(QT) || PLATFORM(GTK) || (PLATFORM(CHROMIUM) && (PLATFORM(WIN_OS) || PLATFORM(LINUX))) +#ifdef STORE_FONT_CUSTOM_PLATFORM_DATA if (m_fontData) { delete m_fontData; m_fontData = 0; diff --git a/WebCore/loader/CachedResource.cpp b/WebCore/loader/CachedResource.cpp index 478873f..43de633 100644 --- a/WebCore/loader/CachedResource.cpp +++ b/WebCore/loader/CachedResource.cpp @@ -59,7 +59,7 @@ CachedResource::CachedResource(const String& url, Type type) , m_docLoader(0) , m_handleCount(0) , m_resourceToRevalidate(0) - , m_isBeingRevalidated(false) + , m_proxyResource(0) { #ifndef NDEBUG cachedResourceLeakCounter.increment(); @@ -89,6 +89,8 @@ CachedResource::CachedResource(const String& url, Type type) CachedResource::~CachedResource() { + ASSERT(!m_resourceToRevalidate); // Should be true because canDelete() checks this. + ASSERT(canDelete()); ASSERT(!inCache()); ASSERT(!m_deleted); ASSERT(url().isNull() || cache()->resourceForURL(url()) != this); @@ -97,9 +99,6 @@ CachedResource::~CachedResource() cachedResourceLeakCounter.decrement(); #endif - if (m_resourceToRevalidate) - m_resourceToRevalidate->m_isBeingRevalidated = false; - if (m_docLoader) m_docLoader->removeCachedResource(this); } @@ -298,18 +297,26 @@ void CachedResource::setResourceToRevalidate(CachedResource* resource) ASSERT(resource); ASSERT(!m_resourceToRevalidate); ASSERT(resource != this); - ASSERT(!resource->m_isBeingRevalidated); ASSERT(m_handlesToRevalidate.isEmpty()); ASSERT(resource->type() == type()); - resource->m_isBeingRevalidated = true; + + // The following assert should be investigated whenever it occurs. Although it should never fire, it currently does in rare circumstances. + // https://bugs.webkit.org/show_bug.cgi?id=28604. + // So the code needs to be robust to this assert failing thus the "if (m_resourceToRevalidate->m_proxyResource == this)" in CachedResource::clearResourceToRevalidate. + ASSERT(!resource->m_proxyResource); + + resource->m_proxyResource = this; m_resourceToRevalidate = resource; } void CachedResource::clearResourceToRevalidate() { ASSERT(m_resourceToRevalidate); - m_resourceToRevalidate->m_isBeingRevalidated = false; - m_resourceToRevalidate->deleteIfPossible(); + // A resource may start revalidation before this method has been called, so check that this resource is still the proxy resource before clearing it out. + if (m_resourceToRevalidate->m_proxyResource == this) { + m_resourceToRevalidate->m_proxyResource = 0; + m_resourceToRevalidate->deleteIfPossible(); + } m_handlesToRevalidate.clear(); m_resourceToRevalidate = 0; deleteIfPossible(); @@ -403,7 +410,7 @@ bool CachedResource::mustRevalidate(CachePolicy cachePolicy) const bool CachedResource::isSafeToMakePurgeable() const { - return !hasClients() && !m_isBeingRevalidated && !m_resourceToRevalidate; + return !hasClients() && !m_proxyResource && !m_resourceToRevalidate; } bool CachedResource::makePurgeable(bool purgeable) diff --git a/WebCore/loader/CachedResource.h b/WebCore/loader/CachedResource.h index babdf89..05d24fc 100644 --- a/WebCore/loader/CachedResource.h +++ b/WebCore/loader/CachedResource.h @@ -129,7 +129,7 @@ public: // while still being referenced. This means the object should delete itself // if the number of clients observing it ever drops to 0. // The resource can be brought back to cache after successful revalidation. - void setInCache(bool b) { m_inCache = b; if (b) m_isBeingRevalidated = false; } + void setInCache(bool inCache) { m_inCache = inCache; } bool inCache() const { return m_inCache; } void setInLiveDecodedResourcesList(bool b) { m_inLiveDecodedResourcesList = b; } @@ -142,7 +142,7 @@ public: void setResponse(const ResourceResponse&); const ResourceResponse& response() const { return m_response; } - bool canDelete() const { return !hasClients() && !m_request && !m_preloadCount && !m_handleCount && !m_resourceToRevalidate && !m_isBeingRevalidated; } + bool canDelete() const { return !hasClients() && !m_request && !m_preloadCount && !m_handleCount && !m_resourceToRevalidate && !m_proxyResource; } bool isExpired() const; @@ -251,7 +251,10 @@ private: // to to be clients of m_resourceToRevalidate and the resource is deleted. If not, the field is zeroed and this // resources becomes normal resource load. CachedResource* m_resourceToRevalidate; - bool m_isBeingRevalidated; + + // If this field is non-null, the resource has a proxy for checking whether it is still up to date (see m_resourceToRevalidate). + CachedResource* m_proxyResource; + // These handles will need to be updated to point to the m_resourceToRevalidate in case we get 304 response. HashSet m_handlesToRevalidate; }; diff --git a/WebCore/loader/CachedResourceClient.h b/WebCore/loader/CachedResourceClient.h index 2e0b15b..dd9bb94 100644 --- a/WebCore/loader/CachedResourceClient.h +++ b/WebCore/loader/CachedResourceClient.h @@ -25,6 +25,8 @@ #ifndef CachedResourceClient_h #define CachedResourceClient_h +#include + #if ENABLE(XBL) namespace XBL { class XBLDocument; @@ -48,7 +50,7 @@ namespace WebCore { * inherit from this class and overload one of the 3 functions * */ - class CachedResourceClient + class CachedResourceClient : public FastAllocBase { public: virtual ~CachedResourceClient() { } diff --git a/WebCore/loader/CachedResourceHandle.h b/WebCore/loader/CachedResourceHandle.h index 13c03c7..9d45b94 100644 --- a/WebCore/loader/CachedResourceHandle.h +++ b/WebCore/loader/CachedResourceHandle.h @@ -38,7 +38,8 @@ namespace WebCore { bool operator!() const { return !m_resource; } // This conversion operator allows implicit conversion to bool but not to other integer types. - typedef CachedResource* CachedResourceHandleBase::*UnspecifiedBoolType; + // Parenthesis is needed for winscw compiler to resolve class qualifier in this case. + typedef CachedResource* (CachedResourceHandleBase::*UnspecifiedBoolType); operator UnspecifiedBoolType() const { return m_resource ? &CachedResourceHandleBase::m_resource : 0; } protected: diff --git a/WebCore/loader/CrossOriginPreflightResultCache.cpp b/WebCore/loader/CrossOriginPreflightResultCache.cpp index 4bd05b2..cea66b1 100644 --- a/WebCore/loader/CrossOriginPreflightResultCache.cpp +++ b/WebCore/loader/CrossOriginPreflightResultCache.cpp @@ -30,6 +30,8 @@ #include "CrossOriginAccessControl.h" #include "ResourceResponse.h" #include +#include +#include namespace WebCore { @@ -64,8 +66,7 @@ static void addToAccessControlAllowList(const String& string, unsigned start, un while (end && isSpaceOrNewline((*stringImpl)[end])) --end; - // substringCopy() is called on the strings because the cache is accessed on multiple threads. - set.add(string.substringCopy(start, end - start + 1)); + set.add(string.substring(start, end - start + 1)); } template @@ -137,20 +138,20 @@ bool CrossOriginPreflightResultCacheItem::allowsRequest(bool includeCredentials, CrossOriginPreflightResultCache& CrossOriginPreflightResultCache::shared() { - AtomicallyInitializedStatic(CrossOriginPreflightResultCache&, cache = *new CrossOriginPreflightResultCache); + DEFINE_STATIC_LOCAL(CrossOriginPreflightResultCache, cache, ()); + ASSERT(isMainThread()); return cache; } void CrossOriginPreflightResultCache::appendEntry(const String& origin, const KURL& url, CrossOriginPreflightResultCacheItem* preflightResult) { - MutexLocker lock(m_mutex); - // Note that the entry may already be present in the HashMap if another thread is accessing the same location. - m_preflightHashMap.set(std::make_pair(origin.copy(), url.copy()), preflightResult); + ASSERT(isMainThread()); + m_preflightHashMap.set(std::make_pair(origin, url), preflightResult); } bool CrossOriginPreflightResultCache::canSkipPreflight(const String& origin, const KURL& url, bool includeCredentials, const String& method, const HTTPHeaderMap& requestHeaders) { - MutexLocker lock(m_mutex); + ASSERT(isMainThread()); CrossOriginPreflightResultHashMap::iterator cacheIt = m_preflightHashMap.find(std::make_pair(origin, url)); if (cacheIt == m_preflightHashMap.end()) return false; @@ -165,7 +166,7 @@ bool CrossOriginPreflightResultCache::canSkipPreflight(const String& origin, con void CrossOriginPreflightResultCache::empty() { - MutexLocker lock(m_mutex); + ASSERT(isMainThread()); deleteAllValues(m_preflightHashMap); m_preflightHashMap.clear(); } diff --git a/WebCore/loader/CrossOriginPreflightResultCache.h b/WebCore/loader/CrossOriginPreflightResultCache.h index f71d1c8..97b526a 100644 --- a/WebCore/loader/CrossOriginPreflightResultCache.h +++ b/WebCore/loader/CrossOriginPreflightResultCache.h @@ -72,7 +72,6 @@ namespace WebCore { typedef HashMap, CrossOriginPreflightResultCacheItem*> CrossOriginPreflightResultHashMap; CrossOriginPreflightResultHashMap m_preflightHashMap; - Mutex m_mutex; }; } // namespace WebCore diff --git a/WebCore/loader/DocLoader.cpp b/WebCore/loader/DocLoader.cpp index 9c11a88..9e97354 100644 --- a/WebCore/loader/DocLoader.cpp +++ b/WebCore/loader/DocLoader.cpp @@ -200,6 +200,41 @@ bool DocLoader::canRequest(CachedResource::Type type, const KURL& url) ASSERT_NOT_REACHED(); break; } + + // Given that the load is allowed by the same-origin policy, we should + // check whether the load passes the mixed-content policy. + // + // Note: Currently, we always allow mixed content, but we generate a + // callback to the FrameLoaderClient in case the embedder wants to + // update any security indicators. + // + switch (type) { + case CachedResource::Script: +#if ENABLE(XSLT) + case CachedResource::XSLStyleSheet: +#endif +#if ENABLE(XBL) + case CachedResource::XBL: +#endif + // These resource can inject script into the current document. + if (Frame* f = frame()) + f->loader()->checkIfRunInsecureContent(m_doc->securityOrigin(), url); + break; + case CachedResource::ImageResource: + case CachedResource::CSSStyleSheet: + case CachedResource::FontResource: { + // These resources can corrupt only the frame's pixels. + if (Frame* f = frame()) { + Frame* top = f->tree()->top(); + top->loader()->checkIfDisplayInsecureContent(top->document()->securityOrigin(), url); + } + break; + } + default: + ASSERT_NOT_REACHED(); + break; + } + // FIXME: Consider letting the embedder block mixed content loads. return true; } @@ -224,7 +259,7 @@ CachedResource* DocLoader::requestResource(CachedResource::Type type, const Stri if (resource) { // Check final URL of resource to catch redirects. // See . - if (!canRequest(type, KURL(resource->url()))) + if (fullURL != resource->url() && !canRequest(type, KURL(ParsedURLString, resource->url()))) return 0; m_documentResources.set(resource->url(), resource); diff --git a/WebCore/loader/DocumentLoader.cpp b/WebCore/loader/DocumentLoader.cpp index 4ec69a7..5ca6e58 100644 --- a/WebCore/loader/DocumentLoader.cpp +++ b/WebCore/loader/DocumentLoader.cpp @@ -148,7 +148,6 @@ DocumentLoader::DocumentLoader(const ResourceRequest& req, const SubstituteData& , m_gotFirstByte(false) , m_primaryLoadComplete(false) , m_isClientRedirect(false) - , m_loadingFromCachedPage(false) , m_stopRecordingResponses(false) , m_substituteResourceDeliveryTimer(this, &DocumentLoader::substituteResourceDeliveryTimerFired) , m_didCreateGlobalHistoryEntry(false) @@ -278,7 +277,7 @@ void DocumentLoader::stopLoading(DatabasePolicy databasePolicy) Document* doc = m_frame->document(); if (loading || doc->parsing()) - m_frame->loader()->stopLoading(false, databasePolicy); + m_frame->loader()->stopLoading(UnloadEventPolicyNone, databasePolicy); } // Always cancel multipart loaders @@ -568,7 +567,7 @@ void DocumentLoader::getSubresources(Vector >& subre const DocLoader::DocumentResourceMap& allResources = document->docLoader()->allCachedResources(); DocLoader::DocumentResourceMap::const_iterator end = allResources.end(); for (DocLoader::DocumentResourceMap::const_iterator it = allResources.begin(); it != end; ++it) { - RefPtr subresource = this->subresource(KURL(it->second->url())); + RefPtr subresource = this->subresource(KURL(ParsedURLString, it->second->url())); if (subresource) subresources.append(subresource.release()); } @@ -697,16 +696,6 @@ bool DocumentLoader::urlForHistoryReflectsFailure() const return m_substituteData.isValid() || m_response.httpStatusCode() >= 400; } -void DocumentLoader::loadFromCachedPage(PassRefPtr cachedPage) -{ - LOG(PageCache, "WebCorePageCache: DocumentLoader %p loading from cached page %p", this, cachedPage.get()); - - prepareForLoadStart(); - setLoadingFromCachedPage(true); - setCommitted(true); - frameLoader()->commitProvisionalLoad(cachedPage); -} - const KURL& DocumentLoader::originalURL() const { return m_originalRequestCopy.url(); diff --git a/WebCore/loader/DocumentLoader.h b/WebCore/loader/DocumentLoader.h index 134d954..1220a0e 100644 --- a/WebCore/loader/DocumentLoader.h +++ b/WebCore/loader/DocumentLoader.h @@ -43,8 +43,11 @@ namespace WebCore { class Archive; class ArchiveResource; class ArchiveResourceCollection; +<<<<<<< HEAD:WebCore/loader/DocumentLoader.h #endif class CachedPage; +======= +>>>>>>> webkit.org at 49305:WebCore/loader/DocumentLoader.h class Frame; class FrameLoader; class MainResourceLoader; @@ -174,10 +177,6 @@ namespace WebCore { bool didCreateGlobalHistoryEntry() const { return m_didCreateGlobalHistoryEntry; } void setDidCreateGlobalHistoryEntry(bool didCreateGlobalHistoryEntry) { m_didCreateGlobalHistoryEntry = didCreateGlobalHistoryEntry; } - void loadFromCachedPage(PassRefPtr); - void setLoadingFromCachedPage(bool loading) { m_loadingFromCachedPage = loading; } - bool isLoadingFromCachedPage() const { return m_loadingFromCachedPage; } - void setDefersLoading(bool); bool startLoadingMainResource(unsigned long identifier); @@ -264,7 +263,6 @@ namespace WebCore { bool m_gotFirstByte; bool m_primaryLoadComplete; bool m_isClientRedirect; - bool m_loadingFromCachedPage; String m_pageTitle; diff --git a/WebCore/loader/DocumentThreadableLoader.cpp b/WebCore/loader/DocumentThreadableLoader.cpp index dd5ca76..8a223fd 100644 --- a/WebCore/loader/DocumentThreadableLoader.cpp +++ b/WebCore/loader/DocumentThreadableLoader.cpp @@ -32,8 +32,9 @@ #include "DocumentThreadableLoader.h" #include "AuthenticationChallenge.h" +#include "CrossOriginAccessControl.h" +#include "CrossOriginPreflightResultCache.h" #include "Document.h" -#include "DocumentThreadableLoader.h" #include "Frame.h" #include "FrameLoader.h" #include "ResourceRequest.h" @@ -43,61 +44,106 @@ namespace WebCore { -void DocumentThreadableLoader::loadResourceSynchronously(Document* document, const ResourceRequest& request, ThreadableLoaderClient& client, StoredCredentials storedCredentials) +void DocumentThreadableLoader::loadResourceSynchronously(Document* document, const ResourceRequest& request, ThreadableLoaderClient& client, const ThreadableLoaderOptions& options) { - bool sameOriginRequest = document->securityOrigin()->canRequest(request.url()); - - Vector data; - ResourceError error; - ResourceResponse response; - unsigned long identifier = std::numeric_limits::max(); - if (document->frame()) - identifier = document->frame()->loader()->loadResourceSynchronously(request, storedCredentials, error, response, data); - - // No exception for file:/// resources, see . - // Also, if we have an HTTP response, then it wasn't a network error in fact. - if (!error.isNull() && !request.url().isLocalFile() && response.httpStatusCode() <= 0) { - client.didFail(error); - return; - } - - // FIXME: This check along with the one in willSendRequest is specific to xhr and - // should be made more generic. - if (sameOriginRequest && !document->securityOrigin()->canRequest(response.url())) { - client.didFailRedirectCheck(); - return; - } - - client.didReceiveResponse(response); - - const char* bytes = static_cast(data.data()); - int len = static_cast(data.size()); - client.didReceiveData(bytes, len); - - client.didFinishLoading(identifier); + // The loader will be deleted as soon as this function exits. + RefPtr loader = adoptRef(new DocumentThreadableLoader(document, &client, LoadSynchronously, request, options)); + ASSERT(loader->hasOneRef()); } -PassRefPtr DocumentThreadableLoader::create(Document* document, ThreadableLoaderClient* client, const ResourceRequest& request, LoadCallbacks callbacksSetting, ContentSniff contentSniff, StoredCredentials storedCredentials, CrossOriginRedirectPolicy crossOriginRedirectPolicy) +PassRefPtr DocumentThreadableLoader::create(Document* document, ThreadableLoaderClient* client, const ResourceRequest& request, const ThreadableLoaderOptions& options) { - ASSERT(document); - RefPtr loader = adoptRef(new DocumentThreadableLoader(document, client, request, callbacksSetting, contentSniff, storedCredentials, crossOriginRedirectPolicy)); + RefPtr loader = adoptRef(new DocumentThreadableLoader(document, client, LoadAsynchronously, request, options)); if (!loader->m_loader) loader = 0; return loader.release(); } -DocumentThreadableLoader::DocumentThreadableLoader(Document* document, ThreadableLoaderClient* client, const ResourceRequest& request, LoadCallbacks callbacksSetting, ContentSniff contentSniff, StoredCredentials storedCredentials, CrossOriginRedirectPolicy crossOriginRedirectPolicy) +DocumentThreadableLoader::DocumentThreadableLoader(Document* document, ThreadableLoaderClient* client, BlockingBehavior blockingBehavior, const ResourceRequest& request, const ThreadableLoaderOptions& options) : m_client(client) , m_document(document) - , m_allowStoredCredentials(storedCredentials == AllowStoredCredentials) + , m_options(options) , m_sameOriginRequest(document->securityOrigin()->canRequest(request.url())) - , m_denyCrossOriginRedirect(crossOriginRedirectPolicy == DenyCrossOriginRedirect) + , m_async(blockingBehavior == LoadAsynchronously) { ASSERT(document); ASSERT(client); - ASSERT(storedCredentials == AllowStoredCredentials || storedCredentials == DoNotAllowStoredCredentials); - ASSERT(crossOriginRedirectPolicy == DenyCrossOriginRedirect || crossOriginRedirectPolicy == AllowCrossOriginRedirect); - m_loader = SubresourceLoader::create(document->frame(), this, request, false, callbacksSetting == SendLoadCallbacks, contentSniff == SniffContent); + + if (m_sameOriginRequest || m_options.crossOriginRequestPolicy == AllowCrossOriginRequests) { + bool skipCanLoadCheck = false; + loadRequest(request, skipCanLoadCheck); + return; + } + + if (m_options.crossOriginRequestPolicy == DenyCrossOriginRequests) { + m_client->didFail(ResourceError()); + return; + } + + ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl); + + if (!m_options.forcePreflight && isSimpleCrossOriginAccessRequest(request.httpMethod(), request.httpHeaderFields())) + makeSimpleCrossOriginAccessRequest(request); + else { + m_actualRequest.set(new ResourceRequest(request)); + m_actualRequest->setAllowCookies(m_options.allowCredentials); + + if (CrossOriginPreflightResultCache::shared().canSkipPreflight(document->securityOrigin()->toString(), request.url(), m_options.allowCredentials, request.httpMethod(), request.httpHeaderFields())) + preflightSuccess(); + else + makeCrossOriginAccessRequestWithPreflight(request); + } +} + +void DocumentThreadableLoader::makeSimpleCrossOriginAccessRequest(const ResourceRequest& request) +{ + ASSERT(isSimpleCrossOriginAccessRequest(request.httpMethod(), request.httpHeaderFields())); + + // Cross-origin requests are only defined for HTTP. We would catch this when checking response headers later, but there is no reason to send a request that's guaranteed to be denied. + if (!request.url().protocolInHTTPFamily()) { + m_client->didFail(ResourceError()); + return; + } + + // Make a copy of the passed request so that we can modify some details. + ResourceRequest crossOriginRequest(request); + crossOriginRequest.removeCredentials(); + crossOriginRequest.setAllowCookies(m_options.allowCredentials); + crossOriginRequest.setHTTPOrigin(m_document->securityOrigin()->toString()); + + bool skipCanLoadCheck = false; + loadRequest(crossOriginRequest, skipCanLoadCheck); +} + +void DocumentThreadableLoader::makeCrossOriginAccessRequestWithPreflight(const ResourceRequest& request) +{ + ResourceRequest preflightRequest(request.url()); + preflightRequest.removeCredentials(); + preflightRequest.setHTTPOrigin(m_document->securityOrigin()->toString()); + preflightRequest.setAllowCookies(m_options.allowCredentials); + preflightRequest.setHTTPMethod("OPTIONS"); + preflightRequest.setHTTPHeaderField("Access-Control-Request-Method", request.httpMethod()); + + const HTTPHeaderMap& requestHeaderFields = request.httpHeaderFields(); + + if (requestHeaderFields.size() > 0) { + Vector headerBuffer; + HTTPHeaderMap::const_iterator it = requestHeaderFields.begin(); + append(headerBuffer, it->first); + ++it; + + HTTPHeaderMap::const_iterator end = requestHeaderFields.end(); + for (; it != end; ++it) { + headerBuffer.append(','); + headerBuffer.append(' '); + append(headerBuffer, it->first); + } + + preflightRequest.setHTTPHeaderField("Access-Control-Request-Headers", String::adopt(headerBuffer)); + } + + bool skipCanLoadCheck = false; + loadRequest(preflightRequest, skipCanLoadCheck); } DocumentThreadableLoader::~DocumentThreadableLoader() @@ -122,8 +168,7 @@ void DocumentThreadableLoader::willSendRequest(SubresourceLoader* loader, Resour ASSERT(m_client); ASSERT_UNUSED(loader, loader == m_loader); - // FIXME: This needs to be fixed to follow the redirect correctly even for cross-domain requests. - if (m_denyCrossOriginRedirect && !m_document->securityOrigin()->canRequest(request.url())) { + if (!isAllowedRedirect(request.url())) { RefPtr protect(this); m_client->didFailRedirectCheck(); request = ResourceRequest(); @@ -143,7 +188,31 @@ void DocumentThreadableLoader::didReceiveResponse(SubresourceLoader* loader, con ASSERT(m_client); ASSERT_UNUSED(loader, loader == m_loader); - m_client->didReceiveResponse(response); + if (m_actualRequest) { + if (!passesAccessControlCheck(response, m_options.allowCredentials, m_document->securityOrigin())) { + preflightFailure(); + return; + } + + OwnPtr preflightResult(new CrossOriginPreflightResultCacheItem(m_options.allowCredentials)); + if (!preflightResult->parse(response) + || !preflightResult->allowsCrossOriginMethod(m_actualRequest->httpMethod()) + || !preflightResult->allowsCrossOriginHeaders(m_actualRequest->httpHeaderFields())) { + preflightFailure(); + return; + } + + CrossOriginPreflightResultCache::shared().appendEntry(m_document->securityOrigin()->toString(), m_actualRequest->url(), preflightResult.release()); + } else { + if (!m_sameOriginRequest && m_options.crossOriginRequestPolicy == UseAccessControl) { + if (!passesAccessControlCheck(response, m_options.allowCredentials, m_document->securityOrigin())) { + m_client->didFail(ResourceError()); + return; + } + } + + m_client->didReceiveResponse(response); + } } void DocumentThreadableLoader::didReceiveData(SubresourceLoader* loader, const char* data, int lengthReceived) @@ -158,7 +227,17 @@ void DocumentThreadableLoader::didFinishLoading(SubresourceLoader* loader) { ASSERT(loader == m_loader); ASSERT(m_client); - m_client->didFinishLoading(loader->identifier()); + didFinishLoading(loader->identifier()); +} + +void DocumentThreadableLoader::didFinishLoading(unsigned long identifier) +{ + if (m_actualRequest) { + ASSERT(!m_sameOriginRequest); + ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl); + preflightSuccess(); + } else + m_client->didFinishLoading(identifier); } void DocumentThreadableLoader::didFail(SubresourceLoader* loader, const ResourceError& error) @@ -172,9 +251,9 @@ void DocumentThreadableLoader::didFail(SubresourceLoader* loader, const Resource bool DocumentThreadableLoader::getShouldUseCredentialStorage(SubresourceLoader* loader, bool& shouldUseCredentialStorage) { - ASSERT_UNUSED(loader, loader == m_loader); + ASSERT_UNUSED(loader, loader == m_loader || !m_loader); - if (!m_allowStoredCredentials) { + if (!m_options.allowCredentials) { shouldUseCredentialStorage = false; return true; } @@ -200,4 +279,76 @@ void DocumentThreadableLoader::receivedCancellation(SubresourceLoader* loader, c m_client->didReceiveAuthenticationCancellation(challenge.failureResponse()); } +void DocumentThreadableLoader::preflightSuccess() +{ + OwnPtr actualRequest; + actualRequest.swap(m_actualRequest); + + bool skipCanLoadCheck = true; // ok to skip load check since we already asked about the preflight request + loadRequest(*actualRequest, skipCanLoadCheck); +} + +void DocumentThreadableLoader::preflightFailure() +{ + m_client->didFail(ResourceError()); +} + +void DocumentThreadableLoader::loadRequest(const ResourceRequest& request, bool skipCanLoadCheck) +{ + if (m_async) { + // Don't sniff content or send load callbacks for the preflight request. + bool sendLoadCallbacks = m_options.sendLoadCallbacks && !m_actualRequest; + bool sniffContent = m_options.sniffContent && !m_actualRequest; + + // Clear the loader so that any callbacks from SubresourceLoader::create will not have the old loader. + m_loader = 0; + m_loader = SubresourceLoader::create(m_document->frame(), this, request, skipCanLoadCheck, sendLoadCallbacks, sniffContent); + return; + } + + // FIXME: ThreadableLoaderOptions.sniffContent is not supported for synchronous requests. + StoredCredentials storedCredentials = m_options.allowCredentials ? AllowStoredCredentials : DoNotAllowStoredCredentials; + + Vector data; + ResourceError error; + ResourceResponse response; + unsigned long identifier = std::numeric_limits::max(); + if (m_document->frame()) + identifier = m_document->frame()->loader()->loadResourceSynchronously(request, storedCredentials, error, response, data); + + // No exception for file:/// resources, see . + // Also, if we have an HTTP response, then it wasn't a network error in fact. + if (!error.isNull() && !request.url().isLocalFile() && response.httpStatusCode() <= 0) { + m_client->didFail(error); + return; + } + + // FIXME: FrameLoader::loadSynchronously() does not tell us whether a redirect happened or not, so we guess by comparing the + // request and response URLs. This isn't a perfect test though, since a server can serve a redirect to the same URL that was + // requested. + if (request.url() != response.url() && !isAllowedRedirect(response.url())) { + m_client->didFailRedirectCheck(); + return; + } + + didReceiveResponse(0, response); + + const char* bytes = static_cast(data.data()); + int len = static_cast(data.size()); + didReceiveData(0, bytes, len); + + didFinishLoading(identifier); +} + +bool DocumentThreadableLoader::isAllowedRedirect(const KURL& url) +{ + if (m_options.crossOriginRequestPolicy == AllowCrossOriginRequests) + return true; + + // FIXME: We need to implement access control for each redirect. This will require some refactoring though, because the code + // that processes redirects doesn't know about access control and expects a synchronous answer from its client about whether + // a redirect should proceed. + return m_sameOriginRequest && m_document->securityOrigin()->canRequest(url); +} + } // namespace WebCore diff --git a/WebCore/loader/DocumentThreadableLoader.h b/WebCore/loader/DocumentThreadableLoader.h index 465475f..64b1a22 100644 --- a/WebCore/loader/DocumentThreadableLoader.h +++ b/WebCore/loader/DocumentThreadableLoader.h @@ -33,19 +33,21 @@ #include "SubresourceLoaderClient.h" #include "ThreadableLoader.h" +#include #include #include #include namespace WebCore { class Document; + class KURL; struct ResourceRequest; class ThreadableLoaderClient; 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, CrossOriginRedirectPolicy); + static void loadResourceSynchronously(Document*, const ResourceRequest&, ThreadableLoaderClient&, const ThreadableLoaderOptions&); + static PassRefPtr create(Document*, ThreadableLoaderClient*, const ResourceRequest&, const ThreadableLoaderOptions&); virtual ~DocumentThreadableLoader(); virtual void cancel(); @@ -58,7 +60,13 @@ namespace WebCore { virtual void derefThreadableLoader() { deref(); } private: - DocumentThreadableLoader(Document*, ThreadableLoaderClient*, const ResourceRequest&, LoadCallbacks, ContentSniff, StoredCredentials, CrossOriginRedirectPolicy); + enum BlockingBehavior { + LoadSynchronously, + LoadAsynchronously + }; + + DocumentThreadableLoader(Document*, ThreadableLoaderClient*, BlockingBehavior blockingBehavior, const ResourceRequest&, const ThreadableLoaderOptions& options); + virtual void willSendRequest(SubresourceLoader*, ResourceRequest&, const ResourceResponse& redirectResponse); virtual void didSendData(SubresourceLoader*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent); @@ -71,12 +79,22 @@ namespace WebCore { virtual void didReceiveAuthenticationChallenge(SubresourceLoader*, const AuthenticationChallenge&); virtual void receivedCancellation(SubresourceLoader*, const AuthenticationChallenge&); + void didFinishLoading(unsigned long identifier); + void makeSimpleCrossOriginAccessRequest(const ResourceRequest& request); + void makeCrossOriginAccessRequestWithPreflight(const ResourceRequest& request); + void preflightSuccess(); + void preflightFailure(); + + void loadRequest(const ResourceRequest&, bool skipCanLoadCheck); + bool isAllowedRedirect(const KURL&); + RefPtr m_loader; ThreadableLoaderClient* m_client; Document* m_document; - bool m_allowStoredCredentials; + ThreadableLoaderOptions m_options; bool m_sameOriginRequest; - bool m_denyCrossOriginRedirect; + bool m_async; + OwnPtr m_actualRequest; // non-null during Access Control preflight checks }; } // namespace WebCore diff --git a/WebCore/loader/EmptyClients.h b/WebCore/loader/EmptyClients.h index 3f70c43..d9e09fb 100644 --- a/WebCore/loader/EmptyClients.h +++ b/WebCore/loader/EmptyClients.h @@ -39,6 +39,7 @@ #include "FormState.h" #include "FrameLoaderClient.h" #include "InspectorClient.h" +#include "PluginHalterClient.h" #include "ResourceError.h" #include "SharedBuffer.h" @@ -120,9 +121,10 @@ public: virtual void scroll(const IntSize&, const IntRect&, const IntRect&) { } virtual IntPoint screenToWindow(const IntPoint& p) const { return p; } virtual IntRect windowToScreen(const IntRect& r) const { return r; } - virtual PlatformWidget platformWindow() const { return 0; } + virtual PlatformPageClient platformPageClient() const { return 0; } virtual void contentsSizeChanged(Frame*, const IntSize&) const { } + virtual void scrollbarsModeDidChange() const { } virtual void mouseDidMoveOverElement(const HitTestResult&, unsigned) { } virtual void setToolTip(const String&, TextDirection) { } @@ -137,6 +139,10 @@ public: virtual void reachedMaxAppCacheSize(int64_t) { } #endif +#if ENABLE(NOTIFICATIONS) + virtual NotificationPresenter* notificationPresenter() const { return 0; } +#endif + virtual void runOpenPanel(Frame*, PassRefPtr) { } virtual void formStateDidChange(const Node*) { } @@ -280,7 +286,8 @@ public: #endif virtual void saveViewStateToItem(HistoryItem*) { } virtual bool canCachePage() const { return false; } - + virtual void didDisplayInsecureContent() { } + virtual void didRunInsecureContent(SecurityOrigin*) { } virtual PassRefPtr createFrame(const KURL&, const String&, HTMLFrameOwnerElement*, const String&, bool, int, int) { 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; } @@ -414,6 +421,7 @@ public: }; +#if ENABLE(CONTEXT_MENUS) class EmptyContextMenuClient : public ContextMenuClient { public: virtual ~EmptyContextMenuClient() { } @@ -434,7 +442,9 @@ public: virtual void searchWithSpotlight() { } #endif }; +#endif // ENABLE(CONTEXT_MENUS) +#if ENABLE(DRAG_SUPPORT) class EmptyDragClient : public DragClient { public: virtual ~EmptyDragClient() {} @@ -446,6 +456,7 @@ public: virtual DragImageRef createDragImageForLink(KURL&, const String&, Frame*) { return 0; } virtual void dragControllerDestroyed() { } }; +#endif // ENABLE(DRAG_SUPPORT) class EmptyInspectorClient : public InspectorClient { public: @@ -478,6 +489,12 @@ public: virtual void inspectorWindowObjectCleared() { } }; +class EmptyPluginHalterClient : public PluginHalterClient +{ +public: + virtual bool shouldHaltPlugin(Node*) const { return false; } +}; + } #endif // EmptyClients_h diff --git a/WebCore/loader/FTPDirectoryDocument.cpp b/WebCore/loader/FTPDirectoryDocument.cpp index ace4cfe..ee0f4ca 100644 --- a/WebCore/loader/FTPDirectoryDocument.cpp +++ b/WebCore/loader/FTPDirectoryDocument.cpp @@ -118,7 +118,7 @@ void FTPDirectoryTokenizer::appendEntry(const String& filename, const String& si rowElement->setAttribute("class", "ftpDirectoryEntryRow", ec); RefPtr element = m_doc->createElement(tdTag, false); - element->appendChild(new Text(m_doc, String(&noBreakSpace, 1)), ec); + element->appendChild(Text::create(m_doc, String(&noBreakSpace, 1)), ec); if (isDirectory) element->setAttribute("class", "ftpDirectoryIcon ftpDirectoryTypeDirectory", ec); else @@ -130,12 +130,12 @@ void FTPDirectoryTokenizer::appendEntry(const String& filename, const String& si rowElement->appendChild(element, ec); element = m_doc->createElement(tdTag, false); - element->appendChild(new Text(m_doc, date), ec); + element->appendChild(Text::create(m_doc, date), ec); element->setAttribute("class", "ftpDirectoryFileDate", ec); rowElement->appendChild(element, ec); element = m_doc->createElement(tdTag, false); - element->appendChild(new Text(m_doc, size), ec); + element->appendChild(Text::create(m_doc, size), ec); element->setAttribute("class", "ftpDirectoryFileSize", ec); rowElement->appendChild(element, ec); } @@ -152,7 +152,7 @@ PassRefPtr FTPDirectoryTokenizer::createTDForFilename(const String& fil RefPtr anchorElement = m_doc->createElement(aTag, false); anchorElement->setAttribute("href", fullURL, ec); - anchorElement->appendChild(new Text(m_doc, filename), ec); + anchorElement->appendChild(Text::create(m_doc, filename), ec); RefPtr tdElement = m_doc->createElement(tdTag, false); tdElement->appendChild(anchorElement, ec); diff --git a/WebCore/loader/FTPDirectoryDocument.h b/WebCore/loader/FTPDirectoryDocument.h index ecc6f73..b208c4e 100644 --- a/WebCore/loader/FTPDirectoryDocument.h +++ b/WebCore/loader/FTPDirectoryDocument.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,7 +35,7 @@ class FTPDirectoryDocument : public HTMLDocument { public: static PassRefPtr create(Frame* frame) { - return new FTPDirectoryDocument(frame); + return adoptRef(new FTPDirectoryDocument(frame)); } private: diff --git a/WebCore/loader/FTPDirectoryParser.cpp b/WebCore/loader/FTPDirectoryParser.cpp index 6573fb6..40bd714 100644 --- a/WebCore/loader/FTPDirectoryParser.cpp +++ b/WebCore/loader/FTPDirectoryParser.cpp @@ -57,6 +57,13 @@ static struct tm *gmtimeQt(const time_t *const timep, struct tm *result) #endif #endif +static inline FTPEntryType ParsingFailed(ListState& state) +{ + if (state.parsedOne || state.listStyle) /* junk if we fail to parse */ + return FTPJunkEntry; /* this time but had previously parsed sucessfully */ + return FTPMiscEntry; /* its part of a comment or error message */ +} + FTPEntryType parseOneFTPLine(const char* line, ListState& state, ListResult& result) { result.clear(); @@ -126,6 +133,9 @@ FTPEntryType parseOneFTPLine(const char* line, ListState& state, ListResult& res } } + if (!numtoks) + return ParsingFailed(state); + linelen_sans_wsp = &(tokens[numtoks-1][toklen[numtoks-1]]) - tokens[0]; if (numtoks == (sizeof(tokens)/sizeof(tokens[0])) ) { @@ -356,11 +366,16 @@ FTPEntryType parseOneFTPLine(const char* line, ListState& state, ListResult& res pos++; p++; } - if (lstyle && pos < (toklen[0]-1) && *p == ']') + if (lstyle && pos < (toklen[0]-1)) { + /* ']' was found and there is at least one character after it */ + ASSERT(*p == ']'); pos++; p++; tokmarker = pos; /* length of leading "[DIR1.DIR2.etc]" */ + } else { + /* not a CMU style listing */ + lstyle = 0; } } while (lstyle && pos < toklen[0] && *p != ';') @@ -387,7 +402,7 @@ FTPEntryType parseOneFTPLine(const char* line, ListState& state, ListResult& res pos -= tokmarker; /* => fnlength sans "[DIR1.DIR2.etc]" */ p = &(tokens[0][tokmarker]); /* offset of basename */ - if (!lstyle || pos > 80) /* VMS filenames can't be longer than that */ + if (!lstyle || pos == 0 || pos > 80) /* VMS filenames can't be longer than that */ { lstyle = 0; } @@ -780,7 +795,7 @@ FTPEntryType parseOneFTPLine(const char* line, ListState& state, ListResult& res state.parsedOne = true; state.listStyle = lstyle; - p = &(line[linelen_sans_wsp]); /* line end sans wsp */ + p = &(line[linelen]); /* line end */ result.caseSensitive = true; result.filename = tokens[3]; result.filenameLength = p - tokens[3]; @@ -788,29 +803,46 @@ FTPEntryType parseOneFTPLine(const char* line, ListState& state, ListResult& res if (*tokens[2] != '<') /* not or */ { + // try to handle correctly spaces at the beginning of the filename + // filesize (token[2]) must end at offset 38 + if (tokens[2] + toklen[2] - line == 38) { + result.filename = &(line[39]); + result.filenameLength = p - result.filename; + } result.type = FTPFileEntry; pos = toklen[2]; result.fileSize = String(tokens[2], pos); } - else if ((tokens[2][1]) != 'D') /* not */ - { - result.type = FTPJunkEntry; /* unknown until junc for sure */ - if (result.filenameLength > 4) + else { + // try to handle correctly spaces at the beginning of the filename + // token[2] must begin at offset 24, the length is 5 or 10 + // token[3] must begin at offset 39 or higher + if (tokens[2] - line == 24 && (toklen[2] == 5 || toklen[2] == 10) && + tokens[3] - line >= 39) { + result.filename = &(line[39]); + result.filenameLength = p - result.filename; + } + + if ((tokens[2][1]) != 'D') /* not */ { - p = result.filename; - for (pos = result.filenameLength - 4; pos > 0; pos--) + result.type = FTPJunkEntry; /* unknown until junc for sure */ + if (result.filenameLength > 4) { - if (p[0] == ' ' && p[3] == ' ' && p[2] == '>' && - (p[1] == '=' || p[1] == '-')) + p = result.filename; + for (pos = result.filenameLength - 4; pos > 0; pos--) { - result.type = FTPLinkEntry; - result.filenameLength = p - result.filename; - result.linkname = p + 4; - result.linknameLength = &(line[linelen_sans_wsp]) - - result.linkname; - break; + if (p[0] == ' ' && p[3] == ' ' && p[2] == '>' && + (p[1] == '=' || p[1] == '-')) + { + result.type = FTPLinkEntry; + result.filenameLength = p - result.filename; + result.linkname = p + 4; + result.linknameLength = &(line[linelen]) + - result.linkname; + break; + } + p++; } - p++; } } } @@ -821,8 +853,13 @@ FTPEntryType parseOneFTPLine(const char* line, ListState& state, ListResult& res result.modifiedTime.tm_mon--; result.modifiedTime.tm_mday = atoi(tokens[0]+3); result.modifiedTime.tm_year = atoi(tokens[0]+6); + /* if year has only two digits then assume that + 00-79 is 2000-2079 + 80-99 is 1980-1999 */ if (result.modifiedTime.tm_year < 80) - result.modifiedTime.tm_year += 100; + result.modifiedTime.tm_year += 2000; + else if (result.modifiedTime.tm_year < 100) + result.modifiedTime.tm_year += 1900; } result.modifiedTime.tm_hour = atoi(tokens[1]+0); @@ -974,6 +1011,8 @@ FTPEntryType parseOneFTPLine(const char* line, ListState& state, ListResult& res * "drwxr-xr-x 2 0 0 512 May 28 22:17 etc" */ + bool isOldHellsoft = false; + if (numtoks >= 6) { /* there are two perm formats (Hellsoft/NetWare and *IX strmode(3)). @@ -999,6 +1038,8 @@ FTPEntryType parseOneFTPLine(const char* line, ListState& state, ListResult& res { /* rest is FMA[S] or AFM[S] */ lstyle = 'U'; /* very likely one of the NetWare servers */ + if (toklen[0] == 10) + isOldHellsoft = true; } } } @@ -1063,7 +1104,7 @@ FTPEntryType parseOneFTPLine(const char* line, ListState& state, ListResult& res /* check that size is numeric */ p = tokens[tokmarker]; - for (pos = 0; lstyle && pos < toklen[tokmarker]; pos++) + for (unsigned int i = 0; lstyle && i < toklen[tokmarker]; ++i) { if (!isASCIIDigit(*p++)) lstyle = 0; @@ -1072,11 +1113,11 @@ FTPEntryType parseOneFTPLine(const char* line, ListState& state, ListResult& res { month_num = 0; p = tokens[tokmarker+1]; - for (pos = 0;pos < (12*3); pos+=3) + for (unsigned int i = 0; i < (12*3); i+=3) { - if (p[0] == month_names[pos+0] && - p[1] == month_names[pos+1] && - p[2] == month_names[pos+2]) + if (p[0] == month_names[i+0] && + p[1] == month_names[i+1] && + p[2] == month_names[i+2]) break; month_num++; } @@ -1084,8 +1125,8 @@ FTPEntryType parseOneFTPLine(const char* line, ListState& state, ListResult& res lstyle = 0; } } /* relative position test */ - } /* while (pos+5) < numtoks */ - } /* if (numtoks >= 4) */ + } /* for (pos = (numtoks-5); !lstyle && pos > 1; pos--) */ + } /* if (lstyle == 'U') */ if (lstyle == 'U') { @@ -1144,24 +1185,49 @@ FTPEntryType parseOneFTPLine(const char* line, ListState& state, ListResult& res } /* time/year */ - result.filename = tokens[tokmarker+4]; - result.filenameLength = (&(line[linelen_sans_wsp])) + // there is exacly 1 space between filename and previous token in all + // outputs except old Hellsoft + if (!isOldHellsoft) + result.filename = tokens[tokmarker+3] + toklen[tokmarker+3] + 1; + else + result.filename = tokens[tokmarker+4]; + + result.filenameLength = (&(line[linelen])) - (result.filename); if (result.type == FTPLinkEntry && result.filenameLength > 4) { - p = result.filename + 1; - for (pos = 1; pos < (result.filenameLength - 4); pos++) + /* First try to use result.fe_size to find " -> " sequence. + This can give proper result for cases like "aaa -> bbb -> ccc". */ + unsigned int fileSize = result.fileSize.toUInt(); + + if (result.filenameLength > (fileSize + 4) && + strncmp(result.filename + result.filenameLength - fileSize - 4, " -> ", 4) == 0) + { + result.linkname = result.filename + (result.filenameLength - fileSize); + result.linknameLength = (&(line[linelen])) - (result.linkname); + result.filenameLength -= fileSize + 4; + } + else { - if (*p == ' ' && p[1] == '-' && p[2] == '>' && p[3] == ' ') + /* Search for sequence " -> " from the end for case when there are + more occurrences. F.e. if ftpd returns "a -> b -> c" assume + "a -> b" as a name. Powerusers can remove unnecessary parts + manually but there is no way to follow the link when some + essential part is missing. */ + p = result.filename + (result.filenameLength - 5); + for (pos = (result.filenameLength - 5); pos > 0; pos--) { - result.linkname = p + 4; - result.linknameLength = (&(line[linelen_sans_wsp])) - - (result.linkname); - result.filenameLength = pos; - break; + if (strncmp(p, " -> ", 4) == 0) + { + result.linkname = p + 4; + result.linknameLength = (&(line[linelen])) + - (result.linkname); + result.filenameLength = pos; + break; + } + p--; } - p++; } } @@ -1618,9 +1684,7 @@ FTPEntryType parseOneFTPLine(const char* line, ListState& state, ListResult& res } /* if (linelen > 0) */ - if (state.parsedOne || state.listStyle) /* junk if we fail to parse */ - return FTPJunkEntry; /* this time but had previously parsed sucessfully */ - return FTPMiscEntry; /* its part of a comment or error message */ + return ParsingFailed(state); } } // namespace WebCore diff --git a/WebCore/loader/FrameLoader.cpp b/WebCore/loader/FrameLoader.cpp index c28040f..9dfefcd 100644 --- a/WebCore/loader/FrameLoader.cpp +++ b/WebCore/loader/FrameLoader.cpp @@ -73,6 +73,7 @@ #include "Page.h" #include "PageCache.h" #include "PageGroup.h" +#include "PageTransitionEvent.h" #include "PlaceholderDocument.h" #include "PluginData.h" #include "PluginDocument.h" @@ -89,6 +90,11 @@ #include "SecurityOrigin.h" #include "SegmentedString.h" #include "Settings.h" + +#if ENABLE(SHARED_WORKERS) +#include "SharedWorkerRepository.h" +#endif + #include "TextResourceDecoder.h" #include "WindowFeatures.h" #include "XMLHttpRequest.h" @@ -108,6 +114,7 @@ #include "SVGViewSpec.h" #endif +<<<<<<< HEAD:WebCore/loader/FrameLoader.cpp #ifdef ANDROID_INSTRUMENT #include "TimeCounter.h" #include "RenderArena.h" @@ -115,6 +122,10 @@ #if PLATFORM(ANDROID) #include "WebCoreFrameBridge.h" +======= +#if PLATFORM(MAC) || PLATFORM(WIN) +#define PAGE_CACHE_ACCEPTS_UNLOAD_HANDLERS +>>>>>>> webkit.org at 49305:WebCore/loader/FrameLoader.cpp #endif namespace WebCore { @@ -124,91 +135,12 @@ using namespace SVGNames; #endif using namespace HTMLNames; -struct ScheduledRedirection { - enum Type { redirection, locationChange, historyNavigation, formSubmission }; - - const Type type; - const double delay; - const String url; - const String referrer; - const FrameLoadRequest frameRequest; - const RefPtr event; - const RefPtr formState; - const int historySteps; - const bool lockHistory; - const bool lockBackForwardList; - const bool wasUserGesture; - const bool wasRefresh; - const bool wasDuringLoad; - - ScheduledRedirection(double delay, const String& url, bool lockHistory, bool lockBackForwardList, bool wasUserGesture, bool refresh) - : type(redirection) - , delay(delay) - , url(url) - , historySteps(0) - , lockHistory(lockHistory) - , lockBackForwardList(lockBackForwardList) - , wasUserGesture(wasUserGesture) - , wasRefresh(refresh) - , wasDuringLoad(false) - { - ASSERT(!url.isEmpty()); - } - - ScheduledRedirection(const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool wasUserGesture, bool refresh, bool duringLoad) - : type(locationChange) - , delay(0) - , url(url) - , referrer(referrer) - , historySteps(0) - , lockHistory(lockHistory) - , lockBackForwardList(lockBackForwardList) - , wasUserGesture(wasUserGesture) - , wasRefresh(refresh) - , wasDuringLoad(duringLoad) - { - ASSERT(!url.isEmpty()); - } - - explicit ScheduledRedirection(int historyNavigationSteps) - : type(historyNavigation) - , delay(0) - , historySteps(historyNavigationSteps) - , lockHistory(false) - , lockBackForwardList(false) - , wasUserGesture(false) - , wasRefresh(false) - , wasDuringLoad(false) - { - } - - ScheduledRedirection(const FrameLoadRequest& frameRequest, - bool lockHistory, bool lockBackForwardList, PassRefPtr event, PassRefPtr formState, - bool duringLoad) - : type(formSubmission) - , delay(0) - , frameRequest(frameRequest) - , event(event) - , formState(formState) - , historySteps(0) - , lockHistory(lockHistory) - , lockBackForwardList(lockBackForwardList) - , wasUserGesture(false) - , wasRefresh(false) - , wasDuringLoad(duringLoad) - { - ASSERT(!frameRequest.isEmpty()); - ASSERT(this->formState); - } -}; - #if ENABLE(XHTMLMP) static const char defaultAcceptHeader[] = "application/xml,application/vnd.wap.xhtml+xml,application/xhtml+xml;profile='http://www.wapforum.org/xhtml',text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"; #else static const char defaultAcceptHeader[] = "application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"; #endif static double storedTimeOfLastCompletedLoad; -static FrameLoader::LocalLoadPolicy localLoadPolicy = FrameLoader::AllowLocalLoadsForLocalOnly; bool isBackForwardLoadType(FrameLoadType type) { @@ -246,12 +178,10 @@ static inline bool canReferToParentFrameEncoding(const Frame* frame, const Frame FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client) : m_frame(frame) , m_client(client) + , m_policyChecker(frame) , m_state(FrameStateCommittedPage) , m_loadType(FrameLoadTypeStandard) - , m_policyLoadType(FrameLoadTypeStandard) , m_delegateIsHandlingProvisionalLoadError(false) - , m_delegateIsDecidingNavigationPolicy(false) - , m_delegateIsHandlingUnimplementablePolicy(false) , m_firstLayoutDone(false) , m_quickRedirectComing(false) , m_sentRedirectNotification(false) @@ -263,20 +193,19 @@ FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client) , m_unloadEventBeingDispatched(false) , m_isComplete(false) , m_isLoadingMainResource(false) - , m_cancellingWithLoadInProgress(false) , m_needsClear(false) , m_receivedData(false) , m_encodingWasChosenByUser(false) , m_containsPlugIns(false) - , m_redirectionTimer(this, &FrameLoader::redirectionTimerFired) - , m_checkCompletedTimer(this, &FrameLoader::checkCompletedTimerFired) - , m_checkLoadCompleteTimer(this, &FrameLoader::checkLoadCompleteTimerFired) + , m_checkTimer(this, &FrameLoader::checkTimerFired) + , m_shouldCallCheckCompleted(false) + , m_shouldCallCheckLoadComplete(false) , m_opener(0) - , m_openedByDOM(false) , m_creatingInitialEmptyDocument(false) , m_isDisplayingInitialEmptyDocument(false) , m_committedFirstRealDocumentLoad(false) , m_didPerformFirstNavigation(false) + , m_loadingFromCachedPage(false) #ifndef NDEBUG , m_didDispatchDidCommitLoad(false) #endif @@ -299,7 +228,7 @@ void FrameLoader::init() // this somewhat odd set of steps is needed to give the frame an initial empty document m_isDisplayingInitialEmptyDocument = false; m_creatingInitialEmptyDocument = true; - setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(KURL("")), SubstituteData()).get()); + setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(KURL(ParsedURLString, "")), SubstituteData()).get()); setProvisionalDocumentLoader(m_policyDocumentLoader.get()); setState(FrameStateProvisional); m_provisionalDocumentLoader->setResponse(ResourceResponse(KURL(), "text/html", 0, String(), String())); @@ -319,6 +248,11 @@ void FrameLoader::setDefersLoading(bool defers) m_provisionalDocumentLoader->setDefersLoading(defers); if (m_policyDocumentLoader) m_policyDocumentLoader->setDefersLoading(defers); + + if (!defers) { + m_frame->redirectScheduler()->startTimer(); + startCheckCompleteTimer(); + } } Frame* FrameLoader::createWindow(FrameLoader* frameLoaderForFrameLookup, const FrameLoadRequest& request, const WindowFeatures& features, bool& created) @@ -433,7 +367,7 @@ bool FrameLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String Frame* frame = ownerElement->contentFrame(); if (frame) - frame->loader()->scheduleLocationChange(url.string(), m_outgoingReferrer, true, true, isProcessingUserGesture()); + frame->redirectScheduler()->scheduleLocationChange(url.string(), m_outgoingReferrer, true, true, isProcessingUserGesture()); else frame = loadSubframe(ownerElement, url, frameName, m_outgoingReferrer); @@ -458,12 +392,12 @@ Frame* FrameLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL marginHeight = o->getMarginHeight(); } - if (!canLoad(url, referrer)) { + if (!SecurityOrigin::canLoad(url, referrer, 0)) { FrameLoader::reportLocalLoadFailed(m_frame, url.string()); return 0; } - bool hideReferrer = shouldHideReferrer(url, referrer); + bool hideReferrer = SecurityOrigin::shouldHideReferrer(url, referrer); RefPtr frame = m_client->createFrame(url, name, ownerElement, hideReferrer ? String() : referrer, allowsScrolling, marginWidth, marginHeight); if (!frame) { @@ -571,23 +505,27 @@ void FrameLoader::submitForm(const char* action, const String& url, PassRefPtrloader()->scheduleFormSubmission(frameRequest, lockHistory, event, formState); + targetFrame->redirectScheduler()->scheduleFormSubmission(frameRequest, lockHistory, event, formState); } -void FrameLoader::stopLoading(bool sendUnload, DatabasePolicy databasePolicy) +void FrameLoader::stopLoading(UnloadEventPolicy unloadEventPolicy, DatabasePolicy databasePolicy) { if (m_frame->document() && m_frame->document()->tokenizer()) m_frame->document()->tokenizer()->stopParsing(); - if (sendUnload) { + if (unloadEventPolicy != UnloadEventPolicyNone) { if (m_frame->document()) { if (m_didCallImplicitClose && !m_wasUnloadEventEmitted) { Node* currentFocusedNode = m_frame->document()->focusedNode(); if (currentFocusedNode) currentFocusedNode->aboutToUnload(); m_unloadEventBeingDispatched = true; - if (m_frame->domWindow()) - m_frame->domWindow()->dispatchUnloadEvent(); + if (m_frame->domWindow()) { + if (unloadEventPolicy == UnloadEventPolicyUnloadAndPageHide) + m_frame->domWindow()->dispatchEvent(PageTransitionEvent::create(EventNames().pagehideEvent, m_frame->document()->inPageCache()), m_frame->document()); + if (!m_frame->document()->inPageCache()) + m_frame->domWindow()->dispatchEvent(Event::create(eventNames().unloadEvent, false, false), m_frame->domWindow()->document()); + } m_unloadEventBeingDispatched = false; if (m_frame->document()) m_frame->document()->updateStyleIfNeeded(); @@ -600,7 +538,7 @@ void FrameLoader::stopLoading(bool sendUnload, DatabasePolicy databasePolicy) m_frame->document()->removeAllEventListeners(); } - m_isComplete = true; // to avoid calling completed() in finishedParsing() (David) + m_isComplete = true; // to avoid calling completed() in finishedParsing() m_isLoadingMainResource = false; m_didCallImplicitClose = true; // don't want that one either @@ -623,9 +561,9 @@ void FrameLoader::stopLoading(bool sendUnload, DatabasePolicy databasePolicy) // tell all subframes to stop as well for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) - child->loader()->stopLoading(sendUnload); + child->loader()->stopLoading(unloadEventPolicy); - cancelRedirection(); + m_frame->redirectScheduler()->cancel(); } void FrameLoader::stop() @@ -645,20 +583,15 @@ void FrameLoader::stop() bool FrameLoader::closeURL() { saveDocumentState(); - stopLoading(true); + + // Should only send the pagehide event here if the current document exists and has not been placed in the page cache. + Document* currentDocument = m_frame->document(); + stopLoading(currentDocument && !currentDocument->inPageCache() ? UnloadEventPolicyUnloadAndPageHide : UnloadEventPolicyUnloadOnly); + m_frame->editor()->clearUndoRedoOperations(); return true; } -void FrameLoader::cancelRedirection(bool cancelWithLoadInProgress) -{ - m_cancellingWithLoadInProgress = cancelWithLoadInProgress; - - stopRedirectionTimer(); - - m_scheduledRedirection.clear(); -} - KURL FrameLoader::iconURL() { // If this isn't a top level frame, return nothing @@ -667,7 +600,7 @@ KURL FrameLoader::iconURL() // If we have an iconURL from a Link element, return that if (!m_frame->document()->iconURL().isEmpty()) - return KURL(m_frame->document()->iconURL()); + return KURL(ParsedURLString, m_frame->document()->iconURL()); // Don't return a favicon iconURL unless we're http or https if (!m_URL.protocolInHTTPFamily()) @@ -684,13 +617,13 @@ KURL FrameLoader::iconURL() bool FrameLoader::didOpenURL(const KURL& url) { - if (m_scheduledRedirection && m_scheduledRedirection->wasDuringLoad) { + if (m_frame->redirectScheduler()->redirectScheduledDuringLoad()) { // A redirect was scheduled before the document was created. // This can happen when one frame changes another frame's location. return false; } - cancelRedirection(); + m_frame->redirectScheduler()->cancel(); m_frame->editor()->clearLastEditCommand(); closeURL(); @@ -727,7 +660,7 @@ void FrameLoader::didExplicitOpen() // from a subsequent window.document.open / window.document.write call. // Cancelling redirection here works for all cases because document.open // implicitly precedes document.write. - cancelRedirection(); + m_frame->redirectScheduler()->cancel(); if (m_frame->document()->url() != blankURL()) m_URL = m_frame->document()->url(); } @@ -742,8 +675,10 @@ bool FrameLoader::executeIfJavaScriptURL(const KURL& url, bool userGesture, bool const int javascriptSchemeLength = sizeof("javascript:") - 1; - String script = decodeURLEscapeSequences(url.string().substring(javascriptSchemeLength)); - ScriptValue result = executeScript(script, userGesture); + String script = url.string().substring(javascriptSchemeLength); + ScriptValue result; + if (m_frame->script()->xssAuditor()->canEvaluateJavaScriptURL(script)) + result = executeScript(decodeURLEscapeSequences(script), userGesture); String scriptResult; if (!result.getString(scriptResult)) @@ -789,7 +724,7 @@ ScriptValue FrameLoader::executeScript(const ScriptSourceCode& sourceCode) void FrameLoader::cancelAndClear() { - cancelRedirection(); + m_frame->redirectScheduler()->cancel(); if (!m_isComplete) closeURL(); @@ -798,7 +733,7 @@ void FrameLoader::cancelAndClear() m_frame->script()->updatePlatformScriptObjects(); } -void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects) +void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects, bool clearFrameView) { m_frame->editor()->clear(); @@ -825,7 +760,7 @@ void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects) m_frame->selection()->clear(); m_frame->eventHandler()->clear(); - if (m_frame->view()) + if (clearFrameView && m_frame->view()) m_frame->view()->clear(); m_frame->setSelectionGranularity(CharacterGranularity); @@ -840,11 +775,11 @@ void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects) if (clearScriptObjects) m_frame->script()->clearScriptObjects(); - m_redirectionTimer.stop(); - m_scheduledRedirection.clear(); + m_frame->redirectScheduler()->clear(); - m_checkCompletedTimer.stop(); - m_checkLoadCompleteTimer.stop(); + m_checkTimer.stop(); + m_shouldCallCheckCompleted = false; + m_shouldCallCheckLoadComplete = false; m_receivedData = false; m_isDisplayingInitialEmptyDocument = false; @@ -881,7 +816,7 @@ void FrameLoader::receivedFirstData() else url = m_frame->document()->completeURL(url).string(); - scheduleHTTPRedirection(delay, url); + m_frame->redirectScheduler()->scheduleRedirect(delay, url); } const String& FrameLoader::responseMIMEType() const @@ -933,12 +868,9 @@ void FrameLoader::begin(const KURL& url, bool dispatch, SecurityOrigin* origin) m_outgoingReferrer = ref.string(); m_URL = url; + document->setURL(m_URL); m_frame->setDocument(document); - if (dispatch) - dispatchWindowObjectAvailable(); - - document->setURL(m_URL); if (m_decoder) document->setDecoder(m_decoder.get()); if (forcedSecurityOrigin) @@ -947,6 +879,9 @@ void FrameLoader::begin(const KURL& url, bool dispatch, SecurityOrigin* origin) m_frame->domWindow()->setURL(document->url()); m_frame->domWindow()->setSecurityOrigin(document->securityOrigin()); + if (dispatch) + dispatchWindowObjectAvailable(); + updateFirstPartyForCookies(); Settings* settings = document->settings(); @@ -961,12 +896,6 @@ void FrameLoader::begin(const KURL& url, bool dispatch, SecurityOrigin* origin) document->parseDNSPrefetchControlHeader(dnsPrefetchControl); } -#if FRAME_LOADS_USER_STYLESHEET - KURL userStyleSheet = settings ? settings->userStyleSheetLocation() : KURL(); - if (!userStyleSheet.isEmpty()) - m_frame->setUserStyleSheetLocation(userStyleSheet); -#endif - restoreDocumentState(); document->implicitOpen(); @@ -1146,21 +1075,6 @@ void FrameLoader::startIconLoader() m_iconLoader->startLoading(); } -void FrameLoader::setLocalLoadPolicy(LocalLoadPolicy policy) -{ - localLoadPolicy = policy; -} - -bool FrameLoader::restrictAccessToLocal() -{ - return localLoadPolicy != FrameLoader::AllowLocalLoadsForAll; -} - -bool FrameLoader::allowSubstituteDataAccessToLocal() -{ - return localLoadPolicy != FrameLoader::AllowLocalLoadsForLocalOnly; -} - void FrameLoader::commitIconURLToIconDatabase(const KURL& icon) { ASSERT(iconDatabase()); @@ -1220,6 +1134,8 @@ void FrameLoader::finishedParsing() if (m_creatingInitialEmptyDocument) return; + m_frame->injectUserScripts(InjectAtDocumentEnd); + // This can be called from the Frame's destructor, in which case we shouldn't protect ourselves // because doing so will cause us to re-enter the destructor when protector goes out of scope. // Null-checking the FrameView indicates whether or not we're in the destructor. @@ -1244,15 +1160,34 @@ void FrameLoader::loadDone() checkCompleted(); } +bool FrameLoader::allChildrenAreComplete() const +{ + for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) { + if (!child->loader()->m_isComplete) + return false; + } + return true; +} + +bool FrameLoader::allAncestorsAreComplete() const +{ + for (Frame* ancestor = m_frame; ancestor; ancestor = ancestor->tree()->parent()) { + if (!ancestor->loader()->m_isComplete) + return false; + } + return true; +} + void FrameLoader::checkCompleted() { + m_shouldCallCheckCompleted = false; + if (m_frame->view()) m_frame->view()->checkStopDelayingDeferredRepaints(); // Any frame that hasn't completed yet? - for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) - if (!child->loader()->m_isComplete) - return; + if (!allChildrenAreComplete()) + return; // Have we completed before? if (m_isComplete) @@ -1272,38 +1207,44 @@ void FrameLoader::checkCompleted() RefPtr protect(m_frame); checkCallImplicitClose(); // if we didn't do it before - // Do not start a redirection timer for subframes here. - // That is deferred until the parent is completed. - if (m_scheduledRedirection && !m_frame->tree()->parent()) - startRedirectionTimer(); + m_frame->redirectScheduler()->startTimer(); completed(); if (m_frame->page()) checkLoadComplete(); } -void FrameLoader::checkCompletedTimerFired(Timer*) +void FrameLoader::checkTimerFired(Timer*) { - checkCompleted(); + if (Page* page = m_frame->page()) { + if (page->defersLoading()) + return; + } + if (m_shouldCallCheckCompleted) + checkCompleted(); + if (m_shouldCallCheckLoadComplete) + checkLoadComplete(); } -void FrameLoader::scheduleCheckCompleted() +void FrameLoader::startCheckCompleteTimer() { - if (!m_checkCompletedTimer.isActive()) - m_checkCompletedTimer.startOneShot(0); + if (!(m_shouldCallCheckCompleted || m_shouldCallCheckLoadComplete)) + return; + if (m_checkTimer.isActive()) + return; + m_checkTimer.startOneShot(0); } -void FrameLoader::checkLoadCompleteTimerFired(Timer*) +void FrameLoader::scheduleCheckCompleted() { - if (!m_frame->page()) - return; - checkLoadComplete(); + m_shouldCallCheckCompleted = true; + startCheckCompleteTimer(); } void FrameLoader::scheduleCheckLoadComplete() { - if (!m_checkLoadCompleteTimer.isActive()) - m_checkLoadCompleteTimer.startOneShot(0); + m_shouldCallCheckLoadComplete = true; + startCheckCompleteTimer(); } void FrameLoader::checkCallImplicitClose() @@ -1311,9 +1252,8 @@ void FrameLoader::checkCallImplicitClose() if (m_didCallImplicitClose || m_frame->document()->parsing()) return; - for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) - if (!child->loader()->m_isComplete) // still got a frame running -> too early - return; + if (!allChildrenAreComplete()) + return; // still got a frame running -> too early m_didCallImplicitClose = true; m_wasUnloadEventEmitted = false; @@ -1332,183 +1272,6 @@ KURL FrameLoader::completeURL(const String& url) return m_frame->document()->completeURL(url); } -void FrameLoader::scheduleHTTPRedirection(double delay, const String& url) -{ - if (delay < 0 || delay > INT_MAX / 1000) - return; - - if (!m_frame->page()) - return; - - if (url.isEmpty()) - return; - - // We want a new history item if the refresh timeout is > 1 second. - if (!m_scheduledRedirection || delay <= m_scheduledRedirection->delay) - 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()) - return; - - 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.hasFragmentIdentifier() && equalIgnoringFragmentIdentifier(m_URL, parsedURL)) { - changeLocation(completeURL(url), referrer, lockHistory, lockBackForwardList, wasUserGesture); - return; - } - - // Handle a location change of a page with no document as a special case. - // This may happen when a frame changes the location of another frame. - bool duringLoad = !m_committedFirstRealDocumentLoad; - - scheduleRedirection(new ScheduledRedirection(url, referrer, lockHistory, lockBackForwardList, wasUserGesture, false, duringLoad)); -} - -void FrameLoader::scheduleFormSubmission(const FrameLoadRequest& frameRequest, - bool lockHistory, PassRefPtr event, PassRefPtr formState) -{ - ASSERT(m_frame->page()); - ASSERT(!frameRequest.isEmpty()); - - // FIXME: Do we need special handling for form submissions where the URL is the same - // as the current one except for the fragment part? See scheduleLocationChange above. - - // Handle a location change of a page with no document as a special case. - // This may happen when a frame changes the location of another frame. - bool duringLoad = !m_committedFirstRealDocumentLoad; - - scheduleRedirection(new ScheduledRedirection(frameRequest, lockHistory, mustLockBackForwardList(m_frame), event, formState, duringLoad)); -} - -void FrameLoader::scheduleRefresh(bool wasUserGesture) -{ - if (!m_frame->page()) - return; - - if (m_URL.isEmpty()) - return; - - scheduleRedirection(new ScheduledRedirection(m_URL.string(), m_outgoingReferrer, true, true, wasUserGesture, true, false)); -} - -bool FrameLoader::isLocationChange(const ScheduledRedirection& redirection) -{ - switch (redirection.type) { - case ScheduledRedirection::redirection: - return false; - case ScheduledRedirection::historyNavigation: - case ScheduledRedirection::locationChange: - case ScheduledRedirection::formSubmission: - return true; - } - ASSERT_NOT_REACHED(); - return false; -} - -void FrameLoader::scheduleHistoryNavigation(int steps) -{ - if (!m_frame->page()) - return; - - // navigation will always be allowed in the 0 steps case, which is OK because that's supposed to force a reload. - if (!canGoBackOrForward(steps)) { - cancelRedirection(); - return; - } - - scheduleRedirection(new ScheduledRedirection(steps)); -} - -void FrameLoader::goBackOrForward(int distance) -{ - if (distance == 0) - return; - - Page* page = m_frame->page(); - if (!page) - return; - BackForwardList* list = page->backForwardList(); - if (!list) - return; - - HistoryItem* item = list->itemAtIndex(distance); - if (!item) { - if (distance > 0) { - int forwardListCount = list->forwardListCount(); - if (forwardListCount > 0) - item = list->itemAtIndex(forwardListCount); - } else { - int backListCount = list->backListCount(); - if (backListCount > 0) - item = list->itemAtIndex(-backListCount); - } - } - - ASSERT(item); // we should not reach this line with an empty back/forward list - if (item) - page->goToItem(item, FrameLoadTypeIndexedBackForward); -} - -void FrameLoader::redirectionTimerFired(Timer*) -{ - ASSERT(m_frame->page()); - - OwnPtr redirection(m_scheduledRedirection.release()); - - switch (redirection->type) { - case ScheduledRedirection::redirection: - case ScheduledRedirection::locationChange: - changeLocation(KURL(redirection->url), redirection->referrer, - redirection->lockHistory, redirection->lockBackForwardList, redirection->wasUserGesture, redirection->wasRefresh); - return; - case ScheduledRedirection::historyNavigation: - if (redirection->historySteps == 0) { - // Special case for go(0) from a frame -> reload only the frame - urlSelected(m_URL, "", 0, redirection->lockHistory, redirection->lockBackForwardList, redirection->wasUserGesture); - return; - } - // go(i!=0) from a frame navigates into the history of the frame only, - // in both IE and NS (but not in Mozilla). We can't easily do that. - goBackOrForward(redirection->historySteps); - return; - case ScheduledRedirection::formSubmission: - // The submitForm function will find a target frame before using the redirection timer. - // Now that the timer has fired, we need to repeat the security check which normally is done when - // selecting a target, in case conditions have changed. Other code paths avoid this by targeting - // without leaving a time window. If we fail the check just silently drop the form submission. - if (!redirection->formState->sourceFrame()->loader()->shouldAllowNavigation(m_frame)) - return; - loadFrameRequest(redirection->frameRequest, redirection->lockHistory, redirection->lockBackForwardList, - redirection->event, redirection->formState); - return; - } - - ASSERT_NOT_REACHED(); -} - void FrameLoader::loadURLIntoChildFrame(const KURL& url, const String& referer, Frame* childFrame) { ASSERT(childFrame); @@ -1527,7 +1290,7 @@ void FrameLoader::loadURLIntoChildFrame(const KURL& url, const String& referer, // Use the original URL to ensure we get all the side-effects, such as // onLoad handlers, of any redirects that happened. An example of where // this is needed is Radar 3213556. - workingURL = KURL(childItem->originalURLString()); + workingURL = KURL(ParsedURLString, childItem->originalURLString()); childLoadType = loadType; childFrame->loader()->m_provisionalHistoryItem = childItem; } @@ -1716,7 +1479,7 @@ bool FrameLoader::loadPlugin(RenderPart* renderer, const KURL& url, const String if (renderer && !useFallback) { HTMLPlugInElement* element = toPlugInElement(renderer->node()); - if (!canLoad(url, String(), frame()->document())) { + if (!SecurityOrigin::canLoad(url, String(), frame()->document())) { FrameLoader::reportLocalLoadFailed(m_frame, url.string()); return false; } @@ -1733,12 +1496,6 @@ bool FrameLoader::loadPlugin(RenderPart* renderer, const KURL& url, const String return widget != 0; } -void FrameLoader::parentCompleted() -{ - if (m_scheduledRedirection && !m_redirectionTimer.isActive()) - startRedirectionTimer(); -} - String FrameLoader::outgoingReferrer() const { return m_outgoingReferrer; @@ -1749,6 +1506,33 @@ String FrameLoader::outgoingOrigin() const return m_frame->document()->securityOrigin()->toString(); } +bool FrameLoader::isMixedContent(SecurityOrigin* context, const KURL& url) +{ + if (context->protocol() != "https") + return false; // We only care about HTTPS security origins. + + if (url.protocolIs("https") || url.protocolIs("about") || url.protocolIs("data")) + return false; // Loading these protocols is secure. + + return true; +} + +void FrameLoader::checkIfDisplayInsecureContent(SecurityOrigin* context, const KURL& url) +{ + if (!isMixedContent(context, url)) + return; + + m_client->didDisplayInsecureContent(); +} + +void FrameLoader::checkIfRunInsecureContent(SecurityOrigin* context, const KURL& url) +{ + if (!isMixedContent(context, url)) + return; + + m_client->didRunInsecureContent(context); +} + Frame* FrameLoader::opener() { return m_opener; @@ -1768,16 +1552,6 @@ void FrameLoader::setOpener(Frame* opener) } } -bool FrameLoader::openedByDOM() const -{ - return m_openedByDOM; -} - -void FrameLoader::setOpenedByDOM() -{ - m_openedByDOM = true; -} - void FrameLoader::handleFallbackContent() { HTMLFrameOwnerElement* owner = m_frame->ownerElement(); @@ -1793,7 +1567,7 @@ void FrameLoader::provisionalLoadStarted() android::TimeCounter::reset(); #endif m_firstLayoutDone = false; - cancelRedirection(true); + m_frame->redirectScheduler()->cancel(true); m_client->provisionalLoadStarted(); } @@ -1839,9 +1613,13 @@ static inline bool frameContainsWMLContent(Frame* frame) bool FrameLoader::canCachePageContainingThisFrame() { + for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) { + if (!child->loader()->canCachePageContainingThisFrame()) + return false; + } + return m_documentLoader && m_documentLoader->mainDocumentError().isNull() - && !m_frame->tree()->childCount() // FIXME: If we ever change this so that frames with plug-ins will be cached, // we need to make sure that we don't cache frames that have outstanding NPObjects // (objects created by the plug-in). Since there is no way to pause/resume a Netscape plug-in, @@ -1849,10 +1627,15 @@ bool FrameLoader::canCachePageContainingThisFrame() // the right NPObjects. See for more information. && !m_containsPlugIns && !m_URL.protocolIs("https") - && (!m_frame->domWindow() || !m_frame->domWindow()->hasEventListener(eventNames().unloadEvent)) +#ifndef PAGE_CACHE_ACCEPTS_UNLOAD_HANDLERS + && (!m_frame->domWindow() || !m_frame->domWindow()->hasEventListeners(eventNames().unloadEvent)) +#endif #if ENABLE(DATABASE) && !m_frame->document()->hasOpenDatabases() #endif +#if ENABLE(SHARED_WORKERS) + && !SharedWorkerRepository::hasSharedWorkers(m_frame->document()) +#endif && !m_frame->document()->usingGeolocation() && m_currentHistoryItem && !m_quickRedirectComing @@ -1987,18 +1770,22 @@ bool FrameLoader::logCanCacheFrameDecision(int indentLevel) } if (!m_documentLoader->mainDocumentError().isNull()) { PCLOG(" -Main document has an error"); cannotCache = true; } - if (m_frame->tree()->childCount()) - { PCLOG(" -Frame has child frames"); cannotCache = true; } if (m_containsPlugIns) { PCLOG(" -Frame contains plugins"); cannotCache = true; } if (m_URL.protocolIs("https")) { PCLOG(" -Frame is HTTPS"); cannotCache = true; } - if (m_frame->domWindow() && m_frame->domWindow()->hasEventListener(eventNames().unloadEvent)) +#ifndef PAGE_CACHE_ACCEPTS_UNLOAD_HANDLERS + if (m_frame->domWindow() && m_frame->domWindow()->hasEventListeners(eventNames().unloadEvent)) { PCLOG(" -Frame has an unload event listener"); cannotCache = true; } +#endif #if ENABLE(DATABASE) if (m_frame->document()->hasOpenDatabases()) { PCLOG(" -Frame has open database handles"); cannotCache = true; } #endif +#if ENABLE(SHARED_WORKERS) + if (SharedWorkerRepository::hasSharedWorkers(m_frame->document())) + { PCLOG(" -Frame has associated SharedWorkers"); cannotCache = true; } +#endif if (m_frame->document()->usingGeolocation()) { PCLOG(" -Frame uses Geolocation"); cannotCache = true; } if (!m_currentHistoryItem) @@ -2055,7 +1842,7 @@ public: virtual void performTask(ScriptExecutionContext* context) { ASSERT_UNUSED(context, context->isDocument()); - m_document->dispatchWindowEvent(eventNames().hashchangeEvent, false, false); + m_document->dispatchWindowEvent(Event::create(eventNames().hashchangeEvent, false, false)); } private: @@ -2067,7 +1854,7 @@ private: 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) @@ -2097,86 +1884,11 @@ bool FrameLoader::isComplete() const return m_isComplete; } -void FrameLoader::scheduleRedirection(ScheduledRedirection* redirection) -{ - ASSERT(m_frame->page()); - - // If a redirect was scheduled during a load, then stop the current load. - // Otherwise when the current load transitions from a provisional to a - // committed state, pending redirects may be cancelled. - if (redirection->wasDuringLoad) { - if (m_provisionalDocumentLoader) - m_provisionalDocumentLoader->stopLoading(); - stopLoading(true); - } - - stopRedirectionTimer(); - m_scheduledRedirection.set(redirection); - if (!m_isComplete && redirection->type != ScheduledRedirection::redirection) - completed(); - if (m_isComplete || redirection->type != ScheduledRedirection::redirection) - startRedirectionTimer(); -} - -void FrameLoader::startRedirectionTimer() -{ - ASSERT(m_frame->page()); - ASSERT(m_scheduledRedirection); - - m_redirectionTimer.stop(); - m_redirectionTimer.startOneShot(m_scheduledRedirection->delay); - - switch (m_scheduledRedirection->type) { - case ScheduledRedirection::locationChange: - case ScheduledRedirection::redirection: - clientRedirected(KURL(m_scheduledRedirection->url), - m_scheduledRedirection->delay, - currentTime() + m_redirectionTimer.nextFireInterval(), - m_scheduledRedirection->lockBackForwardList); - return; - case ScheduledRedirection::formSubmission: - // FIXME: It would make sense to report form submissions as client redirects too. - // But we didn't do that in the past when form submission used a separate delay - // mechanism, so doing it will be a behavior change. - return; - case ScheduledRedirection::historyNavigation: - // Don't report history navigations. - return; - } - ASSERT_NOT_REACHED(); -} - -void FrameLoader::stopRedirectionTimer() -{ - if (!m_redirectionTimer.isActive()) - return; - - m_redirectionTimer.stop(); - - if (m_scheduledRedirection) { - switch (m_scheduledRedirection->type) { - case ScheduledRedirection::locationChange: - case ScheduledRedirection::redirection: - clientRedirectCancelledOrFinished(m_cancellingWithLoadInProgress); - return; - case ScheduledRedirection::formSubmission: - // FIXME: It would make sense to report form submissions as client redirects too. - // But we didn't do that in the past when form submission used a separate delay - // mechanism, so doing it will be a behavior change. - return; - case ScheduledRedirection::historyNavigation: - // Don't report history navigations. - return; - } - ASSERT_NOT_REACHED(); - } -} - void FrameLoader::completed() { RefPtr protect(m_frame); for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) - child->loader()->parentCompleted(); + child->redirectScheduler()->startTimer(); if (Frame* parent = m_frame->tree()->parent()) parent->loader()->checkCompleted(); if (m_frame->view()) @@ -2243,13 +1955,13 @@ void FrameLoader::loadFrameRequest(const FrameLoadRequest& request, bool lockHis ASSERT(frame()->document()); if (SecurityOrigin::shouldTreatURLAsLocal(url.string()) && !isFeedWithNestedProtocolInHTTPFamily(url)) { - if (!canLoad(url, String(), frame()->document()) && !canLoad(url, referrer)) { + if (!SecurityOrigin::canLoad(url, String(), frame()->document()) && !SecurityOrigin::canLoad(url, referrer, 0)) { FrameLoader::reportLocalLoadFailed(m_frame, url.string()); return; } } - if (shouldHideReferrer(url, referrer)) + if (SecurityOrigin::shouldHideReferrer(url, referrer)) referrer = String(); FrameLoadType loadType; @@ -2319,10 +2031,14 @@ void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const Stri return; } + if (m_unloadEventBeingDispatched) + return; + NavigationAction action(newURL, newLoadType, isFormSubmission, event); if (!targetFrame && !frameName.isEmpty()) { - checkNewWindowPolicy(action, request, formState.release(), frameName); + policyChecker()->checkNewWindowPolicy(action, FrameLoader::callContinueLoadAfterNewWindowPolicy, + request, formState.release(), frameName, this); return; } @@ -2335,8 +2051,9 @@ void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const Stri // work properly. if (shouldScrollToAnchor(isFormSubmission, newLoadType, newURL)) { oldDocumentLoader->setTriggeringAction(action); - stopPolicyCheck(); - checkNavigationPolicy(request, oldDocumentLoader.get(), formState.release(), + policyChecker()->stopCheck(); + policyChecker()->setLoadType(newLoadType); + policyChecker()->checkNavigationPolicy(request, oldDocumentLoader.get(), formState.release(), callContinueFragmentScrollAfterNavigationPolicy, this); } else { // must grab this now, since this load may stop the previous load and clear this flag @@ -2385,7 +2102,7 @@ void FrameLoader::load(const ResourceRequest& request, const String& frameName, return; } - checkNewWindowPolicy(NavigationAction(request.url(), NavigationTypeOther), request, 0, frameName); + policyChecker()->checkNewWindowPolicy(NavigationAction(request.url(), NavigationTypeOther), FrameLoader::callContinueLoadAfterNewWindowPolicy, request, 0, frameName, this); } void FrameLoader::loadWithNavigationAction(const ResourceRequest& request, const NavigationAction& action, bool lockHistory, FrameLoadType type, PassRefPtr formState) @@ -2440,54 +2157,37 @@ void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t ASSERT(m_frame->view()); - m_policyLoadType = type; + if (m_unloadEventBeingDispatched) + return; + + policyChecker()->setLoadType(type); RefPtr formState = prpFormState; bool isFormSubmission = formState; const KURL& newURL = loader->request().url(); - if (shouldScrollToAnchor(isFormSubmission, m_policyLoadType, newURL)) { + if (shouldScrollToAnchor(isFormSubmission, policyChecker()->loadType(), newURL)) { RefPtr oldDocumentLoader = m_documentLoader; - NavigationAction action(newURL, m_policyLoadType, isFormSubmission); + NavigationAction action(newURL, policyChecker()->loadType(), isFormSubmission); oldDocumentLoader->setTriggeringAction(action); - stopPolicyCheck(); - checkNavigationPolicy(loader->request(), oldDocumentLoader.get(), formState, + policyChecker()->stopCheck(); + policyChecker()->checkNavigationPolicy(loader->request(), oldDocumentLoader.get(), formState, callContinueFragmentScrollAfterNavigationPolicy, this); } else { if (Frame* parent = m_frame->tree()->parent()) loader->setOverrideEncoding(parent->loader()->documentLoader()->overrideEncoding()); - stopPolicyCheck(); + policyChecker()->stopCheck(); setPolicyDocumentLoader(loader); if (loader->triggeringAction().isEmpty()) - loader->setTriggeringAction(NavigationAction(newURL, m_policyLoadType, isFormSubmission)); + loader->setTriggeringAction(NavigationAction(newURL, policyChecker()->loadType(), isFormSubmission)); - checkNavigationPolicy(loader->request(), loader, formState, + policyChecker()->checkNavigationPolicy(loader->request(), loader, formState, callContinueLoadAfterNavigationPolicy, this); } } -bool FrameLoader::canLoad(const KURL& url, const String& referrer, const Document* doc) -{ - return canLoad(url, referrer, doc ? doc->securityOrigin() : 0); -} - -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 (!SecurityOrigin::shouldTreatURLAsLocal(url.string())) - return true; - - // If we were provided a document, we let its local file policy dictate the result, - // otherwise we allow local loads only if the supplied referrer is also local. - if (securityOrigin) - return securityOrigin->canLoadLocalResources(); - if (!referrer.isEmpty()) - return SecurityOrigin::shouldTreatURLAsLocal(referrer); - return false; -} - void FrameLoader::reportLocalLoadFailed(Frame* frame, const String& url) { ASSERT(!url.isEmpty()); @@ -2497,22 +2197,6 @@ void FrameLoader::reportLocalLoadFailed(Frame* frame, const String& url) 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) -{ - bool referrerIsSecureURL = protocolIs(referrer, "https"); - bool referrerIsWebURL = referrerIsSecureURL || protocolIs(referrer, "http"); - - if (!referrerIsWebURL) - return true; - - if (!referrerIsSecureURL) - return false; - - bool URLIsSecureURL = url.protocolIs("https"); - - return !URLIsSecureURL; -} - const ResourceRequest& FrameLoader::initialRequest() const { return activeDocumentLoader()->originalRequest(); @@ -2523,50 +2207,26 @@ void FrameLoader::receivedData(const char* data, int length) activeDocumentLoader()->receivedData(data, length); } -void FrameLoader::handleUnimplementablePolicy(const ResourceError& error) +bool FrameLoader::willLoadMediaElementURL(KURL& url) { - m_delegateIsHandlingUnimplementablePolicy = true; - m_client->dispatchUnableToImplementPolicy(error); - m_delegateIsHandlingUnimplementablePolicy = false; -} + if (!m_client->shouldLoadMediaElementURL(url)) + return false; -void FrameLoader::cannotShowMIMEType(const ResourceResponse& response) -{ - handleUnimplementablePolicy(m_client->cannotShowMIMETypeError(response)); -} + ResourceRequest request(url); -ResourceError FrameLoader::interruptionForPolicyChangeError(const ResourceRequest& request) -{ - return m_client->interruptForPolicyChangeError(request); -} + unsigned long identifier; + ResourceError error; + requestFromDelegate(request, identifier, error); + sendRemainingDelegateMessages(identifier, ResourceResponse(url, String(), -1, String(), String()), -1, error); -void FrameLoader::checkNavigationPolicy(const ResourceRequest& newRequest, NavigationPolicyDecisionFunction function, void* argument) -{ - checkNavigationPolicy(newRequest, activeDocumentLoader(), 0, function, argument); + url = request.url(); + + return error.isNull(); } -void FrameLoader::checkContentPolicy(const String& MIMEType, ContentPolicyDecisionFunction function, void* argument) +ResourceError FrameLoader::interruptionForPolicyChangeError(const ResourceRequest& request) { - ASSERT(activeDocumentLoader()); - - // Always show content with valid substitute data. - if (activeDocumentLoader()->substituteData().isValid()) { - function(argument, PolicyUse); - return; - } - -#if ENABLE(FTPDIR) - // Respect the hidden FTP Directory Listing pref so it can be tested even if the policy delegate might otherwise disallow it - Settings* settings = m_frame->settings(); - if (settings && settings->forceFTPDirectoryListings() && MIMEType == "application/x-ftp-directory") { - function(argument, PolicyUse); - return; - } -#endif - - m_policyCheck.set(function, argument); - m_client->dispatchDecidePolicyForMIMEType(&FrameLoader::continueAfterContentPolicy, - MIMEType, activeDocumentLoader()->request()); + return m_client->interruptForPolicyChangeError(request); } bool FrameLoader::shouldReloadToHandleUnreachableURL(DocumentLoader* docLoader) @@ -2576,7 +2236,7 @@ bool FrameLoader::shouldReloadToHandleUnreachableURL(DocumentLoader* docLoader) if (unreachableURL.isEmpty()) return false; - if (!isBackForwardLoadType(m_policyLoadType)) + if (!isBackForwardLoadType(policyChecker()->loadType())) return false; // We only treat unreachableURLs specially during the delegate callbacks @@ -2585,7 +2245,7 @@ bool FrameLoader::shouldReloadToHandleUnreachableURL(DocumentLoader* docLoader) // case handles malformed URLs and unknown schemes. Loading alternate content // at other times behaves like a standard load. DocumentLoader* compareDocumentLoader = 0; - if (m_delegateIsDecidingNavigationPolicy || m_delegateIsHandlingUnimplementablePolicy) + if (policyChecker()->delegateIsDecidingNavigationPolicy() || policyChecker()->delegateIsHandlingUnimplementablePolicy()) compareDocumentLoader = m_policyDocumentLoader.get(); else if (m_delegateIsHandlingProvisionalLoadError) compareDocumentLoader = m_provisionalDocumentLoader.get(); @@ -2676,7 +2336,8 @@ bool FrameLoader::shouldAllowNavigation(Frame* targetFrame) const // // Or the target frame is: // - a top-level frame in the frame hierarchy and the active frame can - // navigate the target frame's opener per above. + // navigate the target frame's opener per above or it is the opener of + // the target frame. if (!targetFrame) return true; @@ -2691,6 +2352,10 @@ bool FrameLoader::shouldAllowNavigation(Frame* targetFrame) const if (targetFrame == m_frame->tree()->top()) return true; + // Let a frame navigate its opener if the opener is a top-level window. + if (!targetFrame->tree()->parent() && m_frame->loader()->opener() == targetFrame) + return true; + Document* activeDocument = m_frame->document(); ASSERT(activeDocument); const SecurityOrigin* activeSecurityOrigin = activeDocument->securityOrigin(); @@ -2725,6 +2390,7 @@ void FrameLoader::stopLoadingSubframes() void FrameLoader::stopAllLoaders(DatabasePolicy databasePolicy) { + ASSERT(!m_frame->document() || !m_frame->document()->inPageCache()); if (m_unloadEventBeingDispatched) return; @@ -2734,7 +2400,7 @@ void FrameLoader::stopAllLoaders(DatabasePolicy databasePolicy) m_inStopAllLoaders = true; - stopPolicyCheck(); + policyChecker()->stopCheck(); stopLoadingSubframes(); if (m_provisionalDocumentLoader) @@ -2862,7 +2528,8 @@ void FrameLoader::commitProvisionalLoad(PassRefPtr prpCachedPage) RefPtr cachedPage = prpCachedPage; RefPtr pdl = m_provisionalDocumentLoader; - LOG(Loading, "WebCoreLoading %s: About to commit provisional load from previous URL %s", m_frame->tree()->name().string().utf8().data(), m_URL.string().utf8().data()); + LOG(PageCache, "WebCoreLoading %s: About to commit provisional load from previous URL '%s' to new URL '%s'", m_frame->tree()->name().string().utf8().data(), m_URL.string().utf8().data(), + pdl ? pdl->url().string().utf8().data() : ""); // Check to see if we need to cache the page we are navigating away from into the back/forward cache. // We are doing this here because we know for sure that a new page is about to be loaded. @@ -2883,10 +2550,9 @@ void FrameLoader::commitProvisionalLoad(PassRefPtr prpCachedPage) if (m_sentRedirectNotification) clientRedirectCancelledOrFinished(false); - if (cachedPage && cachedPage->document()) { + if (cachedPage && cachedPage->document()) open(*cachedPage); - cachedPage->clear(); - } else { + else { KURL url = pdl->substituteData().responseURL(); if (url.isEmpty()) url = pdl->url(); @@ -2903,11 +2569,11 @@ void FrameLoader::commitProvisionalLoad(PassRefPtr prpCachedPage) if (m_loadType == FrameLoadTypeStandard && m_documentLoader->isClientRedirect()) updateHistoryForClientRedirect(); - if (m_documentLoader->isLoadingFromCachedPage()) { + if (m_loadingFromCachedPage) { m_frame->document()->documentDidBecomeActive(); // Force a layout to update view size and thereby update scrollbars. - m_client->forceLayout(); + m_frame->view()->forceLayout(); const ResponseVector& responses = m_documentLoader->responses(); size_t count = responses.size(); @@ -3104,7 +2770,7 @@ void FrameLoader::open(CachedPage& cachedPage) ASSERT(m_frame->page()); ASSERT(m_frame->page()->mainFrame() == m_frame); - cancelRedirection(); + m_frame->redirectScheduler()->cancel(); // We still have to close the previous part page. closeURL(); @@ -3115,13 +2781,12 @@ void FrameLoader::open(CachedPage& cachedPage) m_frame->setJSDefaultStatusBarText(String()); } - open(*cachedPage.cachedMainFrame()); cachedPage.restore(m_frame->page()); checkCompleted(); } -void FrameLoader::open(CachedFrame& cachedFrame) +void FrameLoader::open(CachedFrameBase& cachedFrame) { m_isComplete = false; @@ -3137,8 +2802,7 @@ void FrameLoader::open(CachedFrame& cachedFrame) m_workingURL = url; started(); - - clear(); + clear(true, true, cachedFrame.isMainFrame()); Document* document = cachedFrame.document(); ASSERT(document); @@ -3153,8 +2817,11 @@ void FrameLoader::open(CachedFrame& cachedFrame) // When navigating to a CachedFrame its FrameView should never be null. If it is we'll crash in creative ways downstream. ASSERT(view); - if (view) - view->setWasScrolledByUser(false); + view->setWasScrolledByUser(false); + + // Use the current ScrollView's frame rect. + if (m_frame->view()) + view->setFrameRect(m_frame->view()->frameRect()); m_frame->setView(view); m_frame->setDocument(document); @@ -3215,12 +2882,6 @@ String FrameLoader::generatedMIMETypeForURLScheme(const String& URLScheme) return m_client->generatedMIMETypeForURLScheme(URLScheme); } -void FrameLoader::cancelContentPolicyCheck() -{ - m_client->cancelPolicyCheck(); - m_policyCheck.clear(); -} - void FrameLoader::didReceiveServerRedirectForProvisionalLoadForFrame() { m_client->dispatchDidReceiveServerRedirectForProvisionalLoad(); @@ -3344,14 +3005,6 @@ CachePolicy FrameLoader::subresourceCachePolicy() const return CachePolicyVerify; } -void FrameLoader::stopPolicyCheck() -{ - m_client->cancelPolicyCheck(); - PolicyCheck check = m_policyCheck; - m_policyCheck.clear(); - check.cancel(); -} - void FrameLoader::checkLoadCompleteForThisFrame() { ASSERT(m_client->hasWebView()); @@ -3456,14 +3109,7 @@ void FrameLoader::checkLoadCompleteForThisFrame() ASSERT_NOT_REACHED(); } -void FrameLoader::continueAfterContentPolicy(PolicyAction policy) -{ - PolicyCheck check = m_policyCheck; - m_policyCheck.clear(); - check.call(policy); -} - -void FrameLoader::continueLoadAfterWillSubmitForm(PolicyAction) +void FrameLoader::continueLoadAfterWillSubmitForm() { if (!m_provisionalDocumentLoader) return; @@ -3480,7 +3126,7 @@ void FrameLoader::continueLoadAfterWillSubmitForm(PolicyAction) if (activeDocLoader && activeDocLoader->isLoadingMainResource()) return; - m_provisionalDocumentLoader->setLoadingFromCachedPage(false); + m_loadingFromCachedPage = false; unsigned long identifier = 0; @@ -3544,7 +3190,7 @@ void FrameLoader::closeAndRemoveChild(Frame* child) child->tree()->detachFromParent(); child->setView(0); - if (child->ownerElement()) + if (child->ownerElement() && child->page()) child->page()->decrementFrameCount(); child->pageDestroyed(); @@ -3570,6 +3216,8 @@ void FrameLoader::checkLoadComplete() { ASSERT(m_client->hasWebView()); + m_shouldCallCheckLoadComplete = false; + // FIXME: Always traversing the entire frame tree is a bit inefficient, but // is currently needed in order to null out the previous history item for all frames. if (Page* page = m_frame->page()) @@ -3618,12 +3266,13 @@ void FrameLoader::detachFromParent() saveScrollPositionAndViewStateToItem(currentHistoryItem()); detachChildren(); +#if ENABLE(INSPECTOR) if (Page* page = m_frame->page()) page->inspectorController()->frameDetachedFromParent(m_frame); +#endif + + detachViewsAndDocumentLoader(); - m_client->detachedFromParent2(); - setDocumentLoader(0); - m_client->detachedFromParent3(); if (Frame* parent = m_frame->tree()->parent()) { parent->loader()->closeAndRemoveChild(m_frame); parent->loader()->scheduleCheckCompleted(); @@ -3632,6 +3281,13 @@ void FrameLoader::detachFromParent() m_frame->pageDestroyed(); } } + +void FrameLoader::detachViewsAndDocumentLoader() +{ + m_client->detachedFromParent2(); + setDocumentLoader(0); + m_client->detachedFromParent3(); +} void FrameLoader::addExtraFieldsToSubresourceRequest(ResourceRequest& request) { @@ -3759,7 +3415,7 @@ void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String if (Frame* targetFrame = formState ? 0 : findFrameForNavigation(frameName)) targetFrame->loader()->loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, formState.release()); else - checkNewWindowPolicy(action, workingResourceRequest, formState.release(), frameName); + policyChecker()->checkNewWindowPolicy(action, FrameLoader::callContinueLoadAfterNewWindowPolicy, workingResourceRequest, formState.release(), frameName, this); } else loadWithNavigationAction(workingResourceRequest, action, lockHistory, loadType, formState.release()); } @@ -3767,7 +3423,7 @@ void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String unsigned long FrameLoader::loadResourceSynchronously(const ResourceRequest& request, StoredCredentials storedCredentials, ResourceError& error, ResourceResponse& response, Vector& data) { String referrer = m_outgoingReferrer; - if (shouldHideReferrer(request.url(), referrer)) + if (SecurityOrigin::shouldHideReferrer(request.url(), referrer)) referrer = String(); ResourceRequest initialRequest = request; @@ -3898,7 +3554,7 @@ void FrameLoader::callContinueFragmentScrollAfterNavigationPolicy(void* argument void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequest& request, bool shouldContinue) { - bool isRedirect = m_quickRedirectComing || m_policyLoadType == FrameLoadTypeRedirectWithLockedBackForwardList; + bool isRedirect = m_quickRedirectComing || policyChecker()->loadType() == FrameLoadTypeRedirectWithLockedBackForwardList; m_quickRedirectComing = false; if (!shouldContinue) @@ -3961,101 +3617,6 @@ bool FrameLoader::shouldScrollToAnchor(bool isFormSubmission, FrameLoadType load && !m_frame->document()->isFrameSet(); } -void FrameLoader::checkNewWindowPolicy(const NavigationAction& action, const ResourceRequest& request, - PassRefPtr formState, const String& frameName) -{ - m_policyCheck.set(request, formState, frameName, - callContinueLoadAfterNewWindowPolicy, this); - m_client->dispatchDecidePolicyForNewWindowAction(&FrameLoader::continueAfterNewWindowPolicy, - action, request, formState, frameName); -} - -void FrameLoader::continueAfterNewWindowPolicy(PolicyAction policy) -{ - PolicyCheck check = m_policyCheck; - m_policyCheck.clear(); - - switch (policy) { - case PolicyIgnore: - check.clearRequest(); - break; - case PolicyDownload: - m_client->startDownload(check.request()); - check.clearRequest(); - break; - case PolicyUse: - break; - } - - check.call(policy == PolicyUse); -} - -void FrameLoader::checkNavigationPolicy(const ResourceRequest& request, DocumentLoader* loader, - PassRefPtr formState, NavigationPolicyDecisionFunction function, void* argument) -{ - NavigationAction action = loader->triggeringAction(); - if (action.isEmpty()) { - action = NavigationAction(request.url(), NavigationTypeOther); - loader->setTriggeringAction(action); - } - - // Don't ask more than once for the same request or if we are loading an empty URL. - // This avoids confusion on the part of the client. - if (equalIgnoringHeaderFields(request, loader->lastCheckedRequest()) || (!request.isNull() && request.url().isEmpty())) { - function(argument, request, 0, true); - loader->setLastCheckedRequest(request); - return; - } - - // We are always willing to show alternate content for unreachable URLs; - // treat it like a reload so it maintains the right state for b/f list. - if (loader->substituteData().isValid() && !loader->substituteData().failingURL().isEmpty()) { - if (isBackForwardLoadType(m_policyLoadType)) - m_policyLoadType = FrameLoadTypeReload; - function(argument, request, 0, true); - return; - } - - loader->setLastCheckedRequest(request); - - m_policyCheck.set(request, formState.get(), function, argument); - - m_delegateIsDecidingNavigationPolicy = true; - m_client->dispatchDecidePolicyForNavigationAction(&FrameLoader::continueAfterNavigationPolicy, - action, request, formState); - m_delegateIsDecidingNavigationPolicy = false; -} - -void FrameLoader::continueAfterNavigationPolicy(PolicyAction policy) -{ - PolicyCheck check = m_policyCheck; - m_policyCheck.clear(); - - bool shouldContinue = policy == PolicyUse; - - switch (policy) { - case PolicyIgnore: - check.clearRequest(); - break; - case PolicyDownload: - m_client->startDownload(check.request()); - check.clearRequest(); - break; - case PolicyUse: { - ResourceRequest request(check.request()); - - if (!m_client->canHandleRequest(request)) { - handleUnimplementablePolicy(m_client->cannotShowURLError(check.request())); - check.clearRequest(); - shouldContinue = false; - } - break; - } - } - - check.call(shouldContinue); -} - void FrameLoader::callContinueLoadAfterNavigationPolicy(void* argument, const ResourceRequest& request, PassRefPtr formState, bool shouldContinue) { @@ -4090,7 +3651,7 @@ void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, Pass // If the navigation request came from the back/forward menu, and we punt on it, we have the // problem that we have optimistically moved the b/f cursor already, so move it back. For sanity, // we only do this when punting a navigation for the target frame or top-level frame. - if ((isTargetItem || isLoadingMainFrame()) && isBackForwardLoadType(m_policyLoadType)) + if ((isTargetItem || isLoadingMainFrame()) && isBackForwardLoadType(policyChecker()->loadType())) if (Page* page = m_frame->page()) { Frame* mainFrame = page->mainFrame(); if (HistoryItem* resetItem = mainFrame->loader()->m_currentHistoryItem.get()) { @@ -4102,7 +3663,7 @@ void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, Pass return; } - FrameLoadType type = m_policyLoadType; + FrameLoadType type = policyChecker()->loadType(); stopAllLoaders(); // - In certain circumstances on pages with multiple frames, stopAllLoaders() @@ -4110,7 +3671,7 @@ void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, Pass if (!m_frame->page()) return; -#if ENABLE(JAVASCRIPT_DEBUGGER) +#if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR) if (Page* page = m_frame->page()) { if (page->mainFrame() == m_frame) page->inspectorController()->resumeDebugger(); @@ -4127,12 +3688,11 @@ void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, Pass return; if (formState) - m_client->dispatchWillSubmitForm(&FrameLoader::continueLoadAfterWillSubmitForm, formState); + m_client->dispatchWillSubmitForm(&PolicyChecker::continueLoadAfterWillSubmitForm, formState); else continueLoadAfterWillSubmitForm(); } - void FrameLoader::callContinueLoadAfterNewWindowPolicy(void* argument, const ResourceRequest& request, PassRefPtr formState, const String& frameName, bool shouldContinue) { @@ -4154,7 +3714,7 @@ void FrameLoader::continueLoadAfterNewWindowPolicy(const ResourceRequest& reques if (frameName != "_blank") mainFrame->tree()->setName(frameName); - mainFrame->loader()->setOpenedByDOM(); + mainFrame->page()->setOpenedByDOM(); mainFrame->loader()->m_client->dispatchShow(); mainFrame->loader()->setOpener(frame.get()); mainFrame->loader()->loadWithNavigationAction(request, NavigationAction(), false, FrameLoadTypeStandard, formState); @@ -4201,7 +3761,9 @@ void FrameLoader::loadedResourceFromMemoryCache(const CachedResource* resource) if (!page) return; +#if ENABLE(INSPECTOR) page->inspectorController()->didLoadResourceFromMemoryCache(m_documentLoader.get(), resource); +#endif if (!resource->sendResourceLoadCallbacks() || m_documentLoader->haveToldClientAboutLoad(resource->url())) return; @@ -4249,26 +3811,6 @@ bool FrameLoader::shouldInterruptLoadForXFrameOptions(const String& content, con return false; } -bool FrameLoader::canGoBackOrForward(int distance) const -{ - if (Page* page = m_frame->page()) { - if (distance == 0) - return true; - if (distance > 0 && distance <= page->backForwardList()->forwardListCount()) - return true; - if (distance < 0 && -distance <= page->backForwardList()->backListCount()) - return true; - } - return false; -} - -int FrameLoader::getHistoryLength() -{ - if (Page* page = m_frame->page()) - return page->backForwardList()->backListCount() + 1; - return 0; -} - void FrameLoader::addHistoryItemForFragmentScroll() { addBackForwardItemClippedAtTarget(false); @@ -4279,7 +3821,17 @@ bool FrameLoader::loadProvisionalItemFromCachedPage() RefPtr cachedPage = pageCache()->get(m_provisionalHistoryItem.get()); if (!cachedPage || !cachedPage->document()) return false; - provisionalDocumentLoader()->loadFromCachedPage(cachedPage.release()); + + DocumentLoader *provisionalLoader = provisionalDocumentLoader(); + LOG(PageCache, "WebCorePageCache: FrameLoader %p loading provisional DocumentLoader %p with URL '%s' from CachedPage %p", this, provisionalLoader, provisionalLoader->url().string().utf8().data(), cachedPage.get()); + + provisionalLoader->prepareForLoadStart(); + + m_loadingFromCachedPage = true; + + provisionalLoader->setCommitted(true); + commitProvisionalLoad(cachedPage); + return true; } @@ -4288,12 +3840,26 @@ void FrameLoader::cachePageForHistoryItem(HistoryItem* item) if (!canCachePage() || item->isInPageCache()) return; + pageHidden(); + if (Page* page = m_frame->page()) { RefPtr cachedPage = CachedPage::create(page); pageCache()->add(item, cachedPage.release()); } } +void FrameLoader::pageHidden() +{ + m_unloadEventBeingDispatched = true; + if (m_frame->domWindow()) + m_frame->domWindow()->dispatchEvent(PageTransitionEvent::create(EventNames().pagehideEvent, true), m_frame->document()); + m_unloadEventBeingDispatched = false; + + // Send pagehide event for subframes as well + for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) + child->loader()->pageHidden(); +} + bool FrameLoader::shouldTreatURLAsSameAsCurrent(const KURL& url) const { if (!m_currentHistoryItem) @@ -5038,94 +4604,6 @@ void FrameLoader::didCancelAuthenticationChallenge(ResourceLoader* loader, const m_client->dispatchDidCancelAuthenticationChallenge(loader->documentLoader(), loader->identifier(), currentWebChallenge); } -PolicyCheck::PolicyCheck() - : m_navigationFunction(0) - , m_newWindowFunction(0) - , m_contentFunction(0) -{ -} - -void PolicyCheck::clear() -{ - clearRequest(); - m_navigationFunction = 0; - m_newWindowFunction = 0; - m_contentFunction = 0; -} - -void PolicyCheck::set(const ResourceRequest& request, PassRefPtr formState, - NavigationPolicyDecisionFunction function, void* argument) -{ - m_request = request; - m_formState = formState; - m_frameName = String(); - - m_navigationFunction = function; - m_newWindowFunction = 0; - m_contentFunction = 0; - m_argument = argument; -} - -void PolicyCheck::set(const ResourceRequest& request, PassRefPtr formState, - const String& frameName, NewWindowPolicyDecisionFunction function, void* argument) -{ - m_request = request; - m_formState = formState; - m_frameName = frameName; - - m_navigationFunction = 0; - m_newWindowFunction = function; - m_contentFunction = 0; - m_argument = argument; -} - -void PolicyCheck::set(ContentPolicyDecisionFunction function, void* argument) -{ - m_request = ResourceRequest(); - m_formState = 0; - m_frameName = String(); - - m_navigationFunction = 0; - m_newWindowFunction = 0; - m_contentFunction = function; - m_argument = argument; -} - -void PolicyCheck::call(bool shouldContinue) -{ - if (m_navigationFunction) - m_navigationFunction(m_argument, m_request, m_formState.get(), shouldContinue); - if (m_newWindowFunction) - m_newWindowFunction(m_argument, m_request, m_formState.get(), m_frameName, shouldContinue); - ASSERT(!m_contentFunction); -} - -void PolicyCheck::call(PolicyAction action) -{ - ASSERT(!m_navigationFunction); - ASSERT(!m_newWindowFunction); - ASSERT(m_contentFunction); - m_contentFunction(m_argument, action); -} - -void PolicyCheck::clearRequest() -{ - m_request = ResourceRequest(); - m_formState = 0; - m_frameName = String(); -} - -void PolicyCheck::cancel() -{ - clearRequest(); - if (m_navigationFunction) - m_navigationFunction(m_argument, m_request, m_formState.get(), false); - if (m_newWindowFunction) - m_newWindowFunction(m_argument, m_request, m_formState.get(), m_frameName, false); - if (m_contentFunction) - m_contentFunction(m_argument, PolicyIgnore); -} - void FrameLoader::setTitle(const String& title) { documentLoader()->setTitle(title); @@ -5143,6 +4621,7 @@ String FrameLoader::referrer() const void FrameLoader::dispatchDocumentElementAvailable() { + m_frame->injectUserScripts(InjectAtDocumentStart); m_client->documentElementAvailable(); } @@ -5153,12 +4632,14 @@ void FrameLoader::dispatchWindowObjectAvailable() m_client->windowObjectCleared(); +#if ENABLE(INSPECTOR) if (Page* page = m_frame->page()) { if (InspectorController* inspector = page->inspectorController()) inspector->inspectedWindowScriptObjectCleared(m_frame); if (InspectorController* inspector = page->parentInspectorController()) inspector->windowScriptObjectAvailable(); } +#endif } PassRefPtr FrameLoader::createJavaAppletWidget(const IntSize& size, HTMLAppletElement* element, const HashMap& args) @@ -5179,7 +4660,7 @@ PassRefPtr FrameLoader::createJavaAppletWidget(const IntSize& size, HTML if (!codeBaseURLString.isEmpty()) { KURL codeBaseURL = completeURL(codeBaseURLString); - if (!canLoad(codeBaseURL, String(), element->document())) { + if (!SecurityOrigin::canLoad(codeBaseURL, String(), element->document())) { FrameLoader::reportLocalLoadFailed(m_frame, codeBaseURL.string()); return 0; } @@ -5223,16 +4704,20 @@ void FrameLoader::dispatchDidCommitLoad() m_client->dispatchDidCommitLoad(); +#if ENABLE(INSPECTOR) if (Page* page = m_frame->page()) page->inspectorController()->didCommitLoad(m_documentLoader.get()); +#endif } void FrameLoader::dispatchAssignIdentifierToInitialRequest(unsigned long identifier, DocumentLoader* loader, const ResourceRequest& request) { m_client->assignIdentifierToInitialRequest(identifier, loader, request); +#if ENABLE(INSPECTOR) if (Page* page = m_frame->page()) page->inspectorController()->identifierForInitialRequest(identifier, loader, request); +#endif } void FrameLoader::dispatchWillSendRequest(DocumentLoader* loader, unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse) @@ -5246,32 +4731,40 @@ void FrameLoader::dispatchWillSendRequest(DocumentLoader* loader, unsigned long if (!request.isNull() && oldRequestURL != request.url().string().impl()) m_documentLoader->didTellClientAboutLoad(request.url()); +#if ENABLE(INSPECTOR) if (Page* page = m_frame->page()) page->inspectorController()->willSendRequest(loader, identifier, request, redirectResponse); +#endif } void FrameLoader::dispatchDidReceiveResponse(DocumentLoader* loader, unsigned long identifier, const ResourceResponse& r) { m_client->dispatchDidReceiveResponse(loader, identifier, r); +#if ENABLE(INSPECTOR) if (Page* page = m_frame->page()) page->inspectorController()->didReceiveResponse(loader, identifier, r); +#endif } void FrameLoader::dispatchDidReceiveContentLength(DocumentLoader* loader, unsigned long identifier, int length) { m_client->dispatchDidReceiveContentLength(loader, identifier, length); +#if ENABLE(INSPECTOR) if (Page* page = m_frame->page()) page->inspectorController()->didReceiveContentLength(loader, identifier, length); +#endif } void FrameLoader::dispatchDidFinishLoading(DocumentLoader* loader, unsigned long identifier) { m_client->dispatchDidFinishLoading(loader, identifier); +#if ENABLE(INSPECTOR) if (Page* page = m_frame->page()) page->inspectorController()->didFinishLoading(loader, identifier); +#endif } void FrameLoader::tellClientAboutPastMemoryCacheLoads() diff --git a/WebCore/loader/FrameLoader.h b/WebCore/loader/FrameLoader.h index 3d3f9c3..3a1d27f 100644 --- a/WebCore/loader/FrameLoader.h +++ b/WebCore/loader/FrameLoader.h @@ -32,9 +32,13 @@ #include "CachePolicy.h" #include "FrameLoaderTypes.h" +#include "PolicyCallback.h" +#include "PolicyChecker.h" +#include "RedirectScheduler.h" #include "ResourceRequest.h" #include "ThreadableLoader.h" #include "Timer.h" +#include namespace WebCore { @@ -42,7 +46,7 @@ namespace WebCore { class Archive; #endif class AuthenticationChallenge; - class CachedFrame; + class CachedFrameBase; class CachedPage; class CachedResource; class Document; @@ -73,46 +77,10 @@ namespace WebCore { class Widget; struct FrameLoadRequest; - struct ScheduledRedirection; struct WindowFeatures; bool isBackForwardLoadType(FrameLoadType); - typedef void (*NavigationPolicyDecisionFunction)(void* argument, - const ResourceRequest&, PassRefPtr, bool shouldContinue); - typedef void (*NewWindowPolicyDecisionFunction)(void* argument, - const ResourceRequest&, PassRefPtr, const String& frameName, bool shouldContinue); - typedef void (*ContentPolicyDecisionFunction)(void* argument, PolicyAction); - - class PolicyCheck { - public: - PolicyCheck(); - - void clear(); - void set(const ResourceRequest&, PassRefPtr, - NavigationPolicyDecisionFunction, void* argument); - void set(const ResourceRequest&, PassRefPtr, const String& frameName, - NewWindowPolicyDecisionFunction, void* argument); - void set(ContentPolicyDecisionFunction, void* argument); - - const ResourceRequest& request() const { return m_request; } - void clearRequest(); - - void call(bool shouldContinue); - void call(PolicyAction); - void cancel(); - - private: - ResourceRequest m_request; - RefPtr m_formState; - String m_frameName; - - NavigationPolicyDecisionFunction m_navigationFunction; - NewWindowPolicyDecisionFunction m_newWindowFunction; - ContentPolicyDecisionFunction m_contentFunction; - void* m_argument; - }; - class FrameLoader : public Noncopyable { public: FrameLoader(Frame*, FrameLoaderClient*); @@ -122,6 +90,8 @@ namespace WebCore { Frame* frame() const { return m_frame; } + PolicyChecker* policyChecker() { return &m_policyChecker; } + // FIXME: This is not cool, people. There are too many different functions that all start loads. // We should aim to consolidate these into a smaller set of functions, and try to reuse more of // the logic by extracting common code paths. @@ -144,14 +114,8 @@ namespace WebCore { void loadArchive(PassRefPtr); #endif - // Returns true for any non-local URL. If document parameter is supplied, its local load policy dictates, - // otherwise if referrer is non-empty and represents a local file, then the local load is allowed. - static bool canLoad(const KURL&, const String& referrer, const Document*); - static bool canLoad(const KURL&, const String& referrer, const SecurityOrigin* = 0); static void reportLocalLoadFailed(Frame*, const String& url); - static bool shouldHideReferrer(const KURL&, const String& referrer); - // Called by createWindow in JSDOMWindowBase.cpp, e.g. to fulfill a modal dialog creation Frame* createWindow(FrameLoader* frameLoaderForFrameLookup, const FrameLoadRequest&, const WindowFeatures&, bool& created); @@ -195,6 +159,8 @@ namespace WebCore { void receivedMainResourceError(const ResourceError&, bool isComplete); void receivedData(const char*, int); + bool willLoadMediaElementURL(KURL&); + void handleFallbackContent(); bool isStopping() const; @@ -204,8 +170,6 @@ namespace WebCore { ResourceError fileDoesNotExistError(const ResourceResponse&) const; ResourceError blockedError(const ResourceRequest&) const; ResourceError cannotShowURLError(const ResourceRequest&) const; - - void cannotShowMIMEType(const ResourceResponse&); ResourceError interruptionForPolicyChangeError(const ResourceRequest&); bool isHostedByObjectElement() const; @@ -214,10 +178,6 @@ namespace WebCore { bool representationExistsForURLScheme(const String& URLScheme); String generatedMIMETypeForURLScheme(const String& URLScheme); - void checkNavigationPolicy(const ResourceRequest&, NavigationPolicyDecisionFunction function, void* argument); - void checkContentPolicy(const String& MIMEType, ContentPolicyDecisionFunction, void* argument); - void cancelContentPolicyCheck(); - void reload(bool endToEndReload = false); void reloadWithOverrideEncoding(const String& overrideEncoding); @@ -246,6 +206,7 @@ namespace WebCore { void checkLoadComplete(); void detachFromParent(); + void detachViewsAndDocumentLoader(); void addExtraFieldsToSubresourceRequest(ResourceRequest&); void addExtraFieldsToMainResourceRequest(ResourceRequest&); @@ -265,7 +226,7 @@ namespace WebCore { bool lockHistory, PassRefPtr, PassRefPtr); void stop(); - void stopLoading(bool sendUnload, DatabasePolicy = DatabasePolicyStop); + void stopLoading(UnloadEventPolicy, DatabasePolicy = DatabasePolicyStop); bool closeURL(); void didExplicitOpen(); @@ -275,16 +236,6 @@ namespace WebCore { KURL baseURL() const; - bool isScheduledLocationChangePending() const { return m_scheduledRedirection && isLocationChange(*m_scheduledRedirection); } - void scheduleHTTPRedirection(double delay, const String& url); - void scheduleLocationChange(const String& url, const String& referrer, bool lockHistory = true, bool lockBackForwardList = true, bool userGesture = false); - void scheduleRefresh(bool userGesture = false); - void scheduleHistoryNavigation(int steps); - - bool canGoBackOrForward(int distance) const; - void goBackOrForward(int distance); - int getHistoryLength(); - void begin(); void begin(const KURL&, bool dispatchWindowObjectAvailable = true, SecurityOrigin* forcedSecurityOrigin = 0); @@ -312,10 +263,13 @@ namespace WebCore { void dispatchDocumentElementAvailable(); void restoreDocumentState(); + // Mixed content related functions. + static bool isMixedContent(SecurityOrigin* context, const KURL&); + void checkIfDisplayInsecureContent(SecurityOrigin* context, const KURL&); + void checkIfRunInsecureContent(SecurityOrigin* context, const KURL&); + Frame* opener(); void setOpener(Frame*); - bool openedByDOM() const; - void setOpenedByDOM(); bool isProcessingUserGesture(); @@ -350,6 +304,7 @@ namespace WebCore { void setTitle(const String&); void commitProvisionalLoad(PassRefPtr); + bool isLoadingFromCachedPage() const { return m_loadingFromCachedPage; } void goToItem(HistoryItem*, FrameLoadType); void saveDocumentAndScrollState(); @@ -357,16 +312,8 @@ namespace WebCore { HistoryItem* currentHistoryItem(); void setCurrentHistoryItem(PassRefPtr); - enum LocalLoadPolicy { - AllowLocalLoadsForAll, // No restriction on local loads. - AllowLocalLoadsForLocalAndSubstituteData, - AllowLocalLoadsForLocalOnly, - }; - static void setLocalLoadPolicy(LocalLoadPolicy); - static bool restrictAccessToLocal(); - static bool allowSubstituteDataAccessToLocal(); - bool committingFirstRealLoad() const { return !m_creatingInitialEmptyDocument && !m_committedFirstRealDocumentLoad; } + bool committedFirstRealDocumentLoad() const { return m_committedFirstRealDocumentLoad; } void iconLoadDecisionAvailable(); @@ -379,6 +326,20 @@ namespace WebCore { bool shouldInterruptLoadForXFrameOptions(const String&, const KURL&); + void open(CachedFrameBase&); + + // FIXME: Should these really be public? + void completed(); + bool allAncestorsAreComplete() const; // including this + bool allChildrenAreComplete() const; // immediate children, not all descendants + void clientRedirected(const KURL&, double delay, double fireDate, bool lockBackForwardList); + void clientRedirectCancelledOrFinished(bool cancelWithLoadInProgress); + + // FIXME: This is public because this asynchronous callback from the FrameLoaderClient + // uses the policy machinery (and therefore is called via the PolicyChecker). Once we + // introduce a proper callback type for this function, we should make it private again. + void continueLoadAfterWillSubmitForm(); + private: PassRefPtr createHistoryItem(bool useOriginal); PassRefPtr createHistoryItemTree(Frame* targetFrame, bool clipAtTarget); @@ -405,17 +366,10 @@ namespace WebCore { void updateHistoryForClientRedirect(); void updateHistoryForCommit(); void updateHistoryForAnchorScroll(); - - void redirectionTimerFired(Timer*); - void checkCompletedTimerFired(Timer*); - void checkLoadCompleteTimerFired(Timer*); - - void cancelRedirection(bool newLoadInProgress = false); - void started(); + void checkTimerFired(Timer*); - void completed(); - void parentCompleted(); + void started(); bool shouldUsePlugin(const KURL&, const String& mimeType, bool hasFallback, bool& useFallback); bool loadPlugin(RenderPart*, const KURL&, const String& mimeType, @@ -423,6 +377,7 @@ namespace WebCore { bool loadProvisionalItemFromCachedPage(); void cachePageForHistoryItem(HistoryItem*); + void pageHidden(); void receivedFirstData(); @@ -443,25 +398,17 @@ namespace WebCore { void setLoadType(FrameLoadType); - void checkNavigationPolicy(const ResourceRequest&, DocumentLoader*, PassRefPtr, NavigationPolicyDecisionFunction, void* argument); - void checkNewWindowPolicy(const NavigationAction&, const ResourceRequest&, PassRefPtr, const String& frameName); - - void continueAfterNavigationPolicy(PolicyAction); - void continueAfterNewWindowPolicy(PolicyAction); - void continueAfterContentPolicy(PolicyAction); - void continueLoadAfterWillSubmitForm(PolicyAction = PolicyUse); - static void callContinueLoadAfterNavigationPolicy(void*, const ResourceRequest&, PassRefPtr, bool shouldContinue); - void continueLoadAfterNavigationPolicy(const ResourceRequest&, PassRefPtr, bool shouldContinue); static void callContinueLoadAfterNewWindowPolicy(void*, const ResourceRequest&, PassRefPtr, const String& frameName, bool shouldContinue); - void continueLoadAfterNewWindowPolicy(const ResourceRequest&, PassRefPtr, const String& frameName, bool shouldContinue); static void callContinueFragmentScrollAfterNavigationPolicy(void*, const ResourceRequest&, PassRefPtr, bool shouldContinue); + + void continueLoadAfterNavigationPolicy(const ResourceRequest&, PassRefPtr, bool shouldContinue); + void continueLoadAfterNewWindowPolicy(const ResourceRequest&, PassRefPtr, const String& frameName, bool shouldContinue); void continueFragmentScrollAfterNavigationPolicy(const ResourceRequest&, bool shouldContinue); + bool shouldScrollToAnchor(bool isFormSubmission, FrameLoadType, const KURL&); void addHistoryItemForFragmentScroll(); - void stopPolicyCheck(); - void checkLoadCompleteForThisFrame(); void setDocumentLoader(DocumentLoader*); @@ -472,18 +419,12 @@ namespace WebCore { void closeOldDataSources(); void open(CachedPage&); - void open(CachedFrame&); void updateHistoryAfterClientRedirect(); - void clear(bool clearWindowProperties = true, bool clearScriptObjects = true); + void clear(bool clearWindowProperties = true, bool clearScriptObjects = true, bool clearFrameView = true); bool shouldReloadToHandleUnreachableURL(DocumentLoader*); - void handleUnimplementablePolicy(const ResourceError&); - - void scheduleRedirection(ScheduledRedirection*); - void startRedirectionTimer(); - void stopRedirectionTimer(); void dispatchDidCommitLoad(); void dispatchAssignIdentifierToInitialRequest(unsigned long identifier, DocumentLoader*, const ResourceRequest&); @@ -492,9 +433,6 @@ namespace WebCore { void dispatchDidReceiveContentLength(DocumentLoader*, unsigned long identifier, int length); void dispatchDidFinishLoading(DocumentLoader*, unsigned long identifier); - static bool isLocationChange(const ScheduledRedirection&); - void scheduleFormSubmission(const FrameLoadRequest&, bool lockHistory, PassRefPtr, PassRefPtr); - void loadWithDocumentLoader(DocumentLoader*, FrameLoadType, PassRefPtr); // Calls continueLoadAfterNavigationPolicy void load(DocumentLoader*); // Calls loadWithDocumentLoader @@ -513,8 +451,6 @@ namespace WebCore { bool lockHistory, FrameLoadType, PassRefPtr, PassRefPtr); #endif - void clientRedirectCancelledOrFinished(bool cancelWithLoadInProgress); - void clientRedirected(const KURL&, double delay, double fireDate, bool lockBackForwardList); bool shouldReload(const KURL& currentURL, const KURL& destinationURL); void sendRemainingDelegateMessages(unsigned long identifier, const ResourceResponse&, int length, const ResourceError&); @@ -541,6 +477,7 @@ namespace WebCore { void scheduleCheckCompleted(); void scheduleCheckLoadComplete(); + void startCheckCompleteTimer(); KURL originalRequestURL() const; @@ -551,6 +488,8 @@ namespace WebCore { Frame* m_frame; FrameLoaderClient* m_client; + PolicyChecker m_policyChecker; + FrameState m_state; FrameLoadType m_loadType; @@ -562,15 +501,7 @@ namespace WebCore { RefPtr m_provisionalDocumentLoader; RefPtr m_policyDocumentLoader; - // This identifies the type of navigation action which prompted this load. Note - // that WebKit conveys this value as the WebActionNavigationTypeKey value - // on navigation action delegate callbacks. - FrameLoadType m_policyLoadType; - PolicyCheck m_policyCheck; - bool m_delegateIsHandlingProvisionalLoadError; - bool m_delegateIsDecidingNavigationPolicy; - bool m_delegateIsHandlingUnimplementablePolicy; bool m_firstLayoutDone; bool m_quickRedirectComing; @@ -598,8 +529,6 @@ namespace WebCore { bool m_cancellingWithLoadInProgress; - OwnPtr m_scheduledRedirection; - bool m_needsClear; bool m_receivedData; @@ -610,16 +539,14 @@ namespace WebCore { bool m_containsPlugIns; KURL m_submittedFormURL; - - Timer m_redirectionTimer; - Timer m_checkCompletedTimer; - Timer m_checkLoadCompleteTimer; + + Timer m_checkTimer; + bool m_shouldCallCheckCompleted; + bool m_shouldCallCheckLoadComplete; Frame* m_opener; HashSet m_openedFrames; - bool m_openedByDOM; - bool m_creatingInitialEmptyDocument; bool m_isDisplayingInitialEmptyDocument; bool m_committedFirstRealDocumentLoad; @@ -629,6 +556,7 @@ namespace WebCore { RefPtr m_provisionalHistoryItem; bool m_didPerformFirstNavigation; + bool m_loadingFromCachedPage; #ifndef NDEBUG bool m_didDispatchDidCommitLoad; diff --git a/WebCore/loader/FrameLoaderClient.h b/WebCore/loader/FrameLoaderClient.h index bca0d0b..7973ca5 100644 --- a/WebCore/loader/FrameLoaderClient.h +++ b/WebCore/loader/FrameLoaderClient.h @@ -60,22 +60,28 @@ namespace WebCore { class KURL; class NavigationAction; class PluginView; + class PolicyChecker; class ResourceError; class ResourceHandle; class ResourceLoader; struct ResourceRequest; class ResourceResponse; class ScriptString; + class SecurityOrigin; class SharedBuffer; class SubstituteData; class String; class Widget; +<<<<<<< HEAD:WebCore/loader/FrameLoaderClient.h #ifdef ANDROID_HISTORY_CLIENT class BackForwardList; #endif typedef void (FrameLoader::*FramePolicyFunction)(PolicyAction); +======= + typedef void (PolicyChecker::*FramePolicyFunction)(PolicyAction); +>>>>>>> webkit.org at 49305:WebCore/loader/FrameLoaderClient.h class FrameLoaderClient { public: @@ -173,6 +179,15 @@ namespace WebCore { virtual void dispatchDidChangeHistoryIndex(BackForwardList*) const = 0; #endif + // This frame has displayed inactive content (such as an image) from an + // insecure source. Inactive content cannot spread to other frames. + virtual void didDisplayInsecureContent() = 0; + + // The indicated security origin has run active content (such as a + // script) from an insecure source. Note that the insecure content can + // spread to other frames in the same origin. + virtual void didRunInsecureContent(SecurityOrigin*) = 0; + virtual ResourceError cancelledError(const ResourceRequest&) = 0; virtual ResourceError blockedError(const ResourceRequest&) = 0; virtual ResourceError cannotShowURLError(const ResourceRequest&) = 0; @@ -246,6 +261,7 @@ namespace WebCore { #endif virtual bool shouldUsePluginDocument(const String& /*mimeType*/) const { return false; } + virtual bool shouldLoadMediaElementURL(const KURL&) const { return true; } }; } // namespace WebCore diff --git a/WebCore/loader/FrameLoaderTypes.h b/WebCore/loader/FrameLoaderTypes.h index 940bb7f..76299f5 100644 --- a/WebCore/loader/FrameLoaderTypes.h +++ b/WebCore/loader/FrameLoaderTypes.h @@ -81,6 +81,12 @@ namespace WebCore { ObjectContentNetscapePlugin, ObjectContentOtherPlugin }; + + enum UnloadEventPolicy { + UnloadEventPolicyNone, + UnloadEventPolicyUnloadOnly, + UnloadEventPolicyUnloadAndPageHide + }; } #endif diff --git a/WebCore/loader/ImageDocument.cpp b/WebCore/loader/ImageDocument.cpp index 08f2e9a..9b5598d 100644 --- a/WebCore/loader/ImageDocument.cpp +++ b/WebCore/loader/ImageDocument.cpp @@ -54,10 +54,24 @@ using namespace HTMLNames; class ImageEventListener : public EventListener { public: static PassRefPtr create(ImageDocument* document) { return adoptRef(new ImageEventListener(document)); } - virtual void handleEvent(Event*, bool isWindowEvent); + static const ImageEventListener* cast(const EventListener* listener) + { + return listener->type() == ImageEventListenerType + ? static_cast(listener) + : 0; + } + + virtual bool operator==(const EventListener& other); private: - ImageEventListener(ImageDocument* document) : m_doc(document) { } + ImageEventListener(ImageDocument* document) + : EventListener(ImageEventListenerType) + , m_doc(document) + { + } + + virtual void handleEvent(ScriptExecutionContext*, Event*); + ImageDocument* m_doc; }; @@ -344,7 +358,7 @@ bool ImageDocument::shouldShrinkToFit() const // -------- -void ImageEventListener::handleEvent(Event* event, bool) +void ImageEventListener::handleEvent(ScriptExecutionContext*, Event* event) { if (event->type() == eventNames().resizeEvent) m_doc->windowSizeChanged(); @@ -354,6 +368,13 @@ void ImageEventListener::handleEvent(Event* event, bool) } } +bool ImageEventListener::operator==(const EventListener& listener) +{ + if (const ImageEventListener* imageEventListener = ImageEventListener::cast(&listener)) + return m_doc == imageEventListener->m_doc; + return false; +} + // -------- ImageDocumentElement::~ImageDocumentElement() diff --git a/WebCore/loader/ImageDocument.h b/WebCore/loader/ImageDocument.h index 1bc5245..080b250 100644 --- a/WebCore/loader/ImageDocument.h +++ b/WebCore/loader/ImageDocument.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,7 +35,7 @@ class ImageDocument : public HTMLDocument { public: static PassRefPtr create(Frame* frame) { - return new ImageDocument(frame); + return adoptRef(new ImageDocument(frame)); } CachedImage* cachedImage(); diff --git a/WebCore/loader/MainResourceLoader.cpp b/WebCore/loader/MainResourceLoader.cpp index 6c843e9..e7bdbcb 100644 --- a/WebCore/loader/MainResourceLoader.cpp +++ b/WebCore/loader/MainResourceLoader.cpp @@ -93,7 +93,7 @@ void MainResourceLoader::didCancel(const ResourceError& error) RefPtr protect(this); if (m_waitingForContentPolicy) { - frameLoader()->cancelContentPolicyCheck(); + frameLoader()->policyChecker()->cancelCheck(); ASSERT(m_waitingForContentPolicy); m_waitingForContentPolicy = false; deref(); // balances ref in didReceiveResponse @@ -172,13 +172,17 @@ void MainResourceLoader::willSendRequest(ResourceRequest& newRequest, const Reso // Don't set this on the first request. It is set when the main load was started. m_documentLoader->setRequest(newRequest); + Frame* top = m_frame->tree()->top(); + if (top != m_frame) + frameLoader()->checkIfDisplayInsecureContent(top->document()->securityOrigin(), newRequest.url()); + // FIXME: Ideally we'd stop the I/O until we hear back from the navigation policy delegate // listener. But there's no way to do that in practice. So instead we cancel later if the // listener tells us to. In practice that means the navigation policy needs to be decided // synchronously for these redirect cases. if (!redirectResponse.isNull()) { ref(); // balanced by deref in continueAfterNavigationPolicy - frameLoader()->checkNavigationPolicy(newRequest, callContinueAfterNavigationPolicy, this); + frameLoader()->policyChecker()->checkNavigationPolicy(newRequest, callContinueAfterNavigationPolicy, this); } } @@ -201,7 +205,7 @@ void MainResourceLoader::continueAfterContentPolicy(PolicyAction contentPolicy, // Prevent remote web archives from loading because they can claim to be from any domain and thus avoid cross-domain security checks (4120255). bool isRemoteWebArchive = equalIgnoringCase("application/x-webarchive", mimeType) && !m_substituteData.isValid() && !url.isLocalFile(); if (!frameLoader()->canShowMIMEType(mimeType) || isRemoteWebArchive) { - frameLoader()->cannotShowMIMEType(r); + frameLoader()->policyChecker()->cannotShowMIMEType(r); // Check reachedTerminalState since the load may have already been cancelled inside of _handleUnimplementablePolicyWithErrorCode::. if (!reachedTerminalState()) stopLoadingForPolicyChange(); @@ -316,7 +320,25 @@ void MainResourceLoader::didReceiveResponse(const ResourceResponse& r) ASSERT(!m_waitingForContentPolicy); m_waitingForContentPolicy = true; ref(); // balanced by deref in continueAfterContentPolicy and didCancel - frameLoader()->checkContentPolicy(m_response.mimeType(), callContinueAfterContentPolicy, this); + + ASSERT(frameLoader()->activeDocumentLoader()); + + // Always show content with valid substitute data. + if (frameLoader()->activeDocumentLoader()->substituteData().isValid()) { + callContinueAfterContentPolicy(this, PolicyUse); + return; + } + +#if ENABLE(FTPDIR) + // Respect the hidden FTP Directory Listing pref so it can be tested even if the policy delegate might otherwise disallow it + Settings* settings = m_frame->settings(); + if (settings && settings->forceFTPDirectoryListings() && m_response.mimeType() == "application/x-ftp-directory") { + callContinueAfterContentPolicy(this, PolicyUse); + return; + } +#endif + + frameLoader()->policyChecker()->checkContentPolicy(m_response.mimeType(), callContinueAfterContentPolicy, this); } void MainResourceLoader::didReceiveData(const char* data, int length, long long lengthReceived, bool allAtOnce) diff --git a/WebCore/loader/MediaDocument.cpp b/WebCore/loader/MediaDocument.cpp index 0b1fd59..656d0a0 100644 --- a/WebCore/loader/MediaDocument.cpp +++ b/WebCore/loader/MediaDocument.cpp @@ -226,8 +226,8 @@ void MediaDocument::replaceMediaElementTimerFired(Timer*) embedElement->setAttribute(widthAttr, "100%"); embedElement->setAttribute(heightAttr, "100%"); embedElement->setAttribute(nameAttr, "plugin"); - embedElement->setSrc(url().string()); - embedElement->setType(frame()->loader()->responseMIMEType()); + embedElement->setAttribute(srcAttr, url().string()); + embedElement->setAttribute(typeAttr, frame()->loader()->responseMIMEType()); ExceptionCode ec; videoElement->parent()->replaceChild(embedElement, videoElement, ec); diff --git a/WebCore/loader/MediaDocument.h b/WebCore/loader/MediaDocument.h index ac286f0..aa751ab 100644 --- a/WebCore/loader/MediaDocument.h +++ b/WebCore/loader/MediaDocument.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008,2009 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -36,22 +36,23 @@ class MediaDocument : public HTMLDocument { public: static PassRefPtr create(Frame* frame) { - return new MediaDocument(frame); + return adoptRef(new MediaDocument(frame)); } - - virtual void defaultEventHandler(Event*); + virtual ~MediaDocument(); void mediaElementSawUnsupportedTracks(); private: MediaDocument(Frame*); - virtual ~MediaDocument(); - Timer m_replaceMediaElementTimer; virtual bool isMediaDocument() const { return true; } virtual Tokenizer* createTokenizer(); + virtual void defaultEventHandler(Event*); + void replaceMediaElementTimerFired(Timer*); + + Timer m_replaceMediaElementTimer; }; } diff --git a/WebCore/loader/PlaceholderDocument.cpp b/WebCore/loader/PlaceholderDocument.cpp index e071aa8..af14c72 100644 --- a/WebCore/loader/PlaceholderDocument.cpp +++ b/WebCore/loader/PlaceholderDocument.cpp @@ -37,7 +37,7 @@ void PlaceholderDocument::attach() if (!styleSelector()) { RefPtr styleSheetList = StyleSheetList::create(this); - setStyleSelector(new CSSStyleSelector(this, userStyleSheet(), styleSheetList.get(), 0, true, false)); + setStyleSelector(new CSSStyleSelector(this, styleSheetList.get(), 0, pageUserSheet(), pageGroupUserSheets(), true, false)); } // Skipping Document::attach(). diff --git a/WebCore/loader/PlaceholderDocument.h b/WebCore/loader/PlaceholderDocument.h index c542370..a759266 100644 --- a/WebCore/loader/PlaceholderDocument.h +++ b/WebCore/loader/PlaceholderDocument.h @@ -34,7 +34,7 @@ class PlaceholderDocument : public Document { public: static PassRefPtr create(Frame* frame) { - return new PlaceholderDocument(frame); + return adoptRef(new PlaceholderDocument(frame)); } virtual void attach(); diff --git a/WebCore/loader/PluginDocument.cpp b/WebCore/loader/PluginDocument.cpp index 3500c98..788691f 100644 --- a/WebCore/loader/PluginDocument.cpp +++ b/WebCore/loader/PluginDocument.cpp @@ -88,8 +88,8 @@ void PluginTokenizer::createDocumentStructure() m_embedElement->setAttribute(heightAttr, "100%"); m_embedElement->setAttribute(nameAttr, "plugin"); - m_embedElement->setSrc(m_doc->url().string()); - m_embedElement->setType(m_doc->frame()->loader()->responseMIMEType()); + m_embedElement->setAttribute(srcAttr, m_doc->url().string()); + m_embedElement->setAttribute(typeAttr, m_doc->frame()->loader()->responseMIMEType()); body->appendChild(embedElement, ec); } diff --git a/WebCore/loader/PluginDocument.h b/WebCore/loader/PluginDocument.h index 35e4038..1d5c964 100644 --- a/WebCore/loader/PluginDocument.h +++ b/WebCore/loader/PluginDocument.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2008, 2009Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,7 +33,7 @@ class PluginDocument : public HTMLDocument { public: static PassRefPtr create(Frame* frame) { - return new PluginDocument(frame); + return adoptRef(new PluginDocument(frame)); } private: diff --git a/WebCore/loader/PolicyCallback.cpp b/WebCore/loader/PolicyCallback.cpp new file mode 100644 index 0000000..14799cf --- /dev/null +++ b/WebCore/loader/PolicyCallback.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * 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 + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "PolicyCallback.h" + +#include "FormState.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "HTMLFormElement.h" + +namespace WebCore { + +PolicyCallback::PolicyCallback() + : m_navigationFunction(0) + , m_newWindowFunction(0) + , m_contentFunction(0) +{ +} + +PolicyCallback::~PolicyCallback() +{ +} + +void PolicyCallback::clear() +{ + clearRequest(); + m_navigationFunction = 0; + m_newWindowFunction = 0; + m_contentFunction = 0; +} + +void PolicyCallback::set(const ResourceRequest& request, PassRefPtr formState, + NavigationPolicyDecisionFunction function, void* argument) +{ + m_request = request; + m_formState = formState; + m_frameName = String(); + + m_navigationFunction = function; + m_newWindowFunction = 0; + m_contentFunction = 0; + m_argument = argument; +} + +void PolicyCallback::set(const ResourceRequest& request, PassRefPtr formState, + const String& frameName, NewWindowPolicyDecisionFunction function, void* argument) +{ + m_request = request; + m_formState = formState; + m_frameName = frameName; + + m_navigationFunction = 0; + m_newWindowFunction = function; + m_contentFunction = 0; + m_argument = argument; +} + +void PolicyCallback::set(ContentPolicyDecisionFunction function, void* argument) +{ + m_request = ResourceRequest(); + m_formState = 0; + m_frameName = String(); + + m_navigationFunction = 0; + m_newWindowFunction = 0; + m_contentFunction = function; + m_argument = argument; +} + +void PolicyCallback::call(bool shouldContinue) +{ + if (m_navigationFunction) + m_navigationFunction(m_argument, m_request, m_formState.get(), shouldContinue); + if (m_newWindowFunction) + m_newWindowFunction(m_argument, m_request, m_formState.get(), m_frameName, shouldContinue); + ASSERT(!m_contentFunction); +} + +void PolicyCallback::call(PolicyAction action) +{ + ASSERT(!m_navigationFunction); + ASSERT(!m_newWindowFunction); + ASSERT(m_contentFunction); + m_contentFunction(m_argument, action); +} + +void PolicyCallback::clearRequest() +{ + m_request = ResourceRequest(); + m_formState = 0; + m_frameName = String(); +} + +void PolicyCallback::cancel() +{ + clearRequest(); + if (m_navigationFunction) + m_navigationFunction(m_argument, m_request, m_formState.get(), false); + if (m_newWindowFunction) + m_newWindowFunction(m_argument, m_request, m_formState.get(), m_frameName, false); + if (m_contentFunction) + m_contentFunction(m_argument, PolicyIgnore); +} + +} // namespace WebCore diff --git a/WebCore/loader/PolicyCallback.h b/WebCore/loader/PolicyCallback.h new file mode 100644 index 0000000..2aa7c7c --- /dev/null +++ b/WebCore/loader/PolicyCallback.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * 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 + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PolicyCallback_h +#define PolicyCallback_h + +#include "FrameLoaderTypes.h" +#include "PlatformString.h" +#include "ResourceRequest.h" +#include + +namespace WebCore { + + class FormState; + + typedef void (*NavigationPolicyDecisionFunction)(void* argument, + const ResourceRequest&, PassRefPtr, bool shouldContinue); + typedef void (*NewWindowPolicyDecisionFunction)(void* argument, + const ResourceRequest&, PassRefPtr, const String& frameName, bool shouldContinue); + typedef void (*ContentPolicyDecisionFunction)(void* argument, PolicyAction); + + class PolicyCallback { + public: + PolicyCallback(); + ~PolicyCallback(); + + void clear(); + void set(const ResourceRequest&, PassRefPtr, + NavigationPolicyDecisionFunction, void* argument); + void set(const ResourceRequest&, PassRefPtr, const String& frameName, + NewWindowPolicyDecisionFunction, void* argument); + void set(ContentPolicyDecisionFunction, void* argument); + + const ResourceRequest& request() const { return m_request; } + void clearRequest(); + + void call(bool shouldContinue); + void call(PolicyAction); + void cancel(); + + private: + ResourceRequest m_request; + RefPtr m_formState; + String m_frameName; + + NavigationPolicyDecisionFunction m_navigationFunction; + NewWindowPolicyDecisionFunction m_newWindowFunction; + ContentPolicyDecisionFunction m_contentFunction; + void* m_argument; + }; + +} // namespace WebCore + +#endif // PolicyCallback_h diff --git a/WebCore/loader/PolicyChecker.cpp b/WebCore/loader/PolicyChecker.cpp new file mode 100644 index 0000000..196ab4f --- /dev/null +++ b/WebCore/loader/PolicyChecker.cpp @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * 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 + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "PolicyChecker.h" + +#include "DocumentLoader.h" +#include "FormState.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameLoaderClient.h" +#include "HTMLFormElement.h" + +namespace WebCore { + +PolicyChecker::PolicyChecker(Frame* frame) + : m_frame(frame) + , m_delegateIsDecidingNavigationPolicy(false) + , m_delegateIsHandlingUnimplementablePolicy(false) + , m_loadType(FrameLoadTypeStandard) +{ +} + +void PolicyChecker::checkNavigationPolicy(const ResourceRequest& newRequest, NavigationPolicyDecisionFunction function, void* argument) +{ + checkNavigationPolicy(newRequest, m_frame->loader()->activeDocumentLoader(), 0, function, argument); +} + +void PolicyChecker::checkNavigationPolicy(const ResourceRequest& request, DocumentLoader* loader, + PassRefPtr formState, NavigationPolicyDecisionFunction function, void* argument) +{ + NavigationAction action = loader->triggeringAction(); + if (action.isEmpty()) { + action = NavigationAction(request.url(), NavigationTypeOther); + loader->setTriggeringAction(action); + } + + // Don't ask more than once for the same request or if we are loading an empty URL. + // This avoids confusion on the part of the client. + if (equalIgnoringHeaderFields(request, loader->lastCheckedRequest()) || (!request.isNull() && request.url().isEmpty())) { + function(argument, request, 0, true); + loader->setLastCheckedRequest(request); + return; + } + + // We are always willing to show alternate content for unreachable URLs; + // treat it like a reload so it maintains the right state for b/f list. + if (loader->substituteData().isValid() && !loader->substituteData().failingURL().isEmpty()) { + if (isBackForwardLoadType(m_loadType)) + m_loadType = FrameLoadTypeReload; + function(argument, request, 0, true); + return; + } + + loader->setLastCheckedRequest(request); + + m_callback.set(request, formState.get(), function, argument); + + m_delegateIsDecidingNavigationPolicy = true; + m_frame->loader()->client()->dispatchDecidePolicyForNavigationAction(&PolicyChecker::continueAfterNavigationPolicy, + action, request, formState); + m_delegateIsDecidingNavigationPolicy = false; +} + +void PolicyChecker::checkNewWindowPolicy(const NavigationAction& action, NewWindowPolicyDecisionFunction function, + const ResourceRequest& request, PassRefPtr formState, const String& frameName, void* argument) +{ + m_callback.set(request, formState, frameName, function, argument); + m_frame->loader()->client()->dispatchDecidePolicyForNewWindowAction(&PolicyChecker::continueAfterNewWindowPolicy, + action, request, formState, frameName); +} + +void PolicyChecker::checkContentPolicy(const String& MIMEType, ContentPolicyDecisionFunction function, void* argument) +{ + m_callback.set(function, argument); + m_frame->loader()->client()->dispatchDecidePolicyForMIMEType(&PolicyChecker::continueAfterContentPolicy, + MIMEType, m_frame->loader()->activeDocumentLoader()->request()); +} + +void PolicyChecker::cancelCheck() +{ + m_frame->loader()->client()->cancelPolicyCheck(); + m_callback.clear(); +} + +void PolicyChecker::stopCheck() +{ + m_frame->loader()->client()->cancelPolicyCheck(); + PolicyCallback callback = m_callback; + m_callback.clear(); + callback.cancel(); +} + +void PolicyChecker::cannotShowMIMEType(const ResourceResponse& response) +{ + handleUnimplementablePolicy(m_frame->loader()->client()->cannotShowMIMETypeError(response)); +} + +void PolicyChecker::continueLoadAfterWillSubmitForm(PolicyAction) +{ + // See header file for an explaination of why this function + // isn't like the others. + m_frame->loader()->continueLoadAfterWillSubmitForm(); +} + +void PolicyChecker::continueAfterNavigationPolicy(PolicyAction policy) +{ + PolicyCallback callback = m_callback; + m_callback.clear(); + + bool shouldContinue = policy == PolicyUse; + + switch (policy) { + case PolicyIgnore: + callback.clearRequest(); + break; + case PolicyDownload: + m_frame->loader()->client()->startDownload(callback.request()); + callback.clearRequest(); + break; + case PolicyUse: { + ResourceRequest request(callback.request()); + + if (!m_frame->loader()->client()->canHandleRequest(request)) { + handleUnimplementablePolicy(m_frame->loader()->cannotShowURLError(callback.request())); + callback.clearRequest(); + shouldContinue = false; + } + break; + } + } + + callback.call(shouldContinue); +} + +void PolicyChecker::continueAfterNewWindowPolicy(PolicyAction policy) +{ + PolicyCallback callback = m_callback; + m_callback.clear(); + + switch (policy) { + case PolicyIgnore: + callback.clearRequest(); + break; + case PolicyDownload: + m_frame->loader()->client()->startDownload(callback.request()); + callback.clearRequest(); + break; + case PolicyUse: + break; + } + + callback.call(policy == PolicyUse); +} + +void PolicyChecker::continueAfterContentPolicy(PolicyAction policy) +{ + PolicyCallback callback = m_callback; + m_callback.clear(); + callback.call(policy); +} + +void PolicyChecker::handleUnimplementablePolicy(const ResourceError& error) +{ + m_delegateIsHandlingUnimplementablePolicy = true; + m_frame->loader()->client()->dispatchUnableToImplementPolicy(error); + m_delegateIsHandlingUnimplementablePolicy = false; +} + +} // namespace WebCore diff --git a/WebCore/loader/PolicyChecker.h b/WebCore/loader/PolicyChecker.h new file mode 100644 index 0000000..c667f5b --- /dev/null +++ b/WebCore/loader/PolicyChecker.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * 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 + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PolicyChecker_h +#define PolicyChecker_h + +#include "FrameLoaderTypes.h" +#include "PlatformString.h" +#include "PolicyCallback.h" +#include "ResourceRequest.h" +#include + +namespace WebCore { + + class DocumentLoader; + class FormState; + class Frame; + class NavigationAction; + class ResourceError; + class ResourceResponse; + + class PolicyChecker : public Noncopyable { + public: + PolicyChecker(Frame*); + + void checkNavigationPolicy(const ResourceRequest&, DocumentLoader*, PassRefPtr, NavigationPolicyDecisionFunction, void* argument); + void checkNavigationPolicy(const ResourceRequest&, NavigationPolicyDecisionFunction, void* argument); + void checkNewWindowPolicy(const NavigationAction&, NewWindowPolicyDecisionFunction, const ResourceRequest&, PassRefPtr, const String& frameName, void* argument); + void checkContentPolicy(const String& MIMEType, ContentPolicyDecisionFunction, void* argument); + + // FIXME: These are different. They could use better names. + void cancelCheck(); + void stopCheck(); + + void cannotShowMIMEType(const ResourceResponse&); + + FrameLoadType loadType() const { return m_loadType; } + void setLoadType(FrameLoadType loadType) { m_loadType = loadType; } + + bool delegateIsDecidingNavigationPolicy() const { return m_delegateIsDecidingNavigationPolicy; } + bool delegateIsHandlingUnimplementablePolicy() const { return m_delegateIsHandlingUnimplementablePolicy; } + + // FIXME: This function is a cheat. Basically, this is just an asynchronouc callback + // from the FrameLoaderClient, but this callback uses the policy types and so has to + // live on this object. In the long term, we should create a type for non-policy + // callbacks from the FrameLoaderClient and remove this vestige. I just don't have + // the heart to hack on all the platforms to make that happen right now. + void continueLoadAfterWillSubmitForm(PolicyAction); + + private: + void continueAfterNavigationPolicy(PolicyAction); + void continueAfterNewWindowPolicy(PolicyAction); + void continueAfterContentPolicy(PolicyAction); + + void handleUnimplementablePolicy(const ResourceError&); + + Frame* m_frame; + + bool m_delegateIsDecidingNavigationPolicy; + bool m_delegateIsHandlingUnimplementablePolicy; + + // This identifies the type of navigation action which prompted this load. Note + // that WebKit conveys this value as the WebActionNavigationTypeKey value + // on navigation action delegate callbacks. + FrameLoadType m_loadType; + PolicyCallback m_callback; + }; + +} // namespace WebCore + +#endif // PolicyChecker_h diff --git a/WebCore/loader/RedirectScheduler.cpp b/WebCore/loader/RedirectScheduler.cpp new file mode 100644 index 0000000..819cbdd --- /dev/null +++ b/WebCore/loader/RedirectScheduler.cpp @@ -0,0 +1,374 @@ +/* + * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) + * Copyright (C) 2009 Adam Barth. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RedirectScheduler.h" + +#include "DocumentLoader.h" +#include "Event.h" +#include "FormState.h" +#include "Frame.h" +#include "FrameLoadRequest.h" +#include "FrameLoader.h" +#include "HTMLFormElement.h" +#include + +namespace WebCore { + +struct ScheduledRedirection { + enum Type { redirection, locationChange, historyNavigation, formSubmission }; + + const Type type; + const double delay; + const String url; + const String referrer; + const FrameLoadRequest frameRequest; + const RefPtr event; + const RefPtr formState; + const int historySteps; + const bool lockHistory; + const bool lockBackForwardList; + const bool wasUserGesture; + const bool wasRefresh; + const bool wasDuringLoad; + bool toldClient; + + ScheduledRedirection(double delay, const String& url, bool lockHistory, bool lockBackForwardList, bool wasUserGesture, bool refresh) + : type(redirection) + , delay(delay) + , url(url) + , historySteps(0) + , lockHistory(lockHistory) + , lockBackForwardList(lockBackForwardList) + , wasUserGesture(wasUserGesture) + , wasRefresh(refresh) + , wasDuringLoad(false) + , toldClient(false) + { + ASSERT(!url.isEmpty()); + } + + ScheduledRedirection(const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool wasUserGesture, bool refresh, bool duringLoad) + : type(locationChange) + , delay(0) + , url(url) + , referrer(referrer) + , historySteps(0) + , lockHistory(lockHistory) + , lockBackForwardList(lockBackForwardList) + , wasUserGesture(wasUserGesture) + , wasRefresh(refresh) + , wasDuringLoad(duringLoad) + , toldClient(false) + { + ASSERT(!url.isEmpty()); + } + + explicit ScheduledRedirection(int historyNavigationSteps) + : type(historyNavigation) + , delay(0) + , historySteps(historyNavigationSteps) + , lockHistory(false) + , lockBackForwardList(false) + , wasUserGesture(false) + , wasRefresh(false) + , wasDuringLoad(false) + , toldClient(false) + { + } + + ScheduledRedirection(const FrameLoadRequest& frameRequest, + bool lockHistory, bool lockBackForwardList, PassRefPtr event, PassRefPtr formState, + bool duringLoad) + : type(formSubmission) + , delay(0) + , frameRequest(frameRequest) + , event(event) + , formState(formState) + , historySteps(0) + , lockHistory(lockHistory) + , lockBackForwardList(lockBackForwardList) + , wasUserGesture(false) + , wasRefresh(false) + , wasDuringLoad(duringLoad) + , toldClient(false) + { + ASSERT(!frameRequest.isEmpty()); + ASSERT(this->formState); + } +}; + +RedirectScheduler::RedirectScheduler(Frame* frame) + : m_frame(frame) + , m_timer(this, &RedirectScheduler::timerFired) +{ +} + +RedirectScheduler::~RedirectScheduler() +{ +} + +bool RedirectScheduler::redirectScheduledDuringLoad() +{ + return m_scheduledRedirection && m_scheduledRedirection->wasDuringLoad; +} + +void RedirectScheduler::clear() +{ + m_timer.stop(); + m_scheduledRedirection.clear(); +} + +void RedirectScheduler::scheduleRedirect(double delay, const String& url) +{ + if (delay < 0 || delay > INT_MAX / 1000) + return; + + if (!m_frame->page()) + return; + + if (url.isEmpty()) + return; + + // We want a new history item if the refresh timeout is > 1 second. + if (!m_scheduledRedirection || delay <= m_scheduledRedirection->delay) + schedule(new ScheduledRedirection(delay, url, true, delay <= 1, false, false)); +} + +bool RedirectScheduler::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 RedirectScheduler::scheduleLocationChange(const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool wasUserGesture) +{ + if (!m_frame->page()) + return; + + if (url.isEmpty()) + return; + + lockBackForwardList = lockBackForwardList || mustLockBackForwardList(m_frame); + + FrameLoader* loader = m_frame->loader(); + + // 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(ParsedURLString, url); + if (parsedURL.hasFragmentIdentifier() && equalIgnoringFragmentIdentifier(loader->url(), parsedURL)) { + loader->changeLocation(loader->completeURL(url), referrer, lockHistory, lockBackForwardList, wasUserGesture); + return; + } + + // Handle a location change of a page with no document as a special case. + // This may happen when a frame changes the location of another frame. + bool duringLoad = !loader->committedFirstRealDocumentLoad(); + + schedule(new ScheduledRedirection(url, referrer, lockHistory, lockBackForwardList, wasUserGesture, false, duringLoad)); +} + +void RedirectScheduler::scheduleFormSubmission(const FrameLoadRequest& frameRequest, + bool lockHistory, PassRefPtr event, PassRefPtr formState) +{ + ASSERT(m_frame->page()); + ASSERT(!frameRequest.isEmpty()); + + // FIXME: Do we need special handling for form submissions where the URL is the same + // as the current one except for the fragment part? See scheduleLocationChange above. + + // Handle a location change of a page with no document as a special case. + // This may happen when a frame changes the location of another frame. + bool duringLoad = !m_frame->loader()->committedFirstRealDocumentLoad(); + + schedule(new ScheduledRedirection(frameRequest, lockHistory, mustLockBackForwardList(m_frame), event, formState, duringLoad)); +} + +void RedirectScheduler::scheduleRefresh(bool wasUserGesture) +{ + if (!m_frame->page()) + return; + + const KURL& url = m_frame->loader()->url(); + + if (url.isEmpty()) + return; + + schedule(new ScheduledRedirection(url.string(), m_frame->loader()->outgoingReferrer(), true, true, wasUserGesture, true, false)); +} + +bool RedirectScheduler::locationChangePending() +{ + if (!m_scheduledRedirection) + return false; + + switch (m_scheduledRedirection->type) { + case ScheduledRedirection::redirection: + return false; + case ScheduledRedirection::historyNavigation: + case ScheduledRedirection::locationChange: + case ScheduledRedirection::formSubmission: + return true; + } + ASSERT_NOT_REACHED(); + return false; +} + +void RedirectScheduler::scheduleHistoryNavigation(int steps) +{ + if (!m_frame->page()) + return; + + schedule(new ScheduledRedirection(steps)); +} + +void RedirectScheduler::timerFired(Timer*) +{ + ASSERT(m_frame->page()); + + if (m_frame->page()->defersLoading()) + return; + + OwnPtr redirection(m_scheduledRedirection.release()); + FrameLoader* loader = m_frame->loader(); + + switch (redirection->type) { + case ScheduledRedirection::redirection: + case ScheduledRedirection::locationChange: + loader->changeLocation(KURL(ParsedURLString, redirection->url), redirection->referrer, + redirection->lockHistory, redirection->lockBackForwardList, redirection->wasUserGesture, redirection->wasRefresh); + return; + case ScheduledRedirection::historyNavigation: + if (redirection->historySteps == 0) { + // Special case for go(0) from a frame -> reload only the frame + loader->urlSelected(loader->url(), "", 0, redirection->lockHistory, redirection->lockBackForwardList, redirection->wasUserGesture); + return; + } + // go(i!=0) from a frame navigates into the history of the frame only, + // in both IE and NS (but not in Mozilla). We can't easily do that. + if (m_frame->page()->canGoBackOrForward(redirection->historySteps)) + m_frame->page()->goBackOrForward(redirection->historySteps); + return; + case ScheduledRedirection::formSubmission: + // The submitForm function will find a target frame before using the redirection timer. + // Now that the timer has fired, we need to repeat the security check which normally is done when + // selecting a target, in case conditions have changed. Other code paths avoid this by targeting + // without leaving a time window. If we fail the check just silently drop the form submission. + if (!redirection->formState->sourceFrame()->loader()->shouldAllowNavigation(m_frame)) + return; + loader->loadFrameRequest(redirection->frameRequest, redirection->lockHistory, redirection->lockBackForwardList, + redirection->event, redirection->formState); + return; + } + + ASSERT_NOT_REACHED(); +} + +void RedirectScheduler::schedule(PassOwnPtr redirection) +{ + ASSERT(m_frame->page()); + FrameLoader* loader = m_frame->loader(); + + // If a redirect was scheduled during a load, then stop the current load. + // Otherwise when the current load transitions from a provisional to a + // committed state, pending redirects may be cancelled. + if (redirection->wasDuringLoad) { + if (DocumentLoader* provisionalDocumentLoader = loader->provisionalDocumentLoader()) + provisionalDocumentLoader->stopLoading(); + loader->stopLoading(UnloadEventPolicyUnloadAndPageHide); + } + + cancel(); + m_scheduledRedirection = redirection; + if (!loader->isComplete() && m_scheduledRedirection->type != ScheduledRedirection::redirection) + loader->completed(); + startTimer(); +} + +void RedirectScheduler::startTimer() +{ + if (!m_scheduledRedirection) + return; + + ASSERT(m_frame->page()); + + FrameLoader* loader = m_frame->loader(); + + if (m_timer.isActive()) + return; + + if (m_scheduledRedirection->type == ScheduledRedirection::redirection && !loader->allAncestorsAreComplete()) + return; + + m_timer.startOneShot(m_scheduledRedirection->delay); + + switch (m_scheduledRedirection->type) { + case ScheduledRedirection::locationChange: + case ScheduledRedirection::redirection: + if (m_scheduledRedirection->toldClient) + return; + m_scheduledRedirection->toldClient = true; + loader->clientRedirected(KURL(ParsedURLString, m_scheduledRedirection->url), + m_scheduledRedirection->delay, + currentTime() + m_timer.nextFireInterval(), + m_scheduledRedirection->lockBackForwardList); + return; + case ScheduledRedirection::formSubmission: + // FIXME: It would make sense to report form submissions as client redirects too. + // But we didn't do that in the past when form submission used a separate delay + // mechanism, so doing it will be a behavior change. + return; + case ScheduledRedirection::historyNavigation: + // Don't report history navigations. + return; + } + ASSERT_NOT_REACHED(); +} + +void RedirectScheduler::cancel(bool newLoadInProgress) +{ + m_timer.stop(); + + OwnPtr redirection(m_scheduledRedirection.release()); + if (redirection && redirection->toldClient) + m_frame->loader()->clientRedirectCancelledOrFinished(newLoadInProgress); +} + +} // namespace WebCore + diff --git a/WebCore/loader/RedirectScheduler.h b/WebCore/loader/RedirectScheduler.h new file mode 100644 index 0000000..bf076d6 --- /dev/null +++ b/WebCore/loader/RedirectScheduler.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) + * Copyright (C) 2009 Adam Barth. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RedirectScheduler_h +#define RedirectScheduler_h + +#include "Event.h" +#include "Timer.h" +#include +#include +#include + +namespace WebCore { + + class FormState; + class Frame; + class String; + + struct FrameLoadRequest; + struct ScheduledRedirection; + + class RedirectScheduler : public Noncopyable { + public: + RedirectScheduler(Frame*); + ~RedirectScheduler(); + + bool redirectScheduledDuringLoad(); + bool locationChangePending(); + + void scheduleRedirect(double delay, const String& url); + void scheduleLocationChange(const String& url, const String& referrer, bool lockHistory = true, bool lockBackForwardList = true, bool userGesture = false); + void scheduleFormSubmission(const FrameLoadRequest&, bool lockHistory, PassRefPtr, PassRefPtr); + void scheduleRefresh(bool userGesture = false); + void scheduleHistoryNavigation(int steps); + + void startTimer(); + + void cancel(bool newLoadInProgress = false); + void clear(); + + private: + void timerFired(Timer*); + void schedule(PassOwnPtr); + + static bool mustLockBackForwardList(Frame* targetFrame); + + Frame* m_frame; + Timer m_timer; + OwnPtr m_scheduledRedirection; + }; + +} // namespace WebCore + +#endif // FrameLoader_h diff --git a/WebCore/loader/ResourceLoader.cpp b/WebCore/loader/ResourceLoader.cpp index 5ad181b..2dac844 100644 --- a/WebCore/loader/ResourceLoader.cpp +++ b/WebCore/loader/ResourceLoader.cpp @@ -94,8 +94,9 @@ void ResourceLoader::releaseResources() if (m_handle) { // Clear out the ResourceHandle's client so that it doesn't try to call - // us back after we release it. - m_handle->setClient(0); + // us back after we release it, unless it has been replaced by someone else. + if (m_handle->client() == this) + m_handle->setClient(0); m_handle = 0; } diff --git a/WebCore/loader/SubresourceLoader.cpp b/WebCore/loader/SubresourceLoader.cpp index 047cc6d..2ee4626 100644 --- a/WebCore/loader/SubresourceLoader.cpp +++ b/WebCore/loader/SubresourceLoader.cpp @@ -33,6 +33,7 @@ #include "Frame.h" #include "FrameLoader.h" #include "ResourceHandle.h" +#include "SecurityOrigin.h" #include "SubresourceLoaderClient.h" #include @@ -72,13 +73,13 @@ PassRefPtr SubresourceLoader::create(Frame* frame, Subresourc ResourceRequest newRequest = request; if (!skipCanLoadCheck - && FrameLoader::restrictAccessToLocal() - && !FrameLoader::canLoad(request.url(), String(), frame->document())) { + && SecurityOrigin::restrictAccessToLocal() + && !SecurityOrigin::canLoad(request.url(), String(), frame->document())) { FrameLoader::reportLocalLoadFailed(frame, request.url().string()); return 0; } - if (FrameLoader::shouldHideReferrer(request.url(), fl->outgoingReferrer())) + if (SecurityOrigin::shouldHideReferrer(request.url(), fl->outgoingReferrer())) newRequest.clearHTTPReferrer(); else if (!request.httpReferrer()) newRequest.setHTTPReferrer(fl->outgoingReferrer()); diff --git a/WebCore/loader/TextDocument.h b/WebCore/loader/TextDocument.h index c67fea5..53e3074 100644 --- a/WebCore/loader/TextDocument.h +++ b/WebCore/loader/TextDocument.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,7 +35,7 @@ class TextDocument : public HTMLDocument { public: static PassRefPtr create(Frame* frame) { - return new TextDocument(frame); + return adoptRef(new TextDocument(frame)); } private: diff --git a/WebCore/loader/TextResourceDecoder.cpp b/WebCore/loader/TextResourceDecoder.cpp index db68441..6ddd604 100644 --- a/WebCore/loader/TextResourceDecoder.cpp +++ b/WebCore/loader/TextResourceDecoder.cpp @@ -798,23 +798,15 @@ String TextResourceDecoder::decode(const char* data, size_t len) if (!checkForHeadCharset(data, len, movedDataToBuffer)) return ""; - // FIXME: It seems wrong to change our encoding downstream after - // we have already done some decoding. However, it's not possible - // to avoid in a sense in two cases below because triggering conditions - // for both cases depend on the information that won't be available - // until we do partial read. - // The first case had better be removed altogether (see bug 21990) - // or at least be made to be invoked only when the encoding detection - // is turned on. - // Do the auto-detect 1) using Japanese detector if our default encoding is - // one of the Japanese detector or 2) using detectTextEncoding if encoding - // detection is turned on. - if (m_source != UserChosenEncoding && m_source != AutoDetectedEncoding && m_encoding.isJapanese()) - detectJapaneseEncoding(data, len); - else if (shouldAutoDetect()) { - TextEncoding detectedEncoding; - if (detectTextEncoding(data, len, m_hintEncoding, &detectedEncoding)) - setEncoding(detectedEncoding, AutoDetectedEncoding); + // FIXME: It is wrong to change the encoding downstream after we have already done some decoding. + if (shouldAutoDetect()) { + if (m_encoding.isJapanese()) + detectJapaneseEncoding(data, len); // FIXME: We should use detectTextEncoding() for all languages. + else { + TextEncoding detectedEncoding; + if (detectTextEncoding(data, len, m_hintEncoding, &detectedEncoding)) + setEncoding(detectedEncoding, AutoDetectedEncoding); + } } ASSERT(m_encoding.isValid()); diff --git a/WebCore/loader/ThreadableLoader.cpp b/WebCore/loader/ThreadableLoader.cpp index b174af7..720ba4e 100644 --- a/WebCore/loader/ThreadableLoader.cpp +++ b/WebCore/loader/ThreadableLoader.cpp @@ -40,33 +40,33 @@ namespace WebCore { -PassRefPtr ThreadableLoader::create(ScriptExecutionContext* context, ThreadableLoaderClient* client, const ResourceRequest& request, LoadCallbacks callbacksSetting, ContentSniff contentSniff, StoredCredentials storedCredentials, CrossOriginRedirectPolicy crossOriginRedirectPolicy) +PassRefPtr ThreadableLoader::create(ScriptExecutionContext* context, ThreadableLoaderClient* client, const ResourceRequest& request, const ThreadableLoaderOptions& options) { ASSERT(client); ASSERT(context); #if ENABLE(WORKERS) if (context->isWorkerContext()) - return WorkerThreadableLoader::create(static_cast(context), client, WorkerRunLoop::defaultMode(), request, callbacksSetting, contentSniff, storedCredentials, crossOriginRedirectPolicy); + return WorkerThreadableLoader::create(static_cast(context), client, WorkerRunLoop::defaultMode(), request, options); #endif // ENABLE(WORKERS) ASSERT(context->isDocument()); - return DocumentThreadableLoader::create(static_cast(context), client, request, callbacksSetting, contentSniff, storedCredentials, crossOriginRedirectPolicy); + return DocumentThreadableLoader::create(static_cast(context), client, request, options); } -void ThreadableLoader::loadResourceSynchronously(ScriptExecutionContext* context, const ResourceRequest& request, ThreadableLoaderClient& client, StoredCredentials storedCredentials) +void ThreadableLoader::loadResourceSynchronously(ScriptExecutionContext* context, const ResourceRequest& request, ThreadableLoaderClient& client, const ThreadableLoaderOptions& options) { ASSERT(context); #if ENABLE(WORKERS) if (context->isWorkerContext()) { - WorkerThreadableLoader::loadResourceSynchronously(static_cast(context), request, client, storedCredentials, DenyCrossOriginRedirect); + WorkerThreadableLoader::loadResourceSynchronously(static_cast(context), request, client, options); return; } #endif // ENABLE(WORKERS) ASSERT(context->isDocument()); - DocumentThreadableLoader::loadResourceSynchronously(static_cast(context), request, client, storedCredentials); + DocumentThreadableLoader::loadResourceSynchronously(static_cast(context), request, client, options); } } // namespace WebCore diff --git a/WebCore/loader/ThreadableLoader.h b/WebCore/loader/ThreadableLoader.h index 1ac12cb..a52bfad 100644 --- a/WebCore/loader/ThreadableLoader.h +++ b/WebCore/loader/ThreadableLoader.h @@ -43,32 +43,32 @@ namespace WebCore { class ScriptExecutionContext; class ThreadableLoaderClient; - enum LoadCallbacks { - SendLoadCallbacks, - DoNotSendLoadCallbacks - }; - - enum ContentSniff { - SniffContent, - DoNotSniffContent - }; - enum StoredCredentials { AllowStoredCredentials, DoNotAllowStoredCredentials }; - - enum CrossOriginRedirectPolicy { - DenyCrossOriginRedirect, - AllowCrossOriginRedirect + + enum CrossOriginRequestPolicy { + DenyCrossOriginRequests, + UseAccessControl, + AllowCrossOriginRequests + }; + + struct ThreadableLoaderOptions { + ThreadableLoaderOptions() : sendLoadCallbacks(false), sniffContent(false), allowCredentials(false), forcePreflight(false), crossOriginRequestPolicy(DenyCrossOriginRequests) { } + bool sendLoadCallbacks; + bool sniffContent; + bool allowCredentials; // Whether HTTP credentials and cookies are sent with the request. + bool forcePreflight; // If AccessControl is used, whether to force a preflight. + CrossOriginRequestPolicy crossOriginRequestPolicy; }; // Useful for doing loader operations from any thread (not threadsafe, // just able to run on threads other than the main thread). class ThreadableLoader : public Noncopyable { public: - static void loadResourceSynchronously(ScriptExecutionContext*, const ResourceRequest&, ThreadableLoaderClient&, StoredCredentials); - static PassRefPtr create(ScriptExecutionContext*, ThreadableLoaderClient*, const ResourceRequest&, LoadCallbacks, ContentSniff, StoredCredentials, CrossOriginRedirectPolicy); + static void loadResourceSynchronously(ScriptExecutionContext*, const ResourceRequest&, ThreadableLoaderClient&, const ThreadableLoaderOptions&); + static PassRefPtr create(ScriptExecutionContext*, ThreadableLoaderClient*, const ResourceRequest&, const ThreadableLoaderOptions&); virtual void cancel() = 0; void ref() { refThreadableLoader(); } diff --git a/WebCore/loader/UserStyleSheetLoader.cpp b/WebCore/loader/UserStyleSheetLoader.cpp deleted file mode 100644 index 3afbc15..0000000 --- a/WebCore/loader/UserStyleSheetLoader.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2004, 2005, 2006, 2007, 2008 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "UserStyleSheetLoader.h" - -#include "CachedCSSStyleSheet.h" -#include "DocLoader.h" -#include "Frame.h" - -using namespace WebCore; - -UserStyleSheetLoader::UserStyleSheetLoader(PassRefPtr document, const String& url) - : m_document(document) - , m_cachedSheet(m_document->docLoader()->requestUserCSSStyleSheet(url, "")) -{ - if (m_cachedSheet) { - m_document->addPendingSheet(); - m_cachedSheet->addClient(this); - } -} - -UserStyleSheetLoader::~UserStyleSheetLoader() -{ - if (m_cachedSheet) { - if (!m_cachedSheet->isLoaded()) - m_document->removePendingSheet(); - m_cachedSheet->removeClient(this); - } -} - -void UserStyleSheetLoader::setCSSStyleSheet(const String& /*URL*/, const String& /*charset*/, const CachedCSSStyleSheet* sheet) -{ - m_document->removePendingSheet(); - if (Frame* frame = m_document->frame()) - frame->setUserStyleSheet(sheet->sheetText()); -} diff --git a/WebCore/loader/UserStyleSheetLoader.h b/WebCore/loader/UserStyleSheetLoader.h deleted file mode 100644 index 6e7a1ba..0000000 --- a/WebCore/loader/UserStyleSheetLoader.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2004, 2005, 2006, 2007, 2008 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef UserStyleSheetLoader_h -#define UserStyleSheetLoader_h - -#include "CachedResourceClient.h" -#include "CachedResourceHandle.h" - -#include "Document.h" - -namespace WebCore { - class CachedCSSStyleSheet; - class String; - - // This class is deprecated and should not be used in any new code. User - // stylesheet loading should instead happen through Page. - class UserStyleSheetLoader : CachedResourceClient { - public: - UserStyleSheetLoader(PassRefPtr, const String& url); - ~UserStyleSheetLoader(); - - private: - virtual void setCSSStyleSheet(const String& URL, const String& charset, const CachedCSSStyleSheet* sheet); - - RefPtr m_document; - CachedResourceHandle m_cachedSheet; - }; - -} // namespace WebCore - -#endif // UserStyleSheetLoader_h diff --git a/WebCore/loader/WorkerThreadableLoader.cpp b/WebCore/loader/WorkerThreadableLoader.cpp index 4d12b8d..bd362f4 100644 --- a/WebCore/loader/WorkerThreadableLoader.cpp +++ b/WebCore/loader/WorkerThreadableLoader.cpp @@ -53,11 +53,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, CrossOriginRedirectPolicy crossOriginRedirectPolicy) +WorkerThreadableLoader::WorkerThreadableLoader(WorkerContext* workerContext, ThreadableLoaderClient* client, const String& taskMode, const ResourceRequest& request, const ThreadableLoaderOptions& options) : m_workerContext(workerContext) , m_workerClientWrapper(ThreadableLoaderClientWrapper::create(client)) - , m_bridge(*(new MainThreadBridge(m_workerClientWrapper, m_workerContext->thread()->workerLoaderProxy(), taskMode, request, callbacksSetting, contentSniff, storedCredentials, crossOriginRedirectPolicy))) + , m_bridge(*(new MainThreadBridge(m_workerClientWrapper, m_workerContext->thread()->workerLoaderProxy(), taskMode, request, options))) { } @@ -66,7 +65,7 @@ WorkerThreadableLoader::~WorkerThreadableLoader() m_bridge.destroy(); } -void WorkerThreadableLoader::loadResourceSynchronously(WorkerContext* workerContext, const ResourceRequest& request, ThreadableLoaderClient& client, StoredCredentials storedCredentials, CrossOriginRedirectPolicy crossOriginRedirectPolicy) +void WorkerThreadableLoader::loadResourceSynchronously(WorkerContext* workerContext, const ResourceRequest& request, ThreadableLoaderClient& client, const ThreadableLoaderOptions& options) { WorkerRunLoop& runLoop = workerContext->thread()->runLoop(); @@ -74,9 +73,7 @@ void WorkerThreadableLoader::loadResourceSynchronously(WorkerContext* workerCont String mode = loadResourceSynchronouslyMode; mode.append(String::number(runLoop.createUniqueId())); - ContentSniff contentSniff = request.url().isLocalFile() ? SniffContent : DoNotSniffContent; - RefPtr loader = WorkerThreadableLoader::create(workerContext, &client, mode, request, DoNotSendLoadCallbacks, contentSniff, storedCredentials, crossOriginRedirectPolicy); - + RefPtr loader = WorkerThreadableLoader::create(workerContext, &client, mode, request, options); MessageQueueWaitResult result = MessageQueueMessageReceived; while (!loader->done() && result != MessageQueueTerminated) result = runLoop.runInMode(workerContext, mode); @@ -91,21 +88,20 @@ void WorkerThreadableLoader::cancel() } WorkerThreadableLoader::MainThreadBridge::MainThreadBridge(PassRefPtr workerClientWrapper, WorkerLoaderProxy& loaderProxy, const String& taskMode, - const ResourceRequest& request, LoadCallbacks callbacksSetting, ContentSniff contentSniff, StoredCredentials storedCredentials, - CrossOriginRedirectPolicy crossOriginRedirectPolicy) + const ResourceRequest& request, const ThreadableLoaderOptions& options) : m_workerClientWrapper(workerClientWrapper) , m_loaderProxy(loaderProxy) - , m_taskMode(taskMode.copy()) + , m_taskMode(taskMode.crossThreadString()) { ASSERT(m_workerClientWrapper.get()); - m_loaderProxy.postTaskToLoader(createCallbackTask(&MainThreadBridge::mainThreadCreateLoader, this, request, callbacksSetting, contentSniff, storedCredentials, crossOriginRedirectPolicy)); + m_loaderProxy.postTaskToLoader(createCallbackTask(&MainThreadBridge::mainThreadCreateLoader, this, request, options)); } WorkerThreadableLoader::MainThreadBridge::~MainThreadBridge() { } -void WorkerThreadableLoader::MainThreadBridge::mainThreadCreateLoader(ScriptExecutionContext* context, MainThreadBridge* thisPtr, auto_ptr requestData, LoadCallbacks callbacksSetting, ContentSniff contentSniff, StoredCredentials storedCredentials, CrossOriginRedirectPolicy crossOriginRedirectPolicy) +void WorkerThreadableLoader::MainThreadBridge::mainThreadCreateLoader(ScriptExecutionContext* context, MainThreadBridge* thisPtr, auto_ptr requestData, ThreadableLoaderOptions options) { ASSERT(isMainThread()); ASSERT(context->isDocument()); @@ -117,7 +113,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, crossOriginRedirectPolicy); + thisPtr->m_mainThreadLoader = ThreadableLoader::create(context, thisPtr, *request, options); ASSERT(thisPtr->m_mainThreadLoader); } diff --git a/WebCore/loader/WorkerThreadableLoader.h b/WebCore/loader/WorkerThreadableLoader.h index 8b11b70..230c77d 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, CrossOriginRedirectPolicy); - static PassRefPtr create(WorkerContext* workerContext, ThreadableLoaderClient* client, const String& taskMode, const ResourceRequest& request, LoadCallbacks callbacksSetting, ContentSniff contentSniff, StoredCredentials storedCredentials, CrossOriginRedirectPolicy crossOriginRedirectPolicy) + static void loadResourceSynchronously(WorkerContext*, const ResourceRequest&, ThreadableLoaderClient&, const ThreadableLoaderOptions&); + static PassRefPtr create(WorkerContext* workerContext, ThreadableLoaderClient* client, const String& taskMode, const ResourceRequest& request, const ThreadableLoaderOptions& options) { - return adoptRef(new WorkerThreadableLoader(workerContext, client, taskMode, request, callbacksSetting, contentSniff, storedCredentials, crossOriginRedirectPolicy)); + return adoptRef(new WorkerThreadableLoader(workerContext, client, taskMode, request, options)); } ~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, CrossOriginRedirectPolicy); + MainThreadBridge(PassRefPtr, WorkerLoaderProxy&, const String& taskMode, const ResourceRequest&, const ThreadableLoaderOptions&); 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, CrossOriginRedirectPolicy); + static void mainThreadCreateLoader(ScriptExecutionContext*, MainThreadBridge*, std::auto_ptr, ThreadableLoaderOptions); 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, CrossOriginRedirectPolicy); + WorkerThreadableLoader(WorkerContext*, ThreadableLoaderClient*, const String& taskMode, const ResourceRequest&, const ThreadableLoaderOptions&); RefPtr m_workerContext; RefPtr m_workerClientWrapper; diff --git a/WebCore/loader/appcache/ApplicationCache.cpp b/WebCore/loader/appcache/ApplicationCache.cpp index 34dace4..c0cd3ea 100644 --- a/WebCore/loader/appcache/ApplicationCache.cpp +++ b/WebCore/loader/appcache/ApplicationCache.cpp @@ -111,7 +111,7 @@ unsigned ApplicationCache::removeResource(const String& url) ApplicationCacheResource* ApplicationCache::resourceForURL(const String& url) { - ASSERT(!KURL(url).hasFragmentIdentifier()); + ASSERT(!KURL(ParsedURLString, url).hasFragmentIdentifier()); return m_resources.get(url).get(); } @@ -147,6 +147,9 @@ void ApplicationCache::setOnlineWhitelist(const Vector& onlineWhitelist) bool ApplicationCache::isURLInOnlineWhitelist(const KURL& url) { + if (m_allowAllNetworkRequests) + return true; + size_t whitelistSize = m_onlineWhitelist.size(); for (size_t i = 0; i < whitelistSize; ++i) { if (protocolHostAndPortAreEqual(url, m_onlineWhitelist[i]) && url.string().startsWith(m_onlineWhitelist[i].string())) diff --git a/WebCore/loader/appcache/ApplicationCache.h b/WebCore/loader/appcache/ApplicationCache.h index b1753be..d1444c0 100644 --- a/WebCore/loader/appcache/ApplicationCache.h +++ b/WebCore/loader/appcache/ApplicationCache.h @@ -65,6 +65,8 @@ public: ApplicationCacheResource* resourceForRequest(const ResourceRequest&); ApplicationCacheResource* resourceForURL(const String& url); + void setAllowsAllNetworkRequests(bool value) { m_allowAllNetworkRequests = value; } + bool allowsAllNetworkRequests() const { return m_allowAllNetworkRequests; } 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. @@ -96,6 +98,7 @@ private: ResourceMap m_resources; ApplicationCacheResource* m_manifest; + bool m_allowAllNetworkRequests; Vector m_onlineWhitelist; FallbackURLVector m_fallbackURLs; diff --git a/WebCore/loader/appcache/ApplicationCacheGroup.cpp b/WebCore/loader/appcache/ApplicationCacheGroup.cpp index 41c5cac..a3d551b 100644 --- a/WebCore/loader/appcache/ApplicationCacheGroup.cpp +++ b/WebCore/loader/appcache/ApplicationCacheGroup.cpp @@ -158,7 +158,7 @@ void ApplicationCacheGroup::selectCache(Frame* frame, const KURL& passedManifest // Restart the current navigation from the top of the navigation algorithm, undoing any changes that were made // as part of the initial load. // The navigation will not result in the same resource being loaded, because "foreign" entries are never picked during navigation. - frame->loader()->scheduleLocationChange(documentLoader->url(), frame->loader()->referrer(), true); + frame->redirectScheduler()->scheduleLocationChange(documentLoader->url(), frame->loader()->referrer(), true); } return; @@ -672,6 +672,7 @@ void ApplicationCacheGroup::didFinishLoadingManifest() m_cacheBeingUpdated->setOnlineWhitelist(manifest.onlineWhitelistedURLs); m_cacheBeingUpdated->setFallbackURLs(manifest.fallbackURLs); + m_cacheBeingUpdated->setAllowsAllNetworkRequests(manifest.allowAllNetworkRequests); startLoadingEntry(); } @@ -852,7 +853,7 @@ void ApplicationCacheGroup::startLoadingEntry() ASSERT(!m_currentHandle); - m_currentHandle = createResourceHandle(KURL(it->first), m_newestCache ? m_newestCache->resourceForURL(it->first) : 0); + m_currentHandle = createResourceHandle(KURL(ParsedURLString, it->first), m_newestCache ? m_newestCache->resourceForURL(it->first) : 0); } void ApplicationCacheGroup::deliverDelayedMainResources() @@ -879,7 +880,7 @@ void ApplicationCacheGroup::deliverDelayedMainResources() void ApplicationCacheGroup::addEntry(const String& url, unsigned type) { ASSERT(m_cacheBeingUpdated); - ASSERT(!KURL(url).hasFragmentIdentifier()); + ASSERT(!KURL(ParsedURLString, 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). @@ -962,7 +963,7 @@ public: ASSERT(frame->loader()->documentLoader() == m_documentLoader.get()); - m_documentLoader->applicationCacheHost()->notifyEventListener(m_eventID); + m_documentLoader->applicationCacheHost()->notifyDOMApplicationCache(m_eventID); } private: diff --git a/WebCore/loader/appcache/ApplicationCacheGroup.h b/WebCore/loader/appcache/ApplicationCacheGroup.h index 939646f..8df52cc 100644 --- a/WebCore/loader/appcache/ApplicationCacheGroup.h +++ b/WebCore/loader/appcache/ApplicationCacheGroup.h @@ -97,6 +97,10 @@ private: PassRefPtr createResourceHandle(const KURL&, ApplicationCacheResource* newestCachedResource); + // For normal resource loading, WebKit client is asked about each resource individually. Since application cache does not belong to any particular document, + // the existing client callback cannot be used, so assume that any client that enables application cache also wants it to use credential storage. + virtual bool shouldUseCredentialStorage(ResourceHandle*) { return true; } + virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&); virtual void didReceiveData(ResourceHandle*, const char*, int, int lengthReceived); virtual void didFinishLoading(ResourceHandle*); diff --git a/WebCore/loader/appcache/ApplicationCacheHost.cpp b/WebCore/loader/appcache/ApplicationCacheHost.cpp index b0c9e74..751efc1 100644 --- a/WebCore/loader/appcache/ApplicationCacheHost.cpp +++ b/WebCore/loader/appcache/ApplicationCacheHost.cpp @@ -227,10 +227,13 @@ void ApplicationCacheHost::setDOMApplicationCache(DOMApplicationCache* domApplic m_domApplicationCache = domApplicationCache; } -void ApplicationCacheHost::notifyEventListener(EventID id) +void ApplicationCacheHost::notifyDOMApplicationCache(EventID id) { - if (m_domApplicationCache) - m_domApplicationCache->callEventListener(id); + if (m_domApplicationCache) { + ExceptionCode ec = 0; + m_domApplicationCache->dispatchEvent(Event::create(DOMApplicationCache::toEventType(id), false, false), ec); + ASSERT(!ec); + } } void ApplicationCacheHost::setCandidateApplicationCacheGroup(ApplicationCacheGroup* group) @@ -255,8 +258,9 @@ bool ApplicationCacheHost::shouldLoadResourceFromApplicationCache(const Resource if (!cache || !cache->isComplete()) return false; - // If the resource is not a HTTP/HTTPS GET, then abort - if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request)) + // If the resource is not to be fetched using the HTTP GET mechanism or equivalent, or if its URL has a different + // component than the application cache's manifest, then fetch the resource normally. + if (!ApplicationCache::requestIsHTTPOrHTTPSGet(request) || !equalIgnoringCase(request.url().protocol(), cache->manifestResource()->url().protocol())) return false; // If the resource's URL is an master entry, the manifest, an explicit entry, or a fallback entry diff --git a/WebCore/loader/appcache/ApplicationCacheHost.h b/WebCore/loader/appcache/ApplicationCacheHost.h index cb68862..236013d 100644 --- a/WebCore/loader/appcache/ApplicationCacheHost.h +++ b/WebCore/loader/appcache/ApplicationCacheHost.h @@ -108,7 +108,7 @@ namespace WebCore { bool swapCache(); void setDOMApplicationCache(DOMApplicationCache* domApplicationCache); - void notifyEventListener(EventID id); + void notifyDOMApplicationCache(EventID id); private: bool isApplicationCacheEnabled(); diff --git a/WebCore/loader/appcache/ApplicationCacheStorage.cpp b/WebCore/loader/appcache/ApplicationCacheStorage.cpp index 5a2b642..d6ee723 100644 --- a/WebCore/loader/appcache/ApplicationCacheStorage.cpp +++ b/WebCore/loader/appcache/ApplicationCacheStorage.cpp @@ -216,7 +216,7 @@ ApplicationCacheGroup* ApplicationCacheStorage::cacheGroupForURL(const KURL& url int result; while ((result = statement.step()) == SQLResultRow) { - KURL manifestURL = KURL(statement.getColumnText(1)); + KURL manifestURL = KURL(ParsedURLString, statement.getColumnText(1)); if (m_cachesInMemory.contains(manifestURL)) continue; @@ -284,7 +284,7 @@ ApplicationCacheGroup* ApplicationCacheStorage::fallbackCacheGroupForURL(const K int result; while ((result = statement.step()) == SQLResultRow) { - KURL manifestURL = KURL(statement.getColumnText(1)); + KURL manifestURL = KURL(ParsedURLString, statement.getColumnText(1)); if (m_cachesInMemory.contains(manifestURL)) continue; @@ -427,7 +427,7 @@ bool ApplicationCacheStorage::executeSQLCommand(const String& sql) return result; } -static const int schemaVersion = 4; +static const int schemaVersion = 5; void ApplicationCacheStorage::verifySchemaVersion() { @@ -479,6 +479,7 @@ void ApplicationCacheStorage::openDatabase(bool createIfDoesNotExist) "manifestHostHash INTEGER NOT NULL ON CONFLICT FAIL, manifestURL TEXT UNIQUE ON CONFLICT FAIL, newestCache INTEGER)"); executeSQLCommand("CREATE TABLE IF NOT EXISTS Caches (id INTEGER PRIMARY KEY AUTOINCREMENT, cacheGroup INTEGER, size INTEGER)"); executeSQLCommand("CREATE TABLE IF NOT EXISTS CacheWhitelistURLs (url TEXT NOT NULL ON CONFLICT FAIL, cache INTEGER NOT NULL ON CONFLICT FAIL)"); + executeSQLCommand("CREATE TABLE IF NOT EXISTS CacheAllowsAllNetworkRequests (wildcard INTEGER NOT NULL ON CONFLICT FAIL, cache INTEGER NOT NULL ON CONFLICT FAIL)"); executeSQLCommand("CREATE TABLE IF NOT EXISTS FallbackURLs (namespace TEXT NOT NULL ON CONFLICT FAIL, fallbackURL TEXT NOT NULL ON CONFLICT FAIL, " "cache INTEGER NOT NULL ON CONFLICT FAIL)"); executeSQLCommand("CREATE TABLE IF NOT EXISTS CacheEntries (cache INTEGER NOT NULL ON CONFLICT FAIL, type INTEGER, resource INTEGER NOT NULL)"); @@ -491,6 +492,7 @@ void ApplicationCacheStorage::openDatabase(bool createIfDoesNotExist) " FOR EACH ROW BEGIN" " DELETE FROM CacheEntries WHERE cache = OLD.id;" " DELETE FROM CacheWhitelistURLs WHERE cache = OLD.id;" + " DELETE FROM CacheAllowsAllNetworkRequests WHERE cache = OLD.id;" " DELETE FROM FallbackURLs WHERE cache = OLD.id;" " END"); @@ -584,6 +586,18 @@ bool ApplicationCacheStorage::store(ApplicationCache* cache, ResourceStorageIDJo return false; } } + + // Store online whitelist wildcard flag. + { + SQLiteStatement statement(m_database, "INSERT INTO CacheAllowsAllNetworkRequests (wildcard, cache) VALUES (?, ?)"); + statement.prepare(); + + statement.bindInt64(1, cache->allowsAllNetworkRequests()); + statement.bindInt64(2, cacheStorageID); + + if (!executeStatement(statement)) + return false; + } // Store fallback URLs. const FallbackURLVector& fallbackURLs = cache->fallbackURLs(); @@ -821,7 +835,7 @@ PassRefPtr ApplicationCacheStorage::loadCache(unsigned storage int result; while ((result = cacheStatement.step()) == SQLResultRow) { - KURL url(cacheStatement.getColumnText(0)); + KURL url(ParsedURLString, cacheStatement.getColumnText(0)); unsigned type = static_cast(cacheStatement.getColumnInt64(1)); @@ -857,13 +871,28 @@ PassRefPtr ApplicationCacheStorage::loadCache(unsigned storage Vector whitelist; while ((result = whitelistStatement.step()) == SQLResultRow) - whitelist.append(whitelistStatement.getColumnText(0)); + whitelist.append(KURL(ParsedURLString, whitelistStatement.getColumnText(0))); if (result != SQLResultDone) LOG_ERROR("Could not load cache online whitelist, error \"%s\"", m_database.lastErrorMsg()); cache->setOnlineWhitelist(whitelist); + // Load online whitelist wildcard flag. + SQLiteStatement whitelistWildcardStatement(m_database, "SELECT wildcard FROM CacheAllowsAllNetworkRequests WHERE cache=?"); + if (whitelistWildcardStatement.prepare() != SQLResultOk) + return 0; + whitelistWildcardStatement.bindInt64(1, storageID); + + result = whitelistWildcardStatement.step(); + if (result != SQLResultRow) + LOG_ERROR("Could not load cache online whitelist wildcard flag, error \"%s\"", m_database.lastErrorMsg()); + + cache->setAllowsAllNetworkRequests(whitelistWildcardStatement.getColumnInt64(0)); + + if (whitelistWildcardStatement.step() != SQLResultDone) + LOG_ERROR("Too many rows for online whitelist wildcard flag"); + // Load fallback URLs. SQLiteStatement fallbackStatement(m_database, "SELECT namespace, fallbackURL FROM FallbackURLs WHERE cache=?"); if (fallbackStatement.prepare() != SQLResultOk) @@ -872,7 +901,7 @@ PassRefPtr ApplicationCacheStorage::loadCache(unsigned storage FallbackURLVector fallbackURLs; while ((result = fallbackStatement.step()) == SQLResultRow) - fallbackURLs.append(make_pair(fallbackStatement.getColumnText(0), fallbackStatement.getColumnText(1))); + fallbackURLs.append(make_pair(KURL(ParsedURLString, fallbackStatement.getColumnText(0)), KURL(ParsedURLString, fallbackStatement.getColumnText(1)))); if (result != SQLResultDone) LOG_ERROR("Could not load fallback URLs, error \"%s\"", m_database.lastErrorMsg()); @@ -987,7 +1016,7 @@ bool ApplicationCacheStorage::manifestURLs(Vector* urls) return false; while (selectURLs.step() == SQLResultRow) - urls->append(selectURLs.getColumnText(0)); + urls->append(KURL(ParsedURLString, selectURLs.getColumnText(0))); return true; } diff --git a/WebCore/loader/appcache/DOMApplicationCache.cpp b/WebCore/loader/appcache/DOMApplicationCache.cpp index ab5802f..1496b8a 100644 --- a/WebCore/loader/appcache/DOMApplicationCache.cpp +++ b/WebCore/loader/appcache/DOMApplicationCache.cpp @@ -42,8 +42,10 @@ namespace WebCore { DOMApplicationCache::DOMApplicationCache(Frame* frame) : m_frame(frame) { - ASSERT(applicationCacheHost()); - applicationCacheHost()->setDOMApplicationCache(this); + ASSERT(!m_frame || applicationCacheHost()); + ApplicationCacheHost* cacheHost = applicationCacheHost(); + if (cacheHost) + cacheHost->setDOMApplicationCache(this); } void DOMApplicationCache::disconnectFrame() @@ -76,90 +78,17 @@ void DOMApplicationCache::update(ExceptionCode& ec) ec = INVALID_STATE_ERR; } -bool DOMApplicationCache::swapCache() -{ - ApplicationCacheHost* cacheHost = applicationCacheHost(); - if (!cacheHost) - return false; - return cacheHost->swapCache(); -} - void DOMApplicationCache::swapCache(ExceptionCode& ec) { - if (!swapCache()) + ApplicationCacheHost* cacheHost = applicationCacheHost(); + if (!cacheHost || !cacheHost->swapCache()) ec = INVALID_STATE_ERR; } ScriptExecutionContext* DOMApplicationCache::scriptExecutionContext() const { - return m_frame->document(); -} - -void DOMApplicationCache::addEventListener(const AtomicString& eventType, PassRefPtr eventListener, bool) -{ - EventListenersMap::iterator iter = m_eventListeners.find(eventType); - if (iter == m_eventListeners.end()) { - ListenerVector listeners; - listeners.append(eventListener); - m_eventListeners.add(eventType, listeners); - } else { - ListenerVector& listeners = iter->second; - for (ListenerVector::iterator listenerIter = listeners.begin(); listenerIter != listeners.end(); ++listenerIter) { - if (*listenerIter == eventListener) - return; - } - - listeners.append(eventListener); - m_eventListeners.add(eventType, listeners); - } -} - -void DOMApplicationCache::removeEventListener(const AtomicString& eventType, EventListener* eventListener, bool) -{ - EventListenersMap::iterator iter = m_eventListeners.find(eventType); - if (iter == m_eventListeners.end()) - return; - - ListenerVector& listeners = iter->second; - for (ListenerVector::const_iterator listenerIter = listeners.begin(); listenerIter != listeners.end(); ++listenerIter) { - if (*listenerIter == eventListener) { - listeners.remove(listenerIter - listeners.begin()); - return; - } - } -} - -bool DOMApplicationCache::dispatchEvent(PassRefPtr event, ExceptionCode& ec) -{ - if (!event || event->type().isEmpty()) { - 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); - event->setCurrentTarget(this); - listenerIter->get()->handleEvent(event.get(), false); - } - - return !event->defaultPrevented(); -} - -void DOMApplicationCache::callListener(const AtomicString& eventType, EventListener* listener) -{ ASSERT(m_frame); - - RefPtr event = Event::create(eventType, false, false); - if (listener) { - event->setTarget(this); - event->setCurrentTarget(this); - listener->handleEvent(event.get(), false); - } - - ExceptionCode ec = 0; - dispatchEvent(event.release(), ec); - ASSERT(!ec); + return m_frame->document(); } const AtomicString& DOMApplicationCache::toEventType(ApplicationCacheHost::EventID id) @@ -186,29 +115,19 @@ const AtomicString& DOMApplicationCache::toEventType(ApplicationCacheHost::Event return eventNames().errorEvent; } -ApplicationCacheHost::EventID DOMApplicationCache::toEventID(const AtomicString& eventType) +EventTargetData* DOMApplicationCache::eventTargetData() { - 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; + return &m_eventTargetData; +} + +<<<<<<< HEAD:WebCore/loader/appcache/DOMApplicationCache.cpp +======= +EventTargetData* DOMApplicationCache::ensureEventTargetData() +{ + return &m_eventTargetData; } +>>>>>>> webkit.org at 49305:WebCore/loader/appcache/DOMApplicationCache.cpp } // namespace WebCore #endif // ENABLE(OFFLINE_WEB_APPLICATIONS) diff --git a/WebCore/loader/appcache/DOMApplicationCache.h b/WebCore/loader/appcache/DOMApplicationCache.h index 276f50e..077cae0 100644 --- a/WebCore/loader/appcache/DOMApplicationCache.h +++ b/WebCore/loader/appcache/DOMApplicationCache.h @@ -30,8 +30,9 @@ #include "ApplicationCacheHost.h" #include "AtomicStringHash.h" -#include "EventTarget.h" #include "EventListener.h" +#include "EventNames.h" +#include "EventTarget.h" #include #include #include @@ -55,73 +56,39 @@ public: void update(ExceptionCode&); void swapCache(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; } - using RefCounted::ref; using RefCounted::deref; // Explicitly named attribute event listener helpers - void setOnchecking(PassRefPtr listener) { setAttributeEventListener(ApplicationCacheHost::CHECKING_EVENT, listener); } - EventListener* onchecking() const { return getAttributeEventListener(ApplicationCacheHost::CHECKING_EVENT); } - - void setOnerror(PassRefPtr listener) { setAttributeEventListener(ApplicationCacheHost::ERROR_EVENT, listener);} - EventListener* onerror() const { return getAttributeEventListener(ApplicationCacheHost::ERROR_EVENT); } - - 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 listener) { setAttributeEventListener(ApplicationCacheHost::UPDATEREADY_EVENT, listener); } - EventListener* onupdateready() const { return getAttributeEventListener(ApplicationCacheHost::UPDATEREADY_EVENT); } - - void setOncached(PassRefPtr listener) { setAttributeEventListener(ApplicationCacheHost::CACHED_EVENT, listener); } - EventListener* oncached() const { return getAttributeEventListener(ApplicationCacheHost::CACHED_EVENT); } - - void setOnobsolete(PassRefPtr listener) { setAttributeEventListener(ApplicationCacheHost::OBSOLETE_EVENT, listener); } - EventListener* onobsolete() const { return getAttributeEventListener(ApplicationCacheHost::OBSOLETE_EVENT); } + DEFINE_ATTRIBUTE_EVENT_LISTENER(checking); + DEFINE_ATTRIBUTE_EVENT_LISTENER(error); + DEFINE_ATTRIBUTE_EVENT_LISTENER(noupdate); + DEFINE_ATTRIBUTE_EVENT_LISTENER(downloading); + DEFINE_ATTRIBUTE_EVENT_LISTENER(progress); + DEFINE_ATTRIBUTE_EVENT_LISTENER(updateready); + DEFINE_ATTRIBUTE_EVENT_LISTENER(cached); + DEFINE_ATTRIBUTE_EVENT_LISTENER(obsolete); virtual ScriptExecutionContext* scriptExecutionContext() const; DOMApplicationCache* toDOMApplicationCache() { return this; } static const AtomicString& toEventType(ApplicationCacheHost::EventID id); - static ApplicationCacheHost::EventID toEventID(const AtomicString& eventType); private: DOMApplicationCache(Frame*); - void callListener(const AtomicString& eventType, EventListener*); - virtual void refEventTarget() { ref(); } virtual void derefEventTarget() { deref(); } + virtual EventTargetData* eventTargetData(); + virtual EventTargetData* ensureEventTargetData(); ApplicationCacheHost* applicationCacheHost() const; - bool swapCache(); - - RefPtr m_attributeEventListeners[ApplicationCacheHost::OBSOLETE_EVENT + 1]; - - EventListenersMap m_eventListeners; Frame* m_frame; + EventTargetData m_eventTargetData; }; } // namespace WebCore diff --git a/WebCore/loader/appcache/DOMApplicationCache.idl b/WebCore/loader/appcache/DOMApplicationCache.idl index ebc1d19..dd5468a 100644 --- a/WebCore/loader/appcache/DOMApplicationCache.idl +++ b/WebCore/loader/appcache/DOMApplicationCache.idl @@ -27,7 +27,7 @@ module offline { interface [ Conditional=OFFLINE_WEB_APPLICATIONS, - CustomMarkFunction + EventTarget ] DOMApplicationCache { // update status const unsigned short UNCACHED = 0; diff --git a/WebCore/loader/appcache/ManifestParser.cpp b/WebCore/loader/appcache/ManifestParser.cpp index a2df825..b001bff 100644 --- a/WebCore/loader/appcache/ManifestParser.cpp +++ b/WebCore/loader/appcache/ManifestParser.cpp @@ -43,7 +43,8 @@ bool parseManifest(const KURL& manifestURL, const char* data, int length, Manife ASSERT(manifest.explicitURLs.isEmpty()); ASSERT(manifest.onlineWhitelistedURLs.isEmpty()); ASSERT(manifest.fallbackURLs.isEmpty()); - + manifest.allowAllNetworkRequests = false; + Mode mode = Explicit; RefPtr decoder = TextResourceDecoder::create("text/cache-manifest", "UTF-8"); @@ -109,6 +110,12 @@ bool parseManifest(const KURL& manifestURL, const char* data, int length, Manife while (p < lineEnd && *p != '\t' && *p != ' ') p++; + if (mode == OnlineWhitelist && p - line.characters() == 1 && *line.characters() == '*') { + // Wildcard was found. + manifest.allowAllNetworkRequests = true; + continue; + } + KURL url(manifestURL, String(line.characters(), p - line.characters())); if (!url.isValid()) diff --git a/WebCore/loader/appcache/ManifestParser.h b/WebCore/loader/appcache/ManifestParser.h index c03cf27..f0369ee 100644 --- a/WebCore/loader/appcache/ManifestParser.h +++ b/WebCore/loader/appcache/ManifestParser.h @@ -38,6 +38,7 @@ namespace WebCore { Vector onlineWhitelistedURLs; HashSet explicitURLs; FallbackURLVector fallbackURLs; + bool allowAllNetworkRequests; // Wildcard found in NETWORK section. }; bool parseManifest(const KURL& manifestURL, const char* data, int length, Manifest&); diff --git a/WebCore/loader/archive/cf/LegacyWebArchive.cpp b/WebCore/loader/archive/cf/LegacyWebArchive.cpp index d1269cc..3141e98 100644 --- a/WebCore/loader/archive/cf/LegacyWebArchive.cpp +++ b/WebCore/loader/archive/cf/LegacyWebArchive.cpp @@ -233,7 +233,7 @@ PassRefPtr LegacyWebArchive::createResource(CFDictionaryRef dic response = createResourceResponseFromPropertyListData(resourceResponseData, resourceResponseVersion); } - return ArchiveResource::create(SharedBuffer::create(CFDataGetBytePtr(resourceData), CFDataGetLength(resourceData)), KURL(url), mimeType, textEncoding, frameName, response); + return ArchiveResource::create(SharedBuffer::create(CFDataGetBytePtr(resourceData), CFDataGetLength(resourceData)), KURL(ParsedURLString, url), mimeType, textEncoding, frameName, response); } PassRefPtr LegacyWebArchive::create() @@ -489,7 +489,7 @@ PassRefPtr LegacyWebArchive::create(const String& markupString // it's possible to have a response without a URL here // if (responseURL.isNull()) - responseURL = KURL(""); + responseURL = KURL(ParsedURLString, ""); PassRefPtr mainResource = ArchiveResource::create(utf8Buffer(markupString), responseURL, response.mimeType(), "UTF-8", frame->tree()->name()); @@ -548,7 +548,7 @@ PassRefPtr LegacyWebArchive::create(const String& markupString const String& iconURL = iconDatabase()->iconURLForPageURL(responseURL); if (!iconURL.isEmpty() && iconDatabase()->iconDataKnownForIconURL(iconURL)) { if (Image* iconImage = iconDatabase()->iconForPageURL(responseURL, IntSize(16, 16))) { - if (RefPtr resource = ArchiveResource::create(iconImage->data(), KURL(iconURL), "image/x-icon", "", "")) + if (RefPtr resource = ArchiveResource::create(iconImage->data(), KURL(ParsedURLString, iconURL), "image/x-icon", "", "")) subresources.append(resource.release()); } } diff --git a/WebCore/loader/icon/IconDatabase.cpp b/WebCore/loader/icon/IconDatabase.cpp index c0af78f..8982cda 100644 --- a/WebCore/loader/icon/IconDatabase.cpp +++ b/WebCore/loader/icon/IconDatabase.cpp @@ -137,7 +137,7 @@ bool IconDatabase::open(const String& databasePath) return false; } - m_databaseDirectory = databasePath.copy(); + m_databaseDirectory = databasePath.crossThreadString(); // Formulate the full path for the database file m_completeDatabasePath = pathByAppendingComponent(m_databaseDirectory, defaultDatabaseFilename()); @@ -241,7 +241,7 @@ Image* IconDatabase::iconForPageURL(const String& pageURLOriginal, const IntSize PageURLRecord* pageRecord = m_pageURLToRecordMap.get(pageURLOriginal); if (!pageRecord) { - pageURLCopy = pageURLOriginal.copy(); + pageURLCopy = pageURLOriginal.crossThreadString(); pageRecord = getOrCreatePageURLRecord(pageURLCopy); } @@ -277,7 +277,7 @@ Image* IconDatabase::iconForPageURL(const String& pageURLOriginal, const IntSize // mark it to be read by the background thread if (iconRecord->imageDataStatus() == ImageDataStatusUnknown) { if (pageURLCopy.isNull()) - pageURLCopy = pageURLOriginal.copy(); + pageURLCopy = pageURLOriginal.crossThreadString(); MutexLocker locker(m_pendingReadingLock); m_pageURLsInterestedInIcons.add(pageURLCopy); @@ -326,7 +326,7 @@ String IconDatabase::iconURLForPageURL(const String& pageURLOriginal) PageURLRecord* pageRecord = m_pageURLToRecordMap.get(pageURLOriginal); if (!pageRecord) - pageRecord = getOrCreatePageURLRecord(pageURLOriginal.copy()); + pageRecord = getOrCreatePageURLRecord(pageURLOriginal.crossThreadString()); // If pageRecord is NULL, one of two things is true - // 1 - The initial url import is incomplete and this pageURL has already been marked to be notified once it is complete if an iconURL exists @@ -335,7 +335,7 @@ String IconDatabase::iconURLForPageURL(const String& pageURLOriginal) return String(); // Possible the pageRecord is around because it's a retained pageURL with no iconURL, so we have to check - return pageRecord->iconRecord() ? pageRecord->iconRecord()->iconURL().copy() : String(); + return pageRecord->iconRecord() ? pageRecord->iconRecord()->iconURL().threadsafeCopy() : String(); } #ifdef CAN_THEME_URL_ICON @@ -419,7 +419,7 @@ void IconDatabase::retainIconForPageURL(const String& pageURLOriginal) String pageURL; if (!record) { - pageURL = pageURLOriginal.copy(); + pageURL = pageURLOriginal.crossThreadString(); record = new PageURLRecord(pageURL); m_pageURLToRecordMap.set(pageURL, record); @@ -427,7 +427,7 @@ void IconDatabase::retainIconForPageURL(const String& pageURLOriginal) if (!record->retain()) { if (pageURL.isNull()) - pageURL = pageURLOriginal.copy(); + pageURL = pageURLOriginal.crossThreadString(); // This page just had its retain count bumped from 0 to 1 - Record that fact m_retainedPageURLs.add(pageURL); @@ -502,7 +502,7 @@ void IconDatabase::releaseIconForPageURL(const String& pageURLOriginal) // Mark stuff for deletion from the database only if we're not in private browsing if (!m_privateBrowsingEnabled) { MutexLocker locker(m_pendingSyncLock); - m_pageURLsPendingSync.set(pageURLOriginal.copy(), pageRecord->snapshot(true)); + m_pageURLsPendingSync.set(pageURLOriginal.crossThreadString(), pageRecord->snapshot(true)); // If this page is the last page to refer to a particular IconRecord, that IconRecord needs to // be marked for deletion @@ -526,7 +526,7 @@ void IconDatabase::setIconDataForIconURL(PassRefPtr dataOriginal, return; RefPtr data = dataOriginal ? dataOriginal->copy() : 0; - String iconURL = iconURLOriginal.copy(); + String iconURL = iconURLOriginal.crossThreadString(); Vector pageURLs; { @@ -603,8 +603,8 @@ void IconDatabase::setIconURLForPageURL(const String& iconURLOriginal, const Str if (pageRecord && pageRecord->iconRecord() && pageRecord->iconRecord()->iconURL() == iconURLOriginal) return; - pageURL = pageURLOriginal.copy(); - iconURL = iconURLOriginal.copy(); + pageURL = pageURLOriginal.crossThreadString(); + iconURL = iconURLOriginal.crossThreadString(); if (!pageRecord) { pageRecord = new PageURLRecord(pageURL); @@ -861,13 +861,13 @@ bool IconDatabase::isOpen() const String IconDatabase::databasePath() const { MutexLocker locker(m_syncLock); - return m_completeDatabasePath.copy(); + return m_completeDatabasePath.threadsafeCopy(); } String IconDatabase::defaultDatabaseFilename() { DEFINE_STATIC_LOCAL(String, defaultDatabaseFilename, ("WebpageIcons.db")); - return defaultDatabaseFilename.copy(); + return defaultDatabaseFilename.threadsafeCopy(); } // Unlike getOrCreatePageURLRecord(), getOrCreateIconRecord() does not mark the icon as "interested in import" diff --git a/WebCore/loader/icon/IconDatabaseNone.cpp b/WebCore/loader/icon/IconDatabaseNone.cpp index 03a7964..7b7cc9f 100644 --- a/WebCore/loader/icon/IconDatabaseNone.cpp +++ b/WebCore/loader/icon/IconDatabaseNone.cpp @@ -53,7 +53,7 @@ const int updateTimerDelay = 5; String IconDatabase::defaultDatabaseFilename() { DEFINE_STATIC_LOCAL(String, defaultDatabaseFilename, ("Icons.db")); - return defaultDatabaseFilename.copy(); + return defaultDatabaseFilename.threadsafeCopy(); } IconDatabase* iconDatabase() diff --git a/WebCore/loader/loader.cpp b/WebCore/loader/loader.cpp index 65d15a5..eb606d8 100644 --- a/WebCore/loader/loader.cpp +++ b/WebCore/loader/loader.cpp @@ -102,7 +102,7 @@ void Loader::load(DocLoader* docLoader, CachedResource* resource, bool increment Request* request = new Request(docLoader, resource, incremental, skipCanLoadCheck, sendResourceLoadCallbacks); RefPtr host; - KURL url(resource->url()); + KURL url(ParsedURLString, resource->url()); if (url.protocolInHTTPFamily()) { AtomicString hostName = url.host(); host = m_hosts.get(hostName.impl()); @@ -355,7 +355,7 @@ void Loader::Host::didFinishLoading(SubresourceLoader* loader) DocLoader* docLoader = request->docLoader(); // Prevent the document from being destroyed before we are done with // the docLoader that it will delete when the document gets deleted. - DocPtr protector(docLoader->doc()); + RefPtr protector(docLoader->doc()); if (!request->isMultipart()) docLoader->decrementRequestCount(); @@ -403,7 +403,7 @@ void Loader::Host::didFail(SubresourceLoader* loader, bool cancelled) DocLoader* docLoader = request->docLoader(); // Prevent the document from being destroyed before we are done with // the docLoader that it will delete when the document gets deleted. - DocPtr protector(docLoader->doc()); + RefPtr protector(docLoader->doc()); if (!request->isMultipart()) docLoader->decrementRequestCount(); -- cgit v1.1