WebSocket: Send ArrayBuffer as WebSocket binary message
authoryutak@chromium.org <yutak@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 3 Sep 2011 07:45:22 +0000 (07:45 +0000)
committeryutak@chromium.org <yutak@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 3 Sep 2011 07:45:22 +0000 (07:45 +0000)
https://bugs.webkit.org/show_bug.cgi?id=67477

Reviewed by Kent Tamura.

Source/WebCore:

Tests: http/tests/websocket/tests/hybi/send-arraybuffer.html
       http/tests/websocket/tests/hybi/workers/send-arraybuffer.html
       http/tests/websocket/tests/hybi/bufferedAmount-after-close.html (updated)

* bindings/js/JSWebSocketCustom.cpp:
(WebCore::JSWebSocket::send):
* bindings/v8/custom/V8WebSocketCustom.cpp:
(WebCore::V8WebSocket::sendCallback):
* websockets/ThreadableWebSocketChannel.h:
* websockets/ThreadableWebSocketChannelClientWrapper.cpp:
(WebCore::ThreadableWebSocketChannelClientWrapper::ThreadableWebSocketChannelClientWrapper):
(WebCore::ThreadableWebSocketChannelClientWrapper::sendRequestResult):
(WebCore::ThreadableWebSocketChannelClientWrapper::setSendRequestResult):
* websockets/ThreadableWebSocketChannelClientWrapper.h:
Rename "sent" to "sendRequestResult" to clarify the meaning. Messages from the script may not
be sent immediately, thus the return value of WebSocketChannel::send() indicates whether the
message has been queued successfully, rather than whether the message has been sent or not.
* websockets/WebSocket.cpp:
(WebCore::WebSocket::send):
Case of sending "[object ArrayBuffer]" is covered by an existing test
http/tests/websocket/tests/{hybi,hixie76}/send-object.html.
* websockets/WebSocket.h:
* websockets/WebSocket.idl:
* websockets/WebSocketChannel.cpp:
(WebCore::WebSocketChannel::send):
* websockets/WebSocketChannel.h:
* websockets/WorkerThreadableWebSocketChannel.cpp:
(WebCore::WorkerThreadableWebSocketChannel::send):
(WebCore::workerContextDidSend):
(WebCore::WorkerThreadableWebSocketChannel::Peer::send):
(WebCore::WorkerThreadableWebSocketChannel::mainThreadSendArrayBuffer):
Construct an ArrayBuffer from the data on Vector<char>.
(WebCore::WorkerThreadableWebSocketChannel::Bridge::send):
Copy the content into temporary buffer of Vector<char>, and send it to the main thread.
* websockets/WorkerThreadableWebSocketChannel.h:

LayoutTests:

* http/tests/websocket/tests/hybi/bufferedAmount-after-close-expected.txt:
* http/tests/websocket/tests/hybi/bufferedAmount-after-close.html:
Add tests to send ArrayBuffers.
* http/tests/websocket/tests/hybi/check-binary-messages_wsh.py:
Renamed from LayoutTests/http/tests/websocket/tests/hybi/send-blob_wsh.py, because this handler
is used from send-blob.html and send-arraybuffer.html.
* http/tests/websocket/tests/hybi/send-arraybuffer-expected.txt: Added.
* http/tests/websocket/tests/hybi/send-arraybuffer.html:
Added. Send three small binary messages as ArrayBuffers.
* http/tests/websocket/tests/hybi/send-blob.html:
* http/tests/websocket/tests/hybi/workers/resources/check-binary-messages_wsh.py:
Renamed from LayoutTests/http/tests/websocket/tests/hybi/workers/resources/send-blob_wsh.py.
* http/tests/websocket/tests/hybi/workers/resources/send-arraybuffer.js:
Added. Same as send-arraybuffer.html, except that this test is run on the worker.
* http/tests/websocket/tests/hybi/workers/resources/send-blob.js:
Removed the definition of unnecessary function startsWith().
* http/tests/websocket/tests/hybi/workers/send-arraybuffer-expected.txt: Added.
* http/tests/websocket/tests/hybi/workers/send-arraybuffer.html: Added

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

