WebSocket: Receive binary message as ArrayBuffer
authoryutak@chromium.org <yutak@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 31 Aug 2011 08:33:38 +0000 (08:33 +0000)
committeryutak@chromium.org <yutak@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 31 Aug 2011 08:33:38 +0000 (08:33 +0000)
https://bugs.webkit.org/show_bug.cgi?id=67180

Reviewed by Kent Tamura.

Source/WebCore:

Tests: http/tests/websocket/tests/hybi/receive-arraybuffer.html
       http/tests/websocket/tests/hybi/workers/receive-arraybuffer.html

* bindings/js/JSMessageEventCustom.cpp:
(WebCore::JSMessageEvent::data): Convert ArrayBuffer to JSValue.
* bindings/v8/custom/V8MessageEventCustom.cpp:
(WebCore::V8MessageEvent::dataAccessorGetter): Convert ArrayBuffer to v8::Value.
* dom/MessageEvent.cpp:
(WebCore::MessageEvent::MessageEvent):
* dom/MessageEvent.h:
Added DataTypeArrayBuffer and ArrayBuffer-related functions.
(WebCore::MessageEvent::create):
(WebCore::MessageEvent::dataAsArrayBuffer):
* websockets/WebSocket.cpp:
(WebCore::WebSocket::didReceiveBinaryData):
Construct an ArrayBuffer from binaryData and raise MessageEvent.

LayoutTests:

* http/tests/websocket/tests/hybi/receive-arraybuffer-expected.txt: Added.
* http/tests/websocket/tests/hybi/receive-arraybuffer.html:
Added. Connect to binary-frames_wsh.py (which is also used from receive-blob.html) and
check the content of MessageEvent's data attribute.
* http/tests/websocket/tests/hybi/receive-blob.html:
Update function names to match ones in receive-arraybuffer.html.
* http/tests/websocket/tests/hybi/workers/receive-arraybuffer-expected.txt: Added.
* http/tests/websocket/tests/hybi/workers/receive-arraybuffer.html: Added.
* http/tests/websocket/tests/hybi/workers/resources/receive-arraybuffer.js: Added.
* http/tests/websocket/tests/hybi/workers/resources/receive-blob.js:
Same as receive-blob.html above.

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

14 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/websocket/tests/hybi/receive-arraybuffer-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/websocket/tests/hybi/receive-arraybuffer.html [new file with mode: 0644]
LayoutTests/http/tests/websocket/tests/hybi/receive-blob.html
LayoutTests/http/tests/websocket/tests/hybi/workers/receive-arraybuffer-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/websocket/tests/hybi/workers/receive-arraybuffer.html [new file with mode: 0644]
LayoutTests/http/tests/websocket/tests/hybi/workers/resources/receive-arraybuffer.js [new file with mode: 0644]
LayoutTests/http/tests/websocket/tests/hybi/workers/resources/receive-blob.js
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/JSMessageEventCustom.cpp
Source/WebCore/bindings/v8/custom/V8MessageEventCustom.cpp
Source/WebCore/dom/MessageEvent.cpp
Source/WebCore/dom/MessageEvent.h
Source/WebCore/websockets/WebSocket.cpp

index e0dba2f..f07b3e0 100644 (file)
@@ -1,3 +1,22 @@
+2011-08-31  Yuta Kitamura  <yutak@chromium.org>
+
+        WebSocket: Receive binary message as ArrayBuffer
+        https://bugs.webkit.org/show_bug.cgi?id=67180
+
+        Reviewed by Kent Tamura.
+
+        * http/tests/websocket/tests/hybi/receive-arraybuffer-expected.txt: Added.
+        * http/tests/websocket/tests/hybi/receive-arraybuffer.html:
+        Added. Connect to binary-frames_wsh.py (which is also used from receive-blob.html) and
+        check the content of MessageEvent's data attribute.
+        * http/tests/websocket/tests/hybi/receive-blob.html:
+        Update function names to match ones in receive-arraybuffer.html.
+        * http/tests/websocket/tests/hybi/workers/receive-arraybuffer-expected.txt: Added.
+        * http/tests/websocket/tests/hybi/workers/receive-arraybuffer.html: Added.
+        * http/tests/websocket/tests/hybi/workers/resources/receive-arraybuffer.js: Added.
+        * http/tests/websocket/tests/hybi/workers/resources/receive-blob.js:
+        Same as receive-blob.html above.
+
 2011-08-31  Philippe Normand  <pnormand@igalia.com>
 
         Unreviewed, GTK rebaseline after r94109 and r93909.
