window.postMessage() / MessagePort.postMessage() throw wrong exception for invalid...
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 22 Aug 2012 10:37:10 +0000 (10:37 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 22 Aug 2012 10:37:10 +0000 (10:37 +0000)
https://bugs.webkit.org/show_bug.cgi?id=94581

Patch by Christophe Dumez <christophe.dumez@intel.com> on 2012-08-22
Reviewed by Kentaro Hara.

Source/WebCore:

Update JSC and V8 implementations of window.postMessage() and
MessagePort.postMessage() in order to throw an
INVALID_STATE_ERR instead of a DATA_CLONE_ERR when values
in the "ports" argument are invalid. Additionally, we now
check for duplicate ports and throw an exception for this
case as well.

This change was made to comply with the latest HTML5
specification at:
http://www.w3.org/TR/html5/comms.html

No new tests, already tested by:
fast/events/constructors/message-event-constructor.html
fast/events/message-port-clone.html
fast/events/message-port-multi.html
fast/workers/worker-context-multi-port.html
fast/workers/worker-multi-port.html

* bindings/js/JSMessagePortCustom.cpp:
(WebCore::fillMessagePortArray):
* bindings/v8/V8Utilities.cpp:
(WebCore::extractTransferables):
* dom/MessagePort.cpp:
(WebCore::MessagePort::postMessage):

LayoutTests:

Update several tests and their expected results now that an
INVALID_STATE_ERR is thrown instead of a DATA_CLONE_ERROR
when window.postMessage() / MessagePort.postMessage() are
called with invalid values in their 'ports' argument.

* fast/events/constructors/message-event-constructor-expected.txt:
* fast/events/constructors/message-event-constructor.html: Stop using duplicate
ports in the test since it throws an exception now.
* fast/events/message-port-clone-expected.txt:
* fast/events/message-port-multi-expected.txt:
* fast/events/resources/message-port-multi.js: Add check for duplicate port case.
* fast/workers/worker-context-multi-port-expected.txt:
* fast/workers/worker-multi-port-expected.txt:

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

12 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/events/constructors/message-event-constructor-expected.txt
LayoutTests/fast/events/constructors/message-event-constructor.html
LayoutTests/fast/events/message-port-clone-expected.txt
LayoutTests/fast/events/message-port-multi-expected.txt
LayoutTests/fast/events/resources/message-port-multi.js
LayoutTests/fast/workers/worker-context-multi-port-expected.txt
LayoutTests/fast/workers/worker-multi-port-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/JSMessagePortCustom.cpp
Source/WebCore/bindings/v8/V8Utilities.cpp
Source/WebCore/dom/MessagePort.cpp

index 3382d1d..f0b64c1 100644 (file)
@@ -1,3 +1,24 @@
+2012-08-22  Christophe Dumez  <christophe.dumez@intel.com>
+
+        window.postMessage() / MessagePort.postMessage() throw wrong exception for invalid ports argument
+        https://bugs.webkit.org/show_bug.cgi?id=94581
+
+        Reviewed by Kentaro Hara.
+
+        Update several tests and their expected results now that an
+        INVALID_STATE_ERR is thrown instead of a DATA_CLONE_ERROR
+        when window.postMessage() / MessagePort.postMessage() are
+        called with invalid values in their 'ports' argument.
+
+        * fast/events/constructors/message-event-constructor-expected.txt:
+        * fast/events/constructors/message-event-constructor.html: Stop using duplicate
+        ports in the test since it throws an exception now.
+        * fast/events/message-port-clone-expected.txt:
+        * fast/events/message-port-multi-expected.txt:
+        * fast/events/resources/message-port-multi.js: Add check for duplicate port case.
+        * fast/workers/worker-context-multi-port-expected.txt:
+        * fast/workers/worker-multi-port-expected.txt:
+
 2012-08-22  Ulan Degenbaev  <ulan@chromium.org>
 
         Remove chromium/fast/js/array-functions-non-arrays-expected.txt and add WebKit bug id to chromium/TestExpectation.
index 733ae4c..32df67d 100644 (file)
@@ -74,9 +74,9 @@ PASS new MessageEvent('eventType', { source: NaN }).source is null
 PASS new MessageEvent('eventType', { source: {valueOf: function () { return window; } } }).source == window is false
 PASS new MessageEvent('eventType', { get source() { return 123; } }).source is null
 PASS new MessageEvent('eventType', { get source() { throw 'MessageEvent Error'; } }) threw exception MessageEvent Error.
-PASS new MessageEvent('eventType', { ports: [channel.port1, channel.port2, channel.port2] }).ports[0] is channel.port1
-PASS new MessageEvent('eventType', { ports: [channel.port1, channel.port2, channel.port2] }).ports[1] is channel.port2
-PASS new MessageEvent('eventType', { ports: [channel.port1, channel.port2, channel.port2] }).ports[2] is channel.port2
+PASS new MessageEvent('eventType', { ports: [channel.port1, channel.port2, channel2.port1] }).ports[0] is channel.port1
+PASS new MessageEvent('eventType', { ports: [channel.port1, channel.port2, channel2.port1] }).ports[1] is channel.port2
+PASS new MessageEvent('eventType', { ports: [channel.port1, channel.port2, channel2.port1] }).ports[2] is channel2.port1
 PASS new MessageEvent('eventType', { ports: [] }).ports is []
 PASS new MessageEvent('eventType', { ports: undefined }).ports is []
 PASS new MessageEvent('eventType', { ports: null }).ports is []
@@ -93,15 +93,15 @@ PASS new MessageEvent('eventType', { ports: NaN }).ports threw exception TypeErr
 PASS new MessageEvent('eventType', { get ports() { return 123; } }).ports threw exception TypeError: Type error.
 PASS new MessageEvent('eventType', { get ports() { throw 'MessageEvent Error'; } }) threw exception MessageEvent Error.
 PASS new MessageEvent('eventType', { ports: {valueOf: function () { return [channel.port1, channel.port2, channel.port2]; } } }).ports[0] threw exception TypeError: Type error.
-PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel.port2] }).bubbles is true
-PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel.port2] }).cancelable is true
-PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel.port2] }).data is test_object
-PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel.port2] }).origin is "wonderful"
-PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel.port2] }).lastEventId is "excellent"
-PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel.port2] }).source is window
-PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel.port2] }).ports[0] is channel.port1
-PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel.port2] }).ports[1] is channel.port2
-PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel.port2] }).ports[2] is channel.port2
+PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel2.port1] }).bubbles is true
+PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel2.port1] }).cancelable is true
+PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel2.port1] }).data is test_object
+PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel2.port1] }).origin is "wonderful"
+PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel2.port1] }).lastEventId is "excellent"
+PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel2.port1] }).source is window
+PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel2.port1] }).ports[0] is channel.port1
+PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel2.port1] }).ports[1] is channel.port2
+PASS new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel2.port1] }).ports[2] is channel2.port1
 PASS successfullyParsed is true
 
 TEST COMPLETE