25 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/websocket/tests/hybi/bufferedAmount-after-close-expected.txt
LayoutTests/http/tests/websocket/tests/hybi/bufferedAmount-after-close.html
LayoutTests/http/tests/websocket/tests/hybi/check-binary-messages_wsh.py [moved from LayoutTests/http/tests/websocket/tests/hybi/send-blob_wsh.py with 100% similarity]
LayoutTests/http/tests/websocket/tests/hybi/send-arraybuffer-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/websocket/tests/hybi/send-arraybuffer.html [new file with mode: 0644]
LayoutTests/http/tests/websocket/tests/hybi/send-blob.html
LayoutTests/http/tests/websocket/tests/hybi/workers/resources/check-binary-messages_wsh.py [moved from LayoutTests/http/tests/websocket/tests/hybi/workers/resources/send-blob_wsh.py with 100% similarity]
LayoutTests/http/tests/websocket/tests/hybi/workers/resources/send-arraybuffer.js [new file with mode: 0644]
LayoutTests/http/tests/websocket/tests/hybi/workers/resources/send-blob.js
LayoutTests/http/tests/websocket/tests/hybi/workers/send-arraybuffer-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/websocket/tests/hybi/workers/send-arraybuffer.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/JSWebSocketCustom.cpp
Source/WebCore/bindings/v8/custom/V8WebSocketCustom.cpp
Source/WebCore/websockets/ThreadableWebSocketChannel.h
Source/WebCore/websockets/ThreadableWebSocketChannelClientWrapper.cpp
Source/WebCore/websockets/ThreadableWebSocketChannelClientWrapper.h
Source/WebCore/websockets/WebSocket.cpp
Source/WebCore/websockets/WebSocket.h
Source/WebCore/websockets/WebSocket.idl
Source/WebCore/websockets/WebSocketChannel.cpp
Source/WebCore/websockets/WebSocketChannel.h
Source/WebCore/websockets/WorkerThreadableWebSocketChannel.cpp
Source/WebCore/websockets/WorkerThreadableWebSocketChannel.h

index 2688edc..d45b73f 100644 (file)
@@ -1,3 +1,29 @@
+2011-09-03  Yuta Kitamura  <yutak@chromium.org>
+
+        WebSocket: Send ArrayBuffer as WebSocket binary message
+        https://bugs.webkit.org/show_bug.cgi?id=67477
+
+        Reviewed by Kent Tamura.
+
+        * http/tests/websocket/tests/hybi/bufferedAmount-after-close-expected.txt:
+        * http/tests/websocket/tests/hybi/bufferedAmount-after-close.html:
+        Add tests to send ArrayBuffers.
+        * http/tests/websocket/tests/hybi/check-binary-messages_wsh.py:
+        Renamed from LayoutTests/http/tests/websocket/tests/hybi/send-blob_wsh.py, because this handler
+        is used from send-blob.html and send-arraybuffer.html.
+        * http/tests/websocket/tests/hybi/send-arraybuffer-expected.txt: Added.
+        * http/tests/websocket/tests/hybi/send-arraybuffer.html:
+        Added. Send three small binary messages as ArrayBuffers.
+        * http/tests/websocket/tests/hybi/send-blob.html:
+        * http/tests/websocket/tests/hybi/workers/resources/check-binary-messages_wsh.py:
+        Renamed from LayoutTests/http/tests/websocket/tests/hybi/workers/resources/send-blob_wsh.py.
+        * http/tests/websocket/tests/hybi/workers/resources/send-arraybuffer.js:
+        Added. Same as send-arraybuffer.html, except that this test is run on the worker.
+        * http/tests/websocket/tests/hybi/workers/resources/send-blob.js:
+        Removed the definition of unnecessary function startsWith().
+        * http/tests/websocket/tests/hybi/workers/send-arraybuffer-expected.txt: Added.
+        * http/tests/websocket/tests/hybi/workers/send-arraybuffer.html: Added
+
 2011-09-02  Kentaro Hara  <haraken@google.com>
 
         Implement a CustomEvent constructor for V8
index 7c6d55e..044fe0f 100644 (file)
@@ -21,6 +21,19 @@ PASS ws.send(messageToSend) is false
 PASS bufferedAmountDifference is 65543
 PASS ws.send(messageToSend) is false
 PASS bufferedAmountDifference is 65550
+Testing send(ArrayBuffer)...
+PASS ws.send(messageToSend) is false
+PASS bufferedAmountDifference is 6
+PASS ws.send(messageToSend) is false
+PASS bufferedAmountDifference is 7
+PASS ws.send(messageToSend) is false
+PASS bufferedAmountDifference is 131
+PASS ws.send(messageToSend) is false
+PASS bufferedAmountDifference is 134
+PASS ws.send(messageToSend) is false
+PASS bufferedAmountDifference is 65543
+PASS ws.send(messageToSend) is false
+PASS bufferedAmountDifference is 65550
 Testing send(Blob)...
 PASS ws.send(messageToSend) is false
 PASS bufferedAmountDifference is 6
