WebCore:
authorweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 31 Jan 2008 19:52:42 +0000 (19:52 +0000)
committerweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 31 Jan 2008 19:52:42 +0000 (19:52 +0000)
        Reviewed by Darin Adler.

        Fix for <rdar://problem/5708993> Mutability of the History object

        - Don't allow cross-domain get access to any of the history objects properties
          except the back(), forward() and go() methods.
        - Don't allow cross-domain put access to any of the history objects properties.
        - Don't allow cross-domain enumeration of the History or Location objects.

        Tests: http/tests/security/cross-frame-access-history-get-override.html
               http/tests/security/cross-frame-access-history-get.html
               http/tests/security/cross-frame-access-history-put.html

        * WebCore.xcodeproj/project.pbxproj:
        * bindings/js/JSDOMWindowCustom.cpp: Remove unnessary KJS::'s
        (WebCore::JSDOMWindow::customGetOwnPropertySlot):
        (WebCore::JSDOMWindow::customPut):
        (WebCore::JSDOMWindow::getPropertyNames): Moved implementation from KJS::Window now that the declaration is autogenerated
        using the new CustomGetPropertyNames.
        (WebCore::JSDOMWindow::postMessage):

        * bindings/js/JSHistoryCustom.cpp: Added.
        (WebCore::allowsAccessFromFrame):
        (WebCore::JSHistory::customGetOwnPropertySlot): Only allow getting the declared functions back(), forward() and go() from cross-domain.
        Deny all other gets.
        (WebCore::JSHistory::customPut): Don't allow putting cross-domain.
        (WebCore::JSHistory::getPropertyNames): Don't allow enumeration cross-domain.

        * bindings/js/JSLocation.cpp:
        (WebCore::allowsAccessFromFrame):
        (WebCore::JSLocation::getPropertyNames): Don't allow enumeration cross-domain.
        * bindings/js/JSLocation.h:

        * bindings/js/kjs_window.cpp:
        * bindings/js/kjs_window.h:

        * bindings/scripts/CodeGeneratorJS.pm:
        Add support for new CustomGetPropertNames extended attribute and changed the logic of CustomPutFunction
        to create an overrided put() function even if no read-write properties exist.

        * page/DOMWindow.idl: Added CustomGetPropertNames
        * page/History.idl: Added CustomGetPropertNames

LayoutTests:

        Reviewed by Darin Adler.

        Tests for <rdar://problem/5708993> Mutability of the History object

        * http/tests/security/cross-frame-access-enumeration-expected.txt:
        * http/tests/security/cross-frame-access-enumeration.html:
        * http/tests/security/cross-frame-access-history-expected.txt: Removed.
        * http/tests/security/cross-frame-access-history-get-expected.txt: Renamed from LayoutTests/http/tests/security/cross-frame-access-history-expected.txt.
        * http/tests/security/cross-frame-access-history-get-override-expected.txt: Added.
        * http/tests/security/cross-frame-access-history-get-override.html: Added.
        * http/tests/security/cross-frame-access-history-get.html: Renamed from LayoutTests/http/tests/security/cross-frame-access-history.html.
        * http/tests/security/cross-frame-access-history-put-expected.txt: Added.
        * http/tests/security/cross-frame-access-history-put.html: Added.
        * http/tests/security/cross-frame-access-history.html: Removed.
        * http/tests/security/resources/cross-frame-access.js:
        * http/tests/security/resources/cross-frame-iframe-for-enumeration-test.html:
        * http/tests/security/resources/cross-frame-iframe-for-history-get-override-test.html: Added.
        * http/tests/security/resources/cross-frame-iframe-for-history-get-test.html: Added.
        * http/tests/security/resources/cross-frame-iframe-for-history-put-test.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@29890 268f45cc-cd09-0410-ab3c-d52691b4dbfc

27 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/security/cross-frame-access-enumeration-expected.txt
LayoutTests/http/tests/security/cross-frame-access-enumeration.html
LayoutTests/http/tests/security/cross-frame-access-history-expected.txt [deleted file]
LayoutTests/http/tests/security/cross-frame-access-history-get-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/security/cross-frame-access-history-get-override-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/security/cross-frame-access-history-get-override.html [new file with mode: 0644]
LayoutTests/http/tests/security/cross-frame-access-history-get.html [new file with mode: 0644]
LayoutTests/http/tests/security/cross-frame-access-history-put-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/security/cross-frame-access-history-put.html [new file with mode: 0644]
LayoutTests/http/tests/security/cross-frame-access-history.html [deleted file]
LayoutTests/http/tests/security/resources/cross-frame-access.js
LayoutTests/http/tests/security/resources/cross-frame-iframe-for-enumeration-test.html
LayoutTests/http/tests/security/resources/cross-frame-iframe-for-history-get-override-test.html [new file with mode: 0644]
LayoutTests/http/tests/security/resources/cross-frame-iframe-for-history-get-test.html [new file with mode: 0644]
LayoutTests/http/tests/security/resources/cross-frame-iframe-for-history-put-test.html [new file with mode: 0644]
WebCore/ChangeLog
WebCore/WebCore.xcodeproj/project.pbxproj
WebCore/bindings/js/JSDOMWindowCustom.cpp
WebCore/bindings/js/JSHistoryCustom.cpp [new file with mode: 0644]
WebCore/bindings/js/JSLocation.cpp
WebCore/bindings/js/JSLocation.h
WebCore/bindings/js/kjs_window.cpp
WebCore/bindings/js/kjs_window.h
WebCore/bindings/scripts/CodeGeneratorJS.pm
WebCore/page/DOMWindow.idl
WebCore/page/History.idl

index 8dbcb9fa60444affc7e21d8a1a3d57a60534f7b8..a6730212b525b000f42822552af0c65e6a55712e 100644 (file)
@@ -1,3 +1,25 @@
+2008-01-30  Samuel Weinig  <sam@webkit.org>
+
+        Reviewed by Darin Adler.
+
+        Tests for <rdar://problem/5708993> Mutability of the History object
+
+        * http/tests/security/cross-frame-access-enumeration-expected.txt:
+        * http/tests/security/cross-frame-access-enumeration.html:
+        * http/tests/security/cross-frame-access-history-expected.txt: Removed.
+        * http/tests/security/cross-frame-access-history-get-expected.txt: Renamed from LayoutTests/http/tests/security/cross-frame-access-history-expected.txt.
+        * http/tests/security/cross-frame-access-history-get-override-expected.txt: Added.
+        * http/tests/security/cross-frame-access-history-get-override.html: Added.
+        * http/tests/security/cross-frame-access-history-get.html: Renamed from LayoutTests/http/tests/security/cross-frame-access-history.html.
+        * http/tests/security/cross-frame-access-history-put-expected.txt: Added.
+        * http/tests/security/cross-frame-access-history-put.html: Added.
+        * http/tests/security/cross-frame-access-history.html: Removed.
+        * http/tests/security/resources/cross-frame-access.js:
+        * http/tests/security/resources/cross-frame-iframe-for-enumeration-test.html:
+        * http/tests/security/resources/cross-frame-iframe-for-history-get-override-test.html: Added.
+        * http/tests/security/resources/cross-frame-iframe-for-history-get-test.html: Added.
+        * http/tests/security/resources/cross-frame-iframe-for-history-put-test.html: Added.
+
 2008-01-31  Dan Bernstein  <mitz@apple.com>
 
         Reviewed by Dave Hyatt.
index c59096dbad45764ba470b7fd292d66df39d5aefe..be52da6e3b23caf4c4210f402c0c7a9bfa23aae1 100644 (file)
@@ -1,7 +1,13 @@
 CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8000/security/resources/cross-frame-iframe-for-enumeration-test from frame with URL http://127.0.0.1:8000/security/cross-frame-access-enumeration.html. Domains, protocols and ports must match.
 
+CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8000/security/resources/cross-frame-iframe-for-enumeration-test from frame with URL http://127.0.0.1:8000/security/cross-frame-access-enumeration.html. Domains, protocols and ports must match.
+
+CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8000/security/resources/cross-frame-iframe-for-enumeration-test from frame with URL http://127.0.0.1:8000/security/cross-frame-access-enumeration.html. Domains, protocols and ports must match.
+
 This tests that variable names can't be enumerated cross domain (see http://bugs.webkit.org/show_bug.cgi?id=16387)
 
 
 PASS: Cross frame access by enumerating the window object was denied.
+PASS: Cross frame access by enumerating the History object was denied.
+PASS: Cross frame access by enumerating the Location object was denied.
 
index f433395812077a837ec9cc5c6a0d1bae398db6a0..7bc7f54830d1156de8204eafe3590238adc9fa83 100644 (file)
 
         runTest = function()
         {
+            // Test enumerating the Window object
             var b_win = document.getElementsByTagName("iframe")[0].contentWindow;
             try {
                 for (var k in b_win) {
-                    if (k == "customProperty") {
+                    if (k == "customWindowProperty") {
                         log("FAIL: Cross frame access by enumerating the window object was allowed.");
                         return;
                     }
             } catch (e) {
             }
             log("PASS: Cross frame access by enumerating the window object was denied.");
+
+            // Test enumerating the History object
+            var b_win_history = b_win.history;
+            try {
+                for (var k in b_win_history) {
+                    if (k == "customHistoryProperty") {
+                        log("FAIL: Cross frame access by enumerating the History object was allowed.");
+                        return;
+                    }
+                }
+            } catch (e) {
+            }
+            log("PASS: Cross frame access by enumerating the History object was denied.");
+
+            // Test enumerating the Location object
+            var b_win_location = b_win.location;
+            try {
+                for (var k in b_win_location) {
+                    if (k == "customLocationProperty") {
+                        log("FAIL: Cross frame access by enumerating the Location object was allowed.");
+                        return;
+                    }
+                }
+            } catch (e) {
+            }
+            log("PASS: Cross frame access by enumerating the Location object was denied.");
         }
     </script>
 </head>
diff --git a/LayoutTests/http/tests/security/cross-frame-access-history-expected.txt b/LayoutTests/http/tests/security/cross-frame-access-history-expected.txt
deleted file mode 100644 (file)
index 51805bd..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
------ tests for getting/setting window.history and its properties -----
-
-Firefox prohibits getting 'history.length' but that seems unnecessarily strict since you're allowed to use the 'history' object.
-PASS: canGet('targetWindow.history.length') should be 'true' and is.
-PASS: canGet('targetWindow.history.back') should be 'true' and is.
-PASS: canGet('targetWindow.history.forward') should be 'true' and is.
-PASS: canGet('targetWindow.history.go') should be 'true' and is.
-PASS: canGet('targetWindow.history.toString') should be 'true' and is.
-PASS: toString('targetWindow.history') should be '[object History]' and is.
-
diff --git a/LayoutTests/http/tests/security/cross-frame-access-history-get-expected.txt b/LayoutTests/http/tests/security/cross-frame-access-history-get-expected.txt
new file mode 100644 (file)
index 0000000..4a27b64
--- /dev/null
@@ -0,0 +1,31 @@
+CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8000/security/resources/cross-frame-iframe-for-history-get-test.html from frame with URL http://127.0.0.1:8000/security/cross-frame-access-history-get.html. Domains, protocols and ports must match.
+
+CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8000/security/resources/cross-frame-iframe-for-history-get-test.html from frame with URL http://127.0.0.1:8000/security/cross-frame-access-history-get.html. Domains, protocols and ports must match.
+
+CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8000/security/resources/cross-frame-iframe-for-history-get-test.html from frame with URL http://127.0.0.1:8000/security/cross-frame-access-history-get.html. Domains, protocols and ports must match.
+
+CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8000/security/resources/cross-frame-iframe-for-history-get-test.html from frame with URL http://127.0.0.1:8000/security/cross-frame-access-history-get.html. Domains, protocols and ports must match.
+
+CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8000/security/resources/cross-frame-iframe-for-history-get-test.html from frame with URL http://127.0.0.1:8000/security/cross-frame-access-history-get.html. Domains, protocols and ports must match.
+
+CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8000/security/resources/cross-frame-iframe-for-history-get-test.html from frame with URL http://127.0.0.1:8000/security/cross-frame-access-history-get.html. Domains, protocols and ports must match.
+
+CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8000/security/resources/cross-frame-iframe-for-history-get-test.html from frame with URL http://127.0.0.1:8000/security/cross-frame-access-history-get.html. Domains, protocols and ports must match.
+
+
+
+----- tests for getting window.history and its properties -----
+
+PASS: canGet('targetWindow.history.length') should be 'false' and is.
+PASS: canGet('targetWindow.history.back') should be 'true' and is.
+PASS: canGet('targetWindow.history.forward') should be 'true' and is.
+PASS: canGet('targetWindow.history.go') should be 'true' and is.
+PASS: canGet('targetWindow.history.toString') should be 'true' and is.
+PASS: toString('targetWindow.history') should be '[object History]' and is.
+PASS: canGet('targetWindow.__proto__') should be 'false' and is.
+PASS: canGet('targetWindow.constructor') should be 'false' and is.
+PASS: canGet('targetWindow.history.existingCustomProperty') should be 'false' and is.
+PASS: canGet('targetWindow.history.__proto__.prototypeCustomProperty') should be 'false' and is.
+PASS: canCall('targetWindow.history.existingCustomFunction') should be 'false' and is.
+PASS: canCall('targetWindow.history.prototypeCustomFunction') should be 'false' and is.
+
diff --git a/LayoutTests/http/tests/security/cross-frame-access-history-get-override-expected.txt b/LayoutTests/http/tests/security/cross-frame-access-history-get-override-expected.txt
new file mode 100644 (file)
index 0000000..7cbdc46
--- /dev/null
@@ -0,0 +1,10 @@
+
+----- tests for getting custorm overrides of window.history's functions  -----
+
+PASS: canGet('targetWindow.history.back') should be 'true' and is.
+PASS: toString('targetWindow.history.back') should be 'function () {  return "new back";}' and is.
+PASS: canGet('targetWindow.history.forward') should be 'true' and is.
+PASS: toString('targetWindow.history.forward') should be 'function () {  return "new forward";}' and is.
+PASS: canGet('targetWindow.history.go') should be 'true' and is.
+PASS: toString('targetWindow.history.go') should be 'new go' and is.
+
diff --git a/LayoutTests/http/tests/security/cross-frame-access-history-get-override.html b/LayoutTests/http/tests/security/cross-frame-access-history-get-override.html
new file mode 100644 (file)
index 0000000..f870e70
--- /dev/null
@@ -0,0 +1,59 @@
+<html>
+<head>
+    <script src="resources/cross-frame-access.js"></script>
+    <script>
+        window.onload = function()
+        {
+            if (window.layoutTestController) {
+                layoutTestController.dumpAsText();
+                layoutTestController.waitUntilDone();
+            }
+
+            if (window.layoutTestController) {
+                setTimeout(pollForTest, 1);
+            } else {
+                log("To run the test, click the button below when the opened window finishes loading.");
+                var button = document.createElement("button");
+                button.appendChild(document.createTextNode("Run Test"));
+                button.onclick = runTest;
+                document.body.appendChild(button);
+            }
+        }
+
+        pollForTest = function()
+        {
+            if (!layoutTestController.globalFlag) {
+                setTimeout(pollForTest, 1);
+                return;
+            }
+            runTest();
+            layoutTestController.notifyDone();
+        }
+
+        runTest = function()
+        {
+            window.targetWindow = frames[0];
+
+            log("----- tests for getting custorm overrides of window.history's functions  -----\n");
+
+            // Overriden using window.history.back = function() { return "new back" }
+            newBack = function() { return "new back"; }
+            shouldBeTrue("canGet('targetWindow.history.back')");
+            shouldBe("toString('targetWindow.history.back')", "toString(newBack)");
+
+            // Overriden using window.history.__proto__.forward = function() { return "new forward;" }
+            newForward = function() { return "new forward"; }
+            shouldBeTrue("canGet('targetWindow.history.forward')");
+            shouldBe("toString('targetWindow.history.forward')", "toString(newForward)");
+
+            // Overriden using window.history.go = "new go"
+            shouldBeTrue("canGet('targetWindow.history.go')");
+            shouldBe("toString('targetWindow.history.go')", "'new go'");
+        }
+    </script>
+</head>
+<body>
+<iframe src="http://localhost:8000/security/resources/cross-frame-iframe-for-history-get-override-test.html"></iframe>
+<pre id="console"></pre>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/security/cross-frame-access-history-get.html b/LayoutTests/http/tests/security/cross-frame-access-history-get.html
new file mode 100644 (file)
index 0000000..0a492ce
--- /dev/null
@@ -0,0 +1,70 @@
+<html>
+<head>
+    <script src="resources/cross-frame-access.js"></script>
+    <script>
+        window.onload = function()
+        {
+            if (window.layoutTestController) {
+                layoutTestController.dumpAsText();
+                layoutTestController.waitUntilDone();
+            }
+
+            if (window.layoutTestController) {
+                setTimeout(pollForTest, 1);
+            } else {
+                log("To run the test, click the button below when the opened window finishes loading.");
+                var button = document.createElement("button");
+                button.appendChild(document.createTextNode("Run Test"));
+                button.onclick = runTest;
+                document.body.appendChild(button);
+            }
+        }
+
+        pollForTest = function()
+        {
+            if (!layoutTestController.globalFlag) {
+                setTimeout(pollForTest, 1);
+                return;
+            }
+            runTest();
+            layoutTestController.notifyDone();
+        }
+
+        runTest = function()
+        {
+            window.targetWindow = frames[0];
+
+            log("\n----- tests for getting window.history and its properties -----\n");
+
+            // history object
+            shouldBeFalse("canGet('targetWindow.history.length')");
+
+            shouldBeTrue("canGet('targetWindow.history.back')");
+            shouldBeTrue("canGet('targetWindow.history.forward')");
+            shouldBeTrue("canGet('targetWindow.history.go')");
+
+            // FIXME: Calling these currently cause the subsequent test to include a dump of this test's render tree.
+            // (see http://bugs.webkit.org/show_bug.cgi?id=16510)
+            // shouldBeTrue("canCall('targetWindow.history.back')");
+            // shouldBeTrue("canCall('targetWindow.history.forward')");
+            // shouldBeTrue("canCall('targetWindow.history.go', '-1')");
+
+            shouldBeTrue("canGet('targetWindow.history.toString')");
+            shouldBe("toString('targetWindow.history')", "'[object History]'");
+
+            shouldBeFalse("canGet('targetWindow.__proto__')");
+            shouldBeFalse("canGet('targetWindow.constructor')");
+
+            // Check custom properties
+            shouldBeFalse("canGet('targetWindow.history.existingCustomProperty')");
+            shouldBeFalse("canGet('targetWindow.history.__proto__.prototypeCustomProperty')");
+            shouldBeFalse("canCall('targetWindow.history.existingCustomFunction')");
+            shouldBeFalse("canCall('targetWindow.history.prototypeCustomFunction')");
+        }
+    </script>
+</head>
+<body>
+<iframe src="http://localhost:8000/security/resources/cross-frame-iframe-for-history-get-test.html"></iframe>
+<pre id="console"></pre>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/security/cross-frame-access-history-put-expected.txt b/LayoutTests/http/tests/security/cross-frame-access-history-put-expected.txt
new file mode 100644 (file)
index 0000000..da56613
--- /dev/null
@@ -0,0 +1,24 @@
+CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8000/security/resources/cross-frame-iframe-for-history-put-test.html from frame with URL http://127.0.0.1:8000/security/cross-frame-access-history-put.html. Domains, protocols and ports must match.
+
+CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8000/security/resources/cross-frame-iframe-for-history-put-test.html from frame with URL http://127.0.0.1:8000/security/cross-frame-access-history-put.html. Domains, protocols and ports must match.
+
+CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8000/security/resources/cross-frame-iframe-for-history-put-test.html from frame with URL http://127.0.0.1:8000/security/cross-frame-access-history-put.html. Domains, protocols and ports must match.
+
+CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8000/security/resources/cross-frame-iframe-for-history-put-test.html from frame with URL http://127.0.0.1:8000/security/cross-frame-access-history-put.html. Domains, protocols and ports must match.
+
+CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8000/security/resources/cross-frame-iframe-for-history-put-test.html from frame with URL http://127.0.0.1:8000/security/cross-frame-access-history-put.html. Domains, protocols and ports must match.
+
+
+
+--------
+Frame: '<!--framePath //<!--frame0-->-->'
+--------
+
+----- tests for putting window.history and its properties -----
+
+PASS: window.history.back should be 'function back() {    [native code]}' and is.
+PASS: window.history.forward should be 'function forward() {    [native code]}' and is.
+PASS: window.history.go should be 'function go() {    [native code]}' and is.
+PASS: window.history.toString should be 'function toString() {    [native code]}' and is.
+PASS: window.history.length matched the expected value.
+
diff --git a/LayoutTests/http/tests/security/cross-frame-access-history-put.html b/LayoutTests/http/tests/security/cross-frame-access-history-put.html
new file mode 100644 (file)
index 0000000..d4fd6d2
--- /dev/null
@@ -0,0 +1,34 @@
+<html>
+<head>
+    <script>
+        if (window.layoutTestController) {
+            layoutTestController.dumpAsText();
+            layoutTestController.dumpChildFramesAsText();
+            layoutTestController.waitUntilDone();
+        }
+
+        receiver = function(e)
+        {
+            if (e.data == "storedOldValuesComplete")
+                setTest();
+        }
+        document.addEventListener('message', receiver, false);
+
+        setTest = function()
+        {
+            window.targetWindow = frames[0];
+
+            targetWindow.history.back = "FAIL!! CUSTOM back";
+            targetWindow.history.forward = "FAIL!! CUSTOM forward";
+            targetWindow.history.go = "FAIL!! CUSTOM go";
+            targetWindow.history.toString = "FAIL!! CUSTOM toString";
+            targetWindow.history.length = "FAIL!! CUSTOM length";
+
+            targetWindow.postMessage("settingValuesComplete");
+        }
+    </script>
+</head>
+<body>
+<iframe src="http://localhost:8000/security/resources/cross-frame-iframe-for-history-put-test.html"></iframe>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/security/cross-frame-access-history.html b/LayoutTests/http/tests/security/cross-frame-access-history.html
deleted file mode 100644 (file)
index f96672e..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-<html>
-<head>
-    <script src="resources/cross-frame-access.js"></script>
-</head>
-<body>
-<iframe src="http://localhost:8000/security/resources/cross-frame-iframe-for-get-test.html" style=""></iframe>
-<pre id="console"></pre>
-<script>
-
-window.targetWindow = frames[0];
-
-window.onload = function()
-{
-    if (window.layoutTestController)
-        layoutTestController.dumpAsText();
-
-    log("\n----- tests for getting/setting window.history and its properties -----\n");
-
-    // history object
-    log("Firefox prohibits getting 'history.length' but that seems unnecessarily strict since you're allowed to use the 'history' object.");
-    shouldBeTrue("canGet('targetWindow.history.length')");
-
-    shouldBeTrue("canGet('targetWindow.history.back')");
-    shouldBeTrue("canGet('targetWindow.history.forward')");
-    shouldBeTrue("canGet('targetWindow.history.go')");
-
-    // FIXME: Calling these currently cause the subsequent test to include a dump of this test's render tree.
-    // (see http://bugs.webkit.org/show_bug.cgi?id=16510)
-    // shouldBeTrue("canCall('targetWindow.history.back')");
-    // shouldBeTrue("canCall('targetWindow.history.forward')");
-    // shouldBeTrue("canCall('targetWindow.history.go', '-1')");
-
-    shouldBeTrue("canGet('targetWindow.history.toString')");
-    shouldBe("toString('targetWindow.history')", "'[object History]'");
-
-    // Work around DRT bug that causes subsequent tests to fail.
-    window.stop();
-}
-</script>
-</body>
-</html>
index 684719c38c5760fa72a9e148fc552ff2d38d27d3..8faee5ace9ceaa46f6aa668d2f985891665c11ec 100644 (file)
@@ -3,7 +3,7 @@ function log(s)
     document.getElementById("console").appendChild(document.createTextNode(s + "\n"));
 }
 
-function shouldBe(a, b)
+function shouldBe(a, b, shouldNotPrintValues)
 {
     var evalA, evalB;
     try {
@@ -13,9 +13,19 @@ function shouldBe(a, b)
         evalA = e;
     }
 
-    var message = (evalA === evalB)
-                    ? "PASS: " + a + " should be '" + evalB + "' and is."
-                    : "*** FAIL: " + a + " should be '" + evalB + "' but instead is " + evalA + ". ***";
+    var message;
+    if (evalA === evalB) {
+        message = "PASS";
+        if (!shouldNotPrintValues) {
+            message += ": " + a + " should be '" + evalB + "' and is.";
+        } else {
+            message += ": " + a + " matched the expected value.";
+        }
+    } else {
+       message = "*** FAIL: " + a + " should be '" + evalB + "' but instead is " + evalA + ". ***";
+    }
+
+    message = String(message).replace(/\n/g, "");
     log(message);
 }
 
index 3a6d77057e82c018b4cd74a9059691e9d6ab8b7a..8edfb5a1ccc21cd38fd8abb65cf45bd1367d7c96 100644 (file)
@@ -1,5 +1,7 @@
 <script>
-    window.customProperty = 1;
+    window.customWindowProperty = 1;
+    window.history.customHistoryProperty = 1;
+    window.location.customLocationProperty = 1;
 
     window.onload = function()
     {
diff --git a/LayoutTests/http/tests/security/resources/cross-frame-iframe-for-history-get-override-test.html b/LayoutTests/http/tests/security/resources/cross-frame-iframe-for-history-get-override-test.html
new file mode 100644 (file)
index 0000000..655ce9e
--- /dev/null
@@ -0,0 +1,18 @@
+<html>
+<head>
+    <script>
+        
+        window.history.back = function() { return "new back"; }
+        window.history.__proto__.forward = function() { return "new forward"; }
+        window.history.go = "new go";
+
+        window.onload = function()
+        {
+            if (window.layoutTestController)
+                layoutTestController.globalFlag = true;
+        }
+    </script>
+</head>
+<body>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/security/resources/cross-frame-iframe-for-history-get-test.html b/LayoutTests/http/tests/security/resources/cross-frame-iframe-for-history-get-test.html
new file mode 100644 (file)
index 0000000..e94d2be
--- /dev/null
@@ -0,0 +1,16 @@
+<html>
+<head>
+    <script>
+        window.history.existingCustomProperty = 1; 
+        window.history.__proto__.prototypeCustomProperty = 1; 
+
+        window.onload = function()
+        {
+            if (window.layoutTestController)
+                layoutTestController.globalFlag = true;
+        }
+    </script>
+</head>
+<body>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/security/resources/cross-frame-iframe-for-history-put-test.html b/LayoutTests/http/tests/security/resources/cross-frame-iframe-for-history-put-test.html
new file mode 100644 (file)
index 0000000..db9346d
--- /dev/null
@@ -0,0 +1,47 @@
+<html>
+<head>
+    <script src="cross-frame-access.js"></script>
+    <script>
+        var backOld;
+        var forwardOld;
+        var goOld;
+        var toStringOld;
+        var lengthOld;
+
+        receiver = function(e)
+        {
+            if (e.data == "settingValuesComplete")
+                setCheck();
+        }
+        document.addEventListener('message', receiver, false);
+
+        window.onload = function()
+        {
+            backOld = window.history.back;
+            forwardOld = window.history.forward;
+            goOld = window.history.go;
+            toStringOld = window.history.toString;
+            lengthOld = window.history.length;
+
+            window.parent.postMessage("storedOldValuesComplete");
+        }
+
+        setCheck = function()
+        {
+            log("\n----- tests for putting window.history and its properties -----\n");
+
+            shouldBe("window.history.back", "backOld");
+            shouldBe("window.history.forward", "forwardOld");
+            shouldBe("window.history.go", "goOld");
+            shouldBe("window.history.toString", "toStringOld");
+            shouldBe("window.history.length", "lengthOld", true);
+
+            if (window.layoutTestController)
+                layoutTestController.notifyDone();
+        }
+    </script>
+</head>
+<body>
+    <pre id="console"></pre>
+</body>
+</html>
index 88b6a3d83a0ac263c167fcf6c3431b3588b87bbd..0ce6259826ae828db85a46745874921f92d5812a 100644 (file)
@@ -1,3 +1,48 @@
+2008-01-30  Samuel Weinig  <sam@webkit.org>
+
+        Reviewed by Darin Adler.
+
+        Fix for <rdar://problem/5708993> Mutability of the History object
+
+        - Don't allow cross-domain get access to any of the history objects properties
+          except the back(), forward() and go() methods.
+        - Don't allow cross-domain put access to any of the history objects properties.
+        - Don't allow cross-domain enumeration of the History or Location objects.
+
+        Tests: http/tests/security/cross-frame-access-history-get-override.html
+               http/tests/security/cross-frame-access-history-get.html
+               http/tests/security/cross-frame-access-history-put.html
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * bindings/js/JSDOMWindowCustom.cpp: Remove unnessary KJS::'s
+        (WebCore::JSDOMWindow::customGetOwnPropertySlot):
+        (WebCore::JSDOMWindow::customPut):
+        (WebCore::JSDOMWindow::getPropertyNames): Moved implementation from KJS::Window now that the declaration is autogenerated
+        using the new CustomGetPropertyNames.
+        (WebCore::JSDOMWindow::postMessage):
+
+        * bindings/js/JSHistoryCustom.cpp: Added.
+        (WebCore::allowsAccessFromFrame):
+        (WebCore::JSHistory::customGetOwnPropertySlot): Only allow getting the declared functions back(), forward() and go() from cross-domain.
+        Deny all other gets.
+        (WebCore::JSHistory::customPut): Don't allow putting cross-domain.
+        (WebCore::JSHistory::getPropertyNames): Don't allow enumeration cross-domain.
+
+        * bindings/js/JSLocation.cpp:
+        (WebCore::allowsAccessFromFrame):
+        (WebCore::JSLocation::getPropertyNames): Don't allow enumeration cross-domain.
+        * bindings/js/JSLocation.h:
+
+        * bindings/js/kjs_window.cpp:
+        * bindings/js/kjs_window.h:
+
+        * bindings/scripts/CodeGeneratorJS.pm:
+        Add support for new CustomGetPropertNames extended attribute and changed the logic of CustomPutFunction
+        to create an overrided put() function even if no read-write properties exist.
+
+        * page/DOMWindow.idl: Added CustomGetPropertNames
+        * page/History.idl: Added CustomGetPropertNames
+
 2008-01-30  Justin Garcia  <justin.garcia@apple.com>
 
         Reviewed by Darin Adler.
index ac3ff90c95b4eeb58a298e928e93a8dc32cf7e29..a29056cb7374f1a74920caa8fa71fdb7e0bb426f 100644 (file)
                BCE0139B0C0BEF180043860A /* JSStyleSheet.h in Headers */ = {isa = PBXBuildFile; fileRef = BCE013990C0BEF180043860A /* JSStyleSheet.h */; };
                BCE3BEC20D222B1D007E06E4 /* TagNodeList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCE3BEC00D222B1D007E06E4 /* TagNodeList.cpp */; };
                BCE3BEC30D222B1D007E06E4 /* TagNodeList.h in Headers */ = {isa = PBXBuildFile; fileRef = BCE3BEC10D222B1D007E06E4 /* TagNodeList.h */; };
+               BCE7B1930D4E86960075A539 /* JSHistoryCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCE7B1920D4E86960075A539 /* JSHistoryCustom.cpp */; };
                BCEA478F097CAAC80094C9E4 /* CSSComputedStyleDeclaration.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCEA477C097CAAC80094C9E4 /* CSSComputedStyleDeclaration.cpp */; };
                BCEA4790097CAAC80094C9E4 /* CSSComputedStyleDeclaration.h in Headers */ = {isa = PBXBuildFile; fileRef = BCEA477D097CAAC80094C9E4 /* CSSComputedStyleDeclaration.h */; };
                BCEA4852097D93020094C9E4 /* bidi.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCEA4813097D93020094C9E4 /* bidi.cpp */; };
                BCE013990C0BEF180043860A /* JSStyleSheet.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = JSStyleSheet.h; sourceTree = "<group>"; };
                BCE3BEC00D222B1D007E06E4 /* TagNodeList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TagNodeList.cpp; sourceTree = "<group>"; };
                BCE3BEC10D222B1D007E06E4 /* TagNodeList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TagNodeList.h; sourceTree = "<group>"; };
+               BCE7B1920D4E86960075A539 /* JSHistoryCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSHistoryCustom.cpp; sourceTree = "<group>"; };
                BCEA477C097CAAC80094C9E4 /* CSSComputedStyleDeclaration.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CSSComputedStyleDeclaration.cpp; sourceTree = "<group>"; };
                BCEA477D097CAAC80094C9E4 /* CSSComputedStyleDeclaration.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CSSComputedStyleDeclaration.h; sourceTree = "<group>"; };
                BCEA477E097CAAC80094C9E4 /* CSSGrammar.y */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.yacc; path = CSSGrammar.y; sourceTree = "<group>"; };
                                BCD9C25E0C17AA67005C90A2 /* JSDOMWindowCustom.cpp */,
                                BC2ED5540C6B9BD300920BFF /* JSElementCustom.cpp */,
                                BCEFAF4D0C317E6900FA81F6 /* JSEventCustom.cpp */,
