summaryrefslogtreecommitdiffstats
path: root/WebCore/loader
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/loader')
-rw-r--r--WebCore/loader/Cache.cpp4
-rw-r--r--WebCore/loader/Cache.h2
-rw-r--r--WebCore/loader/CachedCSSStyleSheet.cpp11
-rw-r--r--WebCore/loader/CachedCSSStyleSheet.h2
-rw-r--r--WebCore/loader/CachedFont.cpp57
-rw-r--r--WebCore/loader/CachedFont.h2
-rw-r--r--WebCore/loader/CachedImage.cpp29
-rw-r--r--WebCore/loader/CachedImage.h5
-rw-r--r--WebCore/loader/CachedMetadata.h125
-rw-r--r--WebCore/loader/CachedResource.cpp100
-rw-r--r--WebCore/loader/CachedResource.h81
-rw-r--r--WebCore/loader/CachedResourceClient.h2
-rw-r--r--WebCore/loader/CachedScript.cpp16
-rw-r--r--WebCore/loader/CachedScript.h3
-rw-r--r--WebCore/loader/CachedXBLDocument.h2
-rw-r--r--WebCore/loader/CachedXSLStyleSheet.cpp11
-rw-r--r--WebCore/loader/CachedXSLStyleSheet.h2
-rw-r--r--WebCore/loader/CrossOriginAccessControl.cpp18
-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/DocLoader.cpp44
-rw-r--r--WebCore/loader/DocLoader.h14
-rw-r--r--WebCore/loader/DocumentLoadTiming.h58
-rw-r--r--WebCore/loader/DocumentLoader.cpp24
-rw-r--r--WebCore/loader/DocumentLoader.h18
-rw-r--r--WebCore/loader/DocumentThreadableLoader.cpp67
-rw-r--r--WebCore/loader/DocumentThreadableLoader.h3
-rw-r--r--WebCore/loader/DocumentWriter.cpp251
-rw-r--r--WebCore/loader/DocumentWriter.h89
-rw-r--r--WebCore/loader/EmptyClients.h124
-rw-r--r--WebCore/loader/FTPDirectoryDocument.cpp180
-rw-r--r--WebCore/loader/FTPDirectoryDocument.h8
-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.cpp1350
-rw-r--r--WebCore/loader/FrameLoader.h135
-rw-r--r--WebCore/loader/FrameLoaderClient.h33
-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.cpp152
-rw-r--r--WebCore/loader/HistoryController.h6
-rw-r--r--WebCore/loader/ImageDocument.cpp129
-rw-r--r--WebCore/loader/ImageDocument.h8
-rw-r--r--WebCore/loader/ImageLoader.cpp14
-rw-r--r--WebCore/loader/ImageLoader.h4
-rw-r--r--WebCore/loader/MainResourceLoader.cpp38
-rw-r--r--WebCore/loader/MainResourceLoader.h6
-rw-r--r--WebCore/loader/MediaDocument.cpp86
-rw-r--r--WebCore/loader/MediaDocument.h8
-rw-r--r--WebCore/loader/PlaceholderDocument.h6
-rw-r--r--WebCore/loader/PluginDocument.cpp132
-rw-r--r--WebCore/loader/PluginDocument.h18
-rw-r--r--WebCore/loader/ProgressTracker.cpp15
-rw-r--r--WebCore/loader/RedirectScheduler.cpp386
-rw-r--r--WebCore/loader/RedirectScheduler.h15
-rw-r--r--WebCore/loader/ResourceLoadNotifier.cpp5
-rw-r--r--WebCore/loader/ResourceLoadNotifier.h1
-rw-r--r--WebCore/loader/ResourceLoader.cpp59
-rw-r--r--WebCore/loader/ResourceLoader.h9
-rw-r--r--WebCore/loader/SinkDocument.cpp56
-rw-r--r--WebCore/loader/SinkDocument.h49
-rw-r--r--WebCore/loader/SubframeLoader.cpp365
-rw-r--r--WebCore/loader/SubframeLoader.h91
-rw-r--r--WebCore/loader/SubresourceLoader.cpp41
-rw-r--r--WebCore/loader/SubresourceLoader.h1
-rw-r--r--WebCore/loader/SubresourceLoaderClient.h1
-rw-r--r--WebCore/loader/TextDocument.cpp78
-rw-r--r--WebCore/loader/TextDocument.h10
-rw-r--r--WebCore/loader/TextResourceDecoder.cpp8
-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.cpp277
-rw-r--r--WebCore/loader/appcache/ApplicationCacheGroup.h46
-rw-r--r--WebCore/loader/appcache/ApplicationCacheHost.cpp67
-rw-r--r--WebCore/loader/appcache/ApplicationCacheHost.h59
-rw-r--r--WebCore/loader/appcache/ApplicationCacheStorage.cpp218
-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/android/WebArchiveAndroid.cpp469
-rw-r--r--WebCore/loader/archive/android/WebArchiveAndroid.h55
-rw-r--r--WebCore/loader/archive/cf/LegacyWebArchive.cpp4
-rw-r--r--WebCore/loader/archive/cf/LegacyWebArchiveMac.mm2
-rw-r--r--WebCore/loader/icon/IconDatabase.cpp14
-rw-r--r--WebCore/loader/icon/IconDatabase.h2
-rw-r--r--WebCore/loader/icon/IconDatabaseClient.h3
-rw-r--r--WebCore/loader/icon/IconFetcher.cpp5
-rw-r--r--WebCore/loader/icon/IconLoader.cpp10
-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.cpp2
-rw-r--r--WebCore/loader/loader.cpp52
-rw-r--r--WebCore/loader/loader.h11
103 files changed, 4556 insertions, 2125 deletions
diff --git a/WebCore/loader/Cache.cpp b/WebCore/loader/Cache.cpp
index fdd9b25..521d075 100644
--- a/WebCore/loader/Cache.cpp
+++ b/WebCore/loader/Cache.cpp
@@ -86,6 +86,10 @@ static CachedResource* createResource(CachedResource::Type type, const KURL& url
case CachedResource::XBLStyleSheet:
return new CachedXBLDocument(url.string());
#endif
+#if ENABLE(LINK_PREFETCH)
+ case CachedResource::LinkPrefetch:
+ return new CachedResource(url.string(), CachedResource::LinkPrefetch);
+#endif
default:
break;
}
diff --git a/WebCore/loader/Cache.h b/WebCore/loader/Cache.h
index 0a5b74d..23aad1e 100644
--- a/WebCore/loader/Cache.h
+++ b/WebCore/loader/Cache.h
@@ -28,12 +28,12 @@
#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 {
diff --git a/WebCore/loader/CachedCSSStyleSheet.cpp b/WebCore/loader/CachedCSSStyleSheet.cpp
index b2e03b9..7866efd 100644
--- a/WebCore/loader/CachedCSSStyleSheet.cpp
+++ b/WebCore/loader/CachedCSSStyleSheet.cpp
@@ -31,6 +31,7 @@
#include "CachedResourceClientWalker.h"
#include "HTTPParsers.h"
#include "TextResourceDecoder.h"
+#include "SharedBuffer.h"
#include "loader.h"
#include <wtf/Vector.h>
@@ -51,7 +52,7 @@ CachedCSSStyleSheet::~CachedCSSStyleSheet()
void CachedCSSStyleSheet::didAddClient(CachedResourceClient *c)
{
- if (!m_loading)
+ if (!isLoading())
c->setCSSStyleSheet(m_url, m_response.url(), m_decoder->encoding().name(), this);
}
@@ -99,7 +100,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 +108,7 @@ void CachedCSSStyleSheet::data(PassRefPtr<SharedBuffer> data, bool allDataReceiv
void CachedCSSStyleSheet::checkNotify()
{
- if (m_loading)
+ if (isLoading())
return;
CachedResourceClientWalker w(m_clients);
@@ -117,8 +118,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/CachedCSSStyleSheet.h
index 908c4c0..f5bf042 100644
--- a/WebCore/loader/CachedCSSStyleSheet.h
+++ b/WebCore/loader/CachedCSSStyleSheet.h
@@ -51,8 +51,6 @@ namespace WebCore {
virtual void data(PassRefPtr<SharedBuffer> data, bool allDataReceived);
virtual void error();
- virtual bool schedule() const { return true; }
-
void checkNotify();
private:
diff --git a/WebCore/loader/CachedFont.cpp b/WebCore/loader/CachedFont.cpp
index 3d9eeb9..272166e 100644
--- a/WebCore/loader/CachedFont.cpp
+++ b/WebCore/loader/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))) || PLATFORM(HAIKU) || OS(WINCE) || PLATFORM(ANDROID)
#define STORE_FONT_CUSTOM_PLATFORM_DATA
#endif
#include "Cache.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"
@@ -73,12 +74,12 @@ CachedFont::~CachedFont()
void CachedFont::load(DocLoader*)
{
// 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,7 +90,7 @@ 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();
}
@@ -107,10 +108,10 @@ 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;
@@ -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/CachedFont.h
index 05b28f3..01c8c9c 100644
--- a/WebCore/loader/CachedFont.h
+++ b/WebCore/loader/CachedFont.h
@@ -57,8 +57,6 @@ public:
virtual void allClientsRemoved();
- virtual bool schedule() const { return true; }
-
void checkNotify();
void beginLoadIfNeeded(DocLoader* dl);
diff --git a/WebCore/loader/CachedImage.cpp b/WebCore/loader/CachedImage.cpp
index dd93041..97b80f2 100644
--- a/WebCore/loader/CachedImage.cpp
+++ b/WebCore/loader/CachedImage.cpp
@@ -34,6 +34,7 @@
#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()
@@ -88,7 +89,7 @@ void CachedImage::load(DocLoader* docLoader)
#endif
CachedResource::load(docLoader, 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)
@@ -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,13 @@ 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)
+ } else if (m_image && !errorOccurred())
m_image->destroyDecodedData();
}
diff --git a/WebCore/loader/CachedImage.h b/WebCore/loader/CachedImage.h
index 2aa35ac..eb55955 100644
--- a/WebCore/loader/CachedImage.h
+++ b/WebCore/loader/CachedImage.h
@@ -25,7 +25,6 @@
#include "CachedResource.h"
#include "ImageObserver.h"
-#include "Image.h"
#include "IntRect.h"
#include "Timer.h"
#include <wtf/Vector.h>
@@ -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
diff --git a/WebCore/loader/CachedMetadata.h b/WebCore/loader/CachedMetadata.h
new file mode 100644
index 0000000..d26539e
--- /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<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/CachedResource.cpp b/WebCore/loader/CachedResource.cpp
index 640d1f7..887b0b5 100644
--- a/WebCore/loader/CachedResource.cpp
+++ b/WebCore/loader/CachedResource.cpp
@@ -25,13 +25,18 @@
#include "CachedResource.h"
#include "Cache.h"
+#include "CachedMetadata.h"
+#include "CachedResourceClient.h"
+#include "CachedResourceClientWalker.h"
#include "CachedResourceHandle.h"
#include "DocLoader.h"
#include "Frame.h"
-#include "FrameLoader.h"
+#include "FrameLoaderClient.h"
#include "KURL.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 +53,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_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_docLoader(0)
- , m_handleCount(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()
@@ -102,7 +102,7 @@ CachedResource::~CachedResource()
if (m_docLoader)
m_docLoader->removeCachedResource(this);
}
-
+
void CachedResource::load(DocLoader* docLoader, bool incremental, SecurityCheckPolicy securityCheck, bool sendResourceLoadCallbacks)
{
m_sendResourceLoadCallbacks = sendResourceLoadCallbacks;
@@ -110,6 +110,16 @@ void CachedResource::load(DocLoader* docLoader, bool incremental, SecurityCheckP
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 +173,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 +216,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());
@@ -383,7 +427,7 @@ void CachedResource::updateResponseAfterRevalidation(const ResourceResponse& val
m_response.setHTTPHeaderField(it->first, it->second);
}
}
-
+
bool CachedResource::canUseCacheValidator() const
{
if (m_loading || m_errorOccurred)
@@ -441,9 +485,9 @@ bool CachedResource::makePurgeable(bool purgeable)
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;
}
diff --git a/WebCore/loader/CachedResource.h b/WebCore/loader/CachedResource.h
index 0f46a62..4b83a8e 100644
--- a/WebCore/loader/CachedResource.h
+++ b/WebCore/loader/CachedResource.h
@@ -27,7 +27,6 @@
#include "FrameLoaderTypes.h"
#include "PlatformString.h"
#include "ResourceResponse.h"
-#include "SharedBuffer.h"
#include <wtf/HashCountedSet.h>
#include <wtf/HashSet.h>
#include <wtf/OwnPtr.h>
@@ -37,9 +36,11 @@
namespace WebCore {
class Cache;
+class CachedMetadata;
class CachedResourceClient;
class CachedResourceHandleBase;
class DocLoader;
+class Frame;
class InspectorResource;
class Request;
class PurgeableBuffer;
@@ -63,6 +64,9 @@ public:
#if ENABLE(XBL)
, XBL
#endif
+#if ENABLE(LINK_PREFETCH)
+ , LinkPrefetch
+#endif
};
enum Status {
@@ -81,12 +85,12 @@ public:
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 +103,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,18 +158,29 @@ 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() { }
@@ -200,11 +226,6 @@ protected:
RefPtr<SharedBuffer> m_data;
OwnPtr<PurgeableBuffer> m_purgeableData;
- Type m_type;
- Status m_status;
-
- bool m_errorOccurred;
-
private:
void addClientToSet(CachedResourceClient*);
@@ -217,27 +238,34 @@ private:
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 : 3; // Status
+
#ifndef NDEBUG
bool m_deleted;
unsigned m_lruIndex;
#endif
-private:
CachedResource* m_nextInAllResourcesList;
CachedResource* m_prevInAllResourcesList;
@@ -246,7 +274,6 @@ private:
DocLoader* m_docLoader; // 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/CachedResourceClient.h
index be3f87e..40a6a06 100644
--- a/WebCore/loader/CachedResourceClient.h
+++ b/WebCore/loader/CachedResourceClient.h
@@ -26,6 +26,7 @@
#define CachedResourceClient_h
#include <wtf/FastAllocBase.h>
+#include <wtf/Forward.h>
#if ENABLE(XBL)
namespace XBL {
@@ -39,7 +40,6 @@ namespace WebCore {
class CachedFont;
class CachedResource;
class CachedImage;
- class String;
class Image;
class IntRect;
class KURL;
diff --git a/WebCore/loader/CachedScript.cpp b/WebCore/loader/CachedScript.cpp
index 31483d6..58895d6 100644
--- a/WebCore/loader/CachedScript.cpp
+++ b/WebCore/loader/CachedScript.cpp
@@ -29,6 +29,7 @@
#include "CachedResourceClient.h"
#include "CachedResourceClientWalker.h"
+#include "SharedBuffer.h"
#include "TextResourceDecoder.h"
#include <wtf/Vector.h>
@@ -49,12 +50,6 @@ CachedScript::~CachedScript()
{
}
-void CachedScript::didAddClient(CachedResourceClient* c)
-{
- if (!m_loading)
- c->notifyFinished(this);
-}
-
void CachedScript::allClientsRemoved()
{
m_decodedDataDeletionTimer.startOneShot(0);
@@ -79,7 +74,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 +85,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 +101,8 @@ void CachedScript::checkNotify()
void CachedScript::error()
{
- m_loading = false;
- m_errorOccurred = true;
+ setLoading(false);
+ setErrorOccurred(true);
checkNotify();
}
diff --git a/WebCore/loader/CachedScript.h b/WebCore/loader/CachedScript.h
index 13afa89..beab508 100644
--- a/WebCore/loader/CachedScript.h
+++ b/WebCore/loader/CachedScript.h
@@ -41,7 +41,6 @@ namespace WebCore {
const String& script();
- virtual void didAddClient(CachedResourceClient*);
virtual void allClientsRemoved();
virtual void setEncoding(const String&);
@@ -49,8 +48,6 @@ namespace WebCore {
virtual void data(PassRefPtr<SharedBuffer> data, bool allDataReceived);
virtual void error();
- virtual bool schedule() const { return false; }
-
void checkNotify();
virtual void destroyDecodedData();
diff --git a/WebCore/loader/CachedXBLDocument.h b/WebCore/loader/CachedXBLDocument.h
index b92a255..9a8d366 100644
--- a/WebCore/loader/CachedXBLDocument.h
+++ b/WebCore/loader/CachedXBLDocument.h
@@ -51,8 +51,6 @@ namespace WebCore {
virtual void data(Vector<char>&, bool allDataReceived);
virtual void error();
- virtual bool schedule() const { return true; }
-
void checkNotify();
protected:
diff --git a/WebCore/loader/CachedXSLStyleSheet.cpp b/WebCore/loader/CachedXSLStyleSheet.cpp
index 59c3907..5b30e30 100644
--- a/WebCore/loader/CachedXSLStyleSheet.cpp
+++ b/WebCore/loader/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/CachedXSLStyleSheet.h
index b6b0585..a0b5477 100644
--- a/WebCore/loader/CachedXSLStyleSheet.h
+++ b/WebCore/loader/CachedXSLStyleSheet.h
@@ -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/CrossOriginAccessControl.cpp b/WebCore/loader/CrossOriginAccessControl.cpp
index 01596e2..630f2b7 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 {
@@ -92,7 +92,7 @@ bool isOnAccessControlResponseHeaderWhitelist(const String& name)
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/DocLoader.cpp b/WebCore/loader/DocLoader.cpp
index 8c0a1b2..f6588c7 100644
--- a/WebCore/loader/DocLoader.cpp
+++ b/WebCore/loader/DocLoader.cpp
@@ -34,7 +34,6 @@
#include "CachedScript.h"
#include "CachedXSLStyleSheet.h"
#include "Console.h"
-#include "CString.h"
#include "Document.h"
#include "DOMWindow.h"
#include "HTMLElement.h"
@@ -44,6 +43,7 @@
#include "loader.h"
#include "SecurityOrigin.h"
#include "Settings.h"
+#include <wtf/text/CString.h>
#define PRELOAD_DEBUG 0
@@ -176,6 +176,13 @@ CachedXBLDocument* DocLoader::requestXBLDocument(const String& url)
}
#endif
+#if ENABLE(LINK_PREFETCH)
+CachedResource* DocLoader::requestLinkPrefetch(const String& url)
+{
+ return requestResource(CachedResource::LinkPrefetch, url, String());
+}
+#endif
+
bool DocLoader::canRequest(CachedResource::Type type, const KURL& url)
{
// Some types of resources can be loaded only from the same origin. Other
@@ -186,6 +193,9 @@ 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;
@@ -236,6 +246,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;
@@ -402,13 +417,19 @@ void DocLoader::checkCacheObjectStatus(CachedResource* resource)
frame()->loader()->loadedResourceFromMemoryCache(resource);
}
-void DocLoader::incrementRequestCount()
+void DocLoader::incrementRequestCount(const CachedResource* res)
{
+ if (res->isPrefetch())
+ return;
+
++m_requestCount;
}
-void DocLoader::decrementRequestCount()
+void DocLoader::decrementRequestCount(const CachedResource* res)
{
+ if (res->isPrefetch())
+ return;
+
--m_requestCount;
ASSERT(m_requestCount > -1);
}
@@ -451,13 +472,17 @@ void DocLoader::requestPreload(CachedResource::Type type, const String& url, con
{
String encoding;
if (type == CachedResource::Script || type == CachedResource::CSSStyleSheet)
- encoding = charset.isEmpty() ? m_doc->frame()->loader()->encoding() : charset;
+ encoding = charset.isEmpty() ? m_doc->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.set(new ListHashSet<CachedResource*>);
+ m_preloads->add(resource);
+
#if PRELOAD_DEBUG
printf("PRELOADING %s\n", resource->url().latin1().data());
#endif
@@ -468,8 +493,11 @@ void DocLoader::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())
diff --git a/WebCore/loader/DocLoader.h b/WebCore/loader/DocLoader.h
index 06d8a47..06b02c9 100644
--- a/WebCore/loader/DocLoader.h
+++ b/WebCore/loader/DocLoader.h
@@ -29,10 +29,10 @@
#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 {
@@ -47,8 +47,7 @@ class ImageLoader;
class KURL;
// The DocLoader manages the loading of scripts/images/stylesheets for a single document.
-class DocLoader : public Noncopyable
-{
+class DocLoader : public Noncopyable {
friend class Cache;
friend class ImageLoader;
@@ -68,6 +67,9 @@ public:
#if ENABLE(XBL)
CachedXBLDocument* requestXBLDocument(const String &url);
#endif
+#if ENABLE(LINK_PREFETCH)
+ CachedResource* requestLinkPrefetch(const String &url);
+#endif
// Logs an access denied message to the console for the specified URL.
void printAccessDeniedMessage(const KURL& url) const;
@@ -98,8 +100,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();
@@ -123,7 +125,7 @@ private:
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/DocumentLoadTiming.h b/WebCore/loader/DocumentLoadTiming.h
new file mode 100644
index 0000000..2d4b0fa
--- /dev/null
+++ b/WebCore/loader/DocumentLoadTiming.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ *
+ * 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 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
+ * 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 DocumentLoadTiming_h
+#define DocumentLoadTiming_h
+
+namespace WebCore {
+
+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)
+ {
+ }
+
+ double navigationStart;
+ double unloadEventEnd;
+ double redirectStart;
+ double redirectEnd;
+ short redirectCount;
+ double fetchStart;
+ double responseEnd;
+ double loadEventStart;
+ double loadEventEnd;
+};
+
+}
+
+#endif
diff --git a/WebCore/loader/DocumentLoader.cpp b/WebCore/loader/DocumentLoader.cpp
index dca416e..26d66e8 100644
--- a/WebCore/loader/DocumentLoader.cpp
+++ b/WebCore/loader/DocumentLoader.cpp
@@ -39,6 +39,7 @@
#include "CachedPage.h"
#include "DocLoader.h"
#include "Document.h"
+#include "DocumentParser.h"
#include "Event.h"
#include "Frame.h"
#include "FrameLoader.h"
@@ -50,7 +51,6 @@
#include "PlatformString.h"
#include "Settings.h"
#include "SharedBuffer.h"
-#include "XMLTokenizer.h"
#include <wtf/Assertions.h>
#include <wtf/unicode/Unicode.h>
@@ -86,6 +86,7 @@ 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)
@@ -259,7 +260,7 @@ void DocumentLoader::commitIfReady()
{
if (m_gotFirstByte && !m_committed) {
m_committed = true;
- frameLoader()->commitProvisionalLoad(0);
+ frameLoader()->commitProvisionalLoad();
}
}
@@ -269,7 +270,7 @@ void DocumentLoader::finishedLoading()
commitIfReady();
if (FrameLoader* loader = frameLoader()) {
loader->finishedLoadingDocument(this);
- loader->end();
+ loader->writer()->end();
}
}
@@ -311,7 +312,7 @@ void DocumentLoader::setupForReplaceByMIMEType(const String& newMIMEType)
}
frameLoader()->finishedLoadingDocument(this);
- m_frame->loader()->end();
+ m_frame->loader()->writer()->end();
frameLoader()->setReplacing();
m_gotFirstByte = false;
@@ -399,8 +400,8 @@ bool DocumentLoader::isLoadingInAPISense() const
Document* doc = m_frame->document();
if (doc->docLoader()->requestCount())
return true;
- if (Tokenizer* tok = doc->tokenizer())
- if (tok->processingData())
+ if (DocumentParser* parser = doc->parser())
+ if (parser->processingData())
return true;
}
return frameLoader()->subframeIsLoading();
@@ -617,6 +618,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.
diff --git a/WebCore/loader/DocumentLoader.h b/WebCore/loader/DocumentLoader.h
index 440cfc4..bc81350 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"
@@ -108,9 +109,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 +158,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;
@@ -198,11 +203,18 @@ namespace WebCore {
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(); }
+
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
ApplicationCacheHost* applicationCacheHost() const { return m_applicationCacheHost.get(); }
#endif
@@ -259,8 +271,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 +307,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..16f114d 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(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();
+ 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..d99f340
--- /dev/null
+++ b/WebCore/loader/DocumentWriter.cpp
@@ -0,0 +1,251 @@
+/*
+ * 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()->setParseMode(Document::Strict);
+ }
+
+ // 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::reportDataRecieved()
+{
+ 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();
+}
+
+} // namespace WebCore
diff --git a/WebCore/loader/DocumentWriter.h b/WebCore/loader/DocumentWriter.h
new file mode 100644
index 0000000..b1007ef
--- /dev/null
+++ b/WebCore/loader/DocumentWriter.h
@@ -0,0 +1,89 @@
+/*
+ * 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 reportDataRecieved();
+
+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..0d30713 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,26 @@
#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 "InspectorClient.h"
#include "PluginHalterClient.h"
+#include "PopupMenu.h"
#include "ResourceError.h"
-#include "SharedBuffer.h"
+#include "SearchPopupMenu.h"
+
+#if USE(GLES2_RENDERING)
+#include "GLES2Context.h"
+#endif
/*
This file holds empty Client stubs for use by WebCore.
@@ -58,6 +65,25 @@
namespace WebCore {
+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,11 +96,11 @@ 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; }
@@ -114,17 +140,21 @@ 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()); }
+
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&) { }
+
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 +173,7 @@ public:
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
virtual void reachedMaxAppCacheSize(int64_t) { }
+ virtual void reachedApplicationCacheOriginQuota(SecurityOrigin*) { }
#endif
#if ENABLE(NOTIFICATIONS)
@@ -150,6 +181,7 @@ public:
#endif
virtual void runOpenPanel(Frame*, PassRefPtr<FileChooser>) { }
+ virtual void chooseIconForFiles(const Vector<String>&, FileChooser*) { }
virtual void formStateDidChange(const Node*) { }
@@ -158,12 +190,12 @@ 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*) {};
@@ -171,6 +203,14 @@ public:
virtual void scheduleCompositingLayerSync() {};
#endif
+#if USE(GLES2_RENDERING)
+ virtual PassOwnPtr<GLES2Context> getOnscreenGLES2Context() { return 0; }
+ virtual PassOwnPtr<GLES2Context> getOffscreenGLES2Context() { return 0; }
+#endif
+
+#if PLATFORM(WIN)
+ virtual void setLastSetCursorToCurrentCursor() { }
+#endif
#if ENABLE(TOUCH_EVENTS)
virtual void needTouchEvents(bool) { }
#endif
@@ -199,12 +239,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 +260,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&) { }
@@ -236,6 +279,7 @@ public:
virtual void dispatchUnableToImplementPolicy(const ResourceError&) { }
+ virtual void dispatchWillSendSubmitEvent(HTMLFormElement*) { }
virtual void dispatchWillSubmitForm(FramePolicyFunction, PassRefPtr<FormState>) { }
virtual void dispatchDidLoadMainResource(DocumentLoader*) { }
@@ -301,8 +345,14 @@ 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() { }
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,14 +362,18 @@ public:
virtual void documentElementAvailable() { }
virtual void didPerformFirstNavigation() const { }
- virtual void registerForIconNotification(bool) { }
-
#if USE(V8)
virtual void didCreateScriptContextForFrame() { }
virtual void didDestroyScriptContextForFrame() { }
virtual void didCreateIsolatedScriptContext() { }
#endif
+ virtual void registerForIconNotification(bool) { }
+
+#ifdef ANDROID_APPLE_TOUCH_ICON
+ virtual void dispatchDidReceiveTouchIconURL(const String& url, bool precomposed) { }
+#endif
+
#if PLATFORM(MAC)
virtual NSCachedURLResponse* willCacheResponse(DocumentLoader*, unsigned long, NSCachedURLResponse* response) const { return response; }
#endif
@@ -428,6 +482,7 @@ public:
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 +530,33 @@ 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; }
+};
+
+class EmptyDeviceOrientationClient : public DeviceOrientationClient {
+public:
+ virtual void setController(DeviceOrientationController*) { }
+ virtual void startUpdating() { }
+ virtual void stopUpdating() { }
+ virtual DeviceOrientation* lastOrientation() const { return 0; }
};
}
#endif // EmptyClients_h
-
diff --git a/WebCore/loader/FTPDirectoryDocument.cpp b/WebCore/loader/FTPDirectoryDocument.cpp
index 62173f5..5c7102c 100644
--- a/WebCore/loader/FTPDirectoryDocument.cpp
+++ b/WebCore/loader/FTPDirectoryDocument.cpp
@@ -27,10 +27,9 @@
#include "FTPDirectoryDocument.h"
#include "CharacterNames.h"
-#include "CString.h"
+#include "HTMLDocumentParser.h"
#include "HTMLNames.h"
#include "HTMLTableElement.h"
-#include "HTMLTokenizer.h"
#include "LocalizedStrings.h"
#include "Logging.h"
#include "FTPDirectoryParser.h"
@@ -39,6 +38,7 @@
#include "SharedBuffer.h"
#include "Text.h"
+#include <wtf/text/CString.h>
#include <wtf/CurrentTime.h>
#include <wtf/StdLibExtras.h>
@@ -48,13 +48,13 @@ namespace WebCore {
using namespace HTMLNames;
-class FTPDirectoryTokenizer : public HTMLTokenizer {
+class FTPDirectoryDocumentParser : public HTMLDocumentParser {
public:
- FTPDirectoryTokenizer(HTMLDocument*);
+ FTPDirectoryDocumentParser(HTMLDocument*);
- virtual void write(const SegmentedString&, bool appendData);
+ virtual void append(const SegmentedString&);
virtual void finish();
-
+
virtual bool isWaitingForScripts() const { return false; }
inline void checkBuffer(int len = 10)
@@ -70,7 +70,7 @@ public:
}
private:
- // The tokenizer will attempt to load the document template specified via the preference
+ // The parser 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();
@@ -79,8 +79,7 @@ private:
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;
@@ -94,64 +93,63 @@ private:
ListState m_listState;
};
-FTPDirectoryTokenizer::FTPDirectoryTokenizer(HTMLDocument* doc)
- : HTMLTokenizer(doc, false)
- , m_doc(doc)
+FTPDirectoryDocumentParser::FTPDirectoryDocumentParser(HTMLDocument* document)
+ : HTMLDocumentParser(document, false)
, 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)
+void FTPDirectoryDocumentParser::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);
+
+ RefPtr<Element> element = document()->createElement(tdTag, false);
+ element->appendChild(Text::create(document(), 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 = document()->createElement(tdTag, false);
+ element->appendChild(Text::create(document(), 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 = document()->createElement(tdTag, false);
+ element->appendChild(Text::create(document(), size), ec);
element->setAttribute("class", "ftpDirectoryFileSize", ec);
rowElement->appendChild(element, ec);
}
-PassRefPtr<Element> FTPDirectoryTokenizer::createTDForFilename(const String& filename)
+PassRefPtr<Element> FTPDirectoryDocumentParser::createTDForFilename(const String& filename)
{
ExceptionCode ec;
-
- String fullURL = m_doc->baseURL().string();
+
+ String fullURL = document()->baseURL().string();
if (fullURL[fullURL.length() - 1] == '/')
fullURL.append(filename);
else
fullURL.append("/" + filename);
- RefPtr<Element> anchorElement = m_doc->createElement(aTag, false);
+ RefPtr<Element> anchorElement = document()->createElement(aTag, false);
anchorElement->setAttribute("href", fullURL, ec);
- anchorElement->appendChild(Text::create(m_doc, filename), ec);
-
- RefPtr<Element> tdElement = m_doc->createElement(tdTag, false);
+ anchorElement->appendChild(Text::create(document(), filename), ec);
+
+ RefPtr<Element> tdElement = document()->createElement(tdTag, false);
tdElement->appendChild(anchorElement, ec);
-
+
return tdElement.release();
}
@@ -159,18 +157,18 @@ 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);
}
@@ -179,19 +177,19 @@ 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;
}
@@ -200,11 +198,11 @@ 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;
@@ -216,15 +214,15 @@ static String processFileDateString(const FTPTime& fileTime)
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)
@@ -237,48 +235,48 @@ static String processFileDateString(const FTPTime& fileTime)
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)
+void FTPDirectoryDocumentParser::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);
}
@@ -292,9 +290,9 @@ static inline PassRefPtr<SharedBuffer> createTemplateDocumentData(Settings* sett
return buffer.release();
}
-bool FTPDirectoryTokenizer::loadDocumentTemplate()
+bool FTPDirectoryDocumentParser::loadDocumentTemplate()
{
- DEFINE_STATIC_LOCAL(RefPtr<SharedBuffer>, templateDocumentData, (createTemplateDocumentData(m_doc->settings())));
+ DEFINE_STATIC_LOCAL(RefPtr<SharedBuffer>, templateDocumentData, (createTemplateDocumentData(document()->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.
@@ -303,13 +301,10 @@ bool FTPDirectoryTokenizer::loadDocumentTemplate()
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");
+
+ HTMLDocumentParser::insert(String(templateDocumentData->data(), templateDocumentData->size()));
+
+ RefPtr<Element> tableElement = document()->getElementById("ftpDirectoryTable");
if (!tableElement)
LOG_ERROR("Unable to find element by id \"ftpDirectoryTable\" in the template document.");
else if (!tableElement->hasTagName(tableTag))
@@ -322,7 +317,7 @@ bool FTPDirectoryTokenizer::loadDocumentTemplate()
return true;
// Otherwise create one manually
- tableElement = m_doc->createElement(tableTag, false);
+ tableElement = document()->createElement(tableTag, false);
m_tableElement = static_cast<HTMLTableElement*>(tableElement.get());
ExceptionCode ec;
m_tableElement->setAttribute("id", "ftpDirectoryTable", ec);
@@ -330,35 +325,34 @@ bool FTPDirectoryTokenizer::loadDocumentTemplate()
// 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())
+ if (Element* body = document()->body())
body->appendChild(m_tableElement, ec);
else
- m_doc->appendChild(m_tableElement, ec);
-
+ document()->appendChild(m_tableElement, ec);
+
return true;
}
-void FTPDirectoryTokenizer::createBasicDocument()
+void FTPDirectoryDocumentParser::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);
-
+ RefPtr<Element> bodyElement = document()->createElement(bodyTag, false);
+
ExceptionCode ec;
- m_doc->appendChild(bodyElement, ec);
-
- RefPtr<Element> tableElement = m_doc->createElement(tableTag, false);
+ document()->appendChild(bodyElement, ec);
+
+ RefPtr<Element> tableElement = document()->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*/)
-{
+void FTPDirectoryDocumentParser::append(const SegmentedString& source)
+{
// 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) {
@@ -366,14 +360,14 @@ void FTPDirectoryTokenizer::write(const SegmentedString& s, bool /*appendData*/)
createBasicDocument();
ASSERT(m_tableElement);
}
-
+
bool foundNewLine = false;
-
+
m_dest = m_buffer;
- SegmentedString str = s;
+ SegmentedString str = source;
while (!str.isEmpty()) {
UChar c = *str;
-
+
if (c == '\r') {
*m_dest++ = '\n';
foundNewLine = true;
@@ -388,13 +382,13 @@ void FTPDirectoryTokenizer::write(const SegmentedString& s, bool /*appendData*/)
*m_dest++ = c;
m_skipLF = false;
}
-
+
str.advance();
-
+
// Maybe enlarge the buffer
checkBuffer();
}
-
+
if (!foundNewLine) {
m_dest = m_buffer;
return;
@@ -402,7 +396,7 @@ void FTPDirectoryTokenizer::write(const SegmentedString& s, bool /*appendData*/)
UChar* start = m_buffer;
UChar* cursor = start;
-
+
while (cursor < m_dest) {
if (*cursor == '\n') {
m_carryOver.append(String(start, cursor - start));
@@ -414,37 +408,37 @@ void FTPDirectoryTokenizer::write(const SegmentedString& s, bool /*appendData*/)
} 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()
+void FTPDirectoryDocumentParser::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();
+
+ HTMLDocumentParser::finish();
}
-FTPDirectoryDocument::FTPDirectoryDocument(Frame* frame)
- : HTMLDocument(frame)
+FTPDirectoryDocument::FTPDirectoryDocument(Frame* frame, const KURL& url)
+ : HTMLDocument(frame, url)
{
#ifndef NDEBUG
LogFTP.state = WTFLogChannelOn;
#endif
}
-Tokenizer* FTPDirectoryDocument::createTokenizer()
+DocumentParser* FTPDirectoryDocument::createParser()
{
- return new FTPDirectoryTokenizer(this);
+ return new FTPDirectoryDocumentParser(this);
}
}
diff --git a/WebCore/loader/FTPDirectoryDocument.h b/WebCore/loader/FTPDirectoryDocument.h
index b208c4e..920f870 100644
--- a/WebCore/loader/FTPDirectoryDocument.h
+++ b/WebCore/loader/FTPDirectoryDocument.h
@@ -33,14 +33,14 @@ class DOMImplementation;
class FTPDirectoryDocument : public HTMLDocument {
public:
- static PassRefPtr<FTPDirectoryDocument> create(Frame* frame)
+ static PassRefPtr<FTPDirectoryDocument> create(Frame* frame, const KURL& url)
{
- return adoptRef(new FTPDirectoryDocument(frame));
+ return adoptRef(new FTPDirectoryDocument(frame, url));
}
private:
- FTPDirectoryDocument(Frame*);
- virtual Tokenizer* createTokenizer();
+ FTPDirectoryDocument(Frame*, const KURL&);
+ virtual DocumentParser* createParser();
};
} // namespace WebCore
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..22e89d7
--- /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 "CSSHelper.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 "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 = deprecatedParseURL(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(domFormData->items(), domFormData->encoding(), document);
+ boundary = formData->boundary().data();
+ } else {
+ formData = FormData::create(domFormData->items(), 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..dc2c68c 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>
@@ -39,7 +39,7 @@
#include "ArchiveFactory.h"
#endif
#include "BackForwardList.h"
-#include "CString.h"
+#include "BeforeUnloadEvent.h"
#include "Cache.h"
#include "CachedPage.h"
#include "Chrome.h"
@@ -47,6 +47,7 @@
#include "DOMWindow.h"
#include "DocLoader.h"
#include "Document.h"
+#include "DocumentLoadTiming.h"
#include "DocumentLoader.h"
#include "Editor.h"
#include "EditorClient.h"
@@ -55,15 +56,17 @@
#include "EventNames.h"
#include "FloatRect.h"
#include "FormState.h"
+#include "FormSubmission.h"
#include "Frame.h"
#include "FrameLoadRequest.h"
#include "FrameLoaderClient.h"
#include "FrameTree.h"
#include "FrameView.h"
#include "HTMLAnchorElement.h"
-#include "HTMLAppletElement.h"
#include "HTMLFormElement.h"
-#include "HTMLFrameElement.h"
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+#include "HTMLMediaElement.h"
+#endif
#include "HTMLNames.h"
#include "HTMLObjectElement.h"
#include "HTTPParsers.h"
@@ -83,31 +86,26 @@
#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>
+#if ENABLE(SHARED_WORKERS)
+#include "SharedWorkerRepository.h"
+#endif
#if ENABLE(SVG)
#include "SVGDocument.h"
@@ -126,16 +124,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)
@@ -171,40 +171,48 @@ static inline bool canReferToParentFrameEncoding(const Frame* frame, const Frame
return parentFrame && parentFrame->document()->securityOrigin()->canAccess(frame->document()->securityOrigin());
}
+// 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 frame->document() && frame->document()->securityOrigin()->isSandboxed(mask);
+}
+
FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client)
: m_frame(frame)
, m_client(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
@@ -224,22 +232,22 @@ FrameLoader::~FrameLoader()
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();
}
void FrameLoader::setDefersLoading(bool defers)
@@ -257,71 +265,6 @@ void FrameLoader::setDefersLoading(bool defers)
}
}
-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);
@@ -332,21 +275,22 @@ void FrameLoader::changeLocation(const KURL& url, const String& referrer, bool l
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, userGesture, 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, bool userGesture, ReferrerPolicy referrerPolicy)
+{
+ urlSelected(ResourceRequest(url), passedTarget, triggeringEvent, lockHistory, lockBackForwardList, userGesture, 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, bool userGesture, ReferrerPolicy referrerPolicy, ShouldReplaceDocumentIfJavaScriptURL shouldReplaceDocumentIfJavaScriptURL)
{
ASSERT(!m_suppressOpenerInNewFrame);
- if (m_frame->script()->executeIfJavaScriptURL(request.url(), userGesture, false))
+ if (m_frame->script()->executeIfJavaScriptURL(request.url(), userGesture, shouldReplaceDocumentIfJavaScriptURL))
return;
String target = passedTarget;
@@ -366,125 +310,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);
-
- 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);
+ ASSERT(submission->method() == FormSubmission::PostMethod || submission->method() == FormSubmission::GetMethod);
- 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(), false, 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 +362,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;
- }
-
- 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);
+ m_submittedFormURL = submission->action();
}
- 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->redirectScheduler()->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 +385,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 +411,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)
@@ -589,10 +442,7 @@ 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);
-
+ // FIXME: This will cancel redirection timer, which really needs to be restarted when restoring the frame from b/f cache.
m_frame->redirectScheduler()->cancel();
}
@@ -602,8 +452,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)
@@ -664,9 +514,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,7 +536,8 @@ 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.
@@ -707,14 +560,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 +582,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,14 +590,12 @@ 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();
@@ -763,16 +606,13 @@ void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects, boo
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);
dispatchDidCommitLoad();
dispatchDidClearWindowObjectsInAllWorlds();
@@ -803,193 +643,51 @@ void FrameLoader::receivedFirstData()
m_frame->redirectScheduler()->scheduleRedirect(delay, url);
}
-const String& FrameLoader::responseMIMEType() const
-{
- return m_responseMIMEType;
-}
-
-void FrameLoader::setResponseMIMEType(const String& type)
-{
- m_responseMIMEType = type;
-}
-
-void FrameLoader::begin()
-{
- begin(KURL());
-}
-
-void FrameLoader::begin(const KURL& url, bool dispatch, SecurityOrigin* origin)
+void FrameLoader::setURL(const KURL& url)
{
- // 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;
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()->docLoader()->setAutoLoadImages(settings && settings->loadsImagesAutomatically());
#ifdef ANDROID_BLOCK_NETWORK_IMAGE
- document->docLoader()->setBlockNetworkImage(settings && settings->blockNetworkImage());
+ m_frame->document()->docLoader()->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 +757,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 +772,7 @@ void FrameLoader::commitIconURLToIconDatabase(const KURL& icon)
void FrameLoader::finishedParsing()
{
- if (m_creatingInitialEmptyDocument)
+ if (m_stateMachine.creatingInitialEmptyDocument())
return;
m_frame->injectUserScripts(InjectAtDocumentEnd);
@@ -1245,11 +943,7 @@ void FrameLoader::loadURLIntoChildFrame(const KURL& url, const String& referer,
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 +969,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 +982,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 +993,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 +1008,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;
@@ -1489,7 +1071,8 @@ void FrameLoader::provisionalLoadStarted()
if (!m_frame->tree()->parent())
android::TimeCounter::reset();
#endif
- m_firstLayoutDone = false;
+ if (m_stateMachine.firstLayoutDone())
+ m_stateMachine.advanceTo(FrameLoaderStateMachine::CommittedFirstRealLoad);
m_frame->redirectScheduler()->cancel(true);
m_client->provisionalLoadStarted();
}
@@ -1497,9 +1080,9 @@ void FrameLoader::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,12 +1090,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)
@@ -1520,7 +1101,7 @@ void FrameLoader::addData(const char* bytes, int length)
ASSERT(m_workingURL.isEmpty());
ASSERT(m_frame->document());
ASSERT(m_frame->document()->parsing());
- write(bytes, length);
+ writer()->addData(bytes, length);
}
#if ENABLE(WML)
@@ -1534,208 +1115,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 +1155,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 +1169,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 +1185,15 @@ void FrameLoader::loadInSameDocument(const KURL& url, SerializedScriptValue* sta
checkLoadComplete();
}
+ m_client->dispatchDidNavigateWithinPage();
+
if (stateObject) {
m_frame->document()->statePopped(stateObject);
m_client->dispatchDidPopStateWithinPage();
}
if (hashChange) {
- m_frame->document()->dispatchWindowEvent(Event::create(eventNames().hashchangeEvent, false, false));
+ m_frame->document()->enqueueHashchangeEvent(oldURL, url);
m_client->dispatchDidChangeLocationWithinPage();
}
@@ -1842,11 +1226,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,7 +1274,7 @@ void FrameLoader::loadFrameRequest(const FrameLoadRequest& request, bool lockHis
referrer = m_outgoingReferrer;
ASSERT(frame()->document());
- if (SecurityOrigin::shouldTreatURLAsLocal(url.string()) && !isFeedWithNestedProtocolInHTTPFamily(url)) {
+ if (SchemeRegistry::shouldTreatURLAsLocal(url.string()) && !isFeedWithNestedProtocolInHTTPFamily(url)) {
if (!SecurityOrigin::canLoad(url, String(), frame()->document()) && !SecurityOrigin::canLoad(url, referrer, 0)) {
FrameLoader::reportLocalLoadFailed(m_frame, url.string());
return;
@@ -1913,17 +1292,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 +1303,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 +1328,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);
@@ -2102,7 +1458,7 @@ void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t
ASSERT(m_frame->view());
- if (m_unloadEventBeingDispatched)
+ if (m_pageDismissalEventBeingDispatched)
return;
policyChecker()->setLoadType(type);
@@ -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;
@@ -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,7 @@ 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::setDocumentLoader(DocumentLoader* loader)
@@ -2478,9 +1839,9 @@ 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(),
@@ -2488,12 +1849,14 @@ void FrameLoader::commitProvisionalLoad(PassRefPtr<CachedPage> prpCachedPage)
// 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 +1868,11 @@ 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());
+ checkCompleted();
+ } else {
KURL url = pdl->substituteData().responseURL();
if (url.isEmpty())
url = pdl->url();
@@ -2595,18 +1960,24 @@ void FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage)
case FrameLoadTypeIndexedBackForward:
if (Page* page = m_frame->page()) {
if (page->backForwardList()) {
+ // 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();
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();
}
@@ -2643,15 +2014,16 @@ 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();
@@ -2690,7 +2062,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,7 +2095,7 @@ 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());
@@ -2735,14 +2107,12 @@ void FrameLoader::open(CachedPage& cachedPage)
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 +2158,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();
@@ -2850,7 +2220,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
@@ -2881,14 +2251,14 @@ void FrameLoader::finishedLoadingDocument(DocumentLoader* loader)
ArchiveResource* mainResource = archive->mainResource();
loader->setParsedArchiveData(mainResource->data());
- m_responseMIMEType = mainResource->mimeType();
+ writer()->setMIMEType(mainResource->mimeType());
closeURL();
didOpenURL(mainResource->url());
String userChosenEncoding = documentLoader()->overrideEncoding();
bool encodingIsUserChosen = !userChosenEncoding.isNull();
- setEncoding(encodingIsUserChosen ? userChosenEncoding : mainResource->textEncoding(), encodingIsUserChosen);
+ writer()->setEncoding(encodingIsUserChosen ? userChosenEncoding : mainResource->textEncoding(), encodingIsUserChosen);
ASSERT(m_frame->document());
@@ -2924,6 +2294,9 @@ bool FrameLoader::subframeIsLoading() const
documentLoader = childLoader->provisionalDocumentLoader();
if (documentLoader && documentLoader->isLoadingInAPISense())
return true;
+ documentLoader = childLoader->policyDocumentLoader();
+ if (documentLoader)
+ return true;
}
return false;
}
@@ -3046,7 +2419,7 @@ void FrameLoader::checkLoadCompleteForThisFrame()
if ((isBackForwardLoadType(m_loadType) || m_loadType == FrameLoadTypeReload || m_loadType == FrameLoadTypeReloadFromOrigin) && page->backForwardList())
history()->restoreScrollPositionAndViewState();
- if (m_creatingInitialEmptyDocument || !m_committedFirstRealDocumentLoad)
+ if (m_stateMachine.creatingInitialEmptyDocument() || !m_stateMachine.committedFirstRealDocumentLoad())
return;
const ResourceError& error = dl->mainDocumentError();
@@ -3103,6 +2476,9 @@ 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();
}
@@ -3113,7 +2489,8 @@ void FrameLoader::didFirstLayout()
if (isBackForwardLoadType(m_loadType) && page->backForwardList())
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 +2509,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()
@@ -3206,18 +2578,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()
@@ -3286,14 +2656,30 @@ void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, FrameLoadTyp
applyUserAgent(request);
- if (loadType == FrameLoadTypeReload) {
+ // 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) {
request.setCachePolicy(ReloadIgnoringCacheData);
request.setHTTPHeaderField("Cache-Control", "max-age=0");
} else if (loadType == FrameLoadTypeReloadFromOrigin) {
request.setCachePolicy(ReloadIgnoringCacheData);
request.setHTTPHeaderField("Cache-Control", "no-cache");
request.setHTTPHeaderField("Pragma", "no-cache");
- } else if (isBackForwardLoadType(loadType) && !request.url().protocolIs("https"))
+ } else if (request.isConditional())
+ request.setCachePolicy(ReloadIgnoringCacheData);
+ else if (isBackForwardLoadType(loadType) && m_stateMachine.committedFirstRealDocumentLoad() && !request.url().protocolIs("https"))
request.setCachePolicy(ReturnCacheDataElseLoad);
if (mainResource)
@@ -3305,7 +2691,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)
@@ -3343,11 +2729,7 @@ void FrameLoader::committedLoad(DocumentLoader* loader, const char* data, int le
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 +2749,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 +2779,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 +2786,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);
@@ -3526,6 +2896,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 +2940,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
@@ -3576,7 +2976,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 +2986,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);
@@ -3650,14 +3052,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 +3066,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;
}
@@ -3700,48 +3104,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
@@ -3767,7 +3145,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 +3175,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 +3197,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 +3234,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:
@@ -3891,12 +3260,11 @@ void FrameLoader::navigateToDifferentDocument(HistoryItem* item, FrameLoadType l
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.
+ // - The HistoryItem corresponds to the same document.
+ // - The HistoryItem is not the same as the current item.
HistoryItem* currentItem = history()->currentItem();
- bool sameDocumentNavigation = (!item->formData() && !(currentItem && currentItem->formData()) && history()->urlsMatchItem(item))
- || (currentItem && item->documentSequenceNumber() == currentItem->documentSequenceNumber());
+ bool sameDocumentNavigation = currentItem && item != currentItem
+ && item->documentSequenceNumber() == currentItem->documentSequenceNumber();
#if ENABLE(WML)
// All WML decks should go through the real load mechanism, not the scroll-to-anchor code
@@ -3961,11 +3329,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 +3353,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 +3364,7 @@ void FrameLoader::dispatchDocumentElementAvailable()
void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds()
{
- if (!m_frame->script()->canExecuteScripts())
+ if (!m_frame->script()->canExecuteScripts(NotAboutToExecuteScript))
return;
Vector<DOMWrapperWorld*> worlds;
@@ -3995,7 +3375,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 +3387,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 +3408,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 +3422,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
@@ -4134,4 +3477,69 @@ 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;
+
+ Page* page = oldPage->chrome()->createWindow(openerFrame, 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;
+}
+
} // namespace WebCore
diff --git a/WebCore/loader/FrameLoader.h b/WebCore/loader/FrameLoader.h
index abe3b3a..639b6cc 100644
--- a/WebCore/loader/FrameLoader.h
+++ b/WebCore/loader/FrameLoader.h
@@ -32,6 +32,8 @@
#define FrameLoader_h
#include "CachePolicy.h"
+#include "DocumentWriter.h"
+#include "FrameLoaderStateMachine.h"
#include "FrameLoaderTypes.h"
#include "HistoryController.h"
#include "PolicyCallback.h"
@@ -39,6 +41,7 @@
#include "RedirectScheduler.h"
#include "ResourceLoadNotifier.h"
#include "ResourceRequest.h"
+#include "SubframeLoader.h"
#include "ThreadableLoader.h"
#include "Timer.h"
#include <wtf/Forward.h>
@@ -58,16 +61,14 @@ class DocumentLoader;
class Event;
class FormData;
class FormState;
+class FormSubmission;
class Frame;
class FrameLoaderClient;
class HistoryItem;
-class HTMLAppletElement;
class HTMLFormElement;
-class HTMLFrameOwnerElement;
class IconLoader;
-class IntSize;
class NavigationAction;
-class RenderPart;
+class ProtectionSpace;
class ResourceError;
class ResourceLoader;
class ResourceResponse;
@@ -79,7 +80,6 @@ class SerializedScriptValue;
class SharedBuffer;
class SubstituteData;
class TextResourceDecoder;
-class Widget;
struct FrameLoadRequest;
struct WindowFeatures;
@@ -98,6 +98,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 +124,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&);
@@ -150,6 +149,9 @@ 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);
@@ -188,12 +190,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();
@@ -214,12 +217,9 @@ 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 urlSelected(const KURL&, const String& target, PassRefPtr<Event>, bool lockHistory, bool lockBackForwardList, bool userGesture, 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 +227,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 +248,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&);
@@ -281,10 +272,8 @@ public:
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 +283,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 +325,14 @@ 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();
+
private:
bool canCachePageContainingThisFrame();
#ifndef NDEBUG
@@ -348,19 +341,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();
@@ -400,33 +385,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, bool userGesture, 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 +415,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 +432,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 +439,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 +456,6 @@ private:
bool m_delegateIsHandlingProvisionalLoadError;
- bool m_firstLayoutDone;
bool m_quickRedirectComing;
bool m_sentRedirectNotification;
bool m_inStopAllLoaders;
@@ -488,11 +464,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 +478,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 +489,27 @@ 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
};
+// 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..26a1259 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;
@@ -55,11 +54,16 @@ namespace WebCore {
class FrameLoader;
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 ProtectionSpace;
class PluginView;
class PolicyChecker;
class ResourceError;
@@ -71,7 +75,6 @@ namespace WebCore {
class SecurityOrigin;
class SharedBuffer;
class SubstituteData;
- class String;
class Widget;
typedef void (PolicyChecker::*FramePolicyFunction)(PolicyAction);
@@ -105,17 +108,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 +130,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;
@@ -142,6 +149,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;
@@ -219,12 +227,18 @@ namespace WebCore {
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() = 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;
@@ -245,7 +259,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 +276,15 @@ 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() { }
};
} // 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..144faa5 100644
--- a/WebCore/loader/HistoryController.cpp
+++ b/WebCore/loader/HistoryController.cpp
@@ -33,11 +33,11 @@
#include "BackForwardList.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
@@ -227,25 +238,6 @@ void HistoryController::goToItem(HistoryItem* targetItem, FrameLoadType type)
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 +274,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 +286,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);
@@ -311,7 +304,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();
@@ -355,7 +348,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 +375,7 @@ void HistoryController::updateForClientRedirect()
if (!historyURL.isEmpty() && !needPrivacy) {
if (Page* page = m_frame->page())
- page->group().addVisitedLink(historyURL);
+ addVisitedLink(page, historyURL);
}
}
@@ -420,7 +413,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 +434,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;
@@ -508,9 +510,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 +537,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 +552,15 @@ 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()
+ && ((m_frame->tree()->name().isEmpty() && item->target().isEmpty()) || m_frame->tree()->name() == item->target())
+ && childFramesMatchItem(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)
@@ -624,43 +633,46 @@ 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->backForwardList()->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);
+
+ // Create a null state object for the previous HistoryItem so that we will
+ // generate a popstate event when navigating back to it.
+ // FIXME: http://webkit.org/b/41372 implies that we shouldn't need this.
+ if (!m_previousItem->stateObject())
+ m_previousItem->setStateObject(SerializedScriptValue::create());
+
+ page->backForwardList()->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..19902f8 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,7 @@ public:
HistoryItem* currentItem() const { return m_currentItem.get(); }
void setCurrentItem(HistoryItem*);
void setCurrentItemTitle(const String&);
+ bool currentItemShouldBeReplaced() const;
HistoryItem* provisionalItem() const { return m_provisionalItem.get(); }
void setProvisionalItem(HistoryItem*);
diff --git a/WebCore/loader/ImageDocument.cpp b/WebCore/loader/ImageDocument.cpp
index 2f564cc..b1e33f4 100644
--- a/WebCore/loader/ImageDocument.cpp
+++ b/WebCore/loader/ImageDocument.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 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
@@ -25,14 +25,11 @@
#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"
@@ -41,10 +38,8 @@
#include "MouseEvent.h"
#include "NotImplemented.h"
#include "Page.h"
-#include "SegmentedString.h"
+#include "RawDataDocumentParser.h"
#include "Settings.h"
-#include "Text.h"
-#include "XMLTokenizer.h"
using std::min;
@@ -76,101 +71,102 @@ private:
ImageDocument* m_doc;
};
-class ImageTokenizer : public Tokenizer {
+class ImageDocumentParser : public RawDataDocumentParser {
public:
- ImageTokenizer(ImageDocument* doc) : m_doc(doc) {}
+ ImageDocumentParser(ImageDocument* document)
+ : RawDataDocumentParser(document)
+ {
+ }
- 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);
+ ImageDocument* document() const
+ {
+ return static_cast<ImageDocument*>(m_document);
+ }
private:
- ImageDocument* m_doc;
+ virtual void appendBytes(DocumentWriter*, const char*, int, bool);
+ virtual void finish();
};
class ImageDocumentElement : public HTMLImageElement {
public:
- ImageDocumentElement(ImageDocument* doc)
- : HTMLImageElement(imgTag, doc)
- , m_imageDocument(doc)
+ static PassRefPtr<ImageDocumentElement> create(ImageDocument*);
+
+private:
+ ImageDocumentElement(ImageDocument* document)
+ : HTMLImageElement(imgTag, document)
+ , m_imageDocument(document)
{
}
virtual ~ImageDocumentElement();
virtual void willMoveToNewOwnerDocument();
-private:
ImageDocument* m_imageDocument;
};
+inline PassRefPtr<ImageDocumentElement> ImageDocumentElement::create(ImageDocument* document)
+{
+ return adoptRef(new ImageDocumentElement(document));
+}
+
// --------
-void ImageTokenizer::write(const SegmentedString&, bool)
+static float pageZoomFactor(Document* document)
{
- // <https://bugs.webkit.org/show_bug.cgi?id=25397>: JS code can always call document.write, we need to handle it.
- notImplemented();
+ FrameView* view = document->view();
+ return view ? view->pageZoomFactor() : 1;
}
-bool ImageTokenizer::writeRawData(const char*, int)
+void ImageDocumentParser::appendBytes(DocumentWriter*, const char*, int, bool)
{
- Frame* frame = m_doc->frame();
+ Frame* frame = document()->frame();
Settings* settings = frame->settings();
if (!frame->loader()->client()->allowImages(!settings || settings->areImagesEnabled()))
- return false;
-
- CachedImage* cachedImage = m_doc->cachedImage();
+ return;
+
+ CachedImage* cachedImage = document()->cachedImage();
cachedImage->data(frame->loader()->documentLoader()->mainResourceData(), false);
- m_doc->imageChanged();
-
- return false;
+ document()->imageChanged();
}
-void ImageTokenizer::finish()
+void ImageDocumentParser::finish()
{
- if (!m_parserStopped && m_doc->imageElement()) {
- CachedImage* cachedImage = m_doc->cachedImage();
- RefPtr<SharedBuffer> data = m_doc->frame()->loader()->documentLoader()->mainResourceData();
+ if (!m_parserStopped && document()->imageElement()) {
+ CachedImage* cachedImage = document()->cachedImage();
+ RefPtr<SharedBuffer> data = document()->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())
+ if (document()->frame()->loader()->documentLoader()->isLoadingMultipartContent())
data = data->copy();
cachedImage->data(data.release(), true);
cachedImage->finish();
- cachedImage->setResponse(m_doc->frame()->loader()->documentLoader()->response());
+ cachedImage->setResponse(document()->frame()->loader()->documentLoader()->response());
- IntSize size = cachedImage->imageSize(m_doc->frame()->pageZoomFactor());
+ IntSize size = cachedImage->imageSize(pageZoomFactor(document()));
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());
+ String fileName = decodeURLEscapeSequences(document()->url().lastPathComponent());
if (fileName.isEmpty())
- fileName = m_doc->url().host();
- m_doc->setTitle(imageTitle(fileName, size));
+ fileName = document()->url().host();
+ document()->setTitle(imageTitle(fileName, size));
}
- m_doc->imageChanged();
+ document()->imageChanged();
}
- m_doc->finishedParsing();
-}
-
-bool ImageTokenizer::isWaitingForScripts() const
-{
- // An image document is never waiting for scripts
- return false;
+ document()->finishedParsing();
}
// --------
-ImageDocument::ImageDocument(Frame* frame)
- : HTMLDocument(frame)
+ImageDocument::ImageDocument(Frame* frame, const KURL& url)
+ : HTMLDocument(frame, url)
, m_imageElement(0)
, m_imageSizeIsKnown(false)
, m_didShrinkImage(false)
@@ -179,9 +175,9 @@ ImageDocument::ImageDocument(Frame* frame)
setParseMode(Compat);
}
-Tokenizer* ImageDocument::createTokenizer()
+DocumentParser* ImageDocument::createParser()
{
- return new ImageTokenizer(this);
+ return new ImageDocumentParser(this);
}
void ImageDocument::createDocumentStructure()
@@ -190,13 +186,16 @@ void ImageDocument::createDocumentStructure()
RefPtr<Element> rootElement = Document::createElement(htmlTag, false);
appendChild(rootElement, ec);
+
+ if (frame() && frame()->loader())
+ frame()->loader()->dispatchDocumentElementAvailable();
RefPtr<Element> body = Document::createElement(bodyTag, false);
body->setAttribute(styleAttr, "margin: 0px;");
rootElement->appendChild(body, ec);
- RefPtr<ImageDocumentElement> imageElement = new ImageDocumentElement(this);
+ RefPtr<ImageDocumentElement> imageElement = ImageDocumentElement::create(this);
imageElement->setAttribute(styleAttr, "-webkit-user-select: none");
imageElement->setLoadManually(true);
@@ -220,8 +219,12 @@ 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());
+ FrameView* view = frame()->view();
+ if (!view)
+ return 1;
+
+ IntSize imageSize = m_imageElement->cachedImage()->imageSize(view->pageZoomFactor());
+ IntSize windowSize = IntSize(view->width(), view->height());
float widthScale = (float)windowSize.width() / imageSize.width();
float heightScale = (float)windowSize.height() / imageSize.height();
@@ -234,7 +237,7 @@ void ImageDocument::resizeImageToFit()
if (!m_imageElement)
return;
- IntSize imageSize = m_imageElement->cachedImage()->imageSize(frame()->pageZoomFactor());
+ IntSize imageSize = m_imageElement->cachedImage()->imageSize(pageZoomFactor(this));
float scale = this->scale();
m_imageElement->setWidth(static_cast<int>(imageSize.width() * scale));
@@ -274,7 +277,7 @@ void ImageDocument::imageChanged()
if (m_imageSizeIsKnown)
return;
- if (m_imageElement->cachedImage()->imageSize(frame()->pageZoomFactor()).isEmpty())
+ if (m_imageElement->cachedImage()->imageSize(pageZoomFactor(this)).isEmpty())
return;
m_imageSizeIsKnown = true;
@@ -290,8 +293,8 @@ 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());
+ m_imageElement->setWidth(m_imageElement->cachedImage()->imageSize(pageZoomFactor(this)).width());
+ m_imageElement->setHeight(m_imageElement->cachedImage()->imageSize(pageZoomFactor(this)).height());
ExceptionCode ec;
if (imageFitsInWindow())
@@ -307,8 +310,10 @@ 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());
+ FrameView* view = frame()->view();
+
+ IntSize imageSize = m_imageElement->cachedImage()->imageSize(view->pageZoomFactor());
+ IntSize windowSize = IntSize(view->width(), view->height());
return imageSize.width() <= windowSize.width() && imageSize.height() <= windowSize.height();
}
diff --git a/WebCore/loader/ImageDocument.h b/WebCore/loader/ImageDocument.h
index 080b250..e85b3ab 100644
--- a/WebCore/loader/ImageDocument.h
+++ b/WebCore/loader/ImageDocument.h
@@ -33,9 +33,9 @@ class ImageDocumentElement;
class ImageDocument : public HTMLDocument {
public:
- static PassRefPtr<ImageDocument> create(Frame* frame)
+ static PassRefPtr<ImageDocument> create(Frame* frame, const KURL& url)
{
- return adoptRef(new ImageDocument(frame));
+ return adoptRef(new ImageDocument(frame, url));
}
CachedImage* cachedImage();
@@ -47,9 +47,9 @@ public:
void imageClicked(int x, int y);
private:
- ImageDocument(Frame*);
+ ImageDocument(Frame*, const KURL&);
- virtual Tokenizer* createTokenizer();
+ virtual DocumentParser* createParser();
virtual bool isImageDocument() const { return true; }
void createDocumentStructure();
diff --git a/WebCore/loader/ImageLoader.cpp b/WebCore/loader/ImageLoader.cpp
index c61d133..d169d3e 100644
--- a/WebCore/loader/ImageLoader.cpp
+++ b/WebCore/loader/ImageLoader.cpp
@@ -27,6 +27,8 @@
#include "DocLoader.h"
#include "Document.h"
#include "Element.h"
+#include "HTMLNames.h"
+#include "HTMLObjectElement.h"
#include "RenderImage.h"
#if !ASSERT_DISABLED
@@ -155,11 +157,13 @@ void ImageLoader::updateFromElement()
CachedImage* newImage = 0;
if (!(attr.isNull() || (attr.isEmpty() && document->baseURI().isLocalFile()))) {
if (m_loadManually) {
+ bool autoLoadOtherImages = document->docLoader()->autoLoadImages();
document->docLoader()->setAutoLoadImages(false);
newImage = new CachedImage(sourceURI(attr));
newImage->setLoading(true);
newImage->setDocLoader(document->docLoader());
document->docLoader()->m_documentResources.set(newImage->url(), newImage);
+ document->docLoader()->setAutoLoadImages(autoLoadOtherImages);
} else
newImage = document->docLoader()->requestImage(sourceURI(attr));
@@ -230,7 +234,7 @@ void ImageLoader::updateRenderer()
// 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()))
+ if (m_image != cachedImage && (m_imageComplete || !cachedImage))
imageRenderer->setCachedImage(m_image.get());
}
}
@@ -253,6 +257,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 +284,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..02ddce8 100644
--- a/WebCore/loader/ImageLoader.h
+++ b/WebCore/loader/ImageLoader.h
@@ -23,9 +23,9 @@
#ifndef ImageLoader_h
#define ImageLoader_h
-#include "AtomicString.h"
#include "CachedResourceClient.h"
#include "CachedResourceHandle.h"
+#include <wtf/text/AtomicString.h>
namespace WebCore {
@@ -45,6 +45,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; }
diff --git a/WebCore/loader/MainResourceLoader.cpp b/WebCore/loader/MainResourceLoader.cpp
index 3e75880..a7a5968 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.
@@ -157,7 +160,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())
@@ -194,7 +207,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 +236,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());
@@ -285,15 +298,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,6 +415,8 @@ 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);
}
@@ -421,6 +436,8 @@ void MainResourceLoader::didFinishLoading()
RefPtr<DocumentLoader> dl = documentLoader();
#endif
+ ASSERT(!documentLoader()->timing()->responseEnd);
+ documentLoader()->timing()->responseEnd = m_timeOfLastDataReceived;
frameLoader()->finishedLoading();
ResourceLoader::didFinishLoading();
@@ -464,6 +481,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);
@@ -517,7 +538,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(r, this, m_frame.get(), false, true);
return false;
}
@@ -528,6 +549,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..e2d075c 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"
@@ -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
index a2d6276..97e1775 100644
--- a/WebCore/loader/MediaDocument.cpp
+++ b/WebCore/loader/MediaDocument.cpp
@@ -29,11 +29,8 @@
#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"
@@ -41,52 +38,41 @@
#include "KeyboardEvent.h"
#include "MainResourceLoader.h"
#include "NodeList.h"
-#include "Page.h"
-#include "SegmentedString.h"
-#include "Settings.h"
-#include "Text.h"
-#include "XMLTokenizer.h"
+#include "RawDataDocumentParser.h"
namespace WebCore {
using namespace HTMLNames;
-class MediaTokenizer : public Tokenizer {
+// FIXME: Share more code with PluginDocumentParser.
+class MediaDocumentParser : public RawDataDocumentParser {
public:
- MediaTokenizer(Document* doc) : m_doc(doc), m_mediaElement(0) {}
-
+ MediaDocumentParser(Document* document)
+ : RawDataDocumentParser(document)
+ , 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);
-
+ virtual void appendBytes(DocumentWriter*, const char*, int, bool);
+
void createDocumentStructure();
- Document* m_doc;
HTMLMediaElement* m_mediaElement;
};
-
-void MediaTokenizer::write(const SegmentedString&, bool)
-{
- ASSERT_NOT_REACHED();
-}
-void MediaTokenizer::createDocumentStructure()
+void MediaDocumentParser::createDocumentStructure()
{
ExceptionCode ec;
- RefPtr<Element> rootElement = m_doc->createElement(htmlTag, false);
- m_doc->appendChild(rootElement, ec);
+ RefPtr<Element> rootElement = document()->createElement(htmlTag, false);
+ document()->appendChild(rootElement, ec);
- RefPtr<Element> body = m_doc->createElement(bodyTag, false);
+ RefPtr<Element> body = document()->createElement(bodyTag, false);
body->setAttribute(styleAttr, "background-color: rgb(38,38,38);");
rootElement->appendChild(body, ec);
- RefPtr<Element> mediaElement = m_doc->createElement(videoTag, false);
+ RefPtr<Element> mediaElement = document()->createElement(videoTag, false);
m_mediaElement = static_cast<HTMLVideoElement*>(mediaElement.get());
m_mediaElement->setAttribute(controlsAttr, "");
@@ -94,47 +80,29 @@ void MediaTokenizer::createDocumentStructure()
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());
+ m_mediaElement->setSrc(document()->url());
body->appendChild(mediaElement, ec);
- Frame* frame = m_doc->frame();
+ Frame* frame = document()->frame();
if (!frame)
return;
frame->loader()->activeDocumentLoader()->mainResourceLoader()->setShouldBufferData(false);
}
-
-bool MediaTokenizer::writeRawData(const char*, int)
+
+void MediaDocumentParser::appendBytes(DocumentWriter*, const char*, int, bool)
{
ASSERT(!m_mediaElement);
if (m_mediaElement)
- return false;
-
+ return;
+
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)
+MediaDocument::MediaDocument(Frame* frame, const KURL& url)
+ : HTMLDocument(frame, url)
, m_replaceMediaElementTimer(this, &MediaDocument::replaceMediaElementTimerFired)
{
setParseMode(Compat);
@@ -145,9 +113,9 @@ MediaDocument::~MediaDocument()
ASSERT(!m_replaceMediaElementTimer.isActive());
}
-Tokenizer* MediaDocument::createTokenizer()
+DocumentParser* MediaDocument::createParser()
{
- return new MediaTokenizer(this);
+ return new MediaDocumentParser(this);
}
void MediaDocument::defaultEventHandler(Event* event)
@@ -227,7 +195,7 @@ void MediaDocument::replaceMediaElementTimerFired(Timer<MediaDocument>*)
embedElement->setAttribute(heightAttr, "100%");
embedElement->setAttribute(nameAttr, "plugin");
embedElement->setAttribute(srcAttr, url().string());
- embedElement->setAttribute(typeAttr, frame()->loader()->responseMIMEType());
+ embedElement->setAttribute(typeAttr, frame()->loader()->writer()->mimeType());
ExceptionCode ec;
videoElement->parent()->replaceChild(embedElement, videoElement, ec);
diff --git a/WebCore/loader/MediaDocument.h b/WebCore/loader/MediaDocument.h
index aa751ab..5a8ec52 100644
--- a/WebCore/loader/MediaDocument.h
+++ b/WebCore/loader/MediaDocument.h
@@ -34,19 +34,19 @@ namespace WebCore {
class MediaDocument : public HTMLDocument {
public:
- static PassRefPtr<MediaDocument> create(Frame* frame)
+ static PassRefPtr<MediaDocument> create(Frame* frame, const KURL& url)
{
- return adoptRef(new MediaDocument(frame));
+ return adoptRef(new MediaDocument(frame, url));
}
virtual ~MediaDocument();
void mediaElementSawUnsupportedTracks();
private:
- MediaDocument(Frame*);
+ MediaDocument(Frame*, const KURL&);
virtual bool isMediaDocument() const { return true; }
- virtual Tokenizer* createTokenizer();
+ virtual DocumentParser* createParser();
virtual void defaultEventHandler(Event*);
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
index 788691f..cca6894 100644
--- a/WebCore/loader/PluginDocument.cpp
+++ b/WebCore/loader/PluginDocument.cpp
@@ -26,125 +26,127 @@
#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 "RawDataDocumentParser.h"
+#include "RenderEmbeddedObject.h"
#include "Settings.h"
-#include "Text.h"
-#include "XMLTokenizer.h"
namespace WebCore {
using namespace HTMLNames;
-
-class PluginTokenizer : public Tokenizer {
+
+// FIXME: Share more code with MediaDocumentParser.
+class PluginDocumentParser : public RawDataDocumentParser {
public:
- PluginTokenizer(Document* doc) : m_doc(doc), m_embedElement(0) {}
-
+ PluginDocumentParser(Document* document)
+ : RawDataDocumentParser(document)
+ , m_embedElement(0)
+ {
+ }
+
+ static Widget* pluginWidgetFromDocument(Document*);
+
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);
-
+ virtual void appendBytes(DocumentWriter*, const char*, int, bool);
+
void createDocumentStructure();
- Document* m_doc;
HTMLEmbedElement* m_embedElement;
};
-
-void PluginTokenizer::write(const SegmentedString&, bool)
+
+Widget* PluginDocumentParser::pluginWidgetFromDocument(Document* doc)
{
- ASSERT_NOT_REACHED();
+ ASSERT(doc);
+ RefPtr<Element> body = doc->body();
+ if (body) {
+ RefPtr<Node> node = body->firstChild();
+ if (node && node->renderer()) {
+ ASSERT(node->renderer()->isEmbeddedObject());
+ return toRenderEmbeddedObject(node->renderer())->widget();
+ }
+ }
+ return 0;
}
-
-void PluginTokenizer::createDocumentStructure()
+
+void PluginDocumentParser::createDocumentStructure()
{
ExceptionCode ec;
- RefPtr<Element> rootElement = m_doc->createElement(htmlTag, false);
- m_doc->appendChild(rootElement, ec);
+ RefPtr<Element> rootElement = document()->createElement(htmlTag, false);
+ document()->appendChild(rootElement, ec);
- RefPtr<Element> body = m_doc->createElement(bodyTag, false);
+ RefPtr<Element> body = document()->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);
+ RefPtr<Element> embedElement = document()->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());
+ m_embedElement->setAttribute(srcAttr, document()->url().string());
+ m_embedElement->setAttribute(typeAttr, document()->frame()->loader()->writer()->mimeType());
body->appendChild(embedElement, ec);
}
-
-bool PluginTokenizer::writeRawData(const char*, int)
+
+void PluginDocumentParser::appendBytes(DocumentWriter*, const char*, int, bool)
{
ASSERT(!m_embedElement);
if (m_embedElement)
- return false;
-
+ return;
+
createDocumentStructure();
- if (Frame* frame = m_doc->frame()) {
- Settings* settings = frame->settings();
- if (settings && settings->arePluginsEnabled()) {
- m_doc->updateLayout();
+ Frame* frame = document()->frame();
+ if (!frame)
+ return;
+ Settings* settings = frame->settings();
+ if (!settings || !frame->loader()->subframeLoader()->allowPlugins(NotAboutToInstantiatePlugin))
+ return;
- if (RenderWidget* renderer = toRenderWidget(m_embedElement->renderer())) {
- frame->loader()->client()->redirectDataToPlugin(renderer->widget());
- frame->loader()->activeDocumentLoader()->mainResourceLoader()->setShouldBufferData(false);
- }
+ document()->updateLayout();
- finish();
- }
+ if (RenderWidget* renderer = toRenderWidget(m_embedElement->renderer())) {
+ frame->loader()->client()->redirectDataToPlugin(renderer->widget());
+ frame->loader()->activeDocumentLoader()->mainResourceLoader()->setShouldBufferData(false);
}
- return false;
+ finish();
}
-
-void PluginTokenizer::stopParsing()
-{
- Tokenizer::stopParsing();
-}
-
-void PluginTokenizer::finish()
+
+PluginDocument::PluginDocument(Frame* frame, const KURL& url)
+ : HTMLDocument(frame, url)
{
- if (!m_parserStopped)
- m_doc->finishedParsing();
+ setParseMode(Compat);
}
-bool PluginTokenizer::isWaitingForScripts() const
+DocumentParser* PluginDocument::createParser()
{
- // A plugin document is never waiting for scripts
- return false;
+ return new PluginDocumentParser(this);
}
-
-PluginDocument::PluginDocument(Frame* frame)
- : HTMLDocument(frame)
+
+Widget* PluginDocument::pluginWidget()
{
- setParseMode(Compat);
+ return PluginDocumentParser::pluginWidgetFromDocument(this);
}
-
-Tokenizer* PluginDocument::createTokenizer()
+
+Node* PluginDocument::pluginNode()
{
- return new PluginTokenizer(this);
+ RefPtr<Element> body_element = body();
+ if (body_element)
+ return body_element->firstChild();
+
+ return 0;
}
-
+
}
diff --git a/WebCore/loader/PluginDocument.h b/WebCore/loader/PluginDocument.h
index 1d5c964..53dde65 100644
--- a/WebCore/loader/PluginDocument.h
+++ b/WebCore/loader/PluginDocument.h
@@ -28,19 +28,25 @@
#include "HTMLDocument.h"
namespace WebCore {
-
+
+class Node;
+class Widget;
class PluginDocument : public HTMLDocument {
public:
- static PassRefPtr<PluginDocument> create(Frame* frame)
+ static PassRefPtr<PluginDocument> create(Frame* frame, const KURL& url)
{
- return adoptRef(new PluginDocument(frame));
+ return adoptRef(new PluginDocument(frame, url));
}
-private:
- PluginDocument(Frame*);
+ Widget* pluginWidget();
+ Node* pluginNode();
virtual bool isPluginDocument() const { return true; }
- virtual Tokenizer* createTokenizer();
+
+private:
+ PluginDocument(Frame*, const KURL&);
+
+ virtual DocumentParser* createParser();
};
}
diff --git a/WebCore/loader/ProgressTracker.cpp b/WebCore/loader/ProgressTracker.cpp
index 0c9f2fb..88231c8 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;
@@ -97,7 +100,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()->name().string().utf8().data(), m_progressValue, m_numProgressTrackedFrames, m_originatingProgressFrame.get());
frame->loader()->client()->willChangeEstimatedProgress();
@@ -115,7 +118,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()->name().string().utf8().data(), m_progressValue, m_numProgressTrackedFrames, m_originatingProgressFrame.get());
if (m_numProgressTrackedFrames <= 0)
return;
@@ -132,7 +135,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 +154,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;
@@ -202,7 +205,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 +217,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) &&
diff --git a/WebCore/loader/RedirectScheduler.cpp b/WebCore/loader/RedirectScheduler.cpp
index 4b44422..d969f30 100644
--- a/WebCore/loader/RedirectScheduler.cpp
+++ b/WebCore/loader/RedirectScheduler.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) 2009 Adam Barth. All rights reserved.
@@ -36,98 +36,181 @@
#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 "HistoryItem.h"
#include "HTMLFormElement.h"
#include "HTMLFrameOwnerElement.h"
#include "Page.h"
+#include "UserGestureIndicator.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)
+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)
{
- ASSERT(!url.isEmpty());
}
+ virtual ~ScheduledNavigation() { }
+
+ virtual void fire(Frame*) = 0;
+
+ virtual bool shouldStartTimer(Frame*) { return true; }
+ virtual void didStartTimer(Frame*, Timer<RedirectScheduler>*) { }
+ 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; }
+
+private:
+ double m_delay;
+ bool m_lockHistory;
+ bool m_lockBackForwardList;
+ bool m_wasDuringLoad;
+ bool m_isLocationChange;
+};
+
+class ScheduledURLNavigation : public ScheduledNavigation {
+public:
+ ScheduledURLNavigation(double delay, const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool wasUserGesture, bool duringLoad, bool isLocationChange)
+ : ScheduledNavigation(delay, lockHistory, lockBackForwardList, duringLoad, isLocationChange)
+ , m_url(url)
+ , m_referrer(referrer)
+ , m_wasUserGesture(wasUserGesture)
+ , m_haveToldClient(false)
+ {
+ }
+
+ virtual void fire(Frame* frame)
+ {
+ frame->loader()->changeLocation(KURL(ParsedURLString, m_url), m_referrer, lockHistory(), lockBackForwardList(), m_wasUserGesture, false);
+ }
+
+ virtual void didStartTimer(Frame* frame, Timer<RedirectScheduler>* 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; }
+ bool wasUserGesture() const { return m_wasUserGesture; }
+
+private:
+ String m_url;
+ String m_referrer;
+ bool m_wasUserGesture;
+ bool m_haveToldClient;
+};
+
+class ScheduledRedirect : public ScheduledURLNavigation {
+public:
+ ScheduledRedirect(double delay, const String& url, bool lockHistory, bool lockBackForwardList, bool wasUserGesture)
+ : ScheduledURLNavigation(delay, url, String(), lockHistory, lockBackForwardList, wasUserGesture, false, false) { }
+
+ virtual bool shouldStartTimer(Frame* frame) { return frame->loader()->allAncestorsAreComplete(); }
+};
- 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)
+class ScheduledLocationChange : public ScheduledURLNavigation {
+public:
+ ScheduledLocationChange(const String& url, const String& referrer, bool lockHistory, bool lockBackForwardList, bool wasUserGesture, bool duringLoad)
+ : ScheduledURLNavigation(0.0, url, referrer, lockHistory, lockBackForwardList, wasUserGesture, duringLoad, true) { }
+};
+
+class ScheduledRefresh : public ScheduledURLNavigation {
+public:
+ ScheduledRefresh(const String& url, const String& referrer, bool wasUserGesture)
+ : ScheduledURLNavigation(0.0, url, referrer, true, true, wasUserGesture, false, true) { }
+
+ virtual void fire(Frame* frame)
{
- ASSERT(!url.isEmpty());
+ frame->loader()->changeLocation(KURL(ParsedURLString, url()), referrer(), lockHistory(), lockBackForwardList(), wasUserGesture(), true);
}
+};
+
+class ScheduledHistoryNavigation : public ScheduledNavigation {
+public:
+ explicit ScheduledHistoryNavigation(int historySteps) : ScheduledNavigation(0, false, false, false, true), m_historySteps(historySteps) { }
- explicit ScheduledRedirection(int historyNavigationSteps)
- : type(historyNavigation)
- , delay(0)
- , historySteps(historyNavigationSteps)
- , lockHistory(false)
- , lockBackForwardList(false)
- , wasUserGesture(false)
- , wasRefresh(false)
- , wasDuringLoad(false)
- , toldClient(false)
+ virtual void fire(Frame* frame)
{
+ FrameLoader* loader = frame->loader();
+ if (!m_historySteps) {
+ // Special case for go(0) from a frame -> reload only the frame
+ loader->urlSelected(loader->url(), "", 0, lockHistory(), lockBackForwardList(), false, 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()->goBackOrForward(m_historySteps);
}
- 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)
+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(!frameRequest.isEmpty());
- ASSERT(this->formState);
+ ASSERT(m_submission->state());
}
+
+ virtual void fire(Frame* frame)
+ {
+ // 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<RedirectScheduler>* 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;
};
RedirectScheduler::RedirectScheduler(Frame* frame)
@@ -142,37 +225,44 @@ RedirectScheduler::~RedirectScheduler()
bool RedirectScheduler::redirectScheduledDuringLoad()
{
- return m_scheduledRedirection && m_scheduledRedirection->wasDuringLoad;
+ return m_redirect && m_redirect->wasDuringLoad();
+}
+
+bool RedirectScheduler::locationChangePending()
+{
+ return m_redirect && m_redirect->isLocationChange();
}
void RedirectScheduler::clear()
{
m_timer.stop();
- m_scheduledRedirection.clear();
+ m_redirect.clear();
}
void RedirectScheduler::scheduleRedirect(double delay, const String& url)
{
- if (delay < 0 || delay > INT_MAX / 1000)
- return;
-
if (!m_frame->page())
return;
-
+ if (delay < 0 || delay > INT_MAX / 1000)
+ 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));
+ // We want a new back/forward list item if the refresh timeout is > 1 second.
+ if (!m_redirect || delay <= m_redirect->delay())
+ schedule(new ScheduledRedirect(delay, url, true, delay <= 1, false));
}
-bool RedirectScheduler::mustLockBackForwardList(Frame* targetFrame)
+bool RedirectScheduler::mustLockBackForwardList(Frame* targetFrame, bool wasUserGesture)
{
+ // 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 (!wasUserGesture && 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()))
@@ -185,11 +275,10 @@ void RedirectScheduler::scheduleLocationChange(const String& url, const String&
{
if (!m_frame->page())
return;
-
if (url.isEmpty())
return;
- lockBackForwardList = lockBackForwardList || mustLockBackForwardList(m_frame);
+ lockBackForwardList = lockBackForwardList || mustLockBackForwardList(m_frame, wasUserGesture);
FrameLoader* loader = m_frame->loader();
@@ -203,61 +292,40 @@ void RedirectScheduler::scheduleLocationChange(const String& url, const String&
// 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();
+ bool duringLoad = !loader->stateMachine()->committedFirstRealDocumentLoad();
- schedule(new ScheduledRedirection(url, referrer, lockHistory, lockBackForwardList, wasUserGesture, false, duringLoad));
+ schedule(new ScheduledLocationChange(url, referrer, lockHistory, lockBackForwardList, wasUserGesture, duringLoad));
}
-void RedirectScheduler::scheduleFormSubmission(const FrameLoadRequest& frameRequest,
- bool lockHistory, PassRefPtr<Event> event, PassRefPtr<FormState> formState)
+void RedirectScheduler::scheduleFormSubmission(PassRefPtr<FormSubmission> submission)
{
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();
+ 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) || (formState->formSubmissionTrigger() == SubmittedByJavaScript && m_frame->tree()->parent());
+ bool lockBackForwardList = mustLockBackForwardList(m_frame, UserGestureIndicator::processingUserGesture()) || (submission->state()->formSubmissionTrigger() == SubmittedByJavaScript && m_frame->tree()->parent());
- schedule(new ScheduledRedirection(frameRequest, lockHistory, lockBackForwardList, event, formState, duringLoad));
+ schedule(new ScheduledFormSubmission(submission, lockBackForwardList, 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;
+ schedule(new ScheduledRefresh(url.string(), m_frame->loader()->outgoingReferrer(), wasUserGesture));
}
void RedirectScheduler::scheduleHistoryNavigation(int steps)
@@ -284,120 +352,64 @@ void RedirectScheduler::scheduleHistoryNavigation(int steps)
#endif
// In all other cases, schedule the history traversal to occur asynchronously.
- schedule(new ScheduledRedirection(steps));
+ schedule(new ScheduledHistoryNavigation(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();
+ OwnPtr<ScheduledNavigation> redirect(m_redirect.release());
+ redirect->fire(m_frame);
}
-void RedirectScheduler::schedule(PassOwnPtr<ScheduledRedirection> redirection)
+void RedirectScheduler::schedule(PassOwnPtr<ScheduledNavigation> redirect)
{
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())
+ if (redirect->wasDuringLoad()) {
+ if (DocumentLoader* provisionalDocumentLoader = m_frame->loader()->provisionalDocumentLoader())
provisionalDocumentLoader->stopLoading();
- loader->stopLoading(UnloadEventPolicyUnloadAndPageHide);
+ m_frame->loader()->stopLoading(UnloadEventPolicyUnloadAndPageHide);
}
cancel();
- m_scheduledRedirection = redirection;
- if (!loader->isComplete() && m_scheduledRedirection->type != ScheduledRedirection::redirection)
- loader->completed();
+ m_redirect = redirect;
+
+ if (!m_frame->loader()->isComplete() && m_redirect->isLocationChange())
+ m_frame->loader()->completed();
+
startTimer();
}
void RedirectScheduler::startTimer()
{
- if (!m_scheduledRedirection)
+ if (!m_redirect)
return;
ASSERT(m_frame->page());
-
- FrameLoader* loader = m_frame->loader();
-
if (m_timer.isActive())
return;
-
- if (m_scheduledRedirection->type == ScheduledRedirection::redirection && !loader->allAncestorsAreComplete())
+ if (!m_redirect->shouldStartTimer(m_frame))
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();
+ m_timer.startOneShot(m_redirect->delay());
+ m_redirect->didStartTimer(m_frame, &m_timer);
}
void RedirectScheduler::cancel(bool newLoadInProgress)
{
m_timer.stop();
- OwnPtr<ScheduledRedirection> redirection(m_scheduledRedirection.release());
- if (redirection && redirection->toldClient)
- m_frame->loader()->clientRedirectCancelledOrFinished(newLoadInProgress);
+ 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/RedirectScheduler.h
index 005a173..70b0202 100644
--- a/WebCore/loader/RedirectScheduler.h
+++ b/WebCore/loader/RedirectScheduler.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,11 +41,11 @@
namespace WebCore {
class FormState;
+class FormSubmission;
class Frame;
-class String;
struct FrameLoadRequest;
-struct ScheduledRedirection;
+class ScheduledNavigation;
class RedirectScheduler : public Noncopyable {
public:
@@ -56,7 +57,7 @@ public:
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 scheduleFormSubmission(PassRefPtr<FormSubmission>);
void scheduleRefresh(bool userGesture = false);
void scheduleHistoryNavigation(int steps);
@@ -67,15 +68,15 @@ public:
private:
void timerFired(Timer<RedirectScheduler>*);
- void schedule(PassOwnPtr<ScheduledRedirection>);
+ void schedule(PassOwnPtr<ScheduledNavigation>);
- static bool mustLockBackForwardList(Frame* targetFrame);
+ static bool mustLockBackForwardList(Frame* targetFrame, bool mustLockIfDuringLoad);
Frame* m_frame;
Timer<RedirectScheduler> m_timer;
- OwnPtr<ScheduledRedirection> m_scheduledRedirection;
+ OwnPtr<ScheduledNavigation> m_redirect;
};
} // namespace WebCore
-#endif // FrameLoader_h
+#endif // RedirectScheduler_h
diff --git a/WebCore/loader/ResourceLoadNotifier.cpp b/WebCore/loader/ResourceLoadNotifier.cpp
index 9280434..d225cb8 100644
--- a/WebCore/loader/ResourceLoadNotifier.cpp
+++ b/WebCore/loader/ResourceLoadNotifier.cpp
@@ -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);
diff --git a/WebCore/loader/ResourceLoadNotifier.h b/WebCore/loader/ResourceLoadNotifier.h
index 23e4246..b0a5cbf 100644
--- a/WebCore/loader/ResourceLoadNotifier.h
+++ b/WebCore/loader/ResourceLoadNotifier.h
@@ -55,7 +55,6 @@ public:
void didReceiveData(ResourceLoader*, const char*, int, int lengthReceived);
void didFinishLoad(ResourceLoader*);
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);
diff --git a/WebCore/loader/ResourceLoader.cpp b/WebCore/loader/ResourceLoader.cpp
index d14afc8..b700fcf 100644
--- a/WebCore/loader/ResourceLoader.cpp
+++ b/WebCore/loader/ResourceLoader.cpp
@@ -34,6 +34,7 @@
#include "DocumentLoader.h"
#include "Frame.h"
#include "FrameLoader.h"
+#include "InspectorTimelineAgent.h"
#include "Page.h"
#include "ProgressTracker.h"
#include "ResourceHandle.h"
@@ -111,6 +112,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 +144,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(clientRequest, this, m_frame.get(), m_defersLoading, m_shouldContentSniff);
return true;
}
@@ -397,16 +409,44 @@ void ResourceLoader::didSendData(ResourceHandle*, unsigned long long bytesSent,
void ResourceLoader::didReceiveResponse(ResourceHandle*, const ResourceResponse& response)
{
+#if ENABLE(INSPECTOR)
+ if (InspectorTimelineAgent::instanceCount()) {
+ InspectorTimelineAgent* timelineAgent = m_frame->page() ? m_frame->page()->inspectorTimelineAgent() : 0;
+ if (timelineAgent)
+ timelineAgent->willReceiveResourceResponse(identifier(), response);
+ }
+#endif
#if ENABLE(OFFLINE_WEB_APPLICATIONS)
if (documentLoader()->applicationCacheHost()->maybeLoadFallbackForResponse(this, response))
return;
#endif
didReceiveResponse(response);
+#if ENABLE(INSPECTOR)
+ if (InspectorTimelineAgent::instanceCount()) {
+ InspectorTimelineAgent* timelineAgent = m_frame->page() ? m_frame->page()->inspectorTimelineAgent() : 0;
+ if (timelineAgent)
+ timelineAgent->didReceiveResourceResponse();
+ }
+#endif
}
void ResourceLoader::didReceiveData(ResourceHandle*, const char* data, int length, int lengthReceived)
{
+#if ENABLE(INSPECTOR)
+ if (InspectorTimelineAgent::instanceCount()) {
+ InspectorTimelineAgent* timelineAgent = m_frame->page() ? m_frame->page()->inspectorTimelineAgent() : 0;
+ if (timelineAgent)
+ timelineAgent->willReceiveResourceData(identifier());
+ }
+#endif
didReceiveData(data, length, lengthReceived, false);
+#if ENABLE(INSPECTOR)
+ if (InspectorTimelineAgent::instanceCount()) {
+ InspectorTimelineAgent* timelineAgent = m_frame->page() ? m_frame->page()->inspectorTimelineAgent() : 0;
+ if (timelineAgent)
+ timelineAgent->didReceiveResourceData();
+ }
+#endif
}
void ResourceLoader::didFinishLoading(ResourceHandle*)
@@ -455,6 +495,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,8 +510,15 @@ 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;
}
diff --git a/WebCore/loader/ResourceLoader.h b/WebCore/loader/ResourceLoader.h
index 3178eb4..e7643bf 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,6 +84,7 @@ 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 didFail(const ResourceError&);
@@ -90,6 +92,9 @@ namespace WebCore {
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,6 +102,7 @@ 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 didReceiveCachedMetadata(ResourceHandle*, const char* data, int length) { didReceiveCachedMetadata(data, length); }
virtual void didFinishLoading(ResourceHandle*);
virtual void didFail(ResourceHandle*, const ResourceError&);
virtual void wasBlocked(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)
diff --git a/WebCore/loader/SinkDocument.cpp b/WebCore/loader/SinkDocument.cpp
new file mode 100644
index 0000000..fb0ab94
--- /dev/null
+++ b/WebCore/loader/SinkDocument.cpp
@@ -0,0 +1,56 @@
+/*
+ * 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
+ * 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,
+ * 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 "SinkDocument.h"
+
+#include "RawDataDocumentParser.h"
+
+namespace WebCore {
+
+class SinkDocumentParser : public RawDataDocumentParser {
+public:
+ SinkDocumentParser(SinkDocument* document)
+ : RawDataDocumentParser(document)
+ {
+ }
+
+private:
+ // Ignore all data.
+ virtual void appendBytes(DocumentWriter*, const char*, int, bool) { }
+};
+
+SinkDocument::SinkDocument(Frame* frame, const KURL& url)
+ : HTMLDocument(frame, url)
+{
+ setParseMode(Compat);
+}
+
+DocumentParser* SinkDocument::createParser()
+{
+ return new SinkDocumentParser(this);
+}
+
+} // namespace WebCore
diff --git a/WebCore/loader/SinkDocument.h b/WebCore/loader/SinkDocument.h
new file mode 100644
index 0000000..61930d4
--- /dev/null
+++ b/WebCore/loader/SinkDocument.h
@@ -0,0 +1,49 @@
+/*
+ * 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
+ * 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,
+ * 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 SinkDocument_h
+#define SinkDocument_h
+
+#include "HTMLDocument.h"
+
+namespace WebCore {
+
+class SinkDocument : public HTMLDocument {
+public:
+ static PassRefPtr<SinkDocument> create(Frame* frame, const KURL& url)
+ {
+ return adoptRef(new SinkDocument(frame, url));
+ }
+
+private:
+ SinkDocument(Frame*, const KURL&);
+
+ virtual DocumentParser* createParser();
+};
+
+
+}; // namespace WebCore
+
+#endif // SinkDocument_h
diff --git a/WebCore/loader/SubframeLoader.cpp b/WebCore/loader/SubframeLoader.cpp
new file mode 100644
index 0000000..e7dafa1
--- /dev/null
+++ b/WebCore/loader/SubframeLoader.cpp
@@ -0,0 +1,365 @@
+/*
+ * 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"
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+#include "HTMLMediaElement.h"
+#endif
+#include "HTMLNames.h"
+#include "HTMLPlugInElement.h"
+#include "MIMETypeRegistry.h"
+#include "Node.h"
+#include "Page.h"
+#include "PluginData.h"
+#include "RenderEmbeddedObject.h"
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+#include "RenderVideo.h"
+#endif
+#include "RenderView.h"
+#include "Settings.h"
+#include "XSSAuditor.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+SubframeLoader::SubframeLoader(Frame* frame)
+ : m_containsPlugins(false)
+ , m_frame(frame)
+{
+}
+
+static HTMLPlugInElement* toPlugInElement(Node* node)
+{
+ if (!node)
+ return 0;
+
+ ASSERT(node->hasTagName(objectTag) || node->hasTagName(embedTag) || node->hasTagName(appletTag));
+
+ return static_cast<HTMLPlugInElement*>(node);
+}
+
+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 = ownerElement->contentFrame();
+ if (frame)
+ frame->redirectScheduler()->scheduleLocationChange(url.string(), m_frame->loader()->outgoingReferrer(), lockHistory, lockBackForwardList, m_frame->loader()->isProcessingUserGesture());
+ else
+ frame = loadSubframe(ownerElement, url, frameName, m_frame->loader()->outgoingReferrer());
+
+ if (!frame)
+ return false;
+
+ if (!scriptURL.isEmpty())
+ frame->script()->executeIfJavaScriptURL(scriptURL);
+
+ return true;
+}
+
+bool SubframeLoader::requestObject(RenderEmbeddedObject* 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 ((!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;
+ 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);
+}
+
+
+#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 (!SecurityOrigin::canLoad(completedURL, String(), m_frame->document())) {
+ 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 (!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;
+ 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::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_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;
+}
+
+bool SubframeLoader::loadPlugin(RenderEmbeddedObject* 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(), m_frame->document())) {
+ FrameLoader::reportLocalLoadFailed(m_frame, url.string());
+ return false;
+ }
+
+ m_frame->loader()->checkIfRunInsecureContent(m_frame->document()->securityOrigin(), url);
+
+ widget = m_frame->loader()->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;
+
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ renderer->node()->setNeedsStyleRecalc(SyntheticStyleChange);
+#endif
+ } else
+ renderer->setShowsMissingPluginIndicator();
+ }
+
+ return widget;
+}
+
+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..df08870
--- /dev/null
+++ b/WebCore/loader/SubframeLoader.h
@@ -0,0 +1,91 @@
+/*
+ * 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 Frame;
+class FrameLoaderClient;
+class HTMLAppletElement;
+class HTMLFrameOwnerElement;
+class IntSize;
+class KURL;
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+class Node;
+#endif
+class RenderEmbeddedObject;
+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(RenderEmbeddedObject*, const String& url, const AtomicString& frameName,
+ const String& serviceType, const Vector<String>& paramNames, const Vector<String>& paramValues);
+
+#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
+ 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; }
+
+private:
+ Frame* loadSubframe(HTMLFrameOwnerElement*, const KURL&, const String& name, const String& referrer);
+ bool loadPlugin(RenderEmbeddedObject*, 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);
+
+ 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..1e22fb1 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,7 +66,7 @@ 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;
@@ -78,31 +77,17 @@ PassRefPtr<SubresourceLoader> SubresourceLoader::create(Frame* frame, Subresourc
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;
@@ -175,6 +160,16 @@ void SubresourceLoader::didReceiveData(const char* data, int length, long long l
m_client->didReceiveData(this, data, length);
}
+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()
{
if (cancelled())
@@ -253,14 +248,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..4a58345 100644
--- a/WebCore/loader/SubresourceLoader.h
+++ b/WebCore/loader/SubresourceLoader.h
@@ -51,6 +51,7 @@ 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);
virtual void didFinishLoading();
virtual void didFail(const ResourceError&);
virtual bool shouldUseCredentialStorage();
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
index a3d7061..6b53084 100644
--- a/WebCore/loader/TextDocument.cpp
+++ b/WebCore/loader/TextDocument.cpp
@@ -25,12 +25,12 @@
#include "config.h"
#include "TextDocument.h"
+#include "DecodedDataDocumentParser.h"
#include "Element.h"
#include "HTMLNames.h"
#include "HTMLViewSourceDocument.h"
#include "SegmentedString.h"
#include "Text.h"
-#include "XMLTokenizer.h"
using namespace std;
@@ -38,16 +38,20 @@ namespace WebCore {
using namespace HTMLNames;
-class TextTokenizer : public Tokenizer {
+// FIXME: TextDocumentParser could just be an HTMLDocumentParser
+// which started the Tokenizer in the PlainText state.
+class TextDocumentParser : public DecodedDataDocumentParser {
public:
- TextTokenizer(Document*);
- virtual ~TextTokenizer();
- TextTokenizer(HTMLViewSourceDocument*);
+ TextDocumentParser(Document*);
+ virtual ~TextDocumentParser();
+ TextDocumentParser(HTMLViewSourceDocument*);
- virtual void write(const SegmentedString&, bool appendData);
+private:
+ virtual void insert(const SegmentedString&);
+ virtual void append(const SegmentedString&);
virtual void finish();
- virtual bool isWaitingForScripts() const;
-
+ virtual bool finishWasCalled();
+
inline void checkBuffer(int len = 10)
{
if ((m_dest - m_buffer) > m_size - len) {
@@ -59,9 +63,8 @@ public:
m_size = newSize;
}
}
-
+
private:
- Document* m_doc;
Element* m_preElement;
bool m_skipLF;
@@ -71,8 +74,8 @@ private:
UChar* m_dest;
};
-TextTokenizer::TextTokenizer(Document* doc)
- : m_doc(doc)
+TextDocumentParser::TextDocumentParser(Document* document)
+ : DecodedDataDocumentParser(document)
, m_preElement(0)
, m_skipLF(false)
{
@@ -82,9 +85,8 @@ TextTokenizer::TextTokenizer(Document* doc)
m_dest = m_buffer;
}
-TextTokenizer::TextTokenizer(HTMLViewSourceDocument* doc)
- : Tokenizer(true)
- , m_doc(doc)
+TextDocumentParser::TextDocumentParser(HTMLViewSourceDocument* document)
+ : DecodedDataDocumentParser(document, true)
, m_preElement(0)
, m_skipLF(false)
{
@@ -94,13 +96,18 @@ TextTokenizer::TextTokenizer(HTMLViewSourceDocument* doc)
m_dest = m_buffer;
}
-TextTokenizer::~TextTokenizer()
+TextDocumentParser::~TextDocumentParser()
{
// finish() should have been called to prevent any leaks
ASSERT(!m_buffer);
}
-void TextTokenizer::write(const SegmentedString& s, bool)
+void TextDocumentParser::insert(const SegmentedString&)
+{
+ ASSERT_NOT_REACHED();
+}
+
+void TextDocumentParser::append(const SegmentedString& s)
{
ExceptionCode ec;
@@ -132,13 +139,13 @@ void TextTokenizer::write(const SegmentedString& s, bool)
}
if (!m_preElement && !inViewSourceMode()) {
- RefPtr<Element> rootElement = m_doc->createElement(htmlTag, false);
- m_doc->appendChild(rootElement, ec);
+ RefPtr<Element> rootElement = document()->createElement(htmlTag, false);
+ document()->appendChild(rootElement, ec);
- RefPtr<Element> body = m_doc->createElement(bodyTag, false);
+ RefPtr<Element> body = document()->createElement(bodyTag, false);
rootElement->appendChild(body, ec);
- RefPtr<Element> preElement = m_doc->createElement(preTag, false);
+ RefPtr<Element> preElement = document()->createElement(preTag, false);
preElement->setAttribute("style", "word-wrap: break-word; white-space: pre-wrap;", ec);
body->appendChild(preElement, ec);
@@ -148,49 +155,52 @@ void TextTokenizer::write(const SegmentedString& s, bool)
String string = String(m_buffer, m_dest - m_buffer);
if (inViewSourceMode()) {
- static_cast<HTMLViewSourceDocument*>(m_doc)->addViewSourceText(string);
+ static_cast<HTMLViewSourceDocument*>(document())->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);
+ RefPtr<Text> text = Text::createWithLengthLimit(document(), string, charsLeft);
m_preElement->appendChild(text, ec);
}
}
-void TextTokenizer::finish()
+void TextDocumentParser::finish()
{
if (!m_preElement)
- write(SegmentedString(), true); // Create document structure for an empty text document.
+ append(SegmentedString()); // Create document structure for an empty text document.
m_preElement = 0;
fastFree(m_buffer);
m_buffer = 0;
m_dest = 0;
- m_doc->finishedParsing();
+ // FIXME: Should this call finishParsing even if m_parserStopped is true?
+ // See equivalent implementation in RawDataDocumentParser.
+ document()->finishedParsing();
}
-bool TextTokenizer::isWaitingForScripts() const
+bool TextDocumentParser::finishWasCalled()
{
- // A text document is never waiting for scripts
+ // finish() always calls document()->finishedParsing() so we'll be deleted
+ // after finish().
return false;
}
-TextDocument::TextDocument(Frame* frame)
- : HTMLDocument(frame)
+TextDocument::TextDocument(Frame* frame, const KURL& url)
+ : HTMLDocument(frame, url)
{
}
-Tokenizer* TextDocument::createTokenizer()
+DocumentParser* TextDocument::createParser()
{
- return new TextTokenizer(this);
+ return new TextDocumentParser(this);
}
-Tokenizer* createTextTokenizer(HTMLViewSourceDocument* document)
+DocumentParser* createTextDocumentParser(HTMLViewSourceDocument* document)
{
- return new TextTokenizer(document);
+ return new TextDocumentParser(document);
}
}
diff --git a/WebCore/loader/TextDocument.h b/WebCore/loader/TextDocument.h
index 53e3074..8f58b69 100644
--- a/WebCore/loader/TextDocument.h
+++ b/WebCore/loader/TextDocument.h
@@ -33,18 +33,18 @@ class HTMLViewSourceDocument;
class TextDocument : public HTMLDocument {
public:
- static PassRefPtr<TextDocument> create(Frame* frame)
+ static PassRefPtr<TextDocument> create(Frame* frame, const KURL& url)
{
- return adoptRef(new TextDocument(frame));
+ return adoptRef(new TextDocument(frame, url));
}
private:
- TextDocument(Frame*);
+ TextDocument(Frame*, const KURL&);
- virtual Tokenizer* createTokenizer();
+ virtual DocumentParser* createParser();
};
-Tokenizer* createTextTokenizer(HTMLViewSourceDocument*);
+DocumentParser* createTextDocumentParser(HTMLViewSourceDocument*);
}
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/WorkerThreadableLoader.cpp b/WebCore/loader/WorkerThreadableLoader.cpp
index 6837ca1..4789a05 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(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..3ae8d9f 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
@@ -42,21 +42,36 @@
#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)
{
}
@@ -368,12 +383,30 @@ void ApplicationCacheGroup::cacheDestroyed(ApplicationCache* cache)
}
}
+#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 +417,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 +446,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 +478,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(request, this, m_frame, 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, response);
+ }
+#endif
+
if (handle == m_manifestHandle) {
didReceiveManifestResponse(response);
return;
@@ -455,7 +522,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 +539,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 +549,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 +564,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 +579,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 +597,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)
{
+#if ENABLE(INSPECTOR)
+ if (Page* page = m_frame->page())
+ page->inspectorController()->didFinishLoading(m_currentResourceIdentifier);
+#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 +643,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 +694,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 +751,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 +777,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 +793,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 +809,16 @@ void ApplicationCacheGroup::cacheUpdateFailed()
m_completionType = Failure;
deliverDelayedMainResources();
}
+
+void ApplicationCacheGroup::cacheUpdateFailedDueToOriginQuota()
+{
+ if (!m_originQuotaReached) {
+ m_originQuotaReached = true;
+ scheduleReachedOriginQuotaCallback();
+ }
+
+ cacheUpdateFailed();
+}
void ApplicationCacheGroup::manifestNotFound()
{
@@ -719,7 +842,7 @@ void ApplicationCacheGroup::manifestNotFound()
}
m_downloadingPendingMasterResourceLoadersCount = 0;
- m_updateStatus = Idle;
+ setUpdateStatus(Idle);
m_frame = 0;
if (m_caches.isEmpty()) {
@@ -775,17 +898,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 +937,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 +970,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 +989,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 +1087,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 +1110,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 +1143,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..b5cdf7b 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,13 +67,15 @@ 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; }
@@ -91,9 +94,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,8 +108,11 @@ 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 didReceiveData(ResourceHandle*, const char*, int length, int lengthReceived);
virtual void didFinishLoading(ResourceHandle*);
virtual void didFail(ResourceHandle*, const ResourceError&);
@@ -110,11 +120,13 @@ private:
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 +136,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 +160,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 +192,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..eca6861 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"
@@ -228,35 +229,73 @@ 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::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..c224172 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,8 @@
#include <wtf/Vector.h>
namespace WebCore {
-
class DOMApplicationCache;
class DocumentLoader;
- class KURL;
class ResourceLoader;
class ResourceError;
class ResourceRequest;
@@ -81,6 +80,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();
@@ -108,19 +141,33 @@ 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 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..5a82d6e 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,16 +648,20 @@ 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;
+ if (!ensureOriginRecord(group->origin()))
+ return false;
+
group->setStorageID(static_cast<unsigned>(m_database.lastInsertRowID()));
journal->add(group, 0);
return true;
@@ -626,7 +754,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 +844,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 +874,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 +902,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 +933,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 +959,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 +979,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 +989,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 +1129,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 +1165,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 +1286,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/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..3a144c2 100644
--- a/WebCore/loader/archive/cf/LegacyWebArchive.cpp
+++ b/WebCore/loader/archive/cf/LegacyWebArchive.cpp
@@ -29,7 +29,6 @@
#include "config.h"
#include "LegacyWebArchive.h"
-#include "CString.h"
#include "Cache.h"
#include "Document.h"
#include "DocumentLoader.h"
@@ -47,6 +46,7 @@
#include "Range.h"
#include "SelectionController.h"
#include "SharedBuffer.h"
+#include <wtf/text/CString.h>
#include <wtf/ListHashSet.h>
#include <wtf/RetainPtr.h>
@@ -198,7 +198,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;
}
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/icon/IconDatabase.cpp b/WebCore/loader/icon/IconDatabase.cpp
index 5a9bfaa..63b9c64 100644
--- a/WebCore/loader/icon/IconDatabase.cpp
+++ b/WebCore/loader/icon/IconDatabase.cpp
@@ -1315,7 +1315,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());
@@ -1639,11 +1639,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
diff --git a/WebCore/loader/icon/IconDatabase.h b/WebCore/loader/icon/IconDatabase.h
index 44ef22a..9793d21 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"
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
index d1aa2f3..1107d7b 100644
--- a/WebCore/loader/icon/IconFetcher.cpp
+++ b/WebCore/loader/icon/IconFetcher.cpp
@@ -32,6 +32,7 @@
#include "HTMLNames.h"
#include "ResourceHandle.h"
#include "ResourceRequest.h"
+#include "SharedBuffer.h"
namespace WebCore {
@@ -86,8 +87,8 @@ static void parseIconLink(HTMLLinkElement* link, Vector<IconLinkEntry>& entries)
// Try to determine the file type.
String path = url.path();
- int pos = path.reverseFind('.');
- if (pos >= 0) {
+ size_t pos = path.reverseFind('.');
+ if (pos != notFound) {
String extension = path.substring(pos + 1);
if (equalIgnoringCase(extension, "icns"))
type = IconLinkEntry::ICNS;
diff --git a/WebCore/loader/icon/IconLoader.cpp b/WebCore/loader/icon/IconLoader.cpp
index 5dd000e..6e2762f 100644
--- a/WebCore/loader/icon/IconLoader.cpp
+++ b/WebCore/loader/icon/IconLoader.cpp
@@ -49,9 +49,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 new IconLoader(frame);
}
IconLoader::~IconLoader()
@@ -91,7 +91,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 +115,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 +137,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..230d6ea 100644
--- a/WebCore/loader/loader.cpp
+++ b/WebCore/loader/loader.cpp
@@ -27,8 +27,8 @@
#include "Cache.h"
#include "CachedImage.h"
#include "CachedResource.h"
-#include "CString.h"
#include "DocLoader.h"
+#include "InspectorTimelineAgent.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "HTMLDocument.h"
@@ -37,6 +37,7 @@
#include "ResourceRequest.h"
#include "ResourceResponse.h"
#include "SecurityOrigin.h"
+#include "SharedBuffer.h"
#include "SubresourceLoader.h"
#include <wtf/Assertions.h>
#include <wtf/Vector.h>
@@ -88,7 +89,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;
}
@@ -109,6 +115,10 @@ Loader::Priority Loader::determinePriority(const CachedResource* resource) const
return Medium;
case CachedResource::ImageResource:
return Low;
+#if ENABLE(LINK_PREFETCH)
+ case CachedResource::LinkPrefetch:
+ return VeryLow;
+#endif
}
ASSERT_NOT_REACHED();
return Low;
@@ -138,13 +148,20 @@ void Loader::load(DocLoader* docLoader, CachedResource* resource, bool increment
bool hadRequests = host->hasRequests();
Priority priority = determinePriority(resource);
host->addRequest(request, priority);
- docLoader->incrementRequestCount();
+ docLoader->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
+#if ENABLE(INSPECTOR)
+ if (InspectorTimelineAgent::instanceCount()) {
+ InspectorTimelineAgent* agent = docLoader->doc()->inspectorTimelineAgent();
+ if (agent)
+ agent->didScheduleResourceRequest(resource->url());
+ }
+#endif // ENABLE(INSPECTOR)
scheduleServePendingRequests();
}
}
@@ -286,6 +303,8 @@ void Loader::Host::nonCacheRequestComplete()
{
--m_nonCachedRequestsInFlight;
ASSERT(m_nonCachedRequestsInFlight >= 0);
+
+ cache()->loader()->scheduleServePendingRequests();
}
bool Loader::Host::hasRequests() const
@@ -322,7 +341,6 @@ void Loader::Host::servePendingRequests(RequestQueue& requestsPending, bool& ser
bool shouldLimitRequests = !m_name.isNull() || docLoader->doc()->parsing() || !docLoader->doc()->haveStylesheetsLoaded();
if (shouldLimitRequests && m_requestsLoading.size() + m_nonCachedRequestsInFlight >= m_maxRequestsInFlight) {
serveLowerPriority = false;
- cache()->loader()->scheduleServePendingRequests();
return;
}
requestsPending.removeFirst();
@@ -361,7 +379,7 @@ void Loader::Host::servePendingRequests(RequestQueue& requestsPending, bool& ser
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->decrementRequestCount(request->cachedResource());
docLoader->setLoadInProgress(true);
request->cachedResource()->error();
docLoader->setLoadInProgress(false);
@@ -385,7 +403,7 @@ void Loader::Host::didFinishLoading(SubresourceLoader* loader)
// the docLoader that it will delete when the document gets deleted.
RefPtr<Document> protector(docLoader->doc());
if (!request->isMultipart())
- docLoader->decrementRequestCount();
+ docLoader->decrementRequestCount(request->cachedResource());
CachedResource* resource = request->cachedResource();
ASSERT(!resource->resourceToRevalidate());
@@ -433,7 +451,7 @@ void Loader::Host::didFail(SubresourceLoader* loader, bool cancelled)
// the docLoader that it will delete when the document gets deleted.
RefPtr<Document> protector(docLoader->doc());
if (!request->isMultipart())
- docLoader->decrementRequestCount();
+ docLoader->decrementRequestCount(request->cachedResource());
CachedResource* resource = request->cachedResource();
@@ -478,7 +496,7 @@ void Loader::Host::didReceiveResponse(SubresourceLoader* loader, const ResourceR
// 304 Not modified / Use local copy
m_requestsLoading.remove(loader);
loader->clearClient();
- request->docLoader()->decrementRequestCount();
+ request->docLoader()->decrementRequestCount(request->cachedResource());
// Existing resource is ok, just use it updating the expiration time.
cache()->revalidationSucceeded(resource, response);
@@ -510,7 +528,7 @@ void Loader::Host::didReceiveResponse(SubresourceLoader* loader, const ResourceR
request->setIsMultipart(true);
// We don't count multiParts in a DocLoader's request count
- request->docLoader()->decrementRequestCount();
+ request->docLoader()->decrementRequestCount(request->cachedResource());
// If we get a multipart response, we must have a handle
ASSERT(loader->handle());
@@ -550,6 +568,20 @@ void Loader::Host::didReceiveData(SubresourceLoader* loader, const char* data, i
resource->data(loader->resourceData(), false);
}
+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, DocLoader* docLoader)
{
RequestQueue remaining;
@@ -558,8 +590,8 @@ void Loader::Host::cancelPendingRequests(RequestQueue& requestsPending, DocLoade
Request* request = *it;
if (request->docLoader() == docLoader) {
cache()->remove(request->cachedResource());
+ docLoader->decrementRequestCount(request->cachedResource());
delete request;
- docLoader->decrementRequestCount();
} else
remaining.append(request);
}
diff --git a/WebCore/loader/loader.h b/WebCore/loader/loader.h
index a9de032..52c61aa 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,6 +29,8 @@
#include <wtf/Deque.h>
#include <wtf/HashMap.h>
#include <wtf/Noncopyable.h>
+#include <wtf/text/AtomicString.h>
+#include <wtf/text/AtomicStringImpl.h>
namespace WebCore {
@@ -48,8 +48,8 @@ namespace WebCore {
void cancelRequests(DocLoader*);
- 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,7 +76,7 @@ namespace WebCore {
void addRequest(Request*, Priority);
void nonCacheRequestInFlight();
void nonCacheRequestComplete();
- void servePendingRequests(Priority minimumPriority = Low);
+ void servePendingRequests(Priority minimumPriority = VeryLow);
void cancelRequests(DocLoader*);
bool hasRequests() const;
@@ -87,6 +87,7 @@ 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&);