Diff
Modified: trunk/Source/WebCore/ChangeLog (144804 => 144805)
--- trunk/Source/WebCore/ChangeLog 2013-03-05 21:08:29 UTC (rev 144804)
+++ trunk/Source/WebCore/ChangeLog 2013-03-05 21:11:10 UTC (rev 144805)
@@ -1,3 +1,34 @@
+2013-03-05 Charlie Reis <[email protected]>
+
+ Add FrameLoaderClient::didAccessInitialDocument
+ https://bugs.webkit.org/show_bug.cgi?id=107963
+
+ Notifies the FrameLoaderClient if another page accesses the
+ initial empty document of a main frame. In this case, it is
+ no longer safe to display the provisional URL.
+
+ Only takes effect for PLATFORM(CHROMIUM), since no other platforms
+ listen to the notification.
+
+ Reviewed by Adam Barth.
+
+ * bindings/v8/V8DOMWindowShell.cpp:
+ (WebCore::V8DOMWindowShell::setSecurityToken):
+ Use default token for initial document.
+ * bindings/v8/custom/V8DOMWindowCustom.cpp:
+ Notify loader if initial document is accessed.
+ (WebCore::V8DOMWindow::namedSecurityCheck):
+ (WebCore::V8DOMWindow::indexedSecurityCheck):
+ * loader/FrameLoader.cpp:
+ (WebCore::FrameLoader::FrameLoader):
+ (WebCore::FrameLoader::didAccessInitialDocument):
+ (WebCore):
+ * loader/FrameLoader.h:
+ (FrameLoader):
+ * loader/FrameLoaderClient.h:
+ (FrameLoaderClient):
+ (WebCore::FrameLoaderClient::didAccessInitialDocument):
+
2013-03-05 Otto Derek Cheung <[email protected]>
[BlackBerry] Fix assertion in CookieManager::getBackingStoreCookies
Modified: trunk/Source/WebCore/bindings/v8/V8DOMWindowShell.cpp (144804 => 144805)
--- trunk/Source/WebCore/bindings/v8/V8DOMWindowShell.cpp 2013-03-05 21:08:29 UTC (rev 144804)
+++ trunk/Source/WebCore/bindings/v8/V8DOMWindowShell.cpp 2013-03-05 21:11:10 UTC (rev 144805)
@@ -402,7 +402,11 @@
// Note: we can't use the HTTPOrigin if it was set from the DOM.
SecurityOrigin* origin = document->securityOrigin();
String token;
- if (!origin->domainWasSetInDOM())
+ // We stick with an empty token if document.domain was modified or if we
+ // are in the initial empty document, so that we can do a full canAccess
+ // check in those cases.
+ if (!origin->domainWasSetInDOM()
+ && !m_frame->loader()->stateMachine()->isDisplayingInitialEmptyDocument())
token = document->securityOrigin()->toString();
// An empty or "null" token means we always have to call
Modified: trunk/Source/WebCore/bindings/v8/custom/V8DOMWindowCustom.cpp (144804 => 144805)
--- trunk/Source/WebCore/bindings/v8/custom/V8DOMWindowCustom.cpp 2013-03-05 21:08:29 UTC (rev 144804)
+++ trunk/Source/WebCore/bindings/v8/custom/V8DOMWindowCustom.cpp 2013-03-05 21:11:10 UTC (rev 144805)
@@ -523,6 +523,10 @@
if (!target)
return false;
+ // Notify the loader's client if the initial document has been accessed.
+ if (target->loader()->stateMachine()->isDisplayingInitialEmptyDocument())
+ target->loader()->didAccessInitialDocument();
+
if (key->IsString()) {
DEFINE_STATIC_LOCAL(AtomicString, nameOfProtoProperty, ("__proto__", AtomicString::ConstructFromLiteral));
@@ -558,6 +562,10 @@
return false;
Frame* childFrame = target->tree()->scopedChild(index);
+ // Notify the loader's client if the initial document has been accessed.
+ if (target->loader()->stateMachine()->isDisplayingInitialEmptyDocument())
+ target->loader()->didAccessInitialDocument();
+
// Notice that we can't call HasRealNamedProperty for ACCESS_HAS
// because that would generate infinite recursion.
if (type == v8::ACCESS_HAS && childFrame)
Modified: trunk/Source/WebCore/loader/FrameLoader.cpp (144804 => 144805)
--- trunk/Source/WebCore/loader/FrameLoader.cpp 2013-03-05 21:08:29 UTC (rev 144804)
+++ trunk/Source/WebCore/loader/FrameLoader.cpp 2013-03-05 21:11:10 UTC (rev 144805)
@@ -233,6 +233,10 @@
, m_shouldCallCheckCompleted(false)
, m_shouldCallCheckLoadComplete(false)
, m_opener(0)
+#if PLATFORM(CHROMIUM)
+ , m_didAccessInitialDocument(false)
+ , m_didAccessInitialDocumentTimer(this, &FrameLoader::didAccessInitialDocumentTimerFired)
+#endif
, m_didPerformFirstNavigation(false)
, m_loadingFromCachedPage(false)
, m_suppressOpenerInNewFrame(false)
@@ -1586,6 +1590,23 @@
return m_documentLoader.get();
}
+#if PLATFORM(CHROMIUM)
+void FrameLoader::didAccessInitialDocument()
+{
+ // We only need to notify the client once, and only for the main frame.
+ if (isLoadingMainFrame() && !m_didAccessInitialDocument) {
+ m_didAccessInitialDocument = true;
+ // Notify asynchronously, since this is called within a _javascript_ security check.
+ m_didAccessInitialDocumentTimer.startOneShot(0);
+ }
+}
+
+void FrameLoader::didAccessInitialDocumentTimerFired(Timer<FrameLoader>*)
+{
+ m_client->didAccessInitialDocument();
+}
+#endif
+
bool FrameLoader::isLoading() const
{
DocumentLoader* docLoader = activeDocumentLoader();
Modified: trunk/Source/WebCore/loader/FrameLoader.h (144804 => 144805)
--- trunk/Source/WebCore/loader/FrameLoader.h 2013-03-05 21:08:29 UTC (rev 144804)
+++ trunk/Source/WebCore/loader/FrameLoader.h 2013-03-05 21:11:10 UTC (rev 144805)
@@ -137,6 +137,11 @@
// FIXME: clear() is trying to do too many things. We should break it down into smaller functions (ideally with fewer raw Boolean parameters).
void clear(Document* newDocument, bool clearWindowProperties = true, bool clearScriptObjects = true, bool clearFrameView = true);
+#if PLATFORM(CHROMIUM)
+ void didAccessInitialDocument();
+ void didAccessInitialDocumentTimerFired(Timer<FrameLoader>*);
+#endif
+
bool isLoading() const;
bool frameHasLoaded() const;
@@ -430,6 +435,10 @@
Frame* m_opener;
HashSet<Frame*> m_openedFrames;
+#if PLATFORM(CHROMIUM)
+ bool m_didAccessInitialDocument;
+ Timer<FrameLoader> m_didAccessInitialDocumentTimer;
+#endif
bool m_didPerformFirstNavigation;
bool m_loadingFromCachedPage;
bool m_suppressOpenerInNewFrame;
Modified: trunk/Source/WebCore/loader/FrameLoaderClient.h (144804 => 144805)
--- trunk/Source/WebCore/loader/FrameLoaderClient.h 2013-03-05 21:08:29 UTC (rev 144804)
+++ trunk/Source/WebCore/loader/FrameLoaderClient.h 2013-03-05 21:11:10 UTC (rev 144805)
@@ -211,6 +211,13 @@
virtual bool shouldStopLoadingForHistoryItem(HistoryItem*) const = 0;
virtual void updateGlobalHistoryItemForPage() { }
+#if PLATFORM(CHROMIUM)
+ // Another page has accessed the initial empty document of this frame.
+ // It is no longer safe to display a provisional URL, since a URL spoof
+ // is now possible.
+ virtual void didAccessInitialDocument() { }
+#endif
+
// This frame has set its opener to null, disowning it for the lifetime of the frame.
// See http://html.spec.whatwg.org/#dom-opener.
// FIXME: JSC should allow disowning opener. - <https://bugs.webkit.org/show_bug.cgi?id=103913>.
Modified: trunk/Source/WebKit/chromium/ChangeLog (144804 => 144805)
--- trunk/Source/WebKit/chromium/ChangeLog 2013-03-05 21:08:29 UTC (rev 144804)
+++ trunk/Source/WebKit/chromium/ChangeLog 2013-03-05 21:11:10 UTC (rev 144805)
@@ -1,3 +1,24 @@
+2013-03-05 Charlie Reis <[email protected]>
+
+ Add FrameLoaderClient::didAccessInitialDocument
+ https://bugs.webkit.org/show_bug.cgi?id=107963
+
+ Notifies WebFrameClient if another page accesses the initial
+ empty document of a main frame. In this case, it is no longer
+ safe to display the provisional URL.
+
+ Reviewed by Adam Barth.
+
+ * public/WebFrameClient.h:
+ (WebFrameClient):
+ (WebKit::WebFrameClient::didAccessInitialDocument):
+ * src/FrameLoaderClientImpl.cpp:
+ (WebKit::FrameLoaderClientImpl::didAccessInitialDocument):
+ (WebKit):
+ * src/FrameLoaderClientImpl.h:
+ (FrameLoaderClientImpl):
+ * tests/WebFrameTest.cpp:
+
2013-03-05 Alec Flett <[email protected]>
IndexedDB: Properly refactor frontend/backend code by #includes
Modified: trunk/Source/WebKit/chromium/public/WebFrameClient.h (144804 => 144805)
--- trunk/Source/WebKit/chromium/public/WebFrameClient.h 2013-03-05 21:08:29 UTC (rev 144804)
+++ trunk/Source/WebKit/chromium/public/WebFrameClient.h 2013-03-05 21:11:10 UTC (rev 144805)
@@ -102,6 +102,11 @@
// General notifications -----------------------------------------------
+ // Indicates that another page has accessed the DOM of the initial empty
+ // document of a main frame. After this, it is no longer safe to show a
+ // pending navigation's URL, because a URL spoof is possible.
+ virtual void didAccessInitialDocument(WebFrame*) { }
+
// A child frame was created in this frame. This is called when the frame
// is created and initialized.
virtual void didCreateFrame(WebFrame* parent, WebFrame* child) { }
Modified: trunk/Source/WebKit/chromium/src/FrameLoaderClientImpl.cpp (144804 => 144805)
--- trunk/Source/WebKit/chromium/src/FrameLoaderClientImpl.cpp 2013-03-05 21:08:29 UTC (rev 144804)
+++ trunk/Source/WebKit/chromium/src/FrameLoaderClientImpl.cpp 2013-03-05 21:11:10 UTC (rev 144805)
@@ -1219,6 +1219,12 @@
return !url.protocolIs(backForwardNavigationScheme);
}
+void FrameLoaderClientImpl::didAccessInitialDocument()
+{
+ if (m_webFrame->client())
+ m_webFrame->client()->didAccessInitialDocument(m_webFrame);
+}
+
void FrameLoaderClientImpl::didDisownOpener()
{
if (m_webFrame->client())
Modified: trunk/Source/WebKit/chromium/src/FrameLoaderClientImpl.h (144804 => 144805)
--- trunk/Source/WebKit/chromium/src/FrameLoaderClientImpl.h 2013-03-05 21:08:29 UTC (rev 144804)
+++ trunk/Source/WebKit/chromium/src/FrameLoaderClientImpl.h 2013-03-05 21:11:10 UTC (rev 144805)
@@ -139,6 +139,7 @@
virtual void updateGlobalHistoryRedirectLinks();
virtual bool shouldGoToHistoryItem(WebCore::HistoryItem*) const;
virtual bool shouldStopLoadingForHistoryItem(WebCore::HistoryItem*) const;
+ virtual void didAccessInitialDocument();
virtual void didDisownOpener();
virtual void didDisplayInsecureContent();
virtual void didRunInsecureContent(WebCore::SecurityOrigin*, const WebCore::KURL& insecureURL);
Modified: trunk/Source/WebKit/chromium/tests/WebFrameTest.cpp (144804 => 144805)
--- trunk/Source/WebKit/chromium/tests/WebFrameTest.cpp 2013-03-05 21:08:29 UTC (rev 144804)
+++ trunk/Source/WebKit/chromium/tests/WebFrameTest.cpp 2013-03-05 21:11:10 UTC (rev 144805)
@@ -2428,4 +2428,73 @@
m_webView = 0;
}
+class TestAccessInitialDocumentWebFrameClient : public WebFrameClient {
+public:
+ TestAccessInitialDocumentWebFrameClient() : m_didAccessInitialDocument(false)
+ {
+ }
+
+ virtual void didAccessInitialDocument(WebFrame* frame)
+ {
+ EXPECT_TRUE(!m_didAccessInitialDocument);
+ m_didAccessInitialDocument = true;
+ }
+
+ bool m_didAccessInitialDocument;
+};
+
+TEST_F(WebFrameTest, DidAccessInitialDocumentBody)
+{
+ TestAccessInitialDocumentWebFrameClient webFrameClient;
+ m_webView = FrameTestHelpers::createWebView(true, &webFrameClient);
+ runPendingTasks();
+ EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
+
+ // Create another window that will try to access it.
+ WebView* newView = FrameTestHelpers::createWebView(true);
+ newView->mainFrame()->setOpener(m_webView->mainFrame());
+ runPendingTasks();
+ EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
+
+ // Access the initial document by modifying the body.
+ newView->mainFrame()->executeScript(
+ WebScriptSource("window.opener.document.body.innerHTML += 'Modified';"));
+ runPendingTasks();
+ EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
+
+ // Access the initial document again, to ensure we don't notify twice.
+ newView->mainFrame()->executeScript(
+ WebScriptSource("window.opener.document.body.innerHTML += 'Modified';"));
+ runPendingTasks();
+ EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
+
+ newView->close();
+ m_webView->close();
+ m_webView = 0;
+}
+
+TEST_F(WebFrameTest, DidAccessInitialDocumentNavigator)
+{
+ TestAccessInitialDocumentWebFrameClient webFrameClient;
+ m_webView = FrameTestHelpers::createWebView(true, &webFrameClient);
+ runPendingTasks();
+ EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
+
+ // Create another window that will try to access it.
+ WebView* newView = FrameTestHelpers::createWebView(true);
+ newView->mainFrame()->setOpener(m_webView->mainFrame());
+ runPendingTasks();
+ EXPECT_FALSE(webFrameClient.m_didAccessInitialDocument);
+
+ // Access the initial document to get to the navigator object.
+ newView->mainFrame()->executeScript(
+ WebScriptSource("console.log(window.opener.navigator);"));
+ runPendingTasks();
+ EXPECT_TRUE(webFrameClient.m_didAccessInitialDocument);
+
+ newView->close();
+ m_webView->close();
+ m_webView = 0;
+}
+
} // namespace