WebCore:
authorweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 27 Apr 2008 01:56:37 +0000 (01:56 +0000)
committerweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 27 Apr 2008 01:56:37 +0000 (01:56 +0000)
2008-04-26  Adam Barth  <hk9565@gmail.com>

        Reviewed by Adam Roben and Sam Weinig.

        Fixes bug http://bugs.webkit.org/show_bug.cgi?id=17331
        Fixes bug http://bugs.webkit.org/show_bug.cgi?id=16848

        Updates postMessage implementation to match HTML 5 specification:
        1) Adds origin parameter to postMessage.
        2) Removes domain and uri attributes of MessageEvent in favor of
           origin attribute.

        In order to do this correctly, we need to distinguish between hosts and domains
        in the SecurityOrigin class. There are now three ways to compare security origins:
        1) isSameSchemeHostPort compares scheme, host, and port, and is used for postMessage
        2) equal compares all aspects of the security origin, and is used for hash keys
        3) canAccess understands the semantics of schemes such as file:// and data:// URLs,
           and should be used for scripting access checks.

        Changed SecurityOrigin::toString() to generate identifiers that are suitable for
        being used as a MessageEvent's origin property. In the future, they could be used
        as database string identifiers as well. Re-used KURL parser to parse serialized
        SecurityOrigins.

        Collin Jackson <collinj-webkit@collinjackson.com> also contributed to this patch.

        Tests: http/tests/security/postMessage/invalid-origin-throws-exception.html
               http/tests/security/postMessage/javascript-page-still-sends-origin.html
               http/tests/security/postMessage/origin-unaffected-by-base-tag.html
               http/tests/security/postMessage/origin-unaffected-by-document-domain.html
               http/tests/security/postMessage/target-origin.html

        * WebCore.base.exp:
        * bindings/js/JSDOMWindowCustom.cpp:
        (WebCore::JSDOMWindow::postMessage):
        * dom/Document.cpp:
        (WebCore::Document::domain):
        * dom/MessageEvent.cpp:
        (WebCore::MessageEvent::MessageEvent):
        (WebCore::MessageEvent::initMessageEvent):
        * dom/MessageEvent.h:
        (WebCore::MessageEvent::origin):
        * dom/MessageEvent.idl:
        * html/CanvasRenderingContext2D.cpp:
        (WebCore::CanvasRenderingContext2D::checkOrigin):
        (WebCore::CanvasRenderingContext2D::createPattern):
        * page/DOMWindow.cpp:
        (WebCore::DOMWindow::postMessage):
        * page/DOMWindow.h:
        * page/DOMWindow.idl:
        * platform/SecurityOrigin.cpp:
        (WebCore::SecurityOrigin::SecurityOrigin):
        (WebCore::SecurityOrigin::create):
        (WebCore::SecurityOrigin::createForFrame):
        (WebCore::SecurityOrigin::copy):
        (WebCore::SecurityOrigin::setDomainFromDOM):
        (WebCore::SecurityOrigin::canAccess):
        (WebCore::SecurityOrigin::isSecureTransitionTo):
        (WebCore::SecurityOrigin::toString):
        (WebCore::SecurityOrigin::createFromString):
        (WebCore::SecurityOrigin::createFromDatabaseIdentifier):
        (WebCore::SecurityOrigin::databaseIdentifier):
        (WebCore::SecurityOrigin::equal):
        (WebCore::SecurityOrigin::isSameSchemeHostPort):
        * platform/SecurityOrigin.h:
        (WebCore::SecurityOrigin::host):
        (WebCore::SecurityOrigin::domain):
        * platform/SecurityOriginHash.h:
        (WebCore::SecurityOriginTraits::deletedValue):
        * storage/DatabaseTracker.cpp:
        (WebCore::DatabaseTracker::hasEntryForDatabase):
        (WebCore::DatabaseTracker::originPath):
        (WebCore::DatabaseTracker::fullPathForDatabase):
        (WebCore::DatabaseTracker::populateOrigins):
        (WebCore::DatabaseTracker::databaseNamesForOrigin):
        (WebCore::DatabaseTracker::detailsForNameAndOrigin):
        (WebCore::DatabaseTracker::setDatabaseDetails):
        (WebCore::DatabaseTracker::setQuota):
        (WebCore::DatabaseTracker::addDatabase):
        (WebCore::DatabaseTracker::deleteOrigin):
        (WebCore::DatabaseTracker::deleteDatabase):

WebKit/mac:

2008-04-20 Adam Barth <hk9565@gmail.com>

        Reviewed by Adam Roben and Sam Weinig.

        Updated WebSecurityOrigin to match new SecurityOrigin API.

        Collin Jackson <collinj-webkit@collinjackson.com> also contributed to this patch.

        * Storage/WebSecurityOrigin.mm:
        (-[WebSecurityOrigin host]):
        (-[WebSecurityOrigin domain]):
        * Storage/WebSecurityOriginPrivate.h:

WebKit/win:

2008-04-26  Adam Barth <hk9565@gmail.com>

        Reviewed by Adam Roben and Sam Weinig.

        Renamed "domain" method to "host" to match SecurityOrigin.

        * Interfaces/IWebSecurityOrigin.idl:
        * WebSecurityOrigin.cpp:
        (WebSecurityOrigin::host):
        * WebSecurityOrigin.h:

WebKitTools:

2008-04-26  Adam Barth <hk9565@gmail.com>

        Reviewed by Adam Roben and Sam Weinig.

        Updates LayoutTestController to use host instead of domain.

        Collin Jackson <collinj-webkit@collinjackson.com> also contributed to this patch.

        * DumpRenderTree/mac/LayoutTestControllerMac.mm:
        (LayoutTestController::setDatabaseQuota):
        * DumpRenderTree/mac/UIDelegate.mm:
        (-[UIDelegate webView:frame:exceededDatabaseQuotaForSecurityOrigin:database:]):

LayoutTests:

2008-04-26  Adam Barth  <hk9565@gmail.com>

        Reviewed by Adam Roben and Sam Weinig.

        Update LayoutTests for new postMessage API.

        Collin Jackson <collinj-webkit@collinjackson.com> also contributed to this patch.

        * http/tests/security/postMessage/domain-and-uri-unaffected-by-base-tag-expected.txt: Removed.
        * http/tests/security/postMessage/domain-and-uri-unaffected-by-base-tag.html: Removed.
        * http/tests/security/postMessage/domain-unaffected-by-document-domain-expected.txt: Removed.
        * http/tests/security/postMessage/domain-unaffected-by-document-domain.html: Removed.
        * http/tests/security/postMessage/invalid-origin-throws-exception-expected.txt: Added.
        * http/tests/security/postMessage/invalid-origin-throws-exception.html: Added.
        * http/tests/security/postMessage/javascript-page-still-sends-domain-expected.txt: Removed.
        * http/tests/security/postMessage/javascript-page-still-sends-domain.html: Removed.
        * http/tests/security/postMessage/javascript-page-still-sends-origin-expected.txt: Copied from LayoutTests/http/tests/security/postMessage/javascript-page-still-sends-domain-expected.txt.
        * http/tests/security/postMessage/javascript-page-still-sends-origin.html: Copied from LayoutTests/http/tests/security/postMessage/javascript-page-still-sends-domain.html.
        * http/tests/security/postMessage/origin-unaffected-by-base-tag-expected.txt: Copied from LayoutTests/http/tests/security/postMessage/domain-and-uri-unaffected-by-base-tag-expected.txt.
        * http/tests/security/postMessage/origin-unaffected-by-base-tag.html: Copied from LayoutTests/http/tests/security/postMessage/domain-and-uri-unaffected-by-base-tag.html.
        * http/tests/security/postMessage/origin-unaffected-by-document-domain-expected.txt: Copied from LayoutTests/http/tests/security/postMessage/domain-unaffected-by-document-domain-expected.txt.
        * http/tests/security/postMessage/origin-unaffected-by-document-domain.html: Copied from LayoutTests/http/tests/security/postMessage/domain-unaffected-by-document-domain.html.
        * http/tests/security/postMessage/target-origin-expected.txt: Added.
        * http/tests/security/postMessage/target-origin.html: Added.

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

