summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/page/History.cpp
diff options
context:
space:
mode:
authorKonstantin Tokarev <annulen@yandex.ru>2016-08-25 19:20:41 +0300
committerKonstantin Tokarev <annulen@yandex.ru>2017-02-02 12:30:55 +0000
commit6882a04fb36642862b11efe514251d32070c3d65 (patch)
treeb7959826000b061fd5ccc7512035c7478742f7b0 /Source/WebCore/page/History.cpp
parentab6df191029eeeb0b0f16f127d553265659f739e (diff)
Imported QtWebKit TP3 (git b57bc6801f1876c3220d5a4bfea33d620d477443)
Change-Id: I3b1d8a2808782c9f34d50240000e20cb38d3680f Reviewed-by: Konstantin Tokarev <annulen@yandex.ru>
Diffstat (limited to 'Source/WebCore/page/History.cpp')
-rw-r--r--Source/WebCore/page/History.cpp123
1 files changed, 99 insertions, 24 deletions
diff --git a/Source/WebCore/page/History.cpp b/Source/WebCore/page/History.cpp
index 79bf90bfe..b9571c1d4 100644
--- a/Source/WebCore/page/History.cpp
+++ b/Source/WebCore/page/History.cpp
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
@@ -34,16 +34,19 @@
#include "FrameLoaderClient.h"
#include "HistoryController.h"
#include "HistoryItem.h"
+#include "MainFrame.h"
#include "Page.h"
+#include "ScriptController.h"
#include "SecurityOrigin.h"
#include "SerializedScriptValue.h"
+#include <wtf/CheckedArithmetic.h>
#include <wtf/MainThread.h>
namespace WebCore {
History::History(Frame* frame)
: DOMWindowProperty(frame)
- , m_lastStateObjectRequested(0)
+ , m_lastStateObjectRequested(nullptr)
{
}
@@ -53,7 +56,7 @@ unsigned History::length() const
return 0;
if (!m_frame->page())
return 0;
- return m_frame->page()->backForward()->count();
+ return m_frame->page()->backForward().count();
}
PassRefPtr<SerializedScriptValue> History::state()
@@ -67,7 +70,7 @@ PassRefPtr<SerializedScriptValue> History::stateInternal() const
if (!m_frame)
return 0;
- if (HistoryItem* historyItem = m_frame->loader()->history()->currentItem())
+ if (HistoryItem* historyItem = m_frame->loader().history().currentItem())
return historyItem->stateObject();
return 0;
@@ -108,7 +111,7 @@ void History::go(int distance)
if (!m_frame)
return;
- m_frame->navigationScheduler()->scheduleHistoryNavigation(distance);
+ m_frame->navigationScheduler().scheduleHistoryNavigation(distance);
}
void History::go(ScriptExecutionContext* context, int distance)
@@ -117,48 +120,120 @@ void History::go(ScriptExecutionContext* context, int distance)
return;
ASSERT(isMainThread());
- Document* activeDocument = toDocument(context);
+ Document* activeDocument = downcast<Document>(context);
if (!activeDocument)
return;
if (!activeDocument->canNavigate(m_frame))
return;
- m_frame->navigationScheduler()->scheduleHistoryNavigation(distance);
+ m_frame->navigationScheduler().scheduleHistoryNavigation(distance);
}
-KURL History::urlForState(const String& urlString)
+URL History::urlForState(const String& urlString)
{
- KURL baseURL = m_frame->document()->baseURL();
+ URL baseURL = m_frame->document()->baseURL();
if (urlString.isEmpty())
return baseURL;
- return KURL(baseURL, urlString);
+ return URL(baseURL, urlString);
}
-void History::stateObjectAdded(PassRefPtr<SerializedScriptValue> data, const String& title, const String& urlString, StateObjectType stateObjectType, ExceptionCode& ec)
+void History::stateObjectAdded(PassRefPtr<SerializedScriptValue> data, const String& title, const String& urlString, StateObjectType stateObjectType, ExceptionCodeWithMessage& ec)
{
+ // Each unique main-frame document is only allowed to send 64mb of state object payload to the UI client/process.
+ static uint32_t totalStateObjectPayloadLimit = 0x4000000;
+ static unsigned perUserGestureStateObjectLimit = 100;
+
if (!m_frame || !m_frame->page())
return;
-
- KURL fullURL = urlForState(urlString);
+
+ URL fullURL = urlForState(urlString);
if (!fullURL.isValid() || !m_frame->document()->securityOrigin()->canRequest(fullURL)) {
- ec = SECURITY_ERR;
+ ec.code = SECURITY_ERR;
+ return;
+ }
+
+ Document* mainDocument = m_frame->page()->mainFrame().document();
+ History* mainHistory = nullptr;
+ if (mainDocument) {
+ if (auto* mainDOMWindow = mainDocument->domWindow())
+ mainHistory = mainDOMWindow->history();
+ }
+
+ if (!mainHistory)
+ return;
+
+ bool processingUserGesture = ScriptController::processingUserGesture();
+ if (!processingUserGesture && mainHistory->m_nonUserGestureObjectsAdded >= perUserGestureStateObjectLimit) {
+ ec.code = SECURITY_ERR;
+ if (stateObjectType == StateObjectType::Replace)
+ ec.message = String::format("Attempt to use history.replaceState() more than %u times without a user gesture", perUserGestureStateObjectLimit);
+ else
+ ec.message = String::format("Attempt to use history.pushState() more than %u times without a user gesture", perUserGestureStateObjectLimit);
+ return;
+ }
+
+ double userGestureTimestamp = mainDocument->lastHandledUserGestureTimestamp();
+ if (processingUserGesture) {
+ if (mainHistory->m_currentUserGestureTimestamp < userGestureTimestamp) {
+ mainHistory->m_currentUserGestureTimestamp = userGestureTimestamp;
+ mainHistory->m_currentUserGestureObjectsAdded = 0;
+ }
+
+ if (mainHistory->m_currentUserGestureObjectsAdded >= perUserGestureStateObjectLimit) {
+ ec.code = SECURITY_ERR;
+ if (stateObjectType == StateObjectType::Replace)
+ ec.message = String::format("Attempt to use history.replaceState() more than %u times per gesture", perUserGestureStateObjectLimit);
+ else
+ ec.message = String::format("Attempt to use history.pushState() more than %u times per user gesture", perUserGestureStateObjectLimit);
+ return;
+ }
+ }
+
+ Checked<unsigned> titleSize = title.length();
+ titleSize *= 2;
+
+ Checked<unsigned> urlSize = fullURL.string().length();
+ urlSize *= 2;
+
+ Checked<uint64_t> payloadSize = titleSize;
+ payloadSize += urlSize;
+ payloadSize += data ? data->data().size() : 0;
+
+ Checked<uint64_t> newTotalUsage = mainHistory->m_totalStateObjectUsage;
+
+ if (stateObjectType == StateObjectType::Replace)
+ newTotalUsage -= m_mostRecentStateObjectUsage;
+ newTotalUsage += payloadSize;
+
+ if (newTotalUsage > totalStateObjectPayloadLimit) {
+ ec.code = QUOTA_EXCEEDED_ERR;
+ if (stateObjectType == StateObjectType::Replace)
+ ec.message = ASCIILiteral("Attempt to store more data than allowed using history.replaceState()");
+ else
+ ec.message = ASCIILiteral("Attempt to store more data than allowed using history.pushState()");
return;
}
- if (stateObjectType == StateObjectPush)
- m_frame->loader()->history()->pushState(data, title, fullURL.string());
- else if (stateObjectType == StateObjectReplace)
- m_frame->loader()->history()->replaceState(data, title, fullURL.string());
-
+ m_mostRecentStateObjectUsage = payloadSize.unsafeGet();
+
+ mainHistory->m_totalStateObjectUsage = newTotalUsage.unsafeGet();
+ if (processingUserGesture)
+ ++mainHistory->m_currentUserGestureObjectsAdded;
+ else
+ ++mainHistory->m_nonUserGestureObjectsAdded;
+
if (!urlString.isEmpty())
m_frame->document()->updateURLForPushOrReplaceState(fullURL);
- if (stateObjectType == StateObjectPush)
- m_frame->loader()->client()->dispatchDidPushStateWithinPage();
- else if (stateObjectType == StateObjectReplace)
- m_frame->loader()->client()->dispatchDidReplaceStateWithinPage();
+ if (stateObjectType == StateObjectType::Push) {
+ m_frame->loader().history().pushState(data, title, fullURL.string());
+ m_frame->loader().client().dispatchDidPushStateWithinPage();
+ } else if (stateObjectType == StateObjectType::Replace) {
+ m_frame->loader().history().replaceState(data, title, fullURL.string());
+ m_frame->loader().client().dispatchDidReplaceStateWithinPage();
+ }
}
} // namespace WebCore