diff --git a/LayoutTests/http/tests/websocket/tests/hybi/receive-arraybuffer-expected.txt b/LayoutTests/http/tests/websocket/tests/hybi/receive-arraybuffer-expected.txt
new file mode 100644 (file)
index 0000000..006c072
--- /dev/null
@@ -0,0 +1,22 @@
+WebSocket: Receive ArrayBuffers.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS ws.binaryType is "arraybuffer"
+PASS receivedMessages.length is 3
+Checking message #0.
+PASS responseType is "[object ArrayBuffer]"
+PASS actualArray.length is 13
+PASS Passed: Message #0.
+Checking message #1.
+PASS responseType is "[object ArrayBuffer]"
+PASS actualArray.length is 0
+PASS Passed: Message #1.
+Checking message #2.
+PASS responseType is "[object ArrayBuffer]"
+PASS actualArray.length is 256
+PASS Passed: Message #2.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/websocket/tests/hybi/receive-arraybuffer.html b/LayoutTests/http/tests/websocket/tests/hybi/receive-arraybuffer.html
new file mode 100644 (file)
index 0000000..8893427
--- /dev/null
@@ -0,0 +1,94 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link rel="stylesheet" href="../../../../js-test-resources/js-test-style.css">
+<script src="../../../../js-test-resources/js-test-pre.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+description("WebSocket: Receive ArrayBuffers.");
+
+window.jsTestIsAsync = true;
+if (window.layoutTestController)
+    layoutTestController.overridePreference("WebKitHixie76WebSocketProtocolEnabled", 0);
+
+function createArrayBufferContainingHelloWorld()
+{
+    var hello = "Hello, world!";
+    var array = new Uint8Array(hello.length);
+    for (var i = 0; i < hello.length; ++i)
+        array[i] = hello.charCodeAt(i);
+    return array.buffer;
+}
+
+function createEmptyArrayBuffer()
+{
+    return new ArrayBuffer(0);
+}
+
+function createArrayBufferContainingAllDistinctBytes()
+{
+    var array = new Uint8Array(256);
+    for (var i = 0; i < 256; ++i)
+        array[i] = i;
+    return array.buffer;
+}
+
+var ws = new WebSocket("ws://127.0.0.1:8880/websocket/tests/hybi/binary-frames");
+ws.binaryType = "arraybuffer";
+shouldBeEqualToString("ws.binaryType", "arraybuffer");
+
+var closeEvent;
+var receivedMessages = [];
+var expectedValues = [createArrayBufferContainingHelloWorld(), createEmptyArrayBuffer(), createArrayBufferContainingAllDistinctBytes()];
+
+ws.onmessage = function(event)
+{
+    receivedMessages.push(event.data);
+};
+
+ws.onclose = function(event)
+{
+    closeEvent = event;
+
+    shouldEvaluateTo("receivedMessages.length", expectedValues.length);
+    for (var i = 0; i < expectedValues.length; ++i)
+        check(i);
+    finishJSTest();
+};
+
+var responseType;
+
+function check(index)
+{
+    debug("Checking message #" + index + ".");
+    responseType = '' + receivedMessages[index];
+    shouldBeEqualToString("responseType", "[object ArrayBuffer]");
+    checkArrayBuffer(index, receivedMessages[index], expectedValues[index]);
+}
+
+var actualArray;
+var expectedArray;
+
+function checkArrayBuffer(testIndex, actual, expected)
+{
+    actualArray = new Uint8Array(actual);
+    expectedArray = new Uint8Array(expected);
+    shouldEvaluateTo("actualArray.length", expectedArray.length);
+    // Print only the first mismatched byte in order not to flood console.
+    for (var i = 0; i < expectedArray.length; ++i) {
+        if (actualArray[i] != expectedArray[i]) {
+            testFailed("Value mismatch: actualArray[" + i + "] = " + actualArray[i] + ", expectedArray[" + i + "] = " + expectedArray[i]);
+            return;
+        }
+    }
+    testPassed("Passed: Message #" + testIndex + ".");
+}
+
+var successfullyParsed = true;
+</script>
+<script src="../../../../js-test-resources/js-test-post.js"></script>
+</body>
+</html>
index bb0cf6d..fbdaf68 100644 (file)
@@ -14,7 +14,7 @@ window.jsTestIsAsync = true;
 if (window.layoutTestController)
     layoutTestController.overridePreference("WebKitHixie76WebSocketProtocolEnabled", 0);
 