42 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/messaging/cross-domain-message-send-expected.txt
LayoutTests/http/tests/messaging/resources/cross-domain-message-receive.html
LayoutTests/http/tests/security/postMessage/domain-and-uri-unaffected-by-base-tag-expected.txt [deleted file]
LayoutTests/http/tests/security/postMessage/domain-unaffected-by-document-domain-expected.txt [deleted file]
LayoutTests/http/tests/security/postMessage/invalid-origin-throws-exception-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/security/postMessage/invalid-origin-throws-exception.html [new file with mode: 0644]
LayoutTests/http/tests/security/postMessage/javascript-page-still-sends-domain-expected.txt [deleted file]
LayoutTests/http/tests/security/postMessage/javascript-page-still-sends-origin-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/security/postMessage/javascript-page-still-sends-origin.html [moved from LayoutTests/http/tests/security/postMessage/javascript-page-still-sends-domain.html with 88% similarity]
LayoutTests/http/tests/security/postMessage/origin-unaffected-by-base-tag-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/security/postMessage/origin-unaffected-by-base-tag.html [moved from LayoutTests/http/tests/security/postMessage/domain-and-uri-unaffected-by-base-tag.html with 100% similarity]
LayoutTests/http/tests/security/postMessage/origin-unaffected-by-document-domain-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/security/postMessage/origin-unaffected-by-document-domain.html [moved from LayoutTests/http/tests/security/postMessage/domain-unaffected-by-document-domain.html with 100% similarity]
LayoutTests/http/tests/security/postMessage/resources/post-message-listener.html
LayoutTests/http/tests/security/postMessage/target-origin-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/security/postMessage/target-origin.html [new file with mode: 0644]
WebCore/ChangeLog
WebCore/WebCore.base.exp
WebCore/bindings/js/JSDOMWindowCustom.cpp
WebCore/dom/Document.cpp
WebCore/dom/MessageEvent.cpp
WebCore/dom/MessageEvent.h
WebCore/dom/MessageEvent.idl
WebCore/html/CanvasRenderingContext2D.cpp
WebCore/page/DOMWindow.cpp
WebCore/page/DOMWindow.h
WebCore/page/DOMWindow.idl
WebCore/platform/SecurityOrigin.cpp
WebCore/platform/SecurityOrigin.h
WebCore/platform/SecurityOriginHash.h
WebCore/storage/DatabaseTracker.cpp
WebKit/mac/ChangeLog
WebKit/mac/Storage/WebSecurityOrigin.mm
WebKit/mac/Storage/WebSecurityOriginPrivate.h
WebKit/win/ChangeLog
WebKit/win/Interfaces/IWebSecurityOrigin.idl
WebKit/win/WebSecurityOrigin.cpp
WebKit/win/WebSecurityOrigin.h
WebKitTools/ChangeLog
WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm
WebKitTools/DumpRenderTree/mac/UIDelegate.mm

index fd265f7..3d03d21 100644 (file)
@@ -1,3 +1,28 @@
+2008-04-26  Adam Barth  <hk9565@gmail.com>
+
+        Reviewed by Adam Roben and Sam Weinig.
+
+        Update LayoutTests for new postMessage API.
+
+        Collin Jackson <collinj-webkit@collinjackson.com> also contributed to this patch.
+
+        * http/tests/security/postMessage/domain-and-uri-unaffected-by-base-tag-expected.txt: Removed.
+        * http/tests/security/postMessage/domain-and-uri-unaffected-by-base-tag.html: Removed.
+        * http/tests/security/postMessage/domain-unaffected-by-document-domain-expected.txt: Removed.
+        * http/tests/security/postMessage/domain-unaffected-by-document-domain.html: Removed.
+        * http/tests/security/postMessage/invalid-origin-throws-exception-expected.txt: Added.
+        * http/tests/security/postMessage/invalid-origin-throws-exception.html: Added.
+        * http/tests/security/postMessage/javascript-page-still-sends-domain-expected.txt: Removed.
+        * http/tests/security/postMessage/javascript-page-still-sends-domain.html: Removed.
+        * http/tests/security/postMessage/javascript-page-still-sends-origin-expected.txt: Copied from LayoutTests/http/tests/security/postMessage/javascript-page-still-sends-domain-expected.txt.
+        * http/tests/security/postMessage/javascript-page-still-sends-origin.html: Copied from LayoutTests/http/tests/security/postMessage/javascript-page-still-sends-domain.html.
+        * http/tests/security/postMessage/origin-unaffected-by-base-tag-expected.txt: Copied from LayoutTests/http/tests/security/postMessage/domain-and-uri-unaffected-by-base-tag-expected.txt.
+        * http/tests/security/postMessage/origin-unaffected-by-base-tag.html: Copied from LayoutTests/http/tests/security/postMessage/domain-and-uri-unaffected-by-base-tag.html.
+        * http/tests/security/postMessage/origin-unaffected-by-document-domain-expected.txt: Copied from LayoutTests/http/tests/security/postMessage/domain-unaffected-by-document-domain-expected.txt.
+        * http/tests/security/postMessage/origin-unaffected-by-document-domain.html: Copied from LayoutTests/http/tests/security/postMessage/domain-unaffected-by-document-domain.html.
+        * http/tests/security/postMessage/target-origin-expected.txt: Added.
+        * http/tests/security/postMessage/target-origin.html: Added.
+
 2008-04-26  Anatoli Papirovski  <apapirovski@mac.com>
 
         Reviewed by Dave Hyatt.
index 9b83ec4..1224122 100644 (file)
@@ -1,2 +1,2 @@
 
-data: Something uri: http://127.0.0.1:8000/messaging/cross-domain-message-send.html domain: 127.0.0.1
+data: Something origin: http://127.0.0.1:8000
index cbc8a34..defb573 100644 (file)
@@ -9,8 +9,7 @@
 function receiver(e) {
     var result = "";
     result += "data: " + e.data + "\n";
-    result += "uri: " + e.uri + "\n";
-    result += "domain: " + e.domain + "\n";
+    result += "origin: " + e.origin + "\n";
     e.source.postMessage(result);   
 }
 