index c6b2604..2333d73 100644 (file)
@@ -53,6 +53,14 @@ ws.onclose = function()
     testBufferedAmount(createStringWithLength(0xFFFF), 0xFFFF + baseOverhead + 2);
     testBufferedAmount(createStringWithLength(0x10000), 0x10000 + baseOverhead + 8); // With 64-bit extended payload length field.
 
+    debug("Testing send(ArrayBuffer)...");
+    testBufferedAmount(new ArrayBuffer(0), baseOverhead);
+    testBufferedAmount(new ArrayBuffer(1), 1 + baseOverhead);
+    testBufferedAmount(new ArrayBuffer(125), 125 + baseOverhead);
+    testBufferedAmount(new ArrayBuffer(126), 126 + baseOverhead + 2);
+    testBufferedAmount(new ArrayBuffer(0xFFFF), 0xFFFF + baseOverhead + 2);
+    testBufferedAmount(new ArrayBuffer(0x10000), 0x10000 + baseOverhead + 8);
+
     debug("Testing send(Blob)...");
     testBufferedAmount(createBlobWithLength(0), baseOverhead);
     testBufferedAmount(createBlobWithLength(1), 1 + baseOverhead);
diff --git a/LayoutTests/http/tests/websocket/tests/hybi/send-arraybuffer-expected.txt b/LayoutTests/http/tests/websocket/tests/hybi/send-arraybuffer-expected.txt
new file mode 100644 (file)
index 0000000..850c52e
--- /dev/null
@@ -0,0 +1,12 @@
+WebSocket: Send ArrayBuffers.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS PASS: Message #0.
+PASS PASS: Message #1.
+PASS PASS: Message #2.
+PASS closeEvent.wasClean is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/websocket/tests/hybi/send-arraybuffer.html b/LayoutTests/http/tests/websocket/tests/hybi/send-arraybuffer.html
new file mode 100644 (file)
index 0000000..20de553
--- /dev/null
@@ -0,0 +1,75 @@
+<!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: Send ArrayBuffers.");
+
+window.jsTestIsAsync = true;
+if (window.layoutTestController)
+    layoutTestController.overridePreference("WebKitHixie76WebSocketProtocolEnabled", 0);
+
+function startsWith(target, prefix)
+{
+    return target.indexOf(prefix) === 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 url = "ws://127.0.0.1:8880/websocket/tests/hybi/check-binary-messages";
+var ws = new WebSocket(url);
+var closeEvent;
+
+ws.onopen = function()
+{
+    ws.send(createArrayBufferContainingHelloWorld());
+    ws.send(createEmptyArrayBuffer());
+    ws.send(createArrayBufferContainingAllDistinctBytes());
+};
+
+ws.onmessage = function(event)
+{
+    var message = event.data;
+    if (startsWith(message, "PASS"))
+        testPassed(message);
+    else
+        testFailed(message);
+};
+
+ws.onclose = function(event)
+{
+    closeEvent = event;
+    shouldBeTrue("closeEvent.wasClean");
+    finishJSTest();
+};
+
+var successfullyParsed = true;
+</script>
+<script src="../../../../js-test-resources/js-test-post.js"></script>
+</body>
+</html>
index eab9346..b3c95f2 100644 (file)
@@ -42,7 +42,7 @@ function createBlobContainingAllDistinctBytes()
     return builder.getBlob();
 }
 
-var url = "ws://127.0.0.1:8880/websocket/tests/hybi/send-blob";
+var url = "ws://127.0.0.1:8880/websocket/tests/hybi/check-binary-messages";
 var ws = new WebSocket(url);
 var closeEvent;
 
