summaryrefslogtreecommitdiffstats
path: root/WebCore/loader
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/loader')
-rw-r--r--WebCore/loader/CachedMetadata.h125
-rw-r--r--WebCore/loader/CachedXBLDocument.cpp110
-rw-r--r--WebCore/loader/CachedXBLDocument.h67
-rw-r--r--WebCore/loader/CrossOriginAccessControl.cpp26
-rw-r--r--WebCore/loader/CrossOriginAccessControl.h5
-rw-r--r--WebCore/loader/CrossOriginPreflightResultCache.cpp48
-rw-r--r--WebCore/loader/CrossOriginPreflightResultCache.h16
-rw-r--r--WebCore/loader/DocumentLoadTiming.h (renamed from WebCore/loader/MediaDocument.h)55
-rw-r--r--WebCore/loader/DocumentLoader.cpp99
-rw-r--r--WebCore/loader/DocumentLoader.h27
-rw-r--r--WebCore/loader/DocumentThreadableLoader.cpp69
-rw-r--r--WebCore/loader/DocumentThreadableLoader.h3
-rw-r--r--WebCore/loader/DocumentWriter.cpp256
-rw-r--r--WebCore/loader/DocumentWriter.h91
-rw-r--r--WebCore/loader/EmptyClients.h151
-rw-r--r--WebCore/loader/FTPDirectoryDocument.cpp452
-rw-r--r--WebCore/loader/FTPDirectoryParser.cpp6
-rw-r--r--WebCore/loader/FormSubmission.cpp215
-rw-r--r--WebCore/loader/FormSubmission.h126
-rw-r--r--WebCore/loader/FrameLoader.cpp1580
-rw-r--r--WebCore/loader/FrameLoader.h158
-rw-r--r--WebCore/loader/FrameLoaderClient.h45
-rw-r--r--WebCore/loader/FrameLoaderStateMachine.cpp73
-rw-r--r--WebCore/loader/FrameLoaderStateMachine.h67
-rw-r--r--WebCore/loader/FrameLoaderTypes.h19
-rw-r--r--WebCore/loader/FrameNetworkingContext.h51
-rw-r--r--WebCore/loader/HistoryController.cpp197
-rw-r--r--WebCore/loader/HistoryController.h10
-rw-r--r--WebCore/loader/ImageDocument.cpp401
-rw-r--r--WebCore/loader/ImageDocument.h76
-rw-r--r--WebCore/loader/ImageLoader.cpp90
-rw-r--r--WebCore/loader/ImageLoader.h6
-rw-r--r--WebCore/loader/MainResourceLoader.cpp67
-rw-r--r--WebCore/loader/MainResourceLoader.h10
-rw-r--r--WebCore/loader/MediaDocument.cpp238
-rw-r--r--WebCore/loader/NavigationScheduler.cpp422
-rw-r--r--WebCore/loader/NavigationScheduler.h (renamed from WebCore/loader/RedirectScheduler.h)27
-rw-r--r--WebCore/loader/NetscapePlugInStreamLoader.cpp4
-rw-r--r--WebCore/loader/NetscapePlugInStreamLoader.h2
-rw-r--r--WebCore/loader/PingLoader.cpp106
-rw-r--r--WebCore/loader/PingLoader.h75
-rw-r--r--WebCore/loader/PlaceholderDocument.cpp3
-rw-r--r--WebCore/loader/PlaceholderDocument.h6
-rw-r--r--WebCore/loader/PluginDocument.cpp150
-rw-r--r--WebCore/loader/PluginDocument.h48
-rw-r--r--WebCore/loader/PolicyCallback.cpp7
-rw-r--r--WebCore/loader/PolicyCallback.h8
-rw-r--r--WebCore/loader/PolicyChecker.cpp2
-rw-r--r--WebCore/loader/ProgressTracker.cpp24
-rw-r--r--WebCore/loader/ProgressTracker.h4
-rw-r--r--WebCore/loader/RedirectScheduler.cpp403
-rw-r--r--WebCore/loader/Request.cpp4
-rw-r--r--WebCore/loader/Request.h16
-rw-r--r--WebCore/loader/ResourceLoadNotifier.cpp17
-rw-r--r--WebCore/loader/ResourceLoadNotifier.h6
-rw-r--r--WebCore/loader/ResourceLoader.cpp57
-rw-r--r--WebCore/loader/ResourceLoader.h18
-rw-r--r--WebCore/loader/SinkDocument.cpp (renamed from WebCore/loader/FTPDirectoryDocument.h)48
-rw-r--r--WebCore/loader/SinkDocument.h (renamed from WebCore/loader/TextDocument.h)24
-rw-r--r--WebCore/loader/SubframeLoader.cpp382
-rw-r--r--WebCore/loader/SubframeLoader.h99
-rw-r--r--WebCore/loader/SubresourceLoader.cpp51
-rw-r--r--WebCore/loader/SubresourceLoader.h3
-rw-r--r--WebCore/loader/SubresourceLoaderClient.h1
-rw-r--r--WebCore/loader/TextDocument.cpp196
-rw-r--r--WebCore/loader/TextResourceDecoder.cpp8
-rw-r--r--WebCore/loader/ThreadableLoaderClient.h2
-rw-r--r--WebCore/loader/WorkerThreadableLoader.cpp15
-rw-r--r--WebCore/loader/WorkerThreadableLoader.h4
-rw-r--r--WebCore/loader/appcache/ApplicationCache.cpp3
-rw-r--r--WebCore/loader/appcache/ApplicationCache.h3
-rw-r--r--WebCore/loader/appcache/ApplicationCacheGroup.cpp301
-rw-r--r--WebCore/loader/appcache/ApplicationCacheGroup.h50
-rw-r--r--WebCore/loader/appcache/ApplicationCacheHost.cpp90
-rw-r--r--WebCore/loader/appcache/ApplicationCacheHost.h63
-rw-r--r--WebCore/loader/appcache/ApplicationCacheStorage.cpp222
-rw-r--r--WebCore/loader/appcache/ApplicationCacheStorage.h29
-rw-r--r--WebCore/loader/appcache/DOMApplicationCache.h6
-rw-r--r--WebCore/loader/appcache/DOMApplicationCache.idl15
-rw-r--r--WebCore/loader/appcache/ManifestParser.cpp3
-rw-r--r--WebCore/loader/archive/ArchiveFactory.cpp4
-rw-r--r--WebCore/loader/archive/ArchiveFactory.h2
-rw-r--r--WebCore/loader/archive/ArchiveResource.cpp47
-rw-r--r--WebCore/loader/archive/ArchiveResource.h19
-rw-r--r--WebCore/loader/archive/android/WebArchiveAndroid.cpp469
-rw-r--r--WebCore/loader/archive/android/WebArchiveAndroid.h55
-rw-r--r--WebCore/loader/archive/cf/LegacyWebArchive.cpp17
-rw-r--r--WebCore/loader/archive/cf/LegacyWebArchiveMac.mm2
-rw-r--r--WebCore/loader/cache/CachePolicy.h (renamed from WebCore/loader/CachePolicy.h)0
-rw-r--r--WebCore/loader/cache/CachedCSSStyleSheet.cpp (renamed from WebCore/loader/CachedCSSStyleSheet.cpp)14
-rw-r--r--WebCore/loader/cache/CachedCSSStyleSheet.h (renamed from WebCore/loader/CachedCSSStyleSheet.h)5
-rw-r--r--WebCore/loader/cache/CachedFont.cpp (renamed from WebCore/loader/CachedFont.cpp)67
-rw-r--r--WebCore/loader/cache/CachedFont.h (renamed from WebCore/loader/CachedFont.h)15
-rw-r--r--WebCore/loader/cache/CachedImage.cpp (renamed from WebCore/loader/CachedImage.cpp)48
-rw-r--r--WebCore/loader/cache/CachedImage.h (renamed from WebCore/loader/CachedImage.h)14
-rw-r--r--WebCore/loader/cache/CachedResource.cpp (renamed from WebCore/loader/CachedResource.cpp)168
-rw-r--r--WebCore/loader/cache/CachedResource.h (renamed from WebCore/loader/CachedResource.h)108
-rw-r--r--WebCore/loader/cache/CachedResourceClient.h (renamed from WebCore/loader/CachedResourceClient.h)14
-rw-r--r--WebCore/loader/cache/CachedResourceClientWalker.cpp (renamed from WebCore/loader/CachedResourceClientWalker.cpp)0
-rw-r--r--WebCore/loader/cache/CachedResourceClientWalker.h (renamed from WebCore/loader/CachedResourceClientWalker.h)0
-rw-r--r--WebCore/loader/cache/CachedResourceHandle.cpp (renamed from WebCore/loader/CachedResourceHandle.cpp)0
-rw-r--r--WebCore/loader/cache/CachedResourceHandle.h (renamed from WebCore/loader/CachedResourceHandle.h)0
-rw-r--r--WebCore/loader/cache/CachedResourceLoader.cpp (renamed from WebCore/loader/DocLoader.cpp)174
-rw-r--r--WebCore/loader/cache/CachedResourceLoader.h (renamed from WebCore/loader/DocLoader.h)33
-rw-r--r--WebCore/loader/cache/CachedScript.cpp (renamed from WebCore/loader/CachedScript.cpp)19
-rw-r--r--WebCore/loader/cache/CachedScript.h (renamed from WebCore/loader/CachedScript.h)6
-rw-r--r--WebCore/loader/cache/CachedXSLStyleSheet.cpp (renamed from WebCore/loader/CachedXSLStyleSheet.cpp)11
-rw-r--r--WebCore/loader/cache/CachedXSLStyleSheet.h (renamed from WebCore/loader/CachedXSLStyleSheet.h)4
-rw-r--r--WebCore/loader/cache/MemoryCache.cpp (renamed from WebCore/loader/Cache.cpp)180
-rw-r--r--WebCore/loader/cache/MemoryCache.h (renamed from WebCore/loader/Cache.h)57
-rw-r--r--WebCore/loader/icon/IconDatabase.cpp38
-rw-r--r--WebCore/loader/icon/IconDatabase.h7
-rw-r--r--WebCore/loader/icon/IconDatabaseClient.h3
-rw-r--r--WebCore/loader/icon/IconFetcher.cpp228
-rw-r--r--WebCore/loader/icon/IconFetcher.h78
-rw-r--r--WebCore/loader/icon/IconLoader.cpp11
-rw-r--r--WebCore/loader/icon/IconLoader.h3
-rw-r--r--WebCore/loader/icon/IconRecord.cpp1
-rw-r--r--WebCore/loader/icon/IconRecord.h4
-rw-r--r--WebCore/loader/icon/wince/IconDatabaseWinCE.cpp (renamed from WebCore/loader/icon/wince/IconDatabaseWince.cpp)2
-rw-r--r--WebCore/loader/loader.cpp174
-rw-r--r--WebCore/loader/loader.h21
122 files changed, 5437 insertions, 4747 deletions
diff --git a/WebCore/loader/CachedMetadata.h b/WebCore/loader/CachedMetadata.h
new file mode 100644
index 0000000..120e4c0
--- /dev/null
+++ b/WebCore/loader/CachedMetadata.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CachedMetadata_h
+#define CachedMetadata_h
+
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+// Metadata retrieved from the embedding application's cache.
+//
+// Serialized data is NOT portable across architectures. However, reading the
+// data type ID will reject data generated with a different byte-order.
+class CachedMetadata : public RefCounted<CachedMetadata> {
+public:
+ static PassRefPtr<CachedMetadata> create(unsigned dataTypeID, const char* data, size_t size)
+ {
+ return adoptRef(new CachedMetadata(dataTypeID, data, size));
+ }
+
+ static PassRefPtr<CachedMetadata> deserialize(const char* data, size_t size)
+ {
+ return adoptRef(new CachedMetadata(data, size));
+ }
+
+ const Vector<char>& serialize() const
+ {
+ return m_serializedData;
+ }
+
+ ~CachedMetadata() { }
+
+ unsigned dataTypeID() const
+ {
+ return readUnsigned(dataTypeIDStart);
+ }
+
+ const char* data() const
+ {
+ if (m_serializedData.size() < dataStart)
+ return 0;
+ return m_serializedData.data() + dataStart;
+ }
+
+ size_t size() const
+ {
+ if (m_serializedData.size() < dataStart)
+ return 0;
+ return m_serializedData.size() - dataStart;
+ }
+
+private:
+ // Reads an unsigned value at position. Returns 0 on error.
+ unsigned readUnsigned(size_t position) const
+ {
+ if (m_serializedData.size() < position + sizeof(unsigned))
+ return 0;
+ return *reinterpret_cast_ptr<unsigned*>(const_cast<char*>(m_serializedData.data() + position));
+ }
+
+ // Appends an unsigned value to the end of the serialized data.
+ void appendUnsigned(unsigned value)
+ {
+ m_serializedData.append(reinterpret_cast<const char*>(&value), sizeof(unsigned));
+ }
+
+ CachedMetadata(const char* data, size_t size)
+ {
+ // Serialized metadata should have non-empty data.
+ ASSERT(size > dataStart);
+
+ m_serializedData.append(data, size);
+ }
+
+ CachedMetadata(unsigned dataTypeID, const char* data, size_t size)
+ {
+ // Don't allow an ID of 0, it is used internally to indicate errors.
+ ASSERT(dataTypeID);
+ ASSERT(data);
+
+ appendUnsigned(dataTypeID);
+ m_serializedData.append(data, size);
+ }
+
+ // Serialization offsets. Format: [DATA_TYPE_ID][DATA].
+ static const size_t dataTypeIDStart = 0;
+ static const size_t dataStart = sizeof(unsigned);
+
+ // Since the serialization format supports random access, storing it in
+ // serialized form avoids need for a copy during serialization.
+ Vector<char> m_serializedData;
+};
+
+}
+
+#endif
diff --git a/WebCore/loader/CachedXBLDocument.cpp b/WebCore/loader/CachedXBLDocument.cpp
deleted file mode 100644
index 0ff17f2..0000000
--- a/WebCore/loader/CachedXBLDocument.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
- Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
- Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
- Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public License
- along with this library; see the file COPYING.LIB. If not, write to
- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-
- This class provides all functionality needed for loading images, style sheets and html
- pages from the web. It has a memory cache for these objects.
-*/
-
-#include "config.h"
-
-#if ENABLE(XBL)
-
-#include "CachedXBLDocument.h"
-
-#include "CachedResourceClientWalker.h"
-#include "TextResourceDecoder.h"
-#include <wtf/Vector.h>
-
-namespace WebCore {
-
-CachedXBLDocument::CachedXBLDocument(const String &url)
-: CachedResource(url, XBL), m_document(0)
-{
- // It's XML we want.
- setAccept("text/xml, application/xml, application/xhtml+xml, text/xsl, application/rss+xml, application/atom+xml");
-
- m_decoder = new TextResourceDecoder("application/xml");
-}
-
-CachedXBLDocument::~CachedXBLDocument()
-{
- if (m_document)
- m_document->deref();
-}
-
-void CachedXBLDocument::ref(CachedResourceClient *c)
-{
- CachedResource::ref(c);
- if (!m_loading)
- c->setXBLDocument(m_url, m_document);
-}
-
-void CachedXBLDocument::setEncoding(const String& chs)
-{
- m_decoder->setEncoding(chs, TextResourceDecoder::EncodingFromHTTPHeader);
-}
-
-String CachedXBLDocument::encoding() const
-{
- return m_decoder->encoding().name();
-}
-
-void CachedXBLDocument::data(Vector<char>& data, bool )
-{
- if (!allDataReceived)
- return;
-
- ASSERT(!m_document);
-
- m_document = new XBL::XBLDocument();
- m_document->ref();
- m_document->open();
-
- m_document->write(m_decoder->decode(data.data(), data.size()));
- setSize(data.size());
-
- m_document->finishParsing();
- m_document->close();
- m_loading = false;
- checkNotify();
-}
-
-void CachedXBLDocument::checkNotify()
-{
- if (m_loading)
- return;
-
- CachedResourceClientWalker w(m_clients);
- while (CachedResourceClient *c = w.next())
- c->setXBLDocument(m_url, m_document);
-}
-
-void CachedXBLDocument::error()
-{
- m_loading = false;
- m_errorOccurred = true;
- checkNotify();
-}
-
-}
-
-#endif
diff --git a/WebCore/loader/CachedXBLDocument.h b/WebCore/loader/CachedXBLDocument.h
deleted file mode 100644
index b92a255..0000000
--- a/WebCore/loader/CachedXBLDocument.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
- Copyright (C) 2001 Dirk Mueller <mueller@kde.org>
- Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public License
- along with this library; see the file COPYING.LIB. If not, write to
- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-
- This class provides all functionality needed for loading images, style sheets and html
- pages from the web. It has a memory cache for these objects.
-*/
-
-#ifndef CachedXBLDocument_h
-#define CachedXBLDocument_h
-
-#include "CachedResource.h"
-#include <wtf/Vector.h>
-
-namespace WebCore {
- class CachedResource;
- class Request;
- class DocLoader;
- class TextResourceDecoder;
- class CachedResourceClient;
-
-#if ENABLE(XBL)
- class CachedXBLDocument : public CachedResource {
- public:
- CachedXBLDocument(const String& url);
- virtual ~CachedXBLDocument();
-
- XBL::XBLDocument* document() const { return m_document; }
-
- virtual void addClient(CachedResourceClient*);
-
- virtual void setEncoding(const String&);
- virtual String encoding() const;
- virtual void data(Vector<char>&, bool allDataReceived);
- virtual void error();
-
- virtual bool schedule() const { return true; }
-
- void checkNotify();
-
- protected:
- XBL::XBLDocument* m_document;
- RefPtr<TextResourceDecoder> m_decoder;
- };
-
-#endif
-
-}
-
-#endif
diff --git a/WebCore/loader/CrossOriginAccessControl.cpp b/WebCore/loader/CrossOriginAccessControl.cpp
index 01596e2..f510704 100644
--- a/WebCore/loader/CrossOriginAccessControl.cpp
+++ b/WebCore/loader/CrossOriginAccessControl.cpp
@@ -27,11 +27,11 @@
#include "config.h"
#include "CrossOriginAccessControl.h"
-#include "AtomicString.h"
#include "HTTPParsers.h"
#include "ResourceResponse.h"
#include "SecurityOrigin.h"
#include <wtf/Threading.h>
+#include <wtf/text/AtomicString.h>
namespace WebCore {
@@ -71,9 +71,9 @@ bool isSimpleCrossOriginAccessRequest(const String& method, const HTTPHeaderMap&
}
typedef HashSet<String, CaseFoldingHash> HTTPHeaderSet;
-static HTTPHeaderSet* createAllowedCrossOriginResponseHeadersSet()
+static PassOwnPtr<HTTPHeaderSet> createAllowedCrossOriginResponseHeadersSet()
{
- HTTPHeaderSet* headerSet = new HashSet<String, CaseFoldingHash>;
+ OwnPtr<HTTPHeaderSet> headerSet = adoptPtr(new HashSet<String, CaseFoldingHash>);
headerSet->add("cache-control");
headerSet->add("content-language");
@@ -82,17 +82,17 @@ static HTTPHeaderSet* createAllowedCrossOriginResponseHeadersSet()
headerSet->add("last-modified");
headerSet->add("pragma");
- return headerSet;
+ return headerSet.release();
}
bool isOnAccessControlResponseHeaderWhitelist(const String& name)
{
- AtomicallyInitializedStatic(HTTPHeaderSet*, allowedCrossOriginResponseHeaders = createAllowedCrossOriginResponseHeadersSet());
+ AtomicallyInitializedStatic(HTTPHeaderSet*, allowedCrossOriginResponseHeaders = createAllowedCrossOriginResponseHeadersSet().leakPtr());
return allowedCrossOriginResponseHeaders->contains(name);
}
-bool passesAccessControlCheck(const ResourceResponse& response, bool includeCredentials, SecurityOrigin* securityOrigin)
+bool passesAccessControlCheck(const ResourceResponse& response, bool includeCredentials, SecurityOrigin* securityOrigin, String& errorDescription)
{
// A wildcard Access-Control-Allow-Origin can not be used if credentials are to be sent,
// even with Access-Control-Allow-Credentials set to true.
@@ -100,17 +100,25 @@ bool passesAccessControlCheck(const ResourceResponse& response, bool includeCred
if (accessControlOriginString == "*" && !includeCredentials)
return true;
- if (securityOrigin->isUnique())
+ if (securityOrigin->isUnique()) {
+ errorDescription = "Cannot make any requests from " + securityOrigin->toString() + ".";
return false;
+ }
+ // FIXME: Access-Control-Allow-Origin can contain a list of origins.
RefPtr<SecurityOrigin> accessControlOrigin = SecurityOrigin::createFromString(accessControlOriginString);
- if (!accessControlOrigin->isSameSchemeHostPort(securityOrigin))
+ if (!accessControlOrigin->isSameSchemeHostPort(securityOrigin)) {
+ errorDescription = (accessControlOriginString == "*") ? "Cannot use wildcard in Access-Control-Allow-Origin when credentials flag is true."
+ : "Origin " + securityOrigin->toString() + " is not allowed by Access-Control-Allow-Origin.";
return false;
+ }
if (includeCredentials) {
const String& accessControlCredentialsString = response.httpHeaderField("Access-Control-Allow-Credentials");
- if (accessControlCredentialsString != "true")
+ if (accessControlCredentialsString != "true") {
+ errorDescription = "Credentials flag is true, but Access-Control-Allow-Credentials is not \"true\".";
return false;
+ }
}
return true;
diff --git a/WebCore/loader/CrossOriginAccessControl.h b/WebCore/loader/CrossOriginAccessControl.h
index 267646f..c44963b 100644
--- a/WebCore/loader/CrossOriginAccessControl.h
+++ b/WebCore/loader/CrossOriginAccessControl.h
@@ -24,18 +24,19 @@
*
*/
+#include <wtf/Forward.h>
+
namespace WebCore {
class HTTPHeaderMap;
class ResourceResponse;
class SecurityOrigin;
- class String;
bool isSimpleCrossOriginAccessRequest(const String& method, const HTTPHeaderMap&);
bool isOnAccessControlSimpleRequestMethodWhitelist(const String&);
bool isOnAccessControlSimpleRequestHeaderWhitelist(const String& name, const String& value);
bool isOnAccessControlResponseHeaderWhitelist(const String&);
- bool passesAccessControlCheck(const ResourceResponse&, bool includeCredentials, SecurityOrigin*);
+ bool passesAccessControlCheck(const ResourceResponse&, bool includeCredentials, SecurityOrigin*, String& errorDescription);
} // namespace WebCore
diff --git a/WebCore/loader/CrossOriginPreflightResultCache.cpp b/WebCore/loader/CrossOriginPreflightResultCache.cpp
index cea66b1..18e4be2 100644
--- a/WebCore/loader/CrossOriginPreflightResultCache.cpp
+++ b/WebCore/loader/CrossOriginPreflightResultCache.cpp
@@ -35,6 +35,8 @@
namespace WebCore {
+using namespace std;
+
// These values are at the discretion of the user agent.
static const unsigned defaultPreflightCacheTimeoutSeconds = 5;
static const unsigned maxPreflightCacheTimeoutSeconds = 600; // Should be short enough to minimize the risk of using a poisoned cache after switching to a secure network.
@@ -72,30 +74,34 @@ static void addToAccessControlAllowList(const String& string, unsigned start, un
template<class HashType>
static bool parseAccessControlAllowList(const String& string, HashSet<String, HashType>& set)
{
- int start = 0;
- int end;
- while ((end = string.find(',', start)) != -1) {
+ unsigned start = 0;
+ size_t end;
+ while ((end = string.find(',', start)) != notFound) {
if (start == end)
return false;
addToAccessControlAllowList(string, start, end - 1, set);
start = end + 1;
}
- if (start != static_cast<int>(string.length()))
+ if (start != string.length())
addToAccessControlAllowList(string, start, string.length() - 1, set);
return true;
}
-bool CrossOriginPreflightResultCacheItem::parse(const ResourceResponse& response)
+bool CrossOriginPreflightResultCacheItem::parse(const ResourceResponse& response, String& errorDescription)
{
m_methods.clear();
- if (!parseAccessControlAllowList(response.httpHeaderField("Access-Control-Allow-Methods"), m_methods))
+ if (!parseAccessControlAllowList(response.httpHeaderField("Access-Control-Allow-Methods"), m_methods)) {
+ errorDescription = "Cannot parse Access-Control-Allow-Methods response header field.";
return false;
+ }
m_headers.clear();
- if (!parseAccessControlAllowList(response.httpHeaderField("Access-Control-Allow-Headers"), m_headers))
+ if (!parseAccessControlAllowList(response.httpHeaderField("Access-Control-Allow-Headers"), m_headers)) {
+ errorDescription = "Cannot parse Access-Control-Allow-Headers response header field.";
return false;
+ }
unsigned expiryDelta;
if (parseAccessControlMaxAge(response.httpHeaderField("Access-Control-Max-Age"), expiryDelta)) {
@@ -108,30 +114,37 @@ bool CrossOriginPreflightResultCacheItem::parse(const ResourceResponse& response
return true;
}
-bool CrossOriginPreflightResultCacheItem::allowsCrossOriginMethod(const String& method) const
+bool CrossOriginPreflightResultCacheItem::allowsCrossOriginMethod(const String& method, String& errorDescription) const
{
- return m_methods.contains(method) || isOnAccessControlSimpleRequestMethodWhitelist(method);
+ if (m_methods.contains(method) || isOnAccessControlSimpleRequestMethodWhitelist(method))
+ return true;
+
+ errorDescription = "Method " + method + " is not allowed by Access-Control-Allow-Methods.";
+ return false;
}
-bool CrossOriginPreflightResultCacheItem::allowsCrossOriginHeaders(const HTTPHeaderMap& requestHeaders) const
+bool CrossOriginPreflightResultCacheItem::allowsCrossOriginHeaders(const HTTPHeaderMap& requestHeaders, String& errorDescription) const
{
HTTPHeaderMap::const_iterator end = requestHeaders.end();
for (HTTPHeaderMap::const_iterator it = requestHeaders.begin(); it != end; ++it) {
- if (!m_headers.contains(it->first) && !isOnAccessControlSimpleRequestHeaderWhitelist(it->first, it->second))
+ if (!m_headers.contains(it->first) && !isOnAccessControlSimpleRequestHeaderWhitelist(it->first, it->second)) {
+ errorDescription = "Request header field " + it->first.string() + " is not allowed by Access-Control-Allow-Headers.";
return false;
+ }
}
return true;
}
bool CrossOriginPreflightResultCacheItem::allowsRequest(bool includeCredentials, const String& method, const HTTPHeaderMap& requestHeaders) const
{
+ String ignoredExplanation;
if (m_absoluteExpiryTime < currentTime())
return false;
if (includeCredentials && !m_credentials)
return false;
- if (!allowsCrossOriginMethod(method))
+ if (!allowsCrossOriginMethod(method, ignoredExplanation))
return false;
- if (!allowsCrossOriginHeaders(requestHeaders))
+ if (!allowsCrossOriginHeaders(requestHeaders, ignoredExplanation))
return false;
return true;
}
@@ -143,10 +156,15 @@ CrossOriginPreflightResultCache& CrossOriginPreflightResultCache::shared()
return cache;
}
-void CrossOriginPreflightResultCache::appendEntry(const String& origin, const KURL& url, CrossOriginPreflightResultCacheItem* preflightResult)
+void CrossOriginPreflightResultCache::appendEntry(const String& origin, const KURL& url, PassOwnPtr<CrossOriginPreflightResultCacheItem> preflightResult)
{
ASSERT(isMainThread());
- m_preflightHashMap.set(std::make_pair(origin, url), preflightResult);
+ CrossOriginPreflightResultCacheItem* resultPtr = preflightResult.leakPtr();
+ pair<CrossOriginPreflightResultHashMap::iterator, bool> addResult = m_preflightHashMap.add(make_pair(origin, url), resultPtr);
+ if (!addResult.second) {
+ // FIXME: We need to delete the old value before replacing with the new one.
+ addResult.first->second = resultPtr;
+ }
}
bool CrossOriginPreflightResultCache::canSkipPreflight(const String& origin, const KURL& url, bool includeCredentials, const String& method, const HTTPHeaderMap& requestHeaders)
diff --git a/WebCore/loader/CrossOriginPreflightResultCache.h b/WebCore/loader/CrossOriginPreflightResultCache.h
index faf55e5..1016aed 100644
--- a/WebCore/loader/CrossOriginPreflightResultCache.h
+++ b/WebCore/loader/CrossOriginPreflightResultCache.h
@@ -24,10 +24,14 @@
*
*/
+#ifndef CrossOriginPreflightResultCache_h
+#define CrossOriginPreflightResultCache_h
+
#include "KURLHash.h"
-#include "StringHash.h"
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/text/StringHash.h>
namespace WebCore {
@@ -42,9 +46,9 @@ namespace WebCore {
{
}
- bool parse(const ResourceResponse&);
- bool allowsCrossOriginMethod(const String&) const;
- bool allowsCrossOriginHeaders(const HTTPHeaderMap&) const;
+ bool parse(const ResourceResponse&, String& errorDescription);
+ bool allowsCrossOriginMethod(const String&, String& errorDescription) const;
+ bool allowsCrossOriginHeaders(const HTTPHeaderMap&, String& errorDescription) const;
bool allowsRequest(bool includeCredentials, const String& method, const HTTPHeaderMap& requestHeaders) const;
private:
@@ -63,7 +67,7 @@ namespace WebCore {
public:
static CrossOriginPreflightResultCache& shared();
- void appendEntry(const String& origin, const KURL&, CrossOriginPreflightResultCacheItem*);
+ void appendEntry(const String& origin, const KURL&, PassOwnPtr<CrossOriginPreflightResultCacheItem>);
bool canSkipPreflight(const String& origin, const KURL&, bool includeCredentials, const String& method, const HTTPHeaderMap& requestHeaders);
void empty();
@@ -77,3 +81,5 @@ namespace WebCore {
};
} // namespace WebCore
+
+#endif
diff --git a/WebCore/loader/MediaDocument.h b/WebCore/loader/DocumentLoadTiming.h
index aa751ab..2d4b0fa 100644
--- a/WebCore/loader/MediaDocument.h
+++ b/WebCore/loader/DocumentLoadTiming.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008,2009 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2010 Google, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -23,39 +23,36 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef MediaDocument_h
-#define MediaDocument_h
-
-#if ENABLE(VIDEO)
-
-#include "HTMLDocument.h"
+#ifndef DocumentLoadTiming_h
+#define DocumentLoadTiming_h
namespace WebCore {
-class MediaDocument : public HTMLDocument {
-public:
- static PassRefPtr<MediaDocument> create(Frame* frame)
+struct DocumentLoadTiming {
+ DocumentLoadTiming()
+ : navigationStart(0.0)
+ , unloadEventEnd(0.0)
+ , redirectStart(0.0)
+ , redirectEnd(0.0)
+ , redirectCount(0)
+ , fetchStart(0.0)
+ , responseEnd(0.0)
+ , loadEventStart(0.0)
+ , loadEventEnd(0.0)
{
- return adoptRef(new MediaDocument(frame));
}
- virtual ~MediaDocument();
-
- void mediaElementSawUnsupportedTracks();
-
-private:
- MediaDocument(Frame*);
-
- virtual bool isMediaDocument() const { return true; }
- virtual Tokenizer* createTokenizer();
- virtual void defaultEventHandler(Event*);
-
- void replaceMediaElementTimerFired(Timer<MediaDocument>*);
-
- Timer<MediaDocument> m_replaceMediaElementTimer;
+ double navigationStart;
+ double unloadEventEnd;
+ double redirectStart;
+ double redirectEnd;
+ short redirectCount;
+ double fetchStart;
+ double responseEnd;
+ double loadEventStart;
+ double loadEventEnd;
};
-
+
}
#endif
-#endif
diff --git a/WebCore/loader/DocumentLoader.cpp b/WebCore/loader/DocumentLoader.cpp
index dca416e..0836805 100644
--- a/WebCore/loader/DocumentLoader.cpp
+++ b/WebCore/loader/DocumentLoader.cpp
@@ -37,11 +37,13 @@
#include "SubstituteResource.h"
#endif
#include "CachedPage.h"
-#include "DocLoader.h"
+#include "CachedResourceLoader.h"
#include "Document.h"
+#include "DocumentParser.h"
#include "Event.h"
#include "Frame.h"
#include "FrameLoader.h"
+#include "FrameLoaderClient.h"
#include "FrameTree.h"
#include "HistoryItem.h"
#include "Logging.h"
@@ -50,9 +52,9 @@
#include "PlatformString.h"
#include "Settings.h"
#include "SharedBuffer.h"
-#include "XMLTokenizer.h"
#include <wtf/Assertions.h>
+#include <wtf/text/CString.h>
#include <wtf/unicode/Unicode.h>
namespace WebCore {
@@ -86,11 +88,12 @@ DocumentLoader::DocumentLoader(const ResourceRequest& req, const SubstituteData&
, m_gotFirstByte(false)
, m_primaryLoadComplete(false)
, m_isClientRedirect(false)
+ , m_wasOnloadHandled(false)
, m_stopRecordingResponses(false)
, m_substituteResourceDeliveryTimer(this, &DocumentLoader::substituteResourceDeliveryTimerFired)
, m_didCreateGlobalHistoryEntry(false)
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
- , m_applicationCacheHost(new ApplicationCacheHost(this))
+ , m_applicationCacheHost(adoptPtr(new ApplicationCacheHost(this)))
#endif
{
}
@@ -221,6 +224,11 @@ void DocumentLoader::stopLoading(DatabasePolicy databasePolicy)
// Always cancel multipart loaders
cancelAll(m_multipartSubresourceLoaders);
+ // Appcache uses ResourceHandle directly, DocumentLoader doesn't count these loads.
+#if ENABLE(OFFLINE_WEB_APPLICATIONS)
+ m_applicationCacheHost->stopLoadingInFrame(m_frame);
+#endif
+
if (!loading)
return;
@@ -259,7 +267,7 @@ void DocumentLoader::commitIfReady()
{
if (m_gotFirstByte && !m_committed) {
m_committed = true;
- frameLoader()->commitProvisionalLoad(0);
+ frameLoader()->commitProvisionalLoad();
}
}
@@ -269,7 +277,7 @@ void DocumentLoader::finishedLoading()
commitIfReady();
if (FrameLoader* loader = frameLoader()) {
loader->finishedLoadingDocument(this);
- loader->end();
+ loader->writer()->end();
}
}
@@ -280,8 +288,29 @@ void DocumentLoader::commitLoad(const char* data, int length)
RefPtr<DocumentLoader> protect(this);
commitIfReady();
- if (FrameLoader* frameLoader = DocumentLoader::frameLoader())
- frameLoader->committedLoad(this, data, length);
+ FrameLoader* frameLoader = DocumentLoader::frameLoader();
+ if (!frameLoader)
+ return;
+#if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size
+ if (ArchiveFactory::isArchiveMimeType(response().mimeType()))
+ return;
+#endif
+ frameLoader->client()->committedLoad(this, data, length);
+}
+
+void DocumentLoader::commitData(const char* bytes, int length)
+{
+ // Set the text encoding. This is safe to call multiple times.
+ bool userChosen = true;
+ String encoding = overrideEncoding();
+ if (encoding.isNull()) {
+ userChosen = false;
+ encoding = response().textEncodingName();
+ }
+ // FIXME: DocumentWriter should be owned by DocumentLoader.
+ m_frame->loader()->writer()->setEncoding(encoding, userChosen);
+ ASSERT(m_frame->document()->parsing());
+ m_frame->loader()->writer()->addData(bytes, length);
}
bool DocumentLoader::doesProgressiveLoad(const String& MIMEType) const
@@ -311,7 +340,7 @@ void DocumentLoader::setupForReplaceByMIMEType(const String& newMIMEType)
}
frameLoader()->finishedLoadingDocument(this);
- m_frame->loader()->end();
+ m_frame->loader()->writer()->end();
frameLoader()->setReplacing();
m_gotFirstByte = false;
@@ -397,10 +426,10 @@ bool DocumentLoader::isLoadingInAPISense() const
if (!m_subresourceLoaders.isEmpty())
return true;
Document* doc = m_frame->document();
- if (doc->docLoader()->requestCount())
+ if (doc->cachedResourceLoader()->requestCount())
return true;
- if (Tokenizer* tok = doc->tokenizer())
- if (tok->processingData())
+ if (DocumentParser* parser = doc->parser())
+ if (parser->processingData())
return true;
}
return frameLoader()->subframeIsLoading();
@@ -410,7 +439,7 @@ bool DocumentLoader::isLoadingInAPISense() const
void DocumentLoader::addAllArchiveResources(Archive* archive)
{
if (!m_archiveResourceCollection)
- m_archiveResourceCollection.set(new ArchiveResourceCollection);
+ m_archiveResourceCollection = adoptPtr(new ArchiveResourceCollection);
ASSERT(archive);
if (!archive)
@@ -424,7 +453,7 @@ void DocumentLoader::addAllArchiveResources(Archive* archive)
void DocumentLoader::addArchiveResource(PassRefPtr<ArchiveResource> resource)
{
if (!m_archiveResourceCollection)
- m_archiveResourceCollection.set(new ArchiveResourceCollection);
+ m_archiveResourceCollection = adoptPtr(new ArchiveResourceCollection);
ASSERT(resource);
if (!resource)
@@ -471,7 +500,7 @@ PassRefPtr<ArchiveResource> DocumentLoader::mainResource() const
if (!mainResourceBuffer)
mainResourceBuffer = SharedBuffer::create();
- return ArchiveResource::create(mainResourceBuffer, r.url(), r.mimeType(), r.textEncodingName(), frame()->tree()->name());
+ return ArchiveResource::create(mainResourceBuffer, r.url(), r.mimeType(), r.textEncodingName(), frame()->tree()->uniqueName());
}
PassRefPtr<ArchiveResource> DocumentLoader::subresource(const KURL& url) const
@@ -479,7 +508,7 @@ PassRefPtr<ArchiveResource> DocumentLoader::subresource(const KURL& url) const
if (!isCommitted())
return 0;
- CachedResource* resource = m_frame->document()->docLoader()->cachedResource(url);
+ CachedResource* resource = m_frame->document()->cachedResourceLoader()->cachedResource(url);
if (!resource || !resource->isLoaded())
return archiveResourceForURL(url);
@@ -502,9 +531,9 @@ void DocumentLoader::getSubresources(Vector<PassRefPtr<ArchiveResource> >& subre
Document* document = m_frame->document();
- 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) {
+ const CachedResourceLoader::DocumentResourceMap& allResources = document->cachedResourceLoader()->allCachedResources();
+ CachedResourceLoader::DocumentResourceMap::const_iterator end = allResources.end();
+ for (CachedResourceLoader::DocumentResourceMap::const_iterator it = allResources.begin(); it != end; ++it) {
RefPtr<ArchiveResource> subresource = this->subresource(KURL(ParsedURLString, it->second->url()));
if (subresource)
subresources.append(subresource.release());
@@ -546,7 +575,7 @@ void DocumentLoader::substituteResourceDeliveryTimerFired(Timer<DocumentLoader>*
loader->didReceiveResponse(resource->response());
loader->didReceiveData(data->data(), data->size(), data->size(), true);
- loader->didFinishLoading();
+ loader->didFinishLoading(0);
} else {
// A null resource means that we should fail the load.
// FIXME: Maybe we should use another error here - something like "not in cache".
@@ -617,6 +646,17 @@ void DocumentLoader::setTitle(const String& title)
}
}
+void DocumentLoader::setIconURL(const String& iconURL)
+{
+ if (iconURL.isEmpty())
+ return;
+
+ if (m_pageIconURL != iconURL) {
+ m_pageIconURL = iconURL;
+ frameLoader()->didChangeIcons(this);
+ }
+}
+
KURL DocumentLoader::urlForHistory() const
{
// Return the URL to be used for history and B/F list.
@@ -759,6 +799,27 @@ void DocumentLoader::subresourceLoaderFinishedLoadingOnePart(ResourceLoader* loa
frame->loader()->checkLoadComplete();
}
+void DocumentLoader::transferLoadingResourcesFromPage(Page* oldPage)
+{
+ ASSERT(oldPage != m_frame->page());
+
+ FrameLoaderClient* frameLoaderClient = frameLoader()->client();
+ const ResourceRequest& request = originalRequest();
+ if (isLoadingMainResource()) {
+ frameLoaderClient->transferLoadingResourceFromPage(
+ m_mainResourceLoader->identifier(), this, request, oldPage);
+ }
+
+ if (isLoadingSubresources()) {
+ ResourceLoaderSet::const_iterator it = m_subresourceLoaders.begin();
+ ResourceLoaderSet::const_iterator end = m_subresourceLoaders.end();
+ for (; it != end; ++it) {
+ frameLoaderClient->transferLoadingResourceFromPage(
+ (*it)->identifier(), this, request, oldPage);
+ }
+ }
+}
+
void DocumentLoader::iconLoadDecisionAvailable()
{
if (m_frame)
diff --git a/WebCore/loader/DocumentLoader.h b/WebCore/loader/DocumentLoader.h
index 440cfc4..2328160 100644
--- a/WebCore/loader/DocumentLoader.h
+++ b/WebCore/loader/DocumentLoader.h
@@ -29,6 +29,7 @@
#ifndef DocumentLoader_h
#define DocumentLoader_h
+#include "DocumentLoadTiming.h"
#include "NavigationAction.h"
#include "ResourceError.h"
#include "ResourceRequest.h"
@@ -47,6 +48,7 @@ namespace WebCore {
class Frame;
class FrameLoader;
class MainResourceLoader;
+ class Page;
class ResourceLoader;
class SchedulePair;
class SharedBuffer;
@@ -108,9 +110,12 @@ namespace WebCore {
void prepareForLoadStart();
bool isClientRedirect() const { return m_isClientRedirect; }
void setIsClientRedirect(bool isClientRedirect) { m_isClientRedirect = isClientRedirect; }
+ void handledOnloadEvents() { m_wasOnloadHandled = true; }
+ bool wasOnloadHandled() { return m_wasOnloadHandled; }
bool isLoadingInAPISense() const;
void setPrimaryLoadComplete(bool);
void setTitle(const String&);
+ void setIconURL(const String&);
const String& overrideEncoding() const { return m_overrideEncoding; }
#if PLATFORM(MAC)
@@ -154,6 +159,7 @@ namespace WebCore {
void stopRecordingResponses();
const String& title() const { return m_pageTitle; }
+ const String& iconURL() const { return m_pageIconURL; }
KURL urlForHistory() const;
bool urlForHistoryReflectsFailure() const;
@@ -194,15 +200,28 @@ namespace WebCore {
void removePlugInStreamLoader(ResourceLoader*);
void subresourceLoaderFinishedLoadingOnePart(ResourceLoader*);
-
+
+ void transferLoadingResourcesFromPage(Page*);
+
void setDeferMainResourceDataLoad(bool defer) { m_deferMainResourceDataLoad = defer; }
bool deferMainResourceDataLoad() const { return m_deferMainResourceDataLoad; }
- void didTellClientAboutLoad(const String& url) { m_resourcesClientKnowsAbout.add(url); }
+ void didTellClientAboutLoad(const String& url)
+ {
+ if (!url.isEmpty())
+ m_resourcesClientKnowsAbout.add(url);
+ }
bool haveToldClientAboutLoad(const String& url) { return m_resourcesClientKnowsAbout.contains(url); }
void recordMemoryCacheLoadForFutureClientNotification(const String& url);
void takeMemoryCacheLoadsForClientNotification(Vector<String>& loads);
+ DocumentLoadTiming* timing() { return &m_documentLoadTiming; }
+ void resetTiming() { m_documentLoadTiming = DocumentLoadTiming(); }
+
+ // The WebKit layer calls this function when it's ready for the data to
+ // actually be added to the document.
+ void commitData(const char* bytes, int length);
+
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
ApplicationCacheHost* applicationCacheHost() const { return m_applicationCacheHost.get(); }
#endif
@@ -259,8 +278,10 @@ namespace WebCore {
bool m_gotFirstByte;
bool m_primaryLoadComplete;
bool m_isClientRedirect;
+ bool m_wasOnloadHandled;
String m_pageTitle;
+ String m_pageIconURL;
String m_overrideEncoding;
@@ -293,6 +314,8 @@ namespace WebCore {
String m_clientRedirectSourceForHistory;
bool m_didCreateGlobalHistoryEntry;
+ DocumentLoadTiming m_documentLoadTiming;
+
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
friend class ApplicationCacheHost; // for substitute resource delivery
OwnPtr<ApplicationCacheHost> m_applicationCacheHost;
diff --git a/WebCore/loader/DocumentThreadableLoader.cpp b/WebCore/loader/DocumentThreadableLoader.cpp
index d0f6c04..a792144 100644
--- a/WebCore/loader/DocumentThreadableLoader.cpp
+++ b/WebCore/loader/DocumentThreadableLoader.cpp
@@ -37,10 +37,12 @@
#include "Document.h"
#include "Frame.h"
#include "FrameLoader.h"
+#include "ResourceHandle.h"
#include "ResourceRequest.h"
#include "SecurityOrigin.h"
#include "SubresourceLoader.h"
#include "ThreadableLoaderClient.h"
+#include <wtf/UnusedParam.h>
namespace WebCore {
@@ -75,22 +77,25 @@ DocumentThreadableLoader::DocumentThreadableLoader(Document* document, Threadabl
}
if (m_options.crossOriginRequestPolicy == DenyCrossOriginRequests) {
- m_client->didFail(ResourceError());
+ m_client->didFail(ResourceError(errorDomainWebKitInternal, 0, request.url().string(), "Cross origin requests are not supported."));
return;
}
ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl);
- if (!m_options.forcePreflight && isSimpleCrossOriginAccessRequest(request.httpMethod(), request.httpHeaderFields()))
- makeSimpleCrossOriginAccessRequest(request);
+ OwnPtr<ResourceRequest> crossOriginRequest = adoptPtr(new ResourceRequest(request));
+ crossOriginRequest->removeCredentials();
+ crossOriginRequest->setAllowCookies(m_options.allowCredentials);
+
+ if (!m_options.forcePreflight && isSimpleCrossOriginAccessRequest(crossOriginRequest->httpMethod(), crossOriginRequest->httpHeaderFields()))
+ makeSimpleCrossOriginAccessRequest(*crossOriginRequest);
else {
- m_actualRequest.set(new ResourceRequest(request));
- m_actualRequest->setAllowCookies(m_options.allowCredentials);
+ m_actualRequest = crossOriginRequest.release();
- if (CrossOriginPreflightResultCache::shared().canSkipPreflight(document->securityOrigin()->toString(), request.url(), m_options.allowCredentials, request.httpMethod(), request.httpHeaderFields()))
+ if (CrossOriginPreflightResultCache::shared().canSkipPreflight(document->securityOrigin()->toString(), m_actualRequest->url(), m_options.allowCredentials, m_actualRequest->httpMethod(), m_actualRequest->httpHeaderFields()))
preflightSuccess();
else
- makeCrossOriginAccessRequestWithPreflight(request);
+ makeCrossOriginAccessRequestWithPreflight(*m_actualRequest);
}
}
@@ -100,14 +105,12 @@ void DocumentThreadableLoader::makeSimpleCrossOriginAccessRequest(const Resource
// 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());
+ m_client->didFail(ResourceError(errorDomainWebKitInternal, 0, request.url().string(), "Cross origin requests are only supported for HTTP."));
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());
loadRequest(crossOriginRequest, DoSecurityCheck);
@@ -185,25 +188,26 @@ void DocumentThreadableLoader::didReceiveResponse(SubresourceLoader* loader, con
ASSERT(m_client);
ASSERT_UNUSED(loader, loader == m_loader);
+ String accessControlErrorDescription;
if (m_actualRequest) {
- if (!passesAccessControlCheck(response, m_options.allowCredentials, m_document->securityOrigin())) {
- preflightFailure();
+ if (!passesAccessControlCheck(response, m_options.allowCredentials, m_document->securityOrigin(), accessControlErrorDescription)) {
+ preflightFailure(response.url(), accessControlErrorDescription);
return;
}
- OwnPtr<CrossOriginPreflightResultCacheItem> preflightResult(new CrossOriginPreflightResultCacheItem(m_options.allowCredentials));
- if (!preflightResult->parse(response)
- || !preflightResult->allowsCrossOriginMethod(m_actualRequest->httpMethod())
- || !preflightResult->allowsCrossOriginHeaders(m_actualRequest->httpHeaderFields())) {
- preflightFailure();
+ OwnPtr<CrossOriginPreflightResultCacheItem> preflightResult = adoptPtr(new CrossOriginPreflightResultCacheItem(m_options.allowCredentials));
+ if (!preflightResult->parse(response, accessControlErrorDescription)
+ || !preflightResult->allowsCrossOriginMethod(m_actualRequest->httpMethod(), accessControlErrorDescription)
+ || !preflightResult->allowsCrossOriginHeaders(m_actualRequest->httpHeaderFields(), accessControlErrorDescription)) {
+ preflightFailure(response.url(), accessControlErrorDescription);
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());
+ if (!passesAccessControlCheck(response, m_options.allowCredentials, m_document->securityOrigin(), accessControlErrorDescription)) {
+ m_client->didFail(ResourceError(errorDomainWebKitInternal, 0, response.url().string(), accessControlErrorDescription));
return;
}
}
@@ -217,6 +221,10 @@ void DocumentThreadableLoader::didReceiveData(SubresourceLoader* loader, const c
ASSERT(m_client);
ASSERT_UNUSED(loader, loader == m_loader);
+ // Ignore response body of preflight requests.
+ if (m_actualRequest)
+ return;
+
m_client->didReceiveData(data, lengthReceived);
}
@@ -258,14 +266,20 @@ bool DocumentThreadableLoader::getShouldUseCredentialStorage(SubresourceLoader*
return false; // Only FrameLoaderClient can ultimately permit credential use.
}
-void DocumentThreadableLoader::didReceiveAuthenticationChallenge(SubresourceLoader* loader, const AuthenticationChallenge&)
+void DocumentThreadableLoader::didReceiveAuthenticationChallenge(SubresourceLoader* loader, const AuthenticationChallenge& challenge)
{
ASSERT(loader == m_loader);
// Users are not prompted for credentials for cross-origin requests.
if (!m_sameOriginRequest) {
+#if PLATFORM(MAC) || USE(CFNETWORK) || USE(CURL)
+ loader->handle()->receivedRequestToContinueWithoutCredential(challenge);
+#else
+ // These platforms don't provide a way to continue without credentials, cancel the load altogether.
+ UNUSED_PARAM(challenge);
RefPtr<DocumentThreadableLoader> protect(this);
m_client->didFail(loader->blockedError());
cancel();
+#endif
}
}
@@ -285,14 +299,19 @@ void DocumentThreadableLoader::preflightSuccess()
loadRequest(*actualRequest, SkipSecurityCheck);
}
-void DocumentThreadableLoader::preflightFailure()
+void DocumentThreadableLoader::preflightFailure(const String& url, const String& errorDescription)
{
m_actualRequest = 0; // Prevent didFinishLoading() from bypassing access check.
- m_client->didFail(ResourceError());
+ m_client->didFail(ResourceError(errorDomainWebKitInternal, 0, url, errorDescription));
}
void DocumentThreadableLoader::loadRequest(const ResourceRequest& request, SecurityCheckPolicy securityCheck)
{
+ // Any credential should have been removed from the cross-site requests.
+ const KURL& requestURL = request.url();
+ ASSERT(m_sameOriginRequest || requestURL.user().isEmpty());
+ ASSERT(m_sameOriginRequest || requestURL.pass().isEmpty());
+
if (m_async) {
// Don't sniff content or send load callbacks for the preflight request.
bool sendLoadCallbacks = m_options.sendLoadCallbacks && !m_actualRequest;
@@ -316,15 +335,15 @@ void DocumentThreadableLoader::loadRequest(const ResourceRequest& request, Secur
// No exception for file:/// resources, see <rdar://problem/4962298>.
// 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) {
+ if (!error.isNull() && !requestURL.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())) {
+ // requested. Also comparing the request and response URLs as strings will fail if the requestURL still has its credentials.
+ if (requestURL != response.url() && !isAllowedRedirect(response.url())) {
m_client->didFailRedirectCheck();
return;
}
diff --git a/WebCore/loader/DocumentThreadableLoader.h b/WebCore/loader/DocumentThreadableLoader.h
index 48d1551..ebf3a25 100644
--- a/WebCore/loader/DocumentThreadableLoader.h
+++ b/WebCore/loader/DocumentThreadableLoader.h
@@ -34,6 +34,7 @@
#include "FrameLoaderTypes.h"
#include "SubresourceLoaderClient.h"
#include "ThreadableLoader.h"
+#include <wtf/Forward.h>
#include <wtf/OwnPtr.h>
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
@@ -84,7 +85,7 @@ namespace WebCore {
void makeSimpleCrossOriginAccessRequest(const ResourceRequest& request);
void makeCrossOriginAccessRequestWithPreflight(const ResourceRequest& request);
void preflightSuccess();
- void preflightFailure();
+ void preflightFailure(const String& url, const String& errorDescription);
void loadRequest(const ResourceRequest&, SecurityCheckPolicy);
bool isAllowedRedirect(const KURL&);
diff --git a/WebCore/loader/DocumentWriter.cpp b/WebCore/loader/DocumentWriter.cpp
new file mode 100644
index 0000000..5b03cd7
--- /dev/null
+++ b/WebCore/loader/DocumentWriter.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2010. 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 "DocumentWriter.h"
+
+#include "DOMImplementation.h"
+#include "DOMWindow.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameLoaderClient.h"
+#include "FrameLoaderStateMachine.h"
+#include "FrameView.h"
+#include "PlaceholderDocument.h"
+#include "PluginDocument.h"
+#include "RawDataDocumentParser.h"
+#include "ScriptableDocumentParser.h"
+#include "SecurityOrigin.h"
+#include "SegmentedString.h"
+#include "Settings.h"
+#include "SinkDocument.h"
+#include "TextResourceDecoder.h"
+
+
+namespace WebCore {
+
+static inline bool canReferToParentFrameEncoding(const Frame* frame, const Frame* parentFrame)
+{
+ return parentFrame && parentFrame->document()->securityOrigin()->canAccess(frame->document()->securityOrigin());
+}
+
+DocumentWriter::DocumentWriter(Frame* frame)
+ : m_frame(frame)
+ , m_receivedData(false)
+ , m_encodingWasChosenByUser(false)
+{
+}
+
+// This is only called by ScriptController::executeIfJavaScriptURL
+// and always contains the result of evaluating a javascript: url.
+// This is the <iframe src="javascript:'html'"> case.
+void DocumentWriter::replaceDocument(const String& source)
+{
+ m_frame->loader()->stopAllLoaders();
+ begin(m_frame->loader()->url(), true, m_frame->document()->securityOrigin());
+
+ if (!source.isNull()) {
+ if (!m_receivedData) {
+ m_receivedData = true;
+ m_frame->document()->setCompatibilityMode(Document::NoQuirksMode);
+ }
+
+ // FIXME: This should call DocumentParser::appendBytes instead of append
+ // to support RawDataDocumentParsers.
+ if (DocumentParser* parser = m_frame->document()->parser())
+ parser->append(source);
+ }
+
+ end();
+}
+
+void DocumentWriter::clear()
+{
+ m_decoder = 0;
+ m_receivedData = false;
+ if (!m_encodingWasChosenByUser)
+ m_encoding = String();
+}
+
+void DocumentWriter::begin()
+{
+ begin(KURL());
+}
+
+PassRefPtr<Document> DocumentWriter::createDocument(const KURL& url)
+{
+ if (!m_frame->loader()->stateMachine()->isDisplayingInitialEmptyDocument() && m_frame->loader()->client()->shouldUsePluginDocument(m_mimeType))
+ return PluginDocument::create(m_frame, url);
+ if (!m_frame->loader()->client()->hasHTMLView())
+ return PlaceholderDocument::create(m_frame, url);
+ return DOMImplementation::createDocument(m_mimeType, m_frame, url, m_frame->inViewSourceMode());
+}
+
+void DocumentWriter::begin(const KURL& url, bool dispatch, SecurityOrigin* origin)
+{
+ // We need to take a reference to the security origin because |clear|
+ // might destroy the document that owns it.
+ RefPtr<SecurityOrigin> forcedSecurityOrigin = origin;
+
+ // Create a new document before clearing the frame, because it may need to
+ // inherit an aliased security context.
+ RefPtr<Document> document = createDocument(url);
+
+ // If the new document is for a Plugin but we're supposed to be sandboxed from Plugins,
+ // then replace the document with one whose parser will ignore the incoming data (bug 39323)
+ if (document->isPluginDocument() && m_frame->loader()->isSandboxed(SandboxPlugins))
+ document = SinkDocument::create(m_frame, url);
+
+ bool resetScripting = !(m_frame->loader()->stateMachine()->isDisplayingInitialEmptyDocument() && m_frame->document()->securityOrigin()->isSecureTransitionTo(url));
+ m_frame->loader()->clear(resetScripting, resetScripting);
+ if (resetScripting)
+ m_frame->script()->updatePlatformScriptObjects();
+
+ m_frame->loader()->setURL(url);
+ m_frame->setDocument(document);
+
+ if (m_decoder)
+ document->setDecoder(m_decoder.get());
+ if (forcedSecurityOrigin)
+ document->setSecurityOrigin(forcedSecurityOrigin.get());
+
+ m_frame->domWindow()->setURL(document->url());
+ m_frame->domWindow()->setSecurityOrigin(document->securityOrigin());
+
+ m_frame->loader()->didBeginDocument(dispatch);
+
+ document->implicitOpen();
+
+ if (m_frame->view() && m_frame->loader()->client()->hasHTMLView())
+ m_frame->view()->setContentsSize(IntSize());
+}
+
+TextResourceDecoder* DocumentWriter::createDecoderIfNeeded()
+{
+ if (!m_decoder) {
+ if (Settings* settings = m_frame->settings()) {
+ m_decoder = TextResourceDecoder::create(m_mimeType,
+ settings->defaultTextEncodingName(),
+ settings->usesEncodingDetector());
+ Frame* parentFrame = m_frame->tree()->parent();
+ // Set the hint encoding to the parent frame encoding only if
+ // the parent and the current frames share the security origin.
+ // We impose this condition because somebody can make a child frame
+ // containing a carefully crafted html/javascript in one encoding
+ // that can be mistaken for hintEncoding (or related encoding) by
+ // an auto detector. When interpreted in the latter, it could be
+ // an attack vector.
+ // FIXME: This might be too cautious for non-7bit-encodings and
+ // we may consider relaxing this later after testing.
+ if (canReferToParentFrameEncoding(m_frame, parentFrame))
+ m_decoder->setHintEncoding(parentFrame->document()->decoder());
+ } else
+ m_decoder = TextResourceDecoder::create(m_mimeType, String());
+ Frame* parentFrame = m_frame->tree()->parent();
+ if (m_encoding.isEmpty()) {
+ if (canReferToParentFrameEncoding(m_frame, parentFrame))
+ m_decoder->setEncoding(parentFrame->document()->inputEncoding(), TextResourceDecoder::EncodingFromParentFrame);
+ } else {
+ m_decoder->setEncoding(m_encoding,
+ m_encodingWasChosenByUser ? TextResourceDecoder::UserChosenEncoding : TextResourceDecoder::EncodingFromHTTPHeader);
+ }
+ m_frame->document()->setDecoder(m_decoder.get());
+ }
+ return m_decoder.get();
+}
+
+void DocumentWriter::reportDataReceived()
+{
+ ASSERT(m_decoder);
+ if (!m_receivedData) {
+ m_receivedData = true;
+ if (m_decoder->encoding().usesVisualOrdering())
+ m_frame->document()->setVisuallyOrdered();
+ m_frame->document()->recalcStyle(Node::Force);
+ }
+}
+
+void DocumentWriter::addData(const char* str, int len, bool flush)
+{
+ if (len == -1)
+ len = strlen(str);
+
+ DocumentParser* parser = m_frame->document()->parser();
+ if (parser)
+ parser->appendBytes(this, str, len, flush);
+}
+
+void DocumentWriter::end()
+{
+ m_frame->loader()->didEndDocument();
+ endIfNotLoadingMainResource();
+}
+
+void DocumentWriter::endIfNotLoadingMainResource()
+{
+ if (m_frame->loader()->isLoadingMainResource() || !m_frame->page() || !m_frame->document())
+ return;
+
+ // http://bugs.webkit.org/show_bug.cgi?id=10854
+ // The frame's last ref may be removed and it can be deleted by checkCompleted(),
+ // so we'll add a protective refcount
+ RefPtr<Frame> protector(m_frame);
+
+ // make sure nothing's left in there
+ addData(0, 0, true);
+ m_frame->document()->finishParsing();
+}
+
+String DocumentWriter::encoding() const
+{
+ if (m_encodingWasChosenByUser && !m_encoding.isEmpty())
+ return m_encoding;
+ if (m_decoder && m_decoder->encoding().isValid())
+ return m_decoder->encoding().name();
+ Settings* settings = m_frame->settings();
+ return settings ? settings->defaultTextEncodingName() : String();
+}
+
+void DocumentWriter::setEncoding(const String& name, bool userChosen)
+{
+ m_frame->loader()->willSetEncoding();
+ m_encoding = name;
+ m_encodingWasChosenByUser = userChosen;
+}
+
+void DocumentWriter::setDecoder(TextResourceDecoder* decoder)
+{
+ m_decoder = decoder;
+}
+
+String DocumentWriter::deprecatedFrameEncoding() const
+{
+ return m_frame->loader()->url().isEmpty() ? m_encoding : encoding();
+}
+
+void DocumentWriter::setDocumentWasLoadedAsPartOfNavigation()
+{
+ m_frame->document()->parser()->setDocumentWasLoadedAsPartOfNavigation();
+}
+
+} // namespace WebCore
diff --git a/WebCore/loader/DocumentWriter.h b/WebCore/loader/DocumentWriter.h
new file mode 100644
index 0000000..5fb3dc1
--- /dev/null
+++ b/WebCore/loader/DocumentWriter.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2010. 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 Adam Barth. ("Adam Barth") 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 DocumentWriter_h
+#define DocumentWriter_h
+
+#include "KURL.h"
+#include "PlatformString.h"
+
+namespace WebCore {
+
+class Document;
+class Frame;
+class SecurityOrigin;
+class TextResourceDecoder;
+
+class DocumentWriter : public Noncopyable {
+public:
+ DocumentWriter(Frame*);
+
+ // This is only called by ScriptController::executeIfJavaScriptURL
+ // and always contains the result of evaluating a javascript: url.
+ void replaceDocument(const String&);
+
+ void begin();
+ void begin(const KURL&, bool dispatchWindowObjectAvailable = true, SecurityOrigin* forcedSecurityOrigin = 0);
+ void addData(const char* string, int length = -1, bool flush = false);
+ void end();
+ void endIfNotLoadingMainResource();
+ void clear();
+
+ String encoding() const;
+ void setEncoding(const String& encoding, bool userChosen);
+
+ // FIXME: It's really unforunate to need to expose this piece of state.
+ // I suspect a better design is to disentangle user-provided encodings,
+ // default encodings, and the decoding we're currently using.
+ String deprecatedFrameEncoding() const;
+
+ const String& mimeType() const { return m_mimeType; }
+ void setMIMEType(const String& type) { m_mimeType = type; }
+
+ void setDecoder(TextResourceDecoder*);
+
+ // Exposed for DoucmentParser::appendBytes
+ TextResourceDecoder* createDecoderIfNeeded();
+ void reportDataReceived();
+
+ void setDocumentWasLoadedAsPartOfNavigation();
+
+private:
+ PassRefPtr<Document> createDocument(const KURL&);
+
+ Frame* m_frame;
+
+ bool m_receivedData;
+ String m_mimeType;
+
+ bool m_encodingWasChosenByUser;
+ String m_encoding;
+ RefPtr<TextResourceDecoder> m_decoder;
+};
+
+} // namespace WebCore
+
+#endif // DocumentWriter_h
diff --git a/WebCore/loader/EmptyClients.h b/WebCore/loader/EmptyClients.h
index 5b24bd3..3a5e0e9 100644
--- a/WebCore/loader/EmptyClients.h
+++ b/WebCore/loader/EmptyClients.h
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2006 Eric Seidel (eric@webkit.org)
- * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,20 +29,23 @@
#define EmptyClients_h
#include "ChromeClient.h"
-#include "ContextMenuClient.h"
#include "Console.h"
+#include "ContextMenuClient.h"
+#include "DeviceMotionClient.h"
+#include "DeviceOrientationClient.h"
#include "DocumentLoader.h"
#include "DragClient.h"
#include "EditCommand.h"
#include "EditorClient.h"
#include "FloatRect.h"
#include "FocusDirection.h"
-#include "FormState.h"
#include "FrameLoaderClient.h"
+#include "FrameNetworkingContext.h"
#include "InspectorClient.h"
#include "PluginHalterClient.h"
+#include "PopupMenu.h"
#include "ResourceError.h"
-#include "SharedBuffer.h"
+#include "SearchPopupMenu.h"
/*
This file holds empty Client stubs for use by WebCore.
@@ -58,6 +62,27 @@
namespace WebCore {
+class SharedGraphicsContext3D;
+
+class EmptyPopupMenu : public PopupMenu {
+public:
+ virtual void show(const IntRect&, FrameView*, int) {}
+ virtual void hide() {}
+ virtual void updateFromElement() {}
+ virtual void disconnectClient() {}
+};
+
+class EmptySearchPopupMenu : public SearchPopupMenu {
+public:
+ virtual PopupMenu* popupMenu() { return m_popup.get(); }
+ virtual void saveRecentSearches(const AtomicString&, const Vector<String>&) {}
+ virtual void loadRecentSearches(const AtomicString&, Vector<String>&) {}
+ virtual bool enabled() { return false; }
+
+private:
+ RefPtr<EmptyPopupMenu> m_popup;
+};
+
class EmptyChromeClient : public ChromeClient {
public:
virtual ~EmptyChromeClient() { }
@@ -70,19 +95,20 @@ public:
virtual float scaleFactor() { return 1.f; }
-#ifdef ANDROID_USER_GESTURE
- virtual void focus(bool userGesture) { }
-#else
- virtual void focus() { }
+#if ENABLE(ANDROID_INSTALLABLE_WEB_APPS)
+ virtual void webAppCanBeInstalled() { }
#endif
+
+ virtual void focus() { }
virtual void unfocus() { }
virtual bool canTakeFocus(FocusDirection) { return false; }
virtual void takeFocus(FocusDirection) { }
virtual void focusedNodeChanged(Node*) { }
+ virtual void focusedFrameChanged(Frame*) { }
- virtual Page* createWindow(Frame*, const FrameLoadRequest&, const WindowFeatures&) { return 0; }
+ virtual Page* createWindow(Frame*, const FrameLoadRequest&, const WindowFeatures&, const NavigationAction&) { return 0; }
virtual void show() { }
virtual bool canRunModal() { return false; }
@@ -114,17 +140,28 @@ public:
virtual bool runJavaScriptPrompt(Frame*, const String&, const String&, String&) { return false; }
virtual bool shouldInterruptJavaScript() { return false; }
+ virtual bool selectItemWritingDirectionIsNatural() { return false; }
+ virtual PassRefPtr<PopupMenu> createPopupMenu(PopupMenuClient*) const { return adoptRef(new EmptyPopupMenu()); }
+ virtual PassRefPtr<SearchPopupMenu> createSearchPopupMenu(PopupMenuClient*) const { return adoptRef(new EmptySearchPopupMenu()); }
+
+#if ENABLE(CONTEXT_MENUS)
+ virtual void showContextMenu() { }
+#endif
+
virtual void setStatusbarText(const String&) { }
virtual bool tabsToLinks() const { return false; }
virtual IntRect windowResizerRect() const { return IntRect(); }
- virtual void addToDirtyRegion(const IntRect&) { }
- virtual void scrollBackingStore(int, int, const IntRect&, const IntRect&) { }
- virtual void updateBackingStore() { }
- virtual void repaint(const IntRect&, bool, bool, bool) { }
+ virtual void invalidateWindow(const IntRect&, bool) { }
+ virtual void invalidateContentsAndWindow(const IntRect&, bool) { }
+ virtual void invalidateContentsForSlowScroll(const IntRect&, bool) {};
virtual void scroll(const IntSize&, const IntRect&, const IntRect&) { }
+#if ENABLE(TILED_BACKING_STORE)
+ virtual void delegatedScrollRequested(const IntSize&) { }
+#endif
+
virtual IntPoint screenToWindow(const IntPoint& p) const { return p; }
virtual IntRect windowToScreen(const IntRect& r) const { return r; }
virtual PlatformPageClient platformPageClient() const { return 0; }
@@ -143,6 +180,7 @@ public:
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
virtual void reachedMaxAppCacheSize(int64_t) { }
+ virtual void reachedApplicationCacheOriginQuota(SecurityOrigin*) { }
#endif
#if ENABLE(NOTIFICATIONS)
@@ -150,6 +188,7 @@ public:
#endif
virtual void runOpenPanel(Frame*, PassRefPtr<FileChooser>) { }
+ virtual void chooseIconForFiles(const Vector<String>&, FileChooser*) { }
virtual void formStateDidChange(const Node*) { }
@@ -158,19 +197,22 @@ public:
virtual PassOwnPtr<HTMLParserQuirks> createHTMLParserQuirks() { return 0; }
- virtual bool setCursor(PlatformCursorHandle) { return false; }
+ virtual void setCursor(const Cursor&) { }
virtual void scrollRectIntoView(const IntRect&, const ScrollView*) const {}
virtual void requestGeolocationPermissionForFrame(Frame*, Geolocation*) {}
- virtual void cancelGeolocationPermissionRequestForFrame(Frame*) {}
+ virtual void cancelGeolocationPermissionRequestForFrame(Frame*, Geolocation*) {}
#if USE(ACCELERATED_COMPOSITING)
- virtual void attachRootGraphicsLayer(Frame*, GraphicsLayer*) {};
- virtual void setNeedsOneShotDrawingSynchronization() {};
- virtual void scheduleCompositingLayerSync() {};
+ virtual void attachRootGraphicsLayer(Frame*, GraphicsLayer*) {}
+ virtual void setNeedsOneShotDrawingSynchronization() {}
+ virtual void scheduleCompositingLayerSync() {}
#endif
+#if PLATFORM(WIN)
+ virtual void setLastSetCursorToCurrentCursor() { }
+#endif
#if ENABLE(TOUCH_EVENTS)
virtual void needTouchEvents(bool) { }
#endif
@@ -199,12 +241,14 @@ public:
virtual void dispatchWillSendRequest(DocumentLoader*, unsigned long, ResourceRequest&, const ResourceResponse&) { }
virtual void dispatchDidReceiveAuthenticationChallenge(DocumentLoader*, unsigned long, const AuthenticationChallenge&) { }
virtual void dispatchDidCancelAuthenticationChallenge(DocumentLoader*, unsigned long, const AuthenticationChallenge&) { }
+#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
+ virtual bool canAuthenticateAgainstProtectionSpace(DocumentLoader*, unsigned long, const ProtectionSpace&) { return false; }
+#endif
virtual void dispatchDidReceiveResponse(DocumentLoader*, unsigned long, const ResourceResponse&) { }
virtual void dispatchDidReceiveContentLength(DocumentLoader*, unsigned long, int) { }
virtual void dispatchDidFinishLoading(DocumentLoader*, unsigned long) { }
virtual void dispatchDidFailLoading(DocumentLoader*, unsigned long, const ResourceError&) { }
virtual bool dispatchDidLoadResourceFromMemoryCache(DocumentLoader*, const ResourceRequest&, const ResourceResponse&, int) { return false; }
- virtual void dispatchDidLoadResourceByXMLHttpRequest(unsigned long, const ScriptString&) { }
virtual void dispatchDidHandleOnloadEvents() { }
virtual void dispatchDidReceiveServerRedirectForProvisionalLoad() { }
@@ -218,6 +262,7 @@ public:
virtual void dispatchDidReceiveIcon() { }
virtual void dispatchDidStartProvisionalLoad() { }
virtual void dispatchDidReceiveTitle(const String&) { }
+ virtual void dispatchDidChangeIcons() { }
virtual void dispatchDidCommitLoad() { }
virtual void dispatchDidFailProvisionalLoad(const ResourceError&) { }
virtual void dispatchDidFailLoad(const ResourceError&) { }
@@ -226,7 +271,7 @@ public:
virtual void dispatchDidFirstLayout() { }
virtual void dispatchDidFirstVisuallyNonEmptyLayout() { }
- virtual Frame* dispatchCreatePage() { return 0; }
+ virtual Frame* dispatchCreatePage(const NavigationAction&) { return 0; }
virtual void dispatchShow() { }
virtual void dispatchDecidePolicyForMIMEType(FramePolicyFunction, const String&, const ResourceRequest&) { }
@@ -236,6 +281,7 @@ public:
virtual void dispatchUnableToImplementPolicy(const ResourceError&) { }
+ virtual void dispatchWillSendSubmitEvent(HTMLFormElement*) { }
virtual void dispatchWillSubmitForm(FramePolicyFunction, PassRefPtr<FormState>) { }
virtual void dispatchDidLoadMainResource(DocumentLoader*) { }
@@ -271,6 +317,7 @@ public:
virtual bool canHandleRequest(const ResourceRequest&) const { return false; }
virtual bool canShowMIMEType(const String&) const { return false; }
+ virtual bool canShowMIMETypeAsHTML(const String&) const { return false; }
virtual bool representationExistsForURLScheme(const String&) const { return false; }
virtual String generatedMIMETypeForURLScheme(const String&) const { return ""; }
@@ -290,6 +337,8 @@ public:
virtual void transitionToCommittedFromCachedFrame(CachedFrame*) { }
virtual void transitionToCommittedForNewPage() { }
+ virtual void dispatchDidBecomeFrameset(bool) { }
+
virtual void updateGlobalHistory() { }
virtual void updateGlobalHistoryRedirectLinks() { }
virtual bool shouldGoToHistoryItem(HistoryItem*) const { return false; }
@@ -301,8 +350,15 @@ public:
virtual void didDisplayInsecureContent() { }
virtual void didRunInsecureContent(SecurityOrigin*) { }
virtual PassRefPtr<Frame> createFrame(const KURL&, const String&, HTMLFrameOwnerElement*, const String&, bool, int, int) { return 0; }
+ virtual void didTransferChildFrameToNewDocument(Page*) { }
+ virtual void transferLoadingResourceFromPage(unsigned long, DocumentLoader*, const ResourceRequest&, Page*) { }
virtual PassRefPtr<Widget> createPlugin(const IntSize&, HTMLPlugInElement*, const KURL&, const Vector<String>&, const Vector<String>&, const String&, bool) { return 0; }
virtual PassRefPtr<Widget> createJavaAppletWidget(const IntSize&, HTMLAppletElement*, const KURL&, const Vector<String>&, const Vector<String>&) { return 0; }
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ virtual PassRefPtr<Widget> createMediaPlayerProxyPlugin(const IntSize&, HTMLMediaElement*, const KURL&, const Vector<String>&, const Vector<String>&, const String&) { return 0; }
+ virtual void hideMediaPlayerProxyPlugin(Widget*) { }
+ virtual void showMediaPlayerProxyPlugin(Widget*) { }
+#endif
virtual ObjectContentType objectContentType(const KURL&, const String&) { return ObjectContentType(); }
virtual String overrideMediaType() const { return String(); }
@@ -312,12 +368,17 @@ public:
virtual void documentElementAvailable() { }
virtual void didPerformFirstNavigation() const { }
- virtual void registerForIconNotification(bool) { }
-
#if USE(V8)
virtual void didCreateScriptContextForFrame() { }
virtual void didDestroyScriptContextForFrame() { }
virtual void didCreateIsolatedScriptContext() { }
+ virtual bool allowScriptExtension(const String& extensionName, int extensionGroup) { return false; }
+#endif
+
+ virtual void registerForIconNotification(bool) { }
+
+#ifdef ANDROID_APPLE_TOUCH_ICON
+ virtual void dispatchDidReceiveTouchIconURL(const String& url, bool precomposed) { }
#endif
#if PLATFORM(MAC)
@@ -327,6 +388,7 @@ public:
virtual bool shouldCacheResponse(DocumentLoader*, unsigned long, const ResourceResponse&, const unsigned char*, unsigned long long) { return true; }
#endif
+ virtual PassRefPtr<FrameNetworkingContext> createNetworkingContext() { return PassRefPtr<FrameNetworkingContext>(); }
};
class EmptyEditorClient : public EditorClient, public Noncopyable {
@@ -393,6 +455,8 @@ public:
virtual void markedTextAbandoned(Frame*) { }
virtual NSString* userVisibleString(NSURL*) { return 0; }
+ virtual DocumentFragment* documentFragmentFromAttributedString(NSAttributedString*, Vector<RefPtr<ArchiveResource> >&) { return 0; };
+ virtual void setInsertionPasteboard(NSPasteboard*) { };
#ifdef BUILDING_ON_TIGER
virtual NSArray* pasteboardTypesForSelection(Frame*) { return 0; }
#endif
@@ -423,11 +487,17 @@ public:
#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
virtual void checkTextOfParagraph(const UChar*, int, uint64_t, Vector<TextCheckingResult>&) { };
#endif
+#if SUPPORT_AUTOCORRECTION_PANEL
+ virtual void showCorrectionPanel(CorrectionPanelInfo::PanelType, const FloatRect&, const String&, const String&, Editor*) { }
+ virtual void dismissCorrectionPanel(CorrectionWasRejectedOrNot) { }
+ virtual bool isShowingCorrectionPanel() { return false; }
+#endif
virtual void updateSpellingUIWithGrammarString(const String&, const GrammarDetail&) { }
virtual void updateSpellingUIWithMisspelledWord(const String&) { }
virtual void showSpellingUI(bool) { }
virtual bool spellingUIIsShowing() { return false; }
virtual void getGuessesForWord(const String&, Vector<String>&) { }
+ virtual void willSetInputMethodState() { }
virtual void setInputMethodState(bool) { }
@@ -475,32 +545,35 @@ public:
virtual ~EmptyInspectorClient() { }
virtual void inspectorDestroyed() { }
-
- virtual Page* createPage() { return 0; };
-
- virtual String localizedStringsURL() { return String(); }
-
- virtual String hiddenPanels() { return String(); }
-
- virtual void showWindow() { }
- virtual void closeWindow() { }
-
- virtual void attachWindow() { }
- virtual void detachWindow() { }
-
- virtual void setAttachedWindowHeight(unsigned) { }
+
+ virtual void openInspectorFrontend(InspectorController*) { }
virtual void highlight(Node*) { }
virtual void hideHighlight() { }
- virtual void inspectedURLChanged(const String&) { }
virtual void populateSetting(const String&, String*) { }
virtual void storeSetting(const String&, const String&) { }
+ virtual bool sendMessageToFrontend(const String&) { return false; }
+};
- virtual void inspectorWindowObjectCleared() { }
+class EmptyDeviceMotionClient : public DeviceMotionClient {
+public:
+ virtual void setController(DeviceMotionController*) { }
+ virtual void startUpdating() { }
+ virtual void stopUpdating() { }
+ virtual DeviceMotionData* currentDeviceMotion() const { return 0; }
+ virtual void deviceMotionControllerDestroyed() { }
+};
+
+class EmptyDeviceOrientationClient : public DeviceOrientationClient {
+public:
+ virtual void setController(DeviceOrientationController*) { }
+ virtual void startUpdating() { }
+ virtual void stopUpdating() { }
+ virtual DeviceOrientation* lastOrientation() const { return 0; }
+ virtual void deviceOrientationControllerDestroyed() { }
};
}
#endif // EmptyClients_h
-
diff --git a/WebCore/loader/FTPDirectoryDocument.cpp b/WebCore/loader/FTPDirectoryDocument.cpp
deleted file mode 100644
index 62173f5..0000000
--- a/WebCore/loader/FTPDirectoryDocument.cpp
+++ /dev/null
@@ -1,452 +0,0 @@
-/*
- * Copyright (C) 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * 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"
-#if ENABLE(FTPDIR)
-#include "FTPDirectoryDocument.h"
-
-#include "CharacterNames.h"
-#include "CString.h"
-#include "HTMLNames.h"
-#include "HTMLTableElement.h"
-#include "HTMLTokenizer.h"
-#include "LocalizedStrings.h"
-#include "Logging.h"
-#include "FTPDirectoryParser.h"
-#include "SegmentedString.h"
-#include "Settings.h"
-#include "SharedBuffer.h"
-#include "Text.h"
-
-#include <wtf/CurrentTime.h>
-#include <wtf/StdLibExtras.h>
-
-using namespace std;
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-class FTPDirectoryTokenizer : public HTMLTokenizer {
-public:
- FTPDirectoryTokenizer(HTMLDocument*);
-
- virtual void write(const SegmentedString&, bool appendData);
- virtual void finish();
-
- virtual bool isWaitingForScripts() const { return false; }
-
- inline void checkBuffer(int len = 10)
- {
- if ((m_dest - m_buffer) > m_size - len) {
- // Enlarge buffer
- int newSize = max(m_size * 2, m_size + len);
- int oldOffset = m_dest - m_buffer;
- m_buffer = static_cast<UChar*>(fastRealloc(m_buffer, newSize * sizeof(UChar)));
- m_dest = m_buffer + oldOffset;
- m_size = newSize;
- }
- }
-
-private:
- // The tokenizer will attempt to load the document template specified via the preference
- // Failing that, it will fall back and create the basic document which will have a minimal
- // table for presenting the FTP directory in a useful manner
- bool loadDocumentTemplate();
- void createBasicDocument();
-
- void parseAndAppendOneLine(const String&);
- void appendEntry(const String& name, const String& size, const String& date, bool isDirectory);
- PassRefPtr<Element> createTDForFilename(const String&);
-
- Document* m_doc;
- RefPtr<HTMLTableElement> m_tableElement;
-
- bool m_skipLF;
- bool m_parsedTemplate;
-
- int m_size;
- UChar* m_buffer;
- UChar* m_dest;
- String m_carryOver;
-
- ListState m_listState;
-};
-
-FTPDirectoryTokenizer::FTPDirectoryTokenizer(HTMLDocument* doc)
- : HTMLTokenizer(doc, false)
- , m_doc(doc)
- , m_skipLF(false)
- , m_parsedTemplate(false)
- , m_size(254)
- , m_buffer(static_cast<UChar*>(fastMalloc(sizeof(UChar) * m_size)))
- , m_dest(m_buffer)
-{
-}
-
-void FTPDirectoryTokenizer::appendEntry(const String& filename, const String& size, const String& date, bool isDirectory)
-{
- ExceptionCode ec;
-
- RefPtr<Element> rowElement = m_tableElement->insertRow(-1, ec);
- rowElement->setAttribute("class", "ftpDirectoryEntryRow", ec);
-
- RefPtr<Element> element = m_doc->createElement(tdTag, false);
- element->appendChild(Text::create(m_doc, String(&noBreakSpace, 1)), ec);
- if (isDirectory)
- element->setAttribute("class", "ftpDirectoryIcon ftpDirectoryTypeDirectory", ec);
- else
- element->setAttribute("class", "ftpDirectoryIcon ftpDirectoryTypeFile", ec);
- rowElement->appendChild(element, ec);
-
- element = createTDForFilename(filename);
- element->setAttribute("class", "ftpDirectoryFileName", ec);
- rowElement->appendChild(element, ec);
-
- element = m_doc->createElement(tdTag, false);
- 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(Text::create(m_doc, size), ec);
- element->setAttribute("class", "ftpDirectoryFileSize", ec);
- rowElement->appendChild(element, ec);
-}
-
-PassRefPtr<Element> FTPDirectoryTokenizer::createTDForFilename(const String& filename)
-{
- ExceptionCode ec;
-
- String fullURL = m_doc->baseURL().string();
- if (fullURL[fullURL.length() - 1] == '/')
- fullURL.append(filename);
- else
- fullURL.append("/" + filename);
-
- RefPtr<Element> anchorElement = m_doc->createElement(aTag, false);
- anchorElement->setAttribute("href", fullURL, ec);
- anchorElement->appendChild(Text::create(m_doc, filename), ec);
-
- RefPtr<Element> tdElement = m_doc->createElement(tdTag, false);
- tdElement->appendChild(anchorElement, ec);
-
- return tdElement.release();
-}
-
-static String processFilesizeString(const String& size, bool isDirectory)
-{
- if (isDirectory)
- return "--";
-
- bool valid;
- int64_t bytes = size.toUInt64(&valid);
- if (!valid)
- return unknownFileSizeText();
-
- if (bytes < 1000000)
- return String::format("%.2f KB", static_cast<float>(bytes)/1000);
-
- if (bytes < 1000000000)
- return String::format("%.2f MB", static_cast<float>(bytes)/1000000);
-
- return String::format("%.2f GB", static_cast<float>(bytes)/1000000000);
-}
-
-static bool wasLastDayOfMonth(int year, int month, int day)
-{
- static int lastDays[] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
- if (month < 0 || month > 11)
- return false;
-
- if (month == 2) {
- if (year % 4 == 0 && (year % 100 || year % 400 == 0)) {
- if (day == 29)
- return true;
- return false;
- }
-
- if (day == 28)
- return true;
- return false;
- }
-
- return lastDays[month] == day;
-}
-
-static String processFileDateString(const FTPTime& fileTime)
-{
- // FIXME: Need to localize this string?
-
- String timeOfDay;
-
- if (!(fileTime.tm_hour == 0 && fileTime.tm_min == 0 && fileTime.tm_sec == 0)) {
- int hour = fileTime.tm_hour;
- ASSERT(hour >= 0 && hour < 24);
-
- if (hour < 12) {
- if (hour == 0)
- hour = 12;
- timeOfDay = String::format(", %i:%02i AM", hour, fileTime.tm_min);
- } else {
- hour = hour - 12;
- if (hour == 0)
- hour = 12;
- timeOfDay = String::format(", %i:%02i PM", hour, fileTime.tm_min);
- }
- }
-
- // If it was today or yesterday, lets just do that - but we have to compare to the current time
- struct tm now;
- time_t now_t = time(NULL);
- getLocalTime(&now_t, &now);
-
- // localtime does "year = current year - 1900", compensate for that for readability and comparison purposes
- now.tm_year += 1900;
-
- if (fileTime.tm_year == now.tm_year) {
- if (fileTime.tm_mon == now.tm_mon) {
- if (fileTime.tm_mday == now.tm_mday)
- return "Today" + timeOfDay;
- if (fileTime.tm_mday == now.tm_mday - 1)
- return "Yesterday" + timeOfDay;
- }
-
- if (now.tm_mday == 1 && (now.tm_mon == fileTime.tm_mon + 1 || (now.tm_mon == 0 && fileTime.tm_mon == 11)) &&
- wasLastDayOfMonth(fileTime.tm_year, fileTime.tm_mon, fileTime.tm_mday))
- return "Yesterday" + timeOfDay;
- }
-
- if (fileTime.tm_year == now.tm_year - 1 && fileTime.tm_mon == 12 && fileTime.tm_mday == 31 && now.tm_mon == 1 && now.tm_mday == 1)
- return "Yesterday" + timeOfDay;
-
- static const char* months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "???" };
-
- int month = fileTime.tm_mon;
- if (month < 0 || month > 11)
- month = 12;
-
- String dateString;
-
- if (fileTime.tm_year > -1)
- dateString = String::format("%s %i, %i", months[month], fileTime.tm_mday, fileTime.tm_year);
- else
- dateString = String::format("%s %i, %i", months[month], fileTime.tm_mday, now.tm_year);
-
- return dateString + timeOfDay;
-}
-
-void FTPDirectoryTokenizer::parseAndAppendOneLine(const String& inputLine)
-{
- ListResult result;
- CString latin1Input = inputLine.latin1();
-
- FTPEntryType typeResult = parseOneFTPLine(latin1Input.data(), m_listState, result);
-
- // FTPMiscEntry is a comment or usage statistic which we don't care about, and junk is invalid data - bail in these 2 cases
- if (typeResult == FTPMiscEntry || typeResult == FTPJunkEntry)
- return;
-
- String filename(result.filename, result.filenameLength);
- if (result.type == FTPDirectoryEntry) {
- filename.append("/");
-
- // We have no interest in linking to "current directory"
- if (filename == "./")
- return;
- }
-
- LOG(FTP, "Appending entry - %s, %s", filename.ascii().data(), result.fileSize.ascii().data());
-
- appendEntry(filename, processFilesizeString(result.fileSize, result.type == FTPDirectoryEntry), processFileDateString(result.modifiedTime), result.type == FTPDirectoryEntry);
-}
-
-static inline PassRefPtr<SharedBuffer> createTemplateDocumentData(Settings* settings)
-{
- RefPtr<SharedBuffer> buffer = 0;
- if (settings)
- buffer = SharedBuffer::createWithContentsOfFile(settings->ftpDirectoryTemplatePath());
- if (buffer)
- LOG(FTP, "Loaded FTPDirectoryTemplate of length %i\n", buffer->size());
- return buffer.release();
-}
-
-bool FTPDirectoryTokenizer::loadDocumentTemplate()
-{
- DEFINE_STATIC_LOCAL(RefPtr<SharedBuffer>, templateDocumentData, (createTemplateDocumentData(m_doc->settings())));
- // FIXME: Instead of storing the data, we'd rather actually parse the template data into the template Document once,
- // store that document, then "copy" it whenever we get an FTP directory listing. There are complexities with this
- // approach that make it worth putting this off.
-
- if (!templateDocumentData) {
- LOG_ERROR("Could not load templateData");
- return false;
- }
-
- // Tokenize the template as an HTML document synchronously
- setForceSynchronous(true);
- HTMLTokenizer::write(String(templateDocumentData->data(), templateDocumentData->size()), true);
- setForceSynchronous(false);
-
- RefPtr<Element> tableElement = m_doc->getElementById("ftpDirectoryTable");
- if (!tableElement)
- LOG_ERROR("Unable to find element by id \"ftpDirectoryTable\" in the template document.");
- else if (!tableElement->hasTagName(tableTag))
- LOG_ERROR("Element of id \"ftpDirectoryTable\" is not a table element");
- else
- m_tableElement = static_cast<HTMLTableElement*>(tableElement.get());
-
- // Bail if we found the table element
- if (m_tableElement)
- return true;
-
- // Otherwise create one manually
- tableElement = m_doc->createElement(tableTag, false);
- m_tableElement = static_cast<HTMLTableElement*>(tableElement.get());
- ExceptionCode ec;
- m_tableElement->setAttribute("id", "ftpDirectoryTable", ec);
-
- // If we didn't find the table element, lets try to append our own to the body
- // If that fails for some reason, cram it on the end of the document as a last
- // ditch effort
- if (Element* body = m_doc->body())
- body->appendChild(m_tableElement, ec);
- else
- m_doc->appendChild(m_tableElement, ec);
-
- return true;
-}
-
-void FTPDirectoryTokenizer::createBasicDocument()
-{
- LOG(FTP, "Creating a basic FTP document structure as no template was loaded");
-
- // FIXME: Make this "basic document" more acceptable
-
-
- RefPtr<Element> bodyElement = m_doc->createElement(bodyTag, false);
-
- ExceptionCode ec;
- m_doc->appendChild(bodyElement, ec);
-
- RefPtr<Element> tableElement = m_doc->createElement(tableTag, false);
- m_tableElement = static_cast<HTMLTableElement*>(tableElement.get());
- m_tableElement->setAttribute("id", "ftpDirectoryTable", ec);
-
- bodyElement->appendChild(m_tableElement, ec);
-}
-
-void FTPDirectoryTokenizer::write(const SegmentedString& s, bool /*appendData*/)
-{
- // Make sure we have the table element to append to by loading the template set in the pref, or
- // creating a very basic document with the appropriate table
- if (!m_tableElement) {
- if (!loadDocumentTemplate())
- createBasicDocument();
- ASSERT(m_tableElement);
- }
-
- bool foundNewLine = false;
-
- m_dest = m_buffer;
- SegmentedString str = s;
- while (!str.isEmpty()) {
- UChar c = *str;
-
- if (c == '\r') {
- *m_dest++ = '\n';
- foundNewLine = true;
- // possibly skip an LF in the case of an CRLF sequence
- m_skipLF = true;
- } else if (c == '\n') {
- if (!m_skipLF)
- *m_dest++ = c;
- else
- m_skipLF = false;
- } else {
- *m_dest++ = c;
- m_skipLF = false;
- }
-
- str.advance();
-
- // Maybe enlarge the buffer
- checkBuffer();
- }
-
- if (!foundNewLine) {
- m_dest = m_buffer;
- return;
- }
-
- UChar* start = m_buffer;
- UChar* cursor = start;
-
- while (cursor < m_dest) {
- if (*cursor == '\n') {
- m_carryOver.append(String(start, cursor - start));
- LOG(FTP, "%s", m_carryOver.ascii().data());
- parseAndAppendOneLine(m_carryOver);
- m_carryOver = String();
-
- start = ++cursor;
- } else
- cursor++;
- }
-
- // Copy the partial line we have left to the carryover buffer
- if (cursor - start > 1)
- m_carryOver.append(String(start, cursor - start - 1));
-}
-
-void FTPDirectoryTokenizer::finish()
-{
- // Possible the last line in the listing had no newline, so try to parse it now
- if (!m_carryOver.isEmpty()) {
- parseAndAppendOneLine(m_carryOver);
- m_carryOver = String();
- }
-
- m_tableElement = 0;
- fastFree(m_buffer);
-
- HTMLTokenizer::finish();
-}
-
-FTPDirectoryDocument::FTPDirectoryDocument(Frame* frame)
- : HTMLDocument(frame)
-{
-#ifndef NDEBUG
- LogFTP.state = WTFLogChannelOn;
-#endif
-}
-
-Tokenizer* FTPDirectoryDocument::createTokenizer()
-{
- return new FTPDirectoryTokenizer(this);
-}
-
-}
-
-#endif // ENABLE(FTPDIR)
diff --git a/WebCore/loader/FTPDirectoryParser.cpp b/WebCore/loader/FTPDirectoryParser.cpp
index 142f2a3..f6a74de 100644
--- a/WebCore/loader/FTPDirectoryParser.cpp
+++ b/WebCore/loader/FTPDirectoryParser.cpp
@@ -188,9 +188,13 @@ FTPEntryType parseOneFTPLine(const char* line, ListState& state, ListResult& res
if (pos < linelen && line[pos] == ',')
{
unsigned long long seconds = 0;
+#if OS(WINDOWS)
+ sscanf(p + 1, "%I64u", &seconds);
+#else
sscanf(p + 1, "%llu", &seconds);
+#endif
time_t t = static_cast<time_t>(seconds);
-
+
// FIXME: This code has the year 2038 bug
gmtime_r(&t, &result.modifiedTime);
result.modifiedTime.tm_year += 1900;
diff --git a/WebCore/loader/FormSubmission.cpp b/WebCore/loader/FormSubmission.cpp
new file mode 100644
index 0000000..f3f19d2
--- /dev/null
+++ b/WebCore/loader/FormSubmission.cpp
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FormSubmission.h"
+
+#include "DOMFormData.h"
+#include "Document.h"
+#include "Event.h"
+#include "FormData.h"
+#include "FormDataBuilder.h"
+#include "FormState.h"
+#include "Frame.h"
+#include "FrameLoadRequest.h"
+#include "FrameLoader.h"
+#include "HTMLFormControlElement.h"
+#include "HTMLFormElement.h"
+#include "HTMLInputElement.h"
+#include "HTMLNames.h"
+#include "HTMLParserIdioms.h"
+#include "TextEncoding.h"
+#include <wtf/CurrentTime.h>
+#include <wtf/RandomNumber.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+static int64_t generateFormDataIdentifier()
+{
+ // Initialize to the current time to reduce the likelihood of generating
+ // identifiers that overlap with those from past/future browser sessions.
+ static int64_t nextIdentifier = static_cast<int64_t>(currentTime() * 1000000.0);
+ return ++nextIdentifier;
+}
+
+static void appendMailtoPostFormDataToURL(KURL& url, const FormData& data, const String& encodingType)
+{
+ String body = data.flattenToString();
+
+ if (equalIgnoringCase(encodingType, "text/plain")) {
+ // Convention seems to be to decode, and s/&/\r\n/. Also, spaces are encoded as %20.
+ body = decodeURLEscapeSequences(body.replace('&', "\r\n").replace('+', ' ') + "\r\n");
+ }
+
+ Vector<char> bodyData;
+ bodyData.append("body=", 5);
+ FormDataBuilder::encodeStringAsFormData(bodyData, body.utf8());
+ body = String(bodyData.data(), bodyData.size()).replace('+', "%20");
+
+ String query = url.query();
+ if (!query.isEmpty())
+ query.append('&');
+ query.append(body);
+ url.setQuery(query);
+}
+
+void FormSubmission::Attributes::parseAction(const String& action)
+{
+ // FIXME: Can we parse into a KURL?
+ m_action = stripLeadingAndTrailingHTMLSpaces(action);
+}
+
+void FormSubmission::Attributes::parseEncodingType(const String& type)
+{
+ if (type.contains("multipart", false) || type.contains("form-data", false)) {
+ m_encodingType = "multipart/form-data";
+ m_isMultiPartForm = true;
+ } else if (type.contains("text", false) || type.contains("plain", false)) {
+ m_encodingType = "text/plain";
+ m_isMultiPartForm = false;
+ } else {
+ m_encodingType = "application/x-www-form-urlencoded";
+ m_isMultiPartForm = false;
+ }
+}
+
+void FormSubmission::Attributes::parseMethodType(const String& type)
+{
+ if (equalIgnoringCase(type, "post"))
+ m_method = FormSubmission::PostMethod;
+ else if (equalIgnoringCase(type, "get"))
+ m_method = FormSubmission::GetMethod;
+}
+
+inline FormSubmission::FormSubmission(Method method, const KURL& action, const String& target, const String& contentType, PassRefPtr<FormState> state, PassRefPtr<FormData> data, const String& boundary, bool lockHistory, PassRefPtr<Event> event)
+ : m_method(method)
+ , m_action(action)
+ , m_target(target)
+ , m_contentType(contentType)
+ , m_formState(state)
+ , m_formData(data)
+ , m_boundary(boundary)
+ , m_lockHistory(lockHistory)
+ , m_event(event)
+{
+}
+
+PassRefPtr<FormSubmission> FormSubmission::create(HTMLFormElement* form, const Attributes& attributes, PassRefPtr<Event> event, bool lockHistory, FormSubmissionTrigger trigger)
+{
+ ASSERT(form);
+ Document* document = form->document();
+ KURL actionURL = document->completeURL(attributes.action().isEmpty() ? document->url().string() : attributes.action());
+ bool isMailtoForm = actionURL.protocolIs("mailto");
+ bool isMultiPartForm = false;
+ String encodingType = attributes.encodingType();
+
+ if (attributes.method() == PostMethod) {
+ isMultiPartForm = attributes.isMultiPartForm();
+ if (isMultiPartForm && isMailtoForm) {
+ encodingType = "application/x-www-form-urlencoded";
+ isMultiPartForm = false;
+ }
+ }
+
+ TextEncoding dataEncoding = isMailtoForm ? UTF8Encoding() : FormDataBuilder::encodingFromAcceptCharset(attributes.acceptCharset(), document);
+ RefPtr<DOMFormData> domFormData = DOMFormData::create(dataEncoding.encodingForFormSubmission());
+ Vector<pair<String, String> > formValues;
+
+ for (unsigned i = 0; i < form->associatedElements().size(); ++i) {
+ HTMLFormControlElement* control = form->associatedElements()[i];
+ if (!control->disabled())
+ control->appendFormData(*domFormData, isMultiPartForm);
+ if (control->hasLocalName(inputTag)) {
+ HTMLInputElement* input = static_cast<HTMLInputElement*>(control);
+ if (input->isTextField()) {
+ formValues.append(pair<String, String>(input->name(), input->value()));
+ if (input->isSearchField())
+ input->addSearchResult();
+ }
+ }
+ }
+
+ RefPtr<FormData> formData;
+ String boundary;
+
+ if (isMultiPartForm) {
+ formData = FormData::createMultiPart(*(static_cast<FormDataList*>(domFormData.get())), domFormData->encoding(), document);
+ boundary = formData->boundary().data();
+ } else {
+ formData = FormData::create(*(static_cast<FormDataList*>(domFormData.get())), domFormData->encoding());
+ if (attributes.method() == PostMethod && isMailtoForm) {
+ // Convert the form data into a string that we put into the URL.
+ appendMailtoPostFormDataToURL(actionURL, *formData, encodingType);
+ formData = FormData::create();
+ }
+ }
+
+ formData->setIdentifier(generateFormDataIdentifier());
+ String targetOrBaseTarget = attributes.target().isEmpty() ? document->baseTarget() : attributes.target();
+ RefPtr<FormState> formState = FormState::create(form, formValues, document->frame(), trigger);
+ return adoptRef(new FormSubmission(attributes.method(), actionURL, targetOrBaseTarget, encodingType, formState.release(), formData.release(), boundary, lockHistory, event));
+}
+
+KURL FormSubmission::requestURL() const
+{
+ if (m_method == FormSubmission::PostMethod)
+ return m_action;
+
+ KURL requestURL(m_action);
+ requestURL.setQuery(m_formData->flattenToString());
+ return requestURL;
+}
+
+void FormSubmission::populateFrameLoadRequest(FrameLoadRequest& frameRequest)
+{
+ if (!m_target.isEmpty())
+ frameRequest.setFrameName(m_target);
+
+ if (!m_referrer.isEmpty())
+ frameRequest.resourceRequest().setHTTPReferrer(m_referrer);
+
+ if (m_method == FormSubmission::PostMethod) {
+ frameRequest.resourceRequest().setHTTPMethod("POST");
+ frameRequest.resourceRequest().setHTTPBody(m_formData);
+
+ // construct some user headers if necessary
+ if (m_contentType.isNull() || m_contentType == "application/x-www-form-urlencoded")
+ frameRequest.resourceRequest().setHTTPContentType(m_contentType);
+ else // contentType must be "multipart/form-data"
+ frameRequest.resourceRequest().setHTTPContentType(m_contentType + "; boundary=" + m_boundary);
+ }
+
+ frameRequest.resourceRequest().setURL(requestURL());
+ FrameLoader::addHTTPOriginIfNeeded(frameRequest.resourceRequest(), m_origin);
+}
+
+}
diff --git a/WebCore/loader/FormSubmission.h b/WebCore/loader/FormSubmission.h
new file mode 100644
index 0000000..b935882
--- /dev/null
+++ b/WebCore/loader/FormSubmission.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FormSubmission_h
+#define FormSubmission_h
+
+#include "FormState.h"
+#include "KURL.h"
+
+namespace WebCore {
+
+class Document;
+class Event;
+class FormData;
+struct FrameLoadRequest;
+class HTMLFormElement;
+class TextEncoding;
+
+class FormSubmission : public RefCounted<FormSubmission> {
+public:
+ enum Method { GetMethod, PostMethod };
+
+ class Attributes : public Noncopyable {
+ public:
+ Attributes()
+ : m_method(GetMethod)
+ , m_isMultiPartForm(false)
+ , m_encodingType("application/x-www-form-urlencoded")
+ {
+ }
+
+ Method method() const { return m_method; }
+ void parseMethodType(const String&);
+
+ const String& action() const { return m_action; }
+ void parseAction(const String&);
+
+ const String& target() const { return m_target; }
+ void setTarget(const String& target) { m_target = target; }
+
+ const String& encodingType() const { return m_encodingType; }
+ void parseEncodingType(const String&);
+ bool isMultiPartForm() const { return m_isMultiPartForm; }
+
+ const String& acceptCharset() const { return m_acceptCharset; }
+ void setAcceptCharset(const String& value) { m_acceptCharset = value; }
+
+ private:
+ Method m_method;
+ bool m_isMultiPartForm;
+
+ String m_action;
+ String m_target;
+ String m_encodingType;
+ String m_acceptCharset;
+ };
+
+ static PassRefPtr<FormSubmission> create(HTMLFormElement*, const Attributes&, PassRefPtr<Event> event, bool lockHistory, FormSubmissionTrigger);
+
+ void populateFrameLoadRequest(FrameLoadRequest&);
+
+ KURL requestURL() const;
+
+ Method method() const { return m_method; }
+ const KURL& action() const { return m_action; }
+ const String& target() const { return m_target; }
+ void clearTarget() { m_target = String(); }
+ const String& contentType() const { return m_contentType; }
+ FormState* state() const { return m_formState.get(); }
+ FormData* data() const { return m_formData.get(); }
+ const String boundary() const { return m_boundary; }
+ bool lockHistory() const { return m_lockHistory; }
+ Event* event() const { return m_event.get(); }
+
+ const String& referrer() const { return m_referrer; }
+ void setReferrer(const String& referrer) { m_referrer = referrer; }
+ const String& origin() const { return m_origin; }
+ void setOrigin(const String& origin) { m_origin = origin; }
+
+private:
+ FormSubmission(Method, const KURL& action, const String& target, const String& contentType, PassRefPtr<FormState>, PassRefPtr<FormData>, const String& boundary, bool lockHistory, PassRefPtr<Event>);
+
+ // FIXME: Hold an instance of Attributes instead of individual members.
+ Method m_method;
+ KURL m_action;
+ String m_target;
+ String m_contentType;
+ RefPtr<FormState> m_formState;
+ RefPtr<FormData> m_formData;
+ String m_boundary;
+ bool m_lockHistory;
+ RefPtr<Event> m_event;
+ String m_referrer;
+ String m_origin;
+};
+
+}
+
+#endif // FormSubmission_h
diff --git a/WebCore/loader/FrameLoader.cpp b/WebCore/loader/FrameLoader.cpp
index 514f98a..8277338 100644
--- a/WebCore/loader/FrameLoader.cpp
+++ b/WebCore/loader/FrameLoader.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010 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) 2008 Alp Toker <alp@atoker.com>
@@ -38,15 +38,16 @@
#include "Archive.h"
#include "ArchiveFactory.h"
#endif
-#include "BackForwardList.h"
-#include "CString.h"
-#include "Cache.h"
+#include "BackForwardController.h"
+#include "BeforeUnloadEvent.h"
+#include "MemoryCache.h"
#include "CachedPage.h"
+#include "CachedResourceLoader.h"
#include "Chrome.h"
#include "DOMImplementation.h"
#include "DOMWindow.h"
-#include "DocLoader.h"
#include "Document.h"
+#include "DocumentLoadTiming.h"
#include "DocumentLoader.h"
#include "Editor.h"
#include "EditorClient.h"
@@ -55,15 +56,15 @@
#include "EventNames.h"
#include "FloatRect.h"
#include "FormState.h"
+#include "FormSubmission.h"
#include "Frame.h"
#include "FrameLoadRequest.h"
#include "FrameLoaderClient.h"
+#include "FrameNetworkingContext.h"
#include "FrameTree.h"
#include "FrameView.h"
#include "HTMLAnchorElement.h"
-#include "HTMLAppletElement.h"
#include "HTMLFormElement.h"
-#include "HTMLFrameElement.h"
#include "HTMLNames.h"
#include "HTMLObjectElement.h"
#include "HTTPParsers.h"
@@ -78,36 +79,34 @@
#include "PageCache.h"
#include "PageGroup.h"
#include "PageTransitionEvent.h"
-#include "PlaceholderDocument.h"
#include "PluginData.h"
#include "PluginDatabase.h"
#include "PluginDocument.h"
#include "ProgressTracker.h"
-#include "RenderPart.h"
-#include "RenderView.h"
-#include "RenderWidget.h"
#include "ResourceHandle.h"
#include "ResourceRequest.h"
+#include "SchemeRegistry.h"
#include "ScriptController.h"
#include "ScriptSourceCode.h"
-#include "ScriptString.h"
-#include "ScriptValue.h"
#include "SecurityOrigin.h"
#include "SegmentedString.h"
+#include "SerializedScriptValue.h"
#include "Settings.h"
-
-#if ENABLE(SHARED_WORKERS)
-#include "SharedWorkerRepository.h"
-#endif
-
#include "TextResourceDecoder.h"
#include "WindowFeatures.h"
-#include "XMLHttpRequest.h"
-#include "XMLTokenizer.h"
-#include "XSSAuditor.h"
+#include "XMLDocumentParser.h"
#include <wtf/CurrentTime.h>
#include <wtf/StdLibExtras.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/StringConcatenate.h>
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+#include "HTMLMediaElement.h"
+#endif
+
+#if ENABLE(SHARED_WORKERS)
+#include "SharedWorkerRepository.h"
+#endif
#if ENABLE(SVG)
#include "SVGDocument.h"
@@ -126,16 +125,18 @@
namespace WebCore {
+using namespace HTMLNames;
+
#if ENABLE(SVG)
using namespace SVGNames;
#endif
-using namespace HTMLNames;
#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;
bool isBackForwardLoadType(FrameLoadType type)
@@ -163,12 +164,19 @@ static int numRequests(Document* document)
if (!document)
return 0;
- return document->docLoader()->requestCount();
+ return document->cachedResourceLoader()->requestCount();
}
-static inline bool canReferToParentFrameEncoding(const Frame* frame, const Frame* parentFrame)
+// This is not in the FrameLoader class to emphasize that it does not depend on
+// private FrameLoader data, and to avoid increasing the number of public functions
+// with access to private data. Since only this .cpp file needs it, making it
+// non-member lets us exclude it from the header file, thus keeping FrameLoader.h's
+// API simpler.
+//
+// FIXME: isDocumentSandboxed should eventually replace isSandboxed.
+static bool isDocumentSandboxed(Frame* frame, SandboxFlags mask)
{
- return parentFrame && parentFrame->document()->securityOrigin()->canAccess(frame->document()->securityOrigin());
+ return frame->document() && frame->document()->securityOrigin()->isSandboxed(mask);
}
FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client)
@@ -177,34 +185,30 @@ FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client)
, m_policyChecker(frame)
, m_history(frame)
, m_notifer(frame)
+ , m_writer(frame)
+ , m_subframeLoader(frame)
, m_state(FrameStateCommittedPage)
, m_loadType(FrameLoadTypeStandard)
, m_delegateIsHandlingProvisionalLoadError(false)
- , m_firstLayoutDone(false)
, m_quickRedirectComing(false)
, m_sentRedirectNotification(false)
, m_inStopAllLoaders(false)
, m_isExecutingJavaScriptFormAction(false)
, m_didCallImplicitClose(false)
, m_wasUnloadEventEmitted(false)
- , m_unloadEventBeingDispatched(false)
+ , m_pageDismissalEventBeingDispatched(false)
, m_isComplete(false)
, m_isLoadingMainResource(false)
, m_needsClear(false)
- , m_receivedData(false)
- , m_encodingWasChosenByUser(false)
- , m_containsPlugIns(false)
, m_checkTimer(this, &FrameLoader::checkTimerFired)
, m_shouldCallCheckCompleted(false)
, m_shouldCallCheckLoadComplete(false)
, m_opener(0)
- , m_creatingInitialEmptyDocument(false)
- , m_isDisplayingInitialEmptyDocument(false)
- , m_committedFirstRealDocumentLoad(false)
, m_didPerformFirstNavigation(false)
, m_loadingFromCachedPage(false)
, m_suppressOpenerInNewFrame(false)
, m_sandboxFlags(SandboxAll)
+ , m_forcedSandboxFlags(SandboxNone)
#ifndef NDEBUG
, m_didDispatchDidCommitLoad(false)
#endif
@@ -220,26 +224,31 @@ FrameLoader::~FrameLoader()
(*it)->loader()->m_opener = 0;
m_client->frameLoaderDestroyed();
+
+ if (m_networkingContext)
+ m_networkingContext->invalidate();
}
void FrameLoader::init()
{
+ // Propagate sandbox attributes to this Frameloader and its descendants.
+ // This needs to be done early, so that an initial document gets correct sandbox flags in its SecurityOrigin.
+ updateSandboxFlags();
+
// this somewhat odd set of steps is needed to give the frame an initial empty document
- m_isDisplayingInitialEmptyDocument = false;
- m_creatingInitialEmptyDocument = true;
+ m_stateMachine.advanceTo(FrameLoaderStateMachine::CreatingInitialEmptyDocument);
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()));
m_provisionalDocumentLoader->finishedLoading();
- begin(KURL(), false);
- end();
+ writer()->begin(KURL(), false);
+ writer()->end();
m_frame->document()->cancelParsing();
- m_creatingInitialEmptyDocument = false;
+ m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocument);
m_didCallImplicitClose = true;
- // Propagate sandbox attributes to this Frameloader and its descendants.
- updateSandboxFlags();
+ m_networkingContext = m_client->createNetworkingContext();
}
void FrameLoader::setDefersLoading(bool defers)
@@ -252,101 +261,37 @@ void FrameLoader::setDefersLoading(bool defers)
m_policyDocumentLoader->setDefersLoading(defers);
if (!defers) {
- m_frame->redirectScheduler()->startTimer();
+ m_frame->navigationScheduler()->startTimer();
startCheckCompleteTimer();
}
}
-Frame* FrameLoader::createWindow(FrameLoader* frameLoaderForFrameLookup, const FrameLoadRequest& request, const WindowFeatures& features, bool& created)
-{
- ASSERT(!features.dialog || request.frameName().isEmpty());
-
- if (!request.frameName().isEmpty() && request.frameName() != "_blank") {
- Frame* frame = frameLoaderForFrameLookup->frame()->tree()->find(request.frameName());
- if (frame && shouldAllowNavigation(frame)) {
- if (!request.resourceRequest().url().isEmpty())
- frame->loader()->loadFrameRequest(request, false, false, 0, 0, SendReferrer);
- if (Page* page = frame->page())
-#ifdef ANDROID_USER_GESTURE
- page->chrome()->focus(isProcessingUserGesture());
-#else
- page->chrome()->focus();
-#endif
- created = false;
- return frame;
- }
- }
-
- // FIXME: Setting the referrer should be the caller's responsibility.
- FrameLoadRequest requestWithReferrer = request;
- requestWithReferrer.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
- addHTTPOriginIfNeeded(requestWithReferrer.resourceRequest(), outgoingOrigin());
-
- Page* oldPage = m_frame->page();
- if (!oldPage)
- return 0;
-
- Page* page = oldPage->chrome()->createWindow(m_frame, requestWithReferrer, features);
- if (!page)
- return 0;
-
- Frame* frame = page->mainFrame();
- if (request.frameName() != "_blank")
- frame->tree()->setName(request.frameName());
-
- page->chrome()->setToolbarsVisible(features.toolBarVisible || features.locationBarVisible);
- page->chrome()->setStatusbarVisible(features.statusBarVisible);
- page->chrome()->setScrollbarsVisible(features.scrollbarsVisible);
- page->chrome()->setMenubarVisible(features.menuBarVisible);
- page->chrome()->setResizable(features.resizable);
-
- // 'x' and 'y' specify the location of the window, while 'width' and 'height'
- // specify the size of the page. We can only resize the window, so
- // adjust for the difference between the window size and the page size.
-
- FloatRect windowRect = page->chrome()->windowRect();
- FloatSize pageSize = page->chrome()->pageRect().size();
- if (features.xSet)
- windowRect.setX(features.x);
- if (features.ySet)
- windowRect.setY(features.y);
- if (features.widthSet)
- windowRect.setWidth(features.width + (windowRect.width() - pageSize.width()));
- if (features.heightSet)
- windowRect.setHeight(features.height + (windowRect.height() - pageSize.height()));
- page->chrome()->setWindowRect(windowRect);
-
- page->chrome()->show();
-
- created = true;
- return frame;
-}
-
bool FrameLoader::canHandleRequest(const ResourceRequest& request)
{
return m_client->canHandleRequest(request);
}
-void FrameLoader::changeLocation(const KURL& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool userGesture, bool refresh)
+void FrameLoader::changeLocation(const KURL& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool refresh)
{
RefPtr<Frame> protect(m_frame);
ResourceRequest request(url, referrer, refresh ? ReloadIgnoringCacheData : UseProtocolCachePolicy);
-#ifdef ANDROID_USER_GESTURE
- request.setUserGesture(userGesture);
-#endif
- if (m_frame->script()->executeIfJavaScriptURL(request.url(), userGesture))
- return;
+ urlSelected(request, "_self", 0, lockHistory, lockBackForwardList, SendReferrer, ReplaceDocumentIfJavaScriptURL);
+}
- urlSelected(request, "_self", 0, lockHistory, lockBackForwardList, userGesture, SendReferrer);
+void FrameLoader::urlSelected(const KURL& url, const String& passedTarget, PassRefPtr<Event> triggeringEvent, bool lockHistory, bool lockBackForwardList, ReferrerPolicy referrerPolicy)
+{
+ urlSelected(ResourceRequest(url), passedTarget, triggeringEvent, lockHistory, lockBackForwardList, referrerPolicy, DoNotReplaceDocumentIfJavaScriptURL);
}
-void FrameLoader::urlSelected(const ResourceRequest& request, const String& passedTarget, PassRefPtr<Event> triggeringEvent, bool lockHistory, bool lockBackForwardList, bool userGesture, ReferrerPolicy referrerPolicy)
+// The shouldReplaceDocumentIfJavaScriptURL parameter will go away when the FIXME to eliminate the
+// corresponding parameter from ScriptController::executeIfJavaScriptURL() is addressed.
+void FrameLoader::urlSelected(const ResourceRequest& request, const String& passedTarget, PassRefPtr<Event> triggeringEvent, bool lockHistory, bool lockBackForwardList, ReferrerPolicy referrerPolicy, ShouldReplaceDocumentIfJavaScriptURL shouldReplaceDocumentIfJavaScriptURL)
{
ASSERT(!m_suppressOpenerInNewFrame);
- if (m_frame->script()->executeIfJavaScriptURL(request.url(), userGesture, false))
+ if (m_frame->script()->executeIfJavaScriptURL(request.url(), shouldReplaceDocumentIfJavaScriptURL))
return;
String target = passedTarget;
@@ -366,125 +311,42 @@ void FrameLoader::urlSelected(const ResourceRequest& request, const String& pass
m_suppressOpenerInNewFrame = false;
}
-bool FrameLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String& urlString, const AtomicString& frameName)
+void FrameLoader::submitForm(PassRefPtr<FormSubmission> submission)
{
- // Support for <frame src="javascript:string">
- KURL scriptURL;
- KURL url;
- if (protocolIsJavaScript(urlString)) {
- scriptURL = completeURL(urlString); // completeURL() encodes the URL.
- url = blankURL();
- } else
- url = completeURL(urlString);
+ ASSERT(submission->method() == FormSubmission::PostMethod || submission->method() == FormSubmission::GetMethod);
- Frame* frame = ownerElement->contentFrame();
- if (frame)
- frame->redirectScheduler()->scheduleLocationChange(url.string(), m_outgoingReferrer, true, true, isProcessingUserGesture());
- else
- frame = loadSubframe(ownerElement, url, frameName, m_outgoingReferrer);
-
- if (!frame)
- return false;
-
- if (!scriptURL.isEmpty())
- frame->script()->executeIfJavaScriptURL(scriptURL);
-
- return true;
-}
-
-Frame* FrameLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const String& name, const String& referrer)
-{
- bool allowsScrolling = true;
- int marginWidth = -1;
- int marginHeight = -1;
- if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag)) {
- HTMLFrameElementBase* o = static_cast<HTMLFrameElementBase*>(ownerElement);
- allowsScrolling = o->scrollingMode() != ScrollbarAlwaysOff;
- marginWidth = o->getMarginWidth();
- marginHeight = o->getMarginHeight();
- }
-
- if (!SecurityOrigin::canLoad(url, referrer, 0)) {
- FrameLoader::reportLocalLoadFailed(m_frame, url.string());
- return 0;
- }
-
- bool hideReferrer = SecurityOrigin::shouldHideReferrer(url, referrer);
- RefPtr<Frame> frame = m_client->createFrame(url, name, ownerElement, hideReferrer ? String() : referrer, allowsScrolling, marginWidth, marginHeight);
-
- if (!frame) {
- checkCallImplicitClose();
- return 0;
- }
-
- // All new frames will have m_isComplete set to true at this point due to synchronously loading
- // an empty document in FrameLoader::init(). But many frames will now be starting an
- // asynchronous load of url, so we set m_isComplete to false and then check if the load is
- // actually completed below. (Note that we set m_isComplete to false even for synchronous
- // loads, so that checkCompleted() below won't bail early.)
- // FIXME: Can we remove this entirely? m_isComplete normally gets set to false when a load is committed.
- frame->loader()->m_isComplete = false;
-
- RenderObject* renderer = ownerElement->renderer();
- FrameView* view = frame->view();
- if (renderer && renderer->isWidget() && view)
- toRenderWidget(renderer)->setWidget(view);
-
- checkCallImplicitClose();
-
- // Some loads are performed synchronously (e.g., about:blank and loads
- // cancelled by returning a null ResourceRequest from requestFromDelegate).
- // In these cases, the synchronous load would have finished
- // before we could connect the signals, so make sure to send the
- // completed() signal for the child by hand and mark the load as being
- // complete.
- // FIXME: In this case the Frame will have finished loading before
- // it's being added to the child list. It would be a good idea to
- // create the child first, then invoke the loader separately.
- if (frame->loader()->state() == FrameStateComplete)
- frame->loader()->checkCompleted();
-
- return frame.get();
-}
-
-void FrameLoader::submitForm(const char* action, const String& url, PassRefPtr<FormData> formData,
- const String& target, const String& contentType, const String& boundary,
- bool lockHistory, PassRefPtr<Event> event, PassRefPtr<FormState> formState)
-{
- ASSERT(action);
- ASSERT(strcmp(action, "GET") == 0 || strcmp(action, "POST") == 0);
- ASSERT(formData);
- ASSERT(formState);
- ASSERT(formState->sourceFrame() == m_frame);
+ // FIXME: Find a good spot for these.
+ ASSERT(submission->data());
+ ASSERT(submission->state());
+ ASSERT(submission->state()->sourceFrame() == m_frame);
if (!m_frame->page())
return;
- KURL u = completeURL(url.isNull() ? "" : url);
- if (u.isEmpty())
+ if (submission->action().isEmpty())
return;
- if (isDocumentSandboxed(SandboxForms))
+ if (isDocumentSandboxed(m_frame, SandboxForms))
return;
- if (protocolIsJavaScript(u)) {
+ if (protocolIsJavaScript(submission->action())) {
m_isExecutingJavaScriptFormAction = true;
- m_frame->script()->executeIfJavaScriptURL(u, false, false);
+ m_frame->script()->executeIfJavaScriptURL(submission->action(), DoNotReplaceDocumentIfJavaScriptURL);
m_isExecutingJavaScriptFormAction = false;
return;
}
- FrameLoadRequest frameRequest;
-#ifdef ANDROID_USER_GESTURE
- frameRequest.resourceRequest().setUserGesture(isProcessingUserGesture());
-#endif
-
- String targetOrBaseTarget = target.isEmpty() ? m_frame->document()->baseTarget() : target;
- Frame* targetFrame = findFrameForNavigation(targetOrBaseTarget);
+ Frame* targetFrame = m_frame->tree()->find(submission->target());
+ if (!shouldAllowNavigation(targetFrame))
+ return;
if (!targetFrame) {
+ if (!DOMWindow::allowPopUp(m_frame) && !isProcessingUserGesture())
+ return;
+
targetFrame = m_frame;
- frameRequest.setFrameName(targetOrBaseTarget);
- }
+ } else
+ submission->clearTarget();
+
if (!targetFrame->page())
return;
@@ -501,39 +363,22 @@ void FrameLoader::submitForm(const char* action, const String& url, PassRefPtr<F
// needed any more now that we reset m_submittedFormURL on each mouse or key down event.
if (m_frame->tree()->isDescendantOf(targetFrame)) {
- if (m_submittedFormURL == u)
+ if (m_submittedFormURL == submission->action())
return;
- m_submittedFormURL = u;
+ m_submittedFormURL = submission->action();
}
- formData->generateFiles(m_frame->page()->chrome()->client());
-
- if (!m_outgoingReferrer.isEmpty())
- frameRequest.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
-
- if (strcmp(action, "GET") == 0)
- u.setQuery(formData->flattenToString());
- else {
- frameRequest.resourceRequest().setHTTPMethod("POST");
- frameRequest.resourceRequest().setHTTPBody(formData);
-
- // construct some user headers if necessary
- if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
- frameRequest.resourceRequest().setHTTPContentType(contentType);
- else // contentType must be "multipart/form-data"
- frameRequest.resourceRequest().setHTTPContentType(contentType + "; boundary=" + boundary);
- }
-
- frameRequest.resourceRequest().setURL(u);
- addHTTPOriginIfNeeded(frameRequest.resourceRequest(), outgoingOrigin());
+ submission->data()->generateFiles(m_frame->document());
+ submission->setReferrer(m_outgoingReferrer);
+ submission->setOrigin(outgoingOrigin());
- targetFrame->redirectScheduler()->scheduleFormSubmission(frameRequest, lockHistory, event, formState);
+ targetFrame->navigationScheduler()->scheduleFormSubmission(submission);
}
void FrameLoader::stopLoading(UnloadEventPolicy unloadEventPolicy, DatabasePolicy databasePolicy)
{
- if (m_frame->document() && m_frame->document()->tokenizer())
- m_frame->document()->tokenizer()->stopParsing();
+ if (m_frame->document() && m_frame->document()->parser())
+ m_frame->document()->parser()->stopParsing();
if (unloadEventPolicy != UnloadEventPolicyNone) {
if (m_frame->document()) {
@@ -541,14 +386,23 @@ void FrameLoader::stopLoading(UnloadEventPolicy unloadEventPolicy, DatabasePolic
Node* currentFocusedNode = m_frame->document()->focusedNode();
if (currentFocusedNode)
currentFocusedNode->aboutToUnload();
- m_unloadEventBeingDispatched = true;
+ m_pageDismissalEventBeingDispatched = true;
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())
+ if (!m_frame->document()->inPageCache()) {
m_frame->domWindow()->dispatchEvent(Event::create(eventNames().unloadEvent, false, false), m_frame->domWindow()->document());
+
+ if (m_provisionalDocumentLoader) {
+ DocumentLoadTiming* timing = m_provisionalDocumentLoader->timing();
+ ASSERT(timing->navigationStart);
+ ASSERT(!timing->unloadEventEnd);
+ timing->unloadEventEnd = currentTime();
+ ASSERT(timing->unloadEventEnd >= timing->navigationStart);
+ }
+ }
}
- m_unloadEventBeingDispatched = false;
+ m_pageDismissalEventBeingDispatched = false;
if (m_frame->document())
m_frame->document()->updateStyleIfNeeded();
m_wasUnloadEventEmitted = true;
@@ -558,7 +412,7 @@ void FrameLoader::stopLoading(UnloadEventPolicy unloadEventPolicy, DatabasePolic
// Dispatching the unload event could have made m_frame->document() null.
if (m_frame->document() && !m_frame->document()->inPageCache()) {
// Don't remove event listeners from a transitional empty document (see bug 28716 for more information).
- bool keepEventListeners = m_isDisplayingInitialEmptyDocument && m_provisionalDocumentLoader
+ bool keepEventListeners = m_stateMachine.isDisplayingInitialEmptyDocument() && m_provisionalDocumentLoader
&& m_frame->document()->securityOrigin()->isSecureTransitionTo(m_provisionalDocumentLoader->url());
if (!keepEventListeners)
@@ -578,8 +432,12 @@ void FrameLoader::stopLoading(UnloadEventPolicy unloadEventPolicy, DatabasePolic
m_workingURL = KURL();
if (Document* doc = m_frame->document()) {
- if (DocLoader* docLoader = doc->docLoader())
- cache()->loader()->cancelRequests(docLoader);
+ // FIXME: HTML5 doesn't tell us to set the state to complete when aborting, but we do anyway to match legacy behavior.
+ // http://www.w3.org/Bugs/Public/show_bug.cgi?id=10537
+ doc->setReadyState(Document::Complete);
+
+ if (CachedResourceLoader* cachedResourceLoader = doc->cachedResourceLoader())
+ cache()->loader()->cancelRequests(cachedResourceLoader);
#if ENABLE(DATABASE)
if (databasePolicy == DatabasePolicyStop)
@@ -589,11 +447,8 @@ void FrameLoader::stopLoading(UnloadEventPolicy unloadEventPolicy, DatabasePolic
#endif
}
- // tell all subframes to stop as well
- for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
- child->loader()->stopLoading(unloadEventPolicy);
-
- m_frame->redirectScheduler()->cancel();
+ // FIXME: This will cancel redirection timer, which really needs to be restarted when restoring the frame from b/f cache.
+ m_frame->navigationScheduler()->cancel();
}
void FrameLoader::stop()
@@ -602,8 +457,8 @@ void FrameLoader::stop()
// The frame's last ref may be removed and it will be deleted by checkCompleted().
RefPtr<Frame> protector(m_frame);
- if (m_frame->document()->tokenizer())
- m_frame->document()->tokenizer()->stopParsing();
+ if (m_frame->document()->parser())
+ m_frame->document()->parser()->stopParsing();
m_frame->document()->finishParsing();
if (m_iconLoader)
@@ -648,13 +503,13 @@ KURL FrameLoader::iconURL()
bool FrameLoader::didOpenURL(const KURL& url)
{
- if (m_frame->redirectScheduler()->redirectScheduledDuringLoad()) {
+ if (m_frame->navigationScheduler()->redirectScheduledDuringLoad()) {
// A redirect was scheduled before the document was created.
// This can happen when one frame changes another frame's location.
return false;
}
- m_frame->redirectScheduler()->cancel();
+ m_frame->navigationScheduler()->cancel();
m_frame->editor()->clearLastEditCommand();
m_isComplete = false;
@@ -664,9 +519,11 @@ bool FrameLoader::didOpenURL(const KURL& url)
// If we are still in the process of initializing an empty document then
// its frame is not in a consistent state for rendering, so avoid setJSStatusBarText
// since it may cause clients to attempt to render the frame.
- if (!m_creatingInitialEmptyDocument) {
- m_frame->setJSStatusBarText(String());
- m_frame->setJSDefaultStatusBarText(String());
+ if (!m_stateMachine.creatingInitialEmptyDocument()) {
+ if (DOMWindow* window = m_frame->existingDOMWindow()) {
+ window->setStatus(String());
+ window->setDefaultStatus(String());
+ }
}
m_URL = url;
if (m_URL.protocolInHTTPFamily() && !m_URL.host().isEmpty() && m_URL.path().isEmpty())
@@ -684,13 +541,14 @@ void FrameLoader::didExplicitOpen()
m_didCallImplicitClose = false;
// Calling document.open counts as committing the first real document load.
- m_committedFirstRealDocumentLoad = true;
+ if (!m_stateMachine.committedFirstRealDocumentLoad())
+ m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit);
// Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
// from a subsequent window.document.open / window.document.write call.
// Canceling redirection here works for all cases because document.open
// implicitly precedes document.write.
- m_frame->redirectScheduler()->cancel();
+ m_frame->navigationScheduler()->cancel();
if (m_frame->document()->url() != blankURL())
m_URL = m_frame->document()->url();
}
@@ -698,7 +556,7 @@ void FrameLoader::didExplicitOpen()
void FrameLoader::cancelAndClear()
{
- m_frame->redirectScheduler()->cancel();
+ m_frame->navigationScheduler()->cancel();
if (!m_isComplete)
closeURL();
@@ -707,14 +565,6 @@ void FrameLoader::cancelAndClear()
m_frame->script()->updatePlatformScriptObjects();
}
-void FrameLoader::replaceDocument(const String& html)
-{
- stopAllLoaders();
- begin(m_URL, true, m_frame->document()->securityOrigin());
- write(html);
- end();
-}
-
void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects, bool clearFrameView)
{
m_frame->editor()->clear();
@@ -737,7 +587,7 @@ void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects, boo
// Do this after detaching the document so that the unload event works.
if (clearWindowProperties) {
m_frame->clearDOMWindow();
- m_frame->script()->clearWindowShell();
+ m_frame->script()->clearWindowShell(m_frame->document()->inPageCache());
}
m_frame->selection()->clear();
@@ -745,34 +595,30 @@ void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects, boo
if (clearFrameView && m_frame->view())
m_frame->view()->clear();
- m_frame->setSelectionGranularity(CharacterGranularity);
-
// Do not drop the document before the ScriptController and view are cleared
// as some destructors might still try to access the document.
m_frame->setDocument(0);
- m_decoder = 0;
+ writer()->clear();
- m_containsPlugIns = false;
+ m_subframeLoader.clear();
if (clearScriptObjects)
m_frame->script()->clearScriptObjects();
- m_frame->redirectScheduler()->clear();
+ m_frame->navigationScheduler()->clear();
m_checkTimer.stop();
m_shouldCallCheckCompleted = false;
m_shouldCallCheckLoadComplete = false;
- m_receivedData = false;
- m_isDisplayingInitialEmptyDocument = false;
-
- if (!m_encodingWasChosenByUser)
- m_encoding = String();
+ if (m_stateMachine.isDisplayingInitialEmptyDocument() && m_stateMachine.committedFirstRealDocumentLoad())
+ m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
}
void FrameLoader::receivedFirstData()
{
- begin(m_workingURL, false);
+ writer()->begin(m_workingURL, false);
+ writer()->setDocumentWasLoadedAsPartOfNavigation();
dispatchDidCommitLoad();
dispatchDidClearWindowObjectsInAllWorlds();
@@ -800,196 +646,55 @@ void FrameLoader::receivedFirstData()
else
url = m_frame->document()->completeURL(url).string();
- m_frame->redirectScheduler()->scheduleRedirect(delay, url);
-}
-
-const String& FrameLoader::responseMIMEType() const
-{
- return m_responseMIMEType;
+ m_frame->navigationScheduler()->scheduleRedirect(delay, url);
}
-void FrameLoader::setResponseMIMEType(const String& type)
+void FrameLoader::setURL(const KURL& url)
{
- m_responseMIMEType = type;
-}
-
-void FrameLoader::begin()
-{
- begin(KURL());
-}
-
-void FrameLoader::begin(const KURL& url, bool dispatch, SecurityOrigin* origin)
-{
- // We need to take a reference to the security origin because |clear|
- // might destroy the document that owns it.
- RefPtr<SecurityOrigin> forcedSecurityOrigin = origin;
-
- RefPtr<Document> document;
-
- // Create a new document before clearing the frame, because it may need to inherit an aliased security context.
- if (!m_isDisplayingInitialEmptyDocument && m_client->shouldUsePluginDocument(m_responseMIMEType))
- document = PluginDocument::create(m_frame);
- else if (!m_client->hasHTMLView())
- document = PlaceholderDocument::create(m_frame);
- else
- document = DOMImplementation::createDocument(m_responseMIMEType, m_frame, m_frame->inViewSourceMode());
-
- bool resetScripting = !(m_isDisplayingInitialEmptyDocument && m_frame->document()->securityOrigin()->isSecureTransitionTo(url));
- clear(resetScripting, resetScripting);
- if (resetScripting)
- m_frame->script()->updatePlatformScriptObjects();
-
- m_needsClear = true;
- m_isComplete = false;
- m_didCallImplicitClose = false;
- m_isLoadingMainResource = true;
- m_isDisplayingInitialEmptyDocument = m_creatingInitialEmptyDocument;
-
KURL ref(url);
ref.setUser(String());
ref.setPass(String());
ref.removeFragmentIdentifier();
m_outgoingReferrer = ref.string();
m_URL = url;
+}
- document->setURL(m_URL);
- m_frame->setDocument(document);
+void FrameLoader::didBeginDocument(bool dispatch)
+{
+ m_needsClear = true;
+ m_isComplete = false;
+ m_didCallImplicitClose = false;
+ m_isLoadingMainResource = true;
+ m_frame->document()->setReadyState(Document::Loading);
if (m_pendingStateObject) {
- document->statePopped(m_pendingStateObject.get());
+ m_frame->document()->statePopped(m_pendingStateObject.get());
m_pendingStateObject.clear();
}
-
- if (m_decoder)
- document->setDecoder(m_decoder.get());
- if (forcedSecurityOrigin)
- document->setSecurityOrigin(forcedSecurityOrigin.get());
-
- m_frame->domWindow()->setURL(document->url());
- m_frame->domWindow()->setSecurityOrigin(document->securityOrigin());
if (dispatch)
dispatchDidClearWindowObjectsInAllWorlds();
-
+
updateFirstPartyForCookies();
- Settings* settings = document->settings();
- document->docLoader()->setAutoLoadImages(settings && settings->loadsImagesAutomatically());
+ Settings* settings = m_frame->document()->settings();
+ m_frame->document()->cachedResourceLoader()->setAutoLoadImages(settings && settings->loadsImagesAutomatically());
#ifdef ANDROID_BLOCK_NETWORK_IMAGE
- document->docLoader()->setBlockNetworkImage(settings && settings->blockNetworkImage());
+ m_frame->document()->cachedResourceLoader()->setBlockNetworkImage(settings && settings->blockNetworkImage());
#endif
if (m_documentLoader) {
String dnsPrefetchControl = m_documentLoader->response().httpHeaderField("X-DNS-Prefetch-Control");
if (!dnsPrefetchControl.isEmpty())
- document->parseDNSPrefetchControlHeader(dnsPrefetchControl);
+ m_frame->document()->parseDNSPrefetchControlHeader(dnsPrefetchControl);
}
history()->restoreDocumentState();
-
- document->implicitOpen();
-
- if (m_frame->view() && m_client->hasHTMLView())
- m_frame->view()->setContentsSize(IntSize());
-}
-
-void FrameLoader::write(const char* str, int len, bool flush)
-{
- if (len == 0 && !flush)
- return;
-
- if (len == -1)
- len = strlen(str);
-
- Tokenizer* tokenizer = m_frame->document()->tokenizer();
- if (tokenizer && tokenizer->wantsRawData()) {
- if (len > 0)
- tokenizer->writeRawData(str, len);
- return;
- }
-
- if (!m_decoder) {
- if (Settings* settings = m_frame->settings()) {
- m_decoder = TextResourceDecoder::create(m_responseMIMEType,
- settings->defaultTextEncodingName(),
- settings->usesEncodingDetector());
- Frame* parentFrame = m_frame->tree()->parent();
- // Set the hint encoding to the parent frame encoding only if
- // the parent and the current frames share the security origin.
- // We impose this condition because somebody can make a child frame
- // containing a carefully crafted html/javascript in one encoding
- // that can be mistaken for hintEncoding (or related encoding) by
- // an auto detector. When interpreted in the latter, it could be
- // an attack vector.
- // FIXME: This might be too cautious for non-7bit-encodings and
- // we may consider relaxing this later after testing.
- if (canReferToParentFrameEncoding(m_frame, parentFrame))
- m_decoder->setHintEncoding(parentFrame->document()->decoder());
- } else
- m_decoder = TextResourceDecoder::create(m_responseMIMEType, String());
- Frame* parentFrame = m_frame->tree()->parent();
- if (m_encoding.isEmpty()) {
- if (canReferToParentFrameEncoding(m_frame, parentFrame))
- m_decoder->setEncoding(parentFrame->document()->inputEncoding(), TextResourceDecoder::EncodingFromParentFrame);
- } else {
- m_decoder->setEncoding(m_encoding,
- m_encodingWasChosenByUser ? TextResourceDecoder::UserChosenEncoding : TextResourceDecoder::EncodingFromHTTPHeader);
- }
- m_frame->document()->setDecoder(m_decoder.get());
- }
-
- String decoded = m_decoder->decode(str, len);
- if (flush)
- decoded += m_decoder->flush();
- if (decoded.isEmpty())
- return;
-
- if (!m_receivedData) {
- m_receivedData = true;
- if (m_decoder->encoding().usesVisualOrdering())
- m_frame->document()->setVisuallyOrdered();
- m_frame->document()->recalcStyle(Node::Force);
- }
-
- if (tokenizer) {
- ASSERT(!tokenizer->wantsRawData());
- tokenizer->write(decoded, true);
- }
}
-void FrameLoader::write(const String& str)
-{
- if (str.isNull())
- return;
-
- if (!m_receivedData) {
- m_receivedData = true;
- m_frame->document()->setParseMode(Document::Strict);
- }
-
- if (Tokenizer* tokenizer = m_frame->document()->tokenizer())
- tokenizer->write(str, true);
-}
-
-void FrameLoader::end()
+void FrameLoader::didEndDocument()
{
m_isLoadingMainResource = false;
- endIfNotLoadingMainResource();
-}
-
-void FrameLoader::endIfNotLoadingMainResource()
-{
- if (m_isLoadingMainResource || !m_frame->page() || !m_frame->document())
- return;
-
- // http://bugs.webkit.org/show_bug.cgi?id=10854
- // The frame's last ref may be removed and it can be deleted by checkCompleted(),
- // so we'll add a protective refcount
- RefPtr<Frame> protector(m_frame);
-
- // make sure nothing's left in there
- write(0, 0, true);
- m_frame->document()->finishParsing();
}
void FrameLoader::iconLoadDecisionAvailable()
@@ -1059,7 +764,7 @@ void FrameLoader::startIconLoader()
// This is either a reload or the icon database said "yes, load the icon", so kick off the load!
if (!m_iconLoader)
- m_iconLoader.set(IconLoader::create(m_frame).release());
+ m_iconLoader = IconLoader::create(m_frame);
m_iconLoader->startLoading();
}
@@ -1074,7 +779,7 @@ void FrameLoader::commitIconURLToIconDatabase(const KURL& icon)
void FrameLoader::finishedParsing()
{
- if (m_creatingInitialEmptyDocument)
+ if (m_stateMachine.creatingInitialEmptyDocument())
return;
m_frame->injectUserScripts(InjectAtDocumentEnd);
@@ -1143,13 +848,18 @@ void FrameLoader::checkCompleted()
if (numRequests(m_frame->document()))
return;
+ // Still waiting for elements that don't go through a FrameLoader?
+ if (m_frame->document()->isDelayingLoadEvent())
+ return;
+
// OK, completed.
m_isComplete = true;
+ m_frame->document()->setReadyState(Document::Complete);
RefPtr<Frame> protect(m_frame);
checkCallImplicitClose(); // if we didn't do it before
- m_frame->redirectScheduler()->startTimer();
+ m_frame->navigationScheduler()->startTimer();
completed();
if (m_frame->page())
@@ -1191,7 +901,7 @@ void FrameLoader::scheduleCheckLoadComplete()
void FrameLoader::checkCallImplicitClose()
{
- if (m_didCallImplicitClose || m_frame->document()->parsing())
+ if (m_didCallImplicitClose || m_frame->document()->parsing() || m_frame->document()->isDelayingLoadEvent())
return;
if (!allChildrenAreComplete())
@@ -1227,7 +937,7 @@ void FrameLoader::loadURLIntoChildFrame(const KURL& url, const String& referer,
// If we're moving in the back/forward list, we might want to replace the content
// of this child frame with whatever was there at that point.
if (parentItem && parentItem->children().size() && isBackForwardLoadType(loadType)) {
- HistoryItem* childItem = parentItem->childItemWithTarget(childFrame->tree()->name());
+ HistoryItem* childItem = parentItem->childItemWithTarget(childFrame->tree()->uniqueName());
if (childItem) {
// Use the original URL to ensure we get all the side-effects, such as
// onLoad handlers, of any redirects that happened. An example of where
@@ -1239,17 +949,13 @@ void FrameLoader::loadURLIntoChildFrame(const KURL& url, const String& referer,
}
#if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size
- RefPtr<Archive> subframeArchive = activeDocumentLoader()->popArchiveForSubframe(childFrame->tree()->name());
+ RefPtr<Archive> subframeArchive = activeDocumentLoader()->popArchiveForSubframe(childFrame->tree()->uniqueName());
if (subframeArchive)
childFrame->loader()->loadArchive(subframeArchive.release());
else
#endif
-#ifdef ANDROID_USER_GESTURE
- childFrame->loader()->loadURL(workingURL, referer, String(), false, childLoadType, 0, 0, false);
-#else
childFrame->loader()->loadURL(workingURL, referer, String(), false, childLoadType, 0, 0);
-#endif
}
#if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size
@@ -1275,74 +981,6 @@ void FrameLoader::loadArchive(PassRefPtr<Archive> prpArchive)
}
#endif
-String FrameLoader::encoding() const
-{
- if (m_encodingWasChosenByUser && !m_encoding.isEmpty())
- return m_encoding;
- if (m_decoder && m_decoder->encoding().isValid())
- return m_decoder->encoding().name();
- Settings* settings = m_frame->settings();
- return settings ? settings->defaultTextEncodingName() : String();
-}
-
-bool FrameLoader::requestObject(RenderPart* renderer, const String& url, const AtomicString& frameName,
- const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues)
-{
- if (url.isEmpty() && mimeType.isEmpty())
- return false;
-
- if (!m_frame->script()->xssAuditor()->canLoadObject(url)) {
- // It is unsafe to honor the request for this object.
- return false;
- }
-
- KURL completedURL;
- if (!url.isEmpty())
- completedURL = completeURL(url);
-
- bool useFallback;
- if (shouldUsePlugin(completedURL, mimeType, renderer->hasFallbackContent(), useFallback)) {
- Settings* settings = m_frame->settings();
- if (!m_client->allowPlugins(settings && settings->arePluginsEnabled())
- || (!settings->isJavaEnabled() && MIMETypeRegistry::isJavaAppletMIMEType(mimeType)))
- return false;
- if (isDocumentSandboxed(SandboxPlugins))
- return false;
- return loadPlugin(renderer, completedURL, mimeType, paramNames, paramValues, useFallback);
- }
-
- ASSERT(renderer->node()->hasTagName(objectTag) || renderer->node()->hasTagName(embedTag));
- HTMLPlugInElement* element = static_cast<HTMLPlugInElement*>(renderer->node());
-
- // If the plug-in element already contains a subframe, requestFrame will re-use it. Otherwise,
- // it will create a new frame and set it as the RenderPart's widget, causing what was previously
- // in the widget to be torn down.
- return requestFrame(element, completedURL, frameName);
-}
-
-bool FrameLoader::shouldUsePlugin(const KURL& url, const String& mimeType, bool hasFallback, bool& useFallback)
-{
- if (m_client->shouldUsePluginDocument(mimeType)) {
- useFallback = false;
- return true;
- }
-
- // Allow other plug-ins to win over QuickTime because if the user has installed a plug-in that
- // can handle TIFF (which QuickTime can also handle) they probably intended to override QT.
- if (m_frame->page() && (mimeType == "image/tiff" || mimeType == "image/tif" || mimeType == "image/x-tiff")) {
- const PluginData* pluginData = m_frame->page()->pluginData();
- String pluginName = pluginData ? pluginData->pluginNameForMimeType(mimeType) : String();
- if (!pluginName.isEmpty() && !pluginName.contains("QuickTime", false))
- return true;
- }
-
- ObjectContentType objectType = m_client->objectContentType(url, mimeType);
- // If an object's content can't be handled and it has no fallback, let
- // it be handled as a plugin to show the broken plugin icon.
- useFallback = objectType == ObjectContentNone && hasFallback;
- return objectType == ObjectContentNone || objectType == ObjectContentNetscapePlugin || objectType == ObjectContentOtherPlugin;
-}
-
ObjectContentType FrameLoader::defaultObjectContentType(const KURL& url, const String& mimeTypeIn)
{
String mimeType = mimeTypeIn;
@@ -1356,7 +994,7 @@ ObjectContentType FrameLoader::defaultObjectContentType(const KURL& url, const S
if (MIMETypeRegistry::isSupportedImageMIMEType(mimeType))
return WebCore::ObjectContentImage;
-#if !PLATFORM(MAC) && !PLATFORM(CHROMIUM) // Mac has no PluginDatabase, nor does Chromium
+#if !PLATFORM(MAC) && !PLATFORM(CHROMIUM) && !PLATFORM(EFL) // Mac has no PluginDatabase, nor does Chromium or EFL
if (PluginDatabase::installedPlugins()->isMIMETypeRegistered(mimeType))
return WebCore::ObjectContentNetscapePlugin;
#endif
@@ -1367,50 +1005,6 @@ ObjectContentType FrameLoader::defaultObjectContentType(const KURL& url, const S
return WebCore::ObjectContentNone;
}
-static HTMLPlugInElement* toPlugInElement(Node* node)
-{
- if (!node)
- return 0;
-
-#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
- ASSERT(node->hasTagName(objectTag) || node->hasTagName(embedTag)
- || node->hasTagName(videoTag) || node->hasTagName(audioTag)
- || node->hasTagName(appletTag));
-#else
- ASSERT(node->hasTagName(objectTag) || node->hasTagName(embedTag)
- || node->hasTagName(appletTag));
-#endif
-
- return static_cast<HTMLPlugInElement*>(node);
-}
-
-bool FrameLoader::loadPlugin(RenderPart* renderer, const KURL& url, const String& mimeType,
- const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback)
-{
- RefPtr<Widget> widget;
-
- if (renderer && !useFallback) {
- HTMLPlugInElement* element = toPlugInElement(renderer->node());
-
- if (!SecurityOrigin::canLoad(url, String(), frame()->document())) {
- FrameLoader::reportLocalLoadFailed(m_frame, url.string());
- return false;
- }
-
- checkIfRunInsecureContent(m_frame->document()->securityOrigin(), url);
-
- widget = m_client->createPlugin(IntSize(renderer->contentWidth(), renderer->contentHeight()),
- element, url, paramNames, paramValues, mimeType,
- m_frame->document()->isPluginDocument() && !m_containsPlugIns);
- if (widget) {
- renderer->setWidget(widget);
- m_containsPlugIns = true;
- }
- }
-
- return widget != 0;
-}
-
String FrameLoader::outgoingReferrer() const
{
return m_outgoingReferrer;
@@ -1426,7 +1020,7 @@ bool FrameLoader::isMixedContent(SecurityOrigin* context, const KURL& url)
if (context->protocol() != "https")
return false; // We only care about HTTPS security origins.
- if (!url.isValid() || url.protocolIs("https") || url.protocolIs("about") || url.protocolIs("data"))
+ if (!url.isValid() || SchemeRegistry::shouldTreatURLSchemeAsSecure(url.protocol()))
return false; // Loading these protocols is secure.
return true;
@@ -1437,8 +1031,7 @@ void FrameLoader::checkIfDisplayInsecureContent(SecurityOrigin* context, const K
if (!isMixedContent(context, url))
return;
- String message = String::format("The page at %s displayed insecure content from %s.\n",
- m_URL.string().utf8().data(), url.string().utf8().data());
+ String message = makeString("The page at ", m_URL.string(), " displayed insecure content from ", url.string(), ".\n");
m_frame->domWindow()->console()->addMessage(HTMLMessageSource, LogMessageType, WarningMessageLevel, message, 1, String());
m_client->didDisplayInsecureContent();
@@ -1449,8 +1042,7 @@ void FrameLoader::checkIfRunInsecureContent(SecurityOrigin* context, const KURL&
if (!isMixedContent(context, url))
return;
- String message = String::format("The page at %s ran insecure content from %s.\n",
- m_URL.string().utf8().data(), url.string().utf8().data());
+ String message = makeString("The page at ", m_URL.string(), " ran insecure content from ", url.string(), ".\n");
m_frame->domWindow()->console()->addMessage(HTMLMessageSource, LogMessageType, WarningMessageLevel, message, 1, String());
m_client->didRunInsecureContent(context);
@@ -1475,6 +1067,7 @@ void FrameLoader::setOpener(Frame* opener)
}
}
+// FIXME: This does not belong in FrameLoader!
void FrameLoader::handleFallbackContent()
{
HTMLFrameOwnerElement* owner = m_frame->ownerElement();
@@ -1489,17 +1082,18 @@ void FrameLoader::provisionalLoadStarted()
if (!m_frame->tree()->parent())
android::TimeCounter::reset();
#endif
- m_firstLayoutDone = false;
- m_frame->redirectScheduler()->cancel(true);
+ if (m_stateMachine.firstLayoutDone())
+ m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
+ m_frame->navigationScheduler()->cancel(true);
m_client->provisionalLoadStarted();
}
bool FrameLoader::isProcessingUserGesture()
{
Frame* frame = m_frame->tree()->top();
- if (!frame->script()->canExecuteScripts())
+ if (!frame->script()->canExecuteScripts(NotAboutToExecuteScript))
return true; // If JavaScript is disabled, a user gesture must have initiated the navigation.
- return frame->script()->processingUserGesture(mainThreadNormalWorld()); // FIXME: Use pageIsProcessingUserGesture.
+ return ScriptController::processingUserGesture(); // FIXME: Use pageIsProcessingUserGesture.
}
void FrameLoader::resetMultipleFormSubmissionProtection()
@@ -1507,20 +1101,10 @@ void FrameLoader::resetMultipleFormSubmissionProtection()
m_submittedFormURL = KURL();
}
-void FrameLoader::setEncoding(const String& name, bool userChosen)
+void FrameLoader::willSetEncoding()
{
if (!m_workingURL.isEmpty())
receivedFirstData();
- m_encoding = name;
- m_encodingWasChosenByUser = userChosen;
-}
-
-void FrameLoader::addData(const char* bytes, int length)
-{
- ASSERT(m_workingURL.isEmpty());
- ASSERT(m_frame->document());
- ASSERT(m_frame->document()->parsing());
- write(bytes, length);
}
#if ENABLE(WML)
@@ -1534,208 +1118,6 @@ static inline bool frameContainsWMLContent(Frame* frame)
}
#endif
-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()
- // FIXME: If we ever change this so that frames with plug-ins will be cached,
- // we need to make sure that we don't cache frames that have outstanding NPObjects
- // (objects created by the plug-in). Since there is no way to pause/resume a Netscape plug-in,
- // they would need to be destroyed and then recreated, and there is no way that we can recreate
- // the right NPObjects. See <rdar://problem/5197041> for more information.
- && !m_containsPlugIns
- && !m_URL.protocolIs("https")
- && (!m_frame->domWindow() || !m_frame->domWindow()->hasEventListeners(eventNames().unloadEvent))
-#if ENABLE(DATABASE)
- && !m_frame->document()->hasOpenDatabases()
-#endif
-#if ENABLE(SHARED_WORKERS)
- && !SharedWorkerRepository::hasSharedWorkers(m_frame->document())
-#endif
- && !m_frame->document()->usingGeolocation()
- && history()->currentItem()
- && !m_quickRedirectComing
- && !m_documentLoader->isLoadingInAPISense()
- && !m_documentLoader->isStopping()
- && m_frame->document()->canSuspendActiveDOMObjects()
-#if ENABLE(OFFLINE_WEB_APPLICATIONS)
- // FIXME: We should investigating caching frames that have an associated
- // application cache. <rdar://problem/5917899> tracks that work.
- && m_documentLoader->applicationCacheHost()->canCacheInPageCache()
-#endif
-#if ENABLE(WML)
- && !frameContainsWMLContent(m_frame)
-#endif
- && m_client->canCachePage()
- ;
-}
-
-bool FrameLoader::canCachePage()
-{
-#ifndef NDEBUG
- logCanCachePageDecision();
-#endif
-
- // Cache the page, if possible.
- // Don't write to the cache if in the middle of a redirect, since we will want to
- // store the final page we end up on.
- // No point writing to the cache on a reload or loadSame, since we will just write
- // over it again when we leave that page.
- // FIXME: <rdar://problem/4886592> - We should work out the complexities of caching pages with frames as they
- // are the most interesting pages on the web, and often those that would benefit the most from caching!
- FrameLoadType loadType = this->loadType();
-
- return !m_frame->tree()->parent()
- && canCachePageContainingThisFrame()
- && m_frame->page()
- && m_frame->page()->backForwardList()->enabled()
- && m_frame->page()->backForwardList()->capacity() > 0
- && m_frame->page()->settings()->usesPageCache()
- && loadType != FrameLoadTypeReload
- && loadType != FrameLoadTypeReloadFromOrigin
- && loadType != FrameLoadTypeSame
- ;
-}
-
-#ifndef NDEBUG
-static String& pageCacheLogPrefix(int indentLevel)
-{
- static int previousIndent = -1;
- DEFINE_STATIC_LOCAL(String, prefix, ());
-
- if (indentLevel != previousIndent) {
- previousIndent = indentLevel;
- prefix.truncate(0);
- for (int i = 0; i < previousIndent; ++i)
- prefix += " ";
- }
-
- return prefix;
-}
-
-static void pageCacheLog(const String& prefix, const String& message)
-{
- LOG(PageCache, "%s%s", prefix.utf8().data(), message.utf8().data());
-}
-
-#define PCLOG(...) pageCacheLog(pageCacheLogPrefix(indentLevel), String::format(__VA_ARGS__))
-
-void FrameLoader::logCanCachePageDecision()
-{
- // Only bother logging for main frames that have actually loaded and have content.
- if (m_creatingInitialEmptyDocument)
- return;
- KURL currentURL = m_documentLoader ? m_documentLoader->url() : KURL();
- if (currentURL.isEmpty())
- return;
-
- int indentLevel = 0;
- PCLOG("--------\n Determining if page can be cached:");
-
- bool cannotCache = !logCanCacheFrameDecision(1);
-
- FrameLoadType loadType = this->loadType();
- do {
- if (m_frame->tree()->parent())
- { PCLOG(" -Frame has a parent frame"); cannotCache = true; }
- if (!m_frame->page()) {
- PCLOG(" -There is no Page object");
- cannotCache = true;
- break;
- }
- if (!m_frame->page()->backForwardList()->enabled())
- { PCLOG(" -The back/forward list is disabled"); cannotCache = true; }
- if (!(m_frame->page()->backForwardList()->capacity() > 0))
- { PCLOG(" -The back/forward list has a 0 capacity"); cannotCache = true; }
- if (!m_frame->page()->settings()->usesPageCache())
- { PCLOG(" -Page settings says b/f cache disabled"); cannotCache = true; }
- if (loadType == FrameLoadTypeReload)
- { PCLOG(" -Load type is: Reload"); cannotCache = true; }
- if (loadType == FrameLoadTypeReloadFromOrigin)
- { PCLOG(" -Load type is: Reload from origin"); cannotCache = true; }
- if (loadType == FrameLoadTypeSame)
- { PCLOG(" -Load type is: Same"); cannotCache = true; }
- } while (false);
-
- PCLOG(cannotCache ? " Page CANNOT be cached\n--------" : " Page CAN be cached\n--------");
-}
-
-bool FrameLoader::logCanCacheFrameDecision(int indentLevel)
-{
- // Only bother logging for frames that have actually loaded and have content.
- if (m_creatingInitialEmptyDocument)
- return false;
- KURL currentURL = m_documentLoader ? m_documentLoader->url() : KURL();
- if (currentURL.isEmpty())
- return false;
-
- PCLOG("+---");
- KURL newURL = m_provisionalDocumentLoader ? m_provisionalDocumentLoader->url() : KURL();
- if (!newURL.isEmpty())
- PCLOG(" Determining if frame can be cached navigating from (%s) to (%s):", currentURL.string().utf8().data(), newURL.string().utf8().data());
- else
- PCLOG(" Determining if subframe with URL (%s) can be cached:", currentURL.string().utf8().data());
-
- bool cannotCache = false;
-
- do {
- if (!m_documentLoader) {
- PCLOG(" -There is no DocumentLoader object");
- cannotCache = true;
- break;
- }
- if (!m_documentLoader->mainDocumentError().isNull())
- { PCLOG(" -Main document has an error"); cannotCache = true; }
- if (m_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()->hasEventListeners(eventNames().unloadEvent))
- { PCLOG(" -Frame has an unload event listener"); cannotCache = true; }
-#if ENABLE(DATABASE)
- if (m_frame->document()->hasOpenDatabases())
- { PCLOG(" -Frame has open database handles"); cannotCache = true; }
-#endif
-#if 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 (!history()->currentItem())
- { PCLOG(" -No current history item"); cannotCache = true; }
- if (m_quickRedirectComing)
- { PCLOG(" -Quick redirect is coming"); cannotCache = true; }
- if (m_documentLoader->isLoadingInAPISense())
- { PCLOG(" -DocumentLoader is still loading in API sense"); cannotCache = true; }
- if (m_documentLoader->isStopping())
- { PCLOG(" -DocumentLoader is in the middle of stopping"); cannotCache = true; }
- if (!m_frame->document()->canSuspendActiveDOMObjects())
- { PCLOG(" -The document cannot suspect its active DOM Objects"); cannotCache = true; }
-#if ENABLE(OFFLINE_WEB_APPLICATIONS)
- if (!m_documentLoader->applicationCacheHost()->canCacheInPageCache())
- { PCLOG(" -The DocumentLoader uses an application cache"); cannotCache = true; }
-#endif
- if (!m_client->canCachePage())
- { PCLOG(" -The client says this frame cannot be cached"); cannotCache = true; }
- } while (false);
-
- for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
- if (!child->loader()->logCanCacheFrameDecision(indentLevel + 1))
- cannotCache = true;
-
- PCLOG(cannotCache ? " Frame CANNOT be cached" : " Frame CAN be cached");
- PCLOG("+---");
-
- return !cannotCache;
-}
-#endif
-
void FrameLoader::updateFirstPartyForCookies()
{
if (m_frame->tree()->parent())
@@ -1776,7 +1158,10 @@ void FrameLoader::loadInSameDocument(const KURL& url, SerializedScriptValue* sta
history()->updateBackForwardListForFragmentScroll();
}
+ String oldURL;
bool hashChange = equalIgnoringFragmentIdentifier(url, m_URL) && url.fragmentIdentifier() != m_URL.fragmentIdentifier();
+ oldURL = m_URL;
+
m_URL = url;
history()->updateForSameDocumentNavigation();
@@ -1787,11 +1172,11 @@ void FrameLoader::loadInSameDocument(const KURL& url, SerializedScriptValue* sta
// It's important to model this as a load that starts and immediately finishes.
// Otherwise, the parent frame may think we never finished loading.
started();
-
- if (hashChange) {
- if (FrameView* view = m_frame->view())
- view->scrollToFragment(m_URL);
- }
+
+ // We need to scroll to the fragment whether or not a hash change occurred, since
+ // the user might have scrolled since the previous navigation.
+ if (FrameView* view = m_frame->view())
+ view->scrollToFragment(m_URL);
m_isComplete = false;
checkCompleted();
@@ -1803,13 +1188,13 @@ void FrameLoader::loadInSameDocument(const KURL& url, SerializedScriptValue* sta
checkLoadComplete();
}
- if (stateObject) {
- m_frame->document()->statePopped(stateObject);
- m_client->dispatchDidPopStateWithinPage();
- }
+ m_client->dispatchDidNavigateWithinPage();
+
+ m_frame->document()->statePopped(stateObject ? stateObject : SerializedScriptValue::nullValue());
+ m_client->dispatchDidPopStateWithinPage();
if (hashChange) {
- m_frame->document()->dispatchWindowEvent(Event::create(eventNames().hashchangeEvent, false, false));
+ m_frame->document()->enqueueHashchangeEvent(oldURL, url);
m_client->dispatchDidChangeLocationWithinPage();
}
@@ -1827,7 +1212,7 @@ void FrameLoader::completed()
RefPtr<Frame> protect(m_frame);
for (Frame* descendant = m_frame->tree()->traverseNext(m_frame); descendant; descendant = descendant->tree()->traverseNext(m_frame))
- descendant->redirectScheduler()->startTimer();
+ descendant->navigationScheduler()->startTimer();
if (Frame* parent = m_frame->tree()->parent())
parent->loader()->checkCompleted();
@@ -1842,11 +1227,6 @@ void FrameLoader::started()
frame->loader()->m_isComplete = false;
}
-bool FrameLoader::containsPlugins() const
-{
- return m_containsPlugIns;
-}
-
void FrameLoader::prepareForLoadStart()
{
if (Page* page = m_frame->page())
@@ -1895,9 +1275,10 @@ void FrameLoader::loadFrameRequest(const FrameLoadRequest& request, bool lockHis
referrer = m_outgoingReferrer;
ASSERT(frame()->document());
- if (SecurityOrigin::shouldTreatURLAsLocal(url.string()) && !isFeedWithNestedProtocolInHTTPFamily(url)) {
- if (!SecurityOrigin::canLoad(url, String(), frame()->document()) && !SecurityOrigin::canLoad(url, referrer, 0)) {
- FrameLoader::reportLocalLoadFailed(m_frame, url.string());
+ // FIXME: Should we move the isFeedWithNestedProtocolInHTTPFamily logic inside SecurityOrigin::canDisplay?
+ if (!isFeedWithNestedProtocolInHTTPFamily(url)) {
+ if (!frame()->document()->securityOrigin()->canDisplay(url) && !SecurityOrigin::deprecatedCanDisplay(referrer, url)) {
+ reportLocalLoadFailed(m_frame, url.string());
return;
}
}
@@ -1913,17 +1294,10 @@ void FrameLoader::loadFrameRequest(const FrameLoadRequest& request, bool lockHis
else
loadType = FrameLoadTypeStandard;
-#ifdef ANDROID_USER_GESTURE
- if (request.resourceRequest().httpMethod() == "POST")
- loadPostRequest(request.resourceRequest(), referrer, request.frameName(), lockHistory, loadType, event, formState.get(), request.resourceRequest().getUserGesture());
- else
- loadURL(request.resourceRequest().url(), referrer, request.frameName(), lockHistory, loadType, event, formState.get(), request.resourceRequest().getUserGesture());
-#else
if (request.resourceRequest().httpMethod() == "POST")
loadPostRequest(request.resourceRequest(), referrer, request.frameName(), lockHistory, loadType, event, formState.get());
else
loadURL(request.resourceRequest().url(), referrer, request.frameName(), lockHistory, loadType, event, formState.get());
-#endif
// FIXME: It's possible this targetFrame will not be the same frame that was targeted by the actual
// load if frame names have changed.
@@ -1931,29 +1305,17 @@ void FrameLoader::loadFrameRequest(const FrameLoadRequest& request, bool lockHis
Frame* targetFrame = sourceFrame->loader()->findFrameForNavigation(request.frameName());
if (targetFrame && targetFrame != sourceFrame) {
if (Page* page = targetFrame->page())
-#ifdef ANDROID_USER_GESTURE
- page->chrome()->focus(request.resourceRequest().getUserGesture());
-#else
page->chrome()->focus();
-#endif
}
}
-#ifdef ANDROID_USER_GESTURE
-void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType newLoadType,
- PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState, bool userGesture)
-#else
void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType newLoadType,
PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState)
-#endif
{
RefPtr<FormState> formState = prpFormState;
bool isFormSubmission = formState;
ResourceRequest request(newURL);
-#ifdef ANDROID_USER_GESTURE
- request.setUserGesture(userGesture);
-#endif
if (!referrer.isEmpty()) {
request.setHTTPReferrer(referrer);
RefPtr<SecurityOrigin> referrerOrigin = SecurityOrigin::createFromString(referrer);
@@ -1968,15 +1330,11 @@ void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const Stri
// The search for a target frame is done earlier in the case of form submission.
Frame* targetFrame = isFormSubmission ? 0 : findFrameForNavigation(frameName);
if (targetFrame && targetFrame != m_frame) {
-#ifdef ANDROID_USER_GESTURE
- targetFrame->loader()->loadURL(newURL, referrer, String(), lockHistory, newLoadType, event, formState.release(), userGesture);
-#else
targetFrame->loader()->loadURL(newURL, referrer, String(), lockHistory, newLoadType, event, formState.release());
-#endif
return;
}
- if (m_unloadEventBeingDispatched)
+ if (m_pageDismissalEventBeingDispatched)
return;
NavigationAction action(newURL, newLoadType, isFormSubmission, event);
@@ -2095,6 +1453,9 @@ void FrameLoader::load(DocumentLoader* newDocumentLoader)
void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType type, PassRefPtr<FormState> prpFormState)
{
+ // Retain because dispatchBeforeLoadEvent may release the last reference to it.
+ RefPtr<Frame> protect(m_frame);
+
ASSERT(m_client->hasWebView());
// Unfortunately the view must be non-nil, this is ultimately due
@@ -2102,7 +1463,7 @@ void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t
ASSERT(m_frame->view());
- if (m_unloadEventBeingDispatched)
+ if (m_pageDismissalEventBeingDispatched)
return;
policyChecker()->setLoadType(type);
@@ -2154,11 +1515,6 @@ const ResourceRequest& FrameLoader::initialRequest() const
return activeDocumentLoader()->originalRequest();
}
-void FrameLoader::receivedData(const char* data, int length)
-{
- activeDocumentLoader()->receivedData(data, length);
-}
-
bool FrameLoader::willLoadMediaElementURL(KURL& url)
{
ResourceRequest request(url);
@@ -2264,6 +1620,7 @@ static bool canAccessAncestor(const SecurityOrigin* activeSecurityOrigin, Frame*
if (!targetFrame)
return false;
+ const bool isLocalActiveOrigin = activeSecurityOrigin->isLocal();
for (Frame* ancestorFrame = targetFrame; ancestorFrame; ancestorFrame = ancestorFrame->tree()->parent()) {
Document* ancestorDocument = ancestorFrame->document();
if (!ancestorDocument)
@@ -2272,6 +1629,10 @@ static bool canAccessAncestor(const SecurityOrigin* activeSecurityOrigin, Frame*
const SecurityOrigin* ancestorSecurityOrigin = ancestorDocument->securityOrigin();
if (activeSecurityOrigin->canAccess(ancestorSecurityOrigin))
return true;
+
+ // Allow file URL descendant navigation even when allowFileAccessFromFileURLs is false.
+ if (isLocalActiveOrigin && ancestorSecurityOrigin->isLocal())
+ return true;
}
return false;
@@ -2295,16 +1656,16 @@ bool FrameLoader::shouldAllowNavigation(Frame* targetFrame) const
if (m_frame == targetFrame)
return true;
- // A sandboxed frame can only navigate itself and its descendants.
- if (isDocumentSandboxed(SandboxNavigation) && !targetFrame->tree()->isDescendantOf(m_frame))
- return false;
-
// Let a frame navigate the top-level window that contains it. This is
// important to allow because it lets a site "frame-bust" (escape from a
// frame created by another web site).
- if (targetFrame == m_frame->tree()->top())
+ if (!isDocumentSandboxed(m_frame, SandboxTopNavigation) && targetFrame == m_frame->tree()->top())
return true;
+ // A sandboxed frame can only navigate itself and its descendants.
+ if (isDocumentSandboxed(m_frame, SandboxNavigation) && !targetFrame->tree()->isDescendantOf(m_frame))
+ return false;
+
// 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;
@@ -2325,8 +1686,8 @@ bool FrameLoader::shouldAllowNavigation(Frame* targetFrame) const
if (settings && !settings->privateBrowsingEnabled()) {
Document* targetDocument = targetFrame->document();
// FIXME: this error message should contain more specifics of why the navigation change is not allowed.
- String message = String::format("Unsafe JavaScript attempt to initiate a navigation change for frame with URL %s from frame with URL %s.\n",
- targetDocument->url().string().utf8().data(), activeDocument->url().string().utf8().data());
+ String message = makeString("Unsafe JavaScript attempt to initiate a navigation change for frame with URL ",
+ targetDocument->url().string(), " from frame with URL ", activeDocument->url().string(), ".\n");
// FIXME: should we print to the console of the activeFrame as well?
targetFrame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, 1, String());
@@ -2344,7 +1705,7 @@ void FrameLoader::stopLoadingSubframes()
void FrameLoader::stopAllLoaders(DatabasePolicy databasePolicy)
{
ASSERT(!m_frame->document() || !m_frame->document()->inPageCache());
- if (m_unloadEventBeingDispatched)
+ if (m_pageDismissalEventBeingDispatched)
return;
// If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
@@ -2400,7 +1761,14 @@ bool FrameLoader::isLoading() const
bool FrameLoader::frameHasLoaded() const
{
- return m_committedFirstRealDocumentLoad || (m_provisionalDocumentLoader && !m_creatingInitialEmptyDocument);
+ return m_stateMachine.committedFirstRealDocumentLoad() || (m_provisionalDocumentLoader && !m_stateMachine.creatingInitialEmptyDocument());
+}
+
+void FrameLoader::transferLoadingResourcesFromPage(Page* oldPage)
+{
+ ASSERT(oldPage != m_frame->page());
+ if (isLoading())
+ activeDocumentLoader()->transferLoadingResourcesFromPage(oldPage);
}
void FrameLoader::setDocumentLoader(DocumentLoader* loader)
@@ -2478,22 +1846,24 @@ void FrameLoader::markLoadComplete()
setState(FrameStateComplete);
}
-void FrameLoader::commitProvisionalLoad(PassRefPtr<CachedPage> prpCachedPage)
+void FrameLoader::commitProvisionalLoad()
{
- RefPtr<CachedPage> cachedPage = prpCachedPage;
+ RefPtr<CachedPage> cachedPage = m_loadingFromCachedPage ? pageCache()->get(history()->provisionalItem()) : 0;
RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
- 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(),
+ LOG(PageCache, "WebCoreLoading %s: About to commit provisional load from previous URL '%s' to new URL '%s'", m_frame->tree()->uniqueName().string().utf8().data(), m_URL.string().utf8().data(),
pdl ? pdl->url().string().utf8().data() : "<no provisional DocumentLoader>");
// 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.
- cachePageForHistoryItem(history()->currentItem());
+ HistoryItem* item = history()->currentItem();
+ if (!m_frame->tree()->parent() && PageCache::canCache(m_frame->page()) && !item->isInPageCache())
+ pageCache()->add(item, m_frame->page());
if (m_loadType != FrameLoadTypeReplace)
closeOldDataSources();
- if (!cachedPage && !m_creatingInitialEmptyDocument)
+ if (!cachedPage && !m_stateMachine.creatingInitialEmptyDocument())
m_client->makeRepresentation(pdl.get());
transitionToCommitted(cachedPage);
@@ -2505,9 +1875,19 @@ void FrameLoader::commitProvisionalLoad(PassRefPtr<CachedPage> prpCachedPage)
if (m_sentRedirectNotification)
clientRedirectCancelledOrFinished(false);
- if (cachedPage && cachedPage->document())
- open(*cachedPage);
- else {
+ if (cachedPage && cachedPage->document()) {
+ prepareForCachedPageRestore();
+ cachedPage->restore(m_frame->page());
+
+ dispatchDidCommitLoad();
+
+ // If we have a title let the WebView know about it.
+ String title = m_documentLoader->title();
+ if (!title.isNull())
+ m_client->dispatchDidReceiveTitle(title);
+
+ checkCompleted();
+ } else {
KURL url = pdl->substituteData().responseURL();
if (url.isEmpty())
url = pdl->url();
@@ -2519,7 +1899,7 @@ void FrameLoader::commitProvisionalLoad(PassRefPtr<CachedPage> prpCachedPage)
didOpenURL(url);
}
- LOG(Loading, "WebCoreLoading %s: Finished committing provisional load to URL %s", m_frame->tree()->name().string().utf8().data(), m_URL.string().utf8().data());
+ LOG(Loading, "WebCoreLoading %s: Finished committing provisional load to URL %s", m_frame->tree()->uniqueName().string().utf8().data(), m_URL.string().utf8().data());
if (m_loadType == FrameLoadTypeStandard && m_documentLoader->isClientRedirect())
history()->updateForClientRedirect();
@@ -2586,30 +1966,34 @@ void FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage)
// Handle adding the URL to the back/forward list.
DocumentLoader* dl = m_documentLoader.get();
- String ptitle = dl->title();
switch (m_loadType) {
case FrameLoadTypeForward:
case FrameLoadTypeBack:
case FrameLoadTypeBackWMLDeckNotAccessible:
case FrameLoadTypeIndexedBackForward:
- if (Page* page = m_frame->page()) {
- if (page->backForwardList()) {
- history()->updateForBackForwardNavigation();
-
- if (history()->currentItem())
- m_pendingStateObject = history()->currentItem()->stateObject();
-
- // Create a document view for this document, or used the cached view.
- if (cachedPage) {
- DocumentLoader* cachedDocumentLoader = cachedPage->documentLoader();
- ASSERT(cachedDocumentLoader);
- cachedDocumentLoader->setFrame(m_frame);
- m_client->transitionToCommittedFromCachedFrame(cachedPage->cachedMainFrame());
-
- } else
- m_client->transitionToCommittedForNewPage();
- }
+ if (m_frame->page()) {
+ // If the first load within a frame is a navigation within a back/forward list that was attached
+ // without any of the items being loaded then we need to update the history in a similar manner as
+ // for a standard load with the exception of updating the back/forward list (<rdar://problem/8091103>).
+ if (!m_stateMachine.committedFirstRealDocumentLoad())
+ history()->updateForStandardLoad(HistoryController::UpdateAllExceptBackForwardList);
+
+ history()->updateForBackForwardNavigation();
+
+ // For cached pages, CachedFrame::restore will take care of firing the popstate event with the history item's state object
+ if (history()->currentItem() && !cachedPage)
+ m_pendingStateObject = history()->currentItem()->stateObject();
+
+ // Create a document view for this document, or used the cached view.
+ if (cachedPage) {
+ DocumentLoader* cachedDocumentLoader = cachedPage->documentLoader();
+ ASSERT(cachedDocumentLoader);
+ cachedDocumentLoader->setFrame(m_frame);
+ m_client->transitionToCommittedFromCachedFrame(cachedPage->cachedMainFrame());
+
+ } else
+ m_client->transitionToCommittedForNewPage();
}
break;
@@ -2643,26 +2027,19 @@ void FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage)
ASSERT_NOT_REACHED();
}
- m_responseMIMEType = dl->responseMIMEType();
+ writer()->setMIMEType(dl->responseMIMEType());
// Tell the client we've committed this URL.
ASSERT(m_frame->view());
- if (m_creatingInitialEmptyDocument)
+ if (m_stateMachine.creatingInitialEmptyDocument())
return;
-
- m_committedFirstRealDocumentLoad = true;
+
+ if (!m_stateMachine.committedFirstRealDocumentLoad())
+ m_stateMachine.advanceTo(FrameLoaderStateMachine::DisplayingInitialEmptyDocumentPostCommit);
if (!m_client->hasHTMLView())
receivedFirstData();
- else if (cachedPage) {
- // For non-cached HTML pages, these methods are called in receivedFirstData().
- dispatchDidCommitLoad();
-
- // If we have a title let the WebView know about it.
- if (!ptitle.isNull())
- m_client->dispatchDidReceiveTitle(ptitle);
- }
}
void FrameLoader::clientRedirectCancelledOrFinished(bool cancelWithLoadInProgress)
@@ -2690,7 +2067,7 @@ void FrameLoader::clientRedirected(const KURL& url, double seconds, double fireD
// load as part of the original navigation. If we don't have a document loader, we have
// no "original" load on which to base a redirect, so we treat the redirect as a normal load.
// Loads triggered by JavaScript form submissions never count as quick redirects.
- m_quickRedirectComing = lockBackForwardList && m_documentLoader && !m_isExecutingJavaScriptFormAction;
+ m_quickRedirectComing = (lockBackForwardList || history()->currentItemShouldBeReplaced()) && m_documentLoader && !m_isExecutingJavaScriptFormAction;
}
bool FrameLoader::shouldReload(const KURL& currentURL, const KURL& destinationURL)
@@ -2723,26 +2100,24 @@ void FrameLoader::closeOldDataSources()
m_client->setMainFrameDocumentReady(false); // stop giving out the actual DOMDocument to observers
}
-void FrameLoader::open(CachedPage& cachedPage)
+void FrameLoader::prepareForCachedPageRestore()
{
ASSERT(!m_frame->tree()->parent());
ASSERT(m_frame->page());
ASSERT(m_frame->page()->mainFrame() == m_frame);
- m_frame->redirectScheduler()->cancel();
+ m_frame->navigationScheduler()->cancel();
// We still have to close the previous part page.
closeURL();
// Delete old status bar messages (if it _was_ activated on last URL).
- if (m_frame->script()->canExecuteScripts()) {
- m_frame->setJSStatusBarText(String());
- m_frame->setJSDefaultStatusBarText(String());
+ if (m_frame->script()->canExecuteScripts(NotAboutToExecuteScript)) {
+ if (DOMWindow* window = m_frame->existingDOMWindow()) {
+ window->setStatus(String());
+ window->setDefaultStatus(String());
+ }
}
-
- cachedPage.restore(m_frame->page());
-
- checkCompleted();
}
void FrameLoader::open(CachedFrameBase& cachedFrame)
@@ -2788,7 +2163,7 @@ void FrameLoader::open(CachedFrameBase& cachedFrame)
m_frame->domWindow()->setURL(document->url());
m_frame->domWindow()->setSecurityOrigin(document->securityOrigin());
- m_decoder = document->decoder();
+ writer()->setDecoder(document->decoder());
updateFirstPartyForCookies();
@@ -2812,6 +2187,10 @@ void FrameLoader::finishedLoading()
dl->setPrimaryLoadComplete(true);
m_client->dispatchDidLoadMainResource(dl.get());
checkLoadComplete();
+
+ DOMWindow* window = m_frame->existingDOMWindow();
+ if (window && window->printDeferred())
+ window->print();
}
bool FrameLoader::isHostedByObjectElement() const
@@ -2850,7 +2229,7 @@ void FrameLoader::finishedLoadingDocument(DocumentLoader* loader)
{
// FIXME: Platforms shouldn't differ here!
#if PLATFORM(WIN) || PLATFORM(CHROMIUM) || defined(ANDROID)
- if (m_creatingInitialEmptyDocument)
+ if (m_stateMachine.creatingInitialEmptyDocument())
return;
#endif
@@ -2876,23 +2255,23 @@ void FrameLoader::finishedLoadingDocument(DocumentLoader* loader)
if (!archive)
return;
- loader->addAllArchiveResources(archive.get());
+ // FIXME: The remainder of this function should be in DocumentLoader.
+ loader->addAllArchiveResources(archive.get());
+
ArchiveResource* mainResource = archive->mainResource();
loader->setParsedArchiveData(mainResource->data());
- m_responseMIMEType = mainResource->mimeType();
+ writer()->setMIMEType(mainResource->mimeType());
closeURL();
didOpenURL(mainResource->url());
+ ASSERT(m_frame->document());
String userChosenEncoding = documentLoader()->overrideEncoding();
bool encodingIsUserChosen = !userChosenEncoding.isNull();
- setEncoding(encodingIsUserChosen ? userChosenEncoding : mainResource->textEncoding(), encodingIsUserChosen);
-
- ASSERT(m_frame->document());
-
- addData(mainResource->data()->data(), mainResource->data()->size());
+ writer()->setEncoding(encodingIsUserChosen ? userChosenEncoding : mainResource->textEncoding(), encodingIsUserChosen);
+ writer()->addData(mainResource->data()->data(), mainResource->data()->size());
#else
m_client->finishedLoading(loader);
#endif // ARCHIVE
@@ -2924,6 +2303,9 @@ bool FrameLoader::subframeIsLoading() const
documentLoader = childLoader->provisionalDocumentLoader();
if (documentLoader && documentLoader->isLoadingInAPISense())
return true;
+ documentLoader = childLoader->policyDocumentLoader();
+ if (documentLoader)
+ return true;
}
return false;
}
@@ -3021,7 +2403,7 @@ void FrameLoader::checkLoadCompleteForThisFrame()
}
if (shouldReset && item)
if (Page* page = m_frame->page()) {
- page->backForwardList()->goToItem(item.get());
+ page->backForward()->setCurrentItem(item.get());
Settings* settings = m_frame->settings();
page->setGlobalHistoryItem((!settings || settings->privateBrowsingEnabled()) ? 0 : item.get());
}
@@ -3042,11 +2424,12 @@ void FrameLoader::checkLoadCompleteForThisFrame()
m_client->forceLayoutForNonHTML();
// If the user had a scroll point, scroll to it, overriding the anchor point if any.
- if (Page* page = m_frame->page())
- if ((isBackForwardLoadType(m_loadType) || m_loadType == FrameLoadTypeReload || m_loadType == FrameLoadTypeReloadFromOrigin) && page->backForwardList())
+ if (m_frame->page()) {
+ if (isBackForwardLoadType(m_loadType) || m_loadType == FrameLoadTypeReload || m_loadType == FrameLoadTypeReloadFromOrigin)
history()->restoreScrollPositionAndViewState();
+ }
- if (m_creatingInitialEmptyDocument || !m_committedFirstRealDocumentLoad)
+ if (m_stateMachine.creatingInitialEmptyDocument() || !m_stateMachine.committedFirstRealDocumentLoad())
return;
const ResourceError& error = dl->mainDocumentError();
@@ -3103,17 +2486,20 @@ void FrameLoader::continueLoadAfterWillSubmitForm()
notifier()->assignIdentifierToInitialRequest(identifier, m_provisionalDocumentLoader.get(), m_provisionalDocumentLoader->originalRequest());
}
+ ASSERT(!m_provisionalDocumentLoader->timing()->navigationStart);
+ m_provisionalDocumentLoader->timing()->navigationStart = currentTime();
+
if (!m_provisionalDocumentLoader->startLoadingMainResource(identifier))
m_provisionalDocumentLoader->updateLoading();
}
void FrameLoader::didFirstLayout()
{
- if (Page* page = m_frame->page())
- if (isBackForwardLoadType(m_loadType) && page->backForwardList())
- history()->restoreScrollPositionAndViewState();
+ if (m_frame->page() && isBackForwardLoadType(m_loadType))
+ history()->restoreScrollPositionAndViewState();
- m_firstLayoutDone = true;
+ if (m_stateMachine.committedFirstRealDocumentLoad() && !m_stateMachine.isDisplayingInitialEmptyDocument() && !m_stateMachine.firstLayoutDone())
+ m_stateMachine.advanceTo(FrameLoaderStateMachine::FirstLayoutDone);
m_client->dispatchDidFirstLayout();
}
@@ -3132,13 +2518,8 @@ void FrameLoader::frameLoadCompleted()
// After a canceled provisional load, firstLayoutDone is false.
// Reset it to true if we're displaying a page.
- if (m_documentLoader)
- m_firstLayoutDone = true;
-}
-
-bool FrameLoader::firstLayoutDone() const
-{
- return m_firstLayoutDone;
+ if (m_documentLoader && m_stateMachine.committedFirstRealDocumentLoad() && !m_stateMachine.isDisplayingInitialEmptyDocument() && !m_stateMachine.firstLayoutDone())
+ m_stateMachine.advanceTo(FrameLoaderStateMachine::FirstLayoutDone);
}
void FrameLoader::detachChildren()
@@ -3158,6 +2539,7 @@ void FrameLoader::closeAndRemoveChild(Frame* child)
child->setView(0);
if (child->ownerElement() && child->page())
child->page()->decrementFrameCount();
+ // FIXME: The page isn't being destroyed, so it's not right to call a function named pageDestroyed().
child->pageDestroyed();
m_frame->tree()->removeChild(child);
@@ -3206,18 +2588,16 @@ String FrameLoader::userAgent(const KURL& url) const
return m_client->userAgent(url);
}
-void FrameLoader::tokenizerProcessedData()
-{
- checkCompleted();
-}
-
void FrameLoader::handledOnloadEvents()
{
m_client->dispatchDidHandleOnloadEvents();
+
+ if (documentLoader()) {
+ documentLoader()->handledOnloadEvents();
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
- if (documentLoader())
documentLoader()->applicationCacheHost()->stopDeferringEvents();
#endif
+ }
}
void FrameLoader::frameDetached()
@@ -3232,9 +2612,12 @@ void FrameLoader::detachFromParent()
RefPtr<Frame> protect(m_frame);
closeURL();
- stopAllLoaders();
history()->saveScrollPositionAndViewStateToItem(history()->currentItem());
detachChildren();
+ // stopAllLoaders() needs to be called after detachChildren(), because detachedChildren()
+ // will trigger the unload event handlers of any child frames, and those event
+ // handlers might start a new subresource load in this frame.
+ stopAllLoaders();
#if ENABLE(INSPECTOR)
if (Page* page = m_frame->page())
@@ -3248,6 +2631,7 @@ void FrameLoader::detachFromParent()
parent->loader()->scheduleCheckCompleted();
} else {
m_frame->setView(0);
+ // FIXME: The page isn't being destroyed, so it's not right to call a function named pageDestroyed().
m_frame->pageDestroyed();
}
}
@@ -3286,15 +2670,33 @@ void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, FrameLoadTyp
applyUserAgent(request);
- if (loadType == FrameLoadTypeReload) {
- request.setCachePolicy(ReloadIgnoringCacheData);
- request.setHTTPHeaderField("Cache-Control", "max-age=0");
- } else if (loadType == FrameLoadTypeReloadFromOrigin) {
+ // If we inherit cache policy from a main resource, we use the DocumentLoader's
+ // original request cache policy for two reasons:
+ // 1. For POST requests, we mutate the cache policy for the main resource,
+ // but we do not want this to apply to subresources
+ // 2. Delegates that modify the cache policy using willSendRequest: should
+ // not affect any other resources. Such changes need to be done
+ // per request.
+ if (!mainResource) {
+ if (request.isConditional())
+ request.setCachePolicy(ReloadIgnoringCacheData);
+ else if (documentLoader()->isLoadingInAPISense())
+ request.setCachePolicy(documentLoader()->originalRequest().cachePolicy());
+ else
+ request.setCachePolicy(UseProtocolCachePolicy);
+ } else if (loadType == FrameLoadTypeReload || loadType == FrameLoadTypeReloadFromOrigin || request.isConditional())
request.setCachePolicy(ReloadIgnoringCacheData);
- request.setHTTPHeaderField("Cache-Control", "no-cache");
- request.setHTTPHeaderField("Pragma", "no-cache");
- } else if (isBackForwardLoadType(loadType) && !request.url().protocolIs("https"))
+ else if (isBackForwardLoadType(loadType) && m_stateMachine.committedFirstRealDocumentLoad() && !request.url().protocolIs("https"))
request.setCachePolicy(ReturnCacheDataElseLoad);
+
+ if (request.cachePolicy() == ReloadIgnoringCacheData) {
+ if (loadType == FrameLoadTypeReload)
+ request.setHTTPHeaderField("Cache-Control", "max-age=0");
+ else if (loadType == FrameLoadTypeReloadFromOrigin) {
+ request.setHTTPHeaderField("Cache-Control", "no-cache");
+ request.setHTTPHeaderField("Pragma", "no-cache");
+ }
+ }
if (mainResource)
request.setHTTPAccept(defaultAcceptHeader);
@@ -3305,7 +2707,7 @@ void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, FrameLoadTyp
// Always try UTF-8. If that fails, try frame encoding (if any) and then the default.
// For a newly opened frame with an empty URL, encoding() should not be used, because this methods asks decoder, which uses ISO-8859-1.
Settings* settings = m_frame->settings();
- request.setResponseContentDispositionEncodingFallbackArray("UTF-8", m_URL.isEmpty() ? m_encoding : encoding(), settings ? settings->defaultTextEncodingName() : String());
+ request.setResponseContentDispositionEncodingFallbackArray("UTF-8", writer()->deprecatedFrameEncoding(), settings ? settings->defaultTextEncodingName() : String());
}
void FrameLoader::addHTTPOriginIfNeeded(ResourceRequest& request, String origin)
@@ -3334,20 +2736,7 @@ void FrameLoader::addHTTPOriginIfNeeded(ResourceRequest& request, String origin)
request.setHTTPOrigin(origin);
}
-void FrameLoader::committedLoad(DocumentLoader* loader, const char* data, int length)
-{
-#if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size
- if (ArchiveFactory::isArchiveMimeType(loader->response().mimeType()))
- return;
-#endif
- m_client->committedLoad(loader, data, length);
-}
-
-#ifdef ANDROID_USER_GESTURE
-void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType loadType, PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState, bool userGesture)
-#else
void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String& referrer, const String& frameName, bool lockHistory, FrameLoadType loadType, PassRefPtr<Event> event, PassRefPtr<FormState> prpFormState)
-#endif
{
RefPtr<FormState> formState = prpFormState;
@@ -3367,9 +2756,6 @@ void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String
String origin = inRequest.httpOrigin();
ResourceRequest workingResourceRequest(url);
-#ifdef ANDROID_USER_GESTURE
- workingResourceRequest.setUserGesture(userGesture);
-#endif
if (!referrer.isEmpty())
workingResourceRequest.setHTTPReferrer(referrer);
@@ -3400,17 +2786,6 @@ unsigned long FrameLoader::loadResourceSynchronously(const ResourceRequest& requ
ResourceRequest initialRequest = request;
initialRequest.setTimeoutInterval(10);
- // Use the original request's cache policy for two reasons:
- // 1. For POST requests, we mutate the cache policy for the main resource,
- // but we do not want this to apply to subresources
- // 2. Delegates that modify the cache policy using willSendRequest: should
- // not affect any other resources. Such changes need to be done
- // per request.
- if (initialRequest.isConditional())
- initialRequest.setCachePolicy(ReloadIgnoringCacheData);
- else
- initialRequest.setCachePolicy(originalRequest().cachePolicy());
-
if (!referrer.isEmpty())
initialRequest.setHTTPReferrer(referrer);
addHTTPOriginIfNeeded(initialRequest, outgoingOrigin());
@@ -3418,6 +2793,8 @@ unsigned long FrameLoader::loadResourceSynchronously(const ResourceRequest& requ
if (Page* page = m_frame->page())
initialRequest.setFirstPartyForCookies(page->mainFrame()->loader()->documentLoader()->request().url());
initialRequest.setHTTPUserAgent(client()->userAgent(request.url()));
+
+ addExtraFieldsToSubresourceRequest(initialRequest);
unsigned long identifier = 0;
ResourceRequest newRequest(initialRequest);
@@ -3429,7 +2806,7 @@ unsigned long FrameLoader::loadResourceSynchronously(const ResourceRequest& requ
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
if (!documentLoader()->applicationCacheHost()->maybeLoadSynchronously(newRequest, error, response, data)) {
#endif
- ResourceHandle::loadResourceSynchronously(newRequest, storedCredentials, error, response, data, m_frame);
+ ResourceHandle::loadResourceSynchronously(networkingContext(), newRequest, storedCredentials, error, response, data);
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
documentLoader()->applicationCacheHost()->maybeLoadFallbackSynchronously(newRequest, error, response, data);
}
@@ -3526,6 +2903,36 @@ void FrameLoader::callContinueLoadAfterNavigationPolicy(void* argument,
loader->continueLoadAfterNavigationPolicy(request, formState, shouldContinue);
}
+bool FrameLoader::shouldClose()
+{
+ Page* page = m_frame->page();
+ Chrome* chrome = page ? page->chrome() : 0;
+ if (!chrome || !chrome->canRunBeforeUnloadConfirmPanel())
+ return true;
+
+ DOMWindow* domWindow = m_frame->existingDOMWindow();
+ if (!domWindow)
+ return true;
+
+ RefPtr<Document> document = m_frame->document();
+ HTMLElement* body = document->body();
+ if (!body)
+ return true;
+
+ RefPtr<BeforeUnloadEvent> beforeUnloadEvent = BeforeUnloadEvent::create();
+ m_pageDismissalEventBeingDispatched = true;
+ domWindow->dispatchEvent(beforeUnloadEvent.get(), domWindow->document());
+ m_pageDismissalEventBeingDispatched = false;
+
+ if (!beforeUnloadEvent->defaultPrevented())
+ document->defaultEventHandler(beforeUnloadEvent.get());
+ if (beforeUnloadEvent->result().isNull())
+ return true;
+
+ String text = document->displayStringModifiedByEncoding(beforeUnloadEvent->result());
+ return chrome->runBeforeUnloadConfirmPanel(text, m_frame);
+}
+
void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, PassRefPtr<FormState> formState, bool shouldContinue)
{
// If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
@@ -3540,7 +2947,7 @@ void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, Pass
// is the user responding Cancel to the form repost nag sheet.
// 2) User responded Cancel to an alert popped up by the before unload event handler.
// The "before unload" event handler runs only for the main frame.
- bool canContinue = shouldContinue && (!isLoadingMainFrame() || m_frame->shouldClose());
+ bool canContinue = shouldContinue && (!isLoadingMainFrame() || shouldClose());
if (!canContinue) {
// If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we
@@ -3557,7 +2964,7 @@ void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, Pass
if (Page* page = m_frame->page()) {
Frame* mainFrame = page->mainFrame();
if (HistoryItem* resetItem = mainFrame->loader()->history()->currentItem()) {
- page->backForwardList()->goToItem(resetItem);
+ page->backForward()->setCurrentItem(resetItem);
Settings* settings = m_frame->settings();
page->setGlobalHistoryItem((!settings || settings->privateBrowsingEnabled()) ? 0 : resetItem);
}
@@ -3576,7 +2983,7 @@ void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, Pass
#if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR) && USE(JSC)
if (Page* page = m_frame->page()) {
if (page->mainFrame() == m_frame)
- page->inspectorController()->resumeDebugger();
+ page->inspectorController()->resume();
}
#endif
@@ -3586,8 +2993,10 @@ void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, Pass
setPolicyDocumentLoader(0);
- if (isBackForwardLoadType(type) && loadProvisionalItemFromCachedPage())
+ if (isBackForwardLoadType(type) && history()->provisionalItem()->isInPageCache()) {
+ loadProvisionalItemFromCachedPage();
return;
+ }
if (formState)
m_client->dispatchWillSubmitForm(&PolicyChecker::continueLoadAfterWillSubmitForm, formState);
@@ -3596,20 +3005,20 @@ void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest&, Pass
}
void FrameLoader::callContinueLoadAfterNewWindowPolicy(void* argument,
- const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, bool shouldContinue)
+ const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue)
{
FrameLoader* loader = static_cast<FrameLoader*>(argument);
- loader->continueLoadAfterNewWindowPolicy(request, formState, frameName, shouldContinue);
+ loader->continueLoadAfterNewWindowPolicy(request, formState, frameName, action, shouldContinue);
}
void FrameLoader::continueLoadAfterNewWindowPolicy(const ResourceRequest& request,
- PassRefPtr<FormState> formState, const String& frameName, bool shouldContinue)
+ PassRefPtr<FormState> formState, const String& frameName, const NavigationAction& action, bool shouldContinue)
{
if (!shouldContinue)
return;
RefPtr<Frame> frame = m_frame;
- RefPtr<Frame> mainFrame = m_client->dispatchCreatePage();
+ RefPtr<Frame> mainFrame = m_client->dispatchCreatePage(action);
if (!mainFrame)
return;
@@ -3650,14 +3059,13 @@ 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;
if (!page->areMemoryCacheClientCallsEnabled()) {
+#if ENABLE(INSPECTOR)
+ page->inspectorController()->didLoadResourceFromMemoryCache(m_documentLoader.get(), resource);
+#endif
m_documentLoader->recordMemoryCacheLoadForFutureClientNotification(resource->url());
m_documentLoader->didTellClientAboutLoad(resource->url());
return;
@@ -3665,6 +3073,9 @@ void FrameLoader::loadedResourceFromMemoryCache(const CachedResource* resource)
ResourceRequest request(resource->url());
if (m_client->dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(), request, resource->response(), resource->encodedSize())) {
+#if ENABLE(INSPECTOR)
+ page->inspectorController()->didLoadResourceFromMemoryCache(m_documentLoader.get(), resource);
+#endif
m_documentLoader->didTellClientAboutLoad(resource->url());
return;
}
@@ -3672,6 +3083,9 @@ void FrameLoader::loadedResourceFromMemoryCache(const CachedResource* resource)
unsigned long identifier;
ResourceError error;
requestFromDelegate(request, identifier, error);
+#if ENABLE(INSPECTOR)
+ page->inspectorController()->markResourceAsCached(identifier);
+#endif
notifier()->sendRemainingDelegateMessages(m_documentLoader.get(), identifier, resource->response(), resource->encodedSize(), error);
}
@@ -3700,48 +3114,22 @@ bool FrameLoader::shouldInterruptLoadForXFrameOptions(const String& content, con
return false;
}
-bool FrameLoader::loadProvisionalItemFromCachedPage()
+void FrameLoader::loadProvisionalItemFromCachedPage()
{
- RefPtr<CachedPage> cachedPage = pageCache()->get(history()->provisionalItem());
- if (!cachedPage || !cachedPage->document())
- return false;
+ DocumentLoader* provisionalLoader = provisionalDocumentLoader();
+ LOG(PageCache, "WebCorePageCache: Loading provisional DocumentLoader %p with URL '%s' from CachedPage", provisionalDocumentLoader(), provisionalDocumentLoader()->url().string().utf8().data());
- 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;
-}
-
-void FrameLoader::cachePageForHistoryItem(HistoryItem* item)
-{
- if (!canCachePage() || item->isInPageCache())
- return;
-
- pageHidden();
- if (Page* page = m_frame->page()) {
- RefPtr<CachedPage> 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;
+ // Should have timing data from previous time(s) the page was shown.
+ ASSERT(provisionalLoader->timing()->navigationStart);
+ provisionalLoader->resetTiming();
+ provisionalLoader->timing()->navigationStart = currentTime();
- // Send pagehide event for subframes as well
- for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
- child->loader()->pageHidden();
+ provisionalLoader->setCommitted(true);
+ commitProvisionalLoad();
}
bool FrameLoader::shouldTreatURLAsSameAsCurrent(const KURL& url) const
@@ -3757,7 +3145,7 @@ void FrameLoader::checkDidPerformFirstNavigation()
if (!page)
return;
- if (!m_didPerformFirstNavigation && page->backForwardList()->entries().size() == 1) {
+ if (!m_didPerformFirstNavigation && page->backForward()->currentItem() && !page->backForward()->backItem() && !page->backForward()->forwardItem()) {
m_didPerformFirstNavigation = true;
m_client->didPerformFirstNavigation();
}
@@ -3767,7 +3155,7 @@ Frame* FrameLoader::findFrameForNavigation(const AtomicString& name)
{
Frame* frame = m_frame->tree()->find(name);
if (!shouldAllowNavigation(frame))
- return 0;
+ return 0;
return frame;
}
@@ -3797,21 +3185,10 @@ void FrameLoader::navigateToDifferentDocument(HistoryItem* item, FrameLoadType l
{
// Remember this item so we can traverse any child items as child frames load
history()->setProvisionalItem(item);
-
- // Check if we'll be using the page cache. We only use the page cache
- // if one exists and it is less than _backForwardCacheExpirationInterval
- // seconds old. If the cache is expired it gets flushed here.
- if (RefPtr<CachedPage> cachedPage = pageCache()->get(item)) {
- // FIXME: 1800 should not be hardcoded, it should come from
- // WebKitBackForwardCacheExpirationIntervalKey in WebKit.
- // Or we should remove WebKitBackForwardCacheExpirationIntervalKey.
- if (currentTime() - cachedPage->timeStamp() <= 1800) {
- loadWithDocumentLoader(cachedPage->documentLoader(), loadType, 0);
- return;
- }
-
- LOG(PageCache, "Not restoring page for %s from back/forward cache because cache entry has expired", history()->provisionalItem()->url().string().ascii().data());
- pageCache()->remove(item);
+
+ if (CachedPage* cachedPage = pageCache()->get(item)) {
+ loadWithDocumentLoader(cachedPage->documentLoader(), loadType, 0);
+ return;
}
KURL itemURL = item->url();
@@ -3830,7 +3207,7 @@ void FrameLoader::navigateToDifferentDocument(HistoryItem* item, FrameLoadType l
// If this was a repost that failed the page cache, we might try to repost the form.
NavigationAction action;
if (formData) {
- formData->generateFiles(m_frame->page()->chrome()->client());
+ formData->generateFiles(m_frame->document());
request.setHTTPMethod("POST");
request.setHTTPBody(formData);
@@ -3867,7 +3244,9 @@ void FrameLoader::navigateToDifferentDocument(HistoryItem* item, FrameLoadType l
case FrameLoadTypeBackWMLDeckNotAccessible:
case FrameLoadTypeForward:
case FrameLoadTypeIndexedBackForward:
- if (!itemURL.protocolIs("https"))
+ // If the first load within a frame is a navigation within a back/forward list that was attached
+ // without any of the items being loaded then we should use the default caching policy (<rdar://problem/8131355>).
+ if (m_stateMachine.committedFirstRealDocumentLoad() && !itemURL.protocolIs("https"))
request.setCachePolicy(ReturnCacheDataElseLoad);
break;
case FrameLoadTypeStandard:
@@ -3890,13 +3269,8 @@ void FrameLoader::navigateToDifferentDocument(HistoryItem* item, FrameLoadType l
// Loads content into this frame, as specified by history item
void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType)
{
- // We do same-document navigation in the following cases:
- // - The HistoryItem has a history state object
- // - Navigating to an anchor within the page, with no form data stored on the target item or the current history entry,
- // and the URLs in the frame tree match the history item for fragment scrolling.
HistoryItem* currentItem = history()->currentItem();
- bool sameDocumentNavigation = (!item->formData() && !(currentItem && currentItem->formData()) && history()->urlsMatchItem(item))
- || (currentItem && item->documentSequenceNumber() == currentItem->documentSequenceNumber());
+ bool sameDocumentNavigation = currentItem && item->shouldDoSameDocumentNavigationTo(currentItem);
#if ENABLE(WML)
// All WML decks should go through the real load mechanism, not the scroll-to-anchor code
@@ -3961,11 +3335,23 @@ bool FrameLoader::shouldUseCredentialStorage(ResourceLoader* loader)
return m_client->shouldUseCredentialStorage(loader->documentLoader(), loader->identifier());
}
+#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
+bool FrameLoader::canAuthenticateAgainstProtectionSpace(ResourceLoader* loader, const ProtectionSpace& protectionSpace)
+{
+ return m_client->canAuthenticateAgainstProtectionSpace(loader->documentLoader(), loader->identifier(), protectionSpace);
+}
+#endif
+
void FrameLoader::setTitle(const String& title)
{
documentLoader()->setTitle(title);
}
+void FrameLoader::setIconURL(const String& iconURL)
+{
+ documentLoader()->setIconURL(iconURL);
+}
+
KURL FrameLoader::originalRequestURL() const
{
return activeDocumentLoader()->originalRequest().url();
@@ -3973,7 +3359,7 @@ KURL FrameLoader::originalRequestURL() const
String FrameLoader::referrer() const
{
- return documentLoader()->request().httpReferrer();
+ return m_documentLoader ? m_documentLoader->request().httpReferrer() : "";
}
void FrameLoader::dispatchDocumentElementAvailable()
@@ -3984,7 +3370,7 @@ void FrameLoader::dispatchDocumentElementAvailable()
void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds()
{
- if (!m_frame->script()->canExecuteScripts())
+ if (!m_frame->script()->canExecuteScripts(NotAboutToExecuteScript))
return;
Vector<DOMWrapperWorld*> worlds;
@@ -3995,7 +3381,7 @@ void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds()
void FrameLoader::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld* world)
{
- if (!m_frame->script()->canExecuteScripts() || !m_frame->script()->existingWindowShell(world))
+ if (!m_frame->script()->canExecuteScripts(NotAboutToExecuteScript) || !m_frame->script()->existingWindowShell(world))
return;
m_client->dispatchDidClearWindowObjectInWorld(world);
@@ -4007,15 +3393,13 @@ void FrameLoader::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld* world)
if (Page* page = m_frame->page()) {
if (InspectorController* inspector = page->inspectorController())
inspector->inspectedWindowScriptObjectCleared(m_frame);
- if (InspectorController* inspector = page->parentInspectorController())
- inspector->windowScriptObjectAvailable();
}
#endif
}
void FrameLoader::updateSandboxFlags()
{
- SandboxFlags flags = SandboxNone;
+ SandboxFlags flags = m_forcedSandboxFlags;
if (Frame* parentFrame = m_frame->tree()->parent())
flags |= parentFrame->loader()->sandboxFlags();
if (HTMLFrameOwnerElement* ownerElement = m_frame->ownerElement())
@@ -4030,47 +3414,6 @@ void FrameLoader::updateSandboxFlags()
child->loader()->updateSandboxFlags();
}
-bool FrameLoader::isDocumentSandboxed(SandboxFlags mask) const
-{
- return m_frame->document() && m_frame->document()->securityOrigin()->isSandboxed(mask);
-}
-
-PassRefPtr<Widget> FrameLoader::createJavaAppletWidget(const IntSize& size, HTMLAppletElement* element, const HashMap<String, String>& args)
-{
- String baseURLString;
- String codeBaseURLString;
- Vector<String> paramNames;
- Vector<String> paramValues;
- HashMap<String, String>::const_iterator end = args.end();
- for (HashMap<String, String>::const_iterator it = args.begin(); it != end; ++it) {
- if (equalIgnoringCase(it->first, "baseurl"))
- baseURLString = it->second;
- else if (equalIgnoringCase(it->first, "codebase"))
- codeBaseURLString = it->second;
- paramNames.append(it->first);
- paramValues.append(it->second);
- }
-
- if (!codeBaseURLString.isEmpty()) {
- KURL codeBaseURL = completeURL(codeBaseURLString);
- if (!SecurityOrigin::canLoad(codeBaseURL, String(), element->document())) {
- FrameLoader::reportLocalLoadFailed(m_frame, codeBaseURL.string());
- return 0;
- }
- }
-
- if (baseURLString.isEmpty())
- baseURLString = m_frame->document()->baseURL().string();
- KURL baseURL = completeURL(baseURLString);
-
- RefPtr<Widget> widget = m_client->createJavaAppletWidget(size, element, baseURL, paramNames, paramValues);
- if (!widget)
- return 0;
-
- m_containsPlugIns = true;
- return widget;
-}
-
void FrameLoader::didChangeTitle(DocumentLoader* loader)
{
m_client->didChangeTitle(loader);
@@ -4085,9 +3428,15 @@ void FrameLoader::didChangeTitle(DocumentLoader* loader)
}
}
+void FrameLoader::didChangeIcons(DocumentLoader* loader)
+{
+ if (loader == m_documentLoader)
+ m_client->dispatchDidChangeIcons();
+}
+
void FrameLoader::dispatchDidCommitLoad()
{
- if (m_creatingInitialEmptyDocument)
+ if (m_stateMachine.creatingInitialEmptyDocument())
return;
#ifndef NDEBUG
@@ -4129,9 +3478,80 @@ void FrameLoader::tellClientAboutPastMemoryCacheLoads()
}
}
+NetworkingContext* FrameLoader::networkingContext() const
+{
+ return m_networkingContext.get();
+}
+
bool FrameLoaderClient::hasHTMLView() const
{
return true;
}
+Frame* createWindow(Frame* openerFrame, Frame* lookupFrame, const FrameLoadRequest& request, const WindowFeatures& features, bool& created)
+{
+ ASSERT(!features.dialog || request.frameName().isEmpty());
+
+ if (!request.frameName().isEmpty() && request.frameName() != "_blank") {
+ Frame* frame = lookupFrame->tree()->find(request.frameName());
+ if (frame && openerFrame->loader()->shouldAllowNavigation(frame)) {
+ if (!request.resourceRequest().url().isEmpty())
+ frame->loader()->loadFrameRequest(request, false, false, 0, 0, SendReferrer);
+ if (Page* page = frame->page())
+ page->chrome()->focus();
+ created = false;
+ return frame;
+ }
+ }
+
+ // Sandboxed frames cannot open new auxiliary browsing contexts.
+ if (isDocumentSandboxed(openerFrame, SandboxNavigation))
+ return 0;
+
+ // FIXME: Setting the referrer should be the caller's responsibility.
+ FrameLoadRequest requestWithReferrer = request;
+ requestWithReferrer.resourceRequest().setHTTPReferrer(openerFrame->loader()->outgoingReferrer());
+ FrameLoader::addHTTPOriginIfNeeded(requestWithReferrer.resourceRequest(), openerFrame->loader()->outgoingOrigin());
+
+ Page* oldPage = openerFrame->page();
+ if (!oldPage)
+ return 0;
+
+ NavigationAction action;
+ Page* page = oldPage->chrome()->createWindow(openerFrame, requestWithReferrer, features, action);
+ if (!page)
+ return 0;
+
+ Frame* frame = page->mainFrame();
+ if (request.frameName() != "_blank")
+ frame->tree()->setName(request.frameName());
+
+ page->chrome()->setToolbarsVisible(features.toolBarVisible || features.locationBarVisible);
+ page->chrome()->setStatusbarVisible(features.statusBarVisible);
+ page->chrome()->setScrollbarsVisible(features.scrollbarsVisible);
+ page->chrome()->setMenubarVisible(features.menuBarVisible);
+ page->chrome()->setResizable(features.resizable);
+
+ // 'x' and 'y' specify the location of the window, while 'width' and 'height'
+ // specify the size of the page. We can only resize the window, so
+ // adjust for the difference between the window size and the page size.
+
+ FloatRect windowRect = page->chrome()->windowRect();
+ FloatSize pageSize = page->chrome()->pageRect().size();
+ if (features.xSet)
+ windowRect.setX(features.x);
+ if (features.ySet)
+ windowRect.setY(features.y);
+ if (features.widthSet)
+ windowRect.setWidth(features.width + (windowRect.width() - pageSize.width()));
+ if (features.heightSet)
+ windowRect.setHeight(features.height + (windowRect.height() - pageSize.height()));
+ page->chrome()->setWindowRect(windowRect);
+
+ page->chrome()->show();
+
+ created = true;
+ return frame;
+}
+
} // namespace WebCore
diff --git a/WebCore/loader/FrameLoader.h b/WebCore/loader/FrameLoader.h
index abe3b3a..b07ed27 100644
--- a/WebCore/loader/FrameLoader.h
+++ b/WebCore/loader/FrameLoader.h
@@ -32,13 +32,16 @@
#define FrameLoader_h
#include "CachePolicy.h"
+#include "DocumentWriter.h"
+#include "FrameLoaderStateMachine.h"
#include "FrameLoaderTypes.h"
#include "HistoryController.h"
+#include "NavigationScheduler.h"
#include "PolicyCallback.h"
#include "PolicyChecker.h"
-#include "RedirectScheduler.h"
#include "ResourceLoadNotifier.h"
#include "ResourceRequest.h"
+#include "SubframeLoader.h"
#include "ThreadableLoader.h"
#include "Timer.h"
#include <wtf/Forward.h>
@@ -58,28 +61,27 @@ class DocumentLoader;
class Event;
class FormData;
class FormState;
+class FormSubmission;
class Frame;
class FrameLoaderClient;
+class FrameNetworkingContext;
class HistoryItem;
-class HTMLAppletElement;
class HTMLFormElement;
-class HTMLFrameOwnerElement;
class IconLoader;
-class IntSize;
class NavigationAction;
-class RenderPart;
+class NetworkingContext;
+class Page;
+class ProtectionSpace;
class ResourceError;
class ResourceLoader;
class ResourceResponse;
class ScriptSourceCode;
-class ScriptString;
class ScriptValue;
class SecurityOrigin;
class SerializedScriptValue;
class SharedBuffer;
class SubstituteData;
class TextResourceDecoder;
-class Widget;
struct FrameLoadRequest;
struct WindowFeatures;
@@ -98,6 +100,8 @@ public:
PolicyChecker* policyChecker() const { return &m_policyChecker; }
HistoryController* history() const { return &m_history; }
ResourceLoadNotifier* notifier() const { return &m_notifer; }
+ DocumentWriter* writer() const { return &m_writer; }
+ SubframeLoader* subframeLoader() const { return &m_subframeLoader; }
// 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
@@ -122,9 +126,6 @@ public:
static void reportLocalLoadFailed(Frame*, const String& url);
- // Called by createWindow in JSDOMWindowBase.cpp, e.g. to fulfill a modal dialog creation
- Frame* createWindow(FrameLoader* frameLoaderForFrameLookup, const FrameLoadRequest&, const WindowFeatures&, bool& created);
-
unsigned long loadResourceSynchronously(const ResourceRequest&, StoredCredentials, ResourceError&, ResourceResponse&, Vector<char>& data);
bool canHandleRequest(const ResourceRequest&);
@@ -136,6 +137,7 @@ public:
bool isLoadingMainResource() const { return m_isLoadingMainResource; }
bool isLoading() const;
bool frameHasLoaded() const;
+ void transferLoadingResourcesFromPage(Page*);
int numPendingOrLoadingRequests(bool recurse) const;
String referrer() const;
@@ -150,10 +152,12 @@ public:
static double timeOfLastCompletedLoad();
bool shouldUseCredentialStorage(ResourceLoader*);
+#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
+ bool canAuthenticateAgainstProtectionSpace(ResourceLoader* loader, const ProtectionSpace& protectionSpace);
+#endif
const ResourceRequest& originalRequest() const;
const ResourceRequest& initialRequest() const;
void receivedMainResourceError(const ResourceError&, bool isComplete);
- void receivedData(const char*, int);
bool willLoadMediaElementURL(KURL&);
@@ -179,7 +183,6 @@ public:
void didReceiveServerRedirectForProvisionalLoadForFrame();
void finishedLoadingDocument(DocumentLoader*);
- void committedLoad(DocumentLoader*, const char*, int);
bool isReplacing() const;
void setReplacing();
void revertToProvisional(DocumentLoader*);
@@ -188,12 +191,13 @@ public:
bool subframeIsLoading() const;
void willChangeTitle(DocumentLoader*);
void didChangeTitle(DocumentLoader*);
+ void didChangeIcons(DocumentLoader*);
FrameLoadType loadType() const;
+
CachePolicy subresourceCachePolicy() const;
void didFirstLayout();
- bool firstLayoutDone() const;
void didFirstVisuallyNonEmptyLayout();
@@ -213,13 +217,10 @@ public:
void setDefersLoading(bool);
- void changeLocation(const KURL&, const String& referrer, bool lockHistory = true, bool lockBackForwardList = true, bool userGesture = false, bool refresh = false);
- void urlSelected(const ResourceRequest&, const String& target, PassRefPtr<Event>, bool lockHistory, bool lockBackForwardList, bool userGesture, ReferrerPolicy);
- bool requestFrame(HTMLFrameOwnerElement*, const String& url, const AtomicString& frameName);
+ void changeLocation(const KURL&, const String& referrer, bool lockHistory = true, bool lockBackForwardList = true, bool refresh = false);
+ void urlSelected(const KURL&, const String& target, PassRefPtr<Event>, bool lockHistory, bool lockBackForwardList, ReferrerPolicy);
- void submitForm(const char* action, const String& url,
- PassRefPtr<FormData>, const String& target, const String& contentType, const String& boundary,
- bool lockHistory, PassRefPtr<Event>, PassRefPtr<FormState>);
+ void submitForm(PassRefPtr<FormSubmission>);
void stop();
void stopLoading(UnloadEventPolicy, DatabasePolicy = DatabasePolicyStop);
@@ -227,31 +228,19 @@ public:
void didExplicitOpen();
+ // Callbacks from DocumentWriter
+ void didBeginDocument(bool dispatchWindowObjectAvailable);
+ void didEndDocument();
+ void willSetEncoding();
+
KURL iconURL();
void commitIconURLToIconDatabase(const KURL&);
KURL baseURL() const;
- void replaceDocument(const String&);
-
- void begin();
- void begin(const KURL&, bool dispatchWindowObjectAvailable = true, SecurityOrigin* forcedSecurityOrigin = 0);
-
- void write(const char* string, int length = -1, bool flush = false);
- void write(const String&);
- void end();
- void endIfNotLoadingMainResource();
-
- void setEncoding(const String& encoding, bool userChosen);
- String encoding() const;
-
- void tokenizerProcessedData();
-
void handledOnloadEvents();
String userAgent(const KURL&) const;
- PassRefPtr<Widget> createJavaAppletWidget(const IntSize&, HTMLAppletElement*, const HashMap<String, String>& args);
-
void dispatchDidClearWindowObjectInWorld(DOMWrapperWorld*);
void dispatchDidClearWindowObjectsInAllWorlds();
void dispatchDocumentElementAvailable();
@@ -260,6 +249,9 @@ public:
bool isSandboxed(SandboxFlags mask) const { return m_sandboxFlags & mask; }
SandboxFlags sandboxFlags() const { return m_sandboxFlags; }
+ // The following sandbox flags will be forced, regardless of changes to
+ // the sandbox attribute of any parent frames.
+ void setForcedSandboxFlags(SandboxFlags flags) { m_forcedSandboxFlags = flags; m_sandboxFlags |= flags; }
// Mixed content related functions.
static bool isMixedContent(SecurityOrigin* context, const KURL&);
@@ -273,18 +265,14 @@ public:
void resetMultipleFormSubmissionProtection();
- void addData(const char* bytes, int length);
-
void checkCallImplicitClose();
void frameDetached();
const KURL& url() const { return m_URL; }
- void setResponseMIMEType(const String&);
- const String& responseMIMEType() const;
-
- bool containsPlugins() const;
+ // setURL is a low-level setter and does not trigger loading.
+ void setURL(const KURL&);
void loadDone();
void finishedParsing();
@@ -294,21 +282,17 @@ public:
bool isComplete() const;
- bool requestObject(RenderPart* frame, const String& url, const AtomicString& frameName,
- const String& serviceType, const Vector<String>& paramNames, const Vector<String>& paramValues);
-
KURL completeURL(const String& url);
void cancelAndClear();
void setTitle(const String&);
+ void setIconURL(const String&);
- void commitProvisionalLoad(PassRefPtr<CachedPage>);
+ void commitProvisionalLoad();
bool isLoadingFromCachedPage() const { return m_loadingFromCachedPage; }
- bool committingFirstRealLoad() const { return !m_creatingInitialEmptyDocument && !m_committedFirstRealDocumentLoad; }
- bool committedFirstRealDocumentLoad() const { return m_committedFirstRealDocumentLoad; }
- bool creatingInitialEmptyDocument() const { return m_creatingInitialEmptyDocument; }
+ FrameLoaderStateMachine* stateMachine() const { return &m_stateMachine; }
void iconLoadDecisionAvailable();
@@ -340,6 +324,18 @@ public:
static ObjectContentType defaultObjectContentType(const KURL& url, const String& mimeType);
+ void clear(bool clearWindowProperties = true, bool clearScriptObjects = true, bool clearFrameView = true);
+
+ bool quickRedirectComing() const { return m_quickRedirectComing; }
+
+ bool shouldClose();
+
+ void started();
+
+ bool pageDismissalEventBeingDispatched() const { return m_pageDismissalEventBeingDispatched; }
+
+ NetworkingContext* networkingContext() const;
+
private:
bool canCachePageContainingThisFrame();
#ifndef NDEBUG
@@ -348,19 +344,11 @@ private:
#endif
void checkTimerFired(Timer<FrameLoader>*);
-
- void started();
-
- bool shouldUsePlugin(const KURL&, const String& mimeType, bool hasFallback, bool& useFallback);
- bool loadPlugin(RenderPart*, const KURL&, const String& mimeType,
- const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback);
void navigateWithinDocument(HistoryItem*);
void navigateToDifferentDocument(HistoryItem*, FrameLoadType);
- bool loadProvisionalItemFromCachedPage();
- void cachePageForHistoryItem(HistoryItem*);
- void pageHidden();
+ void loadProvisionalItemFromCachedPage();
void receivedFirstData();
@@ -382,11 +370,11 @@ private:
void setLoadType(FrameLoadType);
static void callContinueLoadAfterNavigationPolicy(void*, const ResourceRequest&, PassRefPtr<FormState>, bool shouldContinue);
- static void callContinueLoadAfterNewWindowPolicy(void*, const ResourceRequest&, PassRefPtr<FormState>, const String& frameName, bool shouldContinue);
+ static void callContinueLoadAfterNewWindowPolicy(void*, const ResourceRequest&, PassRefPtr<FormState>, const String& frameName, const NavigationAction&, bool shouldContinue);
static void callContinueFragmentScrollAfterNavigationPolicy(void*, const ResourceRequest&, PassRefPtr<FormState>, bool shouldContinue);
void continueLoadAfterNavigationPolicy(const ResourceRequest&, PassRefPtr<FormState>, bool shouldContinue);
- void continueLoadAfterNewWindowPolicy(const ResourceRequest&, PassRefPtr<FormState>, const String& frameName, bool shouldContinue);
+ void continueLoadAfterNewWindowPolicy(const ResourceRequest&, PassRefPtr<FormState>, const String& frameName, const NavigationAction&, bool shouldContinue);
void continueFragmentScrollAfterNavigationPolicy(const ResourceRequest&, bool shouldContinue);
bool shouldScrollToAnchor(bool isFormSubmission, FrameLoadType, const KURL&);
@@ -400,33 +388,26 @@ private:
void setState(FrameState);
void closeOldDataSources();
- void open(CachedPage&);
+ void prepareForCachedPageRestore();
void updateHistoryAfterClientRedirect();
- void clear(bool clearWindowProperties = true, bool clearScriptObjects = true, bool clearFrameView = true);
-
bool shouldReloadToHandleUnreachableURL(DocumentLoader*);
void dispatchDidCommitLoad();
+ void urlSelected(const ResourceRequest&, const String& target, PassRefPtr<Event>, bool lockHistory, bool lockBackForwardList, ReferrerPolicy, ShouldReplaceDocumentIfJavaScriptURL);
+
void loadWithDocumentLoader(DocumentLoader*, FrameLoadType, PassRefPtr<FormState>); // Calls continueLoadAfterNavigationPolicy
void load(DocumentLoader*); // Calls loadWithDocumentLoader
void loadWithNavigationAction(const ResourceRequest&, const NavigationAction&, // Calls loadWithDocumentLoader
bool lockHistory, FrameLoadType, PassRefPtr<FormState>);
-#ifdef ANDROID_USER_GESTURE
- void loadPostRequest(const ResourceRequest&, const String& referrer, // Called by loadFrameRequest, calls loadWithNavigationAction
- const String& frameName, bool lockHistory, FrameLoadType, PassRefPtr<Event>, PassRefPtr<FormState>, bool);
- void loadURL(const KURL&, const String& referrer, const String& frameName, // Called by loadFrameRequest, calls loadWithNavigationAction or dispatches to navigation policy delegate
- bool lockHistory, FrameLoadType, PassRefPtr<Event>, PassRefPtr<FormState>, bool);
-#else
void loadPostRequest(const ResourceRequest&, const String& referrer, // Called by loadFrameRequest, calls loadWithNavigationAction
const String& frameName, bool lockHistory, FrameLoadType, PassRefPtr<Event>, PassRefPtr<FormState>);
void loadURL(const KURL&, const String& referrer, const String& frameName, // Called by loadFrameRequest, calls loadWithNavigationAction or dispatches to navigation policy delegate
bool lockHistory, FrameLoadType, PassRefPtr<Event>, PassRefPtr<FormState>);
-#endif
bool shouldReload(const KURL& currentURL, const KURL& destinationURL);
@@ -437,8 +418,6 @@ private:
void detachChildren();
void closeAndRemoveChild(Frame*);
- Frame* loadSubframe(HTMLFrameOwnerElement*, const KURL&, const String& name, const String& referrer);
-
void loadInSameDocument(const KURL&, SerializedScriptValue* stateObject, bool isNewNavigation);
void provisionalLoadStarted();
@@ -456,8 +435,6 @@ private:
bool shouldTreatURLAsSameAsCurrent(const KURL&) const;
void updateSandboxFlags();
- // FIXME: isDocumentSandboxed should eventually replace isSandboxed.
- bool isDocumentSandboxed(SandboxFlags) const;
Frame* m_frame;
FrameLoaderClient* m_client;
@@ -465,6 +442,9 @@ private:
mutable PolicyChecker m_policyChecker;
mutable HistoryController m_history;
mutable ResourceLoadNotifier m_notifer;
+ mutable DocumentWriter m_writer;
+ mutable SubframeLoader m_subframeLoader;
+ mutable FrameLoaderStateMachine m_stateMachine;
FrameState m_state;
FrameLoadType m_loadType;
@@ -479,7 +459,6 @@ private:
bool m_delegateIsHandlingProvisionalLoadError;
- bool m_firstLayoutDone;
bool m_quickRedirectComing;
bool m_sentRedirectNotification;
bool m_inStopAllLoaders;
@@ -488,11 +467,9 @@ private:
bool m_isExecutingJavaScriptFormAction;
- String m_responseMIMEType;
-
bool m_didCallImplicitClose;
bool m_wasUnloadEventEmitted;
- bool m_unloadEventBeingDispatched;
+ bool m_pageDismissalEventBeingDispatched;
bool m_isComplete;
bool m_isLoadingMainResource;
@@ -504,16 +481,7 @@ private:
OwnPtr<IconLoader> m_iconLoader;
bool m_mayLoadIconLater;
- bool m_cancellingWithLoadInProgress;
-
bool m_needsClear;
- bool m_receivedData;
-
- bool m_encodingWasChosenByUser;
- String m_encoding;
- RefPtr<TextResourceDecoder> m_decoder;
-
- bool m_containsPlugIns;
KURL m_submittedFormURL;
@@ -524,21 +492,29 @@ private:
Frame* m_opener;
HashSet<Frame*> m_openedFrames;
- bool m_creatingInitialEmptyDocument;
- bool m_isDisplayingInitialEmptyDocument;
- bool m_committedFirstRealDocumentLoad;
-
bool m_didPerformFirstNavigation;
bool m_loadingFromCachedPage;
bool m_suppressOpenerInNewFrame;
SandboxFlags m_sandboxFlags;
+ SandboxFlags m_forcedSandboxFlags;
#ifndef NDEBUG
bool m_didDispatchDidCommitLoad;
#endif
+
+ RefPtr<FrameNetworkingContext> m_networkingContext;
};
+// This function is called by createWindow() in JSDOMWindowBase.cpp, for example, for
+// modal dialog creation. The lookupFrame is for looking up the frame name in case
+// the frame name references a frame different from the openerFrame, e.g. when it is
+// "_self" or "_parent".
+//
+// FIXME: Consider making this function part of an appropriate class (not FrameLoader)
+// and moving it to a more appropriate location.
+Frame* createWindow(Frame* openerFrame, Frame* lookupFrame, const FrameLoadRequest&, const WindowFeatures&, bool& created);
+
} // namespace WebCore
#endif // FrameLoader_h
diff --git a/WebCore/loader/FrameLoaderClient.h b/WebCore/loader/FrameLoaderClient.h
index 2668958..7348293 100644
--- a/WebCore/loader/FrameLoaderClient.h
+++ b/WebCore/loader/FrameLoaderClient.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -32,7 +32,6 @@
#include "FrameLoaderTypes.h"
#include "ScrollTypes.h"
#include <wtf/Forward.h>
-#include <wtf/Platform.h>
#include <wtf/Vector.h>
typedef class _jobject* jobject;
@@ -53,13 +52,20 @@ namespace WebCore {
class FormState;
class Frame;
class FrameLoader;
+ class FrameNetworkingContext;
class HistoryItem;
class HTMLAppletElement;
+ class HTMLFormElement;
class HTMLFrameOwnerElement;
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ class HTMLMediaElement;
+#endif
class HTMLPlugInElement;
class IntSize;
class KURL;
class NavigationAction;
+ class Page;
+ class ProtectionSpace;
class PluginView;
class PolicyChecker;
class ResourceError;
@@ -67,11 +73,9 @@ namespace WebCore {
class ResourceLoader;
class ResourceRequest;
class ResourceResponse;
- class ScriptString;
class SecurityOrigin;
class SharedBuffer;
class SubstituteData;
- class String;
class Widget;
typedef void (PolicyChecker::*FramePolicyFunction)(PolicyAction);
@@ -105,17 +109,20 @@ namespace WebCore {
virtual bool shouldUseCredentialStorage(DocumentLoader*, unsigned long identifier) = 0;
virtual void dispatchDidReceiveAuthenticationChallenge(DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&) = 0;
virtual void dispatchDidCancelAuthenticationChallenge(DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&) = 0;
+#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
+ virtual bool canAuthenticateAgainstProtectionSpace(DocumentLoader*, unsigned long identifier, const ProtectionSpace&) = 0;
+#endif
virtual void dispatchDidReceiveResponse(DocumentLoader*, unsigned long identifier, const ResourceResponse&) = 0;
virtual void dispatchDidReceiveContentLength(DocumentLoader*, unsigned long identifier, int lengthReceived) = 0;
virtual void dispatchDidFinishLoading(DocumentLoader*, unsigned long identifier) = 0;
virtual void dispatchDidFailLoading(DocumentLoader*, unsigned long identifier, const ResourceError&) = 0;
virtual bool dispatchDidLoadResourceFromMemoryCache(DocumentLoader*, const ResourceRequest&, const ResourceResponse&, int length) = 0;
- virtual void dispatchDidLoadResourceByXMLHttpRequest(unsigned long identifier, const ScriptString&) = 0;
virtual void dispatchDidHandleOnloadEvents() = 0;
virtual void dispatchDidReceiveServerRedirectForProvisionalLoad() = 0;
virtual void dispatchDidCancelClientRedirect() = 0;
virtual void dispatchWillPerformClientRedirect(const KURL&, double interval, double fireDate) = 0;
+ virtual void dispatchDidNavigateWithinPage() { }
virtual void dispatchDidChangeLocationWithinPage() = 0;
virtual void dispatchDidPushStateWithinPage() = 0;
virtual void dispatchDidReplaceStateWithinPage() = 0;
@@ -124,6 +131,7 @@ namespace WebCore {
virtual void dispatchDidReceiveIcon() = 0;
virtual void dispatchDidStartProvisionalLoad() = 0;
virtual void dispatchDidReceiveTitle(const String& title) = 0;
+ virtual void dispatchDidChangeIcons() = 0;
virtual void dispatchDidCommitLoad() = 0;
virtual void dispatchDidFailProvisionalLoad(const ResourceError&) = 0;
virtual void dispatchDidFailLoad(const ResourceError&) = 0;
@@ -132,7 +140,7 @@ namespace WebCore {
virtual void dispatchDidFirstLayout() = 0;
virtual void dispatchDidFirstVisuallyNonEmptyLayout() = 0;
- virtual Frame* dispatchCreatePage() = 0;
+ virtual Frame* dispatchCreatePage(const NavigationAction&) = 0;
virtual void dispatchShow() = 0;
virtual void dispatchDecidePolicyForMIMEType(FramePolicyFunction, const String& MIMEType, const ResourceRequest&) = 0;
@@ -142,6 +150,7 @@ namespace WebCore {
virtual void dispatchUnableToImplementPolicy(const ResourceError&) = 0;
+ virtual void dispatchWillSendSubmitEvent(HTMLFormElement*) = 0;
virtual void dispatchWillSubmitForm(FramePolicyFunction, PassRefPtr<FormState>) = 0;
virtual void dispatchDidLoadMainResource(DocumentLoader*) = 0;
@@ -195,6 +204,7 @@ namespace WebCore {
virtual bool canHandleRequest(const ResourceRequest&) const = 0;
virtual bool canShowMIMEType(const String& MIMEType) const = 0;
+ virtual bool canShowMIMETypeAsHTML(const String& MIMEType) const = 0;
virtual bool representationExistsForURLScheme(const String& URLScheme) const = 0;
virtual String generatedMIMETypeForURLScheme(const String& URLScheme) const = 0;
@@ -214,17 +224,26 @@ namespace WebCore {
virtual void transitionToCommittedFromCachedFrame(CachedFrame*) = 0;
virtual void transitionToCommittedForNewPage() = 0;
+ virtual void dispatchDidBecomeFrameset(bool) = 0; // Can change due to navigation or DOM modification.
+
virtual bool canCachePage() const = 0;
virtual void download(ResourceHandle*, const ResourceRequest&, const ResourceRequest&, const ResourceResponse&) = 0;
virtual PassRefPtr<Frame> createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement,
const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight) = 0;
+ virtual void didTransferChildFrameToNewDocument(Page* oldPage) = 0;
+ virtual void transferLoadingResourceFromPage(unsigned long identifier, DocumentLoader*, const ResourceRequest&, Page* oldPage) = 0;
virtual PassRefPtr<Widget> createPlugin(const IntSize&, HTMLPlugInElement*, const KURL&, const Vector<String>&, const Vector<String>&, const String&, bool loadManually) = 0;
virtual void redirectDataToPlugin(Widget* pluginWidget) = 0;
virtual PassRefPtr<Widget> createJavaAppletWidget(const IntSize&, HTMLAppletElement*, const KURL& baseURL, const Vector<String>& paramNames, const Vector<String>& paramValues) = 0;
virtual void dispatchDidFailToStartPlugin(const PluginView*) const { }
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ virtual PassRefPtr<Widget> createMediaPlayerProxyPlugin(const IntSize&, HTMLMediaElement*, const KURL&, const Vector<String>&, const Vector<String>&, const String&) = 0;
+ virtual void hideMediaPlayerProxyPlugin(Widget*) = 0;
+ virtual void showMediaPlayerProxyPlugin(Widget*) = 0;
+#endif
virtual ObjectContentType objectContentType(const KURL& url, const String& mimeType) = 0;
virtual String overrideMediaType() const = 0;
@@ -237,6 +256,7 @@ namespace WebCore {
virtual void didCreateScriptContextForFrame() = 0;
virtual void didDestroyScriptContextForFrame() = 0;
virtual void didCreateIsolatedScriptContext() = 0;
+ virtual bool allowScriptExtension(const String& extensionName, int extensionGroup) = 0;
#endif
virtual void registerForIconNotification(bool listen = true) = 0;
@@ -245,7 +265,7 @@ namespace WebCore {
#endif
#if PLATFORM(MAC)
-#if ENABLE(MAC_JAVA_BRIDGE)
+#if ENABLE(JAVA_BRIDGE)
virtual jobject javaApplet(NSView*) { return 0; }
#endif
virtual NSCachedURLResponse* willCacheResponse(DocumentLoader*, unsigned long identifier, NSCachedURLResponse*) const = 0;
@@ -262,6 +282,17 @@ namespace WebCore {
virtual bool allowJavaScript(bool enabledPerSettings) { return enabledPerSettings; }
virtual bool allowPlugins(bool enabledPerSettings) { return enabledPerSettings; }
virtual bool allowImages(bool enabledPerSettings) { return enabledPerSettings; }
+
+ // This callback notifies the client that the frame was about to run
+ // JavaScript but did not because allowJavaScript returned false. We
+ // have a separate callback here because there are a number of places
+ // that need to know if JavaScript is enabled but are not necessarily
+ // preparing to execute script.
+ virtual void didNotAllowScript() { }
+ // This callback is similar, but for plugins.
+ virtual void didNotAllowPlugins() { }
+
+ virtual PassRefPtr<FrameNetworkingContext> createNetworkingContext() = 0;
};
} // namespace WebCore
diff --git a/WebCore/loader/FrameLoaderStateMachine.cpp b/WebCore/loader/FrameLoaderStateMachine.cpp
new file mode 100644
index 0000000..790b144
--- /dev/null
+++ b/WebCore/loader/FrameLoaderStateMachine.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 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 Google, Inc. nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL 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 "FrameLoaderStateMachine.h"
+
+#include <wtf/Assertions.h>
+
+namespace WebCore {
+
+
+FrameLoaderStateMachine::FrameLoaderStateMachine()
+ : m_state(Uninitialized)
+{
+}
+
+bool FrameLoaderStateMachine::committingFirstRealLoad() const
+{
+ return m_state == DisplayingInitialEmptyDocument;
+}
+
+bool FrameLoaderStateMachine::committedFirstRealDocumentLoad() const
+{
+ return m_state >= DisplayingInitialEmptyDocumentPostCommit;
+}
+
+bool FrameLoaderStateMachine::creatingInitialEmptyDocument() const
+{
+ return m_state == CreatingInitialEmptyDocument;
+}
+
+bool FrameLoaderStateMachine::isDisplayingInitialEmptyDocument() const
+{
+ return m_state == DisplayingInitialEmptyDocument || m_state == DisplayingInitialEmptyDocumentPostCommit;
+}
+
+bool FrameLoaderStateMachine::firstLayoutDone() const
+{
+ return m_state == FirstLayoutDone;
+}
+
+void FrameLoaderStateMachine::advanceTo(State state)
+{
+ ASSERT(State(m_state + 1) == state || (firstLayoutDone() && state == CommittedFirstRealLoad));
+ m_state = state;
+}
+
+} // namespace WebCore
diff --git a/WebCore/loader/FrameLoaderStateMachine.h b/WebCore/loader/FrameLoaderStateMachine.h
new file mode 100644
index 0000000..c3408c2
--- /dev/null
+++ b/WebCore/loader/FrameLoaderStateMachine.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 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 Google, Inc. nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL 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 FrameLoaderStateMachine_h
+#define FrameLoaderStateMachine_h
+
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+// Encapsulates a state machine for FrameLoader. Note that this is different from FrameState,
+// which stores the state of the current load that FrameLoader is executing.
+class FrameLoaderStateMachine : public Noncopyable {
+public:
+ FrameLoaderStateMachine();
+
+ // Once a load has been committed, the state may
+ // alternate between CommittedFirstRealLoad and FirstLayoutDone.
+ // Otherwise, the states only go down the list.
+ enum State {
+ Uninitialized,
+ CreatingInitialEmptyDocument,
+ DisplayingInitialEmptyDocument,
+ DisplayingInitialEmptyDocumentPostCommit,
+ CommittedFirstRealLoad,
+ FirstLayoutDone
+ };
+
+ bool committingFirstRealLoad() const;
+ bool committedFirstRealDocumentLoad() const;
+ bool creatingInitialEmptyDocument() const;
+ bool isDisplayingInitialEmptyDocument() const;
+ bool firstLayoutDone() const;
+ void advanceTo(State);
+
+private:
+ State m_state;
+};
+
+} // namespace WebCore
+
+#endif // FrameLoaderStateMachine_h
diff --git a/WebCore/loader/FrameLoaderTypes.h b/WebCore/loader/FrameLoaderTypes.h
index 8288bce..016de19 100644
--- a/WebCore/loader/FrameLoaderTypes.h
+++ b/WebCore/loader/FrameLoaderTypes.h
@@ -92,7 +92,7 @@ namespace WebCore {
SendReferrer,
NoReferrer
};
-
+
enum SandboxFlag {
SandboxNone = 0,
SandboxNavigation = 1,
@@ -100,14 +100,29 @@ namespace WebCore {
SandboxOrigin = 1 << 2,
SandboxForms = 1 << 3,
SandboxScripts = 1 << 4,
+ SandboxTopNavigation = 1 << 5,
SandboxAll = -1 // Mask with all bits set to 1.
};
-
+
enum SecurityCheckPolicy {
SkipSecurityCheck,
DoSecurityCheck
};
+ // Passed to FrameLoader::urlSelected() and ScriptController::executeIfJavaScriptURL()
+ // to control whether, in the case of a JavaScript URL, executeIfJavaScriptURL() should
+ // replace the document. It is a FIXME to eliminate this extra parameter from
+ // executeIfJavaScriptURL(), in which case this enum can go away.
+ enum ShouldReplaceDocumentIfJavaScriptURL {
+ ReplaceDocumentIfJavaScriptURL,
+ DoNotReplaceDocumentIfJavaScriptURL
+ };
+
+ enum ReasonForCallingAllowPlugins {
+ AboutToInstantiatePlugin,
+ NotAboutToInstantiatePlugin
+ };
+
typedef int SandboxFlags;
}
diff --git a/WebCore/loader/FrameNetworkingContext.h b/WebCore/loader/FrameNetworkingContext.h
new file mode 100644
index 0000000..dff1144
--- /dev/null
+++ b/WebCore/loader/FrameNetworkingContext.h
@@ -0,0 +1,51 @@
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef FrameNetworkingContext_h
+#define FrameNetworkingContext_h
+
+#include "Frame.h"
+#include "NetworkingContext.h"
+
+namespace WebCore {
+
+class FrameNetworkingContext : public NetworkingContext {
+public:
+ void invalidate()
+ {
+ m_frame = 0;
+ }
+
+protected:
+ FrameNetworkingContext(Frame* frame)
+ : m_frame(frame)
+ {
+ }
+
+ Frame* frame() const { return m_frame; }
+
+private:
+ virtual bool isValid() const { return m_frame; }
+
+ Frame* m_frame;
+};
+
+}
+
+#endif // FrameNetworkingContext_h
diff --git a/WebCore/loader/HistoryController.cpp b/WebCore/loader/HistoryController.cpp
index 43c9979..07bece7 100644
--- a/WebCore/loader/HistoryController.cpp
+++ b/WebCore/loader/HistoryController.cpp
@@ -31,13 +31,13 @@
#include "config.h"
#include "HistoryController.h"
-#include "BackForwardList.h"
+#include "BackForwardController.h"
#include "CachedPage.h"
-#include "CString.h"
#include "DocumentLoader.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "FrameLoaderClient.h"
+#include "FrameLoaderStateMachine.h"
#include "FrameTree.h"
#include "FrameView.h"
#include "HistoryItem.h"
@@ -46,9 +46,24 @@
#include "PageCache.h"
#include "PageGroup.h"
#include "Settings.h"
+#include <wtf/text/CString.h>
+
+#if USE(PLATFORM_STRATEGIES)
+#include "PlatformStrategies.h"
+#include "VisitedLinkStrategy.h"
+#endif
namespace WebCore {
+static inline void addVisitedLink(Page* page, const KURL& url)
+{
+#if USE(PLATFORM_STRATEGIES)
+ platformStrategies()->visitedLinkStrategy()->addVisitedLink(page, visitedLinkHash(url.string().characters(), url.string().length()));
+#else
+ page->group().addVisitedLink(url);
+#endif
+}
+
HistoryController::HistoryController(Frame* frame)
: m_frame(frame)
{
@@ -81,7 +96,7 @@ void HistoryController::saveScrollPositionAndViewStateToItem(HistoryItem* item)
*/
void HistoryController::restoreScrollPositionAndViewState()
{
- if (!m_frame->loader()->committedFirstRealDocumentLoad())
+ if (!m_frame->loader()->stateMachine()->committedFirstRealDocumentLoad())
return;
ASSERT(m_currentItem);
@@ -106,17 +121,13 @@ void HistoryController::restoreScrollPositionAndViewState()
void HistoryController::updateBackForwardListForFragmentScroll()
{
updateBackForwardListClippedAtTarget(false);
-
- // Since the document isn't changed as a result of a fragment scroll, we should
- // preserve the DocumentSequenceNumber of the previous item.
- m_currentItem->setDocumentSequenceNumber(m_previousItem->documentSequenceNumber());
}
void HistoryController::saveDocumentState()
{
// FIXME: Reading this bit of FrameLoader state here is unfortunate. I need to study
// this more to see if we can remove this dependency.
- if (m_frame->loader()->creatingInitialEmptyDocument())
+ if (m_frame->loader()->stateMachine()->creatingInitialEmptyDocument())
return;
// For a standard page load, we will have a previous item set, which will be used to
@@ -138,7 +149,7 @@ void HistoryController::saveDocumentState()
ASSERT(document);
if (item->isCurrentDocument(document)) {
- LOG(Loading, "WebCoreLoading %s: saving form state to %p", m_frame->tree()->name().string().utf8().data(), item);
+ LOG(Loading, "WebCoreLoading %s: saving form state to %p", m_frame->tree()->uniqueName().string().utf8().data(), item);
item->setDocumentState(document->formElementsState());
}
}
@@ -177,7 +188,7 @@ void HistoryController::restoreDocumentState()
if (!itemToRestore)
return;
- LOG(Loading, "WebCoreLoading %s: restoring form state from %p", m_frame->tree()->name().string().utf8().data(), itemToRestore);
+ LOG(Loading, "WebCoreLoading %s: restoring form state from %p", m_frame->tree()->uniqueName().string().utf8().data(), itemToRestore);
doc->setStateForNewFormElements(itemToRestore->documentState());
}
@@ -219,33 +230,13 @@ void HistoryController::goToItem(HistoryItem* targetItem, FrameLoadType type)
// Set the BF cursor before commit, which lets the user quickly click back/forward again.
// - plus, it only makes sense for the top level of the operation through the frametree,
// as opposed to happening for some/one of the page commits that might happen soon
- BackForwardList* bfList = page->backForwardList();
- HistoryItem* currentItem = bfList->currentItem();
- bfList->goToItem(targetItem);
+ HistoryItem* currentItem = page->backForward()->currentItem();
+ page->backForward()->setCurrentItem(targetItem);
Settings* settings = m_frame->settings();
page->setGlobalHistoryItem((!settings || settings->privateBrowsingEnabled()) ? 0 : targetItem);
recursiveGoToItem(targetItem, currentItem, type);
}
-// Walk the frame tree and ensure that the URLs match the URLs in the item.
-bool HistoryController::urlsMatchItem(HistoryItem* item) const
-{
- const KURL& currentURL = m_frame->loader()->documentLoader()->url();
- if (!equalIgnoringFragmentIdentifier(currentURL, item->url()))
- return false;
-
- const HistoryItemVector& childItems = item->children();
-
- unsigned size = childItems.size();
- for (unsigned i = 0; i < size; ++i) {
- Frame* childFrame = m_frame->tree()->child(childItems[i]->target());
- if (childFrame && !childFrame->loader()->history()->urlsMatchItem(childItems[i].get()))
- return false;
- }
-
- return true;
-}
-
void HistoryController::updateForBackForwardNavigation()
{
#if !LOG_DISABLED
@@ -282,7 +273,7 @@ void HistoryController::updateForReload()
// 2) Global history: Handled by the client.
// 3) Visited links: Handled by the PageGroup.
-void HistoryController::updateForStandardLoad()
+void HistoryController::updateForStandardLoad(HistoryUpdateType updateType)
{
LOG(History, "WebCoreHistory: Updating History for Standard Load in frame %s", m_frame->loader()->documentLoader()->url().string().ascii().data());
@@ -294,7 +285,8 @@ void HistoryController::updateForStandardLoad()
if (!frameLoader->documentLoader()->isClientRedirect()) {
if (!historyURL.isEmpty()) {
- updateBackForwardListClippedAtTarget(true);
+ if (updateType != UpdateAllExceptBackForwardList)
+ updateBackForwardListClippedAtTarget(true);
if (!needPrivacy) {
frameLoader->client()->updateGlobalHistory();
frameLoader->documentLoader()->setDidCreateGlobalHistoryEntry(true);
@@ -302,7 +294,7 @@ void HistoryController::updateForStandardLoad()
frameLoader->client()->updateGlobalHistoryRedirectLinks();
}
if (Page* page = m_frame->page())
- page->setGlobalHistoryItem(needPrivacy ? 0 : page->backForwardList()->currentItem());
+ page->setGlobalHistoryItem(needPrivacy ? 0 : page->backForward()->currentItem());
}
} else if (frameLoader->documentLoader()->unreachableURL().isEmpty() && m_currentItem) {
m_currentItem->setURL(frameLoader->documentLoader()->url());
@@ -311,7 +303,7 @@ void HistoryController::updateForStandardLoad()
if (!historyURL.isEmpty() && !needPrivacy) {
if (Page* page = m_frame->page())
- page->group().addVisitedLink(historyURL);
+ addVisitedLink(page, historyURL);
if (!frameLoader->documentLoader()->didCreateGlobalHistoryEntry() && frameLoader->documentLoader()->unreachableURL().isEmpty() && !frameLoader->url().isEmpty())
frameLoader->client()->updateGlobalHistoryRedirectLinks();
@@ -340,7 +332,7 @@ void HistoryController::updateForRedirectWithLockedBackForwardList()
m_frame->loader()->client()->updateGlobalHistoryRedirectLinks();
}
if (Page* page = m_frame->page())
- page->setGlobalHistoryItem(needPrivacy ? 0 : page->backForwardList()->currentItem());
+ page->setGlobalHistoryItem(needPrivacy ? 0 : page->backForward()->currentItem());
}
}
if (m_currentItem) {
@@ -355,7 +347,7 @@ void HistoryController::updateForRedirectWithLockedBackForwardList()
if (!historyURL.isEmpty() && !needPrivacy) {
if (Page* page = m_frame->page())
- page->group().addVisitedLink(historyURL);
+ addVisitedLink(page, historyURL);
if (!m_frame->loader()->documentLoader()->didCreateGlobalHistoryEntry() && m_frame->loader()->documentLoader()->unreachableURL().isEmpty() && !m_frame->loader()->url().isEmpty())
m_frame->loader()->client()->updateGlobalHistoryRedirectLinks();
@@ -382,7 +374,7 @@ void HistoryController::updateForClientRedirect()
if (!historyURL.isEmpty() && !needPrivacy) {
if (Page* page = m_frame->page())
- page->group().addVisitedLink(historyURL);
+ addVisitedLink(page, historyURL);
}
}
@@ -420,7 +412,7 @@ void HistoryController::updateForSameDocumentNavigation()
if (!page)
return;
- page->group().addVisitedLink(m_frame->loader()->url());
+ addVisitedLink(page, m_frame->loader()->url());
}
void HistoryController::updateForFrameLoadCompleted()
@@ -441,6 +433,15 @@ void HistoryController::setCurrentItemTitle(const String& title)
m_currentItem->setTitle(title);
}
+bool HistoryController::currentItemShouldBeReplaced() const
+{
+ // From the HTML5 spec for location.assign():
+ // "If the browsing context's session history contains only one Document,
+ // and that was the about:blank Document created when the browsing context
+ // was created, then the navigation must be done with replacement enabled."
+ return m_currentItem && !m_previousItem && equalIgnoringCase(m_currentItem->urlString(), blankURL());
+}
+
void HistoryController::setProvisionalItem(HistoryItem* item)
{
m_provisionalItem = item;
@@ -448,9 +449,9 @@ void HistoryController::setProvisionalItem(HistoryItem* item)
PassRefPtr<HistoryItem> HistoryController::createItem(bool useOriginal)
{
- DocumentLoader* docLoader = m_frame->loader()->documentLoader();
+ DocumentLoader* documentLoader = m_frame->loader()->documentLoader();
- KURL unreachableURL = docLoader ? docLoader->unreachableURL() : KURL();
+ KURL unreachableURL = documentLoader ? documentLoader->unreachableURL() : KURL();
KURL url;
KURL originalURL;
@@ -459,11 +460,11 @@ PassRefPtr<HistoryItem> HistoryController::createItem(bool useOriginal)
url = unreachableURL;
originalURL = unreachableURL;
} else {
- originalURL = docLoader ? docLoader->originalURL() : KURL();
+ originalURL = documentLoader ? documentLoader->originalURL() : KURL();
if (useOriginal)
url = originalURL;
- else if (docLoader)
- url = docLoader->requestURL();
+ else if (documentLoader)
+ url = documentLoader->requestURL();
}
LOG(History, "WebCoreHistory: Creating item for %s", url.string().ascii().data());
@@ -479,21 +480,21 @@ PassRefPtr<HistoryItem> HistoryController::createItem(bool useOriginal)
originalURL = blankURL();
Frame* parentFrame = m_frame->tree()->parent();
- String parent = parentFrame ? parentFrame->tree()->name() : "";
- String title = docLoader ? docLoader->title() : "";
+ String parent = parentFrame ? parentFrame->tree()->uniqueName() : "";
+ String title = documentLoader ? documentLoader->title() : "";
- RefPtr<HistoryItem> item = HistoryItem::create(url, m_frame->tree()->name(), parent, title);
+ RefPtr<HistoryItem> item = HistoryItem::create(url, m_frame->tree()->uniqueName(), parent, title);
item->setOriginalURLString(originalURL.string());
- if (!unreachableURL.isEmpty() || !docLoader || docLoader->response().httpStatusCode() >= 400)
+ if (!unreachableURL.isEmpty() || !documentLoader || documentLoader->response().httpStatusCode() >= 400)
item->setLastVisitWasFailure(true);
// Save form state if this is a POST
- if (docLoader) {
+ if (documentLoader) {
if (useOriginal)
- item->setFormInfoFromRequest(docLoader->originalRequest());
+ item->setFormInfoFromRequest(documentLoader->originalRequest());
else
- item->setFormInfoFromRequest(docLoader->request());
+ item->setFormInfoFromRequest(documentLoader->request());
}
// Set the item for which we will save document state
@@ -508,9 +509,21 @@ PassRefPtr<HistoryItem> HistoryController::createItemTree(Frame* targetFrame, bo
RefPtr<HistoryItem> bfItem = createItem(m_frame->tree()->parent() ? true : false);
if (m_previousItem)
saveScrollPositionAndViewStateToItem(m_previousItem.get());
- if (!(clipAtTarget && m_frame == targetFrame)) {
+
+ if (!clipAtTarget || m_frame != targetFrame) {
// save frame state for items that aren't loading (khtml doesn't save those)
saveDocumentState();
+
+ // clipAtTarget is false for navigations within the same document, so
+ // we should copy the documentSequenceNumber over to the newly create
+ // item. Non-target items are just clones, and they should therefore
+ // preserve the same itemSequenceNumber.
+ if (m_previousItem) {
+ if (m_frame != targetFrame)
+ bfItem->setItemSequenceNumber(m_previousItem->itemSequenceNumber());
+ bfItem->setDocumentSequenceNumber(m_previousItem->documentSequenceNumber());
+ }
+
for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) {
FrameLoader* childLoader = child->loader();
bool hasChildLoaded = childLoader->frameHasLoaded();
@@ -523,6 +536,7 @@ PassRefPtr<HistoryItem> HistoryController::createItemTree(Frame* targetFrame, bo
bfItem->addChildItem(childLoader->history()->createItemTree(targetFrame, clipAtTarget));
}
}
+ // FIXME: Eliminate the isTargetItem flag in favor of itemSequenceNumber.
if (m_frame == targetFrame)
bfItem->setIsTargetItem(true);
return bfItem;
@@ -537,21 +551,16 @@ void HistoryController::recursiveGoToItem(HistoryItem* item, HistoryItem* fromIt
ASSERT(item);
ASSERT(fromItem);
- KURL itemURL = item->url();
- KURL currentURL;
- if (m_frame->loader()->documentLoader())
- currentURL = m_frame->loader()->documentLoader()->url();
-
- // Always reload the target frame of the item we're going to. This ensures that we will
- // do -some- load for the transition, which means a proper notification will be posted
- // to the app.
- // The exact URL has to match, including fragment. We want to go through the _load
- // method, even if to do a within-page navigation.
- // The current frame tree and the frame tree snapshot in the item have to match.
- if (!item->isTargetItem() &&
- itemURL == currentURL &&
- ((m_frame->tree()->name().isEmpty() && item->target().isEmpty()) || m_frame->tree()->name() == item->target()) &&
- childFramesMatchItem(item))
+ // If the item we're going to is a clone of the item we're at, then do
+ // not load it again, and continue history traversal to its children.
+ // The current frame tree and the frame tree snapshot in the item have
+ // to match.
+ // Note: If item and fromItem are the same, then we need to create a new
+ // document.
+ if (item != fromItem
+ && item->itemSequenceNumber() == fromItem->itemSequenceNumber()
+ && currentFramesMatchItem(item)
+ && fromItem->hasSameFrames(item))
{
// This content is good, so leave it alone and look for children that need reloading
// Save form state (works from currentItem, since prevItem is nil)
@@ -576,7 +585,7 @@ void HistoryController::recursiveGoToItem(HistoryItem* item, HistoryItem* fromIt
for (int i = 0; i < size; ++i) {
String childFrameName = childItems[i]->target();
HistoryItem* fromChildItem = fromItem->childItemWithTarget(childFrameName);
- ASSERT(fromChildItem || fromItem->isTargetItem());
+ ASSERT(fromChildItem);
Frame* childFrame = m_frame->tree()->child(childFrameName);
ASSERT(childFrame);
childFrame->loader()->history()->recursiveGoToItem(childItems[i].get(), fromChildItem, type);
@@ -586,10 +595,12 @@ void HistoryController::recursiveGoToItem(HistoryItem* item, HistoryItem* fromIt
}
}
-// helper method that determines whether the subframes described by the item's subitems
-// match our own current frameset
-bool HistoryController::childFramesMatchItem(HistoryItem* item) const
+// Helper method that determines whether the current frame tree matches given history item's.
+bool HistoryController::currentFramesMatchItem(HistoryItem* item) const
{
+ if ((!m_frame->tree()->uniqueName().isEmpty() || !item->target().isEmpty()) && m_frame->tree()->uniqueName() != item->target())
+ return false;
+
const HistoryItemVector& childItems = item->children();
if (childItems.size() != m_frame->tree()->childCount())
return false;
@@ -600,7 +611,6 @@ bool HistoryController::childFramesMatchItem(HistoryItem* item) const
return false;
}
- // Found matches for all item targets
return true;
}
@@ -624,43 +634,40 @@ void HistoryController::updateBackForwardListClippedAtTarget(bool doClip)
frameLoader->checkDidPerformFirstNavigation();
- RefPtr<HistoryItem> item = frameLoader->history()->createItemTree(m_frame, doClip);
- LOG(BackForward, "WebCoreBackForward - Adding backforward item %p for frame %s", item.get(), m_frame->loader()->documentLoader()->url().string().ascii().data());
- page->backForwardList()->addItem(item);
+ RefPtr<HistoryItem> topItem = frameLoader->history()->createItemTree(m_frame, doClip);
+ LOG(BackForward, "WebCoreBackForward - Adding backforward item %p for frame %s", topItem.get(), m_frame->loader()->documentLoader()->url().string().ascii().data());
+ page->backForward()->addItem(topItem.release());
}
void HistoryController::pushState(PassRefPtr<SerializedScriptValue> stateObject, const String& title, const String& urlString)
{
+ if (!m_currentItem)
+ return;
+
Page* page = m_frame->page();
ASSERT(page);
// Get a HistoryItem tree for the current frame tree.
- RefPtr<HistoryItem> item = createItemTree(m_frame, false);
- ASSERT(item->isTargetItem());
-
- // Override data in the target item to reflect the pushState() arguments.
- item->setTitle(title);
- item->setStateObject(stateObject);
- item->setURLString(urlString);
-
- // Since the document isn't changed as a result of a pushState call, we
- // should preserve the DocumentSequenceNumber of the previous item.
- item->setDocumentSequenceNumber(m_previousItem->documentSequenceNumber());
+ RefPtr<HistoryItem> topItem = page->mainFrame()->loader()->history()->createItemTree(m_frame, false);
- page->backForwardList()->pushStateItem(item.release());
+ // Override data in the current item (created by createItemTree) to reflect
+ // the pushState() arguments.
+ m_currentItem->setTitle(title);
+ m_currentItem->setStateObject(stateObject);
+ m_currentItem->setURLString(urlString);
+
+ page->backForward()->addItem(topItem.release());
}
void HistoryController::replaceState(PassRefPtr<SerializedScriptValue> stateObject, const String& title, const String& urlString)
{
- Page* page = m_frame->page();
- ASSERT(page);
- HistoryItem* current = page->backForwardList()->currentItem();
- ASSERT(current);
+ if (!m_currentItem)
+ return;
if (!urlString.isEmpty())
- current->setURLString(urlString);
- current->setTitle(title);
- current->setStateObject(stateObject);
+ m_currentItem->setURLString(urlString);
+ m_currentItem->setTitle(title);
+ m_currentItem->setStateObject(stateObject);
}
} // namespace WebCore
diff --git a/WebCore/loader/HistoryController.h b/WebCore/loader/HistoryController.h
index 7c4a1ac..1002dbc 100644
--- a/WebCore/loader/HistoryController.h
+++ b/WebCore/loader/HistoryController.h
@@ -43,6 +43,8 @@ class SerializedScriptValue;
class HistoryController : public Noncopyable {
public:
+ enum HistoryUpdateType { UpdateAll, UpdateAllExceptBackForwardList };
+
HistoryController(Frame*);
~HistoryController();
@@ -58,11 +60,10 @@ public:
void invalidateCurrentItemCachedPage();
void goToItem(HistoryItem*, FrameLoadType);
- bool urlsMatchItem(HistoryItem*) const;
void updateForBackForwardNavigation();
void updateForReload();
- void updateForStandardLoad();
+ void updateForStandardLoad(HistoryUpdateType updateType = UpdateAll);
void updateForRedirectWithLockedBackForwardList();
void updateForClientRedirect();
void updateForCommit();
@@ -72,6 +73,9 @@ public:
HistoryItem* currentItem() const { return m_currentItem.get(); }
void setCurrentItem(HistoryItem*);
void setCurrentItemTitle(const String&);
+ bool currentItemShouldBeReplaced() const;
+
+ HistoryItem* previousItem() const { return m_previousItem.get(); }
HistoryItem* provisionalItem() const { return m_provisionalItem.get(); }
void setProvisionalItem(HistoryItem*);
@@ -84,7 +88,7 @@ private:
PassRefPtr<HistoryItem> createItemTree(Frame* targetFrame, bool clipAtTarget);
void recursiveGoToItem(HistoryItem*, HistoryItem*, FrameLoadType);
- bool childFramesMatchItem(HistoryItem*) const;
+ bool currentFramesMatchItem(HistoryItem*) const;
void updateBackForwardListClippedAtTarget(bool doClip);
Frame* m_frame;
diff --git a/WebCore/loader/ImageDocument.cpp b/WebCore/loader/ImageDocument.cpp
deleted file mode 100644
index 2f564cc..0000000
--- a/WebCore/loader/ImageDocument.cpp
+++ /dev/null
@@ -1,401 +0,0 @@
-/*
- * Copyright (C) 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * 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 "ImageDocument.h"
-
-#include "CSSStyleDeclaration.h"
-#include "CachedImage.h"
-#include "DocumentLoader.h"
-#include "Element.h"
-#include "EventListener.h"
-#include "EventNames.h"
-#include "Frame.h"
-#include "FrameLoader.h"
-#include "FrameLoaderClient.h"
-#include "FrameView.h"
-#include "HTMLImageElement.h"
-#include "HTMLNames.h"
-#include "LocalizedStrings.h"
-#include "MouseEvent.h"
-#include "NotImplemented.h"
-#include "Page.h"
-#include "SegmentedString.h"
-#include "Settings.h"
-#include "Text.h"
-#include "XMLTokenizer.h"
-
-using std::min;
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-class ImageEventListener : public EventListener {
-public:
- static PassRefPtr<ImageEventListener> create(ImageDocument* document) { return adoptRef(new ImageEventListener(document)); }
- static const ImageEventListener* cast(const EventListener* listener)
- {
- return listener->type() == ImageEventListenerType
- ? static_cast<const ImageEventListener*>(listener)
- : 0;
- }
-
- virtual bool operator==(const EventListener& other);
-
-private:
- ImageEventListener(ImageDocument* document)
- : EventListener(ImageEventListenerType)
- , m_doc(document)
- {
- }
-
- virtual void handleEvent(ScriptExecutionContext*, Event*);
-
- ImageDocument* m_doc;
-};
-
-class ImageTokenizer : public Tokenizer {
-public:
- ImageTokenizer(ImageDocument* doc) : m_doc(doc) {}
-
- virtual void write(const SegmentedString&, bool appendData);
- virtual void finish();
- virtual bool isWaitingForScripts() const;
-
- virtual bool wantsRawData() const { return true; }
- virtual bool writeRawData(const char* data, int len);
-
-private:
- ImageDocument* m_doc;
-};
-
-class ImageDocumentElement : public HTMLImageElement {
-public:
- ImageDocumentElement(ImageDocument* doc)
- : HTMLImageElement(imgTag, doc)
- , m_imageDocument(doc)
- {
- }
-
- virtual ~ImageDocumentElement();
- virtual void willMoveToNewOwnerDocument();
-
-private:
- ImageDocument* m_imageDocument;
-};
-
-// --------
-
-void ImageTokenizer::write(const SegmentedString&, bool)
-{
- // <https://bugs.webkit.org/show_bug.cgi?id=25397>: JS code can always call document.write, we need to handle it.
- notImplemented();
-}
-
-bool ImageTokenizer::writeRawData(const char*, int)
-{
- Frame* frame = m_doc->frame();
- Settings* settings = frame->settings();
- if (!frame->loader()->client()->allowImages(!settings || settings->areImagesEnabled()))
- return false;
-
- CachedImage* cachedImage = m_doc->cachedImage();
- cachedImage->data(frame->loader()->documentLoader()->mainResourceData(), false);
-
- m_doc->imageChanged();
-
- return false;
-}
-
-void ImageTokenizer::finish()
-{
- if (!m_parserStopped && m_doc->imageElement()) {
- CachedImage* cachedImage = m_doc->cachedImage();
- RefPtr<SharedBuffer> data = m_doc->frame()->loader()->documentLoader()->mainResourceData();
-
- // If this is a multipart image, make a copy of the current part, since the resource data
- // will be overwritten by the next part.
- if (m_doc->frame()->loader()->documentLoader()->isLoadingMultipartContent())
- data = data->copy();
-
- cachedImage->data(data.release(), true);
- cachedImage->finish();
-
- cachedImage->setResponse(m_doc->frame()->loader()->documentLoader()->response());
-
- IntSize size = cachedImage->imageSize(m_doc->frame()->pageZoomFactor());
- if (size.width()) {
- // Compute the title, we use the decoded filename of the resource, falling
- // back on the (decoded) hostname if there is no path.
- String fileName = decodeURLEscapeSequences(m_doc->url().lastPathComponent());
- if (fileName.isEmpty())
- fileName = m_doc->url().host();
- m_doc->setTitle(imageTitle(fileName, size));
- }
-
- m_doc->imageChanged();
- }
-
- m_doc->finishedParsing();
-}
-
-bool ImageTokenizer::isWaitingForScripts() const
-{
- // An image document is never waiting for scripts
- return false;
-}
-
-// --------
-
-ImageDocument::ImageDocument(Frame* frame)
- : HTMLDocument(frame)
- , m_imageElement(0)
- , m_imageSizeIsKnown(false)
- , m_didShrinkImage(false)
- , m_shouldShrinkImage(shouldShrinkToFit())
-{
- setParseMode(Compat);
-}
-
-Tokenizer* ImageDocument::createTokenizer()
-{
- return new ImageTokenizer(this);
-}
-
-void ImageDocument::createDocumentStructure()
-{
- ExceptionCode ec;
-
- RefPtr<Element> rootElement = Document::createElement(htmlTag, false);
- appendChild(rootElement, ec);
-
- RefPtr<Element> body = Document::createElement(bodyTag, false);
- body->setAttribute(styleAttr, "margin: 0px;");
-
- rootElement->appendChild(body, ec);
-
- RefPtr<ImageDocumentElement> imageElement = new ImageDocumentElement(this);
-
- imageElement->setAttribute(styleAttr, "-webkit-user-select: none");
- imageElement->setLoadManually(true);
- imageElement->setSrc(url().string());
-
- body->appendChild(imageElement, ec);
-
- if (shouldShrinkToFit()) {
- // Add event listeners
- RefPtr<EventListener> listener = ImageEventListener::create(this);
- if (DOMWindow* domWindow = this->domWindow())
- domWindow->addEventListener("resize", listener, false);
- imageElement->addEventListener("click", listener.release(), false);
- }
-
- m_imageElement = imageElement.get();
-}
-
-float ImageDocument::scale() const
-{
- if (!m_imageElement)
- return 1.0f;
-
- IntSize imageSize = m_imageElement->cachedImage()->imageSize(frame()->pageZoomFactor());
- IntSize windowSize = IntSize(frame()->view()->width(), frame()->view()->height());
-
- float widthScale = (float)windowSize.width() / imageSize.width();
- float heightScale = (float)windowSize.height() / imageSize.height();
-
- return min(widthScale, heightScale);
-}
-
-void ImageDocument::resizeImageToFit()
-{
- if (!m_imageElement)
- return;
-
- IntSize imageSize = m_imageElement->cachedImage()->imageSize(frame()->pageZoomFactor());
-
- float scale = this->scale();
- m_imageElement->setWidth(static_cast<int>(imageSize.width() * scale));
- m_imageElement->setHeight(static_cast<int>(imageSize.height() * scale));
-
- ExceptionCode ec;
- m_imageElement->style()->setProperty("cursor", "-webkit-zoom-in", ec);
-}
-
-void ImageDocument::imageClicked(int x, int y)
-{
- if (!m_imageSizeIsKnown || imageFitsInWindow())
- return;
-
- m_shouldShrinkImage = !m_shouldShrinkImage;
-
- if (m_shouldShrinkImage)
- windowSizeChanged();
- else {
- restoreImageSize();
-
- updateLayout();
-
- float scale = this->scale();
-
- int scrollX = static_cast<int>(x / scale - (float)frame()->view()->width() / 2);
- int scrollY = static_cast<int>(y / scale - (float)frame()->view()->height() / 2);
-
- frame()->view()->setScrollPosition(IntPoint(scrollX, scrollY));
- }
-}
-
-void ImageDocument::imageChanged()
-{
- ASSERT(m_imageElement);
-
- if (m_imageSizeIsKnown)
- return;
-
- if (m_imageElement->cachedImage()->imageSize(frame()->pageZoomFactor()).isEmpty())
- return;
-
- m_imageSizeIsKnown = true;
-
- if (shouldShrinkToFit()) {
- // Force resizing of the image
- windowSizeChanged();
- }
-}
-
-void ImageDocument::restoreImageSize()
-{
- if (!m_imageElement || !m_imageSizeIsKnown)
- return;
-
- m_imageElement->setWidth(m_imageElement->cachedImage()->imageSize(frame()->pageZoomFactor()).width());
- m_imageElement->setHeight(m_imageElement->cachedImage()->imageSize(frame()->pageZoomFactor()).height());
-
- ExceptionCode ec;
- if (imageFitsInWindow())
- m_imageElement->style()->removeProperty("cursor", ec);
- else
- m_imageElement->style()->setProperty("cursor", "-webkit-zoom-out", ec);
-
- m_didShrinkImage = false;
-}
-
-bool ImageDocument::imageFitsInWindow() const
-{
- if (!m_imageElement)
- return true;
-
- IntSize imageSize = m_imageElement->cachedImage()->imageSize(frame()->pageZoomFactor());
- IntSize windowSize = IntSize(frame()->view()->width(), frame()->view()->height());
-
- return imageSize.width() <= windowSize.width() && imageSize.height() <= windowSize.height();
-}
-
-void ImageDocument::windowSizeChanged()
-{
- if (!m_imageElement || !m_imageSizeIsKnown)
- return;
-
- bool fitsInWindow = imageFitsInWindow();
-
- // If the image has been explicitly zoomed in, restore the cursor if the image fits
- // and set it to a zoom out cursor if the image doesn't fit
- if (!m_shouldShrinkImage) {
- ExceptionCode ec;
-
- if (fitsInWindow)
- m_imageElement->style()->removeProperty("cursor", ec);
- else
- m_imageElement->style()->setProperty("cursor", "-webkit-zoom-out", ec);
- return;
- }
-
- if (m_didShrinkImage) {
- // If the window has been resized so that the image fits, restore the image size
- // otherwise update the restored image size.
- if (fitsInWindow)
- restoreImageSize();
- else
- resizeImageToFit();
- } else {
- // If the image isn't resized but needs to be, then resize it.
- if (!fitsInWindow) {
- resizeImageToFit();
- m_didShrinkImage = true;
- }
- }
-}
-
-CachedImage* ImageDocument::cachedImage()
-{
- if (!m_imageElement)
- createDocumentStructure();
-
- return m_imageElement->cachedImage();
-}
-
-bool ImageDocument::shouldShrinkToFit() const
-{
- return frame()->page()->settings()->shrinksStandaloneImagesToFit() &&
- frame()->page()->mainFrame() == frame();
-}
-
-// --------
-
-void ImageEventListener::handleEvent(ScriptExecutionContext*, Event* event)
-{
- if (event->type() == eventNames().resizeEvent)
- m_doc->windowSizeChanged();
- else if (event->type() == eventNames().clickEvent) {
- MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
- m_doc->imageClicked(mouseEvent->x(), mouseEvent->y());
- }
-}
-
-bool ImageEventListener::operator==(const EventListener& listener)
-{
- if (const ImageEventListener* imageEventListener = ImageEventListener::cast(&listener))
- return m_doc == imageEventListener->m_doc;
- return false;
-}
-
-// --------
-
-ImageDocumentElement::~ImageDocumentElement()
-{
- if (m_imageDocument)
- m_imageDocument->disconnectImageElement();
-}
-
-void ImageDocumentElement::willMoveToNewOwnerDocument()
-{
- if (m_imageDocument) {
- m_imageDocument->disconnectImageElement();
- m_imageDocument = 0;
- }
- HTMLImageElement::willMoveToNewOwnerDocument();
-}
-
-}
diff --git a/WebCore/loader/ImageDocument.h b/WebCore/loader/ImageDocument.h
deleted file mode 100644
index 080b250..0000000
--- a/WebCore/loader/ImageDocument.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * 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 ImageDocument_h
-#define ImageDocument_h
-
-#include "HTMLDocument.h"
-
-namespace WebCore {
-
-class ImageDocumentElement;
-
-class ImageDocument : public HTMLDocument {
-public:
- static PassRefPtr<ImageDocument> create(Frame* frame)
- {
- return adoptRef(new ImageDocument(frame));
- }
-
- CachedImage* cachedImage();
- ImageDocumentElement* imageElement() const { return m_imageElement; }
- void disconnectImageElement() { m_imageElement = 0; }
-
- void windowSizeChanged();
- void imageChanged();
- void imageClicked(int x, int y);
-
-private:
- ImageDocument(Frame*);
-
- virtual Tokenizer* createTokenizer();
- virtual bool isImageDocument() const { return true; }
-
- void createDocumentStructure();
- void resizeImageToFit();
- void restoreImageSize();
- bool imageFitsInWindow() const;
- bool shouldShrinkToFit() const;
- float scale() const;
-
- ImageDocumentElement* m_imageElement;
-
- // Whether enough of the image has been loaded to determine its size
- bool m_imageSizeIsKnown;
-
- // Whether the image is shrunk to fit or not
- bool m_didShrinkImage;
-
- // Whether the image should be shrunk or not
- bool m_shouldShrinkImage;
-};
-
-}
-
-#endif // ImageDocument_h
diff --git a/WebCore/loader/ImageLoader.cpp b/WebCore/loader/ImageLoader.cpp
index c61d133..94a21a4 100644
--- a/WebCore/loader/ImageLoader.cpp
+++ b/WebCore/loader/ImageLoader.cpp
@@ -22,13 +22,21 @@
#include "config.h"
#include "ImageLoader.h"
-#include "CSSHelper.h"
#include "CachedImage.h"
-#include "DocLoader.h"
+#include "CachedResourceLoader.h"
#include "Document.h"
#include "Element.h"
+#include "HTMLNames.h"
+#include "HTMLObjectElement.h"
#include "RenderImage.h"
+#if ENABLE(SVG)
+#include "RenderSVGImage.h"
+#endif
+#if ENABLE(VIDEO)
+#include "RenderVideo.h"
+#endif
+
#if !ASSERT_DISABLED
// ImageLoader objects are allocated as members of other objects, so generic pointer check would always fail.
namespace WTF {
@@ -128,11 +136,8 @@ void ImageLoader::setImage(CachedImage* newImage)
oldImage->removeClient(this);
}
- if (RenderObject* renderer = m_element->renderer()) {
- if (!renderer->isImage())
- return;
- toRenderImage(renderer)->resetAnimation();
- }
+ if (RenderImageResource* imageResource = renderImageResource())
+ imageResource->resetAnimation();
}
void ImageLoader::updateFromElement()
@@ -155,13 +160,15 @@ void ImageLoader::updateFromElement()
CachedImage* newImage = 0;
if (!(attr.isNull() || (attr.isEmpty() && document->baseURI().isLocalFile()))) {
if (m_loadManually) {
- document->docLoader()->setAutoLoadImages(false);
+ bool autoLoadOtherImages = document->cachedResourceLoader()->autoLoadImages();
+ document->cachedResourceLoader()->setAutoLoadImages(false);
newImage = new CachedImage(sourceURI(attr));
newImage->setLoading(true);
- newImage->setDocLoader(document->docLoader());
- document->docLoader()->m_documentResources.set(newImage->url(), newImage);
+ newImage->setCachedResourceLoader(document->cachedResourceLoader());
+ document->cachedResourceLoader()->m_documentResources.set(newImage->url(), newImage);
+ document->cachedResourceLoader()->setAutoLoadImages(autoLoadOtherImages);
} else
- newImage = document->docLoader()->requestImage(sourceURI(attr));
+ newImage = document->cachedResourceLoader()->requestImage(sourceURI(attr));
// If we do not have an image here, it means that a cross-site
// violation occurred.
@@ -191,11 +198,8 @@ void ImageLoader::updateFromElement()
oldImage->removeClient(this);
}
- if (RenderObject* renderer = m_element->renderer()) {
- if (!renderer->isImage())
- return;
- toRenderImage(renderer)->resetAnimation();
- }
+ if (RenderImageResource* imageResource = renderImageResource())
+ imageResource->resetAnimation();
}
void ImageLoader::updateFromElementIgnoringPreviousError()
@@ -219,20 +223,42 @@ void ImageLoader::notifyFinished(CachedResource*)
loadEventSender().dispatchEventSoon(this);
}
+RenderImageResource* ImageLoader::renderImageResource()
+{
+ RenderObject* renderer = m_element->renderer();
+
+ if (!renderer)
+ return 0;
+
+ if (renderer->isImage())
+ return toRenderImage(renderer)->imageResource();
+
+#if ENABLE(SVG)
+ if (renderer->isSVGImage())
+ return toRenderSVGImage(renderer)->imageResource();
+#endif
+
+#if ENABLE(VIDEO)
+ if (renderer->isVideo())
+ return toRenderVideo(renderer)->imageResource();
+#endif
+
+ return 0;
+}
+
void ImageLoader::updateRenderer()
{
- if (RenderObject* renderer = m_element->renderer()) {
- if (!renderer->isImage() && !renderer->isVideo())
- return;
- RenderImage* imageRenderer = toRenderImage(renderer);
-
- // Only update the renderer if it doesn't have an image or if what we have
- // is a complete image. This prevents flickering in the case where a dynamic
- // change is happening between two images.
- CachedImage* cachedImage = imageRenderer->cachedImage();
- if (m_image != cachedImage && (m_imageComplete || !imageRenderer->cachedImage()))
- imageRenderer->setCachedImage(m_image.get());
- }
+ RenderImageResource* imageResource = renderImageResource();
+
+ if (!imageResource)
+ return;
+
+ // Only update the renderer if it doesn't have an image or if what we have
+ // is a complete image. This prevents flickering in the case where a dynamic
+ // change is happening between two images.
+ CachedImage* cachedImage = imageResource->cachedImage();
+ if (m_image != cachedImage && (m_imageComplete || !cachedImage))
+ imageResource->setCachedImage(m_image.get());
}
void ImageLoader::dispatchPendingBeforeLoadEvent()
@@ -253,6 +279,9 @@ void ImageLoader::dispatchPendingBeforeLoadEvent()
m_image = 0;
}
loadEventSender().cancelEvent(this);
+
+ if (m_element->hasTagName(HTMLNames::objectTag))
+ static_cast<HTMLObjectElement*>(m_element)->renderFallbackContent();
}
void ImageLoader::dispatchPendingLoadEvent()
@@ -277,6 +306,11 @@ void ImageLoader::dispatchPendingLoadEvents()
loadEventSender().dispatchPendingEvents();
}
+void ImageLoader::elementWillMoveToNewOwnerDocument()
+{
+ setImage(0);
+}
+
ImageEventSender::ImageEventSender(const AtomicString& eventType)
: m_eventType(eventType)
, m_timer(this, &ImageEventSender::timerFired)
diff --git a/WebCore/loader/ImageLoader.h b/WebCore/loader/ImageLoader.h
index 44fe98e..9bf7624 100644
--- a/WebCore/loader/ImageLoader.h
+++ b/WebCore/loader/ImageLoader.h
@@ -23,14 +23,15 @@
#ifndef ImageLoader_h
#define ImageLoader_h
-#include "AtomicString.h"
#include "CachedResourceClient.h"
#include "CachedResourceHandle.h"
+#include <wtf/text/AtomicString.h>
namespace WebCore {
class Element;
class ImageLoadEventSender;
+class RenderImageResource;
class ImageLoader : public CachedResourceClient {
public:
@@ -45,6 +46,8 @@ public:
// doesn't change; starts new load unconditionally (matches Firefox and Opera behavior).
void updateFromElementIgnoringPreviousError();
+ void elementWillMoveToNewOwnerDocument();
+
Element* element() const { return m_element; }
bool imageComplete() const { return m_imageComplete; }
@@ -70,6 +73,7 @@ private:
void dispatchPendingBeforeLoadEvent();
void dispatchPendingLoadEvent();
+ RenderImageResource* renderImageResource();
void updateRenderer();
Element* m_element;
diff --git a/WebCore/loader/MainResourceLoader.cpp b/WebCore/loader/MainResourceLoader.cpp
index 3e75880..7e5eb90 100644
--- a/WebCore/loader/MainResourceLoader.cpp
+++ b/WebCore/loader/MainResourceLoader.cpp
@@ -31,6 +31,7 @@
#include "MainResourceLoader.h"
#include "ApplicationCacheHost.h"
+#include "DocumentLoadTiming.h"
#include "DocumentLoader.h"
#include "FormState.h"
#include "Frame.h"
@@ -43,7 +44,9 @@
#endif
#include "ResourceError.h"
#include "ResourceHandle.h"
+#include "SchemeRegistry.h"
#include "Settings.h"
+#include <wtf/CurrentTime.h>
// FIXME: More that is in common with SubresourceLoader should move up into ResourceLoader.
@@ -120,10 +123,17 @@ void MainResourceLoader::callContinueAfterNavigationPolicy(void* argument, const
static_cast<MainResourceLoader*>(argument)->continueAfterNavigationPolicy(request, shouldContinue);
}
-void MainResourceLoader::continueAfterNavigationPolicy(const ResourceRequest&, bool shouldContinue)
+void MainResourceLoader::continueAfterNavigationPolicy(const ResourceRequest& request, bool shouldContinue)
{
if (!shouldContinue)
stopLoadingForPolicyChange();
+ else if (m_substituteData.isValid()) {
+ // A redirect resulted in loading substitute data.
+ ASSERT(documentLoader()->timing()->redirectCount);
+ handle()->cancel();
+ handleDataLoadSoon(request);
+ }
+
deref(); // balances ref in willSendRequest
}
@@ -143,7 +153,7 @@ bool MainResourceLoader::isPostOrRedirectAfterPost(const ResourceRequest& newReq
void MainResourceLoader::addData(const char* data, int length, bool allAtOnce)
{
ResourceLoader::addData(data, length, allAtOnce);
- frameLoader()->receivedData(data, length);
+ documentLoader()->receivedData(data, length);
}
void MainResourceLoader::willSendRequest(ResourceRequest& newRequest, const ResourceResponse& redirectResponse)
@@ -157,7 +167,17 @@ void MainResourceLoader::willSendRequest(ResourceRequest& newRequest, const Reso
// The additional processing can do anything including possibly removing the last
// reference to this object; one example of this is 3266216.
RefPtr<MainResourceLoader> protect(this);
-
+
+ ASSERT(documentLoader()->timing()->fetchStart);
+ if (!redirectResponse.isNull()) {
+ DocumentLoadTiming* documentLoadTiming = documentLoader()->timing();
+ documentLoadTiming->redirectCount++;
+ if (!documentLoadTiming->redirectStart)
+ documentLoadTiming->redirectStart = documentLoadTiming->fetchStart;
+ documentLoadTiming->redirectEnd = currentTime();
+ documentLoadTiming->fetchStart = documentLoadTiming->redirectEnd;
+ }
+
// Update cookie policy base URL as URL changes, except for subframes, which use the
// URL of the main frame which doesn't change when we redirect.
if (frameLoader()->isLoadingMainFrame())
@@ -179,6 +199,14 @@ void MainResourceLoader::willSendRequest(ResourceRequest& newRequest, const Reso
if (top != m_frame)
frameLoader()->checkIfDisplayInsecureContent(top->document()->securityOrigin(), newRequest.url());
+#if ENABLE(OFFLINE_WEB_APPLICATIONS)
+ if (!redirectResponse.isNull()) {
+ // We checked application cache for initial URL, now we need to check it for redirected one.
+ ASSERT(!m_substituteData.isValid());
+ documentLoader()->applicationCacheHost()->maybeLoadMainResourceForRedirect(newRequest, m_substituteData);
+ }
+#endif
+
// 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
@@ -194,7 +222,7 @@ static bool shouldLoadAsEmptyDocument(const KURL& url)
#if PLATFORM(TORCHMOBILE)
return url.isEmpty() || (url.protocolIs("about") && equalIgnoringRef(url, blankURL()));
#else
- return url.isEmpty() || url.protocolIs("about");
+ return url.isEmpty() || SchemeRegistry::shouldLoadURLSchemeAsEmptyDocument(url.protocol());
#endif
}
@@ -223,7 +251,7 @@ void MainResourceLoader::continueAfterContentPolicy(PolicyAction contentPolicy,
receivedError(cannotShowURLError());
return;
}
- frameLoader()->client()->download(m_handle.get(), request(), m_handle.get()->request(), r);
+ frameLoader()->client()->download(m_handle.get(), request(), m_handle.get()->firstRequest(), r);
// It might have gone missing
if (frameLoader())
receivedError(interruptionForPolicyChangeError());
@@ -262,9 +290,9 @@ void MainResourceLoader::continueAfterContentPolicy(PolicyAction contentPolicy,
if (m_substituteData.content()->size())
didReceiveData(m_substituteData.content()->data(), m_substituteData.content()->size(), m_substituteData.content()->size(), true);
if (frameLoader() && !frameLoader()->isStopping())
- didFinishLoading();
+ didFinishLoading(0);
} else if (shouldLoadAsEmptyDocument(url) || frameLoader()->representationExistsForURLScheme(url.protocol()))
- didFinishLoading();
+ didFinishLoading(0);
}
}
@@ -285,15 +313,15 @@ void MainResourceLoader::continueAfterContentPolicy(PolicyAction policy)
#if PLATFORM(QT)
void MainResourceLoader::substituteMIMETypeFromPluginDatabase(const ResourceResponse& r)
{
- if (!m_frame->settings()->arePluginsEnabled())
+ if (!m_frame->loader()->subframeLoader()->allowPlugins(NotAboutToInstantiatePlugin))
return;
String filename = r.url().lastPathComponent();
if (filename.endsWith("/"))
return;
- int extensionPos = filename.reverseFind('.');
- if (extensionPos == -1)
+ size_t extensionPos = filename.reverseFind('.');
+ if (extensionPos == notFound)
return;
String extension = filename.substring(extensionPos + 1);
@@ -402,10 +430,12 @@ void MainResourceLoader::didReceiveData(const char* data, int length, long long
// reference to this object; one example of this is 3266216.
RefPtr<MainResourceLoader> protect(this);
+ m_timeOfLastDataReceived = currentTime();
+
ResourceLoader::didReceiveData(data, length, lengthReceived, allAtOnce);
}
-void MainResourceLoader::didFinishLoading()
+void MainResourceLoader::didFinishLoading(double finishTime)
{
// There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred.
// See <rdar://problem/6304600> for more details.
@@ -421,8 +451,10 @@ void MainResourceLoader::didFinishLoading()
RefPtr<DocumentLoader> dl = documentLoader();
#endif
+ ASSERT(!documentLoader()->timing()->responseEnd);
+ documentLoader()->timing()->responseEnd = finishTime ? finishTime : m_timeOfLastDataReceived;
frameLoader()->finishedLoading();
- ResourceLoader::didFinishLoading();
+ ResourceLoader::didFinishLoading(finishTime);
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
dl->applicationCacheHost()->finishedLoadingMainResource();
@@ -464,6 +496,10 @@ void MainResourceLoader::handleDataLoadNow(MainResourceLoaderTimer*)
KURL url = m_substituteData.responseURL();
if (url.isEmpty())
url = m_initialRequest.url();
+
+ // Clear the initial request here so that subsequent entries into the
+ // loader will not think there's still a deferred load left to do.
+ m_initialRequest = ResourceRequest();
ResourceResponse response(url, m_substituteData.mimeType(), m_substituteData.content()->size(), m_substituteData.textEncoding(), "");
didReceiveResponse(response);
@@ -479,7 +515,7 @@ void MainResourceLoader::startDataLoadTimer()
#endif
}
-void MainResourceLoader::handleDataLoadSoon(ResourceRequest& r)
+void MainResourceLoader::handleDataLoadSoon(const ResourceRequest& r)
{
m_initialRequest = r;
@@ -517,7 +553,7 @@ bool MainResourceLoader::loadNow(ResourceRequest& r)
else if (shouldLoadEmpty || frameLoader()->representationExistsForURLScheme(url.protocol()))
handleEmptyLoad(url, !shouldLoadEmpty);
else
- m_handle = ResourceHandle::create(r, this, m_frame.get(), false, true, true);
+ m_handle = ResourceHandle::create(m_frame->loader()->networkingContext(), r, this, false, true);
return false;
}
@@ -528,6 +564,9 @@ bool MainResourceLoader::load(const ResourceRequest& r, const SubstituteData& su
m_substituteData = substituteData;
+ ASSERT(documentLoader()->timing()->navigationStart);
+ ASSERT(!documentLoader()->timing()->fetchStart);
+ documentLoader()->timing()->fetchStart = currentTime();
ResourceRequest request(r);
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
diff --git a/WebCore/loader/MainResourceLoader.h b/WebCore/loader/MainResourceLoader.h
index eaaf2e8..1620f7a 100644
--- a/WebCore/loader/MainResourceLoader.h
+++ b/WebCore/loader/MainResourceLoader.h
@@ -26,6 +26,9 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#ifndef MainResourceLoader_h
+#define MainResourceLoader_h
+
#include "FrameLoaderTypes.h"
#include "ResourceLoader.h"
#include "SubstituteData.h"
@@ -55,7 +58,7 @@ namespace WebCore {
virtual void willSendRequest(ResourceRequest&, const ResourceResponse& redirectResponse);
virtual void didReceiveResponse(const ResourceResponse&);
virtual void didReceiveData(const char*, int, long long lengthReceived, bool allAtOnce);
- virtual void didFinishLoading();
+ virtual void didFinishLoading(double finishTime);
virtual void didFail(const ResourceError&);
#if HAVE(RUNLOOP_TIMER)
@@ -76,7 +79,7 @@ namespace WebCore {
bool loadNow(ResourceRequest&);
void handleEmptyLoad(const KURL&, bool forURLScheme);
- void handleDataLoadSoon(ResourceRequest& r);
+ void handleDataLoadSoon(const ResourceRequest& r);
void startDataLoadTimer();
void handleDataLoad(ResourceRequest&);
@@ -104,6 +107,9 @@ namespace WebCore {
bool m_loadingMultipartContent;
bool m_waitingForContentPolicy;
+ double m_timeOfLastDataReceived;
};
}
+
+#endif
diff --git a/WebCore/loader/MediaDocument.cpp b/WebCore/loader/MediaDocument.cpp
deleted file mode 100644
index a2d6276..0000000
--- a/WebCore/loader/MediaDocument.cpp
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * Copyright (C) 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#if ENABLE(VIDEO)
-#include "MediaDocument.h"
-
-#include "DocumentLoader.h"
-#include "Element.h"
-#include "Event.h"
-#include "EventNames.h"
-#include "Frame.h"
-#include "FrameLoader.h"
-#include "FrameLoaderClient.h"
-#include "HTMLEmbedElement.h"
-#include "HTMLNames.h"
-#include "HTMLVideoElement.h"
-#include "KeyboardEvent.h"
-#include "MainResourceLoader.h"
-#include "NodeList.h"
-#include "Page.h"
-#include "SegmentedString.h"
-#include "Settings.h"
-#include "Text.h"
-#include "XMLTokenizer.h"
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-class MediaTokenizer : public Tokenizer {
-public:
- MediaTokenizer(Document* doc) : m_doc(doc), m_mediaElement(0) {}
-
-private:
- virtual void write(const SegmentedString&, bool appendData);
- virtual void stopParsing();
- virtual void finish();
- virtual bool isWaitingForScripts() const;
-
- virtual bool wantsRawData() const { return true; }
- virtual bool writeRawData(const char* data, int len);
-
- void createDocumentStructure();
-
- Document* m_doc;
- HTMLMediaElement* m_mediaElement;
-};
-
-void MediaTokenizer::write(const SegmentedString&, bool)
-{
- ASSERT_NOT_REACHED();
-}
-
-void MediaTokenizer::createDocumentStructure()
-{
- ExceptionCode ec;
- RefPtr<Element> rootElement = m_doc->createElement(htmlTag, false);
- m_doc->appendChild(rootElement, ec);
-
- RefPtr<Element> body = m_doc->createElement(bodyTag, false);
- body->setAttribute(styleAttr, "background-color: rgb(38,38,38);");
-
- rootElement->appendChild(body, ec);
-
- RefPtr<Element> mediaElement = m_doc->createElement(videoTag, false);
-
- m_mediaElement = static_cast<HTMLVideoElement*>(mediaElement.get());
- m_mediaElement->setAttribute(controlsAttr, "");
- m_mediaElement->setAttribute(autoplayAttr, "");
- m_mediaElement->setAttribute(styleAttr, "margin: auto; position: absolute; top: 0; right: 0; bottom: 0; left: 0;");
-
- m_mediaElement->setAttribute(nameAttr, "media");
- m_mediaElement->setSrc(m_doc->url());
-
- body->appendChild(mediaElement, ec);
-
- Frame* frame = m_doc->frame();
- if (!frame)
- return;
-
- frame->loader()->activeDocumentLoader()->mainResourceLoader()->setShouldBufferData(false);
-}
-
-bool MediaTokenizer::writeRawData(const char*, int)
-{
- ASSERT(!m_mediaElement);
- if (m_mediaElement)
- return false;
-
- createDocumentStructure();
- finish();
- return false;
-}
-
-void MediaTokenizer::stopParsing()
-{
- Tokenizer::stopParsing();
-}
-
-void MediaTokenizer::finish()
-{
- if (!m_parserStopped)
- m_doc->finishedParsing();
-}
-
-bool MediaTokenizer::isWaitingForScripts() const
-{
- // A media document is never waiting for scripts
- return false;
-}
-
-MediaDocument::MediaDocument(Frame* frame)
- : HTMLDocument(frame)
- , m_replaceMediaElementTimer(this, &MediaDocument::replaceMediaElementTimerFired)
-{
- setParseMode(Compat);
-}
-
-MediaDocument::~MediaDocument()
-{
- ASSERT(!m_replaceMediaElementTimer.isActive());
-}
-
-Tokenizer* MediaDocument::createTokenizer()
-{
- return new MediaTokenizer(this);
-}
-
-void MediaDocument::defaultEventHandler(Event* event)
-{
- // Match the default Quicktime plugin behavior to allow
- // clicking and double-clicking to pause and play the media.
- Node* targetNode = event->target()->toNode();
- if (targetNode && targetNode->hasTagName(videoTag)) {
- HTMLVideoElement* video = static_cast<HTMLVideoElement*>(targetNode);
- if (event->type() == eventNames().clickEvent) {
- if (!video->canPlay()) {
- video->pause(event->fromUserGesture());
- event->setDefaultHandled();
- }
- } else if (event->type() == eventNames().dblclickEvent) {
- if (video->canPlay()) {
- video->play(event->fromUserGesture());
- event->setDefaultHandled();
- }
- }
- }
-
- if (event->type() == eventNames().keydownEvent && event->isKeyboardEvent()) {
- HTMLVideoElement* video = 0;
- if (targetNode) {
- if (targetNode->hasTagName(videoTag))
- video = static_cast<HTMLVideoElement*>(targetNode);
- else {
- RefPtr<NodeList> nodeList = targetNode->getElementsByTagName("video");
- if (nodeList.get()->length() > 0)
- video = static_cast<HTMLVideoElement*>(nodeList.get()->item(0));
- }
- }
- if (video) {
- KeyboardEvent* keyboardEvent = static_cast<KeyboardEvent*>(event);
- if (keyboardEvent->keyIdentifier() == "U+0020") { // space
- if (video->paused()) {
- if (video->canPlay())
- video->play(event->fromUserGesture());
- } else
- video->pause(event->fromUserGesture());
- event->setDefaultHandled();
- }
- }
- }
-}
-
-void MediaDocument::mediaElementSawUnsupportedTracks()
-{
- // The HTMLMediaElement was told it has something that the underlying
- // MediaPlayer cannot handle so we should switch from <video> to <embed>
- // and let the plugin handle this. Don't do it immediately as this
- // function may be called directly from a media engine callback, and
- // replaceChild will destroy the element, media player, and media engine.
- m_replaceMediaElementTimer.startOneShot(0);
-}
-
-void MediaDocument::replaceMediaElementTimerFired(Timer<MediaDocument>*)
-{
- HTMLElement* htmlBody = body();
- if (!htmlBody)
- return;
-
- // Set body margin width and height to 0 as that is what a PluginDocument uses.
- htmlBody->setAttribute(marginwidthAttr, "0");
- htmlBody->setAttribute(marginheightAttr, "0");
-
- RefPtr<NodeList> nodeList = htmlBody->getElementsByTagName("video");
-
- if (nodeList.get()->length() > 0) {
- HTMLVideoElement* videoElement = static_cast<HTMLVideoElement*>(nodeList.get()->item(0));
-
- RefPtr<Element> element = Document::createElement(embedTag, false);
- HTMLEmbedElement* embedElement = static_cast<HTMLEmbedElement*>(element.get());
-
- embedElement->setAttribute(widthAttr, "100%");
- embedElement->setAttribute(heightAttr, "100%");
- embedElement->setAttribute(nameAttr, "plugin");
- embedElement->setAttribute(srcAttr, url().string());
- embedElement->setAttribute(typeAttr, frame()->loader()->responseMIMEType());
-
- ExceptionCode ec;
- videoElement->parent()->replaceChild(embedElement, videoElement, ec);
- }
-}
-
-}
-#endif
diff --git a/WebCore/loader/NavigationScheduler.cpp b/WebCore/loader/NavigationScheduler.cpp
new file mode 100644
index 0000000..28fda9a
--- /dev/null
+++ b/WebCore/loader/NavigationScheduler.cpp
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010 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 "NavigationScheduler.h"
+
+#include "BackForwardController.h"
+#include "DOMWindow.h"
+#include "DocumentLoader.h"
+#include "Event.h"
+#include "FormState.h"
+#include "FormSubmission.h"
+#include "Frame.h"
+#include "FrameLoadRequest.h"
+#include "FrameLoader.h"
+#include "FrameLoaderStateMachine.h"
+#include "HTMLFormElement.h"
+#include "HTMLFrameOwnerElement.h"
+#include "HistoryItem.h"
+#include "Page.h"
+#include "UserGestureIndicator.h"
+#include <wtf/CurrentTime.h>
+
+namespace WebCore {
+
+class ScheduledNavigation : public Noncopyable {
+public:
+ ScheduledNavigation(double delay, bool lockHistory, bool lockBackForwardList, bool wasDuringLoad, bool isLocationChange)
+ : m_delay(delay)
+ , m_lockHistory(lockHistory)
+ , m_lockBackForwardList(lockBackForwardList)
+ , m_wasDuringLoad(wasDuringLoad)
+ , m_isLocationChange(isLocationChange)
+ , m_wasUserGesture(ScriptController::processingUserGesture())
+ {
+ }
+ virtual ~ScheduledNavigation() { }
+
+ virtual void fire(Frame*) = 0;
+
+ virtual bool shouldStartTimer(Frame*) { return true; }
+ virtual void didStartTimer(Frame*, Timer<NavigationScheduler>*) { }
+ virtual void didStopTimer(Frame*, bool /* newLoadInProgress */) { }
+
+ double delay() const { return m_delay; }
+ bool lockHistory() const { return m_lockHistory; }
+ bool lockBackForwardList() const { return m_lockBackForwardList; }
+ bool wasDuringLoad() const { return m_wasDuringLoad; }
+ bool isLocationChange() const { return m_isLocationChange; }
+ bool wasUserGesture() const { return m_wasUserGesture; }
+
+private:
+ double m_delay;
+ bool m_lockHistory;
+ bool m_lockBackForwardList;
+ bool m_wasDuringLoad;
+ bool m_isLocationChange;
+ bool m_wasUserGesture;
+};
+
+class ScheduledURLNavigation : public ScheduledNavigation {
+public:
+ ScheduledURLNavigation(double delay, const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool duringLoad, bool isLocationChange)
+ : ScheduledNavigation(delay, lockHistory, lockBackForwardList, duringLoad, isLocationChange)
+ , m_url(url)
+ , m_referrer(referrer)
+ , m_haveToldClient(false)
+ {
+ }
+
+ virtual void fire(Frame* frame)
+ {
+ UserGestureIndicator gestureIndicator(wasUserGesture() ? DefinitelyProcessingUserGesture : DefinitelyNotProcessingUserGesture);
+ frame->loader()->changeLocation(KURL(ParsedURLString, m_url), m_referrer, lockHistory(), lockBackForwardList(), false);
+ }
+
+ virtual void didStartTimer(Frame* frame, Timer<NavigationScheduler>* timer)
+ {
+ if (m_haveToldClient)
+ return;
+ m_haveToldClient = true;
+ frame->loader()->clientRedirected(KURL(ParsedURLString, m_url), delay(), currentTime() + timer->nextFireInterval(), lockBackForwardList());
+ }
+
+ virtual void didStopTimer(Frame* frame, bool newLoadInProgress)
+ {
+ if (!m_haveToldClient)
+ return;
+ frame->loader()->clientRedirectCancelledOrFinished(newLoadInProgress);
+ }
+
+ String url() const { return m_url; }
+ String referrer() const { return m_referrer; }
+
+private:
+ String m_url;
+ String m_referrer;
+ bool m_haveToldClient;
+};
+
+class ScheduledRedirect : public ScheduledURLNavigation {
+public:
+ ScheduledRedirect(double delay, const String& url, bool lockHistory, bool lockBackForwardList)
+ : ScheduledURLNavigation(delay, url, String(), lockHistory, lockBackForwardList, false, false)
+ {
+ }
+
+ virtual bool shouldStartTimer(Frame* frame) { return frame->loader()->allAncestorsAreComplete(); }
+};
+
+class ScheduledLocationChange : public ScheduledURLNavigation {
+public:
+ ScheduledLocationChange(const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool duringLoad)
+ : ScheduledURLNavigation(0.0, url, referrer, lockHistory, lockBackForwardList, duringLoad, true) { }
+};
+
+class ScheduledRefresh : public ScheduledURLNavigation {
+public:
+ ScheduledRefresh(const String& url, const String& referrer)
+ : ScheduledURLNavigation(0.0, url, referrer, true, true, false, true)
+ {
+ }
+
+ virtual void fire(Frame* frame)
+ {
+ UserGestureIndicator gestureIndicator(wasUserGesture() ? DefinitelyProcessingUserGesture : DefinitelyNotProcessingUserGesture);
+ frame->loader()->changeLocation(KURL(ParsedURLString, url()), referrer(), lockHistory(), lockBackForwardList(), true);
+ }
+};
+
+class ScheduledHistoryNavigation : public ScheduledNavigation {
+public:
+ explicit ScheduledHistoryNavigation(int historySteps)
+ : ScheduledNavigation(0, false, false, false, true)
+ , m_historySteps(historySteps)
+ {
+ }
+
+ virtual void fire(Frame* frame)
+ {
+ UserGestureIndicator gestureIndicator(wasUserGesture() ? DefinitelyProcessingUserGesture : DefinitelyNotProcessingUserGesture);
+
+ FrameLoader* loader = frame->loader();
+ if (!m_historySteps) {
+ // Special case for go(0) from a frame -> reload only the frame
+ // To follow Firefox and IE's behavior, history reload can only navigate the self frame.
+ loader->urlSelected(loader->url(), "_self", 0, lockHistory(), lockBackForwardList(), SendReferrer);
+ 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.
+ frame->page()->backForward()->goBackOrForward(m_historySteps);
+ }
+
+private:
+ int m_historySteps;
+};
+
+class ScheduledFormSubmission : public ScheduledNavigation {
+public:
+ ScheduledFormSubmission(PassRefPtr<FormSubmission> submission, bool lockBackForwardList, bool duringLoad)
+ : ScheduledNavigation(0, submission->lockHistory(), lockBackForwardList, duringLoad, true)
+ , m_submission(submission)
+ , m_haveToldClient(false)
+ {
+ ASSERT(m_submission->state());
+ }
+
+ virtual void fire(Frame* frame)
+ {
+ UserGestureIndicator gestureIndicator(wasUserGesture() ? DefinitelyProcessingUserGesture : DefinitelyNotProcessingUserGesture);
+
+ // 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 (!m_submission->state()->sourceFrame()->loader()->shouldAllowNavigation(frame))
+ return;
+ FrameLoadRequest frameRequest;
+ m_submission->populateFrameLoadRequest(frameRequest);
+ frame->loader()->loadFrameRequest(frameRequest, lockHistory(), lockBackForwardList(), m_submission->event(), m_submission->state(), SendReferrer);
+ }
+
+ virtual void didStartTimer(Frame* frame, Timer<NavigationScheduler>* timer)
+ {
+ if (m_haveToldClient)
+ return;
+ m_haveToldClient = true;
+ frame->loader()->clientRedirected(m_submission->requestURL(), delay(), currentTime() + timer->nextFireInterval(), lockBackForwardList());
+ }
+
+ virtual void didStopTimer(Frame* frame, bool newLoadInProgress)
+ {
+ if (!m_haveToldClient)
+ return;
+ frame->loader()->clientRedirectCancelledOrFinished(newLoadInProgress);
+ }
+
+private:
+ RefPtr<FormSubmission> m_submission;
+ bool m_haveToldClient;
+};
+
+NavigationScheduler::NavigationScheduler(Frame* frame)
+ : m_frame(frame)
+ , m_timer(this, &NavigationScheduler::timerFired)
+{
+}
+
+NavigationScheduler::~NavigationScheduler()
+{
+}
+
+bool NavigationScheduler::redirectScheduledDuringLoad()
+{
+ return m_redirect && m_redirect->wasDuringLoad();
+}
+
+bool NavigationScheduler::locationChangePending()
+{
+ return m_redirect && m_redirect->isLocationChange();
+}
+
+void NavigationScheduler::clear()
+{
+ m_timer.stop();
+ m_redirect.clear();
+}
+
+void NavigationScheduler::scheduleRedirect(double delay, const String& url)
+{
+ if (!m_frame->page())
+ return;
+ if (delay < 0 || delay > INT_MAX / 1000)
+ return;
+ if (url.isEmpty())
+ return;
+
+ // We want a new back/forward list item if the refresh timeout is > 1 second.
+ if (!m_redirect || delay <= m_redirect->delay())
+ schedule(adoptPtr(new ScheduledRedirect(delay, url, true, delay <= 1)));
+}
+
+bool NavigationScheduler::mustLockBackForwardList(Frame* targetFrame)
+{
+ // Non-user navigation before the page has finished firing onload should not create a new back/forward item.
+ // See https://webkit.org/b/42861 for the original motivation for this.
+ if (!ScriptController::processingUserGesture() && targetFrame->loader()->documentLoader() && !targetFrame->loader()->documentLoader()->wasOnloadHandled())
+ return true;
+
+ // 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 NavigationScheduler::scheduleLocationChange(const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList)
+{
+ 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);
+ 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->stateMachine()->committedFirstRealDocumentLoad();
+
+ schedule(adoptPtr(new ScheduledLocationChange(url, referrer, lockHistory, lockBackForwardList, duringLoad)));
+}
+
+void NavigationScheduler::scheduleFormSubmission(PassRefPtr<FormSubmission> submission)
+{
+ ASSERT(m_frame->page());
+
+ // 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()->stateMachine()->committedFirstRealDocumentLoad();
+
+ // If this is a child frame and the form submission was triggered by a script, lock the back/forward list
+ // to match IE and Opera.
+ // See https://bugs.webkit.org/show_bug.cgi?id=32383 for the original motivation for this.
+ bool lockBackForwardList = mustLockBackForwardList(m_frame)
+ || (submission->state()->formSubmissionTrigger() == SubmittedByJavaScript
+ && m_frame->tree()->parent() && !ScriptController::processingUserGesture());
+
+ schedule(adoptPtr(new ScheduledFormSubmission(submission, lockBackForwardList, duringLoad)));
+}
+
+void NavigationScheduler::scheduleRefresh()
+{
+ if (!m_frame->page())
+ return;
+ const KURL& url = m_frame->loader()->url();
+ if (url.isEmpty())
+ return;
+
+ schedule(adoptPtr(new ScheduledRefresh(url.string(), m_frame->loader()->outgoingReferrer())));
+}
+
+void NavigationScheduler::scheduleHistoryNavigation(int steps)
+{
+ if (!m_frame->page())
+ return;
+
+ // Invalid history navigations (such as history.forward() during a new load) have the side effect of cancelling any scheduled
+ // redirects. We also avoid the possibility of cancelling the current load by avoiding the scheduled redirection altogether.
+ BackForwardController* backForward = m_frame->page()->backForward();
+ if (steps > backForward->forwardCount() || -steps > backForward->backCount()) {
+ cancel();
+ return;
+ }
+
+ // In all other cases, schedule the history traversal to occur asynchronously.
+ schedule(adoptPtr(new ScheduledHistoryNavigation(steps)));
+}
+
+void NavigationScheduler::timerFired(Timer<NavigationScheduler>*)
+{
+ if (!m_frame->page())
+ return;
+ if (m_frame->page()->defersLoading())
+ return;
+
+ OwnPtr<ScheduledNavigation> redirect(m_redirect.release());
+ redirect->fire(m_frame);
+}
+
+void NavigationScheduler::schedule(PassOwnPtr<ScheduledNavigation> redirect)
+{
+ 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 (redirect->wasDuringLoad()) {
+ if (DocumentLoader* provisionalDocumentLoader = m_frame->loader()->provisionalDocumentLoader())
+ provisionalDocumentLoader->stopLoading();
+ m_frame->loader()->stopLoading(UnloadEventPolicyUnloadAndPageHide);
+ }
+
+ cancel();
+ m_redirect = redirect;
+
+ if (!m_frame->loader()->isComplete() && m_redirect->isLocationChange())
+ m_frame->loader()->completed();
+
+ startTimer();
+}
+
+void NavigationScheduler::startTimer()
+{
+ if (!m_redirect)
+ return;
+
+ ASSERT(m_frame->page());
+ if (m_timer.isActive())
+ return;
+ if (!m_redirect->shouldStartTimer(m_frame))
+ return;
+
+ m_timer.startOneShot(m_redirect->delay());
+ m_redirect->didStartTimer(m_frame, &m_timer);
+}
+
+void NavigationScheduler::cancel(bool newLoadInProgress)
+{
+ m_timer.stop();
+
+ OwnPtr<ScheduledNavigation> redirect(m_redirect.release());
+ if (redirect)
+ redirect->didStopTimer(m_frame, newLoadInProgress);
+}
+
+} // namespace WebCore
diff --git a/WebCore/loader/RedirectScheduler.h b/WebCore/loader/NavigationScheduler.h
index 005a173..3bf5010 100644
--- a/WebCore/loader/RedirectScheduler.h
+++ b/WebCore/loader/NavigationScheduler.h
@@ -33,6 +33,7 @@
#include "Event.h"
#include "Timer.h"
+#include <wtf/Forward.h>
#include <wtf/OwnPtr.h>
#include <wtf/PassOwnPtr.h>
#include <wtf/PassRefPtr.h>
@@ -40,24 +41,24 @@
namespace WebCore {
class FormState;
+class FormSubmission;
class Frame;
-class String;
struct FrameLoadRequest;
-struct ScheduledRedirection;
+class ScheduledNavigation;
-class RedirectScheduler : public Noncopyable {
+class NavigationScheduler : public Noncopyable {
public:
- RedirectScheduler(Frame*);
- ~RedirectScheduler();
+ NavigationScheduler(Frame*);
+ ~NavigationScheduler();
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<Event>, PassRefPtr<FormState>);
- void scheduleRefresh(bool userGesture = false);
+ void scheduleLocationChange(const String& url, const String& referrer, bool lockHistory = true, bool lockBackForwardList = true);
+ void scheduleFormSubmission(PassRefPtr<FormSubmission>);
+ void scheduleRefresh();
void scheduleHistoryNavigation(int steps);
void startTimer();
@@ -66,16 +67,16 @@ public:
void clear();
private:
- void timerFired(Timer<RedirectScheduler>*);
- void schedule(PassOwnPtr<ScheduledRedirection>);
+ void timerFired(Timer<NavigationScheduler>*);
+ void schedule(PassOwnPtr<ScheduledNavigation>);
static bool mustLockBackForwardList(Frame* targetFrame);
Frame* m_frame;
- Timer<RedirectScheduler> m_timer;
- OwnPtr<ScheduledRedirection> m_scheduledRedirection;
+ Timer<NavigationScheduler> m_timer;
+ OwnPtr<ScheduledNavigation> m_redirect;
};
} // namespace WebCore
-#endif // FrameLoader_h
+#endif // RedirectScheduler_h
diff --git a/WebCore/loader/NetscapePlugInStreamLoader.cpp b/WebCore/loader/NetscapePlugInStreamLoader.cpp
index 9d0e81b..1225652 100644
--- a/WebCore/loader/NetscapePlugInStreamLoader.cpp
+++ b/WebCore/loader/NetscapePlugInStreamLoader.cpp
@@ -95,13 +95,13 @@ void NetscapePlugInStreamLoader::didReceiveData(const char* data, int length, lo
ResourceLoader::didReceiveData(data, length, lengthReceived, allAtOnce);
}
-void NetscapePlugInStreamLoader::didFinishLoading()
+void NetscapePlugInStreamLoader::didFinishLoading(double finishTime)
{
RefPtr<NetscapePlugInStreamLoader> protect(this);
m_documentLoader->removePlugInStreamLoader(this);
m_client->didFinishLoading(this);
- ResourceLoader::didFinishLoading();
+ ResourceLoader::didFinishLoading(finishTime);
}
void NetscapePlugInStreamLoader::didFail(const ResourceError& error)
diff --git a/WebCore/loader/NetscapePlugInStreamLoader.h b/WebCore/loader/NetscapePlugInStreamLoader.h
index 092c6fc..c8c4cb6 100644
--- a/WebCore/loader/NetscapePlugInStreamLoader.h
+++ b/WebCore/loader/NetscapePlugInStreamLoader.h
@@ -55,7 +55,7 @@ namespace WebCore {
private:
virtual void didReceiveResponse(const ResourceResponse&);
virtual void didReceiveData(const char*, int, long long lengthReceived, bool allAtOnce);
- virtual void didFinishLoading();
+ virtual void didFinishLoading(double finishTime);
virtual void didFail(const ResourceError&);
virtual void releaseResources();
diff --git a/WebCore/loader/PingLoader.cpp b/WebCore/loader/PingLoader.cpp
new file mode 100644
index 0000000..d687b42
--- /dev/null
+++ b/WebCore/loader/PingLoader.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "config.h"
+#include "PingLoader.h"
+
+#include "FormData.h"
+#include "Frame.h"
+#include "ResourceHandle.h"
+#include "SecurityOrigin.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/UnusedParam.h>
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+void PingLoader::loadImage(Frame* frame, const KURL& url)
+{
+ if (!frame->document()->securityOrigin()->canDisplay(url)) {
+ FrameLoader::reportLocalLoadFailed(frame, url);
+ return;
+ }
+
+ ResourceRequest request(url);
+ request.setTargetType(ResourceRequest::TargetIsImage);
+ request.setHTTPHeaderField("Cache-Control", "max-age=0");
+ if (!SecurityOrigin::shouldHideReferrer(request.url(), frame->loader()->outgoingReferrer()))
+ request.setHTTPReferrer(frame->loader()->outgoingReferrer());
+ frame->loader()->addExtraFieldsToSubresourceRequest(request);
+ OwnPtr<PingLoader> pingLoader = adoptPtr(new PingLoader(frame, request));
+
+ // Leak the ping loader, since it will kill itself as soon as it receives a response.
+ PingLoader* leakedPingLoader = pingLoader.leakPtr();
+ UNUSED_PARAM(leakedPingLoader);
+}
+
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/links.html#hyperlink-auditing
+void PingLoader::sendPing(Frame* frame, const KURL& pingURL, const KURL& destinationURL)
+{
+ ResourceRequest request(pingURL);
+ request.setTargetType(ResourceRequest::TargetIsSubresource);
+ request.setHTTPMethod("POST");
+ request.setHTTPContentType("text/ping");
+ request.setHTTPBody(FormData::create("PING"));
+ request.setHTTPHeaderField("Cache-Control", "max-age=0");
+ frame->loader()->addExtraFieldsToSubresourceRequest(request);
+
+ SecurityOrigin* sourceOrigin = frame->document()->securityOrigin();
+ RefPtr<SecurityOrigin> pingOrigin = SecurityOrigin::create(pingURL);
+ FrameLoader::addHTTPOriginIfNeeded(request, sourceOrigin->toString());
+ request.setHTTPHeaderField("Ping-To", destinationURL);
+ if (sourceOrigin->isSameSchemeHostPort(pingOrigin.get()))
+ request.setHTTPHeaderField("Ping-From", frame->document()->url());
+ else if (!SecurityOrigin::shouldHideReferrer(pingURL, frame->loader()->outgoingReferrer()))
+ request.setHTTPReferrer(frame->loader()->outgoingReferrer());
+ OwnPtr<PingLoader> pingLoader = adoptPtr(new PingLoader(frame, request));
+
+ // Leak the ping loader, since it will kill itself as soon as it receives a response.
+ PingLoader* leakedPingLoader = pingLoader.leakPtr();
+ UNUSED_PARAM(leakedPingLoader);
+}
+
+PingLoader::PingLoader(Frame* frame, const ResourceRequest& request)
+ : m_timeout(this, &PingLoader::timeout)
+{
+ m_handle = ResourceHandle::create(frame->loader()->networkingContext(), request, this, false, false);
+
+ // If the server never responds, FrameLoader won't be able to cancel this load and
+ // we'll sit here waiting forever. Set a very generous timeout, just in case.
+ m_timeout.startOneShot(60000);
+}
+
+PingLoader::~PingLoader()
+{
+ m_handle->cancel();
+}
+
+}
diff --git a/WebCore/loader/PingLoader.h b/WebCore/loader/PingLoader.h
new file mode 100644
index 0000000..eb43166
--- /dev/null
+++ b/WebCore/loader/PingLoader.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef PingLoader_h
+#define PingLoader_h
+
+#include "ResourceHandleClient.h"
+#include "Timer.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class Frame;
+class KURL;
+class ResourceError;
+class ResourceHandle;
+class ResourceResponse;
+
+// This class triggers asynchronous loads independent of Frame staying alive (i.e., auditing pingbacks).
+// Since nothing depends on resources loaded through this class, we just want
+// to allow the load to live long enough to ensure the message was actually sent.
+// Therefore, as soon as a callback is received from the ResourceHandle, this class
+// will cancel the load and delete itself.
+class PingLoader : private ResourceHandleClient, public Noncopyable {
+public:
+ static void loadImage(Frame*, const KURL& url);
+ static void sendPing(Frame*, const KURL& pingURL, const KURL& destinationURL);
+
+ ~PingLoader();
+
+private:
+ PingLoader(Frame*, const ResourceRequest&);
+
+ void didReceiveResponse(ResourceHandle*, const ResourceResponse&) { delete this; }
+ void didReceiveData(ResourceHandle*, const char*, int) { delete this; }
+ void didFinishLoading(ResourceHandle*, double) { delete this; }
+ void didFail(ResourceHandle*, const ResourceError&) { delete this; }
+ void timeout(Timer<PingLoader>*) { delete this; }
+
+ RefPtr<ResourceHandle> m_handle;
+ Timer<PingLoader> m_timeout;
+};
+
+}
+
+#endif
diff --git a/WebCore/loader/PlaceholderDocument.cpp b/WebCore/loader/PlaceholderDocument.cpp
index 81222b3..93a26db 100644
--- a/WebCore/loader/PlaceholderDocument.cpp
+++ b/WebCore/loader/PlaceholderDocument.cpp
@@ -26,9 +26,6 @@
#include "config.h"
#include "PlaceholderDocument.h"
-#include "CSSStyleSelector.h"
-#include "StyleSheetList.h"
-
namespace WebCore {
void PlaceholderDocument::attach()
diff --git a/WebCore/loader/PlaceholderDocument.h b/WebCore/loader/PlaceholderDocument.h
index 5b76a9c..3d40a6e 100644
--- a/WebCore/loader/PlaceholderDocument.h
+++ b/WebCore/loader/PlaceholderDocument.h
@@ -32,15 +32,15 @@ namespace WebCore {
class PlaceholderDocument : public Document {
public:
- static PassRefPtr<PlaceholderDocument> create(Frame* frame)
+ static PassRefPtr<PlaceholderDocument> create(Frame* frame, const KURL& url)
{
- return adoptRef(new PlaceholderDocument(frame));
+ return adoptRef(new PlaceholderDocument(frame, url));
}
virtual void attach();
private:
- PlaceholderDocument(Frame* frame) : Document(frame, false, false) { }
+ PlaceholderDocument(Frame* frame, const KURL& url) : Document(frame, url, false, false) { }
};
} // namespace WebCore
diff --git a/WebCore/loader/PluginDocument.cpp b/WebCore/loader/PluginDocument.cpp
deleted file mode 100644
index 788691f..0000000
--- a/WebCore/loader/PluginDocument.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2006, 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * 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 "PluginDocument.h"
-
-#include "DocumentLoader.h"
-#include "Element.h"
-#include "Frame.h"
-#include "FrameLoader.h"
-#include "FrameLoaderClient.h"
-#include "HTMLEmbedElement.h"
-#include "HTMLNames.h"
-#include "MainResourceLoader.h"
-#include "Page.h"
-#include "RenderWidget.h"
-#include "SegmentedString.h"
-#include "Settings.h"
-#include "Text.h"
-#include "XMLTokenizer.h"
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-class PluginTokenizer : public Tokenizer {
-public:
- PluginTokenizer(Document* doc) : m_doc(doc), m_embedElement(0) {}
-
-private:
- virtual void write(const SegmentedString&, bool appendData);
- virtual void stopParsing();
- virtual void finish();
- virtual bool isWaitingForScripts() const;
-
- virtual bool wantsRawData() const { return true; }
- virtual bool writeRawData(const char* data, int len);
-
- void createDocumentStructure();
-
- Document* m_doc;
- HTMLEmbedElement* m_embedElement;
-};
-
-void PluginTokenizer::write(const SegmentedString&, bool)
-{
- ASSERT_NOT_REACHED();
-}
-
-void PluginTokenizer::createDocumentStructure()
-{
- ExceptionCode ec;
- RefPtr<Element> rootElement = m_doc->createElement(htmlTag, false);
- m_doc->appendChild(rootElement, ec);
-
- RefPtr<Element> body = m_doc->createElement(bodyTag, false);
- body->setAttribute(marginwidthAttr, "0");
- body->setAttribute(marginheightAttr, "0");
- body->setAttribute(bgcolorAttr, "rgb(38,38,38)");
-
- rootElement->appendChild(body, ec);
-
- RefPtr<Element> embedElement = m_doc->createElement(embedTag, false);
-
- m_embedElement = static_cast<HTMLEmbedElement*>(embedElement.get());
- m_embedElement->setAttribute(widthAttr, "100%");
- m_embedElement->setAttribute(heightAttr, "100%");
-
- m_embedElement->setAttribute(nameAttr, "plugin");
- m_embedElement->setAttribute(srcAttr, m_doc->url().string());
- m_embedElement->setAttribute(typeAttr, m_doc->frame()->loader()->responseMIMEType());
-
- body->appendChild(embedElement, ec);
-}
-
-bool PluginTokenizer::writeRawData(const char*, int)
-{
- ASSERT(!m_embedElement);
- if (m_embedElement)
- return false;
-
- createDocumentStructure();
-
- if (Frame* frame = m_doc->frame()) {
- Settings* settings = frame->settings();
- if (settings && settings->arePluginsEnabled()) {
- m_doc->updateLayout();
-
- if (RenderWidget* renderer = toRenderWidget(m_embedElement->renderer())) {
- frame->loader()->client()->redirectDataToPlugin(renderer->widget());
- frame->loader()->activeDocumentLoader()->mainResourceLoader()->setShouldBufferData(false);
- }
-
- finish();
- }
- }
-
- return false;
-}
-
-void PluginTokenizer::stopParsing()
-{
- Tokenizer::stopParsing();
-}
-
-void PluginTokenizer::finish()
-{
- if (!m_parserStopped)
- m_doc->finishedParsing();
-}
-
-bool PluginTokenizer::isWaitingForScripts() const
-{
- // A plugin document is never waiting for scripts
- return false;
-}
-
-PluginDocument::PluginDocument(Frame* frame)
- : HTMLDocument(frame)
-{
- setParseMode(Compat);
-}
-
-Tokenizer* PluginDocument::createTokenizer()
-{
- return new PluginTokenizer(this);
-}
-
-}
diff --git a/WebCore/loader/PluginDocument.h b/WebCore/loader/PluginDocument.h
deleted file mode 100644
index 1d5c964..0000000
--- a/WebCore/loader/PluginDocument.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * 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 PluginDocument_h
-#define PluginDocument_h
-
-#include "HTMLDocument.h"
-
-namespace WebCore {
-
-class PluginDocument : public HTMLDocument {
-public:
- static PassRefPtr<PluginDocument> create(Frame* frame)
- {
- return adoptRef(new PluginDocument(frame));
- }
-
-private:
- PluginDocument(Frame*);
-
- virtual bool isPluginDocument() const { return true; }
- virtual Tokenizer* createTokenizer();
-};
-
-}
-
-#endif // PluginDocument_h
diff --git a/WebCore/loader/PolicyCallback.cpp b/WebCore/loader/PolicyCallback.cpp
index 14799cf..4ec2c84 100644
--- a/WebCore/loader/PolicyCallback.cpp
+++ b/WebCore/loader/PolicyCallback.cpp
@@ -71,11 +71,12 @@ void PolicyCallback::set(const ResourceRequest& request, PassRefPtr<FormState> f
}
void PolicyCallback::set(const ResourceRequest& request, PassRefPtr<FormState> formState,
- const String& frameName, NewWindowPolicyDecisionFunction function, void* argument)
+ const String& frameName, const NavigationAction& navigationAction, NewWindowPolicyDecisionFunction function, void* argument)
{
m_request = request;
m_formState = formState;
m_frameName = frameName;
+ m_navigationAction = navigationAction;
m_navigationFunction = 0;
m_newWindowFunction = function;
@@ -100,7 +101,7 @@ 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);
+ m_newWindowFunction(m_argument, m_request, m_formState.get(), m_frameName, m_navigationAction, shouldContinue);
ASSERT(!m_contentFunction);
}
@@ -125,7 +126,7 @@ void PolicyCallback::cancel()
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);
+ m_newWindowFunction(m_argument, m_request, m_formState.get(), m_frameName, m_navigationAction, false);
if (m_contentFunction)
m_contentFunction(m_argument, PolicyIgnore);
}
diff --git a/WebCore/loader/PolicyCallback.h b/WebCore/loader/PolicyCallback.h
index 757fff8..415a3e3 100644
--- a/WebCore/loader/PolicyCallback.h
+++ b/WebCore/loader/PolicyCallback.h
@@ -31,9 +31,10 @@
#define PolicyCallback_h
#include "FrameLoaderTypes.h"
-#include "PlatformString.h"
+#include "NavigationAction.h"
#include "ResourceRequest.h"
#include <wtf/RefPtr.h>
+#include <wtf/text/WTFString.h>
namespace WebCore {
@@ -42,7 +43,7 @@ class FormState;
typedef void (*NavigationPolicyDecisionFunction)(void* argument,
const ResourceRequest&, PassRefPtr<FormState>, bool shouldContinue);
typedef void (*NewWindowPolicyDecisionFunction)(void* argument,
- const ResourceRequest&, PassRefPtr<FormState>, const String& frameName, bool shouldContinue);
+ const ResourceRequest&, PassRefPtr<FormState>, const String& frameName, const NavigationAction&, bool shouldContinue);
typedef void (*ContentPolicyDecisionFunction)(void* argument, PolicyAction);
class PolicyCallback {
@@ -53,7 +54,7 @@ public:
void clear();
void set(const ResourceRequest&, PassRefPtr<FormState>,
NavigationPolicyDecisionFunction, void* argument);
- void set(const ResourceRequest&, PassRefPtr<FormState>, const String& frameName,
+ void set(const ResourceRequest&, PassRefPtr<FormState>, const String& frameName, const NavigationAction&,
NewWindowPolicyDecisionFunction, void* argument);
void set(ContentPolicyDecisionFunction, void* argument);
@@ -68,6 +69,7 @@ private:
ResourceRequest m_request;
RefPtr<FormState> m_formState;
String m_frameName;
+ NavigationAction m_navigationAction;
NavigationPolicyDecisionFunction m_navigationFunction;
NewWindowPolicyDecisionFunction m_newWindowFunction;
diff --git a/WebCore/loader/PolicyChecker.cpp b/WebCore/loader/PolicyChecker.cpp
index 196ab4f..2680386 100644
--- a/WebCore/loader/PolicyChecker.cpp
+++ b/WebCore/loader/PolicyChecker.cpp
@@ -92,7 +92,7 @@ void PolicyChecker::checkNavigationPolicy(const ResourceRequest& request, Docume
void PolicyChecker::checkNewWindowPolicy(const NavigationAction& action, NewWindowPolicyDecisionFunction function,
const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, void* argument)
{
- m_callback.set(request, formState, frameName, function, argument);
+ m_callback.set(request, formState, frameName, action, function, argument);
m_frame->loader()->client()->dispatchDecidePolicyForNewWindowAction(&PolicyChecker::continueAfterNewWindowPolicy,
action, request, formState, frameName);
}
diff --git a/WebCore/loader/ProgressTracker.cpp b/WebCore/loader/ProgressTracker.cpp
index 0c9f2fb..6bc2055 100644
--- a/WebCore/loader/ProgressTracker.cpp
+++ b/WebCore/loader/ProgressTracker.cpp
@@ -29,8 +29,11 @@
#include "DocumentLoader.h"
#include "Frame.h"
#include "FrameLoader.h"
+#include "FrameLoaderStateMachine.h"
#include "FrameLoaderClient.h"
+#include "Logging.h"
#include "ResourceResponse.h"
+#include <wtf/text/CString.h>
#include <wtf/CurrentTime.h>
using std::min;
@@ -56,9 +59,10 @@ struct ProgressItem : Noncopyable {
long long estimatedLength;
};
+unsigned long ProgressTracker::s_uniqueIdentifier = 0;
+
ProgressTracker::ProgressTracker()
- : m_uniqueIdentifier(0)
- , m_totalPageAndResourceBytesToLoad(0)
+ : m_totalPageAndResourceBytesToLoad(0)
, m_totalBytesReceived(0)
, m_lastNotifiedProgressValue(0)
, m_lastNotifiedProgressTime(0)
@@ -97,7 +101,7 @@ void ProgressTracker::reset()
void ProgressTracker::progressStarted(Frame* frame)
{
- // LOG (Progress, "frame %p(%@), _private->numProgressTrackedFrames %d, _private->originatingProgressFrame %p", frame, [frame name], _private->numProgressTrackedFrames, _private->originatingProgressFrame);
+ LOG(Progress, "Progress started (%p) - frame %p(\"%s\"), value %f, tracked frames %d, originating frame %p", this, frame, frame->tree()->uniqueName().string().utf8().data(), m_progressValue, m_numProgressTrackedFrames, m_originatingProgressFrame.get());
frame->loader()->client()->willChangeEstimatedProgress();
@@ -115,7 +119,7 @@ void ProgressTracker::progressStarted(Frame* frame)
void ProgressTracker::progressCompleted(Frame* frame)
{
- // LOG (Progress, "frame %p(%@), _private->numProgressTrackedFrames %d, _private->originatingProgressFrame %p", frame, [frame name], _private->numProgressTrackedFrames, _private->originatingProgressFrame);
+ LOG(Progress, "Progress completed (%p) - frame %p(\"%s\"), value %f, tracked frames %d, originating frame %p", this, frame, frame->tree()->uniqueName().string().utf8().data(), m_progressValue, m_numProgressTrackedFrames, m_originatingProgressFrame.get());
if (m_numProgressTrackedFrames <= 0)
return;
@@ -132,7 +136,7 @@ void ProgressTracker::progressCompleted(Frame* frame)
void ProgressTracker::finalProgressComplete()
{
- // LOG (Progress, "");
+ LOG(Progress, "Final progress complete (%p)", this);
RefPtr<Frame> frame = m_originatingProgressFrame.release();
@@ -151,7 +155,7 @@ void ProgressTracker::finalProgressComplete()
void ProgressTracker::incrementProgress(unsigned long identifier, const ResourceResponse& response)
{
- // LOG (Progress, "_private->numProgressTrackedFrames %d, _private->originatingProgressFrame %p", _private->numProgressTrackedFrames, _private->originatingProgressFrame);
+ LOG(Progress, "Progress incremented (%p) - value %f, tracked frames %d, originating frame %p", this, m_progressValue, m_numProgressTrackedFrames, m_originatingProgressFrame.get());
if (m_numProgressTrackedFrames <= 0)
return;
@@ -166,7 +170,7 @@ void ProgressTracker::incrementProgress(unsigned long identifier, const Resource
item->bytesReceived = 0;
item->estimatedLength = estimatedLength;
} else
- m_progressItems.set(identifier, new ProgressItem(estimatedLength));
+ m_progressItems.set(identifier, adoptPtr(new ProgressItem(estimatedLength)).leakPtr());
}
void ProgressTracker::incrementProgress(unsigned long identifier, const char*, int length)
@@ -202,7 +206,7 @@ void ProgressTracker::incrementProgress(unsigned long identifier, const char*, i
// For documents that use WebCore's layout system, treat first layout as the half-way point.
// FIXME: The hasHTMLView function is a sort of roundabout way of asking "do you use WebCore's layout system".
bool useClampedMaxProgress = frame->loader()->client()->hasHTMLView()
- && !frame->loader()->firstLayoutDone();
+ && !frame->loader()->stateMachine()->firstLayoutDone();
double maxProgressValue = useClampedMaxProgress ? 0.5 : finalProgressValue;
increment = (maxProgressValue - m_progressValue) * percentOfRemainingBytes;
m_progressValue += increment;
@@ -214,7 +218,7 @@ void ProgressTracker::incrementProgress(unsigned long identifier, const char*, i
double now = currentTime();
double notifiedProgressTimeDelta = now - m_lastNotifiedProgressTime;
- // LOG (Progress, "_private->progressValue %g, _private->numProgressTrackedFrames %d", _private->progressValue, _private->numProgressTrackedFrames);
+ LOG(Progress, "Progress incremented (%p) - value %f, tracked frames %d", this, m_progressValue, m_numProgressTrackedFrames);
double notificationProgressDelta = m_progressValue - m_lastNotifiedProgressValue;
if ((notificationProgressDelta >= m_progressNotificationInterval ||
notifiedProgressTimeDelta >= m_progressNotificationTimeInterval) &&
@@ -252,7 +256,7 @@ void ProgressTracker::completeProgress(unsigned long identifier)
unsigned long ProgressTracker::createUniqueIdentifier()
{
- return ++m_uniqueIdentifier;
+ return ++s_uniqueIdentifier;
}
diff --git a/WebCore/loader/ProgressTracker.h b/WebCore/loader/ProgressTracker.h
index 744e101..5d5b6b2 100644
--- a/WebCore/loader/ProgressTracker.h
+++ b/WebCore/loader/ProgressTracker.h
@@ -41,7 +41,7 @@ public:
ProgressTracker();
~ProgressTracker();
- unsigned long createUniqueIdentifier();
+ static unsigned long createUniqueIdentifier();
double estimatedProgress() const;
@@ -59,7 +59,7 @@ private:
void reset();
void finalProgressComplete();
- unsigned long m_uniqueIdentifier;
+ static unsigned long s_uniqueIdentifier;
long long m_totalPageAndResourceBytesToLoad;
long long m_totalBytesReceived;
diff --git a/WebCore/loader/RedirectScheduler.cpp b/WebCore/loader/RedirectScheduler.cpp
deleted file mode 100644
index 4b44422..0000000
--- a/WebCore/loader/RedirectScheduler.cpp
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
- * 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 "BackForwardList.h"
-#include "DocumentLoader.h"
-#include "Event.h"
-#include "FormState.h"
-#include "Frame.h"
-#include "FrameLoadRequest.h"
-#include "FrameLoader.h"
-#include "HistoryItem.h"
-#include "HTMLFormElement.h"
-#include "HTMLFrameOwnerElement.h"
-#include "Page.h"
-#include <wtf/CurrentTime.h>
-
-namespace WebCore {
-
-struct ScheduledRedirection : Noncopyable {
- enum Type { redirection, locationChange, historyNavigation, formSubmission };
-
- const Type type;
- const double delay;
- const String url;
- const String referrer;
- const FrameLoadRequest frameRequest;
- const RefPtr<Event> event;
- const RefPtr<FormState> 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> event, PassRefPtr<FormState> 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> event, PassRefPtr<FormState> 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();
-
- // If this is a child frame and the form submission was triggered by a script, lock the back/forward list
- // to match IE and Opera.
- // See https://bugs.webkit.org/show_bug.cgi?id=32383 for the original motivation for this.
-
- bool lockBackForwardList = mustLockBackForwardList(m_frame) || (formState->formSubmissionTrigger() == SubmittedByJavaScript && m_frame->tree()->parent());
-
- schedule(new ScheduledRedirection(frameRequest, lockHistory, lockBackForwardList, 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;
-
- // Invalid history navigations (such as history.forward() during a new load) have the side effect of cancelling any scheduled
- // redirects. We also avoid the possibility of cancelling the current load by avoiding the scheduled redirection altogether.
- HistoryItem* specifiedEntry = m_frame->page()->backForwardList()->itemAtIndex(steps);
- if (!specifiedEntry) {
- cancel();
- return;
- }
-
-#if !ENABLE(HISTORY_ALWAYS_ASYNC)
- // If the specified entry and the current entry have the same document, this is either a state object traversal or a fragment
- // traversal (or both) and should be performed synchronously.
- HistoryItem* currentEntry = m_frame->loader()->history()->currentItem();
- if (currentEntry != specifiedEntry && currentEntry->documentSequenceNumber() == specifiedEntry->documentSequenceNumber()) {
- m_frame->loader()->history()->goToItem(specifiedEntry, FrameLoadTypeIndexedBackForward);
- return;
- }
-#endif
-
- // In all other cases, schedule the history traversal to occur asynchronously.
- schedule(new ScheduledRedirection(steps));
-}
-
-void RedirectScheduler::timerFired(Timer<RedirectScheduler>*)
-{
- if (!m_frame->page())
- return;
-
- if (m_frame->page()->defersLoading())
- return;
-
- OwnPtr<ScheduledRedirection> 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, SendReferrer);
- 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.
- 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, SendReferrer);
- return;
- }
-
- ASSERT_NOT_REACHED();
-}
-
-void RedirectScheduler::schedule(PassOwnPtr<ScheduledRedirection> 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<ScheduledRedirection> redirection(m_scheduledRedirection.release());
- if (redirection && redirection->toldClient)
- m_frame->loader()->clientRedirectCancelledOrFinished(newLoadInProgress);
-}
-
-} // namespace WebCore
-
diff --git a/WebCore/loader/Request.cpp b/WebCore/loader/Request.cpp
index 630a4bb..6ad6f9c 100644
--- a/WebCore/loader/Request.cpp
+++ b/WebCore/loader/Request.cpp
@@ -28,9 +28,9 @@
namespace WebCore {
-Request::Request(DocLoader* docLoader, CachedResource* object, bool incremental, SecurityCheckPolicy shouldDoSecurityCheck, bool sendResourceLoadCallbacks)
+Request::Request(CachedResourceLoader* cachedResourceLoader, CachedResource* object, bool incremental, SecurityCheckPolicy shouldDoSecurityCheck, bool sendResourceLoadCallbacks)
: m_object(object)
- , m_docLoader(docLoader)
+ , m_cachedResourceLoader(cachedResourceLoader)
, m_incremental(incremental)
, m_multipart(false)
, m_shouldDoSecurityCheck(shouldDoSecurityCheck)
diff --git a/WebCore/loader/Request.h b/WebCore/loader/Request.h
index 468f8ff..b6de312 100644
--- a/WebCore/loader/Request.h
+++ b/WebCore/loader/Request.h
@@ -29,30 +29,28 @@
namespace WebCore {
class CachedResource;
- class DocLoader;
+ class CachedResourceLoader;
class Request : public Noncopyable {
public:
- Request(DocLoader*, CachedResource*, bool incremental, SecurityCheckPolicy, bool sendResourceLoadCallbacks);
+ Request(CachedResourceLoader*, CachedResource*, bool incremental, SecurityCheckPolicy, bool sendResourceLoadCallbacks);
~Request();
- Vector<char>& buffer() { return m_buffer; }
- CachedResource* cachedResource() { return m_object; }
- DocLoader* docLoader() { return m_docLoader; }
+ CachedResource* cachedResource() const { return m_object; }
+ CachedResourceLoader* cachedResourceLoader() const { return m_cachedResourceLoader; }
- bool isIncremental() { return m_incremental; }
+ bool isIncremental() const { return m_incremental; }
void setIsIncremental(bool b = true) { m_incremental = b; }
- bool isMultipart() { return m_multipart; }
+ bool isMultipart() const { return m_multipart; }
void setIsMultipart(bool b = true) { m_multipart = b; }
SecurityCheckPolicy shouldDoSecurityCheck() const { return m_shouldDoSecurityCheck; }
bool sendResourceLoadCallbacks() const { return m_sendResourceLoadCallbacks; }
private:
- Vector<char> m_buffer;
CachedResource* m_object;
- DocLoader* m_docLoader;
+ CachedResourceLoader* m_cachedResourceLoader;
bool m_incremental;
bool m_multipart;
SecurityCheckPolicy m_shouldDoSecurityCheck;
diff --git a/WebCore/loader/ResourceLoadNotifier.cpp b/WebCore/loader/ResourceLoadNotifier.cpp
index 9280434..b32b737 100644
--- a/WebCore/loader/ResourceLoadNotifier.cpp
+++ b/WebCore/loader/ResourceLoadNotifier.cpp
@@ -82,11 +82,11 @@ void ResourceLoadNotifier::didReceiveData(ResourceLoader* loader, const char* da
dispatchDidReceiveContentLength(loader->documentLoader(), loader->identifier(), lengthReceived);
}
-void ResourceLoadNotifier::didFinishLoad(ResourceLoader* loader)
+void ResourceLoadNotifier::didFinishLoad(ResourceLoader* loader, double finishTime)
{
if (Page* page = m_frame->page())
page->progress()->completeProgress(loader->identifier());
- dispatchDidFinishLoading(loader->documentLoader(), loader->identifier());
+ dispatchDidFinishLoading(loader->documentLoader(), loader->identifier(), finishTime);
}
void ResourceLoadNotifier::didFailToLoad(ResourceLoader* loader, const ResourceError& error)
@@ -103,11 +103,6 @@ void ResourceLoadNotifier::didFailToLoad(ResourceLoader* loader, const ResourceE
#endif
}
-void ResourceLoadNotifier::didLoadResourceByXMLHttpRequest(unsigned long identifier, const ScriptString& sourceString)
-{
- m_frame->loader()->client()->dispatchDidLoadResourceByXMLHttpRequest(identifier, sourceString);
-}
-
void ResourceLoadNotifier::assignIdentifierToInitialRequest(unsigned long identifier, DocumentLoader* loader, const ResourceRequest& request)
{
m_frame->loader()->client()->assignIdentifierToInitialRequest(identifier, loader, request);
@@ -141,7 +136,7 @@ void ResourceLoadNotifier::dispatchDidReceiveResponse(DocumentLoader* loader, un
#if ENABLE(INSPECTOR)
if (Page* page = m_frame->page())
- page->inspectorController()->didReceiveResponse(identifier, r);
+ page->inspectorController()->didReceiveResponse(identifier, loader, r);
#endif
}
@@ -155,13 +150,13 @@ void ResourceLoadNotifier::dispatchDidReceiveContentLength(DocumentLoader* loade
#endif
}
-void ResourceLoadNotifier::dispatchDidFinishLoading(DocumentLoader* loader, unsigned long identifier)
+void ResourceLoadNotifier::dispatchDidFinishLoading(DocumentLoader* loader, unsigned long identifier, double finishTime)
{
m_frame->loader()->client()->dispatchDidFinishLoading(loader, identifier);
#if ENABLE(INSPECTOR)
if (Page* page = m_frame->page())
- page->inspectorController()->didFinishLoading(identifier);
+ page->inspectorController()->didFinishLoading(identifier, finishTime);
#endif
}
@@ -174,7 +169,7 @@ void ResourceLoadNotifier::sendRemainingDelegateMessages(DocumentLoader* loader,
dispatchDidReceiveContentLength(loader, identifier, length);
if (error.isNull())
- dispatchDidFinishLoading(loader, identifier);
+ dispatchDidFinishLoading(loader, identifier, 0);
else
m_frame->loader()->client()->dispatchDidFailLoading(loader, identifier, error);
}
diff --git a/WebCore/loader/ResourceLoadNotifier.h b/WebCore/loader/ResourceLoadNotifier.h
index 23e4246..93fcccc 100644
--- a/WebCore/loader/ResourceLoadNotifier.h
+++ b/WebCore/loader/ResourceLoadNotifier.h
@@ -40,7 +40,6 @@ class Frame;
class ResourceError;
class ResourceLoader;
class ResourceResponse;
-class ScriptString;
class ResourceRequest;
class ResourceLoadNotifier : public Noncopyable {
@@ -53,15 +52,14 @@ public:
void willSendRequest(ResourceLoader*, ResourceRequest&, const ResourceResponse& redirectResponse);
void didReceiveResponse(ResourceLoader*, const ResourceResponse&);
void didReceiveData(ResourceLoader*, const char*, int, int lengthReceived);
- void didFinishLoad(ResourceLoader*);
+ void didFinishLoad(ResourceLoader*, double finishTime);
void didFailToLoad(ResourceLoader*, const ResourceError&);
- void didLoadResourceByXMLHttpRequest(unsigned long identifier, const ScriptString& sourceString);
void assignIdentifierToInitialRequest(unsigned long identifier, DocumentLoader*, const ResourceRequest&);
void dispatchWillSendRequest(DocumentLoader*, unsigned long identifier, ResourceRequest&, const ResourceResponse& redirectResponse);
void dispatchDidReceiveResponse(DocumentLoader*, unsigned long identifier, const ResourceResponse&);
void dispatchDidReceiveContentLength(DocumentLoader*, unsigned long identifier, int length);
- void dispatchDidFinishLoading(DocumentLoader*, unsigned long identifier);
+ void dispatchDidFinishLoading(DocumentLoader*, unsigned long identifier, double finishTime);
void sendRemainingDelegateMessages(DocumentLoader*, unsigned long identifier, const ResourceResponse&, int length, const ResourceError&);
diff --git a/WebCore/loader/ResourceLoader.cpp b/WebCore/loader/ResourceLoader.cpp
index d14afc8..eab5acd 100644
--- a/WebCore/loader/ResourceLoader.cpp
+++ b/WebCore/loader/ResourceLoader.cpp
@@ -32,8 +32,11 @@
#include "ApplicationCacheHost.h"
#include "DocumentLoader.h"
+#include "FileStreamProxy.h"
#include "Frame.h"
#include "FrameLoader.h"
+#include "FrameLoaderClient.h"
+#include "InspectorInstrumentation.h"
#include "Page.h"
#include "ProgressTracker.h"
#include "ResourceHandle.h"
@@ -111,6 +114,17 @@ bool ResourceLoader::load(const ResourceRequest& r)
ASSERT(!m_documentLoader->isSubstituteLoadPending(this));
ResourceRequest clientRequest(r);
+
+ // https://bugs.webkit.org/show_bug.cgi?id=26391
+ // The various plug-in implementations call directly to ResourceLoader::load() instead of piping requests
+ // through FrameLoader. As a result, they miss the FrameLoader::addExtraFieldsToRequest() step which sets
+ // up the 1st party for cookies URL. Until plug-in implementations can be reigned in to pipe through that
+ // method, we need to make sure there is always a 1st party for cookies set.
+ if (clientRequest.firstPartyForCookies().isNull()) {
+ if (Document* document = m_frame->document())
+ clientRequest.setFirstPartyForCookies(document->firstPartyForCookies());
+ }
+
willSendRequest(clientRequest, ResourceResponse());
if (clientRequest.isNull()) {
didFail(frameLoader()->cancelledError(r));
@@ -132,7 +146,7 @@ bool ResourceLoader::load(const ResourceRequest& r)
return true;
}
- m_handle = ResourceHandle::create(clientRequest, this, m_frame.get(), m_defersLoading, m_shouldContentSniff, true);
+ m_handle = ResourceHandle::create(m_frame->loader()->networkingContext(), clientRequest, this, m_defersLoading, m_shouldContentSniff);
return true;
}
@@ -273,7 +287,7 @@ void ResourceLoader::willStopBufferingData(const char* data, int length)
m_resourceData = SharedBuffer::create(data, length);
}
-void ResourceLoader::didFinishLoading()
+void ResourceLoader::didFinishLoading(double finishTime)
{
// If load has been cancelled after finishing (which could happen with a
// JavaScript that changes the window location), do nothing.
@@ -281,11 +295,11 @@ void ResourceLoader::didFinishLoading()
return;
ASSERT(!m_reachedTerminalState);
- didFinishLoadingOnePart();
+ didFinishLoadingOnePart(finishTime);
releaseResources();
}
-void ResourceLoader::didFinishLoadingOnePart()
+void ResourceLoader::didFinishLoadingOnePart(double finishTime)
{
if (m_cancelled)
return;
@@ -295,7 +309,7 @@ void ResourceLoader::didFinishLoadingOnePart()
return;
m_calledDidFinishLoad = true;
if (m_sendResourceLoadCallbacks)
- frameLoader()->notifier()->didFinishLoad(this);
+ frameLoader()->notifier()->didFinishLoad(this, finishTime);
}
void ResourceLoader::didFail(const ResourceError& error)
@@ -401,17 +415,21 @@ void ResourceLoader::didReceiveResponse(ResourceHandle*, const ResourceResponse&
if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForResponse(this, response))
return;
#endif
+ InspectorInstrumentationCookie cookie = InspectorInstrumentation::willReceiveResourceResponse(m_frame.get(), identifier(), response);
didReceiveResponse(response);
+ InspectorInstrumentation::didReceiveResourceResponse(cookie);
}
void ResourceLoader::didReceiveData(ResourceHandle*, const char* data, int length, int lengthReceived)
{
+ InspectorInstrumentationCookie cookie = InspectorInstrumentation::willReceiveResourceData(m_frame.get(), identifier());
didReceiveData(data, length, lengthReceived, false);
+ InspectorInstrumentation::didReceiveResourceData(cookie);
}
-void ResourceLoader::didFinishLoading(ResourceHandle*)
+void ResourceLoader::didFinishLoading(ResourceHandle*, double finishTime)
{
- didFinishLoading();
+ didFinishLoading(finishTime);
}
void ResourceLoader::didFail(ResourceHandle*, const ResourceError& error)
@@ -455,6 +473,14 @@ void ResourceLoader::didCancelAuthenticationChallenge(const AuthenticationChalle
frameLoader()->notifier()->didCancelAuthenticationChallenge(this, challenge);
}
+#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
+bool ResourceLoader::canAuthenticateAgainstProtectionSpace(const ProtectionSpace& protectionSpace)
+{
+ RefPtr<ResourceLoader> protector(this);
+ return frameLoader()->canAuthenticateAgainstProtectionSpace(this, protectionSpace);
+}
+#endif
+
void ResourceLoader::receivedCancellation(const AuthenticationChallenge&)
{
cancel();
@@ -462,9 +488,24 @@ void ResourceLoader::receivedCancellation(const AuthenticationChallenge&)
void ResourceLoader::willCacheResponse(ResourceHandle*, CacheStoragePolicy& policy)
{
+ // <rdar://problem/7249553> - There are reports of crashes with this method being called
+ // with a null m_frame->settings(), which can only happen if the frame doesn't have a page.
+ // Sadly we have no reproducible cases of this.
+ // We think that any frame without a page shouldn't have any loads happening in it, yet
+ // there is at least one code path where that is not true.
+ ASSERT(m_frame->settings());
+
// When in private browsing mode, prevent caching to disk
- if (policy == StorageAllowed && m_frame->settings()->privateBrowsingEnabled())
+ if (policy == StorageAllowed && m_frame->settings() && m_frame->settings()->privateBrowsingEnabled())
policy = StorageAllowedInMemoryOnly;
}
+#if ENABLE(BLOB)
+AsyncFileStream* ResourceLoader::createAsyncFileStream(FileStreamClient* client)
+{
+ // It is OK to simply return a pointer since FileStreamProxy::create adds an extra ref.
+ return FileStreamProxy::create(m_frame->document()->scriptExecutionContext(), client).get();
+}
+#endif
+
}
diff --git a/WebCore/loader/ResourceLoader.h b/WebCore/loader/ResourceLoader.h
index 3178eb4..29afbc1 100644
--- a/WebCore/loader/ResourceLoader.h
+++ b/WebCore/loader/ResourceLoader.h
@@ -44,6 +44,7 @@ namespace WebCore {
class DocumentLoader;
class Frame;
class FrameLoader;
+ class ProtectionSpace;
class ResourceHandle;
class SharedBuffer;
@@ -83,13 +84,17 @@ namespace WebCore {
virtual void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent);
virtual void didReceiveResponse(const ResourceResponse&);
virtual void didReceiveData(const char*, int, long long lengthReceived, bool allAtOnce);
+ virtual void didReceiveCachedMetadata(const char*, int) { }
void willStopBufferingData(const char*, int);
- virtual void didFinishLoading();
+ virtual void didFinishLoading(double finishTime);
virtual void didFail(const ResourceError&);
virtual bool shouldUseCredentialStorage();
virtual void didReceiveAuthenticationChallenge(const AuthenticationChallenge&);
void didCancelAuthenticationChallenge(const AuthenticationChallenge&);
+#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
+ virtual bool canAuthenticateAgainstProtectionSpace(const ProtectionSpace&);
+#endif
virtual void receivedCancellation(const AuthenticationChallenge&);
// ResourceHandleClient
@@ -97,7 +102,8 @@ namespace WebCore {
virtual void didSendData(ResourceHandle*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent);
virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&);
virtual void didReceiveData(ResourceHandle*, const char*, int, int lengthReceived);
- virtual void didFinishLoading(ResourceHandle*);
+ virtual void didReceiveCachedMetadata(ResourceHandle*, const char* data, int length) { didReceiveCachedMetadata(data, length); }
+ virtual void didFinishLoading(ResourceHandle*, double finishTime);
virtual void didFail(ResourceHandle*, const ResourceError&);
virtual void wasBlocked(ResourceHandle*);
virtual void cannotShowURL(ResourceHandle*);
@@ -105,6 +111,9 @@ namespace WebCore {
virtual bool shouldUseCredentialStorage(ResourceHandle*) { return shouldUseCredentialStorage(); }
virtual void didReceiveAuthenticationChallenge(ResourceHandle*, const AuthenticationChallenge& challenge) { didReceiveAuthenticationChallenge(challenge); }
virtual void didCancelAuthenticationChallenge(ResourceHandle*, const AuthenticationChallenge& challenge) { didCancelAuthenticationChallenge(challenge); }
+#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
+ virtual bool canAuthenticateAgainstProtectionSpace(ResourceHandle*, const ProtectionSpace& protectionSpace) { return canAuthenticateAgainstProtectionSpace(protectionSpace); }
+#endif
virtual void receivedCancellation(ResourceHandle*, const AuthenticationChallenge& challenge) { receivedCancellation(challenge); }
virtual void willCacheResponse(ResourceHandle*, CacheStoragePolicy&);
#if PLATFORM(MAC)
@@ -113,6 +122,9 @@ namespace WebCore {
#if USE(CFNETWORK)
virtual bool shouldCacheResponse(ResourceHandle*, CFCachedURLResponseRef);
#endif
+#if ENABLE(BLOB)
+ virtual AsyncFileStream* createAsyncFileStream(FileStreamClient*);
+#endif
ResourceHandle* handle() const { return m_handle.get(); }
bool sendResourceLoadCallbacks() const { return m_sendResourceLoadCallbacks; }
@@ -127,7 +139,7 @@ namespace WebCore {
#endif
virtual void didCancel(const ResourceError&);
- void didFinishLoadingOnePart();
+ void didFinishLoadingOnePart(double finishTime);
const ResourceRequest& request() const { return m_request; }
bool reachedTerminalState() const { return m_reachedTerminalState; }
diff --git a/WebCore/loader/FTPDirectoryDocument.h b/WebCore/loader/SinkDocument.cpp
index b208c4e..47535dc 100644
--- a/WebCore/loader/FTPDirectoryDocument.h
+++ b/WebCore/loader/SinkDocument.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -16,33 +16,47 @@
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
-#ifndef FTPDirectoryDocument_h
-#define FTPDirectoryDocument_h
-#include "HTMLDocument.h"
+#include "config.h"
+#include "SinkDocument.h"
+
+#include "RawDataDocumentParser.h"
namespace WebCore {
-
-class DOMImplementation;
-
-class FTPDirectoryDocument : public HTMLDocument {
+
+class SinkDocumentParser : public RawDataDocumentParser {
public:
- static PassRefPtr<FTPDirectoryDocument> create(Frame* frame)
+ static PassRefPtr<SinkDocumentParser> create(SinkDocument* document)
{
- return adoptRef(new FTPDirectoryDocument(frame));
+ return adoptRef(new SinkDocumentParser(document));
}
-
+
private:
- FTPDirectoryDocument(Frame*);
- virtual Tokenizer* createTokenizer();
+ SinkDocumentParser(SinkDocument* document)
+ : RawDataDocumentParser(document)
+ {
+ }
+
+ // Ignore all data.
+ virtual void appendBytes(DocumentWriter*, const char*, int, bool) { }
};
-
-} // namespace WebCore
-#endif // FTPDirectoryDocument_h
+SinkDocument::SinkDocument(Frame* frame, const KURL& url)
+ : HTMLDocument(frame, url)
+{
+ setCompatibilityMode(QuirksMode);
+ lockCompatibilityMode();
+}
+
+PassRefPtr<DocumentParser> SinkDocument::createParser()
+{
+ return SinkDocumentParser::create(this);
+}
+
+} // namespace WebCore
diff --git a/WebCore/loader/TextDocument.h b/WebCore/loader/SinkDocument.h
index 53e3074..50152ff 100644
--- a/WebCore/loader/TextDocument.h
+++ b/WebCore/loader/SinkDocument.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -16,36 +16,34 @@
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TextDocument_h
-#define TextDocument_h
+#ifndef SinkDocument_h
+#define SinkDocument_h
#include "HTMLDocument.h"
namespace WebCore {
-class HTMLViewSourceDocument;
-
-class TextDocument : public HTMLDocument {
+class SinkDocument : public HTMLDocument {
public:
- static PassRefPtr<TextDocument> create(Frame* frame)
+ static PassRefPtr<SinkDocument> create(Frame* frame, const KURL& url)
{
- return adoptRef(new TextDocument(frame));
+ return adoptRef(new SinkDocument(frame, url));
}
private:
- TextDocument(Frame*);
+ SinkDocument(Frame*, const KURL&);
- virtual Tokenizer* createTokenizer();
+ virtual PassRefPtr<DocumentParser> createParser();
};
-Tokenizer* createTextTokenizer(HTMLViewSourceDocument*);
-}
+}; // namespace WebCore
-#endif // TextDocument_h
+#endif // SinkDocument_h
diff --git a/WebCore/loader/SubframeLoader.cpp b/WebCore/loader/SubframeLoader.cpp
new file mode 100644
index 0000000..d486de0
--- /dev/null
+++ b/WebCore/loader/SubframeLoader.cpp
@@ -0,0 +1,382 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010 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) 2008 Alp Toker <alp@atoker.com>
+ * Copyright (C) Research In Motion Limited 2009. 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 "SubframeLoader.h"
+
+#include "Frame.h"
+#include "FrameLoaderClient.h"
+#include "HTMLAppletElement.h"
+#include "HTMLFrameElementBase.h"
+#include "HTMLNames.h"
+#include "HTMLPlugInImageElement.h"
+#include "MIMETypeRegistry.h"
+#include "Page.h"
+#include "PluginData.h"
+#include "PluginDocument.h"
+#include "RenderEmbeddedObject.h"
+#include "RenderView.h"
+#include "Settings.h"
+#include "XSSAuditor.h"
+
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+#include "HTMLMediaElement.h"
+#include "RenderVideo.h"
+#endif
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+SubframeLoader::SubframeLoader(Frame* frame)
+ : m_containsPlugins(false)
+ , m_frame(frame)
+{
+}
+
+void SubframeLoader::clear()
+{
+ m_containsPlugins = false;
+}
+
+bool SubframeLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String& urlString, const AtomicString& frameName, bool lockHistory, bool lockBackForwardList)
+{
+ // Support for <frame src="javascript:string">
+ KURL scriptURL;
+ KURL url;
+ if (protocolIsJavaScript(urlString)) {
+ scriptURL = completeURL(urlString); // completeURL() encodes the URL.
+ url = blankURL();
+ } else
+ url = completeURL(urlString);
+
+ Frame* frame = loadOrRedirectSubframe(ownerElement, url, frameName, lockHistory, lockBackForwardList);
+ if (!frame)
+ return false;
+
+ if (!scriptURL.isEmpty())
+ frame->script()->executeIfJavaScriptURL(scriptURL);
+
+ return true;
+}
+
+bool SubframeLoader::resourceWillUsePlugin(const String& url, const String& mimeType)
+{
+ KURL completedURL;
+ if (!url.isEmpty())
+ completedURL = completeURL(url);
+ bool useFallback;
+ return shouldUsePlugin(completedURL, mimeType, false, useFallback);
+}
+
+bool SubframeLoader::requestObject(HTMLPlugInImageElement* ownerElement, const String& url, const AtomicString& frameName,
+ const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues)
+{
+ if (url.isEmpty() && mimeType.isEmpty())
+ return false;
+
+ if (!m_frame->script()->xssAuditor()->canLoadObject(url)) {
+ // It is unsafe to honor the request for this object.
+ return false;
+ }
+
+ // FIXME: None of this code should use renderers!
+ RenderEmbeddedObject* renderer = ownerElement->renderEmbeddedObject();
+ ASSERT(renderer);
+ if (!renderer)
+ return false;
+
+ KURL completedURL;
+ if (!url.isEmpty())
+ completedURL = completeURL(url);
+
+ bool useFallback;
+ if (shouldUsePlugin(completedURL, mimeType, renderer->hasFallbackContent(), useFallback)) {
+ Settings* settings = m_frame->settings();
+ if ((!allowPlugins(AboutToInstantiatePlugin)
+ // Application plugins are plugins implemented by the user agent, for example Qt plugins,
+ // as opposed to third-party code such as flash. The user agent decides whether or not they are
+ // permitted, rather than WebKit.
+ && !MIMETypeRegistry::isApplicationPluginMIMEType(mimeType))
+ || (!settings->isJavaEnabled() && MIMETypeRegistry::isJavaAppletMIMEType(mimeType)))
+ return false;
+ if (m_frame->document() && m_frame->document()->securityOrigin()->isSandboxed(SandboxPlugins))
+ return false;
+
+ ASSERT(ownerElement->hasTagName(objectTag) || ownerElement->hasTagName(embedTag));
+ HTMLPlugInImageElement* pluginElement = static_cast<HTMLPlugInImageElement*>(ownerElement);
+
+ return loadPlugin(pluginElement, completedURL, mimeType, paramNames, paramValues, useFallback);
+ }
+
+ // If the plug-in element already contains a subframe, loadOrRedirectSubframe will re-use it. Otherwise,
+ // it will create a new frame and set it as the RenderPart's widget, causing what was previously
+ // in the widget to be torn down.
+ return loadOrRedirectSubframe(ownerElement, completedURL, frameName, true, true);
+}
+
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+PassRefPtr<Widget> SubframeLoader::loadMediaPlayerProxyPlugin(Node* node, const KURL& url,
+ const Vector<String>& paramNames, const Vector<String>& paramValues)
+{
+ ASSERT(node->hasTagName(videoTag) || node->hasTagName(audioTag));
+
+ if (!m_frame->script()->xssAuditor()->canLoadObject(url.string()))
+ return 0;
+
+ KURL completedURL;
+ if (!url.isEmpty())
+ completedURL = completeURL(url);
+
+ if (!m_frame->document()->securityOrigin()->canDisplay(completedURL)) {
+ FrameLoader::reportLocalLoadFailed(m_frame, completedURL.string());
+ return 0;
+ }
+
+ HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(node);
+ RenderPart* renderer = toRenderPart(node->renderer());
+ IntSize size;
+
+ if (renderer)
+ size = IntSize(renderer->contentWidth(), renderer->contentHeight());
+ else if (mediaElement->isVideo())
+ size = RenderVideo::defaultSize();
+
+ m_frame->loader()->checkIfRunInsecureContent(m_frame->document()->securityOrigin(), completedURL);
+
+ RefPtr<Widget> widget = m_frame->loader()->client()->createMediaPlayerProxyPlugin(size, mediaElement, completedURL,
+ paramNames, paramValues, "application/x-media-element-proxy-plugin");
+
+ if (widget && renderer) {
+ renderer->setWidget(widget);
+ renderer->node()->setNeedsStyleRecalc(SyntheticStyleChange);
+ }
+ m_containsPlugins = true;
+
+ return widget ? widget.release() : 0;
+}
+
+void FrameLoader::hideMediaPlayerProxyPlugin(Widget* widget)
+{
+ m_client->hideMediaPlayerProxyPlugin(widget);
+}
+
+void FrameLoader::showMediaPlayerProxyPlugin(Widget* widget)
+{
+ m_client->showMediaPlayerProxyPlugin(widget);
+}
+
+#endif // ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+
+PassRefPtr<Widget> SubframeLoader::createJavaAppletWidget(const IntSize& size, HTMLAppletElement* element, const HashMap<String, String>& args)
+{
+ String baseURLString;
+ String codeBaseURLString;
+ Vector<String> paramNames;
+ Vector<String> paramValues;
+ HashMap<String, String>::const_iterator end = args.end();
+ for (HashMap<String, String>::const_iterator it = args.begin(); it != end; ++it) {
+ if (equalIgnoringCase(it->first, "baseurl"))
+ baseURLString = it->second;
+ else if (equalIgnoringCase(it->first, "codebase"))
+ codeBaseURLString = it->second;
+ paramNames.append(it->first);
+ paramValues.append(it->second);
+ }
+
+ if (!codeBaseURLString.isEmpty()) {
+ KURL codeBaseURL = completeURL(codeBaseURLString);
+ if (!element->document()->securityOrigin()->canDisplay(codeBaseURL)) {
+ FrameLoader::reportLocalLoadFailed(m_frame, codeBaseURL.string());
+ return 0;
+ }
+ }
+
+ if (baseURLString.isEmpty())
+ baseURLString = m_frame->document()->baseURL().string();
+ KURL baseURL = completeURL(baseURLString);
+
+ RefPtr<Widget> widget;
+ if (allowPlugins(AboutToInstantiatePlugin))
+ widget = m_frame->loader()->client()->createJavaAppletWidget(size, element, baseURL, paramNames, paramValues);
+ if (!widget)
+ return 0;
+
+ m_containsPlugins = true;
+ return widget;
+}
+
+Frame* SubframeLoader::loadOrRedirectSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const AtomicString& frameName, bool lockHistory, bool lockBackForwardList)
+{
+ Frame* frame = ownerElement->contentFrame();
+ if (frame)
+ frame->navigationScheduler()->scheduleLocationChange(url.string(), m_frame->loader()->outgoingReferrer(), lockHistory, lockBackForwardList);
+ else
+ frame = loadSubframe(ownerElement, url, frameName, m_frame->loader()->outgoingReferrer());
+ return frame;
+}
+
+Frame* SubframeLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const String& name, const String& referrer)
+{
+ bool allowsScrolling = true;
+ int marginWidth = -1;
+ int marginHeight = -1;
+ if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag)) {
+ HTMLFrameElementBase* o = static_cast<HTMLFrameElementBase*>(ownerElement);
+ allowsScrolling = o->scrollingMode() != ScrollbarAlwaysOff;
+ marginWidth = o->getMarginWidth();
+ marginHeight = o->getMarginHeight();
+ }
+
+ if (!ownerElement->document()->securityOrigin()->canDisplay(url)) {
+ FrameLoader::reportLocalLoadFailed(m_frame, url.string());
+ return 0;
+ }
+
+ bool hideReferrer = SecurityOrigin::shouldHideReferrer(url, referrer);
+ RefPtr<Frame> frame = m_frame->loader()->client()->createFrame(url, name, ownerElement, hideReferrer ? String() : referrer, allowsScrolling, marginWidth, marginHeight);
+
+ if (!frame) {
+ m_frame->loader()->checkCallImplicitClose();
+ return 0;
+ }
+
+ // All new frames will have m_isComplete set to true at this point due to synchronously loading
+ // an empty document in FrameLoader::init(). But many frames will now be starting an
+ // asynchronous load of url, so we set m_isComplete to false and then check if the load is
+ // actually completed below. (Note that we set m_isComplete to false even for synchronous
+ // loads, so that checkCompleted() below won't bail early.)
+ // FIXME: Can we remove this entirely? m_isComplete normally gets set to false when a load is committed.
+ frame->loader()->started();
+
+ RenderObject* renderer = ownerElement->renderer();
+ FrameView* view = frame->view();
+ if (renderer && renderer->isWidget() && view)
+ toRenderWidget(renderer)->setWidget(view);
+
+ m_frame->loader()->checkCallImplicitClose();
+
+ // Some loads are performed synchronously (e.g., about:blank and loads
+ // cancelled by returning a null ResourceRequest from requestFromDelegate).
+ // In these cases, the synchronous load would have finished
+ // before we could connect the signals, so make sure to send the
+ // completed() signal for the child by hand and mark the load as being
+ // complete.
+ // FIXME: In this case the Frame will have finished loading before
+ // it's being added to the child list. It would be a good idea to
+ // create the child first, then invoke the loader separately.
+ if (frame->loader()->state() == FrameStateComplete && !frame->loader()->policyDocumentLoader())
+ frame->loader()->checkCompleted();
+
+ return frame.get();
+}
+
+bool SubframeLoader::allowPlugins(ReasonForCallingAllowPlugins reason)
+{
+ Settings* settings = m_frame->settings();
+ bool allowed = m_frame->loader()->client()->allowPlugins(settings && settings->arePluginsEnabled());
+ if (!allowed && reason == AboutToInstantiatePlugin)
+ m_frame->loader()->client()->didNotAllowPlugins();
+ return allowed;
+}
+
+bool SubframeLoader::shouldUsePlugin(const KURL& url, const String& mimeType, bool hasFallback, bool& useFallback)
+{
+ if (m_frame->loader()->client()->shouldUsePluginDocument(mimeType)) {
+ useFallback = false;
+ return true;
+ }
+
+ // Allow other plug-ins to win over QuickTime because if the user has installed a plug-in that
+ // can handle TIFF (which QuickTime can also handle) they probably intended to override QT.
+ if (m_frame->page() && (mimeType == "image/tiff" || mimeType == "image/tif" || mimeType == "image/x-tiff")) {
+ const PluginData* pluginData = m_frame->page()->pluginData();
+ String pluginName = pluginData ? pluginData->pluginNameForMimeType(mimeType) : String();
+ if (!pluginName.isEmpty() && !pluginName.contains("QuickTime", false))
+ return true;
+ }
+
+ ObjectContentType objectType = m_frame->loader()->client()->objectContentType(url, mimeType);
+ // If an object's content can't be handled and it has no fallback, let
+ // it be handled as a plugin to show the broken plugin icon.
+ useFallback = objectType == ObjectContentNone && hasFallback;
+ return objectType == ObjectContentNone || objectType == ObjectContentNetscapePlugin || objectType == ObjectContentOtherPlugin;
+}
+
+Document* SubframeLoader::document() const
+{
+ return m_frame->document();
+}
+
+bool SubframeLoader::loadPlugin(HTMLPlugInImageElement* pluginElement, const KURL& url, const String& mimeType,
+ const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback)
+{
+ RenderEmbeddedObject* renderer = pluginElement->renderEmbeddedObject();
+
+ // FIXME: This code should not depend on renderer!
+ if (!renderer || useFallback)
+ return false;
+
+ if (!document()->securityOrigin()->canDisplay(url)) {
+ FrameLoader::reportLocalLoadFailed(m_frame, url.string());
+ return false;
+ }
+
+ FrameLoader* frameLoader = m_frame->loader();
+ frameLoader->checkIfRunInsecureContent(document()->securityOrigin(), url);
+
+ IntSize contentSize(renderer->contentWidth(), renderer->contentHeight());
+ bool loadManually = document()->isPluginDocument() && !m_containsPlugins && toPluginDocument(document())->shouldLoadPluginManually();
+ RefPtr<Widget> widget = frameLoader->client()->createPlugin(contentSize,
+ pluginElement, url, paramNames, paramValues, mimeType, loadManually);
+
+ if (!widget) {
+ renderer->setShowsMissingPluginIndicator();
+ return false;
+ }
+
+ renderer->setWidget(widget);
+ m_containsPlugins = true;
+
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) || ENABLE(3D_PLUGIN)
+ pluginElement->setNeedsStyleRecalc(SyntheticStyleChange);
+#endif
+ return true;
+}
+
+KURL SubframeLoader::completeURL(const String& url) const
+{
+ ASSERT(m_frame->document());
+ return m_frame->document()->completeURL(url);
+}
+
+} // namespace WebCore
diff --git a/WebCore/loader/SubframeLoader.h b/WebCore/loader/SubframeLoader.h
new file mode 100644
index 0000000..a573045
--- /dev/null
+++ b/WebCore/loader/SubframeLoader.h
@@ -0,0 +1,99 @@
+/*
+ * 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) Research In Motion Limited 2009. 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 SubframeLoader_h
+#define SubframeLoader_h
+
+#include "FrameLoaderTypes.h"
+#include "PlatformString.h"
+#include <wtf/Forward.h>
+#include <wtf/HashMap.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class Document;
+class Frame;
+class FrameLoaderClient;
+class HTMLAppletElement;
+class HTMLFrameOwnerElement;
+class HTMLPlugInImageElement;
+class IntSize;
+class KURL;
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+class Node;
+#endif
+class Widget;
+
+// This is a slight misnomer. It handles the higher level logic of loading both subframes and plugins.
+class SubframeLoader : public Noncopyable {
+public:
+ SubframeLoader(Frame*);
+
+ void clear();
+
+ bool requestFrame(HTMLFrameOwnerElement*, const String& url, const AtomicString& frameName, bool lockHistory = true, bool lockBackForwardList = true);
+ bool requestObject(HTMLPlugInImageElement*, const String& url, const AtomicString& frameName,
+ const String& serviceType, const Vector<String>& paramNames, const Vector<String>& paramValues);
+
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ // FIXME: This should take Element* instead of Node*, or better yet the
+ // specific type of Element which this code depends on.
+ PassRefPtr<Widget> loadMediaPlayerProxyPlugin(Node*, const KURL&, const Vector<String>& paramNames, const Vector<String>& paramValues);
+#endif
+
+ PassRefPtr<Widget> createJavaAppletWidget(const IntSize&, HTMLAppletElement*, const HashMap<String, String>& args);
+
+ bool allowPlugins(ReasonForCallingAllowPlugins);
+
+ bool containsPlugins() const { return m_containsPlugins; }
+
+ bool resourceWillUsePlugin(const String& url, const String& mimeType);
+
+private:
+ Frame* loadOrRedirectSubframe(HTMLFrameOwnerElement*, const KURL&, const AtomicString& frameName, bool lockHistory, bool lockBackForwardList);
+ Frame* loadSubframe(HTMLFrameOwnerElement*, const KURL&, const String& name, const String& referrer);
+ bool loadPlugin(HTMLPlugInImageElement*, const KURL&, const String& mimeType,
+ const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback);
+
+ bool shouldUsePlugin(const KURL&, const String& mimeType, bool hasFallback, bool& useFallback);
+
+ Document* document() const;
+
+ bool m_containsPlugins;
+ Frame* m_frame;
+
+ KURL completeURL(const String&) const;
+};
+
+} // namespace WebCore
+
+#endif // SubframeLoader_h
diff --git a/WebCore/loader/SubresourceLoader.cpp b/WebCore/loader/SubresourceLoader.cpp
index ebb943a..5377382 100644
--- a/WebCore/loader/SubresourceLoader.cpp
+++ b/WebCore/loader/SubresourceLoader.cpp
@@ -51,7 +51,6 @@ SubresourceLoader::SubresourceLoader(Frame* frame, SubresourceLoaderClient* clie
#ifndef NDEBUG
subresourceLoaderCounter.increment();
#endif
- m_documentLoader->addSubresourceLoader(this);
}
SubresourceLoader::~SubresourceLoader()
@@ -67,42 +66,26 @@ PassRefPtr<SubresourceLoader> SubresourceLoader::create(Frame* frame, Subresourc
return 0;
FrameLoader* fl = frame->loader();
- if (securityCheck == DoSecurityCheck && (fl->state() == FrameStateProvisional || fl->activeDocumentLoader()->isStopping()))
+ if (securityCheck == DoSecurityCheck && (fl->state() == FrameStateProvisional || !fl->activeDocumentLoader() || fl->activeDocumentLoader()->isStopping()))
return 0;
ResourceRequest newRequest = request;
- if (securityCheck == DoSecurityCheck
- && SecurityOrigin::restrictAccessToLocal()
- && !SecurityOrigin::canLoad(request.url(), String(), frame->document())) {
+ if (securityCheck == DoSecurityCheck && !frame->document()->securityOrigin()->canDisplay(request.url())) {
FrameLoader::reportLocalLoadFailed(frame, request.url().string());
return 0;
}
-
+
if (SecurityOrigin::shouldHideReferrer(request.url(), fl->outgoingReferrer()))
newRequest.clearHTTPReferrer();
-#ifdef ANDROID_FIX
- else if (request.httpReferrer().isEmpty())
-#else
else if (!request.httpReferrer())
-#endif
newRequest.setHTTPReferrer(fl->outgoingReferrer());
FrameLoader::addHTTPOriginIfNeeded(newRequest, fl->outgoingOrigin());
- // Use the original request's cache policy for two reasons:
- // 1. For POST requests, we mutate the cache policy for the main resource,
- // but we do not want this to apply to subresources
- // 2. Delegates that modify the cache policy using willSendRequest: should
- // not affect any other resources. Such changes need to be done
- // per request.
- if (newRequest.isConditional())
- newRequest.setCachePolicy(ReloadIgnoringCacheData);
- else
- newRequest.setCachePolicy(fl->originalRequest().cachePolicy());
-
fl->addExtraFieldsToSubresourceRequest(newRequest);
RefPtr<SubresourceLoader> subloader(adoptRef(new SubresourceLoader(frame, client, sendResourceLoadCallbacks, shouldContentSniff)));
+ subloader->documentLoader()->addSubresourceLoader(subloader.get());
if (!subloader->load(newRequest))
return 0;
@@ -157,7 +140,7 @@ void SubresourceLoader::didReceiveResponse(const ResourceResponse& r)
// After the first multipart section is complete, signal to delegates that this load is "finished"
m_documentLoader->subresourceLoaderFinishedLoadingOnePart(this);
- didFinishLoadingOnePart();
+ didFinishLoadingOnePart(0);
}
}
@@ -175,7 +158,17 @@ void SubresourceLoader::didReceiveData(const char* data, int length, long long l
m_client->didReceiveData(this, data, length);
}
-void SubresourceLoader::didFinishLoading()
+void SubresourceLoader::didReceiveCachedMetadata(const char* data, int length)
+{
+ // Reference the object in this method since the additional processing can do
+ // anything including removing the last reference to this object; one example of this is 3266216.
+ RefPtr<SubresourceLoader> protect(this);
+
+ if (m_client)
+ m_client->didReceiveCachedMetadata(this, data, length);
+}
+
+void SubresourceLoader::didFinishLoading(double finishTime)
{
if (cancelled())
return;
@@ -192,7 +185,7 @@ void SubresourceLoader::didFinishLoading()
if (cancelled())
return;
m_documentLoader->removeSubresourceLoader(this);
- ResourceLoader::didFinishLoading();
+ ResourceLoader::didFinishLoading(finishTime);
}
void SubresourceLoader::didFail(const ResourceError& error)
@@ -253,14 +246,20 @@ void SubresourceLoader::didReceiveAuthenticationChallenge(const AuthenticationCh
{
RefPtr<SubresourceLoader> protect(this);
+ ASSERT(handle()->hasAuthenticationChallenge());
+
if (m_client)
m_client->didReceiveAuthenticationChallenge(this, challenge);
// The SubResourceLoaderClient may have cancelled this ResourceLoader in response to the challenge.
- // If that's the case, don't call didReceiveAuthenticationChallenge
+ // If that's the case, don't call didReceiveAuthenticationChallenge.
if (reachedTerminalState())
return;
-
+
+ // It may have also handled authentication on its own.
+ if (!handle()->hasAuthenticationChallenge())
+ return;
+
ResourceLoader::didReceiveAuthenticationChallenge(challenge);
}
diff --git a/WebCore/loader/SubresourceLoader.h b/WebCore/loader/SubresourceLoader.h
index 907d917..cb7ed81 100644
--- a/WebCore/loader/SubresourceLoader.h
+++ b/WebCore/loader/SubresourceLoader.h
@@ -51,7 +51,8 @@ namespace WebCore {
virtual void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent);
virtual void didReceiveResponse(const ResourceResponse&);
virtual void didReceiveData(const char*, int, long long lengthReceived, bool allAtOnce);
- virtual void didFinishLoading();
+ virtual void didReceiveCachedMetadata(const char*, int);
+ virtual void didFinishLoading(double finishTime);
virtual void didFail(const ResourceError&);
virtual bool shouldUseCredentialStorage();
virtual void didReceiveAuthenticationChallenge(const AuthenticationChallenge&);
diff --git a/WebCore/loader/SubresourceLoaderClient.h b/WebCore/loader/SubresourceLoaderClient.h
index 76fde47..e18abe3 100644
--- a/WebCore/loader/SubresourceLoaderClient.h
+++ b/WebCore/loader/SubresourceLoaderClient.h
@@ -47,6 +47,7 @@ public:
virtual void didReceiveResponse(SubresourceLoader*, const ResourceResponse&) { }
virtual void didReceiveData(SubresourceLoader*, const char*, int /*lengthReceived*/) { }
+ virtual void didReceiveCachedMetadata(SubresourceLoader*, const char*, int /*lengthReceived*/) { }
virtual void didFinishLoading(SubresourceLoader*) { }
virtual void didFail(SubresourceLoader*, const ResourceError&) { }
diff --git a/WebCore/loader/TextDocument.cpp b/WebCore/loader/TextDocument.cpp
deleted file mode 100644
index a3d7061..0000000
--- a/WebCore/loader/TextDocument.cpp
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright (C) 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * 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 "TextDocument.h"
-
-#include "Element.h"
-#include "HTMLNames.h"
-#include "HTMLViewSourceDocument.h"
-#include "SegmentedString.h"
-#include "Text.h"
-#include "XMLTokenizer.h"
-
-using namespace std;
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-class TextTokenizer : public Tokenizer {
-public:
- TextTokenizer(Document*);
- virtual ~TextTokenizer();
- TextTokenizer(HTMLViewSourceDocument*);
-
- virtual void write(const SegmentedString&, bool appendData);
- virtual void finish();
- virtual bool isWaitingForScripts() const;
-
- inline void checkBuffer(int len = 10)
- {
- if ((m_dest - m_buffer) > m_size - len) {
- // Enlarge buffer
- int newSize = std::max(m_size * 2, m_size + len);
- int oldOffset = m_dest - m_buffer;
- m_buffer = static_cast<UChar*>(fastRealloc(m_buffer, newSize * sizeof(UChar)));
- m_dest = m_buffer + oldOffset;
- m_size = newSize;
- }
- }
-
-private:
- Document* m_doc;
- Element* m_preElement;
-
- bool m_skipLF;
-
- int m_size;
- UChar* m_buffer;
- UChar* m_dest;
-};
-
-TextTokenizer::TextTokenizer(Document* doc)
- : m_doc(doc)
- , m_preElement(0)
- , m_skipLF(false)
-{
- // Allocate buffer
- m_size = 254;
- m_buffer = static_cast<UChar*>(fastMalloc(sizeof(UChar) * m_size));
- m_dest = m_buffer;
-}
-
-TextTokenizer::TextTokenizer(HTMLViewSourceDocument* doc)
- : Tokenizer(true)
- , m_doc(doc)
- , m_preElement(0)
- , m_skipLF(false)
-{
- // Allocate buffer
- m_size = 254;
- m_buffer = static_cast<UChar*>(fastMalloc(sizeof(UChar) * m_size));
- m_dest = m_buffer;
-}
-
-TextTokenizer::~TextTokenizer()
-{
- // finish() should have been called to prevent any leaks
- ASSERT(!m_buffer);
-}
-
-void TextTokenizer::write(const SegmentedString& s, bool)
-{
- ExceptionCode ec;
-
- m_dest = m_buffer;
-
- SegmentedString str = s;
- while (!str.isEmpty()) {
- UChar c = *str;
-
- if (c == '\r') {
- *m_dest++ = '\n';
-
- // possibly skip an LF in the case of an CRLF sequence
- m_skipLF = true;
- } else if (c == '\n') {
- if (!m_skipLF)
- *m_dest++ = c;
- else
- m_skipLF = false;
- } else {
- *m_dest++ = c;
- m_skipLF = false;
- }
-
- str.advance();
-
- // Maybe enlarge the buffer
- checkBuffer();
- }
-
- if (!m_preElement && !inViewSourceMode()) {
- RefPtr<Element> rootElement = m_doc->createElement(htmlTag, false);
- m_doc->appendChild(rootElement, ec);
-
- RefPtr<Element> body = m_doc->createElement(bodyTag, false);
- rootElement->appendChild(body, ec);
-
- RefPtr<Element> preElement = m_doc->createElement(preTag, false);
- preElement->setAttribute("style", "word-wrap: break-word; white-space: pre-wrap;", ec);
-
- body->appendChild(preElement, ec);
-
- m_preElement = preElement.get();
- }
-
- String string = String(m_buffer, m_dest - m_buffer);
- if (inViewSourceMode()) {
- static_cast<HTMLViewSourceDocument*>(m_doc)->addViewSourceText(string);
- return;
- }
-
- unsigned charsLeft = string.length();
- while (charsLeft) {
- // split large text to nodes of manageable size
- RefPtr<Text> text = Text::createWithLengthLimit(m_doc, string, charsLeft);
- m_preElement->appendChild(text, ec);
- }
-}
-
-void TextTokenizer::finish()
-{
- if (!m_preElement)
- write(SegmentedString(), true); // Create document structure for an empty text document.
- m_preElement = 0;
- fastFree(m_buffer);
- m_buffer = 0;
- m_dest = 0;
-
- m_doc->finishedParsing();
-}
-
-bool TextTokenizer::isWaitingForScripts() const
-{
- // A text document is never waiting for scripts
- return false;
-}
-
-TextDocument::TextDocument(Frame* frame)
- : HTMLDocument(frame)
-{
-}
-
-Tokenizer* TextDocument::createTokenizer()
-{
- return new TextTokenizer(this);
-}
-
-Tokenizer* createTextTokenizer(HTMLViewSourceDocument* document)
-{
- return new TextTokenizer(document);
-}
-
-}
diff --git a/WebCore/loader/TextResourceDecoder.cpp b/WebCore/loader/TextResourceDecoder.cpp
index 6ddd604..4002b38 100644
--- a/WebCore/loader/TextResourceDecoder.cpp
+++ b/WebCore/loader/TextResourceDecoder.cpp
@@ -488,7 +488,7 @@ bool TextResourceDecoder::checkForCSSCharset(const char* data, size_t len, bool&
if (pos == dataEnd)
return false;
- int encodingNameLength = pos - dataStart + 1;
+ int encodingNameLength = pos - dataStart;
++pos;
if (!skipWhitespace(pos, dataEnd))
@@ -568,7 +568,7 @@ bool TextResourceDecoder::checkForHeadCharset(const char* data, size_t len, bool
if (xmlDeclarationEnd == pEnd)
return false;
// No need for +1, because we have an extra "?" to lose at the end of XML declaration.
- int len;
+ int len = 0;
int pos = findXMLEncoding(ptr, xmlDeclarationEnd - ptr, len);
if (pos != -1)
setEncoding(findTextEncoding(ptr + pos, len), EncodingFromXMLHeader);
@@ -812,7 +812,7 @@ String TextResourceDecoder::decode(const char* data, size_t len)
ASSERT(m_encoding.isValid());
if (!m_codec)
- m_codec.set(newTextCodec(m_encoding).release());
+ m_codec = newTextCodec(m_encoding);
if (m_buffer.isEmpty())
return m_codec->decode(data + lengthOfBOM, len - lengthOfBOM, false, m_contentType == XML, m_sawError);
@@ -842,7 +842,7 @@ String TextResourceDecoder::flush()
}
if (!m_codec)
- m_codec.set(newTextCodec(m_encoding).release());
+ m_codec = newTextCodec(m_encoding);
String result = m_codec->decode(m_buffer.data(), m_buffer.size(), true, m_contentType == XML && !m_useLenientXMLDecoding, m_sawError);
m_buffer.clear();
diff --git a/WebCore/loader/ThreadableLoaderClient.h b/WebCore/loader/ThreadableLoaderClient.h
index b8a6584..bcf68be 100644
--- a/WebCore/loader/ThreadableLoaderClient.h
+++ b/WebCore/loader/ThreadableLoaderClient.h
@@ -31,6 +31,8 @@
#ifndef ThreadableLoaderClient_h
#define ThreadableLoaderClient_h
+#include <wtf/Noncopyable.h>
+
namespace WebCore {
class ResourceError;
diff --git a/WebCore/loader/WorkerThreadableLoader.cpp b/WebCore/loader/WorkerThreadableLoader.cpp
index 6837ca1..4d18c28 100644
--- a/WebCore/loader/WorkerThreadableLoader.cpp
+++ b/WebCore/loader/WorkerThreadableLoader.cpp
@@ -34,7 +34,7 @@
#include "WorkerThreadableLoader.h"
-#include "GenericWorkerTask.h"
+#include "CrossThreadTask.h"
#include "ResourceError.h"
#include "ResourceRequest.h"
#include "ResourceResponse.h"
@@ -42,7 +42,6 @@
#include "WorkerContext.h"
#include "WorkerLoaderProxy.h"
#include "WorkerThread.h"
-#include <memory>
#include <wtf/OwnPtr.h>
#include <wtf/Threading.h>
#include <wtf/Vector.h>
@@ -101,7 +100,7 @@ WorkerThreadableLoader::MainThreadBridge::~MainThreadBridge()
{
}
-void WorkerThreadableLoader::MainThreadBridge::mainThreadCreateLoader(ScriptExecutionContext* context, MainThreadBridge* thisPtr, auto_ptr<CrossThreadResourceRequestData> requestData, ThreadableLoaderOptions options)
+void WorkerThreadableLoader::MainThreadBridge::mainThreadCreateLoader(ScriptExecutionContext* context, MainThreadBridge* thisPtr, PassOwnPtr<CrossThreadResourceRequestData> requestData, ThreadableLoaderOptions options)
{
ASSERT(isMainThread());
ASSERT(context->isDocument());
@@ -174,7 +173,7 @@ void WorkerThreadableLoader::MainThreadBridge::didSendData(unsigned long long by
m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&workerContextDidSendData, m_workerClientWrapper, bytesSent, totalBytesToBeSent), m_taskMode);
}
-static void workerContextDidReceiveResponse(ScriptExecutionContext* context, RefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, auto_ptr<CrossThreadResourceResponseData> responseData)
+static void workerContextDidReceiveResponse(ScriptExecutionContext* context, RefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, PassOwnPtr<CrossThreadResourceResponseData> responseData)
{
ASSERT_UNUSED(context, context->isWorkerContext());
OwnPtr<ResourceResponse> response(ResourceResponse::adopt(responseData));
@@ -186,7 +185,7 @@ void WorkerThreadableLoader::MainThreadBridge::didReceiveResponse(const Resource
m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&workerContextDidReceiveResponse, m_workerClientWrapper, response), m_taskMode);
}
-static void workerContextDidReceiveData(ScriptExecutionContext* context, RefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, auto_ptr<Vector<char> > vectorData)
+static void workerContextDidReceiveData(ScriptExecutionContext* context, RefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, PassOwnPtr<Vector<char> > vectorData)
{
ASSERT_UNUSED(context, context->isWorkerContext());
workerClientWrapper->didReceiveData(vectorData->data(), vectorData->size());
@@ -194,9 +193,9 @@ static void workerContextDidReceiveData(ScriptExecutionContext* context, RefPtr<
void WorkerThreadableLoader::MainThreadBridge::didReceiveData(const char* data, int lengthReceived)
{
- auto_ptr<Vector<char> > vector(new Vector<char>(lengthReceived)); // needs to be an auto_ptr for usage with createCallbackTask.
+ OwnPtr<Vector<char> > vector = adoptPtr(new Vector<char>(lengthReceived)); // needs to be an OwnPtr for usage with createCallbackTask.
memcpy(vector->data(), data, lengthReceived);
- m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&workerContextDidReceiveData, m_workerClientWrapper, vector), m_taskMode);
+ m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&workerContextDidReceiveData, m_workerClientWrapper, vector.release()), m_taskMode);
}
static void workerContextDidFinishLoading(ScriptExecutionContext* context, RefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, unsigned long identifier)
@@ -232,7 +231,7 @@ void WorkerThreadableLoader::MainThreadBridge::didFailRedirectCheck()
m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&workerContextDidFailRedirectCheck, m_workerClientWrapper), m_taskMode);
}
-static void workerContextDidReceiveAuthenticationCancellation(ScriptExecutionContext* context, RefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, auto_ptr<CrossThreadResourceResponseData> responseData)
+static void workerContextDidReceiveAuthenticationCancellation(ScriptExecutionContext* context, RefPtr<ThreadableLoaderClientWrapper> workerClientWrapper, PassOwnPtr<CrossThreadResourceResponseData> responseData)
{
ASSERT_UNUSED(context, context->isWorkerContext());
OwnPtr<ResourceResponse> response(ResourceResponse::adopt(responseData));
diff --git a/WebCore/loader/WorkerThreadableLoader.h b/WebCore/loader/WorkerThreadableLoader.h
index 09f8f85..81da2e0 100644
--- a/WebCore/loader/WorkerThreadableLoader.h
+++ b/WebCore/loader/WorkerThreadableLoader.h
@@ -38,7 +38,7 @@
#include "ThreadableLoaderClient.h"
#include "ThreadableLoaderClientWrapper.h"
-#include <memory>
+#include <wtf/PassOwnPtr.h>
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>
@@ -109,7 +109,7 @@ namespace WebCore {
static void mainThreadDestroy(ScriptExecutionContext*, MainThreadBridge*);
~MainThreadBridge();
- static void mainThreadCreateLoader(ScriptExecutionContext*, MainThreadBridge*, std::auto_ptr<CrossThreadResourceRequestData>, ThreadableLoaderOptions);
+ static void mainThreadCreateLoader(ScriptExecutionContext*, MainThreadBridge*, PassOwnPtr<CrossThreadResourceRequestData>, ThreadableLoaderOptions);
static void mainThreadCancel(ScriptExecutionContext*, MainThreadBridge*);
virtual void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent);
virtual void didReceiveResponse(const ResourceResponse&);
diff --git a/WebCore/loader/appcache/ApplicationCache.cpp b/WebCore/loader/appcache/ApplicationCache.cpp
index c0cd3ea..2a93765 100644
--- a/WebCore/loader/appcache/ApplicationCache.cpp
+++ b/WebCore/loader/appcache/ApplicationCache.cpp
@@ -32,6 +32,7 @@
#include "ApplicationCacheResource.h"
#include "ApplicationCacheStorage.h"
#include "ResourceRequest.h"
+#include <wtf/text/CString.h>
#include <stdio.h>
namespace WebCore {
@@ -130,7 +131,7 @@ ApplicationCacheResource* ApplicationCache::resourceForRequest(const ResourceReq
{
// We only care about HTTP/HTTPS GET requests.
if (!requestIsHTTPOrHTTPSGet(request))
- return false;
+ return 0;
KURL url(request.url());
if (url.hasFragmentIdentifier())
diff --git a/WebCore/loader/appcache/ApplicationCache.h b/WebCore/loader/appcache/ApplicationCache.h
index 08e2dd3..f073499 100644
--- a/WebCore/loader/appcache/ApplicationCache.h
+++ b/WebCore/loader/appcache/ApplicationCache.h
@@ -29,11 +29,11 @@
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
#include "PlatformString.h"
-#include "StringHash.h"
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
+#include <wtf/text/StringHash.h>
namespace WebCore {
@@ -41,7 +41,6 @@ class ApplicationCacheGroup;
class ApplicationCacheResource;
class DocumentLoader;
class KURL;
-
class ResourceRequest;
typedef Vector<std::pair<KURL, KURL> > FallbackURLVector;
diff --git a/WebCore/loader/appcache/ApplicationCacheGroup.cpp b/WebCore/loader/appcache/ApplicationCacheGroup.cpp
index c8a485a..8d5d5c0 100644
--- a/WebCore/loader/appcache/ApplicationCacheGroup.cpp
+++ b/WebCore/loader/appcache/ApplicationCacheGroup.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -39,24 +39,40 @@
#include "DOMWindow.h"
#include "Frame.h"
#include "FrameLoader.h"
+#include "FrameLoaderClient.h"
#include "MainResourceLoader.h"
#include "ManifestParser.h"
#include "Page.h"
+#include "SecurityOrigin.h"
#include "Settings.h"
#include <wtf/HashMap.h>
+#if ENABLE(INSPECTOR)
+#include "InspectorApplicationCacheAgent.h"
+#include "InspectorController.h"
+#include "ProgressTracker.h"
+#else
+#include <wtf/UnusedParam.h>
+#endif
+
namespace WebCore {
ApplicationCacheGroup::ApplicationCacheGroup(const KURL& manifestURL, bool isCopy)
: m_manifestURL(manifestURL)
+ , m_origin(SecurityOrigin::create(manifestURL))
, m_updateStatus(Idle)
, m_downloadingPendingMasterResourceLoadersCount(0)
+ , m_progressTotal(0)
+ , m_progressDone(0)
, m_frame(0)
, m_storageID(0)
, m_isObsolete(false)
, m_completionType(None)
, m_isCopy(isCopy)
, m_calledReachedMaxAppCacheSize(false)
+ , m_loadedSize(0)
+ , m_availableSpaceInQuota(ApplicationCacheStorage::unknownQuota())
+ , m_originQuotaReached(false)
{
}
@@ -143,14 +159,17 @@ void ApplicationCacheGroup::selectCache(Frame* frame, const KURL& passedManifest
if (mainResourceCache) {
if (manifestURL == mainResourceCache->group()->m_manifestURL) {
+ // The cache may have gotten obsoleted after we've loaded from it, but before we parsed the document and saw cache manifest.
+ if (mainResourceCache->group()->isObsolete())
+ return;
mainResourceCache->group()->associateDocumentLoaderWithCache(documentLoader, mainResourceCache);
mainResourceCache->group()->update(frame, ApplicationCacheUpdateWithBrowsingContext);
} else {
// The main resource was loaded from cache, so the cache must have an entry for it. Mark it as foreign.
- KURL documentURL(documentLoader->url());
- if (documentURL.hasFragmentIdentifier())
- documentURL.removeFragmentIdentifier();
- ApplicationCacheResource* resource = mainResourceCache->resourceForURL(documentURL);
+ KURL resourceURL(documentLoader->responseURL());
+ if (resourceURL.hasFragmentIdentifier())
+ resourceURL.removeFragmentIdentifier();
+ ApplicationCacheResource* resource = mainResourceCache->resourceForURL(resourceURL);
bool inStorage = resource->storageID();
resource->addType(ApplicationCacheResource::Foreign);
if (inStorage)
@@ -159,7 +178,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->redirectScheduler()->scheduleLocationChange(documentLoader->url(), frame->loader()->referrer(), true);
+ frame->navigationScheduler()->scheduleLocationChange(documentLoader->url(), frame->loader()->referrer(), true);
}
return;
@@ -368,12 +387,38 @@ void ApplicationCacheGroup::cacheDestroyed(ApplicationCache* cache)
}
}
+void ApplicationCacheGroup::stopLoadingInFrame(Frame* frame)
+{
+ if (frame != m_frame)
+ return;
+
+ stopLoading();
+}
+
+#if ENABLE(INSPECTOR)
+static void inspectorUpdateApplicationCacheStatus(Frame* frame)
+{
+ if (!frame)
+ return;
+
+ if (Page *page = frame->page()) {
+ if (InspectorApplicationCacheAgent* applicationCacheAgent = page->inspectorController()->applicationCacheAgent()) {
+ ApplicationCacheHost::Status status = frame->loader()->documentLoader()->applicationCacheHost()->status();
+ applicationCacheAgent->updateApplicationCacheStatus(status);
+ }
+ }
+}
+#endif
+
void ApplicationCacheGroup::setNewestCache(PassRefPtr<ApplicationCache> newestCache)
{
m_newestCache = newestCache;
m_caches.add(m_newestCache.get());
m_newestCache->setGroup(this);
+#if ENABLE(INSPECTOR)
+ inspectorUpdateApplicationCacheStatus(m_frame);
+#endif
}
void ApplicationCacheGroup::makeObsolete()
@@ -384,6 +429,9 @@ void ApplicationCacheGroup::makeObsolete()
m_isObsolete = true;
cacheStorage().cacheGroupMadeObsolete(this);
ASSERT(!m_storageID);
+#if ENABLE(INSPECTOR)
+ inspectorUpdateApplicationCacheStatus(m_frame);
+#endif
}
void ApplicationCacheGroup::update(Frame* frame, ApplicationCacheUpdateOption updateOption)
@@ -410,7 +458,7 @@ void ApplicationCacheGroup::update(Frame* frame, ApplicationCacheUpdateOption up
ASSERT(!m_frame);
m_frame = frame;
- m_updateStatus = Checking;
+ setUpdateStatus(Checking);
postListenerTask(ApplicationCacheHost::CHECKING_EVENT, m_associatedDocumentLoaders);
if (!m_newestCache) {
@@ -442,12 +490,43 @@ PassRefPtr<ResourceHandle> ApplicationCacheGroup::createResourceHandle(const KUR
request.setHTTPHeaderField("If-None-Match", eTag);
}
}
-
- return ResourceHandle::create(request, this, m_frame, false, true, false);
+
+ RefPtr<ResourceHandle> handle = ResourceHandle::create(m_frame->loader()->networkingContext(), request, this, false, true);
+#if ENABLE(INSPECTOR)
+ // Because willSendRequest only gets called during redirects, we initialize
+ // the identifier and the first willSendRequest here.
+ m_currentResourceIdentifier = m_frame->page()->progress()->createUniqueIdentifier();
+ if (Page* page = m_frame->page()) {
+ InspectorController* inspectorController = page->inspectorController();
+ inspectorController->identifierForInitialRequest(m_currentResourceIdentifier, m_frame->loader()->documentLoader(), handle->firstRequest());
+ ResourceResponse redirectResponse = ResourceResponse();
+ inspectorController->willSendRequest(m_currentResourceIdentifier, request, redirectResponse);
+ }
+#endif
+ return handle;
+}
+
+#if ENABLE(INSPECTOR)
+void ApplicationCacheGroup::willSendRequest(ResourceHandle*, ResourceRequest& request, const ResourceResponse& redirectResponse)
+{
+ // This only gets called by ResourceHandleMac if there is a redirect.
+ if (Page* page = m_frame->page())
+ page->inspectorController()->willSendRequest(m_currentResourceIdentifier, request, redirectResponse);
}
+#endif
void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, const ResourceResponse& response)
{
+#if ENABLE(INSPECTOR)
+ if (Page* page = m_frame->page()) {
+ if (handle == m_manifestHandle) {
+ if (InspectorApplicationCacheAgent* applicationCacheAgent = page->inspectorController()->applicationCacheAgent())
+ applicationCacheAgent->didReceiveManifestResponse(m_currentResourceIdentifier, response);
+ } else
+ page->inspectorController()->didReceiveResponse(m_currentResourceIdentifier, m_frame->loader()->documentLoader(), response);
+ }
+#endif
+
if (handle == m_manifestHandle) {
didReceiveManifestResponse(response);
return;
@@ -455,7 +534,7 @@ void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, const Res
ASSERT(handle == m_currentHandle);
- KURL url(handle->request().url());
+ KURL url(handle->firstRequest().url());
if (url.hasFragmentIdentifier())
url.removeFragmentIdentifier();
@@ -472,7 +551,7 @@ void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, const Res
ApplicationCacheResource* newestCachedResource = m_newestCache->resourceForURL(url);
if (newestCachedResource) {
m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, newestCachedResource->response(), type, newestCachedResource->data()));
- m_pendingEntries.remove(m_currentHandle->request().url());
+ m_pendingEntries.remove(m_currentHandle->firstRequest().url());
m_currentHandle->cancel();
m_currentHandle = 0;
// Load the next resource, if any.
@@ -482,7 +561,7 @@ void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, const Res
// The server could return 304 for an unconditional request - in this case, we handle the response as a normal error.
}
- if (response.httpStatusCode() / 100 != 2 || response.url() != m_currentHandle->request().url()) {
+ if (response.httpStatusCode() / 100 != 2 || response.url() != m_currentHandle->firstRequest().url()) {
if ((type & ApplicationCacheResource::Explicit) || (type & ApplicationCacheResource::Fallback)) {
// Note that cacheUpdateFailed() can cause the cache group to be deleted.
cacheUpdateFailed();
@@ -497,10 +576,10 @@ void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, const Res
// Copy the resource and its metadata from the newest application cache in cache group whose completeness flag is complete, and act
// as if that was the fetched resource, ignoring the resource obtained from the network.
ASSERT(m_newestCache);
- ApplicationCacheResource* newestCachedResource = m_newestCache->resourceForURL(handle->request().url());
+ ApplicationCacheResource* newestCachedResource = m_newestCache->resourceForURL(handle->firstRequest().url());
ASSERT(newestCachedResource);
m_cacheBeingUpdated->addResource(ApplicationCacheResource::create(url, newestCachedResource->response(), type, newestCachedResource->data()));
- m_pendingEntries.remove(m_currentHandle->request().url());
+ m_pendingEntries.remove(m_currentHandle->firstRequest().url());
m_currentHandle->cancel();
m_currentHandle = 0;
// Load the next resource, if any.
@@ -512,8 +591,15 @@ void ApplicationCacheGroup::didReceiveResponse(ResourceHandle* handle, const Res
m_currentResource = ApplicationCacheResource::create(url, response, type);
}
-void ApplicationCacheGroup::didReceiveData(ResourceHandle* handle, const char* data, int length, int)
+void ApplicationCacheGroup::didReceiveData(ResourceHandle* handle, const char* data, int length, int lengthReceived)
{
+#if ENABLE(INSPECTOR)
+ if (Page* page = m_frame->page())
+ page->inspectorController()->didReceiveContentLength(m_currentResourceIdentifier, lengthReceived);
+#else
+ UNUSED_PARAM(lengthReceived);
+#endif
+
if (handle == m_manifestHandle) {
didReceiveManifestData(data, length);
return;
@@ -523,19 +609,42 @@ void ApplicationCacheGroup::didReceiveData(ResourceHandle* handle, const char* d
ASSERT(m_currentResource);
m_currentResource->data()->append(data, length);
+
+ m_loadedSize += length;
}
-void ApplicationCacheGroup::didFinishLoading(ResourceHandle* handle)
+void ApplicationCacheGroup::didFinishLoading(ResourceHandle* handle, double finishTime)
{
+#if ENABLE(INSPECTOR)
+ if (Page* page = m_frame->page())
+ page->inspectorController()->didFinishLoading(m_currentResourceIdentifier, finishTime);
+#endif
+
if (handle == m_manifestHandle) {
didFinishLoadingManifest();
return;
}
-
+
+ // After finishing the loading of any resource, we check if it will
+ // fit in our last known quota limit.
+ if (m_availableSpaceInQuota == ApplicationCacheStorage::unknownQuota()) {
+ // Failed to determine what is left in the quota. Fallback to allowing anything.
+ if (!cacheStorage().remainingSizeForOriginExcludingCache(m_origin.get(), m_newestCache.get(), m_availableSpaceInQuota))
+ m_availableSpaceInQuota = ApplicationCacheStorage::noQuota();
+ }
+
+ // Check each resource, as it loads, to see if it would fit in our
+ // idea of the available quota space.
+ if (m_availableSpaceInQuota < m_loadedSize) {
+ m_currentResource = 0;
+ cacheUpdateFailedDueToOriginQuota();
+ return;
+ }
+
ASSERT(m_currentHandle == handle);
- ASSERT(m_pendingEntries.contains(handle->request().url()));
+ ASSERT(m_pendingEntries.contains(handle->firstRequest().url()));
- m_pendingEntries.remove(handle->request().url());
+ m_pendingEntries.remove(handle->firstRequest().url());
ASSERT(m_cacheBeingUpdated);
@@ -546,15 +655,22 @@ void ApplicationCacheGroup::didFinishLoading(ResourceHandle* handle)
startLoadingEntry();
}
-void ApplicationCacheGroup::didFail(ResourceHandle* handle, const ResourceError&)
+void ApplicationCacheGroup::didFail(ResourceHandle* handle, const ResourceError& error)
{
+#if ENABLE(INSPECTOR)
+ if (Page* page = m_frame->page())
+ page->inspectorController()->didFailLoading(m_currentResourceIdentifier, error);
+#else
+ UNUSED_PARAM(error);
+#endif
+
if (handle == m_manifestHandle) {
cacheUpdateFailed();
return;
}
- unsigned type = m_currentResource ? m_currentResource->type() : m_pendingEntries.get(handle->request().url());
- KURL url(handle->request().url());
+ unsigned type = m_currentResource ? m_currentResource->type() : m_pendingEntries.get(handle->firstRequest().url());
+ KURL url(handle->firstRequest().url());
if (url.hasFragmentIdentifier())
url.removeFragmentIdentifier();
@@ -590,13 +706,12 @@ void ApplicationCacheGroup::didReceiveManifestResponse(const ResourceResponse& r
if (response.httpStatusCode() == 304)
return;
- if (response.httpStatusCode() / 100 != 2 || response.url() != m_manifestHandle->request().url() || !equalIgnoringCase(response.mimeType(), "text/cache-manifest")) {
+ if (response.httpStatusCode() / 100 != 2 || response.url() != m_manifestHandle->firstRequest().url() || !equalIgnoringCase(response.mimeType(), "text/cache-manifest")) {
cacheUpdateFailed();
return;
}
- m_manifestResource = ApplicationCacheResource::create(m_manifestHandle->request().url(), response,
- ApplicationCacheResource::Manifest);
+ m_manifestResource = ApplicationCacheResource::create(m_manifestHandle->firstRequest().url(), response, ApplicationCacheResource::Manifest);
}
void ApplicationCacheGroup::didReceiveManifestData(const char* data, int length)
@@ -648,7 +763,7 @@ void ApplicationCacheGroup::didFinishLoadingManifest()
associateDocumentLoaderWithCache(*iter, m_cacheBeingUpdated.get());
// We have the manifest, now download the resources.
- m_updateStatus = Downloading;
+ setUpdateStatus(Downloading);
postListenerTask(ApplicationCacheHost::DOWNLOADING_EVENT, m_associatedDocumentLoaders);
@@ -674,7 +789,10 @@ void ApplicationCacheGroup::didFinishLoadingManifest()
m_cacheBeingUpdated->setOnlineWhitelist(manifest.onlineWhitelistedURLs);
m_cacheBeingUpdated->setFallbackURLs(manifest.fallbackURLs);
m_cacheBeingUpdated->setAllowsAllNetworkRequests(manifest.allowAllNetworkRequests);
-
+
+ m_progressTotal = m_pendingEntries.size();
+ m_progressDone = 0;
+
startLoadingEntry();
}
@@ -687,6 +805,13 @@ void ApplicationCacheGroup::didReachMaxAppCacheSize()
checkIfLoadIsComplete();
}
+void ApplicationCacheGroup::didReachOriginQuota(PassRefPtr<Frame> frame)
+{
+ // Inform the client the origin quota has been reached,
+ // they may decide to increase the quota.
+ frame->page()->chrome()->client()->reachedApplicationCacheOriginQuota(m_origin.get());
+}
+
void ApplicationCacheGroup::cacheUpdateFailed()
{
stopLoading();
@@ -696,6 +821,16 @@ void ApplicationCacheGroup::cacheUpdateFailed()
m_completionType = Failure;
deliverDelayedMainResources();
}
+
+void ApplicationCacheGroup::cacheUpdateFailedDueToOriginQuota()
+{
+ if (!m_originQuotaReached) {
+ m_originQuotaReached = true;
+ scheduleReachedOriginQuotaCallback();
+ }
+
+ cacheUpdateFailed();
+}
void ApplicationCacheGroup::manifestNotFound()
{
@@ -719,7 +854,7 @@ void ApplicationCacheGroup::manifestNotFound()
}
m_downloadingPendingMasterResourceLoadersCount = 0;
- m_updateStatus = Idle;
+ setUpdateStatus(Idle);
m_frame = 0;
if (m_caches.isEmpty()) {
@@ -775,17 +910,32 @@ void ApplicationCacheGroup::checkIfLoadIsComplete()
ASSERT(cacheStorage().isMaximumSizeReached() && m_calledReachedMaxAppCacheSize);
}
+ ApplicationCacheStorage::FailureReason failureReason;
RefPtr<ApplicationCache> oldNewestCache = (m_newestCache == m_cacheBeingUpdated) ? 0 : m_newestCache;
-
setNewestCache(m_cacheBeingUpdated.release());
- if (cacheStorage().storeNewestCache(this)) {
+ if (cacheStorage().storeNewestCache(this, oldNewestCache.get(), failureReason)) {
// New cache stored, now remove the old cache.
if (oldNewestCache)
cacheStorage().remove(oldNewestCache.get());
- // Fire the success events.
+
+ // Fire the final progress event.
+ ASSERT(m_progressDone == m_progressTotal);
+ postListenerTask(ApplicationCacheHost::PROGRESS_EVENT, m_progressTotal, m_progressDone, m_associatedDocumentLoaders);
+
+ // Fire the success event.
postListenerTask(isUpgradeAttempt ? ApplicationCacheHost::UPDATEREADY_EVENT : ApplicationCacheHost::CACHED_EVENT, m_associatedDocumentLoaders);
+ // It is clear that the origin quota was not reached, so clear the flag if it was set.
+ m_originQuotaReached = false;
} else {
- if (cacheStorage().isMaximumSizeReached() && !m_calledReachedMaxAppCacheSize) {
+ if (failureReason == ApplicationCacheStorage::OriginQuotaReached) {
+ // We ran out of space for this origin. Roll back to previous state.
+ if (oldNewestCache)
+ setNewestCache(oldNewestCache.release());
+ cacheUpdateFailedDueToOriginQuota();
+ return;
+ }
+
+ if (failureReason == ApplicationCacheStorage::TotalQuotaReached && !m_calledReachedMaxAppCacheSize) {
// We ran out of space. All the changes in the cache storage have
// been rolled back. We roll back to the previous state in here,
// as well, call the chrome client asynchronously and retry to
@@ -799,30 +949,30 @@ void ApplicationCacheGroup::checkIfLoadIsComplete()
}
scheduleReachedMaxAppCacheSizeCallback();
return;
+ }
+
+ // Run the "cache failure steps"
+ // Fire the error events to all pending master entries, as well any other cache hosts
+ // currently associated with a cache in this group.
+ postListenerTask(ApplicationCacheHost::ERROR_EVENT, m_associatedDocumentLoaders);
+ // Disassociate the pending master entries from the failed new cache. Note that
+ // all other loaders in the m_associatedDocumentLoaders are still associated with
+ // some other cache in this group. They are not associated with the failed new cache.
+
+ // Need to copy loaders, because the cache group may be destroyed at the end of iteration.
+ Vector<DocumentLoader*> loaders;
+ copyToVector(m_pendingMasterResourceLoaders, loaders);
+ size_t count = loaders.size();
+ for (size_t i = 0; i != count; ++i)
+ disassociateDocumentLoader(loaders[i]); // This can delete this group.
+
+ // Reinstate the oldNewestCache, if there was one.
+ if (oldNewestCache) {
+ // This will discard the failed new cache.
+ setNewestCache(oldNewestCache.release());
} else {
- // Run the "cache failure steps"
- // Fire the error events to all pending master entries, as well any other cache hosts
- // currently associated with a cache in this group.
- postListenerTask(ApplicationCacheHost::ERROR_EVENT, m_associatedDocumentLoaders);
- // Disassociate the pending master entries from the failed new cache. Note that
- // all other loaders in the m_associatedDocumentLoaders are still associated with
- // some other cache in this group. They are not associated with the failed new cache.
-
- // Need to copy loaders, because the cache group may be destroyed at the end of iteration.
- Vector<DocumentLoader*> loaders;
- copyToVector(m_pendingMasterResourceLoaders, loaders);
- size_t count = loaders.size();
- for (size_t i = 0; i != count; ++i)
- disassociateDocumentLoader(loaders[i]); // This can delete this group.
-
- // Reinstate the oldNewestCache, if there was one.
- if (oldNewestCache) {
- // This will discard the failed new cache.
- setNewestCache(oldNewestCache.release());
- } else {
- // We must have been deleted by the last call to disassociateDocumentLoader().
- return;
- }
+ // We must have been deleted by the last call to disassociateDocumentLoader().
+ return;
}
}
break;
@@ -832,8 +982,10 @@ void ApplicationCacheGroup::checkIfLoadIsComplete()
// Empty cache group's list of pending master entries.
m_pendingMasterResourceLoaders.clear();
m_completionType = None;
- m_updateStatus = Idle;
+ setUpdateStatus(Idle);
m_frame = 0;
+ m_loadedSize = 0;
+ m_availableSpaceInQuota = ApplicationCacheStorage::unknownQuota();
m_calledReachedMaxAppCacheSize = false;
}
@@ -849,7 +1001,8 @@ void ApplicationCacheGroup::startLoadingEntry()
EntryMap::const_iterator it = m_pendingEntries.begin();
- postListenerTask(ApplicationCacheHost::PROGRESS_EVENT, m_associatedDocumentLoaders);
+ postListenerTask(ApplicationCacheHost::PROGRESS_EVENT, m_progressTotal, m_progressDone, m_associatedDocumentLoaders);
+ m_progressDone++;
ASSERT(!m_currentHandle);
@@ -946,11 +1099,17 @@ void ApplicationCacheGroup::scheduleReachedMaxAppCacheSizeCallback()
// The timer will delete itself once it fires.
}
+void ApplicationCacheGroup::scheduleReachedOriginQuotaCallback()
+{
+ // FIXME: it might be nice to run this asynchronously, because there is no return value to wait for.
+ didReachOriginQuota(m_frame);
+}
+
class CallCacheListenerTask : public ScriptExecutionContext::Task {
public:
- static PassOwnPtr<CallCacheListenerTask> create(PassRefPtr<DocumentLoader> loader, ApplicationCacheHost::EventID eventID)
+ static PassOwnPtr<CallCacheListenerTask> create(PassRefPtr<DocumentLoader> loader, ApplicationCacheHost::EventID eventID, int progressTotal, int progressDone)
{
- return new CallCacheListenerTask(loader, eventID);
+ return adoptPtr(new CallCacheListenerTask(loader, eventID, progressTotal, progressDone));
}
virtual void performTask(ScriptExecutionContext* context)
@@ -963,28 +1122,32 @@ public:
ASSERT(frame->loader()->documentLoader() == m_documentLoader.get());
- m_documentLoader->applicationCacheHost()->notifyDOMApplicationCache(m_eventID);
+ m_documentLoader->applicationCacheHost()->notifyDOMApplicationCache(m_eventID, m_progressTotal, m_progressDone);
}
private:
- CallCacheListenerTask(PassRefPtr<DocumentLoader> loader, ApplicationCacheHost::EventID eventID)
+ CallCacheListenerTask(PassRefPtr<DocumentLoader> loader, ApplicationCacheHost::EventID eventID, int progressTotal, int progressDone)
: m_documentLoader(loader)
, m_eventID(eventID)
+ , m_progressTotal(progressTotal)
+ , m_progressDone(progressDone)
{
}
RefPtr<DocumentLoader> m_documentLoader;
ApplicationCacheHost::EventID m_eventID;
+ int m_progressTotal;
+ int m_progressDone;
};
-void ApplicationCacheGroup::postListenerTask(ApplicationCacheHost::EventID eventID, const HashSet<DocumentLoader*>& loaderSet)
+void ApplicationCacheGroup::postListenerTask(ApplicationCacheHost::EventID eventID, int progressTotal, int progressDone, const HashSet<DocumentLoader*>& loaderSet)
{
HashSet<DocumentLoader*>::const_iterator loaderSetEnd = loaderSet.end();
for (HashSet<DocumentLoader*>::const_iterator iter = loaderSet.begin(); iter != loaderSetEnd; ++iter)
- postListenerTask(eventID, *iter);
+ postListenerTask(eventID, progressTotal, progressDone, *iter);
}
-void ApplicationCacheGroup::postListenerTask(ApplicationCacheHost::EventID eventID, DocumentLoader* loader)
+void ApplicationCacheGroup::postListenerTask(ApplicationCacheHost::EventID eventID, int progressTotal, int progressDone, DocumentLoader* loader)
{
Frame* frame = loader->frame();
if (!frame)
@@ -992,7 +1155,15 @@ void ApplicationCacheGroup::postListenerTask(ApplicationCacheHost::EventID event
ASSERT(frame->loader()->documentLoader() == loader);
- frame->document()->postTask(CallCacheListenerTask::create(loader, eventID));
+ frame->document()->postTask(CallCacheListenerTask::create(loader, eventID, progressTotal, progressDone));
+}
+
+void ApplicationCacheGroup::setUpdateStatus(UpdateStatus status)
+{
+ m_updateStatus = status;
+#if ENABLE(INSPECTOR)
+ inspectorUpdateApplicationCacheStatus(m_frame);
+#endif
}
void ApplicationCacheGroup::clearStorageID()
diff --git a/WebCore/loader/appcache/ApplicationCacheGroup.h b/WebCore/loader/appcache/ApplicationCacheGroup.h
index 8df52cc..29d0749 100644
--- a/WebCore/loader/appcache/ApplicationCacheGroup.h
+++ b/WebCore/loader/appcache/ApplicationCacheGroup.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,10 +28,6 @@
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
-#include <wtf/Noncopyable.h>
-#include <wtf/HashMap.h>
-#include <wtf/HashSet.h>
-
#include "DOMApplicationCache.h"
#include "KURL.h"
#include "PlatformString.h"
@@ -39,6 +35,10 @@
#include "ResourceHandleClient.h"
#include "SharedBuffer.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+
namespace WebCore {
class ApplicationCache;
@@ -46,6 +46,7 @@ class ApplicationCacheResource;
class Document;
class DocumentLoader;
class Frame;
+class SecurityOrigin;
enum ApplicationCacheUpdateOption {
ApplicationCacheUpdateWithBrowsingContext,
@@ -66,17 +67,21 @@ public:
static void selectCacheWithoutManifestURL(Frame*);
const KURL& manifestURL() const { return m_manifestURL; }
+ const SecurityOrigin* origin() const { return m_origin.get(); }
UpdateStatus updateStatus() const { return m_updateStatus; }
+ void setUpdateStatus(UpdateStatus status);
void setStorageID(unsigned storageID) { m_storageID = storageID; }
unsigned storageID() const { return m_storageID; }
void clearStorageID();
- void update(Frame*, ApplicationCacheUpdateOption); // FIXME: Frame should not bee needed when updating witout browsing context.
+ void update(Frame*, ApplicationCacheUpdateOption); // FIXME: Frame should not be needed when updating without browsing context.
void cacheDestroyed(ApplicationCache*);
bool cacheIsBeingUpdated(const ApplicationCache* cache) const { return cache == m_cacheBeingUpdated; }
+ void stopLoadingInFrame(Frame*);
+
ApplicationCache* newestCache() const { return m_newestCache.get(); }
void setNewestCache(PassRefPtr<ApplicationCache>);
@@ -91,9 +96,13 @@ public:
bool isCopy() const { return m_isCopy; }
private:
- static void postListenerTask(ApplicationCacheHost::EventID, const HashSet<DocumentLoader*>&);
- static void postListenerTask(ApplicationCacheHost::EventID, DocumentLoader*);
+ static void postListenerTask(ApplicationCacheHost::EventID id, const HashSet<DocumentLoader*>& set) { postListenerTask(id, 0, 0, set); }
+ static void postListenerTask(ApplicationCacheHost::EventID id, DocumentLoader* loader) { postListenerTask(id, 0, 0, loader); }
+ static void postListenerTask(ApplicationCacheHost::EventID, int progressTotal, int progressDone, const HashSet<DocumentLoader*>&);
+ static void postListenerTask(ApplicationCacheHost::EventID, int progressTotal, int progressDone, DocumentLoader*);
+
void scheduleReachedMaxAppCacheSizeCallback();
+ void scheduleReachedOriginQuotaCallback();
PassRefPtr<ResourceHandle> createResourceHandle(const KURL&, ApplicationCacheResource* newestCachedResource);
@@ -101,20 +110,25 @@ private:
// 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; }
+#if ENABLE(INSPECTOR)
+ virtual void willSendRequest(ResourceHandle*, ResourceRequest&, const ResourceResponse&);
+#endif
virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&);
- virtual void didReceiveData(ResourceHandle*, const char*, int, int lengthReceived);
- virtual void didFinishLoading(ResourceHandle*);
+ virtual void didReceiveData(ResourceHandle*, const char*, int length, int lengthReceived);
+ virtual void didFinishLoading(ResourceHandle*, double finishTime);
virtual void didFail(ResourceHandle*, const ResourceError&);
void didReceiveManifestResponse(const ResourceResponse&);
void didReceiveManifestData(const char*, int);
void didFinishLoadingManifest();
void didReachMaxAppCacheSize();
+ void didReachOriginQuota(PassRefPtr<Frame> frame);
void startLoadingEntry();
void deliverDelayedMainResources();
void checkIfLoadIsComplete();
void cacheUpdateFailed();
+ void cacheUpdateFailedDueToOriginQuota();
void manifestNotFound();
void addEntry(const String&, unsigned type);
@@ -124,6 +138,7 @@ private:
void stopLoading();
KURL m_manifestURL;
+ RefPtr<SecurityOrigin> m_origin;
UpdateStatus m_updateStatus;
// This is the newest complete cache in the group.
@@ -147,6 +162,10 @@ private:
// The URLs and types of pending cache entries.
typedef HashMap<String, unsigned> EntryMap;
EntryMap m_pendingEntries;
+
+ // The total number of items to be processed to update the cache group and the number that have been done.
+ int m_progressTotal;
+ int m_progressDone;
// Frame used for fetching resources when updating.
// FIXME: An update started by a particular frame should not stop if it is destroyed, but there are other frames associated with the same cache group.
@@ -175,11 +194,20 @@ private:
RefPtr<ResourceHandle> m_currentHandle;
RefPtr<ApplicationCacheResource> m_currentResource;
-
+
+#if ENABLE(INSPECTOR)
+ unsigned long m_currentResourceIdentifier;
+#endif
+
RefPtr<ApplicationCacheResource> m_manifestResource;
RefPtr<ResourceHandle> m_manifestHandle;
+ int64_t m_loadedSize;
+ int64_t m_availableSpaceInQuota;
+ bool m_originQuotaReached;
+
friend class ChromeClientCallbackTimer;
+ friend class OriginQuotaReachedCallbackTimer;
};
} // namespace WebCore
diff --git a/WebCore/loader/appcache/ApplicationCacheHost.cpp b/WebCore/loader/appcache/ApplicationCacheHost.cpp
index fc98746..d5707cf 100644
--- a/WebCore/loader/appcache/ApplicationCacheHost.cpp
+++ b/WebCore/loader/appcache/ApplicationCacheHost.cpp
@@ -37,6 +37,7 @@
#include "FrameLoader.h"
#include "FrameLoaderClient.h"
#include "MainResourceLoader.h"
+#include "ProgressEvent.h"
#include "ResourceLoader.h"
#include "ResourceRequest.h"
#include "Settings.h"
@@ -54,6 +55,8 @@ ApplicationCacheHost::ApplicationCacheHost(DocumentLoader* documentLoader)
ApplicationCacheHost::~ApplicationCacheHost()
{
+ ASSERT(!m_applicationCache || !m_candidateApplicationCacheGroup || m_applicationCache->group() == m_candidateApplicationCacheGroup);
+
if (m_applicationCache)
m_applicationCache->group()->disassociateDocumentLoader(m_documentLoader);
else if (m_candidateApplicationCacheGroup)
@@ -88,6 +91,12 @@ void ApplicationCacheHost::maybeLoadMainResource(ResourceRequest& request, Subst
}
}
+void ApplicationCacheHost::maybeLoadMainResourceForRedirect(ResourceRequest& request, SubstituteData& substituteData)
+{
+ ASSERT(status() == UNCACHED);
+ maybeLoadMainResource(request, substituteData);
+}
+
bool ApplicationCacheHost::maybeLoadFallbackForMainResponse(const ResourceRequest& request, const ResourceResponse& r)
{
if (r.httpStatusCode() / 100 == 4 || r.httpStatusCode() / 100 == 5) {
@@ -125,7 +134,10 @@ void ApplicationCacheHost::failedLoadingMainResource()
{
ApplicationCacheGroup* group = m_candidateApplicationCacheGroup;
if (!group && m_applicationCache) {
- ASSERT(!mainResourceApplicationCache()); // If the main resource were loaded from a cache, it wouldn't fail.
+ if (mainResourceApplicationCache()) {
+ // Even when the main resource is being loaded from an application cache, loading can fail if aborted.
+ return;
+ }
group = m_applicationCache->group();
}
@@ -228,35 +240,83 @@ void ApplicationCacheHost::setDOMApplicationCache(DOMApplicationCache* domApplic
m_domApplicationCache = domApplicationCache;
}
-void ApplicationCacheHost::notifyDOMApplicationCache(EventID id)
+void ApplicationCacheHost::notifyDOMApplicationCache(EventID id, int total, int done)
{
if (m_defersEvents) {
- // Events are deferred until document.onload has fired.
- m_deferredEvents.append(id);
+ // Event dispatching is deferred until document.onload has fired.
+ m_deferredEvents.append(DeferredEvent(id, total, done));
return;
}
- if (m_domApplicationCache) {
- ExceptionCode ec = 0;
- m_domApplicationCache->dispatchEvent(Event::create(DOMApplicationCache::toEventType(id), false, false), ec);
- ASSERT(!ec);
- }
+ dispatchDOMEvent(id, total, done);
+}
+
+void ApplicationCacheHost::stopLoadingInFrame(Frame* frame)
+{
+ ASSERT(!m_applicationCache || !m_candidateApplicationCacheGroup || m_applicationCache->group() == m_candidateApplicationCacheGroup);
+
+ if (m_candidateApplicationCacheGroup)
+ m_candidateApplicationCacheGroup->stopLoadingInFrame(frame);
+ else if (m_applicationCache)
+ m_applicationCache->group()->stopLoadingInFrame(frame);
}
void ApplicationCacheHost::stopDeferringEvents()
{
RefPtr<DocumentLoader> protect(documentLoader());
for (unsigned i = 0; i < m_deferredEvents.size(); ++i) {
- EventID id = m_deferredEvents[i];
- if (m_domApplicationCache) {
- ExceptionCode ec = 0;
- m_domApplicationCache->dispatchEvent(Event::create(DOMApplicationCache::toEventType(id), false, false), ec);
- ASSERT(!ec);
- }
+ const DeferredEvent& deferred = m_deferredEvents[i];
+ dispatchDOMEvent(deferred.eventID, deferred.progressTotal, deferred.progressDone);
}
m_deferredEvents.clear();
m_defersEvents = false;
}
+#if ENABLE(INSPECTOR)
+void ApplicationCacheHost::fillResourceList(ResourceInfoList* resources)
+{
+ ApplicationCache* cache = applicationCache();
+ if (!cache || !cache->isComplete())
+ return;
+
+ ApplicationCache::ResourceMap::const_iterator end = cache->end();
+ for (ApplicationCache::ResourceMap::const_iterator it = cache->begin(); it != end; ++it) {
+ RefPtr<ApplicationCacheResource> resource = it->second;
+ unsigned type = resource->type();
+ bool isMaster = type & ApplicationCacheResource::Master;
+ bool isManifest = type & ApplicationCacheResource::Manifest;
+ bool isExplicit = type & ApplicationCacheResource::Explicit;
+ bool isForeign = type & ApplicationCacheResource::Foreign;
+ bool isFallback = type & ApplicationCacheResource::Fallback;
+ resources->append(ResourceInfo(resource->url(), isMaster, isManifest, isFallback, isForeign, isExplicit, resource->estimatedSizeInStorage()));
+ }
+}
+
+ApplicationCacheHost::CacheInfo ApplicationCacheHost::applicationCacheInfo()
+{
+ ApplicationCache* cache = applicationCache();
+ if (!cache || !cache->isComplete())
+ return CacheInfo(KURL(), 0, 0, 0);
+
+ // FIXME: Add "Creation Time" and "Update Time" to Application Caches.
+ return CacheInfo(cache->manifestResource()->url(), 0, 0, cache->estimatedSizeInStorage());
+}
+#endif
+
+void ApplicationCacheHost::dispatchDOMEvent(EventID id, int total, int done)
+{
+ if (m_domApplicationCache) {
+ const AtomicString& eventType = DOMApplicationCache::toEventType(id);
+ ExceptionCode ec = 0;
+ RefPtr<Event> event;
+ if (id == PROGRESS_EVENT)
+ event = ProgressEvent::create(eventType, true, done, total);
+ else
+ event = Event::create(eventType, false, false);
+ m_domApplicationCache->dispatchEvent(event, ec);
+ ASSERT(!ec);
+ }
+}
+
void ApplicationCacheHost::setCandidateApplicationCacheGroup(ApplicationCacheGroup* group)
{
ASSERT(!m_applicationCache);
diff --git a/WebCore/loader/appcache/ApplicationCacheHost.h b/WebCore/loader/appcache/ApplicationCacheHost.h
index 52d4d40..8ac5357 100644
--- a/WebCore/loader/appcache/ApplicationCacheHost.h
+++ b/WebCore/loader/appcache/ApplicationCacheHost.h
@@ -33,6 +33,7 @@
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
+#include "KURL.h"
#include <wtf/Deque.h>
#include <wtf/OwnPtr.h>
#include <wtf/PassRefPtr.h>
@@ -40,10 +41,9 @@
#include <wtf/Vector.h>
namespace WebCore {
-
class DOMApplicationCache;
class DocumentLoader;
- class KURL;
+ class Frame;
class ResourceLoader;
class ResourceError;
class ResourceRequest;
@@ -81,6 +81,40 @@ namespace WebCore {
OBSOLETE_EVENT // Must remain the last value, this is used to size arrays.
};
+#if ENABLE(INSPECTOR)
+ struct CacheInfo {
+ CacheInfo(const KURL& manifest, double creationTime, double updateTime, long long size)
+ : m_manifest(manifest)
+ , m_creationTime(creationTime)
+ , m_updateTime(updateTime)
+ , m_size(size) { }
+ KURL m_manifest;
+ double m_creationTime;
+ double m_updateTime;
+ long long m_size;
+ };
+
+ struct ResourceInfo {
+ ResourceInfo(const KURL& resource, bool isMaster, bool isManifest, bool isFallback, bool isForeign, bool isExplicit, long long size)
+ : m_resource(resource)
+ , m_isMaster(isMaster)
+ , m_isManifest(isManifest)
+ , m_isFallback(isFallback)
+ , m_isForeign(isForeign)
+ , m_isExplicit(isExplicit)
+ , m_size(size) { }
+ KURL m_resource;
+ bool m_isMaster;
+ bool m_isManifest;
+ bool m_isFallback;
+ bool m_isForeign;
+ bool m_isExplicit;
+ long long m_size;
+ };
+
+ typedef Vector<ResourceInfo> ResourceInfoList;
+#endif
+
ApplicationCacheHost(DocumentLoader*);
~ApplicationCacheHost();
@@ -88,6 +122,7 @@ namespace WebCore {
void selectCacheWithManifest(const KURL& manifestURL);
void maybeLoadMainResource(ResourceRequest&, SubstituteData&);
+ void maybeLoadMainResourceForRedirect(ResourceRequest&, SubstituteData&);
bool maybeLoadFallbackForMainResponse(const ResourceRequest&, const ResourceResponse&);
bool maybeLoadFallbackForMainError(const ResourceRequest&, const ResourceError&);
void mainResourceDataReceived(const char* data, int length, long long lengthReceived, bool allAtOnce);
@@ -108,19 +143,35 @@ namespace WebCore {
bool update();
bool swapCache();
- void setDOMApplicationCache(DOMApplicationCache* domApplicationCache);
- void notifyDOMApplicationCache(EventID id);
+ void setDOMApplicationCache(DOMApplicationCache*);
+ void notifyDOMApplicationCache(EventID, int progressTotal, int progressDone);
+
+ void stopLoadingInFrame(Frame*);
void stopDeferringEvents(); // Also raises the events that have been queued up.
+#if ENABLE(INSPECTOR)
+ void fillResourceList(ResourceInfoList*);
+ CacheInfo applicationCacheInfo();
+#endif
+
private:
bool isApplicationCacheEnabled();
- DocumentLoader* documentLoader() { return m_documentLoader; }
+ DocumentLoader* documentLoader() const { return m_documentLoader; }
+
+ struct DeferredEvent {
+ EventID eventID;
+ int progressTotal;
+ int progressDone;
+ DeferredEvent(EventID id, int total, int done) : eventID(id), progressTotal(total), progressDone(done) { }
+ };
DOMApplicationCache* m_domApplicationCache;
DocumentLoader* m_documentLoader;
bool m_defersEvents; // Events are deferred until after document onload.
- Vector<EventID> m_deferredEvents;
+ Vector<DeferredEvent> m_deferredEvents;
+
+ void dispatchDOMEvent(EventID, int progressTotal, int progressDone);
#if PLATFORM(CHROMIUM)
friend class ApplicationCacheHostInternal;
diff --git a/WebCore/loader/appcache/ApplicationCacheStorage.cpp b/WebCore/loader/appcache/ApplicationCacheStorage.cpp
index 1e97d78..7b20775 100644
--- a/WebCore/loader/appcache/ApplicationCacheStorage.cpp
+++ b/WebCore/loader/appcache/ApplicationCacheStorage.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,14 +29,15 @@
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
#include "ApplicationCache.h"
-#include "ApplicationCacheHost.h"
#include "ApplicationCacheGroup.h"
+#include "ApplicationCacheHost.h"
#include "ApplicationCacheResource.h"
-#include "CString.h"
#include "FileSystem.h"
#include "KURL.h"
#include "SQLiteStatement.h"
#include "SQLiteTransaction.h"
+#include "SecurityOrigin.h"
+#include <wtf/text/CString.h>
#include <wtf/StdLibExtras.h>
#include <wtf/StringExtras.h>
@@ -171,8 +172,7 @@ void ApplicationCacheStorage::loadManifestHostHashes()
if (statement.prepare() != SQLResultOk)
return;
- int result;
- while ((result = statement.step()) == SQLResultRow)
+ while (statement.step() == SQLResultRow)
m_cacheHostSet.add(static_cast<unsigned>(statement.getColumnInt64(0)));
}
@@ -415,6 +415,126 @@ int64_t ApplicationCacheStorage::spaceNeeded(int64_t cacheToSave)
return spaceNeeded;
}
+void ApplicationCacheStorage::setDefaultOriginQuota(int64_t quota)
+{
+ m_defaultOriginQuota = quota;
+}
+
+bool ApplicationCacheStorage::quotaForOrigin(const SecurityOrigin* origin, int64_t& quota)
+{
+ // If an Origin record doesn't exist, then the COUNT will be 0 and quota will be 0.
+ // Using the count to determine if a record existed or not is a safe way to determine
+ // if a quota of 0 is real, from the record, or from null.
+ SQLiteStatement statement(m_database, "SELECT COUNT(quota), quota FROM Origins WHERE origin=?");
+ if (statement.prepare() != SQLResultOk)
+ return false;
+
+ statement.bindText(1, origin->databaseIdentifier());
+ int result = statement.step();
+
+ // Return the quota, or if it was null the default.
+ if (result == SQLResultRow) {
+ bool wasNoRecord = statement.getColumnInt64(0) == 0;
+ quota = wasNoRecord ? m_defaultOriginQuota : statement.getColumnInt64(1);
+ return true;
+ }
+
+ LOG_ERROR("Could not get the quota of an origin, error \"%s\"", m_database.lastErrorMsg());
+ return false;
+}
+
+bool ApplicationCacheStorage::usageForOrigin(const SecurityOrigin* origin, int64_t& usage)
+{
+ // If an Origins record doesn't exist, then the SUM will be null,
+ // which will become 0, as expected, when converting to a number.
+ SQLiteStatement statement(m_database, "SELECT SUM(Caches.size)"
+ " FROM CacheGroups"
+ " INNER JOIN Origins ON CacheGroups.origin = Origins.origin"
+ " INNER JOIN Caches ON CacheGroups.id = Caches.cacheGroup"
+ " WHERE Origins.origin=?");
+ if (statement.prepare() != SQLResultOk)
+ return false;
+
+ statement.bindText(1, origin->databaseIdentifier());
+ int result = statement.step();
+
+ if (result == SQLResultRow) {
+ usage = statement.getColumnInt64(0);
+ return true;
+ }
+
+ LOG_ERROR("Could not get the quota of an origin, error \"%s\"", m_database.lastErrorMsg());
+ return false;
+}
+
+bool ApplicationCacheStorage::remainingSizeForOriginExcludingCache(const SecurityOrigin* origin, ApplicationCache* cache, int64_t& remainingSize)
+{
+ openDatabase(false);
+ if (!m_database.isOpen())
+ return false;
+
+ // Remaining size = total origin quota - size of all caches with origin excluding the provided cache.
+ // Keep track of the number of caches so we can tell if the result was a calculation or not.
+ const char* query;
+ int64_t excludingCacheIdentifier = cache ? cache->storageID() : 0;
+ if (excludingCacheIdentifier != 0) {
+ query = "SELECT COUNT(Caches.size), Origins.quota - SUM(Caches.size)"
+ " FROM CacheGroups"
+ " INNER JOIN Origins ON CacheGroups.origin = Origins.origin"
+ " INNER JOIN Caches ON CacheGroups.id = Caches.cacheGroup"
+ " WHERE Origins.origin=?"
+ " AND Caches.id!=?";
+ } else {
+ query = "SELECT COUNT(Caches.size), Origins.quota - SUM(Caches.size)"
+ " FROM CacheGroups"
+ " INNER JOIN Origins ON CacheGroups.origin = Origins.origin"
+ " INNER JOIN Caches ON CacheGroups.id = Caches.cacheGroup"
+ " WHERE Origins.origin=?";
+ }
+
+ SQLiteStatement statement(m_database, query);
+ if (statement.prepare() != SQLResultOk)
+ return false;
+
+ statement.bindText(1, origin->databaseIdentifier());
+ if (excludingCacheIdentifier != 0)
+ statement.bindInt64(2, excludingCacheIdentifier);
+ int result = statement.step();
+
+ // If the count was 0 that then we have to query the origin table directly
+ // for its quota. Otherwise we can use the calculated value.
+ if (result == SQLResultRow) {
+ int64_t numberOfCaches = statement.getColumnInt64(0);
+ if (numberOfCaches == 0)
+ quotaForOrigin(origin, remainingSize);
+ else
+ remainingSize = statement.getColumnInt64(1);
+ return true;
+ }
+
+ LOG_ERROR("Could not get the remaining size of an origin's quota, error \"%s\"", m_database.lastErrorMsg());
+ return false;
+}
+
+bool ApplicationCacheStorage::storeUpdatedQuotaForOrigin(const SecurityOrigin* origin, int64_t quota)
+{
+ openDatabase(true);
+ if (!m_database.isOpen())
+ return false;
+
+ if (!ensureOriginRecord(origin))
+ return false;
+
+ SQLiteStatement updateStatement(m_database, "UPDATE Origins SET quota=? WHERE origin=?");
+ if (updateStatement.prepare() != SQLResultOk)
+ return false;
+
+ updateStatement.bindInt64(1, quota);
+ updateStatement.bindText(2, origin->databaseIdentifier());
+
+ return executeStatement(updateStatement);
+}
+
bool ApplicationCacheStorage::executeSQLCommand(const String& sql)
{
ASSERT(m_database.isOpen());
@@ -427,7 +547,10 @@ bool ApplicationCacheStorage::executeSQLCommand(const String& sql)
return result;
}
-static const int schemaVersion = 5;
+// Update the schemaVersion when the schema of any the Application Cache
+// SQLite tables changes. This allows the database to be rebuilt when
+// a new, incompatible change has been introduced to the database schema.
+static const int schemaVersion = 6;
void ApplicationCacheStorage::verifySchemaVersion()
{
@@ -476,7 +599,7 @@ void ApplicationCacheStorage::openDatabase(bool createIfDoesNotExist)
// Create tables
executeSQLCommand("CREATE TABLE IF NOT EXISTS CacheGroups (id INTEGER PRIMARY KEY AUTOINCREMENT, "
- "manifestHostHash INTEGER NOT NULL ON CONFLICT FAIL, manifestURL TEXT UNIQUE ON CONFLICT FAIL, newestCache INTEGER)");
+ "manifestHostHash INTEGER NOT NULL ON CONFLICT FAIL, manifestURL TEXT UNIQUE ON CONFLICT FAIL, newestCache INTEGER, origin TEXT)");
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)");
@@ -486,6 +609,7 @@ void ApplicationCacheStorage::openDatabase(bool createIfDoesNotExist)
executeSQLCommand("CREATE TABLE IF NOT EXISTS CacheResources (id INTEGER PRIMARY KEY AUTOINCREMENT, url TEXT NOT NULL ON CONFLICT FAIL, "
"statusCode INTEGER NOT NULL, responseURL TEXT NOT NULL, mimeType TEXT, textEncodingName TEXT, headers TEXT, data INTEGER NOT NULL ON CONFLICT FAIL)");
executeSQLCommand("CREATE TABLE IF NOT EXISTS CacheResourceData (id INTEGER PRIMARY KEY AUTOINCREMENT, data BLOB)");
+ executeSQLCommand("CREATE TABLE IF NOT EXISTS Origins (origin TEXT UNIQUE ON CONFLICT IGNORE, quota INTEGER NOT NULL ON CONFLICT FAIL)");
// When a cache is deleted, all its entries and its whitelist should be deleted.
executeSQLCommand("CREATE TRIGGER IF NOT EXISTS CacheDeleted AFTER DELETE ON Caches"
@@ -524,17 +648,23 @@ bool ApplicationCacheStorage::store(ApplicationCacheGroup* group, GroupStorageID
ASSERT(group->storageID() == 0);
ASSERT(journal);
- SQLiteStatement statement(m_database, "INSERT INTO CacheGroups (manifestHostHash, manifestURL) VALUES (?, ?)");
+ SQLiteStatement statement(m_database, "INSERT INTO CacheGroups (manifestHostHash, manifestURL, origin) VALUES (?, ?, ?)");
if (statement.prepare() != SQLResultOk)
return false;
statement.bindInt64(1, urlHostHash(group->manifestURL()));
statement.bindText(2, group->manifestURL());
+ statement.bindText(3, group->origin()->databaseIdentifier());
if (!executeStatement(statement))
return false;
- group->setStorageID(static_cast<unsigned>(m_database.lastInsertRowID()));
+ unsigned groupStorageID = static_cast<unsigned>(m_database.lastInsertRowID());
+
+ if (!ensureOriginRecord(group->origin()))
+ return false;
+
+ group->setStorageID(groupStorageID);
journal->add(group, 0);
return true;
}
@@ -626,7 +756,11 @@ bool ApplicationCacheStorage::store(ApplicationCacheResource* resource, unsigned
ASSERT(!resource->storageID());
openDatabase(true);
-
+
+ // openDatabase(true) could still fail, for example when cacheStorage is full or no longer available.
+ if (!m_database.isOpen())
+ return false;
+
// First, insert the data
SQLiteStatement dataStatement(m_database, "INSERT INTO CacheResourceData (data) VALUES (?)");
if (dataStatement.prepare() != SQLResultOk)
@@ -712,6 +846,9 @@ bool ApplicationCacheStorage::store(ApplicationCacheResource* resource, Applicat
ASSERT(cache->storageID());
openDatabase(true);
+
+ if (!m_database.isOpen())
+ return false;
m_isMaximumSizeReached = false;
m_database.setMaximumSize(m_maximumSize);
@@ -739,10 +876,27 @@ bool ApplicationCacheStorage::store(ApplicationCacheResource* resource, Applicat
return true;
}
-bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup* group)
+bool ApplicationCacheStorage::ensureOriginRecord(const SecurityOrigin* origin)
+{
+ SQLiteStatement insertOriginStatement(m_database, "INSERT INTO Origins (origin, quota) VALUES (?, ?)");
+ if (insertOriginStatement.prepare() != SQLResultOk)
+ return false;
+
+ insertOriginStatement.bindText(1, origin->databaseIdentifier());
+ insertOriginStatement.bindInt64(2, m_defaultOriginQuota);
+ if (!executeStatement(insertOriginStatement))
+ return false;
+
+ return true;
+}
+
+bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup* group, ApplicationCache* oldCache, FailureReason& failureReason)
{
openDatabase(true);
+ if (!m_database.isOpen())
+ return false;
+
m_isMaximumSizeReached = false;
m_database.setMaximumSize(m_maximumSize);
@@ -750,11 +904,21 @@ bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup* group)
storeCacheTransaction.begin();
+ // Check if this would reach the per-origin quota.
+ int64_t remainingSpaceInOrigin;
+ if (remainingSizeForOriginExcludingCache(group->origin(), oldCache, remainingSpaceInOrigin)) {
+ if (remainingSpaceInOrigin < group->newestCache()->estimatedSizeInStorage()) {
+ failureReason = OriginQuotaReached;
+ return false;
+ }
+ }
+
GroupStorageIDJournal groupStorageIDJournal;
if (!group->storageID()) {
// Store the group
if (!store(group, &groupStorageIDJournal)) {
checkForMaxSizeReached();
+ failureReason = isMaximumSizeReached() ? TotalQuotaReached : DiskOrOperationFailure;
return false;
}
}
@@ -771,20 +935,25 @@ bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup* group)
// Store the newest cache
if (!store(group->newestCache(), &resourceStorageIDJournal)) {
checkForMaxSizeReached();
+ failureReason = isMaximumSizeReached() ? TotalQuotaReached : DiskOrOperationFailure;
return false;
}
// Update the newest cache in the group.
SQLiteStatement statement(m_database, "UPDATE CacheGroups SET newestCache=? WHERE id=?");
- if (statement.prepare() != SQLResultOk)
+ if (statement.prepare() != SQLResultOk) {
+ failureReason = DiskOrOperationFailure;
return false;
+ }
statement.bindInt64(1, group->newestCache()->storageID());
statement.bindInt64(2, group->storageID());
- if (!executeStatement(statement))
+ if (!executeStatement(statement)) {
+ failureReason = DiskOrOperationFailure;
return false;
+ }
groupStorageIDJournal.commit();
resourceStorageIDJournal.commit();
@@ -792,10 +961,17 @@ bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup* group)
return true;
}
+bool ApplicationCacheStorage::storeNewestCache(ApplicationCacheGroup* group)
+{
+ // Ignore the reason for failing, just attempt the store.
+ FailureReason ignoredFailureReason;
+ return storeNewestCache(group, 0, ignoredFailureReason);
+}
+
static inline void parseHeader(const UChar* header, size_t headerLength, ResourceResponse& response)
{
- int pos = find(header, headerLength, ':');
- ASSERT(pos != -1);
+ size_t pos = find(header, headerLength, ':');
+ ASSERT(pos != notFound);
AtomicString headerName = AtomicString(header, pos);
String headerValue = String(header + pos + 1, headerLength - pos - 1);
@@ -805,9 +981,9 @@ static inline void parseHeader(const UChar* header, size_t headerLength, Resourc
static inline void parseHeaders(const String& headers, ResourceResponse& response)
{
- int startPos = 0;
- int endPos;
- while ((endPos = headers.find('\n', startPos)) != -1) {
+ unsigned startPos = 0;
+ size_t endPos;
+ while ((endPos = headers.find('\n', startPos)) != notFound) {
ASSERT(startPos != endPos);
parseHeader(headers.characters() + startPos, endPos - startPos, response);
@@ -815,7 +991,7 @@ static inline void parseHeaders(const String& headers, ResourceResponse& respons
startPos = endPos + 1;
}
- if (startPos != static_cast<int>(headers.length()))
+ if (startPos != headers.length())
parseHeader(headers.characters(), headers.length(), response);
}
@@ -955,9 +1131,10 @@ void ApplicationCacheStorage::empty()
if (!m_database.isOpen())
return;
- // Clear cache groups, caches and cache resources.
+ // Clear cache groups, caches, cache resources, and origins.
executeSQLCommand("DELETE FROM CacheGroups");
executeSQLCommand("DELETE FROM Caches");
+ executeSQLCommand("DELETE FROM Origins");
// Clear the storage IDs for the caches in memory.
// The caches will still work, but cached resources will not be saved to disk
@@ -990,7 +1167,7 @@ bool ApplicationCacheStorage::storeCopyOfCache(const String& cacheDirectory, App
}
// Now create a new cache group.
- OwnPtr<ApplicationCacheGroup> groupCopy(new ApplicationCacheGroup(cache->group()->manifestURL(), true));
+ OwnPtr<ApplicationCacheGroup> groupCopy(adoptPtr(new ApplicationCacheGroup(cache->group()->manifestURL(), true)));
groupCopy->setNewestCache(cacheCopy);
@@ -1111,8 +1288,9 @@ void ApplicationCacheStorage::checkForMaxSizeReached()
}
ApplicationCacheStorage::ApplicationCacheStorage()
- : m_maximumSize(INT_MAX)
+ : m_maximumSize(ApplicationCacheStorage::noQuota())
, m_isMaximumSizeReached(false)
+ , m_defaultOriginQuota(ApplicationCacheStorage::noQuota())
{
}
diff --git a/WebCore/loader/appcache/ApplicationCacheStorage.h b/WebCore/loader/appcache/ApplicationCacheStorage.h
index aaa5c9c..7db34e6 100644
--- a/WebCore/loader/appcache/ApplicationCacheStorage.h
+++ b/WebCore/loader/appcache/ApplicationCacheStorage.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008, 2010 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,22 +30,28 @@
#include "PlatformString.h"
#include "SQLiteDatabase.h"
-#include "StringHash.h"
-
#include <wtf/HashCountedSet.h>
+#include <wtf/text/StringHash.h>
namespace WebCore {
class ApplicationCache;
-class ApplicationCacheHost;
class ApplicationCacheGroup;
+class ApplicationCacheHost;
class ApplicationCacheResource;
class KURL;
template <class T>
class StorageIDJournal;
+class SecurityOrigin;
class ApplicationCacheStorage : public Noncopyable {
public:
+ enum FailureReason {
+ OriginQuotaReached,
+ TotalQuotaReached,
+ DiskOrOperationFailure
+ };
+
void setCacheDirectory(const String&);
const String& cacheDirectory() const;
@@ -54,6 +60,13 @@ public:
bool isMaximumSizeReached() const;
int64_t spaceNeeded(int64_t cacheToSave);
+ int64_t defaultOriginQuota() const { return m_defaultOriginQuota; }
+ void setDefaultOriginQuota(int64_t quota);
+ bool usageForOrigin(const SecurityOrigin*, int64_t& usage);
+ bool quotaForOrigin(const SecurityOrigin*, int64_t& quota);
+ bool remainingSizeForOriginExcludingCache(const SecurityOrigin*, ApplicationCache*, int64_t& remainingSize);
+ bool storeUpdatedQuotaForOrigin(const SecurityOrigin*, int64_t quota);
+
ApplicationCacheGroup* cacheGroupForURL(const KURL&); // Cache to load a main resource from.
ApplicationCacheGroup* fallbackCacheGroupForURL(const KURL&); // Cache that has a fallback entry to load a main resource from if normal loading fails.
@@ -61,6 +74,7 @@ public:
void cacheGroupDestroyed(ApplicationCacheGroup*);
void cacheGroupMadeObsolete(ApplicationCacheGroup*);
+ bool storeNewestCache(ApplicationCacheGroup*, ApplicationCache* oldCache, FailureReason& failureReason);
bool storeNewestCache(ApplicationCacheGroup*); // Updates the cache group, but doesn't remove old cache.
bool store(ApplicationCacheResource*, ApplicationCache*);
bool storeUpdatedType(ApplicationCacheResource*, ApplicationCache*);
@@ -76,6 +90,9 @@ public:
bool cacheGroupSize(const String& manifestURL, int64_t* size);
bool deleteCacheGroup(const String& manifestURL);
void vacuumDatabaseFile();
+
+ static int64_t unknownQuota() { return -1; }
+ static int64_t noQuota() { return std::numeric_limits<int64_t>::max(); }
private:
ApplicationCacheStorage();
PassRefPtr<ApplicationCache> loadCache(unsigned storageID);
@@ -88,6 +105,8 @@ private:
bool store(ApplicationCache*, ResourceStorageIDJournal*);
bool store(ApplicationCacheResource*, unsigned cacheStorageID);
+ bool ensureOriginRecord(const SecurityOrigin*);
+
void loadManifestHostHashes();
void verifySchemaVersion();
@@ -105,6 +124,8 @@ private:
int64_t m_maximumSize;
bool m_isMaximumSizeReached;
+ int64_t m_defaultOriginQuota;
+
SQLiteDatabase m_database;
// In order to quickly determine if a given resource exists in an application cache,
diff --git a/WebCore/loader/appcache/DOMApplicationCache.h b/WebCore/loader/appcache/DOMApplicationCache.h
index 077cae0..2a806fa 100644
--- a/WebCore/loader/appcache/DOMApplicationCache.h
+++ b/WebCore/loader/appcache/DOMApplicationCache.h
@@ -29,27 +29,27 @@
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
#include "ApplicationCacheHost.h"
-#include "AtomicStringHash.h"
#include "EventListener.h"
#include "EventNames.h"
#include "EventTarget.h"
+#include <wtf/Forward.h>
#include <wtf/HashMap.h>
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/Vector.h>
+#include <wtf/text/AtomicStringHash.h>
namespace WebCore {
-class AtomicStringImpl;
class Frame;
class KURL;
-class String;
class DOMApplicationCache : public RefCounted<DOMApplicationCache>, public EventTarget {
public:
static PassRefPtr<DOMApplicationCache> create(Frame* frame) { return adoptRef(new DOMApplicationCache(frame)); }
~DOMApplicationCache() { ASSERT(!m_frame); }
+ Frame* frame() const { return m_frame; }
void disconnectFrame();
unsigned short status() const;
diff --git a/WebCore/loader/appcache/DOMApplicationCache.idl b/WebCore/loader/appcache/DOMApplicationCache.idl
index 9c3a359..9113ffa 100644
--- a/WebCore/loader/appcache/DOMApplicationCache.idl
+++ b/WebCore/loader/appcache/DOMApplicationCache.idl
@@ -28,7 +28,8 @@ module offline {
interface [
Conditional=OFFLINE_WEB_APPLICATIONS,
EventTarget,
- OmitConstructor
+ OmitConstructor,
+ DontCheckEnums
] DOMApplicationCache {
// update status
const unsigned short UNCACHED = 0;
@@ -55,12 +56,12 @@ module offline {
attribute EventListener onobsolete;
// EventTarget interface
- [Custom] void addEventListener(in DOMString type,
- in EventListener listener,
- in boolean useCapture);
- [Custom] void removeEventListener(in DOMString type,
- in EventListener listener,
- in boolean useCapture);
+ void addEventListener(in DOMString type,
+ in EventListener listener,
+ in boolean useCapture);
+ void removeEventListener(in DOMString type,
+ in EventListener listener,
+ in boolean useCapture);
boolean dispatchEvent(in Event evt)
raises(EventException);
};
diff --git a/WebCore/loader/appcache/ManifestParser.cpp b/WebCore/loader/appcache/ManifestParser.cpp
index b001bff..f58a55d 100644
--- a/WebCore/loader/appcache/ManifestParser.cpp
+++ b/WebCore/loader/appcache/ManifestParser.cpp
@@ -127,6 +127,9 @@ bool parseManifest(const KURL& manifestURL, const char* data, int length, Manife
if (!equalIgnoringCase(url.protocol(), manifestURL.protocol()))
continue;
+ if (mode == Explicit && manifestURL.protocolIs("https") && !protocolHostAndPortAreEqual(manifestURL, url))
+ continue;
+
if (mode == Explicit)
manifest.explicitURLs.add(url.string());
else
diff --git a/WebCore/loader/archive/ArchiveFactory.cpp b/WebCore/loader/archive/ArchiveFactory.cpp
index d09b064..5d10415 100644
--- a/WebCore/loader/archive/ArchiveFactory.cpp
+++ b/WebCore/loader/archive/ArchiveFactory.cpp
@@ -34,6 +34,8 @@
#if PLATFORM(CF) && !PLATFORM(QT)
#include "LegacyWebArchive.h"
+#elif PLATFORM(ANDROID)
+#include "WebArchiveAndroid.h"
#endif
#include <wtf/HashMap.h>
@@ -62,6 +64,8 @@ static ArchiveMIMETypesMap& archiveMIMETypes()
#if PLATFORM(CF) && !PLATFORM(QT)
mimeTypes.set("application/x-webarchive", archiveFactoryCreate<LegacyWebArchive>);
+#elif PLATFORM(ANDROID)
+ mimeTypes.set("application/x-webarchive-xml", archiveFactoryCreate<WebArchiveAndroid>);
#endif
initialized = true;
diff --git a/WebCore/loader/archive/ArchiveFactory.h b/WebCore/loader/archive/ArchiveFactory.h
index bf1d5c6..c3b9464 100644
--- a/WebCore/loader/archive/ArchiveFactory.h
+++ b/WebCore/loader/archive/ArchiveFactory.h
@@ -31,12 +31,12 @@
#include "Archive.h"
+#include <wtf/Forward.h>
#include <wtf/PassRefPtr.h>
namespace WebCore {
class SharedBuffer;
-class String;
class ArchiveFactory {
public:
diff --git a/WebCore/loader/archive/ArchiveResource.cpp b/WebCore/loader/archive/ArchiveResource.cpp
index 691f66a..7dedc93 100644
--- a/WebCore/loader/archive/ArchiveResource.cpp
+++ b/WebCore/loader/archive/ArchiveResource.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2010 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -33,31 +33,8 @@
namespace WebCore {
-PassRefPtr<ArchiveResource> ArchiveResource::create(PassRefPtr<SharedBuffer> data, const KURL& url, const ResourceResponse& response)
-{
- return data ? adoptRef(new ArchiveResource(data, url, response)) : 0;
-}
-
-PassRefPtr<ArchiveResource> ArchiveResource::create(PassRefPtr<SharedBuffer> data, const KURL& url, const String& mimeType, const String& textEncoding, const String& frameName)
-{
- return data ? adoptRef(new ArchiveResource(data, url, mimeType, textEncoding, frameName)) : 0;
-}
-
-PassRefPtr<ArchiveResource> ArchiveResource::create(PassRefPtr<SharedBuffer> data, const KURL& url, const String& mimeType, const String& textEncoding, const String& frameName, const ResourceResponse& resourceResponse)
-{
- return data ? adoptRef(new ArchiveResource(data, url, mimeType, textEncoding, frameName, resourceResponse)) : 0;
-}
-
-ArchiveResource::ArchiveResource(PassRefPtr<SharedBuffer> data, const KURL& url, const ResourceResponse& response)
+inline ArchiveResource::ArchiveResource(PassRefPtr<SharedBuffer> data, const KURL& url, const String& mimeType, const String& textEncoding, const String& frameName, const ResourceResponse& response)
: SubstituteResource(url, response, data)
- , m_mimeType(response.mimeType())
- , m_textEncoding(response.textEncodingName())
- , m_shouldIgnoreWhenUnarchiving(false)
-{
-}
-
-ArchiveResource::ArchiveResource(PassRefPtr<SharedBuffer> data, const KURL& url, const String& mimeType, const String& textEncoding, const String& frameName)
- : SubstituteResource(url, ResourceResponse(url, mimeType, data ? data->size() : 0, textEncoding, String()), data)
, m_mimeType(mimeType)
, m_textEncoding(textEncoding)
, m_frameName(frameName)
@@ -65,13 +42,21 @@ ArchiveResource::ArchiveResource(PassRefPtr<SharedBuffer> data, const KURL& url,
{
}
-ArchiveResource::ArchiveResource(PassRefPtr<SharedBuffer> data, const KURL& url, const String& mimeType, const String& textEncoding, const String& frameName, const ResourceResponse& response)
- : SubstituteResource(url, response.isNull() ? ResourceResponse(url, mimeType, data ? data->size() : 0, textEncoding, String()) : response, data)
- , m_mimeType(mimeType)
- , m_textEncoding(textEncoding)
- , m_frameName(frameName)
- , m_shouldIgnoreWhenUnarchiving(false)
+PassRefPtr<ArchiveResource> ArchiveResource::create(PassRefPtr<SharedBuffer> data, const KURL& url, const String& mimeType, const String& textEncoding, const String& frameName, const ResourceResponse& response)
+{
+ if (!data)
+ return 0;
+ if (response.isNull()) {
+ unsigned dataSize = data->size();
+ return adoptRef(new ArchiveResource(data, url, mimeType, textEncoding, frameName,
+ ResourceResponse(url, mimeType, dataSize, textEncoding, String())));
+ }
+ return adoptRef(new ArchiveResource(data, url, mimeType, textEncoding, frameName, response));
+}
+
+PassRefPtr<ArchiveResource> ArchiveResource::create(PassRefPtr<SharedBuffer> data, const KURL& url, const ResourceResponse& response)
{
+ return create(data, url, response.mimeType(), response.textEncodingName(), String(), response);
}
}
diff --git a/WebCore/loader/archive/ArchiveResource.h b/WebCore/loader/archive/ArchiveResource.h
index d975e04..97d6e32 100644
--- a/WebCore/loader/archive/ArchiveResource.h
+++ b/WebCore/loader/archive/ArchiveResource.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2010 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -31,32 +31,29 @@
#include "SubstituteResource.h"
-#include "PlatformString.h"
-
namespace WebCore {
class ArchiveResource : public SubstituteResource {
public:
static PassRefPtr<ArchiveResource> create(PassRefPtr<SharedBuffer>, const KURL&, const ResourceResponse&);
- static PassRefPtr<ArchiveResource> create(PassRefPtr<SharedBuffer>, const KURL&, const String& mimeType, const String& textEncoding, const String& frameName);
- static PassRefPtr<ArchiveResource> create(PassRefPtr<SharedBuffer>, const KURL&, const String& mimeType, const String& textEncoding, const String& frameName, const ResourceResponse&);
-
+ static PassRefPtr<ArchiveResource> create(PassRefPtr<SharedBuffer>, const KURL&,
+ const String& mimeType, const String& textEncoding, const String& frameName,
+ const ResourceResponse& = ResourceResponse());
+
const String& mimeType() const { return m_mimeType; }
const String& textEncoding() const { return m_textEncoding; }
const String& frameName() const { return m_frameName; }
-
+
void ignoreWhenUnarchiving() { m_shouldIgnoreWhenUnarchiving = true; }
bool shouldIgnoreWhenUnarchiving() const { return m_shouldIgnoreWhenUnarchiving; }
private:
- ArchiveResource(PassRefPtr<SharedBuffer>, const KURL&, const ResourceResponse&);
- ArchiveResource(PassRefPtr<SharedBuffer>, const KURL&, const String& mimeType, const String& textEncoding, const String& frameName);
ArchiveResource(PassRefPtr<SharedBuffer>, const KURL&, const String& mimeType, const String& textEncoding, const String& frameName, const ResourceResponse&);
-
+
String m_mimeType;
String m_textEncoding;
String m_frameName;
-
+
bool m_shouldIgnoreWhenUnarchiving;
};
diff --git a/WebCore/loader/archive/android/WebArchiveAndroid.cpp b/WebCore/loader/archive/android/WebArchiveAndroid.cpp
new file mode 100644
index 0000000..49cfe9d
--- /dev/null
+++ b/WebCore/loader/archive/android/WebArchiveAndroid.cpp
@@ -0,0 +1,469 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "webarchive"
+
+#include "config.h"
+#include "WebArchiveAndroid.h"
+
+#include "Base64.h"
+#include <libxml/encoding.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xmlstring.h>
+#include <libxml/xmlwriter.h>
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+static const xmlChar* const archiveTag = BAD_CAST "Archive";
+static const xmlChar* const archiveResourceTag = BAD_CAST "ArchiveResource";
+static const xmlChar* const mainResourceTag = BAD_CAST "mainResource";
+static const xmlChar* const subresourcesTag = BAD_CAST "subresources";
+static const xmlChar* const subframesTag = BAD_CAST "subframes";
+static const xmlChar* const urlFieldTag = BAD_CAST "url";
+static const xmlChar* const mimeFieldTag = BAD_CAST "mimeType";
+static const xmlChar* const encodingFieldTag = BAD_CAST "textEncoding";
+static const xmlChar* const frameFieldTag = BAD_CAST "frameName";
+static const xmlChar* const dataFieldTag = BAD_CAST "data";
+
+PassRefPtr<WebArchiveAndroid> WebArchiveAndroid::create(PassRefPtr<ArchiveResource> mainResource,
+ Vector<PassRefPtr<ArchiveResource> >& subresources,
+ Vector<PassRefPtr<Archive> >& subframeArchives)
+{
+ if (mainResource)
+ return adoptRef(new WebArchiveAndroid(mainResource, subresources, subframeArchives));
+ return 0;
+}
+
+PassRefPtr<WebArchiveAndroid> WebArchiveAndroid::create(Frame* frame)
+{
+ PassRefPtr<ArchiveResource> mainResource = frame->loader()->documentLoader()->mainResource();
+ Vector<PassRefPtr<ArchiveResource> > subresources;
+ Vector<PassRefPtr<Archive> > subframes;
+ int children = frame->tree()->childCount();
+
+ frame->loader()->documentLoader()->getSubresources(subresources);
+
+ for (int child = 0; child < children; child++)
+ subframes.append(create(frame->tree()->child(child)));
+
+ return create(mainResource, subresources, subframes);
+}
+
+WebArchiveAndroid::WebArchiveAndroid(PassRefPtr<ArchiveResource> mainResource,
+ Vector<PassRefPtr<ArchiveResource> >& subresources,
+ Vector<PassRefPtr<Archive> >& subframeArchives)
+{
+ setMainResource(mainResource);
+
+ for (Vector<PassRefPtr<ArchiveResource> >::iterator subresourcesIterator = subresources.begin();
+ subresourcesIterator != subresources.end();
+ subresourcesIterator++) {
+ addSubresource(*subresourcesIterator);
+ }
+
+ for (Vector<PassRefPtr<Archive> >::iterator subframesIterator = subframeArchives.begin();
+ subframesIterator != subframeArchives.end();
+ subframesIterator++) {
+ addSubframeArchive(*subframesIterator);
+ }
+}
+
+static bool loadArchiveResourceField(xmlNodePtr resourceNode, const xmlChar* fieldName, Vector<char>* outputData)
+{
+ if (!outputData)
+ return false;
+
+ outputData->clear();
+
+ const char* base64Data = 0;
+
+ for (xmlNodePtr fieldNode = resourceNode->xmlChildrenNode;
+ fieldNode;
+ fieldNode = fieldNode->next) {
+ if (xmlStrEqual(fieldNode->name, fieldName)) {
+ base64Data = (const char*)xmlNodeGetContent(fieldNode->xmlChildrenNode);
+ if (!base64Data) {
+ /* Empty fields seem to break if they aren't null terminated. */
+ outputData->append('\0');
+ return true;
+ }
+ break;
+ }
+ }
+ if (!base64Data) {
+ LOGD("loadWebArchive: Failed to load field.");
+ return false;
+ }
+
+ const int base64Size = xmlStrlen(BAD_CAST base64Data);
+
+ const int result = base64Decode(base64Data, base64Size, *outputData);
+ if (!result) {
+ LOGD("loadWebArchive: Failed to decode field.");
+ return false;
+ }
+
+ return true;
+}
+
+static PassRefPtr<SharedBuffer> loadArchiveResourceFieldBuffer(xmlNodePtr resourceNode, const xmlChar* fieldName)
+{
+ Vector<char> fieldData;
+
+ if (loadArchiveResourceField(resourceNode, fieldName, &fieldData))
+ return SharedBuffer::create(fieldData.data(), fieldData.size());
+
+ return 0;
+}
+
+static String loadArchiveResourceFieldString(xmlNodePtr resourceNode, const xmlChar* fieldName)
+{
+ Vector<char> fieldData;
+
+ if (loadArchiveResourceField(resourceNode, fieldName, &fieldData))
+ return String::fromUTF8(fieldData.data(), fieldData.size());
+
+ return String();
+}
+
+static KURL loadArchiveResourceFieldURL(xmlNodePtr resourceNode, const xmlChar* fieldName)
+{
+ Vector<char> fieldData;
+
+ if (loadArchiveResourceField(resourceNode, fieldName, &fieldData))
+ return KURL(ParsedURLString, String::fromUTF8(fieldData.data(), fieldData.size()));
+
+ return KURL();
+}
+
+static PassRefPtr<ArchiveResource> loadArchiveResource(xmlNodePtr resourceNode)
+{
+ if (!xmlStrEqual(resourceNode->name, archiveResourceTag)) {
+ LOGD("loadWebArchive: Malformed resource.");
+ return 0;
+ }
+
+ KURL url = loadArchiveResourceFieldURL(resourceNode, urlFieldTag);
+ if (url.isNull()) {
+ LOGD("loadWebArchive: Failed to load resource.");
+ return 0;
+ }
+
+ String mimeType = loadArchiveResourceFieldString(resourceNode, mimeFieldTag);
+ if (mimeType.isNull()) {
+ LOGD("loadWebArchive: Failed to load resource.");
+ return 0;
+ }
+
+ String textEncoding = loadArchiveResourceFieldString(resourceNode, encodingFieldTag);
+ if (textEncoding.isNull()) {
+ LOGD("loadWebArchive: Failed to load resource.");
+ return 0;
+ }
+
+ String frameName = loadArchiveResourceFieldString(resourceNode, frameFieldTag);
+ if (frameName.isNull()) {
+ LOGD("loadWebArchive: Failed to load resource.");
+ return 0;
+ }
+
+ PassRefPtr<SharedBuffer> data = loadArchiveResourceFieldBuffer(resourceNode, dataFieldTag);
+ if (!data) {
+ LOGD("loadWebArchive: Failed to load resource.");
+ return 0;
+ }
+
+ return ArchiveResource::create(data, url, mimeType, textEncoding, frameName);
+}
+
+static PassRefPtr<WebArchiveAndroid> loadArchive(xmlNodePtr archiveNode)
+{
+ xmlNodePtr resourceNode = 0;
+
+ PassRefPtr<ArchiveResource> mainResource;
+ Vector<PassRefPtr<ArchiveResource> > subresources;
+ Vector<PassRefPtr<Archive> > subframes;
+
+ if (!xmlStrEqual(archiveNode->name, archiveTag)) {
+ LOGD("loadWebArchive: Malformed archive.");
+ return 0;
+ }
+
+ for (resourceNode = archiveNode->xmlChildrenNode;
+ resourceNode;
+ resourceNode = resourceNode->next) {
+ if (xmlStrEqual(resourceNode->name, mainResourceTag)) {
+ resourceNode = resourceNode->xmlChildrenNode;
+ if (!resourceNode)
+ break;
+ mainResource = loadArchiveResource(resourceNode);
+ break;
+ }
+ }
+ if (!mainResource) {
+ LOGD("saveWebArchive: Failed to load main resource.");
+ return 0;
+ }
+
+ for (resourceNode = archiveNode->xmlChildrenNode;
+ resourceNode;
+ resourceNode = resourceNode->next) {
+ if (xmlStrEqual(resourceNode->name, subresourcesTag)) {
+ for (resourceNode = resourceNode->xmlChildrenNode;
+ resourceNode;
+ resourceNode = resourceNode->next) {
+ PassRefPtr<ArchiveResource> subresource = loadArchiveResource(resourceNode);
+ if (!subresource) {
+ LOGD("saveWebArchive: Failed to load subresource.");
+ break;
+ }
+ subresources.append(subresource);
+ }
+ break;
+ }
+ }
+
+ for (resourceNode = archiveNode->xmlChildrenNode;
+ resourceNode;
+ resourceNode = resourceNode->next) {
+ if (xmlStrEqual(resourceNode->name, subframesTag)) {
+ for (resourceNode = resourceNode->xmlChildrenNode;
+ resourceNode;
+ resourceNode = resourceNode->next) {
+ PassRefPtr<WebArchiveAndroid> subframe = loadArchive(resourceNode);
+ if (!subframe) {
+ LOGD("saveWebArchive: Failed to load subframe.");
+ break;
+ }
+ subframes.append(subframe);
+ }
+ break;
+ }
+ }
+
+ return WebArchiveAndroid::create(mainResource, subresources, subframes);
+}
+
+static PassRefPtr<WebArchiveAndroid> createArchiveForError()
+{
+ /* When an archive cannot be loaded, we return an empty archive instead. */
+ PassRefPtr<ArchiveResource> mainResource = ArchiveResource::create(
+ SharedBuffer::create(), KURL(ParsedURLString, String::fromUTF8("file:///dummy")),
+ String::fromUTF8("text/plain"), String(""), String(""));
+ Vector<PassRefPtr<ArchiveResource> > subresources;
+ Vector<PassRefPtr<Archive> > subframes;
+
+ return WebArchiveAndroid::create(mainResource, subresources, subframes);
+}
+
+PassRefPtr<WebArchiveAndroid> WebArchiveAndroid::create(SharedBuffer* buffer)
+{
+ const char* const noBaseUrl = "";
+ const char* const defaultEncoding = 0;
+ const int noParserOptions = 0;
+
+ xmlDocPtr doc = xmlReadMemory(buffer->data(), buffer->size(), noBaseUrl, defaultEncoding, noParserOptions);
+ if (!doc) {
+ LOGD("loadWebArchive: Failed to parse document.");
+ return createArchiveForError();
+ }
+
+ xmlNodePtr root = xmlDocGetRootElement(doc);
+ if (!root) {
+ LOGD("loadWebArchive: Empty document.");
+ xmlFreeDoc(doc);
+ return createArchiveForError();
+ }
+
+ RefPtr<WebArchiveAndroid> archive = loadArchive(root);
+ if (!archive) {
+ LOGD("loadWebArchive: Failed to load archive.");
+ xmlFreeDoc(doc);
+ return createArchiveForError();
+ }
+
+ xmlFreeDoc(doc);
+ return archive.release();
+}
+
+static bool saveArchiveResourceField(xmlTextWriterPtr writer, const xmlChar* tag, const char* data, int size)
+{
+ int result = xmlTextWriterStartElement(writer, tag);
+ if (result < 0) {
+ LOGD("saveWebArchive: Failed to start element.");
+ return false;
+ }
+
+ if (size > 0) {
+ Vector<char> base64Data;
+ base64Encode(data, size, base64Data, false);
+ if (base64Data.isEmpty()) {
+ LOGD("saveWebArchive: Failed to base64 encode data.");
+ return false;
+ }
+
+ result = xmlTextWriterWriteRawLen(writer, BAD_CAST base64Data.data(), base64Data.size());
+ if (result < 0) {
+ LOGD("saveWebArchive: Failed to write data.");
+ return false;
+ }
+ }
+
+ result = xmlTextWriterEndElement(writer);
+ if (result < 0) {
+ LOGD("saveWebArchive: Failed to end element.");
+ return false;
+ }
+
+ return true;
+}
+
+static bool saveArchiveResourceField(xmlTextWriterPtr writer, const xmlChar* tag, SharedBuffer* buffer)
+{
+ return saveArchiveResourceField(writer, tag, buffer->data(), buffer->size());
+}
+
+static bool saveArchiveResourceField(xmlTextWriterPtr writer, const xmlChar* tag, const String& string)
+{
+ CString utf8String = string.utf8();
+
+ return saveArchiveResourceField(writer, tag, utf8String.data(), utf8String.length());
+}
+
+static bool saveArchiveResource(xmlTextWriterPtr writer, PassRefPtr<ArchiveResource> resource)
+{
+ int result = xmlTextWriterStartElement(writer, archiveResourceTag);
+ if (result < 0) {
+ LOGD("saveWebArchive: Failed to start element.");
+ return false;
+ }
+
+ if (!saveArchiveResourceField(writer, urlFieldTag, resource->url().string())
+ || !saveArchiveResourceField(writer, mimeFieldTag, resource->mimeType())
+ || !saveArchiveResourceField(writer, encodingFieldTag, resource->textEncoding())
+ || !saveArchiveResourceField(writer, frameFieldTag, resource->frameName())
+ || !saveArchiveResourceField(writer, dataFieldTag, resource->data()))
+ return false;
+
+ result = xmlTextWriterEndElement(writer);
+ if (result < 0) {
+ LOGD("saveWebArchive: Failed to end element.");
+ return false;
+ }
+
+ return true;
+}
+
+static bool saveArchive(xmlTextWriterPtr writer, PassRefPtr<Archive> archive)
+{
+ int result = xmlTextWriterStartElement(writer, archiveTag);
+ if (result < 0) {
+ LOGD("saveWebArchive: Failed to start element.");
+ return false;
+ }
+
+ result = xmlTextWriterStartElement(writer, mainResourceTag);
+ if (result < 0) {
+ LOGD("saveWebArchive: Failed to start element.");
+ return false;
+ }
+
+ if (!saveArchiveResource(writer, archive->mainResource()))
+ return false;
+
+ result = xmlTextWriterEndElement(writer);
+ if (result < 0) {
+ LOGD("saveWebArchive: Failed to end element.");
+ return false;
+ }
+
+ result = xmlTextWriterStartElement(writer, subresourcesTag);
+ if (result < 0) {
+ LOGD("saveWebArchive: Failed to start element.");
+ return false;
+ }
+
+ for (Vector<const RefPtr<ArchiveResource> >::iterator subresource = archive->subresources().begin();
+ subresource != archive->subresources().end();
+ subresource++) {
+ if (!saveArchiveResource(writer, *subresource))
+ return false;
+ }
+
+ result = xmlTextWriterEndElement(writer);
+ if (result < 0) {
+ LOGD("saveWebArchive: Failed to end element.");
+ return false;
+ }
+
+ result = xmlTextWriterStartElement(writer, subframesTag);
+ if (result < 0) {
+ LOGD("saveWebArchive: Failed to start element.");
+ return false;
+ }
+
+ for (Vector<const RefPtr<Archive> >::iterator subframe = archive->subframeArchives().begin();
+ subframe != archive->subframeArchives().end();
+ subframe++) {
+ if (!saveArchive(writer, *subframe))
+ return false;
+ }
+
+ result = xmlTextWriterEndElement(writer);
+ if (result < 0) {
+ LOGD("saveWebArchive: Failed to end element.");
+ return true;
+ }
+
+ return true;
+}
+
+bool WebArchiveAndroid::saveWebArchive(xmlTextWriterPtr writer)
+{
+ const char* const defaultXmlVersion = 0;
+ const char* const defaultEncoding = 0;
+ const char* const defaultStandalone = 0;
+
+ int result = xmlTextWriterStartDocument(writer, defaultXmlVersion, defaultEncoding, defaultStandalone);
+ if (result < 0) {
+ LOGD("saveWebArchive: Failed to start document.");
+ return false;
+ }
+
+ if (!saveArchive(writer, this))
+ return false;
+
+ result = xmlTextWriterEndDocument(writer);
+ if (result< 0) {
+ LOGD("saveWebArchive: Failed to end document.");
+ return false;
+ }
+
+ return true;
+}
+
+}
diff --git a/WebCore/loader/archive/android/WebArchiveAndroid.h b/WebCore/loader/archive/android/WebArchiveAndroid.h
new file mode 100644
index 0000000..1bbf952
--- /dev/null
+++ b/WebCore/loader/archive/android/WebArchiveAndroid.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WebArchiveAndroid_h
+#define WebArchiveAndroid_h
+
+#include "Archive.h"
+#include "DocumentLoader.h"
+#include "Frame.h"
+#include <libxml/xmlwriter.h>
+
+namespace WebCore {
+
+class WebArchiveAndroid : public Archive {
+public:
+ static PassRefPtr<WebArchiveAndroid> create(PassRefPtr<ArchiveResource> mainResource,
+ Vector<PassRefPtr<ArchiveResource> >& subresources,
+ Vector<PassRefPtr<Archive> >& subframeArchives);
+
+ static PassRefPtr<WebArchiveAndroid> create(Frame* frame);
+ static PassRefPtr<WebArchiveAndroid> create(SharedBuffer* buffer);
+
+ bool saveWebArchive(xmlTextWriterPtr writer);
+
+private:
+ WebArchiveAndroid(PassRefPtr<ArchiveResource> mainResource,
+ Vector<PassRefPtr<ArchiveResource> >& subresources,
+ Vector<PassRefPtr<Archive> >& subframeArchives);
+};
+
+}
+
+#endif // WEBARCHIVEANDROID_H
diff --git a/WebCore/loader/archive/cf/LegacyWebArchive.cpp b/WebCore/loader/archive/cf/LegacyWebArchive.cpp
index 3141e98..ddd564e 100644
--- a/WebCore/loader/archive/cf/LegacyWebArchive.cpp
+++ b/WebCore/loader/archive/cf/LegacyWebArchive.cpp
@@ -29,8 +29,7 @@
#include "config.h"
#include "LegacyWebArchive.h"
-#include "CString.h"
-#include "Cache.h"
+#include "MemoryCache.h"
#include "Document.h"
#include "DocumentLoader.h"
#include "Frame.h"
@@ -47,6 +46,8 @@
#include "Range.h"
#include "SelectionController.h"
#include "SharedBuffer.h"
+#include <wtf/text/CString.h>
+#include <wtf/text/StringConcatenate.h>
#include <wtf/ListHashSet.h>
#include <wtf/RetainPtr.h>
@@ -198,7 +199,7 @@ PassRefPtr<ArchiveResource> LegacyWebArchive::createResource(CFDictionaryRef dic
}
CFStringRef mimeType = static_cast<CFStringRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveResourceMIMETypeKey));
- if (mimeType && CFGetTypeID(mimeType) != CFStringGetTypeID()) {
+ if (!mimeType || CFGetTypeID(mimeType) != CFStringGetTypeID()) {
LOG(Archives, "LegacyWebArchive - MIME type is not of type CFString, cannot create invalid resource");
return 0;
}
@@ -233,7 +234,7 @@ PassRefPtr<ArchiveResource> LegacyWebArchive::createResource(CFDictionaryRef dic
response = createResourceResponseFromPropertyListData(resourceResponseData, resourceResponseVersion);
}
- return ArchiveResource::create(SharedBuffer::create(CFDataGetBytePtr(resourceData), CFDataGetLength(resourceData)), KURL(ParsedURLString, url), mimeType, textEncoding, frameName, response);
+ return ArchiveResource::create(SharedBuffer::wrapCFData(resourceData), KURL(KURL(), url), mimeType, textEncoding, frameName, response);
}
PassRefPtr<LegacyWebArchive> LegacyWebArchive::create()
@@ -491,7 +492,7 @@ PassRefPtr<LegacyWebArchive> LegacyWebArchive::create(const String& markupString
if (responseURL.isNull())
responseURL = KURL(ParsedURLString, "");
- PassRefPtr<ArchiveResource> mainResource = ArchiveResource::create(utf8Buffer(markupString), responseURL, response.mimeType(), "UTF-8", frame->tree()->name());
+ PassRefPtr<ArchiveResource> mainResource = ArchiveResource::create(utf8Buffer(markupString), responseURL, response.mimeType(), "UTF-8", frame->tree()->uniqueName());
Vector<PassRefPtr<LegacyWebArchive> > subframeArchives;
Vector<PassRefPtr<ArchiveResource> > subresources;
@@ -508,7 +509,7 @@ PassRefPtr<LegacyWebArchive> LegacyWebArchive::create(const String& markupString
if (subframeArchive)
subframeArchives.append(subframeArchive);
else
- LOG_ERROR("Unabled to archive subframe %s", childFrame->tree()->name().string().utf8().data());
+ LOG_ERROR("Unabled to archive subframe %s", childFrame->tree()->uniqueName().string().utf8().data());
} else {
ListHashSet<KURL> subresourceURLs;
node->getSubresourceURLs(subresourceURLs);
@@ -573,8 +574,8 @@ PassRefPtr<LegacyWebArchive> LegacyWebArchive::createFromSelection(Frame* frame)
// Wrap the frameset document in an iframe so it can be pasted into
// another document (which will have a body or frameset of its own).
- String iframeMarkup = String::format("<iframe frameborder=\"no\" marginwidth=\"0\" marginheight=\"0\" width=\"98%%\" height=\"98%%\" src=\"%s\"></iframe>",
- frame->loader()->documentLoader()->response().url().string().utf8().data());
+ String iframeMarkup = makeString("<iframe frameborder=\"no\" marginwidth=\"0\" marginheight=\"0\" width=\"98%%\" height=\"98%%\" src=\"",
+ frame->loader()->documentLoader()->response().url().string(), "\"></iframe>");
RefPtr<ArchiveResource> iframeResource = ArchiveResource::create(utf8Buffer(iframeMarkup), blankURL(), "text/html", "UTF-8", String());
Vector<PassRefPtr<ArchiveResource> > subresources;
diff --git a/WebCore/loader/archive/cf/LegacyWebArchiveMac.mm b/WebCore/loader/archive/cf/LegacyWebArchiveMac.mm
index c474bba..6a35753 100644
--- a/WebCore/loader/archive/cf/LegacyWebArchiveMac.mm
+++ b/WebCore/loader/archive/cf/LegacyWebArchiveMac.mm
@@ -31,7 +31,7 @@
namespace WebCore {
-static const NSString *LegacyWebArchiveResourceResponseKey = @"WebResourceResponse";
+static NSString * const LegacyWebArchiveResourceResponseKey = @"WebResourceResponse";
// FIXME: If is is possible to parse in a serialized NSURLResponse manually, without using
// NSKeyedUnarchiver, manipulating plists directly, we would prefer to do that instead.
diff --git a/WebCore/loader/CachePolicy.h b/WebCore/loader/cache/CachePolicy.h
index 2639caa..2639caa 100644
--- a/WebCore/loader/CachePolicy.h
+++ b/WebCore/loader/cache/CachePolicy.h
diff --git a/WebCore/loader/CachedCSSStyleSheet.cpp b/WebCore/loader/cache/CachedCSSStyleSheet.cpp
index b2e03b9..f0016d1 100644
--- a/WebCore/loader/CachedCSSStyleSheet.cpp
+++ b/WebCore/loader/cache/CachedCSSStyleSheet.cpp
@@ -27,10 +27,12 @@
#include "config.h"
#include "CachedCSSStyleSheet.h"
+#include "MemoryCache.h"
#include "CachedResourceClient.h"
#include "CachedResourceClientWalker.h"
#include "HTTPParsers.h"
#include "TextResourceDecoder.h"
+#include "SharedBuffer.h"
#include "loader.h"
#include <wtf/Vector.h>
@@ -51,13 +53,13 @@ CachedCSSStyleSheet::~CachedCSSStyleSheet()
void CachedCSSStyleSheet::didAddClient(CachedResourceClient *c)
{
- if (!m_loading)
+ if (!isLoading())
c->setCSSStyleSheet(m_url, m_response.url(), m_decoder->encoding().name(), this);
}
void CachedCSSStyleSheet::allClientsRemoved()
{
- if (isSafeToMakePurgeable())
+ if (!MemoryCache::shouldMakeResourcePurgeableOnEviction() && isSafeToMakePurgeable())
makePurgeable(true);
}
@@ -99,7 +101,7 @@ void CachedCSSStyleSheet::data(PassRefPtr<SharedBuffer> data, bool allDataReceiv
m_decodedSheetText = m_decoder->decode(m_data->data(), m_data->size());
m_decodedSheetText += m_decoder->flush();
}
- m_loading = false;
+ setLoading(false);
checkNotify();
// Clear the decoded text as it is unlikely to be needed immediately again and is cheap to regenerate.
m_decodedSheetText = String();
@@ -107,7 +109,7 @@ void CachedCSSStyleSheet::data(PassRefPtr<SharedBuffer> data, bool allDataReceiv
void CachedCSSStyleSheet::checkNotify()
{
- if (m_loading)
+ if (isLoading())
return;
CachedResourceClientWalker w(m_clients);
@@ -117,8 +119,8 @@ void CachedCSSStyleSheet::checkNotify()
void CachedCSSStyleSheet::error()
{
- m_loading = false;
- m_errorOccurred = true;
+ setLoading(false);
+ setErrorOccurred(true);
checkNotify();
}
diff --git a/WebCore/loader/CachedCSSStyleSheet.h b/WebCore/loader/cache/CachedCSSStyleSheet.h
index 908c4c0..abcdb85 100644
--- a/WebCore/loader/CachedCSSStyleSheet.h
+++ b/WebCore/loader/cache/CachedCSSStyleSheet.h
@@ -32,7 +32,7 @@
namespace WebCore {
- class DocLoader;
+ class CachedResourceLoader;
class TextResourceDecoder;
class CachedCSSStyleSheet : public CachedResource {
@@ -51,12 +51,11 @@ namespace WebCore {
virtual void data(PassRefPtr<SharedBuffer> data, bool allDataReceived);
virtual void error();
- virtual bool schedule() const { return true; }
-
void checkNotify();
private:
bool canUseSheet(bool enforceMIMEType, bool* hasValidMIMEType) const;
+ virtual PurgePriority purgePriority() const { return PurgeLast; }
protected:
RefPtr<TextResourceDecoder> m_decoder;
diff --git a/WebCore/loader/CachedFont.cpp b/WebCore/loader/cache/CachedFont.cpp
index 3d9eeb9..6297ad1 100644
--- a/WebCore/loader/CachedFont.cpp
+++ b/WebCore/loader/cache/CachedFont.cpp
@@ -27,22 +27,23 @@
#include "config.h"
#include "CachedFont.h"
-#if PLATFORM(CG) || PLATFORM(QT) || PLATFORM(GTK) || (PLATFORM(CHROMIUM) && (OS(WINDOWS) || OS(LINUX))) || PLATFORM(HAIKU) || OS(WINCE) || OS(ANDROID)
+#if PLATFORM(CG) || PLATFORM(QT) || PLATFORM(GTK) || (PLATFORM(CHROMIUM) && (OS(WINDOWS) || OS(LINUX) || OS(FREEBSD))) || PLATFORM(HAIKU) || OS(WINCE) || PLATFORM(ANDROID) || PLATFORM(BREWMP)
#define STORE_FONT_CUSTOM_PLATFORM_DATA
#endif
-#include "Cache.h"
+#include "MemoryCache.h"
#include "CachedResourceClient.h"
#include "CachedResourceClientWalker.h"
-#include "DOMImplementation.h"
#include "FontPlatformData.h"
-#ifdef STORE_FONT_CUSTOM_PLATFORM_DATA
-#include "FontCustomPlatformData.h"
-#endif
+#include "SharedBuffer.h"
#include "TextResourceDecoder.h"
#include "loader.h"
#include <wtf/Vector.h>
+#ifdef STORE_FONT_CUSTOM_PLATFORM_DATA
+#include "FontCustomPlatformData.h"
+#endif
+
#if ENABLE(SVG_FONTS)
#include "HTMLNames.h"
#include "NodeList.h"
@@ -70,15 +71,15 @@ CachedFont::~CachedFont()
#endif
}
-void CachedFont::load(DocLoader*)
+void CachedFont::load(CachedResourceLoader*)
{
// Don't load the file yet. Wait for an access before triggering the load.
- m_loading = true;
+ setLoading(true);
}
void CachedFont::didAddClient(CachedResourceClient* c)
{
- if (!m_loading)
+ if (!isLoading())
c->fontLoaded(this);
}
@@ -89,11 +90,11 @@ void CachedFont::data(PassRefPtr<SharedBuffer> data, bool allDataReceived)
m_data = data;
setEncodedSize(m_data.get() ? m_data->size() : 0);
- m_loading = false;
+ setLoading(false);
checkNotify();
}
-void CachedFont::beginLoadIfNeeded(DocLoader* dl)
+void CachedFont::beginLoadIfNeeded(CachedResourceLoader* dl)
{
if (!m_loadInitiated) {
m_loadInitiated = true;
@@ -107,16 +108,16 @@ bool CachedFont::ensureCustomFontData()
#if ENABLE(SVG_FONTS)
ASSERT(!m_isSVGFont);
#endif
- if (!m_fontData && !m_errorOccurred && !m_loading && m_data) {
+ if (!m_fontData && !errorOccurred() && !isLoading() && m_data) {
m_fontData = createFontCustomPlatformData(m_data.get());
if (!m_fontData)
- m_errorOccurred = true;
+ setErrorOccurred(true);
}
#endif
return m_fontData;
}
-FontPlatformData CachedFont::platformDataFromCustomData(float size, bool bold, bool italic, FontRenderingMode renderingMode)
+FontPlatformData CachedFont::platformDataFromCustomData(float size, bool bold, bool italic, FontOrientation orientation, FontRenderingMode renderingMode)
{
#if ENABLE(SVG_FONTS)
if (m_externalSVGDocument)
@@ -124,7 +125,7 @@ FontPlatformData CachedFont::platformDataFromCustomData(float size, bool bold, b
#endif
#ifdef STORE_FONT_CUSTOM_PLATFORM_DATA
ASSERT(m_fontData);
- return m_fontData->fontPlatformData(static_cast<int>(size), bold, italic, renderingMode);
+ return m_fontData->fontPlatformData(static_cast<int>(size), bold, italic, orientation, renderingMode);
#else
return FontPlatformData();
#endif
@@ -134,8 +135,8 @@ FontPlatformData CachedFont::platformDataFromCustomData(float size, bool bold, b
bool CachedFont::ensureSVGFontData()
{
ASSERT(m_isSVGFont);
- if (!m_externalSVGDocument && !m_errorOccurred && !m_loading && m_data) {
- m_externalSVGDocument = SVGDocument::create(0);
+ if (!m_externalSVGDocument && !errorOccurred() && !isLoading() && m_data) {
+ m_externalSVGDocument = SVGDocument::create(0, KURL());
m_externalSVGDocument->open();
RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("application/xml");
@@ -156,20 +157,28 @@ bool CachedFont::ensureSVGFontData()
SVGFontElement* CachedFont::getSVGFontById(const String& fontName) const
{
ASSERT(m_isSVGFont);
- RefPtr<NodeList> list = m_externalSVGDocument->getElementsByTagName(SVGNames::fontTag.localName());
+ RefPtr<NodeList> list = m_externalSVGDocument->getElementsByTagNameNS(SVGNames::fontTag.namespaceURI(), SVGNames::fontTag.localName());
if (!list)
return 0;
- unsigned fonts = list->length();
- for (unsigned i = 0; i < fonts; ++i) {
- Node* node = list->item(i);
- ASSERT(node);
+ unsigned listLength = list->length();
+ if (!listLength)
+ return 0;
+
+#ifndef NDEBUG
+ for (unsigned i = 0; i < listLength; ++i) {
+ ASSERT(list->item(i));
+ ASSERT(list->item(i)->hasTagName(SVGNames::fontTag));
+ }
+#endif
- if (static_cast<Element*>(node)->getAttribute(static_cast<Element*>(node)->idAttributeName()) != fontName)
- continue;
+ if (fontName.isEmpty())
+ return static_cast<SVGFontElement*>(list->item(0));
- ASSERT(node->hasTagName(SVGNames::fontTag));
- return static_cast<SVGFontElement*>(node);
+ for (unsigned i = 0; i < listLength; ++i) {
+ SVGFontElement* element = static_cast<SVGFontElement*>(list->item(i));
+ if (element->getIdAttribute() == fontName)
+ return element;
}
return 0;
@@ -188,7 +197,7 @@ void CachedFont::allClientsRemoved()
void CachedFont::checkNotify()
{
- if (m_loading)
+ if (isLoading())
return;
CachedResourceClientWalker w(m_clients);
@@ -199,8 +208,8 @@ void CachedFont::checkNotify()
void CachedFont::error()
{
- m_loading = false;
- m_errorOccurred = true;
+ setLoading(false);
+ setErrorOccurred(true);
checkNotify();
}
diff --git a/WebCore/loader/CachedFont.h b/WebCore/loader/cache/CachedFont.h
index 05b28f3..e1a34e8 100644
--- a/WebCore/loader/CachedFont.h
+++ b/WebCore/loader/cache/CachedFont.h
@@ -27,6 +27,7 @@
#define CachedFont_h
#include "CachedResource.h"
+#include "FontOrientation.h"
#include "FontRenderingMode.h"
#include <wtf/Vector.h>
@@ -37,8 +38,8 @@
namespace WebCore {
-class DocLoader;
-class Cache;
+class CachedResourceLoader;
+class MemoryCache;
class FontPlatformData;
class SVGFontElement;
@@ -49,7 +50,7 @@ public:
CachedFont(const String& url);
virtual ~CachedFont();
- virtual void load(DocLoader* docLoader);
+ virtual void load(CachedResourceLoader* cachedResourceLoader);
virtual void didAddClient(CachedResourceClient*);
virtual void data(PassRefPtr<SharedBuffer> data, bool allDataReceived);
@@ -57,14 +58,12 @@ public:
virtual void allClientsRemoved();
- virtual bool schedule() const { return true; }
-
void checkNotify();
- void beginLoadIfNeeded(DocLoader* dl);
+ void beginLoadIfNeeded(CachedResourceLoader* dl);
bool ensureCustomFontData();
- FontPlatformData platformDataFromCustomData(float size, bool bold, bool italic, FontRenderingMode = NormalRenderingMode);
+ FontPlatformData platformDataFromCustomData(float size, bool bold, bool italic, FontOrientation = Horizontal, FontRenderingMode = NormalRenderingMode);
#if ENABLE(SVG_FONTS)
bool isSVGFont() const { return m_isSVGFont; }
@@ -82,7 +81,7 @@ private:
RefPtr<SVGDocument> m_externalSVGDocument;
#endif
- friend class Cache;
+ friend class MemoryCache;
};
}
diff --git a/WebCore/loader/CachedImage.cpp b/WebCore/loader/cache/CachedImage.cpp
index dd93041..ce1c9a3 100644
--- a/WebCore/loader/CachedImage.cpp
+++ b/WebCore/loader/cache/CachedImage.cpp
@@ -25,15 +25,16 @@
#include "CachedImage.h"
#include "BitmapImage.h"
-#include "Cache.h"
+#include "MemoryCache.h"
#include "CachedResourceClient.h"
#include "CachedResourceClientWalker.h"
-#include "DocLoader.h"
+#include "CachedResourceLoader.h"
#include "Frame.h"
#include "FrameLoaderTypes.h"
#include "FrameView.h"
#include "Request.h"
#include "Settings.h"
+#include "SharedBuffer.h"
#include <wtf/CurrentTime.h>
#include <wtf/StdLibExtras.h>
#include <wtf/Vector.h>
@@ -56,7 +57,7 @@ CachedImage::CachedImage(const String& url)
, m_decodedDataDeletionTimer(this, &CachedImage::decodedDataDeletionTimerFired)
, m_httpStatusCodeErrorOccurred(false)
{
- m_status = Unknown;
+ setStatus(Unknown);
}
CachedImage::CachedImage(Image* image)
@@ -65,8 +66,8 @@ CachedImage::CachedImage(Image* image)
, m_decodedDataDeletionTimer(this, &CachedImage::decodedDataDeletionTimerFired)
, m_httpStatusCodeErrorOccurred(false)
{
- m_status = Cached;
- m_loading = false;
+ setStatus(Cached);
+ setLoading(false);
}
CachedImage::~CachedImage()
@@ -79,16 +80,16 @@ void CachedImage::decodedDataDeletionTimerFired(Timer<CachedImage>*)
destroyDecodedData();
}
-void CachedImage::load(DocLoader* docLoader)
+void CachedImage::load(CachedResourceLoader* cachedResourceLoader)
{
#ifdef ANDROID_BLOCK_NETWORK_IMAGE
- if (!docLoader || (docLoader->autoLoadImages() && !docLoader->shouldBlockNetworkImage(m_url)))
+ if (!cachedResourceLoader || (cachedResourceLoader->autoLoadImages() && !cachedResourceLoader->shouldBlockNetworkImage(m_url)))
#else
- if (!docLoader || docLoader->autoLoadImages())
+ if (!cachedResourceLoader || cachedResourceLoader->autoLoadImages())
#endif
- CachedResource::load(docLoader, true, DoSecurityCheck, true);
+ CachedResource::load(cachedResourceLoader, true, DoSecurityCheck, true);
else
- m_loading = false;
+ setLoading(false);
}
void CachedImage::didAddClient(CachedResourceClient* c)
@@ -96,7 +97,7 @@ void CachedImage::didAddClient(CachedResourceClient* c)
if (m_decodedDataDeletionTimer.isActive())
m_decodedDataDeletionTimer.stop();
- if (m_data && !m_image && !m_errorOccurred) {
+ if (m_data && !m_image && !errorOccurred()) {
createImage();
m_image->setData(m_data, true);
}
@@ -104,13 +105,13 @@ void CachedImage::didAddClient(CachedResourceClient* c)
if (m_image && !m_image->isNull())
c->imageChanged(this);
- if (!m_loading)
+ if (!isLoading())
c->notifyFinished(this);
}
void CachedImage::allClientsRemoved()
{
- if (m_image && !m_errorOccurred)
+ if (m_image && !errorOccurred())
m_image->resetAnimation();
if (double interval = cache()->deadDecodedDataDeletionInterval())
m_decodedDataDeletionTimer.startOneShot(interval);
@@ -132,7 +133,7 @@ Image* CachedImage::image() const
{
ASSERT(!isPurgeable());
- if (m_errorOccurred)
+ if (errorOccurred())
return brokenImage();
if (m_image)
@@ -240,7 +241,7 @@ inline void CachedImage::createImage()
// Create the image if it doesn't yet exist.
if (m_image)
return;
-#if PLATFORM(CG)
+#if PLATFORM(CG) && !USE(WEBKIT_IMAGE_DECODERS)
if (m_response.mimeType() == "application/pdf") {
m_image = PDFDocumentImage::create();
return;
@@ -260,7 +261,7 @@ inline void CachedImage::createImage()
size_t CachedImage::maximumDecodedImageSize()
{
- Frame* frame = m_request ? m_request->docLoader()->frame() : 0;
+ Frame* frame = m_request ? m_request->cachedResourceLoader()->frame() : 0;
if (!frame)
return 0;
Settings* settings = frame->settings();
@@ -304,7 +305,7 @@ void CachedImage::data(PassRefPtr<SharedBuffer> data, bool allDataReceived)
}
if (allDataReceived) {
- m_loading = false;
+ setLoading(false);
checkNotify();
}
}
@@ -312,16 +313,16 @@ void CachedImage::data(PassRefPtr<SharedBuffer> data, bool allDataReceived)
void CachedImage::error()
{
clear();
- m_errorOccurred = true;
+ setErrorOccurred(true);
m_data.clear();
notifyObservers();
- m_loading = false;
+ setLoading(false);
checkNotify();
}
void CachedImage::checkNotify()
{
- if (m_loading)
+ if (isLoading())
return;
CachedResourceClientWalker w(m_clients);
@@ -332,13 +333,14 @@ void CachedImage::checkNotify()
void CachedImage::destroyDecodedData()
{
bool canDeleteImage = !m_image || (m_image->hasOneRef() && m_image->isBitmapImage());
- if (isSafeToMakePurgeable() && canDeleteImage && !m_loading) {
+ if (isSafeToMakePurgeable() && canDeleteImage && !isLoading()) {
// Image refs the data buffer so we should not make it purgeable while the image is alive.
// Invoking addClient() will reconstruct the image object.
m_image = 0;
setDecodedSize(0);
- makePurgeable(true);
- } else if (m_image && !m_errorOccurred)
+ if (!MemoryCache::shouldMakeResourcePurgeableOnEviction())
+ makePurgeable(true);
+ } else if (m_image && !errorOccurred())
m_image->destroyDecodedData();
}
diff --git a/WebCore/loader/CachedImage.h b/WebCore/loader/cache/CachedImage.h
index 2aa35ac..313f3f3 100644
--- a/WebCore/loader/CachedImage.h
+++ b/WebCore/loader/cache/CachedImage.h
@@ -25,25 +25,24 @@
#include "CachedResource.h"
#include "ImageObserver.h"
-#include "Image.h"
#include "IntRect.h"
#include "Timer.h"
#include <wtf/Vector.h>
namespace WebCore {
-class DocLoader;
-class Cache;
+class CachedResourceLoader;
+class MemoryCache;
class CachedImage : public CachedResource, public ImageObserver {
- friend class Cache;
+ friend class MemoryCache;
public:
CachedImage(const String& url);
CachedImage(Image*);
virtual ~CachedImage();
- virtual void load(DocLoader* docLoader);
+ virtual void load(CachedResourceLoader* cachedResourceLoader);
Image* image() const;
@@ -71,15 +70,13 @@ public:
virtual void httpStatusCodeError() { m_httpStatusCodeErrorOccurred = true; }
bool httpStatusCodeErrorOccurred() const { return m_httpStatusCodeErrorOccurred; }
- virtual bool schedule() const { return true; }
-
void checkNotify();
virtual bool isImage() const { return true; }
void clear();
- bool stillNeedsLoad() const { return !m_errorOccurred && m_status == Unknown && m_loading == false; }
+ bool stillNeedsLoad() const { return !errorOccurred() && status() == Unknown && !isLoading(); }
void load();
// ImageObserver
@@ -96,6 +93,7 @@ private:
// If not null, changeRect is the changed part of the image.
void notifyObservers(const IntRect* changeRect = 0);
void decodedDataDeletionTimerFired(Timer<CachedImage>*);
+ virtual PurgePriority purgePriority() const { return PurgeFirst; }
RefPtr<Image> m_image;
Timer<CachedImage> m_decodedDataDeletionTimer;
diff --git a/WebCore/loader/CachedResource.cpp b/WebCore/loader/cache/CachedResource.cpp
index 640d1f7..c440ec9 100644
--- a/WebCore/loader/CachedResource.cpp
+++ b/WebCore/loader/cache/CachedResource.cpp
@@ -24,14 +24,20 @@
#include "config.h"
#include "CachedResource.h"
-#include "Cache.h"
+#include "MemoryCache.h"
+#include "CachedMetadata.h"
+#include "CachedResourceClient.h"
+#include "CachedResourceClientWalker.h"
#include "CachedResourceHandle.h"
-#include "DocLoader.h"
+#include "CachedResourceLoader.h"
#include "Frame.h"
-#include "FrameLoader.h"
+#include "FrameLoaderClient.h"
#include "KURL.h"
+#include "Logging.h"
#include "PurgeableBuffer.h"
#include "Request.h"
+#include "ResourceHandle.h"
+#include "SharedBuffer.h"
#include <wtf/CurrentTime.h>
#include <wtf/MathExtras.h>
#include <wtf/RefCountedLeakCounter.h>
@@ -48,43 +54,38 @@ static RefCountedLeakCounter cachedResourceLeakCounter("CachedResource");
CachedResource::CachedResource(const String& url, Type type)
: m_url(url)
+ , m_request(0)
, m_responseTimestamp(currentTime())
, m_lastDecodedAccessTime(0)
- , m_sendResourceLoadCallbacks(true)
+ , m_encodedSize(0)
+ , m_decodedSize(0)
+ , m_accessCount(0)
+ , m_handleCount(0)
, m_preloadCount(0)
, m_preloadResult(PreloadNotReferenced)
+ , m_inLiveDecodedResourcesList(false)
, m_requestedFromNetworkingLayer(false)
+ , m_sendResourceLoadCallbacks(true)
+ , m_errorOccurred(false)
, m_inCache(false)
, m_loading(false)
- , m_docLoader(0)
- , m_handleCount(0)
+ , m_type(type)
+ , m_status(Pending)
+#ifndef NDEBUG
+ , m_deleted(false)
+ , m_lruIndex(0)
+#endif
+ , m_nextInAllResourcesList(0)
+ , m_prevInAllResourcesList(0)
+ , m_nextInLiveResourcesList(0)
+ , m_prevInLiveResourcesList(0)
+ , m_cachedResourceLoader(0)
, m_resourceToRevalidate(0)
, m_proxyResource(0)
{
#ifndef NDEBUG
cachedResourceLeakCounter.increment();
#endif
-
- m_type = type;
- m_status = Pending;
- m_encodedSize = 0;
- m_decodedSize = 0;
- m_request = 0;
-
- m_accessCount = 0;
- m_inLiveDecodedResourcesList = false;
-
- m_nextInAllResourcesList = 0;
- m_prevInAllResourcesList = 0;
-
- m_nextInLiveResourcesList = 0;
- m_prevInLiveResourcesList = 0;
-
-#ifndef NDEBUG
- m_deleted = false;
- m_lruIndex = 0;
-#endif
- m_errorOccurred = false;
}
CachedResource::~CachedResource()
@@ -99,17 +100,27 @@ CachedResource::~CachedResource()
cachedResourceLeakCounter.decrement();
#endif
- if (m_docLoader)
- m_docLoader->removeCachedResource(this);
+ if (m_cachedResourceLoader)
+ m_cachedResourceLoader->removeCachedResource(this);
}
-
-void CachedResource::load(DocLoader* docLoader, bool incremental, SecurityCheckPolicy securityCheck, bool sendResourceLoadCallbacks)
+
+void CachedResource::load(CachedResourceLoader* cachedResourceLoader, bool incremental, SecurityCheckPolicy securityCheck, bool sendResourceLoadCallbacks)
{
m_sendResourceLoadCallbacks = sendResourceLoadCallbacks;
- cache()->loader()->load(docLoader, this, incremental, securityCheck, sendResourceLoadCallbacks);
+ cache()->loader()->load(cachedResourceLoader, this, incremental, securityCheck, sendResourceLoadCallbacks);
m_loading = true;
}
+void CachedResource::data(PassRefPtr<SharedBuffer>, bool allDataReceived)
+{
+ if (!allDataReceived)
+ return;
+
+ CachedResourceClientWalker w(m_clients);
+ while (CachedResourceClient* c = w.next())
+ c->notifyFinished(this);
+}
+
void CachedResource::finish()
{
m_status = Cached;
@@ -163,6 +174,34 @@ void CachedResource::setResponse(const ResourceResponse& response)
m_responseTimestamp = currentTime();
}
+void CachedResource::setSerializedCachedMetadata(const char* data, size_t size)
+{
+ // We only expect to receive cached metadata from the platform once.
+ // If this triggers, it indicates an efficiency problem which is most
+ // likely unexpected in code designed to improve performance.
+ ASSERT(!m_cachedMetadata);
+
+ m_cachedMetadata = CachedMetadata::deserialize(data, size);
+}
+
+void CachedResource::setCachedMetadata(unsigned dataTypeID, const char* data, size_t size)
+{
+ // Currently, only one type of cached metadata per resource is supported.
+ // If the need arises for multiple types of metadata per resource this could
+ // be enhanced to store types of metadata in a map.
+ ASSERT(!m_cachedMetadata);
+
+ m_cachedMetadata = CachedMetadata::create(dataTypeID, data, size);
+ ResourceHandle::cacheMetadata(m_response, m_cachedMetadata->serialize());
+}
+
+CachedMetadata* CachedResource::cachedMetadata(unsigned dataTypeID) const
+{
+ if (!m_cachedMetadata || m_cachedMetadata->dataTypeID() != dataTypeID)
+ return 0;
+ return m_cachedMetadata.get();
+}
+
void CachedResource::setRequest(Request* request)
{
if (request && !m_request)
@@ -178,6 +217,12 @@ void CachedResource::addClient(CachedResourceClient* client)
didAddClient(client);
}
+void CachedResource::didAddClient(CachedResourceClient* c)
+{
+ if (!isLoading())
+ c->notifyFinished(this);
+}
+
void CachedResource::addClientToSet(CachedResourceClient* client)
{
ASSERT(!isPurgeable());
@@ -306,6 +351,8 @@ void CachedResource::setResourceToRevalidate(CachedResource* resource)
ASSERT(m_handlesToRevalidate.isEmpty());
ASSERT(resource->type() == type());
+ LOG(ResourceLoading, "CachedResource %p setResourceToRevalidate %p", this, resource);
+
// 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.
@@ -334,6 +381,8 @@ void CachedResource::switchClientsToRevalidatedResource()
ASSERT(m_resourceToRevalidate->inCache());
ASSERT(!inCache());
+ LOG(ResourceLoading, "CachedResource %p switchClientsToRevalidatedResource %p", this, m_resourceToRevalidate);
+
HashSet<CachedResourceHandleBase*>::iterator end = m_handlesToRevalidate.end();
for (HashSet<CachedResourceHandleBase*>::iterator it = m_handlesToRevalidate.begin(); it != end; ++it) {
CachedResourceHandleBase* handle = *it;
@@ -383,7 +432,26 @@ void CachedResource::updateResponseAfterRevalidation(const ResourceResponse& val
m_response.setHTTPHeaderField(it->first, it->second);
}
}
-
+
+void CachedResource::registerHandle(CachedResourceHandleBase* h)
+{
+ ++m_handleCount;
+ if (m_resourceToRevalidate)
+ m_handlesToRevalidate.add(h);
+}
+
+void CachedResource::unregisterHandle(CachedResourceHandleBase* h)
+{
+ ASSERT(m_handleCount > 0);
+ --m_handleCount;
+
+ if (m_resourceToRevalidate)
+ m_handlesToRevalidate.remove(h);
+
+ if (!m_handleCount)
+ deleteIfPossible();
+}
+
bool CachedResource::canUseCacheValidator() const
{
if (m_loading || m_errorOccurred)
@@ -399,19 +467,33 @@ bool CachedResource::canUseCacheValidator() const
bool CachedResource::mustRevalidate(CachePolicy cachePolicy) const
{
- if (m_errorOccurred)
+ if (m_errorOccurred) {
+ LOG(ResourceLoading, "CachedResource %p mustRevalidate because of m_errorOccurred\n", this);
return true;
+ }
if (m_loading)
return false;
- if (m_response.cacheControlContainsNoCache() || m_response.cacheControlContainsNoStore())
+ if (m_response.cacheControlContainsNoCache() || m_response.cacheControlContainsNoStore()) {
+ LOG(ResourceLoading, "CachedResource %p mustRevalidate because of m_response.cacheControlContainsNoCache() || m_response.cacheControlContainsNoStore()\n", this);
return true;
+ }
+
+ if (cachePolicy == CachePolicyCache) {
+ if (m_response.cacheControlContainsMustRevalidate() && isExpired()) {
+ LOG(ResourceLoading, "CachedResource %p mustRevalidate because of cachePolicy == CachePolicyCache and m_response.cacheControlContainsMustRevalidate() && isExpired()\n", this);
+ return true;
+ }
+ return false;
+ }
- if (cachePolicy == CachePolicyCache)
- return m_response.cacheControlContainsMustRevalidate() && isExpired();
+ if (isExpired()) {
+ LOG(ResourceLoading, "CachedResource %p mustRevalidate because of isExpired()\n", this);
+ return true;
+ }
- return isExpired();
+ return false;
}
bool CachedResource::isSafeToMakePurgeable() const
@@ -435,17 +517,13 @@ bool CachedResource::makePurgeable(bool purgeable)
if (!m_data->hasOneRef())
return false;
- // Purgeable buffers are allocated in multiples of the page size (4KB in common CPUs) so it does not make sense for very small buffers.
- const size_t purgeableThreshold = 4 * 4096;
- if (m_data->size() < purgeableThreshold)
- return false;
-
if (m_data->hasPurgeableBuffer()) {
- m_purgeableData.set(m_data->releasePurgeableBuffer());
+ m_purgeableData = m_data->releasePurgeableBuffer();
} else {
- m_purgeableData.set(PurgeableBuffer::create(m_data->data(), m_data->size()));
+ m_purgeableData = PurgeableBuffer::create(m_data->data(), m_data->size());
if (!m_purgeableData)
return false;
+ m_purgeableData->setPurgePriority(purgePriority());
}
m_purgeableData->makePurgeable(true);
diff --git a/WebCore/loader/CachedResource.h b/WebCore/loader/cache/CachedResource.h
index 0f46a62..ba02459 100644
--- a/WebCore/loader/CachedResource.h
+++ b/WebCore/loader/cache/CachedResource.h
@@ -26,8 +26,8 @@
#include "CachePolicy.h"
#include "FrameLoaderTypes.h"
#include "PlatformString.h"
+#include "PurgePriority.h"
#include "ResourceResponse.h"
-#include "SharedBuffer.h"
#include <wtf/HashCountedSet.h>
#include <wtf/HashSet.h>
#include <wtf/OwnPtr.h>
@@ -36,19 +36,21 @@
namespace WebCore {
-class Cache;
+class MemoryCache;
+class CachedMetadata;
class CachedResourceClient;
class CachedResourceHandleBase;
-class DocLoader;
+class CachedResourceLoader;
+class Frame;
class InspectorResource;
-class Request;
class PurgeableBuffer;
+class Request;
// A resource that is held in the cache. Classes who want to use this object should derive
// from CachedResourceClient, to get the function calls in case the requested data has arrived.
// This class also does the actual communication with the loader to obtain the resource from the network.
class CachedResource : public Noncopyable {
- friend class Cache;
+ friend class MemoryCache;
friend class InspectorResource;
public:
@@ -60,15 +62,13 @@ public:
#if ENABLE(XSLT)
, XSLStyleSheet
#endif
-#if ENABLE(XBL)
- , XBL
+#if ENABLE(LINK_PREFETCH)
+ , LinkPrefetch
#endif
};
enum Status {
- NotCached, // this URL is not cached
Unknown, // let cache decide what to do with it
- New, // inserting new item
Pending, // only partially loaded
Cached // regular case
};
@@ -76,17 +76,17 @@ public:
CachedResource(const String& url, Type);
virtual ~CachedResource();
- virtual void load(DocLoader* docLoader) { load(docLoader, false, DoSecurityCheck, true); }
- void load(DocLoader*, bool incremental, SecurityCheckPolicy, bool sendResourceLoadCallbacks);
+ virtual void load(CachedResourceLoader* cachedResourceLoader) { load(cachedResourceLoader, false, DoSecurityCheck, true); }
+ void load(CachedResourceLoader*, bool incremental, SecurityCheckPolicy, bool sendResourceLoadCallbacks);
virtual void setEncoding(const String&) { }
virtual String encoding() const { return String(); }
- virtual void data(PassRefPtr<SharedBuffer> data, bool allDataReceived) = 0;
- virtual void error() = 0;
+ virtual void data(PassRefPtr<SharedBuffer> data, bool allDataReceived);
+ virtual void error() { }
virtual void httpStatusCodeError() { error(); } // Images keep loading in spite of HTTP errors (for legacy compat with <img>, etc.).
const String &url() const { return m_url; }
- Type type() const { return m_type; }
+ Type type() const { return static_cast<Type>(m_type); }
void addClient(CachedResourceClient*);
void removeClient(CachedResourceClient*);
@@ -99,25 +99,36 @@ public:
PreloadReferencedWhileLoading,
PreloadReferencedWhileComplete
};
- PreloadResult preloadResult() const { return m_preloadResult; }
+ PreloadResult preloadResult() const { return static_cast<PreloadResult>(m_preloadResult); }
void setRequestedFromNetworkingLayer() { m_requestedFromNetworkingLayer = true; }
- virtual void didAddClient(CachedResourceClient*) = 0;
+ virtual void didAddClient(CachedResourceClient*);
virtual void allClientsRemoved() { }
unsigned count() const { return m_clients.size(); }
- Status status() const { return m_status; }
+ Status status() const { return static_cast<Status>(m_status); }
+ void setStatus(Status status) { m_status = status; }
unsigned size() const { return encodedSize() + decodedSize() + overheadSize(); }
unsigned encodedSize() const { return m_encodedSize; }
unsigned decodedSize() const { return m_decodedSize; }
unsigned overheadSize() const;
- bool isLoaded() const { return !m_loading; }
+ bool isLoaded() const { return !m_loading; } // FIXME. Method name is inaccurate. Loading might not have started yet.
+
+ bool isLoading() const { return m_loading; }
void setLoading(bool b) { m_loading = b; }
virtual bool isImage() const { return false; }
+ bool isPrefetch() const
+ {
+#if ENABLE(LINK_PREFETCH)
+ return type() == LinkPrefetch;
+#else
+ return false;
+#endif
+ }
unsigned accessCount() const { return m_accessCount; }
void increaseAccessCount() { m_accessCount++; }
@@ -143,30 +154,41 @@ public:
void setResponse(const ResourceResponse&);
const ResourceResponse& response() const { return m_response; }
+ // Sets the serialized metadata retrieved from the platform's cache.
+ void setSerializedCachedMetadata(const char*, size_t);
+
+ // Caches the given metadata in association with this resource and suggests
+ // that the platform persist it. The dataTypeID is a pseudo-randomly chosen
+ // identifier that is used to distinguish data generated by the caller.
+ void setCachedMetadata(unsigned dataTypeID, const char*, size_t);
+
+ // Returns cached metadata of the given type associated with this resource.
+ CachedMetadata* cachedMetadata(unsigned dataTypeID) const;
+
bool canDelete() const { return !hasClients() && !m_request && !m_preloadCount && !m_handleCount && !m_resourceToRevalidate && !m_proxyResource; }
bool isExpired() const;
- virtual bool schedule() const { return false; }
-
// List of acceptable MIME types separated by ",".
// A MIME type may contain a wildcard, e.g. "text/*".
String accept() const { return m_accept; }
void setAccept(const String& accept) { m_accept = accept; }
bool errorOccurred() const { return m_errorOccurred; }
+ void setErrorOccurred(bool b) { m_errorOccurred = b; }
+
bool sendResourceLoadCallbacks() const { return m_sendResourceLoadCallbacks; }
virtual void destroyDecodedData() { }
- void setDocLoader(DocLoader* docLoader) { m_docLoader = docLoader; }
+ void setCachedResourceLoader(CachedResourceLoader* cachedResourceLoader) { m_cachedResourceLoader = cachedResourceLoader; }
bool isPreloaded() const { return m_preloadCount; }
void increasePreloadCount() { ++m_preloadCount; }
void decreasePreloadCount() { ASSERT(m_preloadCount); --m_preloadCount; }
- void registerHandle(CachedResourceHandleBase* h) { ++m_handleCount; if (m_resourceToRevalidate) m_handlesToRevalidate.add(h); }
- void unregisterHandle(CachedResourceHandleBase* h) { ASSERT(m_handleCount > 0); --m_handleCount; if (m_resourceToRevalidate) m_handlesToRevalidate.remove(h); if (!m_handleCount) deleteIfPossible(); }
+ void registerHandle(CachedResourceHandleBase* h);
+ void unregisterHandle(CachedResourceHandleBase* h);
bool canUseCacheValidator() const;
bool mustRevalidate(CachePolicy) const;
@@ -200,53 +222,55 @@ protected:
RefPtr<SharedBuffer> m_data;
OwnPtr<PurgeableBuffer> m_purgeableData;
- Type m_type;
- Status m_status;
-
- bool m_errorOccurred;
-
private:
void addClientToSet(CachedResourceClient*);
- // These are called by the friendly Cache only
+ // These are called by the friendly MemoryCache only
void setResourceToRevalidate(CachedResource*);
void switchClientsToRevalidatedResource();
void clearResourceToRevalidate();
void updateResponseAfterRevalidation(const ResourceResponse& validatingResponse);
+ virtual PurgePriority purgePriority() const { return PurgeDefault; }
double currentAge() const;
double freshnessLifetime() const;
+ RefPtr<CachedMetadata> m_cachedMetadata;
+
+ double m_lastDecodedAccessTime; // Used as a "thrash guard" in the cache
+
unsigned m_encodedSize;
unsigned m_decodedSize;
unsigned m_accessCount;
- unsigned m_inLiveDecodedResourcesList;
- double m_lastDecodedAccessTime; // Used as a "thrash guard" in the cache
-
- bool m_sendResourceLoadCallbacks;
-
+ unsigned m_handleCount;
unsigned m_preloadCount;
- PreloadResult m_preloadResult;
- bool m_requestedFromNetworkingLayer;
-protected:
- bool m_inCache;
- bool m_loading;
+ unsigned m_preloadResult : 2; // PreloadResult
+
+ bool m_inLiveDecodedResourcesList : 1;
+ bool m_requestedFromNetworkingLayer : 1;
+ bool m_sendResourceLoadCallbacks : 1;
+
+ bool m_errorOccurred : 1;
+ bool m_inCache : 1;
+ bool m_loading : 1;
+
+ unsigned m_type : 3; // Type
+ unsigned m_status : 2; // Status
+
#ifndef NDEBUG
bool m_deleted;
unsigned m_lruIndex;
#endif
-private:
CachedResource* m_nextInAllResourcesList;
CachedResource* m_prevInAllResourcesList;
CachedResource* m_nextInLiveResourcesList;
CachedResource* m_prevInLiveResourcesList;
- DocLoader* m_docLoader; // only non-0 for resources that are not in the cache
+ CachedResourceLoader* m_cachedResourceLoader; // only non-0 for resources that are not in the cache
- unsigned m_handleCount;
// If this field is non-null we are using the resource as a proxy for checking whether an existing resource is still up to date
// using HTTP If-Modified-Since/If-None-Match headers. If the response is 304 all clients of this resource are moved
// to to be clients of m_resourceToRevalidate and the resource is deleted. If not, the field is zeroed and this
diff --git a/WebCore/loader/CachedResourceClient.h b/WebCore/loader/cache/CachedResourceClient.h
index be3f87e..275d331 100644
--- a/WebCore/loader/CachedResourceClient.h
+++ b/WebCore/loader/cache/CachedResourceClient.h
@@ -26,12 +26,7 @@
#define CachedResourceClient_h
#include <wtf/FastAllocBase.h>
-
-#if ENABLE(XBL)
-namespace XBL {
- class XBLDocument;
-}
-#endif
+#include <wtf/Forward.h>
namespace WebCore {
@@ -39,7 +34,6 @@ namespace WebCore {
class CachedFont;
class CachedResource;
class CachedImage;
- class String;
class Image;
class IntRect;
class KURL;
@@ -68,13 +62,7 @@ namespace WebCore {
virtual void setCSSStyleSheet(const String& /* href */, const KURL& /* baseURL */, const String& /* charset */, const CachedCSSStyleSheet*) { }
virtual void setXSLStyleSheet(const String& /* href */, const KURL& /* baseURL */, const String& /* sheet */) { }
-
virtual void fontLoaded(CachedFont*) {};
-
-#if ENABLE(XBL)
- virtual void setXBLDocument(const String& /*URL*/, XBL::XBLDocument*) { }
-#endif
-
virtual void notifyFinished(CachedResource*) { }
};
diff --git a/WebCore/loader/CachedResourceClientWalker.cpp b/WebCore/loader/cache/CachedResourceClientWalker.cpp
index 142a2a1..142a2a1 100644
--- a/WebCore/loader/CachedResourceClientWalker.cpp
+++ b/WebCore/loader/cache/CachedResourceClientWalker.cpp
diff --git a/WebCore/loader/CachedResourceClientWalker.h b/WebCore/loader/cache/CachedResourceClientWalker.h
index d079584..d079584 100644
--- a/WebCore/loader/CachedResourceClientWalker.h
+++ b/WebCore/loader/cache/CachedResourceClientWalker.h
diff --git a/WebCore/loader/CachedResourceHandle.cpp b/WebCore/loader/cache/CachedResourceHandle.cpp
index 871292c..871292c 100644
--- a/WebCore/loader/CachedResourceHandle.cpp
+++ b/WebCore/loader/cache/CachedResourceHandle.cpp
diff --git a/WebCore/loader/CachedResourceHandle.h b/WebCore/loader/cache/CachedResourceHandle.h
index 7d485bf..7d485bf 100644
--- a/WebCore/loader/CachedResourceHandle.h
+++ b/WebCore/loader/cache/CachedResourceHandle.h
diff --git a/WebCore/loader/DocLoader.cpp b/WebCore/loader/cache/CachedResourceLoader.cpp
index 8c0a1b2..3cca206 100644
--- a/WebCore/loader/DocLoader.cpp
+++ b/WebCore/loader/cache/CachedResourceLoader.cpp
@@ -25,33 +25,34 @@
*/
#include "config.h"
-#include "DocLoader.h"
+#include "CachedResourceLoader.h"
-#include "Cache.h"
#include "CachedCSSStyleSheet.h"
#include "CachedFont.h"
#include "CachedImage.h"
#include "CachedScript.h"
#include "CachedXSLStyleSheet.h"
#include "Console.h"
-#include "CString.h"
-#include "Document.h"
#include "DOMWindow.h"
-#include "HTMLElement.h"
+#include "Document.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "FrameLoaderClient.h"
-#include "loader.h"
+#include "HTMLElement.h"
+#include "MemoryCache.h"
+#include "PingLoader.h"
#include "SecurityOrigin.h"
#include "Settings.h"
+#include "loader.h"
+#include <wtf/text/StringConcatenate.h>
#define PRELOAD_DEBUG 0
namespace WebCore {
-DocLoader::DocLoader(Document* doc)
+CachedResourceLoader::CachedResourceLoader(Document* document)
: m_cache(cache())
- , m_doc(doc)
+ , m_document(document)
, m_requestCount(0)
#ifdef ANDROID_BLOCK_NETWORK_IMAGE
, m_blockNetworkImage(false)
@@ -60,10 +61,10 @@ DocLoader::DocLoader(Document* doc)
, m_loadInProgress(false)
, m_allowStaleResources(false)
{
- m_cache->addDocLoader(this);
+ m_cache->addCachedResourceLoader(this);
}
-DocLoader::~DocLoader()
+CachedResourceLoader::~CachedResourceLoader()
{
if (m_requestCount)
m_cache->loader()->cancelRequests(this);
@@ -71,19 +72,19 @@ DocLoader::~DocLoader()
clearPreloads();
DocumentResourceMap::iterator end = m_documentResources.end();
for (DocumentResourceMap::iterator it = m_documentResources.begin(); it != end; ++it)
- it->second->setDocLoader(0);
- m_cache->removeDocLoader(this);
+ it->second->setCachedResourceLoader(0);
+ m_cache->removeCachedResourceLoader(this);
- // Make sure no requests still point to this DocLoader
+ // Make sure no requests still point to this CachedResourceLoader
ASSERT(m_requestCount == 0);
}
-Frame* DocLoader::frame() const
+Frame* CachedResourceLoader::frame() const
{
- return m_doc->frame();
+ return m_document->frame();
}
-void DocLoader::checkForReload(const KURL& fullURL)
+void CachedResourceLoader::checkForReload(const KURL& fullURL)
{
if (m_allowStaleResources)
return; // Don't reload resources while pasting
@@ -122,12 +123,19 @@ void DocLoader::checkForReload(const KURL& fullURL)
m_reloadedURLs.add(fullURL.string());
}
-CachedImage* DocLoader::requestImage(const String& url)
+CachedImage* CachedResourceLoader::requestImage(const String& url)
{
if (Frame* f = frame()) {
Settings* settings = f->settings();
if (!f->loader()->client()->allowImages(!settings || settings->areImagesEnabled()))
return 0;
+
+ if (f->loader()->pageDismissalEventBeingDispatched()) {
+ KURL completeURL = m_document->completeURL(url);
+ if (completeURL.isValid() && canRequest(CachedResource::ImageResource, completeURL))
+ PingLoader::loadImage(f, completeURL);
+ return 0;
+ }
}
CachedImage* resource = static_cast<CachedImage*>(requestResource(CachedResource::ImageResource, url, String()));
if (autoLoadImages() && resource && resource->stillNeedsLoad()) {
@@ -142,41 +150,42 @@ CachedImage* DocLoader::requestImage(const String& url)
return resource;
}
-CachedFont* DocLoader::requestFont(const String& url)
+CachedFont* CachedResourceLoader::requestFont(const String& url)
{
return static_cast<CachedFont*>(requestResource(CachedResource::FontResource, url, String()));
}
-CachedCSSStyleSheet* DocLoader::requestCSSStyleSheet(const String& url, const String& charset)
+CachedCSSStyleSheet* CachedResourceLoader::requestCSSStyleSheet(const String& url, const String& charset)
{
return static_cast<CachedCSSStyleSheet*>(requestResource(CachedResource::CSSStyleSheet, url, charset));
}
-CachedCSSStyleSheet* DocLoader::requestUserCSSStyleSheet(const String& url, const String& charset)
+CachedCSSStyleSheet* CachedResourceLoader::requestUserCSSStyleSheet(const String& url, const String& charset)
{
return cache()->requestUserCSSStyleSheet(this, url, charset);
}
-CachedScript* DocLoader::requestScript(const String& url, const String& charset)
+CachedScript* CachedResourceLoader::requestScript(const String& url, const String& charset)
{
return static_cast<CachedScript*>(requestResource(CachedResource::Script, url, charset));
}
#if ENABLE(XSLT)
-CachedXSLStyleSheet* DocLoader::requestXSLStyleSheet(const String& url)
+CachedXSLStyleSheet* CachedResourceLoader::requestXSLStyleSheet(const String& url)
{
return static_cast<CachedXSLStyleSheet*>(requestResource(CachedResource::XSLStyleSheet, url, String()));
}
#endif
-#if ENABLE(XBL)
-CachedXBLDocument* DocLoader::requestXBLDocument(const String& url)
+#if ENABLE(LINK_PREFETCH)
+CachedResource* CachedResourceLoader::requestLinkPrefetch(const String& url)
{
- return static_cast<CachedXSLStyleSheet*>(requestResource(CachedResource::XBL, url, String()));
+ ASSERT(frame());
+ return requestResource(CachedResource::LinkPrefetch, url, String());
}
#endif
-bool DocLoader::canRequest(CachedResource::Type type, const KURL& url)
+bool CachedResourceLoader::canRequest(CachedResource::Type type, const KURL& url)
{
// Some types of resources can be loaded only from the same origin. Other
// types of resources, like Images, Scripts, and CSS, can be loaded from
@@ -186,17 +195,15 @@ bool DocLoader::canRequest(CachedResource::Type type, const KURL& url)
case CachedResource::CSSStyleSheet:
case CachedResource::Script:
case CachedResource::FontResource:
+#if ENABLE(LINK_PREFETCH)
+ case CachedResource::LinkPrefetch:
+#endif
// These types of resources can be loaded from any origin.
// FIXME: Are we sure about CachedResource::FontResource?
break;
#if ENABLE(XSLT)
case CachedResource::XSLStyleSheet:
-#endif
-#if ENABLE(XBL)
- case CachedResource::XBL:
-#endif
-#if ENABLE(XSLT) || ENABLE(XBL)
- if (!m_doc->securityOrigin()->canRequest(url)) {
+ if (!m_document->securityOrigin()->canRequest(url)) {
printAccessDeniedMessage(url);
return false;
}
@@ -219,12 +226,9 @@ bool DocLoader::canRequest(CachedResource::Type type, const KURL& url)
#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);
+ f->loader()->checkIfRunInsecureContent(m_document->securityOrigin(), url);
break;
case CachedResource::ImageResource:
case CachedResource::CSSStyleSheet:
@@ -236,6 +240,11 @@ bool DocLoader::canRequest(CachedResource::Type type, const KURL& url)
}
break;
}
+#if ENABLE(LINK_PREFETCH)
+ case CachedResource::LinkPrefetch:
+ // Prefetch cannot affect the current document.
+ break;
+#endif
default:
ASSERT_NOT_REACHED();
break;
@@ -244,9 +253,9 @@ bool DocLoader::canRequest(CachedResource::Type type, const KURL& url)
return true;
}
-CachedResource* DocLoader::requestResource(CachedResource::Type type, const String& url, const String& charset, bool isPreload)
+CachedResource* CachedResourceLoader::requestResource(CachedResource::Type type, const String& url, const String& charset, bool isPreload)
{
- KURL fullURL = m_doc->completeURL(url);
+ KURL fullURL = m_document->completeURL(url);
if (!fullURL.isValid() || !canRequest(type, fullURL))
return 0;
@@ -255,7 +264,7 @@ CachedResource* DocLoader::requestResource(CachedResource::Type type, const Stri
DocumentResourceMap::iterator it = m_documentResources.find(fullURL.string());
if (it != m_documentResources.end()) {
- it->second->setDocLoader(0);
+ it->second->setCachedResourceLoader(0);
m_documentResources.remove(it);
}
}
@@ -275,7 +284,7 @@ CachedResource* DocLoader::requestResource(CachedResource::Type type, const Stri
return resource;
}
-void DocLoader::printAccessDeniedMessage(const KURL& url) const
+void CachedResourceLoader::printAccessDeniedMessage(const KURL& url) const
{
if (url.isNull())
return;
@@ -287,19 +296,15 @@ void DocLoader::printAccessDeniedMessage(const KURL& url) const
if (!settings || settings->privateBrowsingEnabled())
return;
- String message = m_doc->url().isNull() ?
- String::format("Unsafe attempt to load URL %s.",
- url.string().utf8().data()) :
- String::format("Unsafe attempt to load URL %s from frame with URL %s. "
- "Domains, protocols and ports must match.\n",
- url.string().utf8().data(),
- m_doc->url().string().utf8().data());
+ String message = m_document->url().isNull() ?
+ makeString("Unsafe attempt to load URL ", url.string(), '.') :
+ makeString("Unsafe attempt to load URL ", url.string(), " from frame with URL ", m_document->url().string(), ". Domains, protocols and ports must match.\n");
// FIXME: provide a real line number and source URL.
frame()->domWindow()->console()->addMessage(OtherMessageSource, LogMessageType, ErrorMessageLevel, message, 1, String());
}
-void DocLoader::setAutoLoadImages(bool enable)
+void CachedResourceLoader::setAutoLoadImages(bool enable)
{
if (enable == m_autoLoadImages)
return;
@@ -326,19 +331,19 @@ void DocLoader::setAutoLoadImages(bool enable)
}
#ifdef ANDROID_BLOCK_NETWORK_IMAGE
-bool DocLoader::shouldBlockNetworkImage(const String& url) const
+bool CachedResourceLoader::shouldBlockNetworkImage(const String& url) const
{
if (!m_blockNetworkImage)
return false;
- KURL kurl = m_doc->completeURL(url);
+ KURL kurl = m_document->completeURL(url);
if (kurl.protocolIs("http") || kurl.protocolIs("https"))
return true;
return false;
}
-void DocLoader::setBlockNetworkImage(bool block)
+void CachedResourceLoader::setBlockNetworkImage(bool block)
{
if (block == m_blockNetworkImage)
return;
@@ -360,12 +365,12 @@ void DocLoader::setBlockNetworkImage(bool block)
}
#endif
-CachePolicy DocLoader::cachePolicy() const
+CachePolicy CachedResourceLoader::cachePolicy() const
{
return frame() ? frame()->loader()->subresourceCachePolicy() : CachePolicyVerify;
}
-void DocLoader::removeCachedResource(CachedResource* resource) const
+void CachedResourceLoader::removeCachedResource(CachedResource* resource) const
{
#ifndef NDEBUG
DocumentResourceMap::iterator it = m_documentResources.find(resource->url());
@@ -375,54 +380,50 @@ void DocLoader::removeCachedResource(CachedResource* resource) const
m_documentResources.remove(resource->url());
}
-void DocLoader::setLoadInProgress(bool load)
+void CachedResourceLoader::setLoadInProgress(bool load)
{
m_loadInProgress = load;
if (!load && frame())
frame()->loader()->loadDone();
}
-void DocLoader::checkCacheObjectStatus(CachedResource* resource)
+void CachedResourceLoader::checkCacheObjectStatus(CachedResource* resource)
{
// Return from the function for objects that we didn't load from the cache or if we don't have a frame.
- if (!resource || !frame())
+ if (!resource || !frame() || resource->status() != CachedResource::Cached)
return;
- switch (resource->status()) {
- case CachedResource::Cached:
- break;
- case CachedResource::NotCached:
- case CachedResource::Unknown:
- case CachedResource::New:
- case CachedResource::Pending:
- return;
- }
-
// FIXME: If the WebKit client changes or cancels the request, WebCore does not respect this and continues the load.
frame()->loader()->loadedResourceFromMemoryCache(resource);
}
-void DocLoader::incrementRequestCount()
+void CachedResourceLoader::incrementRequestCount(const CachedResource* res)
{
+ if (res->isPrefetch())
+ return;
+
++m_requestCount;
}
-void DocLoader::decrementRequestCount()
+void CachedResourceLoader::decrementRequestCount(const CachedResource* res)
{
+ if (res->isPrefetch())
+ return;
+
--m_requestCount;
ASSERT(m_requestCount > -1);
}
-int DocLoader::requestCount()
+int CachedResourceLoader::requestCount()
{
if (loadInProgress())
return m_requestCount + 1;
return m_requestCount;
}
-void DocLoader::preload(CachedResource::Type type, const String& url, const String& charset, bool referencedFromBody)
+void CachedResourceLoader::preload(CachedResource::Type type, const String& url, const String& charset, bool referencedFromBody)
{
- bool hasRendering = m_doc->body() && m_doc->body()->renderer();
+ bool hasRendering = m_document->body() && m_document->body()->renderer();
if (!hasRendering && (referencedFromBody || type == CachedResource::ImageResource)) {
// Don't preload images or body resources before we have something to draw. This prevents
// preloads from body delaying first display when bandwidth is limited.
@@ -433,43 +434,50 @@ void DocLoader::preload(CachedResource::Type type, const String& url, const Stri
requestPreload(type, url, charset);
}
-void DocLoader::checkForPendingPreloads()
+void CachedResourceLoader::checkForPendingPreloads()
{
unsigned count = m_pendingPreloads.size();
- if (!count || !m_doc->body() || !m_doc->body()->renderer())
+ if (!count || !m_document->body() || !m_document->body()->renderer())
return;
for (unsigned i = 0; i < count; ++i) {
PendingPreload& preload = m_pendingPreloads[i];
// Don't request preload if the resource already loaded normally (this will result in double load if the page is being reloaded with cached results ignored).
- if (!cachedResource(m_doc->completeURL(preload.m_url)))
+ if (!cachedResource(m_document->completeURL(preload.m_url)))
requestPreload(preload.m_type, preload.m_url, preload.m_charset);
}
m_pendingPreloads.clear();
}
-void DocLoader::requestPreload(CachedResource::Type type, const String& url, const String& charset)
+void CachedResourceLoader::requestPreload(CachedResource::Type type, const String& url, const String& charset)
{
String encoding;
if (type == CachedResource::Script || type == CachedResource::CSSStyleSheet)
- encoding = charset.isEmpty() ? m_doc->frame()->loader()->encoding() : charset;
+ encoding = charset.isEmpty() ? m_document->frame()->loader()->writer()->encoding() : charset;
CachedResource* resource = requestResource(type, url, encoding, true);
- if (!resource || m_preloads.contains(resource))
+ if (!resource || (m_preloads && m_preloads->contains(resource)))
return;
resource->increasePreloadCount();
- m_preloads.add(resource);
+
+ if (!m_preloads)
+ m_preloads = adoptPtr(new ListHashSet<CachedResource*>);
+ m_preloads->add(resource);
+
#if PRELOAD_DEBUG
printf("PRELOADING %s\n", resource->url().latin1().data());
#endif
}
-void DocLoader::clearPreloads()
+void CachedResourceLoader::clearPreloads()
{
#if PRELOAD_DEBUG
printPreloadStats();
#endif
- ListHashSet<CachedResource*>::iterator end = m_preloads.end();
- for (ListHashSet<CachedResource*>::iterator it = m_preloads.begin(); it != end; ++it) {
+ if (!m_preloads)
+ return;
+
+ ListHashSet<CachedResource*>::iterator end = m_preloads->end();
+ for (ListHashSet<CachedResource*>::iterator it = m_preloads->begin(); it != end; ++it) {
CachedResource* res = *it;
res->decreasePreloadCount();
if (res->canDelete() && !res->inCache())
@@ -480,13 +488,13 @@ void DocLoader::clearPreloads()
m_preloads.clear();
}
-void DocLoader::clearPendingPreloads()
+void CachedResourceLoader::clearPendingPreloads()
{
m_pendingPreloads.clear();
}
#if PRELOAD_DEBUG
-void DocLoader::printPreloadStats()
+void CachedResourceLoader::printPreloadStats()
{
unsigned scripts = 0;
unsigned scriptMisses = 0;
diff --git a/WebCore/loader/DocLoader.h b/WebCore/loader/cache/CachedResourceLoader.h
index 06d8a47..eaed52e 100644
--- a/WebCore/loader/DocLoader.h
+++ b/WebCore/loader/cache/CachedResourceLoader.h
@@ -23,16 +23,16 @@
pages from the web. It has a memory cache for these objects.
*/
-#ifndef DocLoader_h
-#define DocLoader_h
+#ifndef CachedResourceLoader_h
+#define CachedResourceLoader_h
#include "CachedResource.h"
#include "CachedResourceHandle.h"
#include "CachePolicy.h"
-#include "StringHash.h"
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
#include <wtf/ListHashSet.h>
+#include <wtf/text/StringHash.h>
namespace WebCore {
@@ -46,15 +46,14 @@ class Frame;
class ImageLoader;
class KURL;
-// The DocLoader manages the loading of scripts/images/stylesheets for a single document.
-class DocLoader : public Noncopyable
-{
-friend class Cache;
+// The CachedResourceLoader manages the loading of scripts/images/stylesheets for a single document.
+class CachedResourceLoader : public Noncopyable {
+friend class MemoryCache;
friend class ImageLoader;
public:
- DocLoader(Document*);
- ~DocLoader();
+ CachedResourceLoader(Document*);
+ ~CachedResourceLoader();
CachedImage* requestImage(const String& url);
CachedCSSStyleSheet* requestCSSStyleSheet(const String& url, const String& charset);
@@ -65,8 +64,8 @@ public:
#if ENABLE(XSLT)
CachedXSLStyleSheet* requestXSLStyleSheet(const String& url);
#endif
-#if ENABLE(XBL)
- CachedXBLDocument* requestXBLDocument(const String &url);
+#if ENABLE(LINK_PREFETCH)
+ CachedResource* requestLinkPrefetch(const String &url);
#endif
// Logs an access denied message to the console for the specified URL.
@@ -89,7 +88,7 @@ public:
CachePolicy cachePolicy() const;
Frame* frame() const; // Can be NULL
- Document* doc() const { return m_doc; }
+ Document* document() const { return m_document; }
void removeCachedResource(CachedResource*) const;
@@ -98,8 +97,8 @@ public:
void setAllowStaleResources(bool allowStaleResources) { m_allowStaleResources = allowStaleResources; }
- void incrementRequestCount();
- void decrementRequestCount();
+ void incrementRequestCount(const CachedResource*);
+ void decrementRequestCount(const CachedResource*);
int requestCount();
void clearPreloads();
@@ -116,14 +115,14 @@ private:
void checkCacheObjectStatus(CachedResource*);
bool canRequest(CachedResource::Type, const KURL&);
- Cache* m_cache;
+ MemoryCache* m_cache;
HashSet<String> m_reloadedURLs;
mutable DocumentResourceMap m_documentResources;
- Document* m_doc;
+ Document* m_document;
int m_requestCount;
- ListHashSet<CachedResource*> m_preloads;
+ OwnPtr<ListHashSet<CachedResource*> > m_preloads;
struct PendingPreload {
CachedResource::Type m_type;
String m_url;
diff --git a/WebCore/loader/CachedScript.cpp b/WebCore/loader/cache/CachedScript.cpp
index 31483d6..50a8c17 100644
--- a/WebCore/loader/CachedScript.cpp
+++ b/WebCore/loader/cache/CachedScript.cpp
@@ -27,8 +27,10 @@
#include "config.h"
#include "CachedScript.h"
+#include "MemoryCache.h"
#include "CachedResourceClient.h"
#include "CachedResourceClientWalker.h"
+#include "SharedBuffer.h"
#include "TextResourceDecoder.h"
#include <wtf/Vector.h>
@@ -49,12 +51,6 @@ CachedScript::~CachedScript()
{
}
-void CachedScript::didAddClient(CachedResourceClient* c)
-{
- if (!m_loading)
- c->notifyFinished(this);
-}
-
void CachedScript::allClientsRemoved()
{
m_decodedDataDeletionTimer.startOneShot(0);
@@ -79,7 +75,6 @@ const String& CachedScript::script()
m_script += m_decoder->flush();
setDecodedSize(m_script.length() * sizeof(UChar));
}
-
m_decodedDataDeletionTimer.startOneShot(0);
return m_script;
}
@@ -91,13 +86,13 @@ void CachedScript::data(PassRefPtr<SharedBuffer> data, bool allDataReceived)
m_data = data;
setEncodedSize(m_data.get() ? m_data->size() : 0);
- m_loading = false;
+ setLoading(false);
checkNotify();
}
void CachedScript::checkNotify()
{
- if (m_loading)
+ if (isLoading())
return;
CachedResourceClientWalker w(m_clients);
@@ -107,8 +102,8 @@ void CachedScript::checkNotify()
void CachedScript::error()
{
- m_loading = false;
- m_errorOccurred = true;
+ setLoading(false);
+ setErrorOccurred(true);
checkNotify();
}
@@ -116,7 +111,7 @@ void CachedScript::destroyDecodedData()
{
m_script = String();
setDecodedSize(0);
- if (isSafeToMakePurgeable())
+ if (!MemoryCache::shouldMakeResourcePurgeableOnEviction() && isSafeToMakePurgeable())
makePurgeable(true);
}
diff --git a/WebCore/loader/CachedScript.h b/WebCore/loader/cache/CachedScript.h
index 13afa89..7311f9b 100644
--- a/WebCore/loader/CachedScript.h
+++ b/WebCore/loader/cache/CachedScript.h
@@ -31,7 +31,7 @@
namespace WebCore {
- class DocLoader;
+ class CachedResourceLoader;
class TextResourceDecoder;
class CachedScript : public CachedResource {
@@ -41,7 +41,6 @@ namespace WebCore {
const String& script();
- virtual void didAddClient(CachedResourceClient*);
virtual void allClientsRemoved();
virtual void setEncoding(const String&);
@@ -49,14 +48,13 @@ namespace WebCore {
virtual void data(PassRefPtr<SharedBuffer> data, bool allDataReceived);
virtual void error();
- virtual bool schedule() const { return false; }
-
void checkNotify();
virtual void destroyDecodedData();
private:
void decodedDataDeletionTimerFired(Timer<CachedScript>*);
+ virtual PurgePriority purgePriority() const { return PurgeLast; }
String m_script;
RefPtr<TextResourceDecoder> m_decoder;
diff --git a/WebCore/loader/CachedXSLStyleSheet.cpp b/WebCore/loader/cache/CachedXSLStyleSheet.cpp
index 59c3907..5b30e30 100644
--- a/WebCore/loader/CachedXSLStyleSheet.cpp
+++ b/WebCore/loader/cache/CachedXSLStyleSheet.cpp
@@ -29,6 +29,7 @@
#include "CachedResourceClient.h"
#include "CachedResourceClientWalker.h"
+#include "SharedBuffer.h"
#include "TextResourceDecoder.h"
#include <wtf/Vector.h>
@@ -47,7 +48,7 @@ CachedXSLStyleSheet::CachedXSLStyleSheet(const String &url)
void CachedXSLStyleSheet::didAddClient(CachedResourceClient* c)
{
- if (!m_loading)
+ if (!isLoading())
c->setXSLStyleSheet(m_url, m_response.url(), m_sheet);
}
@@ -72,13 +73,13 @@ void CachedXSLStyleSheet::data(PassRefPtr<SharedBuffer> data, bool allDataReceiv
m_sheet = String(m_decoder->decode(m_data->data(), encodedSize()));
m_sheet += m_decoder->flush();
}
- m_loading = false;
+ setLoading(false);
checkNotify();
}
void CachedXSLStyleSheet::checkNotify()
{
- if (m_loading)
+ if (isLoading())
return;
CachedResourceClientWalker w(m_clients);
@@ -88,8 +89,8 @@ void CachedXSLStyleSheet::checkNotify()
void CachedXSLStyleSheet::error()
{
- m_loading = false;
- m_errorOccurred = true;
+ setLoading(false);
+ setErrorOccurred(true);
checkNotify();
}
diff --git a/WebCore/loader/CachedXSLStyleSheet.h b/WebCore/loader/cache/CachedXSLStyleSheet.h
index b6b0585..8587b0b 100644
--- a/WebCore/loader/CachedXSLStyleSheet.h
+++ b/WebCore/loader/cache/CachedXSLStyleSheet.h
@@ -31,7 +31,7 @@
namespace WebCore {
- class DocLoader;
+ class CachedResourceLoader;
class TextResourceDecoder;
#if ENABLE(XSLT)
@@ -48,8 +48,6 @@ namespace WebCore {
virtual void data(PassRefPtr<SharedBuffer> data, bool allDataReceived);
virtual void error();
- virtual bool schedule() const { return true; }
-
void checkNotify();
protected:
diff --git a/WebCore/loader/Cache.cpp b/WebCore/loader/cache/MemoryCache.cpp
index fdd9b25..25af774 100644
--- a/WebCore/loader/Cache.cpp
+++ b/WebCore/loader/cache/MemoryCache.cpp
@@ -21,19 +21,20 @@
*/
#include "config.h"
-#include "Cache.h"
+#include "MemoryCache.h"
#include "CachedCSSStyleSheet.h"
#include "CachedFont.h"
#include "CachedImage.h"
#include "CachedScript.h"
#include "CachedXSLStyleSheet.h"
-#include "DocLoader.h"
+#include "CachedResourceLoader.h"
#include "Document.h"
#include "FrameLoader.h"
#include "FrameLoaderTypes.h"
#include "FrameView.h"
#include "Image.h"
+#include "Logging.h"
#include "ResourceHandle.h"
#include "SecurityOrigin.h"
#include <stdio.h>
@@ -48,13 +49,13 @@ static const double cMinDelayBeforeLiveDecodedPrune = 1; // Seconds.
static const float cTargetPrunePercentage = .95f; // Percentage of capacity toward which we prune, to avoid immediately pruning again.
static const double cDefaultDecodedDataDeletionInterval = 0;
-Cache* cache()
+MemoryCache* cache()
{
- static Cache* staticCache = new Cache;
+ static MemoryCache* staticCache = new MemoryCache;
return staticCache;
}
-Cache::Cache()
+MemoryCache::MemoryCache()
: m_disabled(false)
, m_pruneEnabled(true)
, m_inPruneDeadResources(false)
@@ -82,9 +83,9 @@ static CachedResource* createResource(CachedResource::Type type, const KURL& url
case CachedResource::XSLStyleSheet:
return new CachedXSLStyleSheet(url.string());
#endif
-#if ENABLE(XBL)
- case CachedResource::XBLStyleSheet:
- return new CachedXBLDocument(url.string());
+#if ENABLE(LINK_PREFETCH)
+ case CachedResource::LinkPrefetch:
+ return new CachedResource(url.string(), CachedResource::LinkPrefetch);
#endif
default:
break;
@@ -93,27 +94,32 @@ static CachedResource* createResource(CachedResource::Type type, const KURL& url
return 0;
}
-CachedResource* Cache::requestResource(DocLoader* docLoader, CachedResource::Type type, const KURL& url, const String& charset, bool requestIsPreload)
+CachedResource* MemoryCache::requestResource(CachedResourceLoader* cachedResourceLoader, CachedResource::Type type, const KURL& url, const String& charset, bool requestIsPreload)
{
+ LOG(ResourceLoading, "MemoryCache::requestResource '%s', charset '%s', preload=%u", url.string().latin1().data(), charset.latin1().data(), requestIsPreload);
+
// FIXME: Do we really need to special-case an empty URL?
// Would it be better to just go on with the cache code and let it fail later?
if (url.isEmpty())
return 0;
-
+
// Look up the resource in our map.
CachedResource* resource = resourceForURL(url.string());
-
- if (resource && requestIsPreload && !resource->isPreloaded())
+
+ if (resource && requestIsPreload && !resource->isPreloaded()) {
+ LOG(ResourceLoading, "MemoryCache::requestResource already has a preload request for this request, and it hasn't been preloaded yet");
return 0;
-
- if (SecurityOrigin::restrictAccessToLocal() && !SecurityOrigin::canLoad(url, String(), docLoader->doc())) {
- Document* doc = docLoader->doc();
- if (doc && !requestIsPreload)
- FrameLoader::reportLocalLoadFailed(doc->frame(), url.string());
+ }
+
+ if (!cachedResourceLoader->document()->securityOrigin()->canDisplay(url)) {
+ LOG(ResourceLoading, "...URL was not allowed by SecurityOrigin");
+ if (!requestIsPreload)
+ FrameLoader::reportLocalLoadFailed(cachedResourceLoader->document()->frame(), url.string());
return 0;
}
if (!resource) {
+ LOG(ResourceLoading, "CachedResource for '%s' wasn't found in cache. Creating it", url.string().latin1().data());
// The resource does not exist. Create it.
resource = createResource(type, url, charset);
ASSERT(resource);
@@ -122,7 +128,7 @@ CachedResource* Cache::requestResource(DocLoader* docLoader, CachedResource::Typ
// FIXME: CachedResource should just use normal refcounting instead.
resource->setInCache(true);
- resource->load(docLoader);
+ resource->load(cachedResourceLoader);
if (resource->errorOccurred()) {
// We don't support immediate loads, but we do support immediate failure.
@@ -138,22 +144,26 @@ CachedResource* Cache::requestResource(DocLoader* docLoader, CachedResource::Typ
else {
// Kick the resource out of the cache, because the cache is disabled.
resource->setInCache(false);
- resource->setDocLoader(docLoader);
+ resource->setCachedResourceLoader(cachedResourceLoader);
}
}
- if (resource->type() != type)
+ if (resource->type() != type) {
+ LOG(ResourceLoading, "MemoryCache::requestResource cannot use cached resource for '%s' due to type mismatch", url.string().latin1().data());
return 0;
+ }
if (!disabled()) {
// This will move the resource to the front of its LRU list and increase its access count.
resourceAccessed(resource);
}
+ LOG(ResourceLoading, "MemoryCache::requestResource for '%s' returning resource %p\n", url.string().latin1().data(), resource);
+
return resource;
}
-CachedCSSStyleSheet* Cache::requestUserCSSStyleSheet(DocLoader* docLoader, const String& url, const String& charset)
+CachedCSSStyleSheet* MemoryCache::requestUserCSSStyleSheet(CachedResourceLoader* cachedResourceLoader, const String& url, const String& charset)
{
CachedCSSStyleSheet* userSheet;
if (CachedResource* existing = resourceForURL(url)) {
@@ -167,7 +177,7 @@ CachedCSSStyleSheet* Cache::requestUserCSSStyleSheet(DocLoader* docLoader, const
// FIXME: CachedResource should just use normal refcounting instead.
userSheet->setInCache(true);
// Don't load incrementally, skip load checks, don't send resource load callbacks.
- userSheet->load(docLoader, false, SkipSecurityCheck, false);
+ userSheet->load(cachedResourceLoader, false, SkipSecurityCheck, false);
if (!disabled())
m_resources.set(url, userSheet);
else
@@ -182,7 +192,7 @@ CachedCSSStyleSheet* Cache::requestUserCSSStyleSheet(DocLoader* docLoader, const
return userSheet;
}
-void Cache::revalidateResource(CachedResource* resource, DocLoader* docLoader)
+void MemoryCache::revalidateResource(CachedResource* resource, CachedResourceLoader* cachedResourceLoader)
{
ASSERT(resource);
ASSERT(resource->inCache());
@@ -196,15 +206,16 @@ void Cache::revalidateResource(CachedResource* resource, DocLoader* docLoader)
}
const String& url = resource->url();
CachedResource* newResource = createResource(resource->type(), KURL(ParsedURLString, url), resource->encoding());
+ LOG(ResourceLoading, "Resource %p created to revalidate %p", newResource, resource);
newResource->setResourceToRevalidate(resource);
evict(resource);
m_resources.set(url, newResource);
newResource->setInCache(true);
resourceAccessed(newResource);
- newResource->load(docLoader);
+ newResource->load(cachedResourceLoader);
}
-void Cache::revalidationSucceeded(CachedResource* revalidatingResource, const ResourceResponse& response)
+void MemoryCache::revalidationSucceeded(CachedResource* revalidatingResource, const ResourceResponse& response)
{
CachedResource* resource = revalidatingResource->resourceToRevalidate();
ASSERT(resource);
@@ -230,24 +241,29 @@ void Cache::revalidationSucceeded(CachedResource* revalidatingResource, const Re
revalidatingResource->clearResourceToRevalidate();
}
-void Cache::revalidationFailed(CachedResource* revalidatingResource)
+void MemoryCache::revalidationFailed(CachedResource* revalidatingResource)
{
+ LOG(ResourceLoading, "Revalidation failed for %p", revalidatingResource);
ASSERT(revalidatingResource->resourceToRevalidate());
revalidatingResource->clearResourceToRevalidate();
}
-CachedResource* Cache::resourceForURL(const String& url)
+CachedResource* MemoryCache::resourceForURL(const String& url)
{
CachedResource* resource = m_resources.get(url);
+ bool wasPurgeable = MemoryCache::shouldMakeResourcePurgeableOnEviction() && resource && resource->isPurgeable();
if (resource && !resource->makePurgeable(false)) {
ASSERT(!resource->hasClients());
evict(resource);
return 0;
}
+ // Add the size back since we had subtracted it when we marked the memory as purgeable.
+ if (wasPurgeable)
+ adjustSize(resource->hasClients(), resource->size());
return resource;
}
-unsigned Cache::deadCapacity() const
+unsigned MemoryCache::deadCapacity() const
{
// Dead resource capacity is whatever space is not occupied by live resources, bounded by an independent minimum and maximum.
unsigned capacity = m_capacity - min(m_liveSize, m_capacity); // Start with available capacity.
@@ -256,13 +272,13 @@ unsigned Cache::deadCapacity() const
return capacity;
}
-unsigned Cache::liveCapacity() const
+unsigned MemoryCache::liveCapacity() const
{
// Live resource capacity is whatever is left over after calculating dead resource capacity.
return m_capacity - deadCapacity();
}
-void Cache::pruneLiveResources()
+void MemoryCache::pruneLiveResources()
{
if (!m_pruneEnabled)
return;
@@ -306,7 +322,7 @@ void Cache::pruneLiveResources()
}
}
-void Cache::pruneDeadResources()
+void MemoryCache::pruneDeadResources()
{
if (!m_pruneEnabled)
return;
@@ -364,7 +380,9 @@ void Cache::pruneDeadResources()
while (current) {
CachedResource* prev = current->m_prevInAllResourcesList;
if (!current->hasClients() && !current->isPreloaded() && !current->isCacheValidator()) {
- evict(current);
+ if (!makeResourcePurgeable(current))
+ evict(current);
+
// If evict() caused pruneDeadResources() to be re-entered, bail out. This can happen when removing an
// SVG CachedImage that has subresources.
if (!m_inPruneDeadResources)
@@ -388,7 +406,7 @@ void Cache::pruneDeadResources()
m_inPruneDeadResources = false;
}
-void Cache::setCapacities(unsigned minDeadBytes, unsigned maxDeadBytes, unsigned totalBytes)
+void MemoryCache::setCapacities(unsigned minDeadBytes, unsigned maxDeadBytes, unsigned totalBytes)
{
ASSERT(minDeadBytes <= maxDeadBytes);
ASSERT(maxDeadBytes <= totalBytes);
@@ -398,8 +416,31 @@ void Cache::setCapacities(unsigned minDeadBytes, unsigned maxDeadBytes, unsigned
prune();
}
-void Cache::evict(CachedResource* resource)
+bool MemoryCache::makeResourcePurgeable(CachedResource* resource)
{
+ if (!MemoryCache::shouldMakeResourcePurgeableOnEviction())
+ return false;
+
+ if (!resource->inCache())
+ return false;
+
+ if (resource->isPurgeable())
+ return true;
+
+ if (!resource->isSafeToMakePurgeable())
+ return false;
+
+ if (!resource->makePurgeable(true))
+ return false;
+
+ adjustSize(resource->hasClients(), -static_cast<int>(resource->size()));
+
+ return true;
+}
+
+void MemoryCache::evict(CachedResource* resource)
+{
+ LOG(ResourceLoading, "Evicting resource %p for '%s' from cache", resource, resource->url().latin1().data());
// The resource may have already been removed by someone other than our caller,
// who needed a fresh copy for a reload. See <http://bugs.webkit.org/show_bug.cgi?id=12479#c6>.
if (resource->inCache()) {
@@ -411,10 +452,11 @@ void Cache::evict(CachedResource* resource)
removeFromLRUList(resource);
removeFromLiveDecodedResourcesList(resource);
- // Subtract from our size totals.
- int delta = -static_cast<int>(resource->size());
- if (delta)
- adjustSize(resource->hasClients(), delta);
+ // If the resource was purged, it means we had already decremented the size when we made the
+ // resource purgeable in makeResourcePurgeable(). So adjust the size if we are evicting a
+ // resource that was not marked as purgeable.
+ if (!MemoryCache::shouldMakeResourcePurgeableOnEviction() || !resource->isPurgeable())
+ adjustSize(resource->hasClients(), -static_cast<int>(resource->size()));
} else
ASSERT(m_resources.get(resource->url()) != resource);
@@ -422,14 +464,14 @@ void Cache::evict(CachedResource* resource)
delete resource;
}
-void Cache::addDocLoader(DocLoader* docLoader)
+void MemoryCache::addCachedResourceLoader(CachedResourceLoader* cachedResourceLoader)
{
- m_docLoaders.add(docLoader);
+ m_cachedResourceLoaders.add(cachedResourceLoader);
}
-void Cache::removeDocLoader(DocLoader* docLoader)
+void MemoryCache::removeCachedResourceLoader(CachedResourceLoader* cachedResourceLoader)
{
- m_docLoaders.remove(docLoader);
+ m_cachedResourceLoaders.remove(cachedResourceLoader);
}
static inline unsigned fastLog2(unsigned i)
@@ -450,7 +492,7 @@ static inline unsigned fastLog2(unsigned i)
return log2;
}
-Cache::LRUList* Cache::lruListFor(CachedResource* resource)
+MemoryCache::LRUList* MemoryCache::lruListFor(CachedResource* resource)
{
unsigned accessCount = max(resource->accessCount(), 1U);
unsigned queueIndex = fastLog2(resource->size() / accessCount);
@@ -462,7 +504,7 @@ Cache::LRUList* Cache::lruListFor(CachedResource* resource)
return &m_allResources[queueIndex];
}
-void Cache::removeFromLRUList(CachedResource* resource)
+void MemoryCache::removeFromLRUList(CachedResource* resource)
{
// If we've never been accessed, then we're brand new and not in any list.
if (resource->accessCount() == 0)
@@ -509,7 +551,7 @@ void Cache::removeFromLRUList(CachedResource* resource)
list->m_head = next;
}
-void Cache::insertInLRUList(CachedResource* resource)
+void MemoryCache::insertInLRUList(CachedResource* resource)
{
// Make sure we aren't in some list already.
ASSERT(!resource->m_nextInAllResourcesList && !resource->m_prevInAllResourcesList);
@@ -541,7 +583,7 @@ void Cache::insertInLRUList(CachedResource* resource)
}
-void Cache::resourceAccessed(CachedResource* resource)
+void MemoryCache::resourceAccessed(CachedResource* resource)
{
ASSERT(resource->inCache());
@@ -560,7 +602,7 @@ void Cache::resourceAccessed(CachedResource* resource)
insertInLRUList(resource);
}
-void Cache::removeFromLiveDecodedResourcesList(CachedResource* resource)
+void MemoryCache::removeFromLiveDecodedResourcesList(CachedResource* resource)
{
// If we've never been accessed, then we're brand new and not in any list.
if (!resource->m_inLiveDecodedResourcesList)
@@ -599,7 +641,7 @@ void Cache::removeFromLiveDecodedResourcesList(CachedResource* resource)
m_liveDecodedResources.m_head = next;
}
-void Cache::insertInLiveDecodedResourcesList(CachedResource* resource)
+void MemoryCache::insertInLiveDecodedResourcesList(CachedResource* resource)
{
// Make sure we aren't in the list already.
ASSERT(!resource->m_nextInLiveResourcesList && !resource->m_prevInLiveResourcesList && !resource->m_inLiveDecodedResourcesList);
@@ -627,19 +669,19 @@ void Cache::insertInLiveDecodedResourcesList(CachedResource* resource)
}
-void Cache::addToLiveResourcesSize(CachedResource* resource)
+void MemoryCache::addToLiveResourcesSize(CachedResource* resource)
{
m_liveSize += resource->size();
m_deadSize -= resource->size();
}
-void Cache::removeFromLiveResourcesSize(CachedResource* resource)
+void MemoryCache::removeFromLiveResourcesSize(CachedResource* resource)
{
m_liveSize -= resource->size();
m_deadSize += resource->size();
}
-void Cache::adjustSize(bool live, int delta)
+void MemoryCache::adjustSize(bool live, int delta)
{
if (live) {
ASSERT(delta >= 0 || ((int)m_liveSize + delta >= 0));
@@ -650,7 +692,7 @@ void Cache::adjustSize(bool live, int delta)
}
}
-void Cache::TypeStatistic::addResource(CachedResource* o)
+void MemoryCache::TypeStatistic::addResource(CachedResource* o)
{
bool purged = o->wasPurged();
bool purgeable = o->isPurgeable() && !purged;
@@ -663,7 +705,7 @@ void Cache::TypeStatistic::addResource(CachedResource* o)
purgedSize += purged ? pageSize : 0;
}
-Cache::Statistics Cache::getStatistics()
+MemoryCache::Statistics MemoryCache::getStatistics()
{
Statistics stats;
CachedResourceMap::iterator e = m_resources.end();
@@ -687,11 +729,6 @@ Cache::Statistics Cache::getStatistics()
case CachedResource::FontResource:
stats.fonts.addResource(resource);
break;
-#if ENABLE(XBL)
- case CachedResource::XBL:
- stats.xblDocs.addResource(resource)
- break;
-#endif
default:
break;
}
@@ -699,7 +736,7 @@ Cache::Statistics Cache::getStatistics()
return stats;
}
-void Cache::setDisabled(bool disabled)
+void MemoryCache::setDisabled(bool disabled)
{
m_disabled = disabled;
if (!m_disabled)
@@ -714,24 +751,24 @@ void Cache::setDisabled(bool disabled)
}
#ifndef NDEBUG
-void Cache::dumpStats()
+void MemoryCache::dumpStats()
{
Statistics s = getStatistics();
- printf("%-11s %-11s %-11s %-11s %-11s %-11s %-11s\n", "", "Count", "Size", "LiveSize", "DecodedSize", "PurgeableSize", "PurgedSize");
- printf("%-11s %-11s %-11s %-11s %-11s %-11s %-11s\n", "-----------", "-----------", "-----------", "-----------", "-----------", "-----------", "-----------");
- printf("%-11s %11d %11d %11d %11d %11d %11d\n", "Images", s.images.count, s.images.size, s.images.liveSize, s.images.decodedSize, s.images.purgeableSize, s.images.purgedSize);
- printf("%-11s %11d %11d %11d %11d %11d %11d\n", "CSS", s.cssStyleSheets.count, s.cssStyleSheets.size, s.cssStyleSheets.liveSize, s.cssStyleSheets.decodedSize, s.cssStyleSheets.purgeableSize, s.cssStyleSheets.purgedSize);
+ printf("%-13s %-13s %-13s %-13s %-13s %-13s %-13s\n", "", "Count", "Size", "LiveSize", "DecodedSize", "PurgeableSize", "PurgedSize");
+ printf("%-13s %-13s %-13s %-13s %-13s %-13s %-13s\n", "-------------", "-------------", "-------------", "-------------", "-------------", "-------------", "-------------");
+ printf("%-13s %13d %13d %13d %13d %13d %13d\n", "Images", s.images.count, s.images.size, s.images.liveSize, s.images.decodedSize, s.images.purgeableSize, s.images.purgedSize);
+ printf("%-13s %13d %13d %13d %13d %13d %13d\n", "CSS", s.cssStyleSheets.count, s.cssStyleSheets.size, s.cssStyleSheets.liveSize, s.cssStyleSheets.decodedSize, s.cssStyleSheets.purgeableSize, s.cssStyleSheets.purgedSize);
#if ENABLE(XSLT)
- printf("%-11s %11d %11d %11d %11d %11d %11d\n", "XSL", s.xslStyleSheets.count, s.xslStyleSheets.size, s.xslStyleSheets.liveSize, s.xslStyleSheets.decodedSize, s.xslStyleSheets.purgeableSize, s.xslStyleSheets.purgedSize);
+ printf("%-13s %13d %13d %13d %13d %13d %13d\n", "XSL", s.xslStyleSheets.count, s.xslStyleSheets.size, s.xslStyleSheets.liveSize, s.xslStyleSheets.decodedSize, s.xslStyleSheets.purgeableSize, s.xslStyleSheets.purgedSize);
#endif
- printf("%-11s %11d %11d %11d %11d %11d %11d\n", "JavaScript", s.scripts.count, s.scripts.size, s.scripts.liveSize, s.scripts.decodedSize, s.scripts.purgeableSize, s.scripts.purgedSize);
- printf("%-11s %11d %11d %11d %11d %11d %11d\n", "Fonts", s.fonts.count, s.fonts.size, s.fonts.liveSize, s.fonts.decodedSize, s.fonts.purgeableSize, s.fonts.purgedSize);
- printf("%-11s %-11s %-11s %-11s %-11s %-11s %-11s\n\n", "-----------", "-----------", "-----------", "-----------", "-----------", "-----------", "-----------");
+ printf("%-13s %13d %13d %13d %13d %13d %13d\n", "JavaScript", s.scripts.count, s.scripts.size, s.scripts.liveSize, s.scripts.decodedSize, s.scripts.purgeableSize, s.scripts.purgedSize);
+ printf("%-13s %13d %13d %13d %13d %13d %13d\n", "Fonts", s.fonts.count, s.fonts.size, s.fonts.liveSize, s.fonts.decodedSize, s.fonts.purgeableSize, s.fonts.purgedSize);
+ printf("%-13s %-13s %-13s %-13s %-13s %-13s %-13s\n\n", "-------------", "-------------", "-------------", "-------------", "-------------", "-------------", "-------------");
}
-void Cache::dumpLRULists(bool includeLive) const
+void MemoryCache::dumpLRULists(bool includeLive) const
{
- printf("LRU-SP lists in eviction order (Kilobytes decoded, Kilobytes encoded, Access count, Referenced):\n");
+ printf("LRU-SP lists in eviction order (Kilobytes decoded, Kilobytes encoded, Access count, Referenced, isPurgeable, wasPurged):\n");
int size = m_allResources.size();
for (int i = size - 1; i >= 0; i--) {
@@ -740,7 +777,8 @@ void Cache::dumpLRULists(bool includeLive) const
while (current) {
CachedResource* prev = current->m_prevInAllResourcesList;
if (includeLive || !current->hasClients())
- printf("(%.1fK, %.1fK, %uA, %dR); ", current->decodedSize() / 1024.0f, (current->encodedSize() + current->overheadSize()) / 1024.0f, current->accessCount(), current->hasClients());
+ printf("(%.1fK, %.1fK, %uA, %dR, %d, %d); ", current->decodedSize() / 1024.0f, (current->encodedSize() + current->overheadSize()) / 1024.0f, current->accessCount(), current->hasClients(), current->isPurgeable(), current->wasPurged());
+
current = prev;
}
}
diff --git a/WebCore/loader/Cache.h b/WebCore/loader/cache/MemoryCache.h
index 0a5b74d..a40f85e 100644
--- a/WebCore/loader/Cache.h
+++ b/WebCore/loader/cache/MemoryCache.h
@@ -28,18 +28,18 @@
#include "CachePolicy.h"
#include "CachedResource.h"
#include "PlatformString.h"
-#include "StringHash.h"
#include "loader.h"
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
#include <wtf/Noncopyable.h>
#include <wtf/Vector.h>
+#include <wtf/text/StringHash.h>
namespace WebCore {
class CachedCSSStyleSheet;
class CachedResource;
-class DocLoader;
+class CachedResourceLoader;
class KURL;
// This cache holds subresources used by Web pages: images, scripts, stylesheets, etc.
@@ -55,9 +55,25 @@ class KURL;
// -------|-----+++++++++++++++|
// -------|-----+++++++++++++++|+++++
-class Cache : public Noncopyable {
+// The behavior of the cache changes in the following way if shouldMakeResourcePurgeableOnEviction
+// returns true.
+//
+// 1. Dead resources in the cache are kept in non-purgeable memory.
+// 2. When we prune dead resources, instead of freeing them, we mark their memory as purgeable and
+// keep the resources until the kernel reclaims the purgeable memory.
+//
+// By leaving the in-cache dead resources in dirty resident memory, we decrease the likelihood of
+// the kernel claiming that memory and forcing us to refetch the resource (for example when a user
+// presses back).
+//
+// And by having an unbounded number of resource objects using purgeable memory, we can use as much
+// memory as is available on the machine. The trade-off here is that the CachedResource object (and
+// its member variables) are allocated in non-purgeable TC-malloc'd memory so we would see slightly
+// more memory use due to this.
+
+class MemoryCache : public Noncopyable {
public:
- friend Cache* cache();
+ friend MemoryCache* cache();
typedef HashMap<String, CachedResource*> CachedResourceMap;
@@ -85,9 +101,6 @@ public:
#if ENABLE(XSLT)
TypeStatistic xslStyleSheets;
#endif
-#if ENABLE(XBL)
- TypeStatistic xblDocs;
-#endif
TypeStatistic fonts;
};
@@ -96,11 +109,11 @@ public:
// Request resources from the cache. A load will be initiated and a cache object created if the object is not
// found in the cache.
- CachedResource* requestResource(DocLoader*, CachedResource::Type, const KURL& url, const String& charset, bool isPreload = false);
+ CachedResource* requestResource(CachedResourceLoader*, CachedResource::Type, const KURL& url, const String& charset, bool isPreload = false);
- CachedCSSStyleSheet* requestUserCSSStyleSheet(DocLoader*, const String& url, const String& charset);
+ CachedCSSStyleSheet* requestUserCSSStyleSheet(CachedResourceLoader*, const String& url, const String& charset);
- void revalidateResource(CachedResource*, DocLoader*);
+ void revalidateResource(CachedResource*, CachedResourceLoader*);
void revalidationSucceeded(CachedResource* revalidatingResource, const ResourceResponse&);
void revalidationFailed(CachedResource* revalidatingResource);
@@ -132,8 +145,8 @@ public:
// Remove an existing cache entry from both the resource map and from the LRU list.
void remove(CachedResource* resource) { evict(resource); }
- void addDocLoader(DocLoader*);
- void removeDocLoader(DocLoader*);
+ void addCachedResourceLoader(CachedResourceLoader*);
+ void removeCachedResourceLoader(CachedResourceLoader*);
CachedResource* resourceForURL(const String&);
@@ -151,6 +164,8 @@ public:
void addToLiveResourcesSize(CachedResource*);
void removeFromLiveResourcesSize(CachedResource*);
+ static bool shouldMakeResourcePurgeableOnEviction();
+
// Function to collect cache statistics for the caches window in the Safari Debug menu.
Statistics getStatistics();
@@ -160,8 +175,8 @@ public:
#endif
private:
- Cache();
- ~Cache(); // Not implemented to make sure nobody accidentally calls delete -- WebCore does not delete singletons.
+ MemoryCache();
+ ~MemoryCache(); // Not implemented to make sure nobody accidentally calls delete -- WebCore does not delete singletons.
LRUList* lruListFor(CachedResource*);
void resourceAccessed(CachedResource*);
@@ -176,10 +191,11 @@ private:
void pruneDeadResources(); // Flush decoded and encoded data from resources not referenced by Web pages.
void pruneLiveResources(); // Flush decoded data from resources still referenced by Web pages.
+ bool makeResourcePurgeable(CachedResource*);
void evict(CachedResource*);
// Member variables.
- HashSet<DocLoader*> m_docLoaders;
+ HashSet<CachedResourceLoader*> m_cachedResourceLoaders;
Loader m_loader;
bool m_disabled; // Whether or not the cache is enabled.
@@ -207,8 +223,17 @@ private:
HashMap<String, CachedResource*> m_resources;
};
+inline bool MemoryCache::shouldMakeResourcePurgeableOnEviction()
+{
+#if PLATFORM(IOS)
+ return true;
+#else
+ return false;
+#endif
+}
+
// Function to obtain the global cache.
-Cache* cache();
+MemoryCache* cache();
}
diff --git a/WebCore/loader/icon/IconDatabase.cpp b/WebCore/loader/icon/IconDatabase.cpp
index 5a9bfaa..6040037 100644
--- a/WebCore/loader/icon/IconDatabase.cpp
+++ b/WebCore/loader/icon/IconDatabase.cpp
@@ -43,6 +43,7 @@
#include <wtf/CurrentTime.h>
#include <wtf/MainThread.h>
#include <wtf/StdLibExtras.h>
+#include <wtf/text/CString.h>
// For methods that are meant to support API from the main thread - should not be called internally
#define ASSERT_NOT_SYNC_THREAD() ASSERT(!m_syncThreadRunning || !IS_ICON_SYNC_THREAD())
@@ -768,6 +769,7 @@ IconDatabase::IconDatabase()
, m_threadTerminationRequested(false)
, m_removeIconsRequested(false)
, m_iconURLImportComplete(false)
+ , m_disabledSuddenTerminationForSyncThread(false)
, m_initialPruningComplete(false)
, m_client(defaultClient())
, m_imported(false)
@@ -806,13 +808,17 @@ void IconDatabase::notifyPendingLoadDecisions()
void IconDatabase::wakeSyncThread()
{
- // The following is balanced by the call to enableSuddenTermination in the
- // syncThreadMainLoop function.
- // FIXME: It would be better to only disable sudden termination if we have
- // something to write, not just if we have something to read.
- disableSuddenTermination();
-
MutexLocker locker(m_syncLock);
+
+ if (!m_disabledSuddenTerminationForSyncThread) {
+ m_disabledSuddenTerminationForSyncThread = true;
+ // The following is balanced by the call to enableSuddenTermination in the
+ // syncThreadMainLoop function.
+ // FIXME: It would be better to only disable sudden termination if we have
+ // something to write, not just if we have something to read.
+ disableSuddenTermination();
+ }
+
m_syncCondition.signal();
}
@@ -1315,7 +1321,7 @@ void IconDatabase::performURLImport()
}
}
- LOG(IconDatabase, "Notifying %zu interested page URLs that their icon URL is known due to the import", urlsToNotify.size());
+ LOG(IconDatabase, "Notifying %lu interested page URLs that their icon URL is known due to the import", static_cast<unsigned long>(urlsToNotify.size()));
// Now that we don't hold any locks, perform the actual notifications
for (unsigned i = 0; i < urlsToNotify.size(); ++i) {
LOG(IconDatabase, "Notifying icon info known for pageURL %s", urlsToNotify[i].ascii().data());
@@ -1411,7 +1417,9 @@ void* IconDatabase::syncThreadMainLoop()
// The following is balanced by the call to disableSuddenTermination in the
// wakeSyncThread function. Any time we wait on the condition, we also have
// to enableSuddenTermation, after doing the next batch of work.
+ ASSERT(m_disabledSuddenTerminationForSyncThread);
enableSuddenTermination();
+ m_disabledSuddenTerminationForSyncThread = false;
}
m_syncCondition.wait(m_syncLock);
@@ -1428,7 +1436,9 @@ void* IconDatabase::syncThreadMainLoop()
// The following is balanced by the call to disableSuddenTermination in the
// wakeSyncThread function. Any time we wait on the condition, we also have
// to enableSuddenTermation, after doing the next batch of work.
+ ASSERT(m_disabledSuddenTerminationForSyncThread);
enableSuddenTermination();
+ m_disabledSuddenTerminationForSyncThread = false;
}
return 0;
@@ -1639,11 +1649,19 @@ void IconDatabase::pruneUnretainedIcons()
SQLiteStatement pageDeleteSQL(m_syncDB, "DELETE FROM PageURL WHERE rowid = (?);");
pageDeleteSQL.prepare();
for (size_t i = 0; i < numToDelete; ++i) {
- LOG(IconDatabase, "Pruning page with rowid %lli from disk", pageIDsToDelete[i]);
+#if OS(WINDOWS)
+ LOG(IconDatabase, "Pruning page with rowid %I64i from disk", static_cast<long long>(pageIDsToDelete[i]));
+#else
+ LOG(IconDatabase, "Pruning page with rowid %lli from disk", static_cast<long long>(pageIDsToDelete[i]));
+#endif
pageDeleteSQL.bindInt64(1, pageIDsToDelete[i]);
int result = pageDeleteSQL.step();
if (result != SQLResultDone)
- LOG_ERROR("Unabled to delete page with id %lli from disk", pageIDsToDelete[i]);
+#if OS(WINDOWS)
+ LOG_ERROR("Unabled to delete page with id %I64i from disk", static_cast<long long>(pageIDsToDelete[i]));
+#else
+ LOG_ERROR("Unabled to delete page with id %lli from disk", static_cast<long long>(pageIDsToDelete[i]));
+#endif
pageDeleteSQL.reset();
// If the thread was asked to terminate, we should commit what pruning we've done so far, figuring we can
@@ -1829,7 +1847,7 @@ inline void readySQLiteStatement(OwnPtr<SQLiteStatement>& statement, SQLiteDatab
statement.set(0);
}
if (!statement) {
- statement.set(new SQLiteStatement(db, str));
+ statement = adoptPtr(new SQLiteStatement(db, str));
if (statement->prepare() != SQLResultOk)
LOG_ERROR("Preparing statement %s failed", str.ascii().data());
}
diff --git a/WebCore/loader/icon/IconDatabase.h b/WebCore/loader/icon/IconDatabase.h
index 44ef22a..6146aa6 100644
--- a/WebCore/loader/icon/IconDatabase.h
+++ b/WebCore/loader/icon/IconDatabase.h
@@ -27,12 +27,12 @@
#ifndef IconDatabase_h
#define IconDatabase_h
-#include "StringHash.h"
#include "Timer.h"
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
#include <wtf/Noncopyable.h>
#include <wtf/OwnPtr.h>
+#include <wtf/text/StringHash.h>
#if ENABLE(ICONDATABASE)
#include "SQLiteDatabase.h"
@@ -144,11 +144,12 @@ private:
String m_databaseDirectory;
// Holding m_syncLock is required when accessing m_completeDatabasePath
String m_completeDatabasePath;
-
+
bool m_threadTerminationRequested;
bool m_removeIconsRequested;
bool m_iconURLImportComplete;
-
+ bool m_disabledSuddenTerminationForSyncThread;
+
Mutex m_urlAndIconLock;
// Holding m_urlAndIconLock is required when accessing any of the following data structures or the objects they contain
HashMap<String, IconRecord*> m_iconURLToRecordMap;
diff --git a/WebCore/loader/icon/IconDatabaseClient.h b/WebCore/loader/icon/IconDatabaseClient.h
index 1811214..c210d7d 100644
--- a/WebCore/loader/icon/IconDatabaseClient.h
+++ b/WebCore/loader/icon/IconDatabaseClient.h
@@ -29,6 +29,7 @@
#ifndef IconDatabaseClient_h
#define IconDatabaseClient_h
+#include <wtf/Forward.h>
#include <wtf/Noncopyable.h>
// All of these client methods will be called from a non-main thread
@@ -36,8 +37,6 @@
namespace WebCore {
-class String;
-
class IconDatabaseClient : public Noncopyable {
public:
virtual ~IconDatabaseClient() { }
diff --git a/WebCore/loader/icon/IconFetcher.cpp b/WebCore/loader/icon/IconFetcher.cpp
deleted file mode 100644
index d1aa2f3..0000000
--- a/WebCore/loader/icon/IconFetcher.cpp
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright (C) 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "IconFetcher.h"
-
-#include "Frame.h"
-#include "HTMLHeadElement.h"
-#include "HTMLLinkElement.h"
-#include "HTMLNames.h"
-#include "ResourceHandle.h"
-#include "ResourceRequest.h"
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-struct IconLinkEntry {
-public:
- enum IconType {
- Unknown,
- ICNS,
- ICO,
- };
-
- IconLinkEntry(IconType type, const KURL& url)
- : m_type(type)
- , m_url(url)
- {
- }
-
- IconType type() const { return m_type; }
- const KURL& url() const { return m_url; }
-
- SharedBuffer* buffer()
- {
- if (!m_buffer)
- m_buffer = SharedBuffer::create();
-
- return m_buffer.get();
- }
-
-private:
- RefPtr<SharedBuffer> m_buffer;
- IconType m_type;
- KURL m_url;
-};
-
-#if PLATFORM(MAC)
-static const IconLinkEntry::IconType NativeIconType = IconLinkEntry::ICNS;
-#elif PLATFORM(WIN)
-static const IconLinkEntry::IconType NativeIconType = IconLinkEntry::ICO;
-#else
-static const IconLinkEntry::IconType NativeIconType = IconLinkEntry::Unknown;
-#endif
-
-static void parseIconLink(HTMLLinkElement* link, Vector<IconLinkEntry>& entries)
-{
- // FIXME: Parse the size attribute too.
-
- IconLinkEntry::IconType type = IconLinkEntry::Unknown;
- const KURL& url = link->href();
-
- // Try to determine the file type.
- String path = url.path();
-
- int pos = path.reverseFind('.');
- if (pos >= 0) {
- String extension = path.substring(pos + 1);
- if (equalIgnoringCase(extension, "icns"))
- type = IconLinkEntry::ICNS;
- else if (equalIgnoringCase(extension, "ico"))
- type = IconLinkEntry::ICO;
- }
-
- entries.append(IconLinkEntry(type, url));
-}
-
-PassRefPtr<IconFetcher> IconFetcher::create(Frame* frame, IconFetcherClient* client)
-{
- Document* document = frame->document();
-
- HTMLHeadElement* head = document->head();
- if (!head)
- return 0;
-
- Vector<IconLinkEntry> entries;
-
- for (Node* n = head; n; n = n->traverseNextNode()) {
- if (!n->hasTagName(linkTag))
- continue;
-
- HTMLLinkElement* link = static_cast<HTMLLinkElement*>(n);
- if (!link->isIcon())
- continue;
-
- parseIconLink(link, entries);
- }
-
- if (entries.isEmpty())
- return 0;
-
- // Check if any of the entries have the same type as the native icon type.
-
- // FIXME: This should be way more sophisticated, and handle conversion
- // of multisize formats for example.
- for (unsigned i = 0; i < entries.size(); i++) {
- const IconLinkEntry& entry = entries[i];
- if (entry.type() == NativeIconType) {
- RefPtr<IconFetcher> iconFetcher = adoptRef(new IconFetcher(frame, client));
-
- iconFetcher->m_entries.append(entry);
- iconFetcher->loadEntry();
-
- return iconFetcher.release();
- }
- }
-
- return 0;
-}
-
-IconFetcher::IconFetcher(Frame* frame, IconFetcherClient* client)
- : m_frame(frame)
- , m_client(client)
- , m_currentEntry(0)
-{
-}
-
-IconFetcher::~IconFetcher()
-{
- cancel();
-}
-
-void IconFetcher::cancel()
-{
- if (m_handle)
- m_handle->cancel();
-}
-
-PassRefPtr<SharedBuffer> IconFetcher::createIcon()
-{
- ASSERT(!m_entries.isEmpty());
-
- // For now, just return the data of the first entry.
- return m_entries.first().buffer();
-}
-
-void IconFetcher::loadEntry()
-{
- ASSERT(m_currentEntry < m_entries.size());
- ASSERT(!m_handle);
-
- m_handle = ResourceHandle::create(m_entries[m_currentEntry].url(), this, m_frame, false, false);
-}
-
-void IconFetcher::loadFailed()
-{
- m_handle = 0;
-
- m_client->finishedFetchingIcon(0);
-}
-
-void IconFetcher::didReceiveResponse(ResourceHandle* handle, const ResourceResponse& response)
-{
- ASSERT_UNUSED(handle, m_handle == handle);
-
- int statusCode = response.httpStatusCode() / 100;
- if (statusCode == 4 || statusCode == 5) {
- loadFailed();
- return;
- }
-}
-
-void IconFetcher::didReceiveData(ResourceHandle* handle, const char* data, int length, int)
-{
- ASSERT_UNUSED(handle, m_handle == handle);
-
- m_entries[m_currentEntry].buffer()->append(data, length);
-}
-
-void IconFetcher::didFinishLoading(ResourceHandle* handle)
-{
- ASSERT_UNUSED(handle, m_handle == handle);
-
- if (m_currentEntry == m_entries.size() - 1) {
- // We finished loading, create the icon
- RefPtr<SharedBuffer> iconData = createIcon();
-
- m_client->finishedFetchingIcon(iconData.release());
- return;
- }
-
- // Load the next entry
- m_currentEntry++;
-
- loadEntry();
-}
-
-void IconFetcher::didFail(ResourceHandle* handle, const ResourceError&)
-{
- ASSERT_UNUSED(handle, m_handle == handle);
-
- loadFailed();
-}
-
-} // namespace WebCore
diff --git a/WebCore/loader/icon/IconFetcher.h b/WebCore/loader/icon/IconFetcher.h
deleted file mode 100644
index 5327693..0000000
--- a/WebCore/loader/icon/IconFetcher.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef IconFetcher_h
-#define IconFetcher_h
-
-#include <wtf/RefCounted.h>
-#include <wtf/Forward.h>
-#include <wtf/Vector.h>
-
-#include "ResourceHandleClient.h"
-
-namespace WebCore {
-
-class Frame;
-struct IconLinkEntry;
-class ResourceHandle;
-class SharedBuffer;
-
-class IconFetcherClient {
-public:
- virtual void finishedFetchingIcon(PassRefPtr<SharedBuffer> iconData) = 0;
-
- virtual ~IconFetcherClient() { }
-};
-
-class IconFetcher : public RefCounted<IconFetcher>, ResourceHandleClient {
-public:
- static PassRefPtr<IconFetcher> create(Frame*, IconFetcherClient*);
- ~IconFetcher();
-
- void cancel();
-
-private:
- IconFetcher(Frame*, IconFetcherClient*);
- void loadEntry();
- void loadFailed();
-
- PassRefPtr<SharedBuffer> createIcon();
-
- virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&);
- virtual void didReceiveData(ResourceHandle*, const char*, int, int lengthReceived);
- virtual void didFinishLoading(ResourceHandle*);
- virtual void didFail(ResourceHandle*, const ResourceError&);
-
- Frame* m_frame;
- IconFetcherClient* m_client;
-
- unsigned m_currentEntry;
- RefPtr<ResourceHandle> m_handle;
- Vector<IconLinkEntry> m_entries;
-};
-
-} // namespace WebCore
-
-#endif // IconFetcher_h
diff --git a/WebCore/loader/icon/IconLoader.cpp b/WebCore/loader/icon/IconLoader.cpp
index 5dd000e..adfa04b 100644
--- a/WebCore/loader/icon/IconLoader.cpp
+++ b/WebCore/loader/icon/IconLoader.cpp
@@ -38,6 +38,7 @@
#include "SharedBuffer.h"
#include "SubresourceLoader.h"
#include <wtf/UnusedParam.h>
+#include <wtf/text/CString.h>
using namespace std;
@@ -49,9 +50,9 @@ IconLoader::IconLoader(Frame* frame)
{
}
-auto_ptr<IconLoader> IconLoader::create(Frame* frame)
+PassOwnPtr<IconLoader> IconLoader::create(Frame* frame)
{
- return auto_ptr<IconLoader>(new IconLoader(frame));
+ return adoptPtr(new IconLoader(frame));
}
IconLoader::~IconLoader()
@@ -91,7 +92,7 @@ void IconLoader::didReceiveResponse(SubresourceLoader* resourceLoader, const Res
if (status && (status < 200 || status > 299)) {
ResourceHandle* handle = resourceLoader->handle();
- finishLoading(handle ? handle->request().url() : KURL(), 0);
+ finishLoading(handle ? handle->firstRequest().url() : KURL(), 0);
}
}
@@ -115,7 +116,7 @@ void IconLoader::didFail(SubresourceLoader* resourceLoader, const ResourceError&
if (m_loadIsInProgress) {
ASSERT(resourceLoader == m_resourceLoader);
ResourceHandle* handle = resourceLoader->handle();
- finishLoading(handle ? handle->request().url() : KURL(), 0);
+ finishLoading(handle ? handle->firstRequest().url() : KURL(), 0);
}
}
@@ -137,7 +138,7 @@ void IconLoader::didFinishLoading(SubresourceLoader* resourceLoader)
if (m_loadIsInProgress) {
ASSERT(resourceLoader == m_resourceLoader);
ResourceHandle* handle = resourceLoader->handle();
- finishLoading(handle ? handle->request().url() : KURL(), m_resourceLoader->resourceData());
+ finishLoading(handle ? handle->firstRequest().url() : KURL(), m_resourceLoader->resourceData());
}
}
diff --git a/WebCore/loader/icon/IconLoader.h b/WebCore/loader/icon/IconLoader.h
index 7b96ed8..1ebac48 100644
--- a/WebCore/loader/icon/IconLoader.h
+++ b/WebCore/loader/icon/IconLoader.h
@@ -27,7 +27,6 @@
#define IconLoader_h
#include "SubresourceLoaderClient.h"
-#include <memory>
#include <wtf/Forward.h>
#include <wtf/Noncopyable.h>
#include <wtf/RefPtr.h>
@@ -40,7 +39,7 @@ class SharedBuffer;
class IconLoader : private SubresourceLoaderClient, public Noncopyable {
public:
- static std::auto_ptr<IconLoader> create(Frame*);
+ static PassOwnPtr<IconLoader> create(Frame*);
~IconLoader();
void startLoading();
diff --git a/WebCore/loader/icon/IconRecord.cpp b/WebCore/loader/icon/IconRecord.cpp
index ffea318..7e90d8e 100644
--- a/WebCore/loader/icon/IconRecord.cpp
+++ b/WebCore/loader/icon/IconRecord.cpp
@@ -34,6 +34,7 @@
#include "Logging.h"
#include "SQLiteStatement.h"
#include "SQLiteTransaction.h"
+#include <wtf/text/CString.h>
#include <limits.h>
diff --git a/WebCore/loader/icon/IconRecord.h b/WebCore/loader/icon/IconRecord.h
index aaea787..f1fe12f 100644
--- a/WebCore/loader/icon/IconRecord.h
+++ b/WebCore/loader/icon/IconRecord.h
@@ -33,10 +33,10 @@
#include <wtf/RefCounted.h>
#include "SharedBuffer.h"
+#include "PlatformString.h"
#include <wtf/HashSet.h>
#include <wtf/OwnPtr.h>
-#include "PlatformString.h"
-#include "StringHash.h"
+#include <wtf/text/StringHash.h>
namespace WebCore {
diff --git a/WebCore/loader/icon/wince/IconDatabaseWince.cpp b/WebCore/loader/icon/wince/IconDatabaseWinCE.cpp
index e6d686c..54a36e5 100644
--- a/WebCore/loader/icon/wince/IconDatabaseWince.cpp
+++ b/WebCore/loader/icon/wince/IconDatabaseWinCE.cpp
@@ -22,12 +22,12 @@
#include "IconDatabase.h"
#include "AutodrainedPool.h"
-#include "CString.h"
#include "DocumentLoader.h"
#include "FileSystem.h"
#include "IconDatabaseClient.h"
#include "IconRecord.h"
#include "Image.h"
+#include <wtf/text/CString.h>
namespace WebCore {
diff --git a/WebCore/loader/loader.cpp b/WebCore/loader/loader.cpp
index 4d2b474..bd27312 100644
--- a/WebCore/loader/loader.cpp
+++ b/WebCore/loader/loader.cpp
@@ -24,25 +24,26 @@
#include "config.h"
#include "loader.h"
-#include "Cache.h"
+#include "MemoryCache.h"
#include "CachedImage.h"
#include "CachedResource.h"
-#include "CString.h"
-#include "DocLoader.h"
+#include "CachedResourceLoader.h"
+#include "InspectorInstrumentation.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "HTMLDocument.h"
+#include "Logging.h"
#include "Request.h"
#include "ResourceHandle.h"
#include "ResourceRequest.h"
#include "ResourceResponse.h"
#include "SecurityOrigin.h"
+#include "SharedBuffer.h"
#include "SubresourceLoader.h"
#include <wtf/Assertions.h>
#include <wtf/Vector.h>
#define REQUEST_MANAGEMENT_ENABLED 1
-#define REQUEST_DEBUG 0
namespace WebCore {
@@ -78,9 +79,6 @@ static ResourceRequest::TargetType cachedResourceTypeToTargetType(CachedResource
#if ENABLE(XSLT)
case CachedResource::XSLStyleSheet:
#endif
-#if ENABLE(XBL)
- case CachedResource::XBL:
-#endif
return ResourceRequest::TargetIsStyleSheet;
case CachedResource::Script:
return ResourceRequest::TargetIsScript;
@@ -88,7 +86,12 @@ static ResourceRequest::TargetType cachedResourceTypeToTargetType(CachedResource
return ResourceRequest::TargetIsFontResource;
case CachedResource::ImageResource:
return ResourceRequest::TargetIsImage;
+#if ENABLE(LINK_PREFETCH)
+ case CachedResource::LinkPrefetch:
+ return ResourceRequest::TargetIsPrefetch;
+#endif
}
+ ASSERT_NOT_REACHED();
return ResourceRequest::TargetIsSubresource;
}
@@ -100,15 +103,16 @@ Loader::Priority Loader::determinePriority(const CachedResource* resource) const
#if ENABLE(XSLT)
case CachedResource::XSLStyleSheet:
#endif
-#if ENABLE(XBL)
- case CachedResource::XBL:
-#endif
return High;
case CachedResource::Script:
case CachedResource::FontResource:
return Medium;
case CachedResource::ImageResource:
return Low;
+#if ENABLE(LINK_PREFETCH)
+ case CachedResource::LinkPrefetch:
+ return VeryLow;
+#endif
}
ASSERT_NOT_REACHED();
return Low;
@@ -117,10 +121,12 @@ Loader::Priority Loader::determinePriority(const CachedResource* resource) const
#endif
}
-void Loader::load(DocLoader* docLoader, CachedResource* resource, bool incremental, SecurityCheckPolicy securityCheck, bool sendResourceLoadCallbacks)
+void Loader::load(CachedResourceLoader* cachedResourceLoader, CachedResource* resource, bool incremental, SecurityCheckPolicy securityCheck, bool sendResourceLoadCallbacks)
{
- ASSERT(docLoader);
- Request* request = new Request(docLoader, resource, incremental, securityCheck, sendResourceLoadCallbacks);
+ LOG(ResourceLoading, "Loader::load resource %p '%s'", resource, resource->url().latin1().data());
+
+ ASSERT(cachedResourceLoader);
+ Request* request = new Request(cachedResourceLoader, resource, incremental, securityCheck, sendResourceLoadCallbacks);
RefPtr<Host> host;
KURL url(ParsedURLString, resource->url());
@@ -138,30 +144,34 @@ void Loader::load(DocLoader* docLoader, CachedResource* resource, bool increment
bool hadRequests = host->hasRequests();
Priority priority = determinePriority(resource);
host->addRequest(request, priority);
- docLoader->incrementRequestCount();
+ cachedResourceLoader->incrementRequestCount(request->cachedResource());
- if (priority > Low || !url.protocolInHTTPFamily() || !hadRequests) {
+ if (priority > Low || !url.protocolInHTTPFamily() || (priority == Low && !hadRequests)) {
// Try to request important resources immediately
host->servePendingRequests(priority);
} else {
// Handle asynchronously so early low priority requests don't get scheduled before later high priority ones
+ InspectorInstrumentation::didScheduleResourceRequest(cachedResourceLoader->document(), resource->url());
scheduleServePendingRequests();
}
}
void Loader::scheduleServePendingRequests()
{
+ LOG(ResourceLoading, "Loader::scheduleServePendingRequests, m_requestTimer.isActive()=%u", m_requestTimer.isActive());
if (!m_requestTimer.isActive())
m_requestTimer.startOneShot(0);
}
void Loader::requestTimerFired(Timer<Loader>*)
{
+ LOG(ResourceLoading, "Loader::requestTimerFired\n");
servePendingRequests();
}
void Loader::servePendingRequests(Priority minimumPriority)
{
+ LOG(ResourceLoading, "Loader::servePendingRequests. m_isSuspendingPendingRequests=%d", m_isSuspendingPendingRequests);
if (m_isSuspendingPendingRequests)
return;
@@ -232,12 +242,12 @@ void Loader::nonCacheRequestComplete(const KURL& url)
host->nonCacheRequestComplete();
}
-void Loader::cancelRequests(DocLoader* docLoader)
+void Loader::cancelRequests(CachedResourceLoader* cachedResourceLoader)
{
- docLoader->clearPendingPreloads();
+ cachedResourceLoader->clearPendingPreloads();
if (m_nonHTTPProtocolHost->hasRequests())
- m_nonHTTPProtocolHost->cancelRequests(docLoader);
+ m_nonHTTPProtocolHost->cancelRequests(cachedResourceLoader);
Vector<Host*> hostsToCancel;
m_hosts.checkConsistency();
@@ -249,12 +259,12 @@ void Loader::cancelRequests(DocLoader* docLoader)
for (unsigned n = 0; n < hostsToCancel.size(); ++n) {
Host* host = hostsToCancel[n];
if (host->hasRequests())
- host->cancelRequests(docLoader);
+ host->cancelRequests(cachedResourceLoader);
}
scheduleServePendingRequests();
- ASSERT(docLoader->requestCount() == (docLoader->loadInProgress() ? 1 : 0));
+ ASSERT(cachedResourceLoader->requestCount() == (cachedResourceLoader->loadInProgress() ? 1 : 0));
}
Loader::Host::Host(const AtomicString& name, unsigned maxRequestsInFlight)
@@ -286,6 +296,8 @@ void Loader::Host::nonCacheRequestComplete()
{
--m_nonCachedRequestsInFlight;
ASSERT(m_nonCachedRequestsInFlight >= 0);
+
+ cache()->loader()->scheduleServePendingRequests();
}
bool Loader::Host::hasRequests() const
@@ -301,8 +313,11 @@ bool Loader::Host::hasRequests() const
void Loader::Host::servePendingRequests(Loader::Priority minimumPriority)
{
- if (cache()->loader()->isSuspendingPendingRequests())
+ LOG(ResourceLoading, "Host::servePendingRequests '%s'", m_name.string().latin1().data());
+ if (cache()->loader()->isSuspendingPendingRequests()) {
+ LOG(ResourceLoading, "...isSuspendingPendingRequests");
return;
+ }
bool serveMore = true;
for (int priority = High; priority >= minimumPriority && serveMore; --priority)
@@ -313,16 +328,15 @@ void Loader::Host::servePendingRequests(RequestQueue& requestsPending, bool& ser
{
while (!requestsPending.isEmpty()) {
Request* request = requestsPending.first();
- DocLoader* docLoader = request->docLoader();
+ CachedResourceLoader* cachedResourceLoader = request->cachedResourceLoader();
bool resourceIsCacheValidator = request->cachedResource()->isCacheValidator();
// For named hosts - which are only http(s) hosts - we should always enforce the connection limit.
// For non-named hosts - everything but http(s) - we should only enforce the limit if the document isn't done parsing
// and we don't know all stylesheets yet.
- bool shouldLimitRequests = !m_name.isNull() || docLoader->doc()->parsing() || !docLoader->doc()->haveStylesheetsLoaded();
+ bool shouldLimitRequests = !m_name.isNull() || cachedResourceLoader->document()->parsing() || !cachedResourceLoader->document()->haveStylesheetsLoaded();
if (shouldLimitRequests && m_requestsLoading.size() + m_nonCachedRequestsInFlight >= m_maxRequestsInFlight) {
serveLowerPriority = false;
- cache()->loader()->scheduleServePendingRequests();
return;
}
requestsPending.removeFirst();
@@ -342,8 +356,8 @@ void Loader::Host::servePendingRequests(RequestQueue& requestsPending, bool& ser
const String& lastModified = resourceToRevalidate->response().httpHeaderField("Last-Modified");
const String& eTag = resourceToRevalidate->response().httpHeaderField("ETag");
if (!lastModified.isEmpty() || !eTag.isEmpty()) {
- ASSERT(docLoader->cachePolicy() != CachePolicyReload);
- if (docLoader->cachePolicy() == CachePolicyRevalidate)
+ ASSERT(cachedResourceLoader->cachePolicy() != CachePolicyReload);
+ if (cachedResourceLoader->cachePolicy() == CachePolicyRevalidate)
resourceRequest.setHTTPHeaderField("Cache-Control", "max-age=0");
if (!lastModified.isEmpty())
resourceRequest.setHTTPHeaderField("If-Modified-Since", lastModified);
@@ -352,19 +366,27 @@ void Loader::Host::servePendingRequests(RequestQueue& requestsPending, bool& ser
}
}
- RefPtr<SubresourceLoader> loader = SubresourceLoader::create(docLoader->doc()->frame(),
+#if ENABLE(LINK_PREFETCH)
+ if (request->cachedResource()->type() == CachedResource::LinkPrefetch)
+ resourceRequest.setHTTPHeaderField("Purpose", "prefetch");
+#endif
+
+ RefPtr<SubresourceLoader> loader = SubresourceLoader::create(cachedResourceLoader->document()->frame(),
this, resourceRequest, request->shouldDoSecurityCheck(), request->sendResourceLoadCallbacks());
if (loader) {
m_requestsLoading.add(loader.release(), request);
request->cachedResource()->setRequestedFromNetworkingLayer();
-#if REQUEST_DEBUG
- printf("HOST %s COUNT %d LOADING %s\n", resourceRequest.url().host().latin1().data(), m_requestsLoading.size(), request->cachedResource()->url().latin1().data());
-#endif
- } else {
- docLoader->decrementRequestCount();
- docLoader->setLoadInProgress(true);
- request->cachedResource()->error();
- docLoader->setLoadInProgress(false);
+ LOG(ResourceLoading, "Host '%s' loading '%s'. Current count %d", m_name.string().latin1().data(), request->cachedResource()->url().latin1().data(), m_requestsLoading.size());
+ } else {
+ // FIXME: What if resources in other frames were waiting for this revalidation?
+ LOG(ResourceLoading, "Host '%s' cannot start loading '%s'", m_name.string().latin1().data(), request->cachedResource()->url().latin1().data());
+ CachedResource* resource = request->cachedResource();
+ cachedResourceLoader->decrementRequestCount(resource);
+ cachedResourceLoader->setLoadInProgress(true);
+ if (resource->resourceToRevalidate())
+ cache()->revalidationFailed(resource);
+ resource->error();
+ cachedResourceLoader->setLoadInProgress(false);
delete request;
}
}
@@ -380,34 +402,32 @@ void Loader::Host::didFinishLoading(SubresourceLoader* loader)
Request* request = i->second;
m_requestsLoading.remove(i);
- DocLoader* docLoader = request->docLoader();
+ CachedResourceLoader* cachedResourceLoader = request->cachedResourceLoader();
// Prevent the document from being destroyed before we are done with
- // the docLoader that it will delete when the document gets deleted.
- RefPtr<Document> protector(docLoader->doc());
+ // the cachedResourceLoader that it will delete when the document gets deleted.
+ RefPtr<Document> protector(cachedResourceLoader->document());
if (!request->isMultipart())
- docLoader->decrementRequestCount();
+ cachedResourceLoader->decrementRequestCount(request->cachedResource());
CachedResource* resource = request->cachedResource();
ASSERT(!resource->resourceToRevalidate());
+ LOG(ResourceLoading, "Host '%s' received %s. Current count %d\n", m_name.string().latin1().data(), resource->url().latin1().data(), m_requestsLoading.size());
+
// If we got a 4xx response, we're pretending to have received a network
// error, so we can't send the successful data() and finish() callbacks.
if (!resource->errorOccurred()) {
- docLoader->setLoadInProgress(true);
+ cachedResourceLoader->setLoadInProgress(true);
resource->data(loader->resourceData(), true);
resource->finish();
}
delete request;
- docLoader->setLoadInProgress(false);
+ cachedResourceLoader->setLoadInProgress(false);
- docLoader->checkForPendingPreloads();
+ cachedResourceLoader->checkForPendingPreloads();
-#if REQUEST_DEBUG
- KURL u(ParsedURLString, resource->url());
- printf("HOST %s COUNT %d RECEIVED %s\n", u.host().latin1().data(), m_requestsLoading.size(), resource->url().latin1().data());
-#endif
servePendingRequests();
}
@@ -428,30 +448,32 @@ void Loader::Host::didFail(SubresourceLoader* loader, bool cancelled)
Request* request = i->second;
m_requestsLoading.remove(i);
- DocLoader* docLoader = request->docLoader();
+ CachedResourceLoader* cachedResourceLoader = request->cachedResourceLoader();
// Prevent the document from being destroyed before we are done with
- // the docLoader that it will delete when the document gets deleted.
- RefPtr<Document> protector(docLoader->doc());
+ // the cachedResourceLoader that it will delete when the document gets deleted.
+ RefPtr<Document> protector(cachedResourceLoader->document());
if (!request->isMultipart())
- docLoader->decrementRequestCount();
+ cachedResourceLoader->decrementRequestCount(request->cachedResource());
CachedResource* resource = request->cachedResource();
-
+
+ LOG(ResourceLoading, "Host '%s' failed to load %s (cancelled=%d). Current count %d\n", m_name.string().latin1().data(), resource->url().latin1().data(), cancelled, m_requestsLoading.size());
+
if (resource->resourceToRevalidate())
cache()->revalidationFailed(resource);
if (!cancelled) {
- docLoader->setLoadInProgress(true);
+ cachedResourceLoader->setLoadInProgress(true);
resource->error();
}
- docLoader->setLoadInProgress(false);
+ cachedResourceLoader->setLoadInProgress(false);
if (cancelled || !resource->isPreloaded())
cache()->remove(resource);
delete request;
- docLoader->checkForPendingPreloads();
+ cachedResourceLoader->checkForPendingPreloads();
servePendingRequests();
}
@@ -478,13 +500,13 @@ void Loader::Host::didReceiveResponse(SubresourceLoader* loader, const ResourceR
// 304 Not modified / Use local copy
m_requestsLoading.remove(loader);
loader->clearClient();
- request->docLoader()->decrementRequestCount();
+ request->cachedResourceLoader()->decrementRequestCount(request->cachedResource());
// Existing resource is ok, just use it updating the expiration time.
cache()->revalidationSucceeded(resource, response);
- if (request->docLoader()->frame())
- request->docLoader()->frame()->loader()->checkCompleted();
+ if (request->cachedResourceLoader()->frame())
+ request->cachedResourceLoader()->frame()->loader()->checkCompleted();
delete request;
@@ -504,13 +526,13 @@ void Loader::Host::didReceiveResponse(SubresourceLoader* loader, const ResourceR
if (request->isMultipart()) {
ASSERT(resource->isImage());
static_cast<CachedImage*>(resource)->clear();
- if (request->docLoader()->frame())
- request->docLoader()->frame()->loader()->checkCompleted();
+ if (request->cachedResourceLoader()->frame())
+ request->cachedResourceLoader()->frame()->loader()->checkCompleted();
} else if (response.isMultipart()) {
request->setIsMultipart(true);
- // We don't count multiParts in a DocLoader's request count
- request->docLoader()->decrementRequestCount();
+ // We don't count multiParts in a CachedResourceLoader's request count
+ request->cachedResourceLoader()->decrementRequestCount(request->cachedResource());
// If we get a multipart response, we must have a handle
ASSERT(loader->handle());
@@ -533,9 +555,7 @@ void Loader::Host::didReceiveData(SubresourceLoader* loader, const char* data, i
if (resource->errorOccurred())
return;
- if (resource->response().httpStatusCode() / 100 == 4) {
- // Treat a 4xx response like a network error for all resources but images (which will ignore the error and continue to load for
- // legacy compatibility).
+ if (resource->response().httpStatusCode() >= 400) {
resource->httpStatusCodeError();
return;
}
@@ -550,33 +570,47 @@ void Loader::Host::didReceiveData(SubresourceLoader* loader, const char* data, i
resource->data(loader->resourceData(), false);
}
-void Loader::Host::cancelPendingRequests(RequestQueue& requestsPending, DocLoader* docLoader)
+void Loader::Host::didReceiveCachedMetadata(SubresourceLoader* loader, const char* data, int size)
+{
+ RefPtr<Host> protector(this);
+
+ Request* request = m_requestsLoading.get(loader);
+ if (!request)
+ return;
+
+ CachedResource* resource = request->cachedResource();
+ ASSERT(!resource->isCacheValidator());
+
+ resource->setSerializedCachedMetadata(data, size);
+}
+
+void Loader::Host::cancelPendingRequests(RequestQueue& requestsPending, CachedResourceLoader* cachedResourceLoader)
{
RequestQueue remaining;
RequestQueue::iterator end = requestsPending.end();
for (RequestQueue::iterator it = requestsPending.begin(); it != end; ++it) {
Request* request = *it;
- if (request->docLoader() == docLoader) {
+ if (request->cachedResourceLoader() == cachedResourceLoader) {
cache()->remove(request->cachedResource());
+ cachedResourceLoader->decrementRequestCount(request->cachedResource());
delete request;
- docLoader->decrementRequestCount();
} else
remaining.append(request);
}
requestsPending.swap(remaining);
}
-void Loader::Host::cancelRequests(DocLoader* docLoader)
+void Loader::Host::cancelRequests(CachedResourceLoader* cachedResourceLoader)
{
for (unsigned p = 0; p <= High; p++)
- cancelPendingRequests(m_requestsPending[p], docLoader);
+ cancelPendingRequests(m_requestsPending[p], cachedResourceLoader);
Vector<SubresourceLoader*, 256> loadersToCancel;
RequestMap::iterator end = m_requestsLoading.end();
for (RequestMap::iterator i = m_requestsLoading.begin(); i != end; ++i) {
Request* r = i->second;
- if (r->docLoader() == docLoader)
+ if (r->cachedResourceLoader() == cachedResourceLoader)
loadersToCancel.append(i->first.get());
}
diff --git a/WebCore/loader/loader.h b/WebCore/loader/loader.h
index a9de032..4d353e0 100644
--- a/WebCore/loader/loader.h
+++ b/WebCore/loader/loader.h
@@ -22,8 +22,6 @@
#ifndef loader_h
#define loader_h
-#include "AtomicString.h"
-#include "AtomicStringImpl.h"
#include "FrameLoaderTypes.h"
#include "PlatformString.h"
#include "SubresourceLoaderClient.h"
@@ -31,11 +29,13 @@
#include <wtf/Deque.h>
#include <wtf/HashMap.h>
#include <wtf/Noncopyable.h>
+#include <wtf/text/AtomicString.h>
+#include <wtf/text/AtomicStringImpl.h>
namespace WebCore {
class CachedResource;
- class DocLoader;
+ class CachedResourceLoader;
class KURL;
class Request;
@@ -44,12 +44,12 @@ namespace WebCore {
Loader();
~Loader();
- void load(DocLoader*, CachedResource*, bool incremental = true, SecurityCheckPolicy = DoSecurityCheck, bool sendResourceLoadCallbacks = true);
+ void load(CachedResourceLoader*, CachedResource*, bool incremental = true, SecurityCheckPolicy = DoSecurityCheck, bool sendResourceLoadCallbacks = true);
- void cancelRequests(DocLoader*);
+ void cancelRequests(CachedResourceLoader*);
- enum Priority { Low, Medium, High };
- void servePendingRequests(Priority minimumPriority = Low);
+ enum Priority { VeryLow, Low, Medium, High };
+ void servePendingRequests(Priority minimumPriority = VeryLow);
bool isSuspendingPendingRequests() { return m_isSuspendingPendingRequests; }
void suspendPendingRequests();
@@ -76,8 +76,8 @@ namespace WebCore {
void addRequest(Request*, Priority);
void nonCacheRequestInFlight();
void nonCacheRequestComplete();
- void servePendingRequests(Priority minimumPriority = Low);
- void cancelRequests(DocLoader*);
+ void servePendingRequests(Priority minimumPriority = VeryLow);
+ void cancelRequests(CachedResourceLoader*);
bool hasRequests() const;
bool processingResource() const { return m_numResourcesProcessing != 0 || m_nonCachedRequestsInFlight !=0; }
@@ -87,13 +87,14 @@ namespace WebCore {
virtual void didReceiveResponse(SubresourceLoader*, const ResourceResponse&);
virtual void didReceiveData(SubresourceLoader*, const char*, int);
+ virtual void didReceiveCachedMetadata(SubresourceLoader*, const char*, int);
virtual void didFinishLoading(SubresourceLoader*);
virtual void didFail(SubresourceLoader*, const ResourceError&);
typedef Deque<Request*> RequestQueue;
void servePendingRequests(RequestQueue& requestsPending, bool& serveLowerPriority);
void didFail(SubresourceLoader*, bool cancelled = false);
- void cancelPendingRequests(RequestQueue& requestsPending, DocLoader*);
+ void cancelPendingRequests(RequestQueue& requestsPending, CachedResourceLoader*);
RequestQueue m_requestsPending[High + 1];
typedef HashMap<RefPtr<SubresourceLoader>, Request*> RequestMap;