diff --git a/LayoutTests/http/tests/security/postMessage/domain-and-uri-unaffected-by-base-tag-expected.txt b/LayoutTests/http/tests/security/postMessage/domain-and-uri-unaffected-by-base-tag-expected.txt
deleted file mode 100644 (file)
index ba56394..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-window.location.href = http://127.0.0.1:8000/security/postMessage/domain-and-uri-unaffected-by-base-tag.html
-
-Received message: data="Message from parent" domain="127.0.0.1" uri="http://127.0.0.1:8000/security/postMessage/domain-and-uri-unaffected-by-base-tag.html"
diff --git a/LayoutTests/http/tests/security/postMessage/domain-unaffected-by-document-domain-expected.txt b/LayoutTests/http/tests/security/postMessage/domain-unaffected-by-document-domain-expected.txt
deleted file mode 100644 (file)
index 3102b11..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-window.location.href = http://127.0.0.1:8000/security/postMessage/domain-unaffected-by-document-domain.html
-document.domain = 0.0.1
-
-Received message: data="Message from parent" domain="127.0.0.1" uri="http://127.0.0.1:8000/security/postMessage/domain-unaffected-by-document-domain.html"
diff --git a/LayoutTests/http/tests/security/postMessage/invalid-origin-throws-exception-expected.txt b/LayoutTests/http/tests/security/postMessage/invalid-origin-throws-exception-expected.txt
new file mode 100644 (file)
index 0000000..00b17ff
--- /dev/null
@@ -0,0 +1,17 @@
+CONSOLE MESSAGE: line 0: Unable to post message to asdf:. Recipient has origin http://localhost:8000.
+
+CONSOLE MESSAGE: line 0: Unable to post message to http:. Recipient has origin http://localhost:8000.
+
+CONSOLE MESSAGE: line 0: Unable to post message to /tmp/foo. Recipient has origin http://localhost:8000.
+
+CONSOLE MESSAGE: line 0: Unable to post message to //localhost. Recipient has origin http://localhost:8000.
+
+window.location.href = http://127.0.0.1:8000/security/postMessage/invalid-origin-throws-exception.html
+
+waiting...
+Encountered exception Error: SYNTAX_ERR: DOM Exception 12 while posting message to ''.
+Encountered exception Error: SYNTAX_ERR: DOM Exception 12 while posting message to 'asdf'.
+Posted message to 'asdf:' without any exceptions.
+Posted message to 'http:' without any exceptions.
+Posted message to '/tmp/foo' without any exceptions.
+Posted message to '//localhost' without any exceptions.
diff --git a/LayoutTests/http/tests/security/postMessage/invalid-origin-throws-exception.html b/LayoutTests/http/tests/security/postMessage/invalid-origin-throws-exception.html
new file mode 100644 (file)
index 0000000..575c530
--- /dev/null
@@ -0,0 +1,57 @@
+<script>
+if (window.layoutTestController)
+  layoutTestController.dumpAsText();
+</script>
+
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+if (window.layoutTestController) {
+    layoutTestController.dumpAsText();
+    layoutTestController.waitUntilDone();
+}
+
+function recv(e) {
+    document.getElementById("result").innerHTML += "<br>" + e.data;
+}
+document.addEventListener("message", recv, false);
+
+function tryPostMessage(origin) {
+  try {
+    win.postMessage("Trying origin=" + origin, origin);
+    document.getElementById("result").innerHTML += "<br>Posted message to '" + origin + "' without any exceptions.";
+  } catch(ex) {
+    document.getElementById("result").innerHTML += "<br>Encountered exception " + ex + " while posting message to '" + origin + "'.";
+  }
+}
+
+function test() {
+    var iframe = document.getElementById('child');
+    win = iframe.contentWindow;
+
+    // Non-URLs should fail with a syntax error.
+    tryPostMessage("");
+    tryPostMessage("asdf");
+
+    // URLs without an origin should fail without generating any errors.
+    tryPostMessage("asdf:");
+    tryPostMessage("http:");
+
+    // WebKit converts URLs that start with / to file:// URLs. They don't match the target frame, so they fail silently.
+    tryPostMessage("/tmp/foo");
+    tryPostMessage("//localhost");
+
+    if (window.layoutTestController)
+        layoutTestController.notifyDone();
+}
+</script>
+<body>
+<div>window.location.href = <script>document.write(window.location.href);</script></div>
+<div><iframe src="http://localhost:8000/security/postMessage/resources/post-message-listener.html" onload="test()"
+  id="child" width="800" height="300" style="border: 1px solid black;">
+</iframe></div>
+<div id="result">waiting...</div>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/security/postMessage/javascript-page-still-sends-domain-expected.txt b/LayoutTests/http/tests/security/postMessage/javascript-page-still-sends-domain-expected.txt
deleted file mode 100644 (file)
index 6070b4c..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-window.location.href = http://127.0.0.1:8000/security/postMessage/javascript-page-still-sends-domain.html
-
-Received message: data="Hello from child" domain="localhost" uri="http://localhost:8000/security/postMessage/resources/javascript-post-message-sender.html"
diff --git a/LayoutTests/http/tests/security/postMessage/javascript-page-still-sends-origin-expected.txt b/LayoutTests/http/tests/security/postMessage/javascript-page-still-sends-origin-expected.txt
new file mode 100644 (file)
index 0000000..7d871e1
--- /dev/null
@@ -0,0 +1,3 @@
+window.location.href = http://127.0.0.1:8000/security/postMessage/javascript-page-still-sends-origin.html
+
+Received message: data="Hello from child" origin="http://localhost:8000"
@@ -8,7 +8,7 @@ if (window.layoutTestController) {
 }
 
 function recv(e) {
-    var msg = 'Received message: data="' + e.data + '" domain="' + e.domain + '" uri="' + e.uri + '"';
+    var msg = 'Received message: data="' + e.data + '" origin="' + e.origin + '"';
 
     document.getElementById("result").firstChild.data = msg;
 
diff --git a/LayoutTests/http/tests/security/postMessage/origin-unaffected-by-base-tag-expected.txt b/LayoutTests/http/tests/security/postMessage/origin-unaffected-by-base-tag-expected.txt
new file mode 100644 (file)
index 0000000..3d6e990
--- /dev/null
@@ -0,0 +1,3 @@
+window.location.href = http://127.0.0.1:8000/security/postMessage/origin-unaffected-by-base-tag.html
+
+Received message: data="Message from parent" origin="http://127.0.0.1:8000"
diff --git a/LayoutTests/http/tests/security/postMessage/origin-unaffected-by-document-domain-expected.txt b/LayoutTests/http/tests/security/postMessage/origin-unaffected-by-document-domain-expected.txt
new file mode 100644 (file)
index 0000000..23e4c67
--- /dev/null
@@ -0,0 +1,4 @@
+window.location.href = http://127.0.0.1:8000/security/postMessage/origin-unaffected-by-document-domain.html
+document.domain = 0.0.1
+
+Received message: data="Message from parent" origin="http://127.0.0.1:8000"
index 17bc0a8..6a2ca94 100644 (file)
@@ -4,7 +4,7 @@
 <div>window.location.href = <script>document.write(window.location.href);</script></div>
 <script>
 function recv(e) {
-    var msg = 'Received message: data="' + e.data + '" domain="' + e.domain + '" uri="' + e.uri + '"';
+    var msg = 'Received message: data="' + e.data + '" origin="' + e.origin + '"';
     top.postMessage(msg);
 }
 
diff --git a/LayoutTests/http/tests/security/postMessage/target-origin-expected.txt b/LayoutTests/http/tests/security/postMessage/target-origin-expected.txt
new file mode 100644 (file)
index 0000000..64b05c4
--- /dev/null
@@ -0,0 +1,21 @@
+CONSOLE MESSAGE: line 0: Unable to post message to http://localhost:9090. Recipient has origin http://localhost:8000.
+
+CONSOLE MESSAGE: line 0: Unable to post message to http://localhost. Recipient has origin http://localhost:8000.
+
+CONSOLE MESSAGE: line 0: Unable to post message to https://localhost. Recipient has origin http://localhost:8000.
+
+CONSOLE MESSAGE: line 0: Unable to post message to https://localhost:8000. Recipient has origin http://localhost:8000.
+
+CONSOLE MESSAGE: line 0: Unable to post message to http://www.example.com. Recipient has origin http://localhost:8000.
+
+window.location.href = http://127.0.0.1:8000/security/postMessage/target-origin.html
+
+waiting...
+Received message: data="Trying origin=http://localhost:8000" origin="http://127.0.0.1:8000"
+Received message: data="Trying origin=http://localhost:8000/" origin="http://127.0.0.1:8000"
+Received message: data="Trying origin=http://localhost:8000/foo" origin="http://127.0.0.1:8000"
+Received message: data="Trying origin=http://localhost:8000/foo?bar" origin="http://127.0.0.1:8000"
+Received message: data="Trying origin=http://localhost:8000/foo?bar#baz" origin="http://127.0.0.1:8000"
+Received message: data="Trying origin=http://user:pass@localhost:8000/foo?bar#baz" origin="http://127.0.0.1:8000"
+Received message: data="Trying origin=null" origin="http://127.0.0.1:8000"
+Received message: data="Trying origin=undefined" origin="http://127.0.0.1:8000"
diff --git a/LayoutTests/http/tests/security/postMessage/target-origin.html b/LayoutTests/http/tests/security/postMessage/target-origin.html
new file mode 100644 (file)
index 0000000..c937c14
--- /dev/null
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+if (window.layoutTestController) {
+    layoutTestController.dumpAsText();
+    layoutTestController.waitUntilDone();
+}
+
+function recv(e) {
+    document.getElementById("result").innerHTML += "<br>" + e.data;
+}
+document.addEventListener("message", recv, false);
+
+function tryPostMessage(win, origin) {
+    win.postMessage("Trying origin=" + origin, origin);
+}
+
+function test() {
+    var iframe = document.getElementById('child');
+    var win = iframe.contentWindow;
+
+    // Should succeed:
+    tryPostMessage(win, "http://localhost:8000");
+    tryPostMessage(win, "http://localhost:8000/");
+    tryPostMessage(win, "http://localhost:8000/foo");
+    tryPostMessage(win, "http://localhost:8000/foo?bar");
+    tryPostMessage(win, "http://localhost:8000/foo?bar#baz");
+    tryPostMessage(win, "http://user:pass@localhost:8000/foo?bar#baz");
+    tryPostMessage(win, null);
+    tryPostMessage(win, undefined);
+
+    // Should fail:
+    tryPostMessage(win, "http://localhost:9090");
+    tryPostMessage(win, "http://localhost");
+    tryPostMessage(win, "https://localhost");
+    tryPostMessage(win, "https://localhost:8000");
+    tryPostMessage(win, "http://www.example.com");
+
+    if (window.layoutTestController)
+        layoutTestController.notifyDone();
+}
+</script>
+<body>
+<div>window.location.href = <script>document.write(window.location.href);</script></div>
+<div><iframe src="http://localhost:8000/security/postMessage/resources/post-message-listener.html" onload="test()"
+  id="child" width="800" height="300" style="border: 1px solid black;">
+</iframe></div>
+<div id="result">waiting...</div>
+</body>
+</html>
index 611dbed..ef85960 100644 (file)
@@ -1,3 +1,85 @@
+2008-04-26  Adam Barth  <hk9565@gmail.com>
+
+        Reviewed by Adam Roben and Sam Weinig.
+
+        Fixes bug http://bugs.webkit.org/show_bug.cgi?id=17331
+        Fixes bug http://bugs.webkit.org/show_bug.cgi?id=16848
+        
+        Updates postMessage implementation to match HTML 5 specification:
+        1) Adds origin parameter to postMessage.
+        2) Removes domain and uri attributes of MessageEvent in favor of
+           origin attribute.
+
+        In order to do this correctly, we need to distinguish between hosts and domains
+        in the SecurityOrigin class. There are now three ways to compare security origins:
+        1) isSameSchemeHostPort compares scheme, host, and port, and is used for postMessage
+        2) equal compares all aspects of the security origin, and is used for hash keys
+        3) canAccess understands the semantics of schemes such as file:// and data:// URLs,
+           and should be used for scripting access checks.
+
+        Changed SecurityOrigin::toString() to generate identifiers that are suitable for 
+        being used as a MessageEvent's origin property. In the future, they could be used 
+        as database string identifiers as well. Re-used KURL parser to parse serialized 
+        SecurityOrigins.
+
+        Collin Jackson <collinj-webkit@collinjackson.com> also contributed to this patch.
+        
+        Tests: http/tests/security/postMessage/invalid-origin-throws-exception.html
+               http/tests/security/postMessage/javascript-page-still-sends-origin.html
+               http/tests/security/postMessage/origin-unaffected-by-base-tag.html
+               http/tests/security/postMessage/origin-unaffected-by-document-domain.html
+               http/tests/security/postMessage/target-origin.html
+
+        * WebCore.base.exp:
+        * bindings/js/JSDOMWindowCustom.cpp:
+        (WebCore::JSDOMWindow::postMessage):
+        * dom/Document.cpp:
+        (WebCore::Document::domain):
+        * dom/MessageEvent.cpp:
+        (WebCore::MessageEvent::MessageEvent):
+        (WebCore::MessageEvent::initMessageEvent):
+        * dom/MessageEvent.h:
+        (WebCore::MessageEvent::origin):
+        * dom/MessageEvent.idl:
+        * html/CanvasRenderingContext2D.cpp:
+        (WebCore::CanvasRenderingContext2D::checkOrigin):
+        (WebCore::CanvasRenderingContext2D::createPattern):
+        * page/DOMWindow.cpp:
+        (WebCore::DOMWindow::postMessage):
+        * page/DOMWindow.h:
+        * page/DOMWindow.idl:
+        * platform/SecurityOrigin.cpp:
+        (WebCore::SecurityOrigin::SecurityOrigin):
+        (WebCore::SecurityOrigin::create):
+        (WebCore::SecurityOrigin::createForFrame):
+        (WebCore::SecurityOrigin::copy):
+        (WebCore::SecurityOrigin::setDomainFromDOM):
+        (WebCore::SecurityOrigin::canAccess):
+        (WebCore::SecurityOrigin::isSecureTransitionTo):
+        (WebCore::SecurityOrigin::toString):
+        (WebCore::SecurityOrigin::createFromString):
+        (WebCore::SecurityOrigin::createFromDatabaseIdentifier):
+        (WebCore::SecurityOrigin::databaseIdentifier):
+        (WebCore::SecurityOrigin::equal):
+        (WebCore::SecurityOrigin::isSameSchemeHostPort):
+        * platform/SecurityOrigin.h:
+        (WebCore::SecurityOrigin::host):
+        (WebCore::SecurityOrigin::domain):
+        * platform/SecurityOriginHash.h:
+        (WebCore::SecurityOriginTraits::deletedValue):
+        * storage/DatabaseTracker.cpp:
+        (WebCore::DatabaseTracker::hasEntryForDatabase):
+        (WebCore::DatabaseTracker::originPath):
+        (WebCore::DatabaseTracker::fullPathForDatabase):
+        (WebCore::DatabaseTracker::populateOrigins):
+        (WebCore::DatabaseTracker::databaseNamesForOrigin):
+        (WebCore::DatabaseTracker::detailsForNameAndOrigin):
+        (WebCore::DatabaseTracker::setDatabaseDetails):
+        (WebCore::DatabaseTracker::setQuota):
+        (WebCore::DatabaseTracker::addDatabase):
+        (WebCore::DatabaseTracker::deleteOrigin):
+        (WebCore::DatabaseTracker::deleteDatabase):
+
 2008-04-26  Kevin Ollivier  <kevino@theolliviers.com>
 
         wx build fix. Add the AX*ActionVerb functions to the wx build.