+                               BCE7B1920D4E86960075A539 /* JSHistoryCustom.cpp */,
                                BC4EDEF30C08F3FB007EDD49 /* JSHTMLAppletElementCustom.cpp */,
                                BCCBAD3A0C18BFF800CE890F /* JSHTMLCollectionCustom.cpp */,
                                BC51580A0C03D404008BB0EE /* JSHTMLDocumentCustom.cpp */,
                                ABFE7E120D32FAF60066F4D2 /* MediaControlElements.cpp in Sources */,
                                B237C8A70D344D110013F707 /* SVGFontData.cpp in Sources */,
                                E4EEFFC80D34550C00469A58 /* JSAudioConstructor.cpp in Sources */,
+                               BCE7B1930D4E86960075A539 /* JSHistoryCustom.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index 307a0c17434a38fbcd98030792013e14082dada9..9f554710d245e63d3001a86fc240932903a30648 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 Apple, Inc.
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
 #include "kjs/object.h"
 #include "kjs/value.h"
 
+using namespace KJS;
+
 namespace WebCore {
 
-bool JSDOMWindow::customGetOwnPropertySlot(KJS::ExecState* exec, const KJS::Identifier& propertyName, KJS::PropertySlot& slot)
+bool JSDOMWindow::customGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
 {
     // we don't want any properties other than "closed" on a closed window
     if (!impl()->frame()) {
         if (propertyName == "closed") {
-            const KJS::HashEntry* entry = KJS::Lookup::findEntry(classInfo()->propHashTable, propertyName);
+            const HashEntry* entry = Lookup::findEntry(classInfo()->propHashTable, propertyName);
             ASSERT(entry);
             if (entry) {
-                slot.setStaticEntry(this, entry, KJS::staticValueGetter<JSDOMWindow>);
+                slot.setStaticEntry(this, entry, staticValueGetter<JSDOMWindow>);
                 return true;
             }
         }
         if (propertyName == "close") {
-            KJS::JSValue* proto = prototype();
+            JSValue* proto = prototype();
             if (proto->isObject()) {
-                const KJS::HashEntry* entry = KJS::Lookup::findEntry(static_cast<KJS::JSObject*>(proto)->classInfo()->propHashTable, propertyName);
+                const HashEntry* entry = Lookup::findEntry(static_cast<JSObject*>(proto)->classInfo()->propHashTable, propertyName);
                 ASSERT(entry);
                 if (entry) {
-                    slot.setStaticEntry(this, entry, KJS::staticFunctionGetter);
+                    slot.setStaticEntry(this, entry, staticFunctionGetter);
                     return true;
                 }
             }
@@ -69,21 +71,21 @@ bool JSDOMWindow::customGetOwnPropertySlot(KJS::ExecState* exec, const KJS::Iden
 
     // FIXME: We need this to work around the blanket same origin (allowsAccessFrom) check in KJS::Window.  Once we remove that, we
     // can move this to JSDOMWindowPrototype.
-    KJS::JSValue* proto = prototype();
+    JSValue* proto = prototype();
     if (proto->isObject()) {
-        const KJS::HashEntry* entry = KJS::Lookup::findEntry(static_cast<KJS::JSObject*>(proto)->classInfo()->propHashTable, propertyName);
+        const HashEntry* entry = Lookup::findEntry(static_cast<JSObject*>(proto)->classInfo()->propHashTable, propertyName);
         if (entry) {
-            if (entry->attr & KJS::Function) {
+            if (entry->attr & Function) {
                 if (entry->value.functionValue == jsDOMWindowPrototypeFunctionFocus
                     || entry->value.functionValue == jsDOMWindowPrototypeFunctionBlur
                     || entry->value.functionValue == jsDOMWindowPrototypeFunctionClose
                     || entry->value.functionValue == jsDOMWindowPrototypeFunctionPostMessage)
-                        slot.setStaticEntry(this, entry, KJS::staticFunctionGetter);
+                        slot.setStaticEntry(this, entry, staticFunctionGetter);
                 else {
                     if (!allowsAccessFrom(exec))
                         slot.setUndefined(this);
                     else
-                        slot.setStaticEntry(this, entry, KJS::staticFunctionGetter);
+                        slot.setStaticEntry(this, entry, staticFunctionGetter);
                 }
                 return true;
             }
@@ -93,29 +95,37 @@ bool JSDOMWindow::customGetOwnPropertySlot(KJS::ExecState* exec, const KJS::Iden
     return false;
 }
 
-bool JSDOMWindow::customPut(KJS::ExecState* exec, const KJS::Identifier& propertyName, KJS::JSValue* value, int attr)
+bool JSDOMWindow::customPut(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr)
 {
     if (!impl()->frame())
         return true;
 
     // Called by an internal KJS, save time and jump directly to JSGlobalObject.
-    if (attr != KJS::None && attr != KJS::DontDelete) {
-        KJS::JSGlobalObject::put(exec, propertyName, value, attr);
+    if (attr != None && attr != DontDelete) {
+        JSGlobalObject::put(exec, propertyName, value, attr);
         return true;
     }
 
     // We have a local override (e.g. "var location"), save time and jump directly to JSGlobalObject.
-    KJS::PropertySlot slot;
-    if (KJS::JSGlobalObject::getOwnPropertySlot(exec, propertyName, slot)) {
+    PropertySlot slot;
+    if (JSGlobalObject::getOwnPropertySlot(exec, propertyName, slot)) {
         if (allowsAccessFrom(exec))
-            KJS::JSGlobalObject::put(exec, propertyName, value, attr);
+            JSGlobalObject::put(exec, propertyName, value, attr);
         return true;
     }
 
     return false;
 }
 
-KJS::JSValue* JSDOMWindow::postMessage(KJS::ExecState* exec, const KJS::List& args)
+void JSDOMWindow::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
+{
+    // Only allow the window to enumerated by frames in the same origin.
+    if (!allowsAccessFrom(exec))
+        return;
+    Base::getPropertyNames(exec, propertyNames);
+}
+
+JSValue* JSDOMWindow::postMessage(ExecState* exec, const List& args)
 {
     DOMWindow* window = impl();
     
@@ -125,11 +135,11 @@ KJS::JSValue* JSDOMWindow::postMessage(KJS::ExecState* exec, const KJS::List& ar
     String message = args[0]->toString(exec);
     
     if (exec->hadException())
-        return KJS::jsUndefined();
+        return jsUndefined();
     
     window->postMessage(message, domain, uri, source);
     
-    return KJS::jsUndefined();
+    return jsUndefined();
 }
 
 } // namespace WebCore
diff --git a/WebCore/bindings/js/JSHistoryCustom.cpp b/WebCore/bindings/js/JSHistoryCustom.cpp
new file mode 100644 (file)
index 0000000..a1e5c0e
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 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 "JSHistory.h"
+
+#include "Frame.h"
+#include "History.h"
+#include "kjs_window.h"
+
+using namespace KJS;
+
+namespace WebCore {
+
+static bool allowsAccessFromFrame(ExecState* exec, Frame* frame)
+{
+    if (!frame)
+        return false;
+    Window* win = Window::retrieveWindow(frame);
+    return win && win->allowsAccessFrom(exec);
+}
+
+bool JSHistory::customGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+    // Allow access to back(), forward() and go() from any frame.
+    JSValue* proto = prototype();
+    if (proto->isObject()) {
+        const HashEntry* entry = Lookup::findEntry(static_cast<JSObject*>(proto)->classInfo()->propHashTable, propertyName);
+        if (entry && entry->attr & Function) {
+            if (entry->value.functionValue == jsHistoryPrototypeFunctionBack
+                    || entry->value.functionValue == jsHistoryPrototypeFunctionForward
+                    || entry->value.functionValue == jsHistoryPrototypeFunctionGo)
+                return false;
+        }
+    }
+
+    // Allow access to toString() from any frame as well.
+    if (propertyName == exec->propertyNames().toString)
+        return false;
+
+    if (!allowsAccessFromFrame(exec, impl()->frame())) {
+        slot.setUndefined(this);
+        return true;
+    }
+
+    return false;
+}
+
+bool JSHistory::customPut(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr)
+{
+    // Only allow putting by frames in the same origin.
+    if (!allowsAccessFromFrame(exec, impl()->frame()))
+        return true;
+    return false;
+}
+
+void JSHistory::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
+{
+    // Only allow the history object to enumerated by frames in the same origin.
+    if (!allowsAccessFromFrame(exec, impl()->frame()))
+        return;
+    Base::getPropertyNames(exec, propertyNames);
+}
+
+} // namespace WebCore
index aa423f0cf52e021688b985bd43d39191b9882189..cf91a46ac916b7813a6221a6bfce90843983de41 100644 (file)
@@ -1,8 +1,7 @@
-// -*- c-basic-offset: 4 -*-
 /*
  *  Copyright (C) 2000 Harri Porten (porten@kde.org)
  *  Copyright (C) 2006 Jon Shier (jshier@iastate.edu)
- *  Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reseved.
+ *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reseved.
  *  Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
  *
  *  This library is free software; you can redistribute it and/or
@@ -37,6 +36,14 @@ using namespace KJS;
 
 namespace WebCore {
 
+static bool allowsAccessFromFrame(ExecState* exec, Frame* frame)
+{
+    if (!frame)
+        return false;
+    Window* win = Window::retrieveWindow(frame);
+    return win && win->allowsAccessFrom(exec);
+}
+
 const ClassInfo JSLocation::info = { "Location", 0, &JSLocationTable };
 
 /*
@@ -191,6 +198,14 @@ void JSLocation::put(ExecState* exec, const Identifier& propertyName, JSValue* v
   }
 }
 
+void JSLocation::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
+{
+    // Only allow the location object to enumerated by frames in the same origin.
+    if (!allowsAccessFromFrame(exec, frame()))
+        return;
+    Base::getPropertyNames(exec, propertyNames);
+}
+
 JSValue* jsLocationProtoFuncReplace(ExecState* exec, JSObject* thisObj, const List& args)
 {
     if (!thisObj->inherits(&JSLocation::info))
index 34f467464df6b0204c131653c4527eccbe0f4bf0..c831b6d56294c4a6c46de39eabcc621b1e6416eb 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Copyright (C) 2000 Harri Porten (porten@kde.org)
- *  Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reseved.
+ *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reseved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
@@ -31,6 +31,8 @@ namespace WebCore {
     class Frame;
 
     class JSLocation : public KJS::DOMObject {
+        typedef KJS::DOMObject Base;
+
         friend class KJS::Window;
     public:
         JSLocation(KJS::JSObject* protoype, Frame*);
@@ -39,6 +41,8 @@ namespace WebCore {
         KJS::JSValue* getValueProperty(KJS::ExecState*, int token) const;
         virtual void put(KJS::ExecState*, const KJS::Identifier&, KJS::JSValue*, int attr = KJS::None);
 
+        virtual void getPropertyNames(KJS::ExecState*, KJS::PropertyNameArray&);
+
         enum {
             Hash, Href, Hostname, Host,
             Pathname, Port, Protocol, Search,
index 13fb3bf8659adfcbd871880daac86d1edc5b4b01..5a1a87f8714bab46570c867a2f9a6186eb955f30 100644 (file)
@@ -1,8 +1,7 @@
-// -*- c-basic-offset: 4 -*-
 /*
  *  Copyright (C) 2000 Harri Porten (porten@kde.org)
  *  Copyright (C) 2006 Jon Shier (jshier@iastate.edu)
- *  Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reseved.
+ *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reseved.
  *  Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
  *
  *  This library is free software; you can redistribute it and/or
@@ -876,13 +875,6 @@ bool Window::shouldInterruptScript() const
     return page->chrome()->shouldInterruptJavaScript();
 }
 
-void Window::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
-{
-    if (!allowsAccessFrom(exec))
-        return;
-    Base::getPropertyNames(exec, propertyNames);
-}
-
 void Window::setListener(ExecState* exec, const AtomicString& eventType, JSValue* func)
 {
     ASSERT(impl()->frame());
index 7f9d1a8810e7727912e9e03eec26da0834d3469f..415a19a8203e7dedc9890fbc9f1a8bc5ab72650d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Copyright (C) 2000 Harri Porten (porten@kde.org)
- *  Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reseved.
+ *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reseved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
@@ -41,8 +41,6 @@ namespace WebCore {
 namespace KJS {
 
     class DOMWindowTimer;
-    class Window;
-    class WindowFunc;
     class WindowPrivate;
 
   // This is the only WebCore JS binding which does not inherit from DOMObject
@@ -126,8 +124,6 @@ namespace KJS {
     virtual bool allowsAccessFrom(const JSGlobalObject*) const;
     bool allowsAccessFrom(ExecState* exec) const { return allowsAccessFrom(exec->dynamicGlobalObject()); }
 
-    virtual void getPropertyNames(ExecState*, PropertyNameArray&);
-
     enum {
         // Attributes
         Crypto, Event_, Location_, Navigator_,
index fc67dc5bcad8c279e44da293c8506757aef2fcde..15f9af2e33df47f5a2a9471baebe2cf15addbfc1 100644 (file)
@@ -3,7 +3,7 @@
 # Copyright (C) 2006 Anders Carlsson <andersca@mac.com>
 # Copyright (C) 2006, 2007 Samuel Weinig <sam@webkit.org>
 # Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org>
-# Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+# Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Library General Public
@@ -317,6 +317,7 @@ sub GenerateHeader
 
     # Class declaration
     push(@headerContent, "class $className : public $parentClassName {\n");
+    push(@headerContent, "    typedef $parentClassName Base;\n");
     push(@headerContent, "public:\n");
 
     # Constructor
@@ -327,17 +328,13 @@ sub GenerateHeader
     }
 
     # Destructor
-    if (!$hasParent or $interfaceName eq "Document") {
-        push(@headerContent, "    virtual ~$className();\n");
-    }
+    push(@headerContent, "    virtual ~$className();\n") if (!$hasParent or $interfaceName eq "Document");
 
     # Getters
     if ($numAttributes > 0 || $dataNode->extendedAttributes->{"GenerateConstructor"}) {
         push(@headerContent, "    virtual bool getOwnPropertySlot(KJS::ExecState*, const KJS::Identifier&, KJS::PropertySlot&);\n");
         push(@headerContent, "    KJS::JSValue* getValueProperty(KJS::ExecState*, int token) const;\n");
-        if ($dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"}) {
-            push(@headerContent, "    bool customGetOwnPropertySlot(KJS::ExecState*, const KJS::Identifier&, KJS::PropertySlot&);\n");
-        }
+        push(@headerContent, "    bool customGetOwnPropertySlot(KJS::ExecState*, const KJS::Identifier&, KJS::PropertySlot&);\n") if $dataNode->extendedAttributes->{"CustomGetOwnPropertySlot"};
     }
 
     # Check if we have any writable properties
@@ -348,27 +345,19 @@ sub GenerateHeader
         }
     }
 
-    if ($hasReadWriteProperties) {
-        push(@headerContent, "    virtual void put(KJS::ExecState*, const KJS::Identifier&, KJS::JSValue*, int attr = KJS::None);\n");
-        push(@headerContent, "    void putValueProperty(KJS::ExecState*, int, KJS::JSValue*, int attr);\n");
-        if ($dataNode->extendedAttributes->{"CustomPutFunction"}) {
-            push(@headerContent, "    bool customPut(KJS::ExecState*, const KJS::Identifier&, KJS::JSValue*, int attr);\n");
-        }
-    }
+    push(@headerContent, "    virtual void put(KJS::ExecState*, const KJS::Identifier&, KJS::JSValue*, int attr = KJS::None);\n") if ($hasReadWriteProperties || $dataNode->extendedAttributes->{"CustomPutFunction"});
+    push(@headerContent, "    void putValueProperty(KJS::ExecState*, int, KJS::JSValue*, int attr);\n") if $hasReadWriteProperties;
+    push(@headerContent, "    bool customPut(KJS::ExecState*, const KJS::Identifier&, KJS::JSValue*, int attr);\n") if $dataNode->extendedAttributes->{"CustomPutFunction"};
 
     # Class info
     push(@headerContent, "    virtual const KJS::ClassInfo* classInfo() const { return &info; }\n");
     push(@headerContent, "    static const KJS::ClassInfo info;\n\n");
 
     # Custom mark function
-    if ($dataNode->extendedAttributes->{"CustomMarkFunction"}) {
-        push(@headerContent, "    virtual void mark();\n\n");
-    }
+    push(@headerContent, "    virtual void mark();\n\n") if $dataNode->extendedAttributes->{"CustomMarkFunction"};
 
     # Custom pushEventHandlerScope function
-    if ($dataNode->extendedAttributes->{"CustomPushEventHandlerScope"}) {
-        push(@headerContent, "    virtual void pushEventHandlerScope(KJS::ExecState*, KJS::ScopeChain&) const;\n\n");
-    }
+    push(@headerContent, "    virtual void pushEventHandlerScope(KJS::ExecState*, KJS::ScopeChain&) const;\n\n")  if $dataNode->extendedAttributes->{"CustomPushEventHandlerScope"};
 
     # Custom call functions
     if ($dataNode->extendedAttributes->{"CustomCall"}) {
@@ -376,10 +365,11 @@ sub GenerateHeader
         push(@headerContent, "    virtual bool implementsCall() const;\n\n");
     }
 
+    # Custom getPropertyNames function
+    push(@headerContent, "    virtual void getPropertyNames(KJS::ExecState*, KJS::PropertyNameArray&);\n") if $dataNode->extendedAttributes->{"CustomGetPropertyNames"};
+
     # Constructor object getter
-    if ($dataNode->extendedAttributes->{"GenerateConstructor"}) {
-        push(@headerContent, "    static KJS::JSValue* getConstructor(KJS::ExecState*);\n");
-    }
+    push(@headerContent, "    static KJS::JSValue* getConstructor(KJS::ExecState*);\n") if $dataNode->extendedAttributes->{"GenerateConstructor"};
 
     my $numCustomFunctions = 0;
     my $numCustomAttributes = 0;
@@ -761,7 +751,7 @@ sub GenerateImplementation
     # - Initialize static ClassInfo object
     push(@implContent, "const ClassInfo $className" . "::info = { \"${visibleClassName}\", ");
     if ($hasParent) {
-        push(@implContent, "&" .$parentClassName . "::info, ");
+        push(@implContent, "&" . $parentClassName . "::info, ");
     } else {
         push(@implContent, "0, ");
     }
@@ -879,9 +869,9 @@ sub GenerateImplementation
         }
 
         if ($requiresManualLookup) {
-            push(@implContent, "    return ${parentClassName}::getOwnPropertySlot(exec, propertyName, slot);\n");
+            push(@implContent, "    return Base::getOwnPropertySlot(exec, propertyName, slot);\n");
         } else {
-            push(@implContent, "    return getStaticValueSlot<$className, $parentClassName>(exec, &${className}Table, this, propertyName, slot);\n");
+            push(@implContent, "    return getStaticValueSlot<$className, Base>(exec, &${className}Table, this, propertyName, slot);\n");
         }
         push(@implContent, "}\n\n");
 
@@ -972,7 +962,7 @@ sub GenerateImplementation
         foreach my $attribute (@{$dataNode->attributes}) {
             $hasReadWriteProperties = 1 if $attribute->type !~ /^readonly/;
         }
-        if ($hasReadWriteProperties) {
+        if ($hasReadWriteProperties || $dataNode->extendedAttributes->{"CustomPutFunction"}) {
             push(@implContent, "void ${className}::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr)\n");
             push(@implContent, "{\n");
             if ($dataNode->extendedAttributes->{"HasCustomIndexSetter"}) {
@@ -987,69 +977,79 @@ sub GenerateImplementation
                 push(@implContent, "    if (customPut(exec, propertyName, value, attr))\n");
                 push(@implContent, "        return;\n");
             }
+            if ($hasReadWriteProperties) {
+                push(@implContent, "    lookupPut<$className, Base>(exec, propertyName, value, attr, &${className}Table, this);\n");
+            } else {
+                push(@implContent, "    Base::put(exec, propertyName, value, attr);\n");
+            }
 
-            push(@implContent, "    lookupPut<$className, $parentClassName>(exec, propertyName, value, attr, &${className}Table, this);\n");
             push(@implContent, "}\n\n");
 
-            push(@implContent, "void ${className}::putValueProperty(ExecState* exec, int token, JSValue* value, int /*attr*/)\n");
-            push(@implContent, "{\n");
+            if ($hasReadWriteProperties) {
+                push(@implContent, "void ${className}::putValueProperty(ExecState* exec, int token, JSValue* value, int /*attr*/)\n");
+                push(@implContent, "{\n");
 
-            push(@implContent, "    switch (token) {\n");
+                push(@implContent, "    switch (token) {\n");
 
-            foreach my $attribute (@{$dataNode->attributes}) {
-                if ($attribute->type !~ /^readonly/) {
-                    my $name = $attribute->signature->name;
-                    my $setterFunctionName = $codeGenerator->WK_ucfirst($name);
+                foreach my $attribute (@{$dataNode->attributes}) {
+                    if ($attribute->type !~ /^readonly/) {
+                        my $name = $attribute->signature->name;
+                        my $setterFunctionName = $codeGenerator->WK_ucfirst($name);
 
-                    push(@implContent, "    case " . $codeGenerator->WK_ucfirst($attribute->signature->name)
-                        . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : "")
-                        . "AttrNum: {\n");
+                        push(@implContent, "    case " . $codeGenerator->WK_ucfirst($attribute->signature->name)
+                            . ($attribute->signature->type =~ /Constructor$/ ? "Constructor" : "")
+                            . "AttrNum: {\n");
 
-                    if ($dataNode->extendedAttributes->{"CheckDomainSecurity"} && !$attribute->signature->extendedAttributes->{"DoNotCheckDomainSecurity"}) {
-                        push(@implContent, "        if (!allowsAccessFrom(exec))\n");
-                        push(@implContent, "            return;\n");
-                    }
-
-                    if ($attribute->signature->extendedAttributes->{"Custom"} || $attribute->signature->extendedAttributes->{"CustomSetter"}) {
-                        push(@implContent, "        set$setterFunctionName(exec, value);\n");
-                    } elsif ($attribute->signature->type =~ /Constructor$/) {
-                        my $constructorType = $attribute->signature->type;
-                        $constructorType =~ s/Constructor$//;
-                        $implIncludes{"JS" . $constructorType . ".h"} = 1;
-                        push(@implContent, "        // Shadowing a built-in constructor\n");
-                        push(@implContent, "        putDirect(\"$name\", value);\n");
-                    } elsif ($attribute->signature->extendedAttributes->{"Replaceable"}) {
-                        push(@implContent, "        putDirect(\"$name\", value);\n");
-                    } else {
-                        if ($podType) {
-                            push(@implContent, "        $podType imp(*impl());\n");
-                            if ($podType eq "float") { # Special case for JSSVGNumber
-                                push(@implContent, "        imp = " . JSValueToNative($attribute->signature, "value") . ";\n");
+                        if ($dataNode->extendedAttributes->{"CheckDomainSecurity"} && !$attribute->signature->extendedAttributes->{"DoNotCheckDomainSecurity"}) {
+                            if ($interfaceName eq "DOMWindow") {
+                                push(@implContent, "        if (!allowsAccessFrom(exec))\n");
                             } else {
-                                push(@implContent, "        imp.set$setterFunctionName(" . JSValueToNative($attribute->signature, "value") . ");\n");
+                                push(@implContent, "        if (!allowsAccessFromFrame(exec, impl()->frame()))\n");
                             }
-                            push(@implContent, "        m_impl->commitChange(exec, imp);\n");
+                            push(@implContent, "            return;\n");
+                        }
+
+                        if ($attribute->signature->extendedAttributes->{"Custom"} || $attribute->signature->extendedAttributes->{"CustomSetter"}) {
+                            push(@implContent, "        set$setterFunctionName(exec, value);\n");
+                        } elsif ($attribute->signature->type =~ /Constructor$/) {
+                            my $constructorType = $attribute->signature->type;
+                            $constructorType =~ s/Constructor$//;
+                            $implIncludes{"JS" . $constructorType . ".h"} = 1;
+                            push(@implContent, "        // Shadowing a built-in constructor\n");
+                            push(@implContent, "        putDirect(\"$name\", value);\n");
+                        } elsif ($attribute->signature->extendedAttributes->{"Replaceable"}) {
+                            push(@implContent, "        putDirect(\"$name\", value);\n");
                         } else {
-                            push(@implContent, "        $implClassName* imp = static_cast<$implClassName*>(impl());\n");
-                            push(@implContent, "        ExceptionCode ec = 0;\n") if @{$attribute->setterExceptions};
-                            push(@implContent, "        imp->set$setterFunctionName(" . JSValueToNative($attribute->signature, "value"));
-                            push(@implContent, ", ec") if @{$attribute->setterExceptions};
-                            push(@implContent, ");\n");
-                            push(@implContent, "        setDOMException(exec, ec);\n") if @{$attribute->setterExceptions};
+                            if ($podType) {
+                                push(@implContent, "        $podType imp(*impl());\n");
+                                if ($podType eq "float") { # Special case for JSSVGNumber
+                                    push(@implContent, "        imp = " . JSValueToNative($attribute->signature, "value") . ";\n");
+                                } else {
+                                    push(@implContent, "        imp.set$setterFunctionName(" . JSValueToNative($attribute->signature, "value") . ");\n");
+                                }
+                                push(@implContent, "        m_impl->commitChange(exec, imp);\n");
+                            } else {
+                                push(@implContent, "        $implClassName* imp = static_cast<$implClassName*>(impl());\n");
+                                push(@implContent, "        ExceptionCode ec = 0;\n") if @{$attribute->setterExceptions};
+                                push(@implContent, "        imp->set$setterFunctionName(" . JSValueToNative($attribute->signature, "value"));
+                                push(@implContent, ", ec") if @{$attribute->setterExceptions};
+                                push(@implContent, ");\n");
+                                push(@implContent, "        setDOMException(exec, ec);\n") if @{$attribute->setterExceptions};
+                            }
                         }
+                        push(@implContent, "        break;\n");
+                        push(@implContent, "    }\n");
                     }
-                    push(@implContent, "        break;\n");
-                    push(@implContent, "    }\n");
                 }
-            }
-            push(@implContent, "    }\n"); # end switch
+                push(@implContent, "    }\n"); # end switch
 
-            if (IsSVGTypeNeedingContextParameter($implClassName)) {
-                push(@implContent, "    if (context())\n");
-                push(@implContent, "        context()->notifyAttributeChange();\n");
-            }
+                if (IsSVGTypeNeedingContextParameter($implClassName)) {
+                    push(@implContent, "    if (context())\n");
+                    push(@implContent, "        context()->notifyAttributeChange();\n");
+                }
 
-            push(@implContent, "}\n\n"); # end function
+                push(@implContent, "}\n\n"); # end function
+            }
         }
     }
 
@@ -1218,7 +1218,7 @@ sub GenerateImplementation
     if ($dataNode->extendedAttributes->{"GenerateNativeConverter"} && $hasParent) {
         push(@implContent, "\n$implClassName* ${className}::impl() const\n");
         push(@implContent, "{\n");
-        push(@implContent, "    return static_cast<$implClassName*>(${parentClassName}::impl());\n");
+        push(@implContent, "    return static_cast<$implClassName*>(Base::impl());\n");
         push(@implContent, "}\n");
     }
 
index 3c508397d3ec7351a3454f5d8c011338b9b22255..22f037dd496e0831e639bc6e1883968e6d3a0264 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -25,7 +25,7 @@
 
 module window {
 
-    interface [LegacyParent=KJS::Window, DoNotCache, CheckDomainSecurity, GenerateNativeConverter, CustomGetOwnPropertySlot, CustomPutFunction] DOMWindow {
+    interface [LegacyParent=KJS::Window, DoNotCache, CheckDomainSecurity, GenerateNativeConverter, CustomGetOwnPropertySlot, CustomPutFunction, CustomGetPropertyNames] DOMWindow {
         // DOM Level 0
         readonly attribute Screen screen;
         readonly attribute [DoNotCheckDomainSecurity] History history;
index 45d91ff66c4d6b7a7d702d39f8333f6710cdaf11..217518080fe8da3aca9c5a902296d07dfee430d9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 Apple Inc.  All rights reserved.
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -25,7 +25,7 @@
 
 module window {
 
-    interface History {
+    interface [CustomGetOwnPropertySlot, CustomPutFunction, CustomGetPropertyNames] History {
         readonly attribute unsigned long length;
 
         void back();