Title: [144805] trunk/Source
Revision
144805
Author
[email protected]
Date
2013-03-05 13:11:10 -0800 (Tue, 05 Mar 2013)

Log Message

Add FrameLoaderClient::didAccessInitialDocument
https://bugs.webkit.org/show_bug.cgi?id=107963

Source/WebCore:

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):

Source/WebKit/chromium:

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:

Modified Paths

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
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to