index f29794a..df4a47f 100644 (file)
@@ -287,7 +287,8 @@ __ZN7WebCore14DragController9dragEndedEv
 __ZN7WebCore14ResourceHandle12releaseProxyEv
 __ZN7WebCore14ResourceLoader14cancelledErrorEv
 __ZN7WebCore14ResourceLoader19setShouldBufferDataEb
-__ZN7WebCore14SecurityOrigin6createERKNS_6StringES3_tPS0_
+__ZN7WebCore14SecurityOrigin6createERKNS_4KURLE
+__ZNK7WebCore14SecurityOrigin5equalEPKS0_
 __ZN7WebCore15ArchiveResource6createEN3WTF10PassRefPtrINS_12SharedBufferEEERKNS_4KURLERKNS_6StringESA_SA_RKNS_16ResourceResponseE
 __ZN7WebCore15BackForwardList10removeItemEPNS_11HistoryItemE
 __ZN7WebCore15BackForwardList10setEnabledEb
index 0a445fc..a31e47a 100644 (file)
@@ -207,14 +207,18 @@ JSValue* JSDOMWindow::postMessage(ExecState* exec, const List& args)
     DOMWindow* window = impl();
 
     DOMWindow* source = toJSDOMWindow(exec->dynamicGlobalObject())->impl();
-    String domain = source->frame()->loader()->url().host();
-    String uri = source->frame()->loader()->url().string();
     String message = args[0]->toString(exec);
 
     if (exec->hadException())
         return jsUndefined();
 
-    window->postMessage(message, domain, uri, source);
+    String targetOrigin = valueToStringWithUndefinedOrNullCheck(exec, args[1]);
+    if (exec->hadException())
+        return jsUndefined();
+
+    ExceptionCode ec = 0;
+    window->postMessage(message, targetOrigin, source, ec);
+    setDOMException(exec, ec);
 
     return jsUndefined();
 }
index 3049e49..0537ff1 100644 (file)
@@ -2755,7 +2755,7 @@ String Document::referrer() const
 
 String Document::domain() const
 {
-    return m_securityOrigin->host();
+    return m_securityOrigin->domain();
 }
 
 void Document::setDomain(const String& newDomain)
index 06f253d..b11187f 100644 (file)
@@ -41,11 +41,10 @@ MessageEvent::MessageEvent()
 {
 }
 
-MessageEvent::MessageEvent(const String& data, const String& domain, const String& uri, DOMWindow* source)
+MessageEvent::MessageEvent(const String& data, const String& origin, DOMWindow* source)
     : Event(messageEvent, true, true)
     , m_data(data)
-    , m_domain(domain)
-    , m_uri(uri)
+    , m_origin(origin)
     , m_source(source)
 {
 }
@@ -54,7 +53,7 @@ MessageEvent::~MessageEvent()
 {
 }
 
-void MessageEvent::initMessageEvent(const AtomicString& type, bool canBubble, bool cancelable, const String& data, const String& domain, const String& uri, DOMWindow* source)
+void MessageEvent::initMessageEvent(const AtomicString& type, bool canBubble, bool cancelable, const String& data, const String& origin, DOMWindow* source)
 {
     if (dispatched())
         return;
@@ -62,8 +61,7 @@ void MessageEvent::initMessageEvent(const AtomicString& type, bool canBubble, bo
     initEvent(type, canBubble, cancelable);
     
     m_data = data;
-    m_domain = domain;
-    m_uri = uri;
+    m_origin = origin;
     m_source = source;
 }
 
index f8b5f78..f378951 100644 (file)
@@ -39,22 +39,20 @@ namespace WebCore {
     class MessageEvent : public Event {
     public:
         MessageEvent();
-        MessageEvent(const String& data, const String& domain, const String& uri, DOMWindow* source);
+        MessageEvent(const String& data, const String& origin, DOMWindow* source);
         virtual ~MessageEvent();
 
-        void initMessageEvent(const AtomicString& type, bool canBubble, bool cancelable, const String& data, const String& domain, const String& uri, DOMWindow* source);
+        void initMessageEvent(const AtomicString& type, bool canBubble, bool cancelable, const String& data, const String& origin, DOMWindow* source);
         
         const String& data() const { return m_data; }
-        const String& domain() const { return m_domain; }
-        const String& uri() const { return m_uri; }
+        const String& origin() const { return m_origin; }
         DOMWindow* source() const { return m_source.get(); }
         
         virtual bool isMessageEvent() const;
 
     private:    
         String m_data;
-        String m_domain;
-        String m_uri;
+        String m_origin;
         RefPtr<DOMWindow> m_source;
     };
 
index 22f5262..4bb0497 100644 (file)
@@ -29,11 +29,10 @@ module events {
     interface [Conditional=CROSS_DOCUMENT_MESSAGING,GenerateConstructor] MessageEvent : Event {
 
         readonly attribute DOMString data;
-        readonly attribute DOMString domain;
-        readonly attribute DOMString uri;
+        readonly attribute DOMString origin;
         readonly attribute DOMWindow source;
         
-        void initMessageEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString dataArg, in DOMString domainArg, in DOMString uriArg, in DOMWindow sourceArg);
+        void initMessageEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString dataArg, in DOMString originArg, in DOMWindow sourceArg);
 
     };
 
index 4120a51..9102144 100644 (file)
@@ -910,7 +910,7 @@ void CanvasRenderingContext2D::drawImage(HTMLImageElement* image,
 
 void CanvasRenderingContext2D::checkOrigin(const KURL& url)
 {
-    RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url.protocol(), url.host(), url.port(), 0);
+    RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url);
     SecurityOrigin::Reason reason;
     if (!m_canvas->document()->securityOrigin()->canAccess(origin.get(), reason))
         m_canvas->setOriginTainted();
@@ -1061,7 +1061,7 @@ PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLImageEleme
     bool originClean = true;
     if (CachedImage* cachedImage = image->cachedImage()) {
         KURL url(cachedImage->url());
-        RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url.protocol(), url.host(), url.port(), 0);
+        RefPtr<SecurityOrigin> origin = SecurityOrigin::create(url);
         SecurityOrigin::Reason reason;
         originClean = m_canvas->document()->securityOrigin()->canAccess(origin.get(), reason);
     }