diff --git a/LayoutTests/http/tests/websocket/tests/hybi/workers/resources/send-arraybuffer.js b/LayoutTests/http/tests/websocket/tests/hybi/workers/resources/send-arraybuffer.js
new file mode 100644 (file)
index 0000000..8aab9e8
--- /dev/null
@@ -0,0 +1,45 @@
+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 url = "ws://127.0.0.1:8880/websocket/tests/hybi/workers/resources/check-binary-messages";
+var ws = new WebSocket(url);
+
+ws.onopen = function()
+{
+    ws.send(createArrayBufferContainingHelloWorld());
+    ws.send(createEmptyArrayBuffer());
+    ws.send(createArrayBufferContainingAllDistinctBytes());
+};
+
+ws.onmessage = function(event)
+{
+    postMessage(event.data);
+};
+
+ws.onclose = function(closeEvent)
+{
+    if (closeEvent.wasClean === true)
+        postMessage("PASS: closeEvent.wasClean is true.");
+    else
+        postMessage("FAIL: closeEvent.wasClean should be true, but was: " + closeEvent.wasClean);
+    postMessage("DONE");
+};
index cea0503..c0120eb 100644 (file)
@@ -1,8 +1,3 @@
-function startsWith(target, prefix)
-{
-    return target.indexOf(prefix) === 0;
-}
-
 function createBlobContainingHelloWorld()
 {
     var builder = new WebKitBlobBuilder();
@@ -26,7 +21,7 @@ function createBlobContainingAllDistinctBytes()
     return builder.getBlob();
 }
 
-var url = "ws://127.0.0.1:8880/websocket/tests/hybi/workers/resources/send-blob";
+var url = "ws://127.0.0.1:8880/websocket/tests/hybi/workers/resources/check-binary-messages";
 var ws = new WebSocket(url);
 
 ws.onopen = function()
diff --git a/LayoutTests/http/tests/websocket/tests/hybi/workers/send-arraybuffer-expected.txt b/LayoutTests/http/tests/websocket/tests/hybi/workers/send-arraybuffer-expected.txt
new file mode 100644 (file)
index 0000000..5cb499c
--- /dev/null
@@ -0,0 +1,13 @@
+WebSocket: Send ArrayBuffers in Web Workers.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS PASS: Message #0.
+PASS PASS: Message #1.
+PASS PASS: Message #2.
+PASS PASS: closeEvent.wasClean is true.
+DONE
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/websocket/tests/hybi/workers/send-arraybuffer.html b/LayoutTests/http/tests/websocket/tests/hybi/workers/send-arraybuffer.html
new file mode 100644 (file)
index 0000000..ca36511
--- /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: Send 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/send-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>
index 3b6fa49..db2cea5 100644 (file)
@@ -1,3 +1,46 @@
+2011-09-03  Yuta Kitamura  <yutak@chromium.org>
+
+        WebSocket: Send ArrayBuffer as WebSocket binary message
+        https://bugs.webkit.org/show_bug.cgi?id=67477
+
+        Reviewed by Kent Tamura.
+
+        Tests: http/tests/websocket/tests/hybi/send-arraybuffer.html
+               http/tests/websocket/tests/hybi/workers/send-arraybuffer.html
+               http/tests/websocket/tests/hybi/bufferedAmount-after-close.html (updated)
+
+        * bindings/js/JSWebSocketCustom.cpp:
+        (WebCore::JSWebSocket::send):
+        * bindings/v8/custom/V8WebSocketCustom.cpp:
+        (WebCore::V8WebSocket::sendCallback):
+        * websockets/ThreadableWebSocketChannel.h:
+        * websockets/ThreadableWebSocketChannelClientWrapper.cpp:
+        (WebCore::ThreadableWebSocketChannelClientWrapper::ThreadableWebSocketChannelClientWrapper):
+        (WebCore::ThreadableWebSocketChannelClientWrapper::sendRequestResult):
+        (WebCore::ThreadableWebSocketChannelClientWrapper::setSendRequestResult):
+        * websockets/ThreadableWebSocketChannelClientWrapper.h:
+        Rename "sent" to "sendRequestResult" to clarify the meaning. Messages from the script may not
+        be sent immediately, thus the return value of WebSocketChannel::send() indicates whether the
+        message has been queued successfully, rather than whether the message has been sent or not.
+        * websockets/WebSocket.cpp:
+        (WebCore::WebSocket::send):
+        Case of sending "[object ArrayBuffer]" is covered by an existing test
+        http/tests/websocket/tests/{hybi,hixie76}/send-object.html.
+        * websockets/WebSocket.h:
+        * websockets/WebSocket.idl:
+        * websockets/WebSocketChannel.cpp:
+        (WebCore::WebSocketChannel::send):
+        * websockets/WebSocketChannel.h:
+        * websockets/WorkerThreadableWebSocketChannel.cpp:
+        (WebCore::WorkerThreadableWebSocketChannel::send):
+        (WebCore::workerContextDidSend):
+        (WebCore::WorkerThreadableWebSocketChannel::Peer::send):
+        (WebCore::WorkerThreadableWebSocketChannel::mainThreadSendArrayBuffer):
+        Construct an ArrayBuffer from the data on Vector<char>.
+        (WebCore::WorkerThreadableWebSocketChannel::Bridge::send):
+        Copy the content into temporary buffer of Vector<char>, and send it to the main thread.
+        * websockets/WorkerThreadableWebSocketChannel.h:
+
 2011-09-02  Kentaro Hara  <haraken@google.com>
 
         Implement a CustomEvent constructor for V8