index cdfd39f..20155cd 100644 (file)
@@ -91,9 +91,10 @@ shouldThrow("new MessageEvent('eventType', { get source() { throw 'MessageEvent
 // ports is passed.
 // Valid message ports.
 var channel = new MessageChannel();
-shouldBe("new MessageEvent('eventType', { ports: [channel.port1, channel.port2, channel.port2] }).ports[0]", "channel.port1");
-shouldBe("new MessageEvent('eventType', { ports: [channel.port1, channel.port2, channel.port2] }).ports[1]", "channel.port2");
-shouldBe("new MessageEvent('eventType', { ports: [channel.port1, channel.port2, channel.port2] }).ports[2]", "channel.port2");
+var channel2 = new MessageChannel();
+shouldBe("new MessageEvent('eventType', { ports: [channel.port1, channel.port2, channel2.port1] }).ports[0]", "channel.port1");
+shouldBe("new MessageEvent('eventType', { ports: [channel.port1, channel.port2, channel2.port1] }).ports[1]", "channel.port2");
+shouldBe("new MessageEvent('eventType', { ports: [channel.port1, channel.port2, channel2.port1] }).ports[2]", "channel2.port1");
 shouldBe("new MessageEvent('eventType', { ports: [] }).ports", "[]");
 shouldBe("new MessageEvent('eventType', { ports: undefined }).ports", "[]");
 shouldBe("new MessageEvent('eventType', { ports: null }).ports", "[]");
@@ -115,15 +116,15 @@ shouldThrow("new MessageEvent('eventType', { get ports() { throw 'MessageEvent E
 shouldThrow("new MessageEvent('eventType', { ports: {valueOf: function () { return [channel.port1, channel.port2, channel.port2]; } } }).ports[0]");
 
 // All initializers are passed.
-shouldBe("new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel.port2] }).bubbles", "true");
-shouldBe("new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel.port2] }).cancelable", "true");
-shouldBe("new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel.port2] }).data", "test_object");
-shouldBeEqualToString("new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel.port2] }).origin", "wonderful");
-shouldBeEqualToString("new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel.port2] }).lastEventId", "excellent");
-shouldBe("new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel.port2] }).source", "window");
-shouldBe("new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel.port2] }).ports[0]", "channel.port1");
-shouldBe("new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel.port2] }).ports[1]", "channel.port2");
-shouldBe("new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel.port2] }).ports[2]", "channel.port2");
+shouldBe("new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel2.port1] }).bubbles", "true");
+shouldBe("new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel2.port1] }).cancelable", "true");
+shouldBe("new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel2.port1] }).data", "test_object");
+shouldBeEqualToString("new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel2.port1] }).origin", "wonderful");
+shouldBeEqualToString("new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel2.port1] }).lastEventId", "excellent");
+shouldBe("new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel2.port1] }).source", "window");
+shouldBe("new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel2.port1] }).ports[0]", "channel.port1");
+shouldBe("new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel2.port1] }).ports[1]", "channel.port2");
+shouldBe("new MessageEvent('eventType', { bubbles: true, cancelable: true, data: test_object, origin: 'wonderful', lastEventId: 'excellent', source: window, ports: [channel.port1, channel.port2, channel2.port1] }).ports[2]", "channel2.port1");
 </script>
 <script src="../../js/resources/js-test-post.js"></script>
 </body>
index e5dbdac..cd3278a 100644 (file)
@@ -2,8 +2,8 @@ Tests various use cases when cloning MessagePorts.
 
 Should be a series of SUCCESS messages, followed with DONE.
 
-SUCCESS: Posting port to itself: Error: DATA_CLONE_ERR: DOM Exception 25
-SUCCESS: Posting entangled port: Error: DATA_CLONE_ERR: DOM Exception 25
+SUCCESS: Posting port to itself: Error: INVALID_STATE_ERR: DOM Exception 11
+SUCCESS: Posting entangled port: Error: INVALID_STATE_ERR: DOM Exception 11
 SUCCESS: Posting cloned port.
 SUCCESS: Posted messages to cloned port.
 SUCCESS: Cloned both endpoints of a channel.
index c34efca..9f7c130 100644 (file)
@@ -3,13 +3,14 @@ This test checks the various use cases around sending multiple ports through Mes
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS channel.port1.postMessage("same port", [channel.port1]) threw exception Error: DATA_CLONE_ERR: DOM Exception 25.
-PASS channel.port1.postMessage("entangled port", [channel.port2]) threw exception Error: DATA_CLONE_ERR: DOM Exception 25.
-PASS channel.port1.postMessage("null port", [channel3.port1, null, channel3.port2]) threw exception Error: DATA_CLONE_ERR: DOM Exception 25.
+PASS channel.port1.postMessage("same port", [channel.port1]) threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
+PASS channel.port1.postMessage("entangled port", [channel.port2]) threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
+PASS channel.port1.postMessage("null port", [channel3.port1, null, channel3.port2]) threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
 PASS channel.port1.postMessage("notAPort", [channel3.port1, {}, channel3.port2]) threw exception TypeError: Type error.
+PASS channel.port1.postMessage("duplicate port", [channel3.port1, channel3.port1]) threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
 PASS channel.port1.postMessage("notAnArray", channel3.port1) threw exception TypeError: Type error.
 PASS channel.port1.postMessage("notASequence", [{length: 3}]) threw exception TypeError: Type error.
-PASS channel.port1.postMessage("largeSequence", largePortArray) threw exception Error: DATA_CLONE_ERR: DOM Exception 25.
+PASS channel.port1.postMessage("largeSequence", largePortArray) threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
 PASS event.ports is non-null and zero length when no port sent
 PASS event.ports is non-null and zero length when empty array sent
 PASS event.ports contains two ports when two ports sent
index f02ed59..3e0fdb3 100644 (file)
@@ -19,6 +19,7 @@ shouldThrow('channel.port1.postMessage("same port", [channel.port1])');
 shouldThrow('channel.port1.postMessage("entangled port", [channel.port2])');
 shouldThrow('channel.port1.postMessage("null port", [channel3.port1, null, channel3.port2])');
 shouldThrow('channel.port1.postMessage("notAPort", [channel3.port1, {}, channel3.port2])');
+shouldThrow('channel.port1.postMessage("duplicate port", [channel3.port1, channel3.port1])');
 // Should be OK to send channel3.port1 (should not have been disentangled by the previous failed calls).
 channel.port1.postMessage("entangled ports", [channel3.port1, channel3.port2]);
 
index d20453f..61691fa 100644 (file)
@@ -6,7 +6,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
 PASS event.ports is non-null and zero length when no port sent
 PASS event.ports is non-null and zero length when empty array sent
 PASS event.ports contains two ports when two ports sent
-PASS posting a null port did throw: Error: DATA_CLONE_ERR: DOM Exception 25
+PASS posting a null port did throw: Error: INVALID_STATE_ERR: DOM Exception 11
 PASS posting a non-port did throw: TypeError: Type error
 PASS event.ports contains two ports when two ports re-sent after error
 PASS posting a non-array did throw: TypeError: Type error
index 887abe7..99eb8c8 100644 (file)
@@ -3,7 +3,7 @@ This test checks the various use cases around sending multiple ports through Wor
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS worker.postMessage("null port", [channel3.port1, null, channel3.port2]) threw exception Error: DATA_CLONE_ERR: DOM Exception 25.
+PASS worker.postMessage("null port", [channel3.port1, null, channel3.port2]) threw exception Error: INVALID_STATE_ERR: DOM Exception 11.
 PASS worker.postMessage("notAPort", [channel3.port1, {}, channel3.port2]) threw exception TypeError: Type error.
 PASS worker.postMessage("notAnArray", channel3.port1) threw exception TypeError: Type error.
 PASS worker.postMessage("notASequence", [{length: 3}]) threw exception TypeError: Type error.
index 62be85e..a0b5e82 100644 (file)
@@ -1,3 +1,35 @@
+2012-08-22  Christophe Dumez  <christophe.dumez@intel.com>
+
+        window.postMessage() / MessagePort.postMessage() throw wrong exception for invalid ports argument
+        https://bugs.webkit.org/show_bug.cgi?id=94581
+
+        Reviewed by Kentaro Hara.
+
+        Update JSC and V8 implementations of window.postMessage() and
+        MessagePort.postMessage() in order to throw an
+        INVALID_STATE_ERR instead of a DATA_CLONE_ERR when values
+        in the "ports" argument are invalid. Additionally, we now
+        check for duplicate ports and throw an exception for this
+        case as well.
+
+        This change was made to comply with the latest HTML5
+        specification at:
+        http://www.w3.org/TR/html5/comms.html
+
+        No new tests, already tested by:
+        fast/events/constructors/message-event-constructor.html
+        fast/events/message-port-clone.html
+        fast/events/message-port-multi.html
+        fast/workers/worker-context-multi-port.html
+        fast/workers/worker-multi-port.html
+
+        * bindings/js/JSMessagePortCustom.cpp:
+        (WebCore::fillMessagePortArray):
+        * bindings/v8/V8Utilities.cpp:
+        (WebCore::extractTransferables):
+        * dom/MessagePort.cpp:
+        (WebCore::MessagePort::postMessage):
+
 2012-08-22  Allan Sandfeld Jensen  <allan.jensen@nokia.com>
 
         [TouchAdjustment] Adjust to word or selection
index f44bbb7..7a439d3 100644 (file)
@@ -90,15 +90,20 @@ void fillMessagePortArray(JSC::ExecState* exec, JSC::JSValue value, MessagePortA
             return;
         // Validation of non-null objects, per HTML5 spec 10.3.3.
         if (value.isUndefinedOrNull()) {
-            setDOMException(exec, DATA_CLONE_ERR);
+            setDOMException(exec, INVALID_STATE_ERR);
             return;
         }
 
         // Validation of Objects implementing an interface, per WebIDL spec 4.1.15.
         RefPtr<MessagePort> port = toMessagePort(value);
-        if (port)
+        if (port) {
+            // Check for duplicate ports.
+            if (portArray.contains(port)) {
+                setDOMException(exec, INVALID_STATE_ERR);
+                return;
+            }
             portArray.append(port.release());
-        else {
+        else {
             RefPtr<ArrayBuffer> arrayBuffer = toArrayBuffer(value);
             if (arrayBuffer)
                 arrayBuffers.append(arrayBuffer);
index 4cfe531..ef6dad5 100644 (file)
@@ -104,13 +104,19 @@ bool extractTransferables(v8::Local<v8::Value> value, MessagePortArray& ports, A
         v8::Local<v8::Value> transferrable = transferrables->Get(i);
         // Validation of non-null objects, per HTML5 spec 10.3.3.
         if (isUndefinedOrNull(transferrable)) {
-            setDOMException(DATA_CLONE_ERR, isolate);
+            setDOMException(INVALID_STATE_ERR, isolate);
             return false;
         }
         // Validation of Objects implementing an interface, per WebIDL spec 4.1.15.
-        if (V8MessagePort::HasInstance(transferrable))
-            ports.append(V8MessagePort::toNative(v8::Handle<v8::Object>::Cast(transferrable)));
-        else if (V8ArrayBuffer::HasInstance(transferrable))
+        if (V8MessagePort::HasInstance(transferrable)) {
+            RefPtr<MessagePort> port = V8MessagePort::toNative(v8::Handle<v8::Object>::Cast(transferrable));
+            // Check for duplicate MessagePorts.
+            if (ports.contains(port)) {
+                setDOMException(INVALID_STATE_ERR, isolate);
+                return false;
+            }
+            ports.append(port.release());
+        } else if (V8ArrayBuffer::HasInstance(transferrable))
             arrayBuffers.append(V8ArrayBuffer::toNative(v8::Handle<v8::Object>::Cast(transferrable)));
         else {
             throwTypeError();
index ab4dcdc..50d4b16 100644 (file)
@@ -83,7 +83,7 @@ void MessagePort::postMessage(PassRefPtr<SerializedScriptValue> message, const M
         for (unsigned int i = 0; i < ports->size(); ++i) {
             MessagePort* dataPort = (*ports)[i].get();
             if (dataPort == this || m_entangledChannel->isConnectedTo(dataPort)) {
-                ec = DATA_CLONE_ERR;
+                ec = INVALID_STATE_ERR;
                 return;
             }
         }