index b5ef615..1e372d5 100644 (file)
 #include "CSSComputedStyleDeclaration.h"
 #include "CSSRuleList.h"
 #include "CSSStyleSelector.h"
+#include "CString.h"
 #include "Chrome.h"
 #include "Console.h"
 #include "DOMSelection.h"
 #include "Document.h"
 #include "Element.h"
+#include "ExceptionCode.h"
 #include "FloatRect.h"
 #include "Frame.h"
 #include "FrameLoader.h"
@@ -320,10 +322,39 @@ Storage* DOMWindow::localStorage() const
 #endif
 
 #if ENABLE(CROSS_DOCUMENT_MESSAGING)
-void DOMWindow::postMessage(const String& message, const String& domain, const String& uri, DOMWindow* source) const
+void DOMWindow::postMessage(const String& message, const String& targetOrigin, DOMWindow* source, ExceptionCode& ecForSender) const
 {
-   ExceptionCode ec;
-   document()->dispatchEvent(new MessageEvent(message, domain, uri, source), ec, true);
+    if (!m_frame)
+        return;
+
+    if (!targetOrigin.isNull()) {
+        KURL desiredTargetURL(targetOrigin);
+        if (!desiredTargetURL.isValid()) {
+            ecForSender = SYNTAX_ERR;
+            return;
+        }
+
+        RefPtr<SecurityOrigin> desiredTargetOrigin = SecurityOrigin::create(desiredTargetURL);
+        SecurityOrigin* actualTargetOrigin = document()->securityOrigin();
+        if (desiredTargetOrigin->isEmpty() || !desiredTargetOrigin->isSameSchemeHostPort(actualTargetOrigin)) {
+            // The sender is not allowed to find out the origin of
+            // the recipient, so we fail silently and log a message
+            // to the console.
+            String message = String::format("Unable to post message to %s. Recipient has origin %s.\n", 
+                targetOrigin.utf8().data(), actualTargetOrigin->toString().utf8().data());
+            console()->addMessage(JSMessageSource, ErrorMessageLevel, message, 0, String());
+            return;
+        }
+    }
+
+    Document* sourceDocument = source->document();
+    if (!sourceDocument)
+        return;
+    String sourceOrigin = sourceDocument->securityOrigin()->toString();
+
+    // Sender is not allowed to see exceptions other than syntax errors
+    ExceptionCode ec; 
+    document()->dispatchEvent(new MessageEvent(message, sourceOrigin, source), ec, true);
 }
 #endif
 