index 4f92f40..49a828c 100644 (file)
@@ -36,6 +36,7 @@
 #include "JSWebSocket.h"
 
 #include "ExceptionCode.h"
+#include "JSArrayBuffer.h"
 #include "JSBlob.h"
 #include "JSEventListener.h"
 #include "KURL.h"
@@ -97,7 +98,9 @@ JSValue JSWebSocket::send(ExecState* exec)
     JSValue message = exec->argument(0);
     ExceptionCode ec = 0;
     bool result;
-    if (message.inherits(&JSBlob::s_info))
+    if (message.inherits(&JSArrayBuffer::s_info))
+        result = impl()->send(toArrayBuffer(message), ec);
+    else if (message.inherits(&JSBlob::s_info))
         result = impl()->send(toBlob(message), ec);
     else {
         String stringMessage = ustringToString(message.toString(exec));
index d237047..2ee116e 100644 (file)
@@ -37,6 +37,7 @@
 #include "ExceptionCode.h"
 #include "Frame.h"
 #include "Settings.h"
+#include "V8ArrayBuffer.h"
 #include "V8Binding.h"
 #include "V8Blob.h"
 #include "V8Proxy.h"
@@ -123,7 +124,11 @@ v8::Handle<v8::Value> V8WebSocket::sendCallback(const v8::Arguments& args)
     v8::Handle<v8::Value> message = args[0];
     ExceptionCode ec = 0;
     bool result;
-    if (V8Blob::HasInstance(message)) {
+    if (V8ArrayBuffer::HasInstance(message)) {
+        ArrayBuffer* arrayBuffer = V8ArrayBuffer::toNative(v8::Handle<v8::Object>::Cast(message));
+        ASSERT(arrayBuffer);
+        result = webSocket->send(arrayBuffer, ec);
+    } else if (V8Blob::HasInstance(message)) {
         Blob* blob = V8Blob::toNative(v8::Handle<v8::Object>::Cast(message));
         ASSERT(blob);
         result = webSocket->send(blob, ec);
index ca0b372..7a1f297 100644 (file)
@@ -39,6 +39,7 @@
 
 namespace WebCore {
 
+class ArrayBuffer;
 class Blob;
 class KURL;
 class ScriptExecutionContext;
@@ -54,6 +55,7 @@ public:
     virtual void connect(const KURL&, const String& protocol) = 0;
     virtual String subprotocol() = 0; // Will be available after didConnect() callback is invoked.
     virtual bool send(const String& message) = 0;
+    virtual bool send(const ArrayBuffer&) = 0;
     virtual bool send(const Blob&) = 0;
     virtual unsigned long bufferedAmount() const = 0;
     virtual void close(int code, const String& reason) = 0;
index d1b9729..2eecc69 100644 (file)
@@ -45,7 +45,7 @@ ThreadableWebSocketChannelClientWrapper::ThreadableWebSocketChannelClientWrapper
     , m_syncMethodDone(false)
     , m_useHixie76Protocol(true)
     , m_subprotocol("")
-    , m_sent(false)
+    , m_sendRequestResult(false)
     , m_bufferedAmount(0)
     , m_suspended(false)
 {
@@ -91,14 +91,14 @@ void ThreadableWebSocketChannelClientWrapper::setSubprotocol(const String& subpr
     m_subprotocol = subprotocol;
 }
 
-bool ThreadableWebSocketChannelClientWrapper::sent() const
+bool ThreadableWebSocketChannelClientWrapper::sendRequestResult() const
 {
-    return m_sent;
+    return m_sendRequestResult;
 }
 
-void ThreadableWebSocketChannelClientWrapper::setSent(bool sent)
+void ThreadableWebSocketChannelClientWrapper::setSendRequestResult(bool sendRequestResult)
 {
-    m_sent = sent;
+    m_sendRequestResult = sendRequestResult;
     m_syncMethodDone = true;
 }
 
index 8917f83..dd3e6a7 100644 (file)
@@ -63,8 +63,8 @@ public:
     String subprotocol() const;
     void setSubprotocol(const String&);
 
-    bool sent() const;
-    void setSent(bool);
+    bool sendRequestResult() const;
+    void setSendRequestResult(bool);
 
     unsigned long bufferedAmount() const;
     void setBufferedAmount(unsigned long);
@@ -94,7 +94,7 @@ protected:
     bool m_syncMethodDone;
     bool m_useHixie76Protocol;
     String m_subprotocol;
-    bool m_sent;
+    bool m_sendRequestResult;
     unsigned long m_bufferedAmount;
     bool m_suspended;
     Vector<OwnPtr<ScriptExecutionContext::Task> > m_pendingTasks;
index f3b1845..10edd51 100644 (file)
@@ -265,6 +265,24 @@ bool WebSocket::send(const String& message, ExceptionCode& ec)
     return m_channel->send(message);
 }
 
+bool WebSocket::send(ArrayBuffer* binaryData, ExceptionCode& ec)
+{
+    LOG(Network, "WebSocket %p send arraybuffer %p", this, binaryData);
+    ASSERT(binaryData);
+    if (m_useHixie76Protocol)
+        return send("[object ArrayBuffer]", ec);
+    if (m_state == CONNECTING) {
+        ec = INVALID_STATE_ERR;
+        return false;
+    }
+    if (m_state == CLOSING || m_state == CLOSED) {
+        m_bufferedAmountAfterClose += binaryData->byteLength() + getFramingOverhead(binaryData->byteLength());
+        return false;
+    }
+    ASSERT(m_channel);
+    return m_channel->send(*binaryData);
+}
+
 bool WebSocket::send(Blob* binaryData, ExceptionCode& ec)
 {
     LOG(Network, "WebSocket %p send blob %s", this, binaryData->url().string().utf8().data());
index cbb8d60..c621e3d 100644 (file)
@@ -46,6 +46,7 @@
 
 namespace WebCore {
 
+class ArrayBuffer;
 class Blob;
 class ThreadableWebSocketChannel;
 
@@ -68,6 +69,7 @@ public:
     void connect(const String& url, const Vector<String>& protocols, ExceptionCode&);
 
     bool send(const String& message, ExceptionCode&);
+    bool send(ArrayBuffer*, ExceptionCode&);
     bool send(Blob*, ExceptionCode&);
 
     void close(int code, const String& reason, ExceptionCode&);
index 0dc23e7..df20ba6 100644 (file)
@@ -66,8 +66,9 @@ module websockets {
         // FIXME: Use overloading provided by our IDL code generator.
         // According to Web IDL specification, overloaded function with DOMString argument
         // should accept anything that can be converted to a string (including numbers,
-        // booleans, null, undefined and objects except Blob). Current code generator does
-        // not handle this rule correctly.
+        // booleans, null, undefined and objects except ArrayBuffer and Blob). Current code
+        // generator does not handle this rule correctly.
+        // [RequiresAllArguments] boolean send(in ArrayBuffer data) raises(DOMException);
         // [RequiresAllArguments] boolean send(in Blob data) raises(DOMException);
         // [RequiresAllArguments] boolean send(in DOMString data) raises(DOMException);
         [Custom] boolean send(in DOMString data) raises(DOMException);
index ae5c1ac..c1135b5 100644 (file)
@@ -170,6 +170,14 @@ bool WebSocketChannel::send(const String& message)
     return true;
 }
 
+bool WebSocketChannel::send(const ArrayBuffer& binaryData)
+{
+    LOG(Network, "WebSocketChannel %p send arraybuffer %p", this, &binaryData);
+    ASSERT(!m_useHixie76Protocol);
+    enqueueRawFrame(OpCodeBinary, static_cast<const char*>(binaryData.data()), binaryData.byteLength());
+    return true;
+}
+
 bool WebSocketChannel::send(const Blob& binaryData)
 {
     LOG(Network, "WebSocketChannel %p send blob %s", this, binaryData.url().string().utf8().data());
index 3e89e85..897ef60 100644 (file)
@@ -45,6 +45,7 @@
 
 namespace WebCore {
 
+class ArrayBuffer;
 class Blob;
 class FileReaderLoader;
 class ScriptExecutionContext;
@@ -66,6 +67,7 @@ public:
     virtual void connect(const KURL&, const String& protocol);
     virtual String subprotocol();
     virtual bool send(const String& message);
+    virtual bool send(const ArrayBuffer&);
     virtual bool send(const Blob&);
     virtual unsigned long bufferedAmount() const;
     virtual void close(int code, const String& reason); // Start closing handshake.
index 604645a..921bd74 100644 (file)
@@ -34,6 +34,7 @@
 
 #include "WorkerThreadableWebSocketChannel.h"
 
+#include "ArrayBuffer.h"
 #include "Blob.h"
 #include "CrossThreadTask.h"
 #include "PlatformString.h"
@@ -88,6 +89,13 @@ bool WorkerThreadableWebSocketChannel::send(const String& message)
     return m_bridge->send(message);
 }
 
+bool WorkerThreadableWebSocketChannel::send(const ArrayBuffer& binaryData)
+{
+    if (!m_bridge)
+        return false;
+    return m_bridge->send(binaryData);
+}
+
 bool WorkerThreadableWebSocketChannel::send(const Blob& binaryData)
 {
     if (!m_bridge)
@@ -165,10 +173,10 @@ void WorkerThreadableWebSocketChannel::Peer::connect(const KURL& url, const Stri
     m_mainWebSocketChannel->connect(url, protocol);
 }
 
-static void workerContextDidSend(ScriptExecutionContext* context, PassRefPtr<ThreadableWebSocketChannelClientWrapper> workerClientWrapper, bool sent)
+static void workerContextDidSend(ScriptExecutionContext* context, PassRefPtr<ThreadableWebSocketChannelClientWrapper> workerClientWrapper, bool sendRequestResult)
 {
     ASSERT_UNUSED(context, context->isWorkerContext());
-    workerClientWrapper->setSent(sent);
+    workerClientWrapper->setSendRequestResult(sendRequestResult);
 }
 
 void WorkerThreadableWebSocketChannel::Peer::send(const String& message)
@@ -176,8 +184,17 @@ void WorkerThreadableWebSocketChannel::Peer::send(const String& message)
     ASSERT(isMainThread());
     if (!m_mainWebSocketChannel || !m_workerClientWrapper)
         return;
-    bool sent = m_mainWebSocketChannel->send(message);
-    m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&workerContextDidSend, m_workerClientWrapper, sent), m_taskMode);
+    bool sendRequestResult = m_mainWebSocketChannel->send(message);
+    m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&workerContextDidSend, m_workerClientWrapper, sendRequestResult), m_taskMode);
+}
+
+void WorkerThreadableWebSocketChannel::Peer::send(const ArrayBuffer& binaryData)
+{
+    ASSERT(isMainThread());
+    if (!m_mainWebSocketChannel || !m_workerClientWrapper)
+        return;
+    bool sendRequestResult = m_mainWebSocketChannel->send(binaryData);
+    m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&workerContextDidSend, m_workerClientWrapper, sendRequestResult), m_taskMode);
 }
 
 void WorkerThreadableWebSocketChannel::Peer::send(const Blob& binaryData)
@@ -185,8 +202,8 @@ void WorkerThreadableWebSocketChannel::Peer::send(const Blob& binaryData)
     ASSERT(isMainThread());
     if (!m_mainWebSocketChannel || !m_workerClientWrapper)
         return;
-    bool sent = m_mainWebSocketChannel->send(binaryData);
-    m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&workerContextDidSend, m_workerClientWrapper, sent), m_taskMode);
+    bool sendRequestResult = m_mainWebSocketChannel->send(binaryData);
+    m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&workerContextDidSend, m_workerClientWrapper, sendRequestResult), m_taskMode);
 }
 
 static void workerContextDidGetBufferedAmount(ScriptExecutionContext* context, PassRefPtr<ThreadableWebSocketChannelClientWrapper> workerClientWrapper, unsigned long bufferedAmount)