-function createHelloWorldValue()
+function createArrayBufferContainingHelloWorld()
 {
     var hello = "Hello, world!";
     var array = new Uint8Array(hello.length);
@@ -23,13 +23,12 @@ function createHelloWorldValue()
     return array.buffer;
 }
 
-function createEmptyValue()
+function createEmptyArrayBuffer()
 {
     return new ArrayBuffer(0);
 }
 
-// Create an ArrayBuffer containing all distinct bytes ("\x00" to "\xFF").
-function createAllBytesValue()
+function createArrayBufferContainingAllDistinctBytes()
 {
     var array = new Uint8Array(256);
     for (var i = 0; i < 256; ++i)
@@ -42,7 +41,7 @@ shouldBeEqualToString("ws.binaryType", "blob");
 
 var closeEvent;
 var receivedMessages = [];
-var expectedValues = [createHelloWorldValue(), createEmptyValue(), createAllBytesValue()];
+var expectedValues = [createArrayBufferContainingHelloWorld(), createEmptyArrayBuffer(), createArrayBufferContainingAllDistinctBytes()];
 
 ws.onmessage = function(event)
 {
diff --git a/LayoutTests/http/tests/websocket/tests/hybi/workers/receive-arraybuffer-expected.txt b/LayoutTests/http/tests/websocket/tests/hybi/workers/receive-arraybuffer-expected.txt
new file mode 100644 (file)
index 0000000..fd45652
--- /dev/null
@@ -0,0 +1,23 @@
+WebSocket: Receive ArrayBuffers in Web Workers.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS PASS: ws.binaryType is "arraybuffer"
+PASS PASS: receivedMessages.length is 3
+INFO: Checking message #0.
+PASS PASS: responseType is "[object ArrayBuffer]"
+PASS PASS: actualArray.length is 13
+PASS PASS: Passed: Message #0.
+INFO: Checking message #1.
+PASS PASS: responseType is "[object ArrayBuffer]"
+PASS PASS: actualArray.length is 0
+PASS PASS: Passed: Message #1.
+INFO: Checking message #2.
+PASS PASS: responseType is "[object ArrayBuffer]"
+PASS PASS: actualArray.length is 256
+PASS PASS: Passed: Message #2.
+DONE
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/websocket/tests/hybi/workers/receive-arraybuffer.html b/LayoutTests/http/tests/websocket/tests/hybi/workers/receive-arraybuffer.html
new file mode 100644 (file)
index 0000000..0d45ab6
--- /dev/null
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link rel="stylesheet" href="../../../../../js-test-resources/js-test-style.css">
+<script src="../../../../../js-test-resources/js-test-pre.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<script type="text/javascript">
+description("WebSocket: Receive ArrayBuffers in Web Workers.");
+
+window.jsTestIsAsync = true;
+if (window.layoutTestController)
+    layoutTestController.overridePreference("WebKitHixie76WebSocketProtocolEnabled", 0);
+
+function startsWith(str, prefix)
+{
+    return str.indexOf(prefix) == 0;
+}
+
+var worker = new Worker("resources/receive-arraybuffer.js");
+worker.onmessage = function (event)
+{
+    var message = event.data;
+    if (startsWith(message, "PASS"))
+        testPassed(message);
+    else if (startsWith(message, "FAIL"))
+        testFailed(message)
+    else
+        debug(message);
+    if (message === "DONE")
+        finishJSTest();
+};
+
+var successfullyParsed = true;
+</script>
+<script src="../../../../../js-test-resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/websocket/tests/hybi/workers/resources/receive-arraybuffer.js b/LayoutTests/http/tests/websocket/tests/hybi/workers/resources/receive-arraybuffer.js
new file mode 100644 (file)
index 0000000..2b25ab1
--- /dev/null
@@ -0,0 +1,76 @@
+function createArrayBufferContainingHelloWorld()
+{
+    var hello = "Hello, world!";
+    var array = new Uint8Array(hello.length);
+    for (var i = 0; i < hello.length; ++i)
+        array[i] = hello.charCodeAt(i);
+    return array.buffer;
+}
+
+function createEmptyArrayBuffer()
+{
+    return new ArrayBuffer(0);
+}
+
+function createArrayBufferContainingAllDistinctBytes()
+{
+    var array = new Uint8Array(256);
+    for (var i = 0; i < 256; ++i)
+        array[i] = i;
+    return array.buffer;
+}
+
+var ws = new WebSocket("ws://127.0.0.1:8880/websocket/tests/hybi/workers/resources/binary-frames");
+ws.binaryType = "arraybuffer";
+if (ws.binaryType === "arraybuffer")
+    postMessage("PASS: ws.binaryType is \"arraybuffer\"");
+else
+    postMessage("FAIL: ws.binaryType should be \"arraybuffer\" but was \"" + ws.binaryType + "\"");
+
+var receivedMessages = [];
+var expectedValues = [createArrayBufferContainingHelloWorld(), createEmptyArrayBuffer(), createArrayBufferContainingAllDistinctBytes()];
+
+ws.onmessage = function(event)
+{
+    receivedMessages.push(event.data);
+};
+
+ws.onclose = function(closeEvent)
+{
+    if (receivedMessages.length === expectedValues.length)
+        postMessage("PASS: receivedMessages.length is " + expectedValues.length);
+    else
+        postMessage("FAIL: receivedMessages.length should be " + expectedValues.length + " but was " + receivedMessages.length);
+    for (var i = 0; i < expectedValues.length; ++i)
+        check(i);
+    postMessage("DONE");
+};
+
+function check(index)
+{
+    postMessage("INFO: Checking message #" + index + ".");
+    var responseType = '' + receivedMessages[index];
+    if (responseType === "[object ArrayBuffer]")
+        postMessage("PASS: responseType is \"[object ArrayBuffer]\"");
+    else
+        postMessage("FAIL: responseType should be \"[object ArrayBuffer]\" but was \"" + responseType + "\"");
+    checkArrayBuffer(index, receivedMessages[index], expectedValues[index]);
+}
+
+function checkArrayBuffer(testIndex, actual, expected)
+{
+    var actualArray = new Uint8Array(actual);
+    var expectedArray = new Uint8Array(expected);
+    if (actualArray.length === expectedArray.length)
+        postMessage("PASS: actualArray.length is " + expectedArray.length);
+    else
+        postMessage("FAIL: actualArray.length should be " + expectedArray.length + " but was " + actualArray.length);
+    // Print only the first mismatched byte in order not to flood console.
+    for (var i = 0; i < expectedArray.length; ++i) {
+        if (actualArray[i] != expectedArray[i]) {
+            postMessage("FAIL: Value mismatch: actualArray[" + i + "] = " + actualArray[i] + ", expectedArray[" + i + "] = " + expectedArray[i]);
+            return;
+        }
+    }
+    postMessage("PASS: Passed: Message #" + testIndex + ".");
+}
index fc58353..0d58aa9 100644 (file)
@@ -1,4 +1,4 @@
-function createHelloWorldValue()
+function createArrayBufferContainingHelloWorld()
 {
     var hello = "Hello, world!";
     var array = new Uint8Array(hello.length);
@@ -7,13 +7,12 @@ function createHelloWorldValue()
     return array.buffer;
 }
 
-function createEmptyValue()
+function createEmptyArrayBuffer()
 {
     return new ArrayBuffer(0);
 }
 
-// Create an ArrayBuffer containing all distinct bytes ("\x00" to "\xFF").
-function createAllBytesValue()
+function createArrayBufferContainingAllDistinctBytes()
 {
     var array = new Uint8Array(256);
     for (var i = 0; i < 256; ++i)
@@ -28,7 +27,7 @@ else
     postMessage("FAIL: ws.binaryType should be \"blob\" but was \"" + ws.binaryType + "\"");
 
 var receivedMessages = [];
-var expectedValues = [createHelloWorldValue(), createEmptyValue(), createAllBytesValue()];
+var expectedValues = [createArrayBufferContainingHelloWorld(), createEmptyArrayBuffer(), createArrayBufferContainingAllDistinctBytes()];
 
 ws.onmessage = function(event)
 {
index 64eba66..502ea05 100644 (file)
@@ -1,3 +1,27 @@
+2011-08-31  Yuta Kitamura  <yutak@chromium.org>
+
+        WebSocket: Receive binary message as ArrayBuffer
+        https://bugs.webkit.org/show_bug.cgi?id=67180
+
+        Reviewed by Kent Tamura.
+
+        Tests: http/tests/websocket/tests/hybi/receive-arraybuffer.html
+               http/tests/websocket/tests/hybi/workers/receive-arraybuffer.html
+
+        * bindings/js/JSMessageEventCustom.cpp:
+        (WebCore::JSMessageEvent::data): Convert ArrayBuffer to JSValue.
+        * bindings/v8/custom/V8MessageEventCustom.cpp:
+        (WebCore::V8MessageEvent::dataAccessorGetter): Convert ArrayBuffer to v8::Value.
+        * dom/MessageEvent.cpp:
+        (WebCore::MessageEvent::MessageEvent):
+        * dom/MessageEvent.h:
+        Added DataTypeArrayBuffer and ArrayBuffer-related functions.
+        (WebCore::MessageEvent::create):
+        (WebCore::MessageEvent::dataAsArrayBuffer):
+        * websockets/WebSocket.cpp:
+        (WebCore::WebSocket::didReceiveBinaryData):
+        Construct an ArrayBuffer from binaryData and raise MessageEvent.
+
 2011-08-31  Keishi Hattori  <keishi@webkit.org>
 
         input color: onchange event is not fired when changing color from color chooser
index da91154..fb035c5 100644 (file)
@@ -31,6 +31,7 @@
 #include "config.h"
 #include "JSMessageEvent.h"
 
+#include "JSArrayBuffer.h"
 #include "JSBlob.h"
 #include "JSDOMBinding.h"
 #include "JSDOMWindow.h"
@@ -65,6 +66,10 @@ JSValue JSMessageEvent::data(ExecState* exec) const
     case MessageEvent::DataTypeBlob:
         result = toJS(exec, globalObject(), event->dataAsBlob());
         break;
+
+    case MessageEvent::DataTypeArrayBuffer:
+        result = toJS(exec, globalObject(), event->dataAsArrayBuffer());
+        break;
     }
 
     // Save the result so we don't have to deserialize the value again.
index 75c7b57..d64083c 100644 (file)
@@ -34,6 +34,7 @@
 #include "MessageEvent.h"
 #include "SerializedScriptValue.h"
 
+#include "V8ArrayBuffer.h"
 #include "V8Binding.h"
 #include "V8Blob.h"
 #include "V8DOMWindow.h"
@@ -66,6 +67,10 @@ v8::Handle<v8::Value> V8MessageEvent::dataAccessorGetter(v8::Local<v8::String> n
     case MessageEvent::DataTypeBlob:
         result = toV8(event->dataAsBlob());
         break;
+
+    case MessageEvent::DataTypeArrayBuffer:
+        result = toV8(event->dataAsArrayBuffer());
+        break;
     }
 
     // Overwrite the data attribute so it returns the cached result in future invocations.
index 3432d6f..2731fa3 100644 (file)
@@ -68,6 +68,15 @@ MessageEvent::MessageEvent(PassRefPtr<Blob> data)
 {
 }
 
+MessageEvent::MessageEvent(PassRefPtr<ArrayBuffer> data)
+    : Event(eventNames().messageEvent, false, false)
+    , m_dataType(DataTypeArrayBuffer)
+    , m_dataAsArrayBuffer(data)
+    , m_origin("")
+    , m_lastEventId("")
+{
+}
+
 MessageEvent::~MessageEvent()
 {
 }
index 3eb2c4f..ded8074 100644 (file)
@@ -28,6 +28,7 @@
 #ifndef MessageEvent_h
 #define MessageEvent_h
 
+#include "ArrayBuffer.h"
 #include "Blob.h"
 #include "DOMWindow.h"
 #include "Event.h"
@@ -56,6 +57,10 @@ namespace WebCore {
         {
             return adoptRef(new MessageEvent(data));
         }
+        static PassRefPtr<MessageEvent> create(PassRefPtr<ArrayBuffer> data)
+        {
+            return adoptRef(new MessageEvent(data));
+        }
         virtual ~MessageEvent();
 
         void initMessageEvent(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr<SerializedScriptValue> data, const String& origin, const String& lastEventId, DOMWindow* source, PassOwnPtr<MessagePortArray>);
@@ -78,23 +83,27 @@ namespace WebCore {
         enum DataType {
             DataTypeSerializedScriptValue,
             DataTypeString,
-            DataTypeBlob
+            DataTypeBlob,
+            DataTypeArrayBuffer
         };
         DataType dataType() const { return m_dataType; }
         SerializedScriptValue* dataAsSerializedScriptValue() const { return m_dataAsSerializedScriptValue.get(); }
         String dataAsString() const { return m_dataAsString; }
         Blob* dataAsBlob() const { return m_dataAsBlob.get(); }
+        ArrayBuffer* dataAsArrayBuffer() const { return m_dataAsArrayBuffer.get(); }
 
     private:
         MessageEvent();
         MessageEvent(PassRefPtr<SerializedScriptValue> data, const String& origin, const String& lastEventId, PassRefPtr<DOMWindow> source, PassOwnPtr<MessagePortArray>);
         explicit MessageEvent(const String& data);
         explicit MessageEvent(PassRefPtr<Blob> data);
+        explicit MessageEvent(PassRefPtr<ArrayBuffer> data);
 
         DataType m_dataType;
         RefPtr<SerializedScriptValue> m_dataAsSerializedScriptValue;
         String m_dataAsString;
         RefPtr<Blob> m_dataAsBlob;
+        RefPtr<ArrayBuffer> m_dataAsArrayBuffer;
         String m_origin;
         String m_lastEventId;
         RefPtr<DOMWindow> m_source;
index 4fa8719..dc9abba 100644 (file)
@@ -415,7 +415,7 @@ void WebSocket::didReceiveBinaryData(PassOwnPtr<Vector<char> > binaryData)
     }
 
     case BinaryTypeArrayBuffer:
-        m_channel->fail("Cannot receive WebSocket binary data as ArrayBuffer yet.");
+        dispatchEvent(MessageEvent::create(ArrayBuffer::create(binaryData->data(), binaryData->size())));
         break;
     }
 }