index 7b7ad4d..c17f038 100644 (file)
@@ -165,7 +165,7 @@ namespace WebCore {
         DOMApplicationCache* applicationCache() const;
 #endif
 #if ENABLE(CROSS_DOCUMENT_MESSAGING)
-        void postMessage(const String& message, const String& domain, const String& uri, DOMWindow* source) const;
+        void postMessage(const String& message, const String& targetOrigin, DOMWindow* source, ExceptionCode& ecForSender) const;
 #endif
 
         void scrollBy(int x, int y) const;
index 34779a4..4378f2d 100644 (file)
@@ -148,7 +148,8 @@ module window {
 
 #if defined(ENABLE_CROSS_DOCUMENT_MESSAGING)
         // cross-document messaging
-        [DoNotCheckDomainSecurity, Custom] void postMessage(in DOMString message);
+        [DoNotCheckDomainSecurity, Custom] void postMessage(in DOMString message, in [Optional] DOMString targetOrigin)
+            raises(DOMException);
 #endif
 
 #if defined(LANGUAGE_JAVASCRIPT)
index be538e6..f397261 100644 (file)
@@ -29,6 +29,7 @@
 #include "config.h"
 #include "SecurityOrigin.h"
 
+#include "CString.h"
 #include "Document.h"
 #include "Frame.h"
 #include "FrameLoader.h"
@@ -53,11 +54,10 @@ static bool isDefaultPortForProtocol(unsigned short port, const String& protocol
     return defaultPorts.get(protocol) == port;
 }
 
-SecurityOrigin::SecurityOrigin(const String& protocol, const String& host, unsigned short port)
-    : m_protocol(protocol.isNull() ? "" : protocol.lower())
-    , m_host(host.isNull() ? "" : host.lower())
-    , m_port(port)
-    , m_portSet(port)
+SecurityOrigin::SecurityOrigin(const KURL& url)
+    : m_protocol(url.protocol().isNull() ? "" : url.protocol().lower())
+    , m_host(url.host().isNull() ? "" : url.host().lower())
+    , m_port(url.port())
     , m_noAccess(false)
     , m_domainWasSetInDOM(false)
 {
@@ -69,11 +69,21 @@ SecurityOrigin::SecurityOrigin(const String& protocol, const String& host, unsig
     if (m_protocol == "data")
         m_noAccess = true;
 
+    // document.domain starts as m_host, but can be set by the DOM.
+    m_domain = m_host;
 
-    if (isDefaultPortForProtocol(m_port, m_protocol)) {
+    if (isDefaultPortForProtocol(m_port, m_protocol))
         m_port = 0;
-        m_portSet = false;
-    }   
+}
+
+SecurityOrigin::SecurityOrigin(const SecurityOrigin* other)
+    : m_protocol(other->m_protocol.copy())
+    , m_host(other->m_host.copy())
+    , m_domain(other->m_domain.copy())
+    , m_port(other->m_port)
+    , m_noAccess(other->m_noAccess)
+    , m_domainWasSetInDOM(other->m_domainWasSetInDOM)
+{
 }
 
 bool SecurityOrigin::isEmpty() const
@@ -81,24 +91,15 @@ bool SecurityOrigin::isEmpty() const
     return m_protocol.isEmpty();
 }
 
-PassRefPtr<SecurityOrigin> SecurityOrigin::create(const String& protocol, const String& host, unsigned short port, SecurityOrigin* ownerFrameOrigin)
+PassRefPtr<SecurityOrigin> SecurityOrigin::create(const KURL& url)
 {
-    RefPtr<SecurityOrigin> origin = adoptRef(new SecurityOrigin(protocol, host, port));
-
-    // If we do not obtain a meaningful origin from the URL, then we try to find one
-    // via the frame hierarchy.
-    // We alias the SecurityOrigins to match Firefox, see Bug 15313
-    // http://bugs.webkit.org/show_bug.cgi?id=15313
-    if (origin->isEmpty() && ownerFrameOrigin)
-        return ownerFrameOrigin;
-
-    return origin.release();
+    return adoptRef(new SecurityOrigin(url));
 }
 
 PassRefPtr<SecurityOrigin> SecurityOrigin::createForFrame(Frame* frame)
 {
     if (!frame)
-        return create("", "", 0, 0);
+        return create(KURL());
 
     FrameLoader* loader = frame->loader();
     const KURL& url = loader->url();
@@ -111,19 +112,27 @@ PassRefPtr<SecurityOrigin> SecurityOrigin::createForFrame(Frame* frame)
     if (ownerFrame && ownerFrame->document())
         ownerFrameOrigin = ownerFrame->document()->securityOrigin();
 
-    return create(url.protocol(), url.host(), url.port(), ownerFrameOrigin);
+    RefPtr<SecurityOrigin> origin = create(url);
+
+    // If we do not obtain a meaningful origin from the URL, then we try to find one
+    // via the frame hierarchy.
+    // We alias the SecurityOrigins to match Firefox, see Bug 15313
+    // http://bugs.webkit.org/show_bug.cgi?id=15313
+    if (origin->isEmpty() && ownerFrameOrigin)
+        return ownerFrameOrigin;
+
+    return origin.release();
 }
 
 PassRefPtr<SecurityOrigin> SecurityOrigin::copy()
 {
-    return create(m_protocol.copy(), m_host.copy(), m_port, 0);
+    return adoptRef(new SecurityOrigin(this));
 }
 
-
 void SecurityOrigin::setDomainFromDOM(const String& newDomain)
 {
     m_domainWasSetInDOM = true;
-    m_host = newDomain.lower();
+    m_domain = newDomain.lower();
 }
 
 bool SecurityOrigin::canAccess(const SecurityOrigin* other, Reason& reason) const
@@ -166,7 +175,7 @@ bool SecurityOrigin::canAccess(const SecurityOrigin* other, Reason& reason) cons
             if (m_host == other->m_host && m_port == other->m_port)
                 return true;
         } else if (m_domainWasSetInDOM && other->m_domainWasSetInDOM) {
-            if (m_host == other->m_host)
+            if (m_domain == other->m_domain)
                 return true;
         } else {
             if (m_host == other->m_host && m_port == other->m_port) {
@@ -186,55 +195,103 @@ bool SecurityOrigin::isSecureTransitionTo(const KURL& url) const
     if (isEmpty())
         return true;
 
-    if (FrameLoader::shouldTreatSchemeAsLocal(m_protocol))
-        return true;
-
-    return equalIgnoringCase(m_host, String(url.host())) && equalIgnoringCase(m_protocol, String(url.protocol())) && m_port == url.port();
+    RefPtr<SecurityOrigin> other = SecurityOrigin::create(url);
+    Reason reason;
+    return canAccess(other.get(), reason);
 }
 
 String SecurityOrigin::toString() const
 {
-    return m_protocol + ":" + m_host + ":" + String::number(m_port);
+    if (isEmpty())
+        return String();
+
+    if (m_protocol == "file")
+        return String("file://");
+
+    Vector<UChar> result;
+    result.reserveCapacity(m_protocol.length() + m_host.length() + 10);
+    append(result, m_protocol);
+    append(result, "://");
+    append(result, m_host);
+
+    if (m_port) {
+        append(result, ":");
+        append(result, String::number(m_port));
+    }
+
+    return String::adopt(result);
+}
+
+PassRefPtr<SecurityOrigin> SecurityOrigin::createFromString(const String& originString)
+{
+    return SecurityOrigin::create(KURL(originString));
 }
 
 static const char SeparatorCharacter = '_';
 
-PassRefPtr<SecurityOrigin> SecurityOrigin::createFromIdentifier(const String& stringIdentifier)
+PassRefPtr<SecurityOrigin> SecurityOrigin::createFromDatabaseIdentifier(const String& databaseIdentifier)
 { 
     // Make sure there's a first separator
-    int separator1 = stringIdentifier.find(SeparatorCharacter);
+    int separator1 = databaseIdentifier.find(SeparatorCharacter);
     if (separator1 == -1)
-        return create("", "", 0, 0);
+        return create(KURL());
         
     // Make sure there's a second separator
-    int separator2 = stringIdentifier.find(SeparatorCharacter, separator1 + 1);
+    int separator2 = databaseIdentifier.find(SeparatorCharacter, separator1 + 1);
     if (separator2 == -1)
-        return create("", "", 0, 0);
+        return create(KURL());
         
     // Make sure there's not a third separator
-    if (stringIdentifier.reverseFind(SeparatorCharacter) != separator2)
-        return create("", "", 0, 0);
+    if (databaseIdentifier.reverseFind(SeparatorCharacter) != separator2)
+        return create(KURL());
         
     // Make sure the port section is a valid port number or doesn't exist
     bool portOkay;
-    int port = stringIdentifier.right(stringIdentifier.length() - separator2 - 1).toInt(&portOkay);
-    if (!portOkay && separator2 + 1 == static_cast<int>(stringIdentifier.length()))
-        return create("", "", 0, 0);
+    int port = databaseIdentifier.right(databaseIdentifier.length() - separator2 - 1).toInt(&portOkay);
+    if (!portOkay && separator2 + 1 == static_cast<int>(databaseIdentifier.length()))
+        return create(KURL());
     
     if (port < 0 || port > 65535)
-        return create("", "", 0, 0);
+        return create(KURL());
         
     // Split out the 3 sections of data
-    String protocol = stringIdentifier.substring(0, separator1);
-    String host = stringIdentifier.substring(separator1 + 1, separator2 - separator1 - 1);
-    return create(protocol, host, port, 0);
+    String protocol = databaseIdentifier.substring(0, separator1);
+    String host = databaseIdentifier.substring(separator1 + 1, separator2 - separator1 - 1);
+    return create(KURL(protocol + "://" + host + ":" + String::number(port)));
 }
-    
-    
-String SecurityOrigin::stringIdentifier() const 
+
+String SecurityOrigin::databaseIdentifier() const 
 {
     static String separatorString = String(&SeparatorCharacter, 1);
     return m_protocol + separatorString + m_host + separatorString + String::number(m_port); 
 }
 
+bool SecurityOrigin::equal(const SecurityOrigin* other) const 
+{
+    if (!isSameSchemeHostPort(other))
+        return false;
+
+    if (m_domainWasSetInDOM != other->m_domainWasSetInDOM)
+        return false;
+
+    if (m_domainWasSetInDOM && m_domain != other->m_domain)
+        return false;
+
+    return true;
+}
+
+bool SecurityOrigin::isSameSchemeHostPort(const SecurityOrigin* other) const 
+{
+    if (m_host != other->m_host)
+        return false;
+
+    if (m_protocol != other->m_protocol)
+        return false;
+
+    if (m_port != other->m_port)
+        return false;
+
+    return true;
+}
+
 } // namespace WebCore
index 6f7e6f5..4f303b0 100644 (file)
@@ -43,14 +43,16 @@ namespace WebCore {
     class SecurityOrigin : public ThreadSafeShared<SecurityOrigin> {
     public:
         static PassRefPtr<SecurityOrigin> createForFrame(Frame*);
-        static PassRefPtr<SecurityOrigin> createFromIdentifier(const String&);
-        static PassRefPtr<SecurityOrigin> create(const String& protocol, const String& host, unsigned short port, SecurityOrigin* ownerFrameOrigin);
+        static PassRefPtr<SecurityOrigin> createFromDatabaseIdentifier(const String&);
+        static PassRefPtr<SecurityOrigin> createFromString(const String&);
+        static PassRefPtr<SecurityOrigin> create(const KURL&);
 
         PassRefPtr<SecurityOrigin> copy();
 
         void setDomainFromDOM(const String& newDomain);
-        String host() const { return m_host; }
         String protocol() const { return m_protocol; }
+        String host() const { return m_host; }
+        String domain() const { return m_domain; }
         unsigned short port() const { return m_port; }
         
         enum Reason  {
@@ -62,19 +64,31 @@ namespace WebCore {
 
         bool isEmpty() const;
         String toString() const;
-        
-        String stringIdentifier() const;
 
-        // do not use this for access checks, it's there only for using this as a hashtable key
-        bool equal(SecurityOrigin* other) const { return m_protocol == other->m_protocol && m_host == other->m_host && m_port == other->m_port; }
-        
+        // Serialize the security origin for storage in the database. This format is
+        // deprecated and should be used only for compatibility with old databases;
+        // use toString() and createFromString() instead.
+        String databaseIdentifier() const;
+
+        // This method checks for equality between SecurityOrigins, not whether
+        // one origin can access another.  It is used for hash table keys.
+        // For access checks, use canAccess().
+        // FIXME: If this method is really only useful for hash table keys, it
+        // should be refactored into SecurityOriginHash.
+        bool equal(const SecurityOrigin*) const;
+
+        // This method checks for equality, ignoring the value of document.domain
+        // (and whether it was set) but considering the host. It is used for postMessage.
+        bool isSameSchemeHostPort(const SecurityOrigin*) const;
+
     private:
-        SecurityOrigin(const String& protocol, const String& host, unsigned short port);
+        explicit SecurityOrigin(const KURL&);
+        explicit SecurityOrigin(const SecurityOrigin*);
 
         String m_protocol;
         String m_host;
+        String m_domain;
         unsigned short m_port;
-        bool m_portSet;
         bool m_noAccess;
         bool m_domainWasSetInDOM;
     };
index a5f25e5..91e7505 100644 (file)
@@ -29,6 +29,7 @@
 #ifndef SecurityOriginHash_h
 #define SecurityOriginHash_h
 
+#include "KURL.h"
 #include "SecurityOrigin.h"
 #include <wtf/RefPtr.h>
 
@@ -59,9 +60,9 @@ struct SecurityOriginHash {
 struct SecurityOriginTraits : WTF::GenericHashTraits<RefPtr<SecurityOrigin> > {
     static const bool emptyValueIsZero = true;
     static const RefPtr<SecurityOrigin>& deletedValue() 
-    { 
-        // Okay deleted value because file: protocols should always have port 0
-        static const RefPtr<SecurityOrigin> securityOriginDeletedValue = SecurityOrigin::create("file", "", 1, 0);    
+    {
+        // Ok deleted value assuming "invalid-protocol" is not a valid protocol
+        static const RefPtr<SecurityOrigin> securityOriginDeletedValue = SecurityOrigin::create(KURL("invalid-protocol:"));
         return securityOriginDeletedValue; 
     }
 
index 0c06dee..9a78dc8 100644 (file)
@@ -178,7 +178,7 @@ bool DatabaseTracker::hasEntryForDatabase(SecurityOrigin* origin, const String&
     if (statement.prepare() != SQLResultOk)
         return false;
 
-    statement.bindText(1, origin->stringIdentifier());
+    statement.bindText(1, origin->databaseIdentifier());
     statement.bindText(2, databaseIdentifier);
 
     return statement.step() == SQLResultRow;
@@ -189,7 +189,7 @@ String DatabaseTracker::originPath(SecurityOrigin* origin) const
     ASSERT(currentThread() == m_thread);
     if (m_databaseDirectoryPath.isEmpty())
         return String();
-    return pathByAppendingComponent(m_databaseDirectoryPath, origin->stringIdentifier());
+    return pathByAppendingComponent(m_databaseDirectoryPath, origin->databaseIdentifier());
 }
 
 String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String& name, bool createIfNotExists)
@@ -199,7 +199,7 @@ String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String
     if (m_proposedDatabase && m_proposedDatabase->first == origin && m_proposedDatabase->second.name() == name)
         return String();
 
-    String originIdentifier = origin->stringIdentifier();
+    String originIdentifier = origin->databaseIdentifier();
     String originPath = this->originPath(origin);
     
     // Make sure the path for this SecurityOrigin exists
@@ -226,7 +226,7 @@ String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String
         return String();
         
     if (result != SQLResultDone) {
-        LOG_ERROR("Failed to retrieve filename from Database Tracker for origin %s, name %s", origin->stringIdentifier().ascii().data(), name.ascii().data());
+        LOG_ERROR("Failed to retrieve filename from Database Tracker for origin %s, name %s", origin->databaseIdentifier().ascii().data(), name.ascii().data());
         return String();
     }
     statement.finalize();
@@ -288,7 +288,7 @@ void DatabaseTracker::populateOrigins()
 
     int result;
     while ((result = statement.step()) == SQLResultRow) {
-        RefPtr<SecurityOrigin> origin = SecurityOrigin::createFromIdentifier(statement.getColumnText(0));
+        RefPtr<SecurityOrigin> origin = SecurityOrigin::createFromDatabaseIdentifier(statement.getColumnText(0));
         m_quotaMap->set(origin.get(), statement.getColumnInt64(1));
     }
 
@@ -316,14 +316,14 @@ bool DatabaseTracker::databaseNamesForOrigin(SecurityOrigin* origin, Vector<Stri
     if (statement.prepare() != SQLResultOk)
         return false;
 
-    statement.bindText(1, origin->stringIdentifier());
+    statement.bindText(1, origin->databaseIdentifier());
 
     int result;
     while ((result = statement.step()) == SQLResultRow)
         resultVector.append(statement.getColumnText(0));
 
     if (result != SQLResultDone) {
-        LOG_ERROR("Failed to retrieve all database names for origin %s", origin->stringIdentifier().ascii().data());
+        LOG_ERROR("Failed to retrieve all database names for origin %s", origin->databaseIdentifier().ascii().data());
         return false;
     }
 
@@ -337,7 +337,7 @@ DatabaseDetails DatabaseTracker::detailsForNameAndOrigin(const String& name, Sec
     if (m_proposedDatabase && m_proposedDatabase->first == origin && m_proposedDatabase->second.name() == name)
         return m_proposedDatabase->second;
 
-    String originIdentifier = origin->stringIdentifier();
+    String originIdentifier = origin->databaseIdentifier();
 
     openTrackerDatabase(false);
     if (!m_database.isOpen())
@@ -365,7 +365,7 @@ void DatabaseTracker::setDatabaseDetails(SecurityOrigin* origin, const String& n
 {
     ASSERT(currentThread() == m_thread);
 
-    String originIdentifier = origin->stringIdentifier();
+    String originIdentifier = origin->databaseIdentifier();
     int64_t guid = 0;
     
     openTrackerDatabase(true);
@@ -545,26 +545,26 @@ void DatabaseTracker::setQuota(SecurityOrigin* origin, unsigned long long quota)
         if (!m_quotaMap->contains(origin)) {
             SQLiteStatement statement(m_database, "INSERT INTO Origins VALUES (?, ?)");
             if (statement.prepare() != SQLResultOk) {
-                LOG_ERROR("Unable to establish origin %s in the tracker", origin->stringIdentifier().ascii().data());
+                LOG_ERROR("Unable to establish origin %s in the tracker", origin->databaseIdentifier().ascii().data());
             } else {
-                statement.bindText(1, origin->stringIdentifier());
+                statement.bindText(1, origin->databaseIdentifier());
                 statement.bindInt64(2, quota);
 
                 if (statement.step() != SQLResultDone)
-                    LOG_ERROR("Unable to establish origin %s in the tracker", origin->stringIdentifier().ascii().data());
+                    LOG_ERROR("Unable to establish origin %s in the tracker", origin->databaseIdentifier().ascii().data());
             }
         } else {
             SQLiteStatement statement(m_database, "UPDATE Origins SET quota=? WHERE origin=?");        
             bool error = statement.prepare() != SQLResultOk;
             if (!error) {
                 statement.bindInt64(1, quota);
-                statement.bindText(2, origin->stringIdentifier());
+                statement.bindText(2, origin->databaseIdentifier());
 
                 error = !statement.executeCommand();
             }
 
             if (error)
-                LOG_ERROR("Failed to set quota %llu in tracker database for origin %s", quota, origin->stringIdentifier().ascii().data());
+                LOG_ERROR("Failed to set quota %llu in tracker database for origin %s", quota, origin->databaseIdentifier().ascii().data());
         }
 
         // FIXME: Is it really OK to update the quota in memory if we failed to update it on disk?
@@ -590,12 +590,12 @@ bool DatabaseTracker::addDatabase(SecurityOrigin* origin, const String& name, co
     if (statement.prepare() != SQLResultOk)
         return false;
 
-    statement.bindText(1, origin->stringIdentifier());
+    statement.bindText(1, origin->databaseIdentifier());
     statement.bindText(2, name);
     statement.bindText(3, path);
 
     if (!statement.executeCommand()) {
-        LOG_ERROR("Failed to add database %s to origin %s: %s\n", name.ascii().data(), origin->stringIdentifier().ascii().data(), m_database.lastErrorMsg());
+        LOG_ERROR("Failed to add database %s to origin %s: %s\n", name.ascii().data(), origin->databaseIdentifier().ascii().data(), m_database.lastErrorMsg());
         return false;
     }
     
@@ -625,40 +625,40 @@ void DatabaseTracker::deleteOrigin(SecurityOrigin* origin)
 
     Vector<String> databaseNames;
     if (!databaseNamesForOrigin(origin, databaseNames)) {
-        LOG_ERROR("Unable to retrieve list of database names for origin %s", origin->stringIdentifier().ascii().data());
+        LOG_ERROR("Unable to retrieve list of database names for origin %s", origin->databaseIdentifier().ascii().data());
         return;
     }
     
     for (unsigned i = 0; i < databaseNames.size(); ++i) {
         if (!deleteDatabaseFile(origin, databaseNames[i])) {
-            LOG_ERROR("Unable to delete file for database %s in origin %s", databaseNames[i].ascii().data(), origin->stringIdentifier().ascii().data());
+            LOG_ERROR("Unable to delete file for database %s in origin %s", databaseNames[i].ascii().data(), origin->databaseIdentifier().ascii().data());
             return;
         }
     }
     
     SQLiteStatement statement(m_database, "DELETE FROM Databases WHERE origin=?");
     if (statement.prepare() != SQLResultOk) {
-        LOG_ERROR("Unable to prepare deletion of databases from origin %s from tracker", origin->stringIdentifier().ascii().data());
+        LOG_ERROR("Unable to prepare deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data());
         return;
     }
         
-    statement.bindText(1, origin->stringIdentifier());
+    statement.bindText(1, origin->databaseIdentifier());
     
     if (!statement.executeCommand()) {
-        LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin->stringIdentifier().ascii().data());
+        LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data());
         return;
     }
     
     SQLiteStatement originStatement(m_database, "DELETE FROM Origins WHERE origin=?");
     if (originStatement.prepare() != SQLResultOk) {
-        LOG_ERROR("Unable to prepare deletion of origin %s from tracker", origin->stringIdentifier().ascii().data());
+        LOG_ERROR("Unable to prepare deletion of origin %s from tracker", origin->databaseIdentifier().ascii().data());
         return;
     }
 
-    originStatement.bindText(1, origin->stringIdentifier());
+    originStatement.bindText(1, origin->databaseIdentifier());
     
     if (!originStatement.executeCommand()) {
-        LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin->stringIdentifier().ascii().data());
+        LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data());
         return;
     }
 
@@ -696,21 +696,21 @@ void DatabaseTracker::deleteDatabase(SecurityOrigin* origin, const String& name)
         return;
 
     if (!deleteDatabaseFile(origin, name)) {
-        LOG_ERROR("Unable to delete file for database %s in origin %s", name.ascii().data(), origin->stringIdentifier().ascii().data());
+        LOG_ERROR("Unable to delete file for database %s in origin %s", name.ascii().data(), origin->databaseIdentifier().ascii().data());
         return;
     }
     
     SQLiteStatement statement(m_database, "DELETE FROM Databases WHERE origin=? AND name=?");
     if (statement.prepare() != SQLResultOk) {
-        LOG_ERROR("Unable to prepare deletion of database %s from origin %s from tracker", name.ascii().data(), origin->stringIdentifier().ascii().data());
+        LOG_ERROR("Unable to prepare deletion of database %s from origin %s from tracker", name.ascii().data(), origin->databaseIdentifier().ascii().data());
         return;
     }
         
-    statement.bindText(1, origin->stringIdentifier());
+    statement.bindText(1, origin->databaseIdentifier());
     statement.bindText(2, name);
     
     if (!statement.executeCommand()) {
-        LOG_ERROR("Unable to execute deletion of database %s from origin %s from tracker", name.ascii().data(), origin->stringIdentifier().ascii().data());
+        LOG_ERROR("Unable to execute deletion of database %s from origin %s from tracker", name.ascii().data(), origin->databaseIdentifier().ascii().data());
         return;
     }
     
index f252598..1acbc8c 100644 (file)
@@ -1,3 +1,16 @@
+2008-04-20 Adam Barth <hk9565@gmail.com>
+
+        Reviewed by Adam Roben and Sam Weinig.
+
+        Updated WebSecurityOrigin to match new SecurityOrigin API.
+
+        Collin Jackson <collinj-webkit@collinjackson.com> also contributed to this patch.
+
+        * Storage/WebSecurityOrigin.mm:
+        (-[WebSecurityOrigin host]):
+        (-[WebSecurityOrigin domain]):
+        * Storage/WebSecurityOriginPrivate.h:
+
 2008-04-25  Mark Rowe  <mrowe@apple.com>
 
         Rubber-stamped by Sam Weinig.
index 8ee6cd5..85313d0 100644 (file)
 #import "WebSecurityOriginInternal.h"
 
 #import <WebCore/DatabaseTracker.h>
+#import <WebCore/KURL.h>
 #import <WebCore/SecurityOrigin.h>
 
 using namespace WebCore;
 
 @implementation WebSecurityOrigin
-
-- (id)initWithProtocol:(NSString *)protocol domain:(NSString *)domain
-{
-    return [self initWithProtocol:protocol domain:domain port:0];
-}
-
-- (id)initWithProtocol:(NSString *)protocol domain:(NSString *)domain port:(unsigned short)port
+- (id)initWithURL:(NSURL *)url
 {
     self = [super init];
     if (!self)
         return nil;
-    
-    RefPtr<SecurityOrigin> origin = SecurityOrigin::create(protocol, domain, port, 0);
+
+    RefPtr<SecurityOrigin> origin = SecurityOrigin::create(KURL([url absoluteURL]));
     origin->ref();
     _private = reinterpret_cast<WebSecurityOriginPrivate*>(origin.get());
 
@@ -58,11 +53,17 @@ using namespace WebCore;
     return reinterpret_cast<SecurityOrigin*>(_private)->protocol();
 }
 
-- (NSString*)domain
+- (NSString*)host
 {
     return reinterpret_cast<SecurityOrigin*>(_private)->host();
 }
 
+// Deprecated. Use host instead. This needs to stay here until we ship a new Safari.
+- (NSString*)domain
+{
+    return [self host];
+}
+
 - (unsigned short)port
 {
     return reinterpret_cast<SecurityOrigin*>(_private)->port();
index 1e66f42..0796c6e 100644 (file)
     WebSecurityOriginPrivate *_private;
 }
 
-- (id)initWithProtocol:(NSString *)protocol domain:(NSString *)domain;
-- (id)initWithProtocol:(NSString *)protocol domain:(NSString *)domain port:(unsigned short)port;
+- (id)initWithURL:(NSURL *)url;
 
 - (NSString*)protocol;
-- (NSString*)domain;
+- (NSString*)host;
 
 // Returns zero if the port is the default port for the protocol, non-zero otherwise
 - (unsigned short)port;
index 5053de5..112c24a 100644 (file)
@@ -1,3 +1,14 @@
+2008-04-26  Adam Barth <hk9565@gmail.com>
+
+        Reviewed by Adam Roben and Sam Weinig.
+
+        Renamed "domain" method to "host" to match SecurityOrigin.
+
+        * Interfaces/IWebSecurityOrigin.idl:
+        * WebSecurityOrigin.cpp:
+        (WebSecurityOrigin::host):
+        * WebSecurityOrigin.h:
+
 2008-04-25  Anders Carlsson  <andersca@apple.com>
 
         Reviewed by Adam.
index 49302c6..796d59c 100644 (file)
@@ -40,7 +40,7 @@ import "ocidl.idl";
 interface IWebSecurityOrigin : IUnknown
 {
     HRESULT protocol([out, retval] BSTR* result);
-    HRESULT domain([out, retval] BSTR* result);
+    HRESULT host([out, retval] BSTR* result);
     HRESULT port([out, retval] unsigned short* result);
 
     HRESULT usage([out, retval] unsigned long long* result);
index 33a3a3a..2b50abe 100644 (file)
@@ -99,7 +99,7 @@ HRESULT STDMETHODCALLTYPE WebSecurityOrigin::protocol(
     return S_OK;
 }
         
-HRESULT STDMETHODCALLTYPE WebSecurityOrigin::domain
+HRESULT STDMETHODCALLTYPE WebSecurityOrigin::host
     /* [retval][out] */ BSTR* result)
 {
     if (!result)
index e86957b..a4d9f01 100644 (file)
@@ -52,7 +52,7 @@ public:
     virtual HRESULT STDMETHODCALLTYPE protocol( 
         /* [retval][out] */ BSTR* result);
         
-    virtual HRESULT STDMETHODCALLTYPE domain
+    virtual HRESULT STDMETHODCALLTYPE host
         /* [retval][out] */ BSTR* result);
         
     virtual HRESULT STDMETHODCALLTYPE port( 
index 1aaf3f6..b7d4c46 100644 (file)
@@ -1,3 +1,16 @@
+2008-04-26  Adam Barth <hk9565@gmail.com>
+
+        Reviewed by Adam Roben and Sam Weinig.
+
+        Updates LayoutTestController to use host instead of domain.
+
+        Collin Jackson <collinj-webkit@collinjackson.com> also contributed to this patch.
+
+        * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+        (LayoutTestController::setDatabaseQuota):
+        * DumpRenderTree/mac/UIDelegate.mm:
+        (-[UIDelegate webView:frame:exceededDatabaseQuotaForSecurityOrigin:database:]):
+
 2008-04-26  Kevin Ollivier  <kevino@theolliviers.com>
 
         wx build fix. Need the latest libpng. (Somehow my initial test passed without it.)
index 4774310..2ef04a3 100644 (file)
@@ -179,7 +179,7 @@ void LayoutTestController::setCustomPolicyDelegate(bool setDelegate)
 
 void LayoutTestController::setDatabaseQuota(unsigned long long quota)
 {    
-    WebSecurityOrigin *origin = [[WebSecurityOrigin alloc] initWithProtocol:@"file" domain:nil];
+    WebSecurityOrigin *origin = [[WebSecurityOrigin alloc] initWithURL:[NSURL URLWithString:@"file:///"]];
     [origin setQuota:quota];
     [origin release];
 }
index cf4d342..eea3981 100644 (file)
@@ -131,7 +131,7 @@ DumpRenderTreeDraggingInfo *draggingInfo = nil;
 - (void)webView:(WebView *)sender frame:(WebFrame *)frame exceededDatabaseQuotaForSecurityOrigin:(WebSecurityOrigin *)origin database:(NSString *)databaseIdentifier
 {
     if (!done && layoutTestController->dumpDatabaseCallbacks())
-        printf("UI DELEGATE DATABASE CALLBACK: exceededDatabaseQuotaForSecurityOrigin:{%s, %s, %i} database:%s\n", [[origin protocol] UTF8String], [[origin domain] UTF8String], 
+        printf("UI DELEGATE DATABASE CALLBACK: exceededDatabaseQuotaForSecurityOrigin:{%s, %s, %i} database:%s\n", [[origin protocol] UTF8String], [[origin host] UTF8String], 
             [origin port], [databaseIdentifier UTF8String]);
 
     static const unsigned long long defaultQuota = 5 * 1024 * 1024;