@@ -375,6 +392,16 @@ void WorkerThreadableWebSocketChannel::mainThreadSend(ScriptExecutionContext* co
     peer->send(message);
 }
 
+void WorkerThreadableWebSocketChannel::mainThreadSendArrayBuffer(ScriptExecutionContext* context, Peer* peer, PassOwnPtr<Vector<char> > data)
+{
+    ASSERT(isMainThread());
+    ASSERT_UNUSED(context, context->isDocument());
+    ASSERT(peer);
+
+    RefPtr<ArrayBuffer> arrayBuffer = ArrayBuffer::create(data->data(), data->size());
+    peer->send(*arrayBuffer);
+}
+
 void WorkerThreadableWebSocketChannel::mainThreadSendBlob(ScriptExecutionContext* context, Peer* peer, const KURL& url, const String& type, long long size)
 {
     ASSERT(isMainThread());
@@ -395,7 +422,24 @@ bool WorkerThreadableWebSocketChannel::Bridge::send(const String& message)
     RefPtr<Bridge> protect(this);
     waitForMethodCompletion();
     ThreadableWebSocketChannelClientWrapper* clientWrapper = m_workerClientWrapper.get();
-    return clientWrapper && clientWrapper->sent();
+    return clientWrapper && clientWrapper->sendRequestResult();
+}
+
+bool WorkerThreadableWebSocketChannel::Bridge::send(const ArrayBuffer& binaryData)
+{
+    if (!m_workerClientWrapper)
+        return false;
+    ASSERT(m_peer);
+    // ArrayBuffer isn't thread-safe, hence the content of ArrayBuffer is copied into Vector<char>.
+    OwnPtr<Vector<char> > data = adoptPtr(new Vector<char>(binaryData.byteLength()));
+    if (binaryData.byteLength())
+        memcpy(data->data(), binaryData.data(), binaryData.byteLength());
+    setMethodNotCompleted();
+    m_loaderProxy.postTaskToLoader(createCallbackTask(&WorkerThreadableWebSocketChannel::mainThreadSendArrayBuffer, AllowCrossThreadAccess(m_peer), data.release()));
+    RefPtr<Bridge> protect(this);
+    waitForMethodCompletion();
+    ThreadableWebSocketChannelClientWrapper* clientWrapper = m_workerClientWrapper.get();
+    return clientWrapper && clientWrapper->sendRequestResult();
 }
 
 bool WorkerThreadableWebSocketChannel::Bridge::send(const Blob& binaryData)
