Skip to content
Permalink
Browse files
window.postMessage() / MessagePort.postMessage() throw wrong exceptio…
…n for invalid ports argument

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:

Canonical link: https://commits.webkit.org/112518@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@126286 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
cdumez authored and webkit-commit-queue committed Aug 22, 2012
1 parent ecf02a1 commit bcead4bf2bc13c012470d4b3945478caefcde6c3
Showing 12 changed files with 107 additions and 40 deletions.
@@ -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.
@@ -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
@@ -91,9 +91,10 @@
// 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', { 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>
@@ -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.
@@ -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
@@ -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]);

@@ -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
@@ -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.
@@ -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
@@ -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);

0 comments on commit bcead4b

Please sign in to comment.