@@ -408,7 +452,7 @@ bool WorkerThreadableWebSocketChannel::Bridge::send(const Blob& binaryData)
     RefPtr<Bridge> protect(this);
     waitForMethodCompletion();
     ThreadableWebSocketChannelClientWrapper* clientWrapper = m_workerClientWrapper.get();
-    return clientWrapper && clientWrapper->sent();
+    return clientWrapper && clientWrapper->sendRequestResult();
 }
 
 void WorkerThreadableWebSocketChannel::mainThreadBufferedAmount(ScriptExecutionContext* context, Peer* peer)
index 7e2ec1b..4d9aa89 100644 (file)
@@ -64,6 +64,7 @@ public:
     virtual void connect(const KURL&, const String& protocol);
     virtual String subprotocol();
     virtual bool send(const String& message);
+    virtual bool send(const ArrayBuffer&);
     virtual bool send(const Blob&);
     virtual unsigned long bufferedAmount() const;
     virtual void close(int code, const String& reason);
@@ -94,6 +95,7 @@ private:
         bool useHixie76Protocol();
         void connect(const KURL&, const String& protocol);
         void send(const String& message);
+        void send(const ArrayBuffer&);
         void send(const Blob&);
         void bufferedAmount();
         void close(int code, const String& reason);
@@ -127,6 +129,7 @@ private:
         ~Bridge();
         void connect(const KURL&, const String& protocol);
         bool send(const String& message);
+        bool send(const ArrayBuffer&);
         bool send(const Blob&);
         unsigned long bufferedAmount();
         void close(int code, const String& reason);
@@ -163,6 +166,7 @@ private:
 
     static void mainThreadConnect(ScriptExecutionContext*, Peer*, const KURL&, const String& protocol);
     static void mainThreadSend(ScriptExecutionContext*, Peer*, const String& message);
+    static void mainThreadSendArrayBuffer(ScriptExecutionContext*, Peer*, PassOwnPtr<Vector<char> >);
     static void mainThreadSendBlob(ScriptExecutionContext*, Peer*, const KURL&, const String& type, long long size);
     static void mainThreadBufferedAmount(ScriptExecutionContext*, Peer*);
     static void mainThreadClose(ScriptExecutionContext*, Peer*, int code, const String& reason);