WebSocket: Send Blob as WebSocket binary message
authoryutak@chromium.org <yutak@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 2 Sep 2011 11:16:40 +0000 (11:16 +0000)
committeryutak@chromium.org <yutak@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 2 Sep 2011 11:16:40 +0000 (11:16 +0000)
https://bugs.webkit.org/show_bug.cgi?id=67465

Reviewed by Kent Tamura.

Re-lands r94399 with a fix for Leopard builds.

Source/WebCore:

* bindings/js/JSWebSocketCustom.cpp:
(WebCore::JSWebSocket::send):
* bindings/v8/custom/V8WebSocketCustom.cpp:
(WebCore::V8WebSocket::sendCallback):
* websockets/ThreadableWebSocketChannel.h:
* websockets/WebSocket.cpp:
(WebCore::WebSocket::send):
* websockets/WebSocket.h:
* websockets/WebSocket.idl:
* websockets/WebSocketChannel.cpp:
(WebCore::WebSocketChannel::send):
* websockets/WebSocketChannel.h:
* websockets/WorkerThreadableWebSocketChannel.cpp:
(WebCore::WorkerThreadableWebSocketChannel::send):
(WebCore::WorkerThreadableWebSocketChannel::Peer::send):
(WebCore::WorkerThreadableWebSocketChannel::mainThreadSendBlob):
(WebCore::WorkerThreadableWebSocketChannel::Bridge::send):
* websockets/WorkerThreadableWebSocketChannel.h:

LayoutTests:

* http/tests/websocket/tests/hixie76/send-empty-expected.txt: Added.
* http/tests/websocket/tests/hixie76/send-empty.html: Added.
* http/tests/websocket/tests/hixie76/send-object-expected.txt: Added.
* http/tests/websocket/tests/hixie76/send-object.html: Added.
* http/tests/websocket/tests/hybi/bufferedAmount-after-close-expected.txt:
* http/tests/websocket/tests/hybi/bufferedAmount-after-close.html:
* http/tests/websocket/tests/hybi/send-blob-expected.txt: Added.
* http/tests/websocket/tests/hybi/send-blob.html: Added.
* http/tests/websocket/tests/hybi/send-blob_wsh.py: Added.
* http/tests/websocket/tests/hybi/send-empty-expected.txt: Added.
* http/tests/websocket/tests/hybi/send-empty.html: Added.
* http/tests/websocket/tests/hybi/send-file-blob-expected.txt: Added.
* http/tests/websocket/tests/hybi/send-file-blob-fail-expected.txt: Added.
* http/tests/websocket/tests/hybi/send-file-blob-fail.html: Added.
* http/tests/websocket/tests/hybi/send-file-blob.html: Added.
* http/tests/websocket/tests/hybi/send-file-blob_wsh.py: Added.
* http/tests/websocket/tests/hybi/workers/resources/send-blob.js: Added.
* http/tests/websocket/tests/hybi/workers/resources/send-blob_wsh.py: Added.
* http/tests/websocket/tests/hybi/workers/send-blob-expected.txt: Added.
* http/tests/websocket/tests/hybi/workers/send-blob.html: Added.
* platform/gtk/Skipped:
* platform/mac/Skipped:
* platform/qt/Skipped:
* platform/win/Skipped:

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

36 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/websocket/tests/hixie76/send-empty-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/websocket/tests/hixie76/send-empty.html [new file with mode: 0644]
LayoutTests/http/tests/websocket/tests/hixie76/send-object-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/websocket/tests/hixie76/send-object.html [new file with mode: 0644]
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/send-blob-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/websocket/tests/hybi/send-blob.html [new file with mode: 0644]
LayoutTests/http/tests/websocket/tests/hybi/send-blob_wsh.py [new file with mode: 0644]
LayoutTests/http/tests/websocket/tests/hybi/send-empty-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/websocket/tests/hybi/send-empty.html [new file with mode: 0644]
LayoutTests/http/tests/websocket/tests/hybi/send-file-blob-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/websocket/tests/hybi/send-file-blob-fail-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/websocket/tests/hybi/send-file-blob-fail.html [new file with mode: 0644]
LayoutTests/http/tests/websocket/tests/hybi/send-file-blob.html [new file with mode: 0644]
LayoutTests/http/tests/websocket/tests/hybi/send-file-blob_wsh.py [new file with mode: 0644]
LayoutTests/http/tests/websocket/tests/hybi/workers/resources/send-blob.js [new file with mode: 0644]
LayoutTests/http/tests/websocket/tests/hybi/workers/resources/send-blob_wsh.py [new file with mode: 0644]
LayoutTests/http/tests/websocket/tests/hybi/workers/send-blob-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/websocket/tests/hybi/workers/send-blob.html [new file with mode: 0644]
LayoutTests/platform/gtk/Skipped
LayoutTests/platform/mac/Skipped
LayoutTests/platform/qt/Skipped
LayoutTests/platform/win/Skipped
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/JSWebSocketCustom.cpp
Source/WebCore/bindings/v8/custom/V8WebSocketCustom.cpp
Source/WebCore/websockets/ThreadableWebSocketChannel.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 faa0122..9d1964b 100644 (file)
@@ -1,3 +1,37 @@
+2011-09-02  Yuta Kitamura  <yutak@chromium.org>
+
+        WebSocket: Send Blob as WebSocket binary message
+        https://bugs.webkit.org/show_bug.cgi?id=67465
+
+        Reviewed by Kent Tamura.
+
+        Re-lands r94399 with a fix for Leopard builds.
+
+        * http/tests/websocket/tests/hixie76/send-empty-expected.txt: Added.
+        * http/tests/websocket/tests/hixie76/send-empty.html: Added.
+        * http/tests/websocket/tests/hixie76/send-object-expected.txt: Added.
+        * http/tests/websocket/tests/hixie76/send-object.html: Added.
+        * http/tests/websocket/tests/hybi/bufferedAmount-after-close-expected.txt:
+        * http/tests/websocket/tests/hybi/bufferedAmount-after-close.html:
+        * http/tests/websocket/tests/hybi/send-blob-expected.txt: Added.
+        * http/tests/websocket/tests/hybi/send-blob.html: Added.
+        * http/tests/websocket/tests/hybi/send-blob_wsh.py: Added.
+        * http/tests/websocket/tests/hybi/send-empty-expected.txt: Added.
+        * http/tests/websocket/tests/hybi/send-empty.html: Added.
+        * http/tests/websocket/tests/hybi/send-file-blob-expected.txt: Added.
+        * http/tests/websocket/tests/hybi/send-file-blob-fail-expected.txt: Added.
+        * http/tests/websocket/tests/hybi/send-file-blob-fail.html: Added.
+        * http/tests/websocket/tests/hybi/send-file-blob.html: Added.
+        * http/tests/websocket/tests/hybi/send-file-blob_wsh.py: Added.
+        * http/tests/websocket/tests/hybi/workers/resources/send-blob.js: Added.
+        * http/tests/websocket/tests/hybi/workers/resources/send-blob_wsh.py: Added.
+        * http/tests/websocket/tests/hybi/workers/send-blob-expected.txt: Added.
+        * http/tests/websocket/tests/hybi/workers/send-blob.html: Added.
+        * platform/gtk/Skipped:
+        * platform/mac/Skipped:
+        * platform/qt/Skipped:
+        * platform/win/Skipped:
+
 2011-09-02  Kenichi Ishibashi  <bashi@chromium.org>
 
         [chromium] editing/selection/regional-indicators.html timing out on Linux
diff --git a/LayoutTests/http/tests/websocket/tests/hixie76/send-empty-expected.txt b/LayoutTests/http/tests/websocket/tests/hixie76/send-empty-expected.txt
new file mode 100644 (file)
index 0000000..0c70f1f
--- /dev/null
@@ -0,0 +1,12 @@
+WebSocket: Calling send() without arguments should raise SyntaxError.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS ws.send() threw exception SyntaxError: Not enough arguments.
+PASS closeEvent.wasClean is true
+PASS receivedMessages.length is 1
+PASS receivedMessages[0] is "Goodbye"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/websocket/tests/hixie76/send-empty.html b/LayoutTests/http/tests/websocket/tests/hixie76/send-empty.html
new file mode 100644 (file)
index 0000000..fc63763
--- /dev/null
@@ -0,0 +1,47 @@
+<!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: Calling send() without arguments should raise SyntaxError.");
+
+window.jsTestIsAsync = true;
+
+var ws = new WebSocket("ws://127.0.0.1:8880/websocket/tests/hixie76/echo");
+
+var closeEvent;
+var receivedMessages = [];
+var expectedMessages = ["Goodbye"];
+
+ws.onopen = function()
+{
+    shouldThrow("ws.send()");
+    ws.send("Goodbye");
+};
+
+ws.onmessage = function(event)
+{
+    receivedMessages.push(event.data);
+};
+
+ws.onclose = function(event)
+{
+    closeEvent = event;
+    shouldBeTrue("closeEvent.wasClean");
+
+    shouldEvaluateTo("receivedMessages.length", expectedMessages.length);
+    for (var i = 0; i < expectedMessages.length; ++i)
+        shouldBeEqualToString("receivedMessages[" + i + "]", expectedMessages[i]);
+    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/hixie76/send-object-expected.txt b/LayoutTests/http/tests/websocket/tests/hixie76/send-object-expected.txt
new file mode 100644 (file)
index 0000000..ac9b2ca
--- /dev/null
@@ -0,0 +1,14 @@
+WebSocket: send(object) should be interpreted as send(object.toString()).
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS closeEvent.wasClean is true
+PASS receivedMessages.length is 4
+PASS receivedMessages[0] is "[object Object]"
+PASS receivedMessages[1] is "[object ArrayBuffer]"
+PASS receivedMessages[2] is "[object Blob]"
+PASS receivedMessages[3] is "Goodbye"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/websocket/tests/hixie76/send-object.html b/LayoutTests/http/tests/websocket/tests/hixie76/send-object.html
new file mode 100644 (file)
index 0000000..ca31713
--- /dev/null
@@ -0,0 +1,55 @@
+<!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: send(object) should be interpreted as send(object.toString()).");
+
+window.jsTestIsAsync = true;
+
+function createEmptyBlob()
+{
+    var builder = new WebKitBlobBuilder();
+    return builder.getBlob();
+}
+
+var ws = new WebSocket("ws://127.0.0.1:8880/websocket/tests/hixie76/echo");
+
+var closeEvent;
+var receivedMessages = [];
+var expectedMessages = ["[object Object]", "[object ArrayBuffer]", "[object Blob]", "Goodbye"];
+
+ws.onopen = function()
+{
+    ws.send({});
+    ws.send(new ArrayBuffer());
+    ws.send(createEmptyBlob());
+    ws.send("Goodbye");
+};
+
+ws.onmessage = function(event)
+{
+    receivedMessages.push(event.data);
+};
+
+ws.onclose = function(event)
+{
+    closeEvent = event;
+    shouldBeTrue("closeEvent.wasClean");
+
+    shouldEvaluateTo("receivedMessages.length", expectedMessages.length);
+    for (var i = 0; i < expectedMessages.length; ++i)
+        shouldBeEqualToString("receivedMessages[" + i + "]", expectedMessages[i]);
+    finishJSTest();
+};
+
+var successfullyParsed = true;
+</script>
+<script src="../../../../js-test-resources/js-test-post.js"></script>
+</body>
+</html>
index e729807..7c6d55e 100644 (file)
@@ -6,6 +6,7 @@ Connected.
 Closed.
 PASS ws.readyState is 3
 PASS ws.bufferedAmount is 0
+Testing send(string)...
 PASS ws.send(messageToSend) is false
 PASS bufferedAmountDifference is 27
 PASS ws.send(messageToSend) is false
@@ -20,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(Blob)...
+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
 PASS successfullyParsed is true
 
 TEST COMPLETE
index 16a6a4b..c6b2604 100644 (file)
@@ -22,6 +22,13 @@ function createStringWithLength(length)
     return string.substring(0, length);
 }
 
+function createBlobWithLength(length)
+{
+    var builder = new WebKitBlobBuilder();
+    builder.append(new ArrayBuffer(length));
+    return builder.getBlob();
+}
+
 var ws = new WebSocket("ws://localhost:8880/websocket/tests/hybi/simple");
 
 ws.onopen = function()
@@ -37,6 +44,7 @@ ws.onclose = function()
     shouldBe("ws.bufferedAmount", "0");
 
     var baseOverhead = 2 + 4; // Base header size and masking key size.
+    debug("Testing send(string)...");
     testBufferedAmount('send to closed socket', 21 + baseOverhead);
     testBufferedAmount('', baseOverhead);
     testBufferedAmount('a', 1 + baseOverhead);
@@ -45,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(Blob)...");
+    testBufferedAmount(createBlobWithLength(0), baseOverhead);
+    testBufferedAmount(createBlobWithLength(1), 1 + baseOverhead);
+    testBufferedAmount(createBlobWithLength(125), 125 + baseOverhead);
+    testBufferedAmount(createBlobWithLength(126), 126 + baseOverhead + 2);
+    testBufferedAmount(createBlobWithLength(0xFFFF), 0xFFFF + baseOverhead + 2);
+    testBufferedAmount(createBlobWithLength(0x10000), 0x10000 + baseOverhead + 8);
+
     finishJSTest();
 };
 
diff --git a/LayoutTests/http/tests/websocket/tests/hybi/send-blob-expected.txt b/LayoutTests/http/tests/websocket/tests/hybi/send-blob-expected.txt
new file mode 100644 (file)
index 0000000..fdf48d0
--- /dev/null
@@ -0,0 +1,12 @@
+WebSocket: Send Blobs.
+
+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-blob.html b/LayoutTests/http/tests/websocket/tests/hybi/send-blob.html
new file mode 100644 (file)
index 0000000..eab9346
--- /dev/null
@@ -0,0 +1,76 @@
+<!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 Blobs.");
+
+window.jsTestIsAsync = true;
+if (window.layoutTestController)
+    layoutTestController.overridePreference("WebKitHixie76WebSocketProtocolEnabled", 0);
+
+function startsWith(target, prefix)
+{
+    return target.indexOf(prefix) === 0;
+}
+
+function createBlobContainingHelloWorld()
+{
+    var builder = new WebKitBlobBuilder();
+    builder.append("Hello, world!");
+    return builder.getBlob();
+}
+
+function createEmptyBlob()
+{
+    var builder = new WebKitBlobBuilder();
+    return builder.getBlob();
+}
+
+function createBlobContainingAllDistinctBytes()
+{
+    var array = new Uint8Array(256);
+    for (var i = 0; i < 256; ++i)
+        array[i] = i;
+    var builder = new WebKitBlobBuilder();
+    builder.append(array.buffer);
+    return builder.getBlob();
+}
+
+var url = "ws://127.0.0.1:8880/websocket/tests/hybi/send-blob";
+var ws = new WebSocket(url);
+var closeEvent;
+
+ws.onopen = function()
+{
+    ws.send(createBlobContainingHelloWorld());
+    ws.send(createEmptyBlob());
+    ws.send(createBlobContainingAllDistinctBytes());
+};
+
+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>
diff --git a/LayoutTests/http/tests/websocket/tests/hybi/send-blob_wsh.py b/LayoutTests/http/tests/websocket/tests/hybi/send-blob_wsh.py
new file mode 100644 (file)
index 0000000..024e3f4
--- /dev/null
@@ -0,0 +1,21 @@
+from mod_pywebsocket import common
+from mod_pywebsocket import msgutil
+
+
+def web_socket_do_extra_handshake(request):
+    pass # Always accept.
+
+
+def web_socket_transfer_data(request):
+    expected_messages = ['Hello, world!', '', all_distinct_bytes()]
+
+    for test_number, expected_message in enumerate(expected_messages):
+        message = msgutil.receive_message(request)
+        if type(message) == str and message == expected_message:
+            msgutil.send_message(request, 'PASS: Message #%d.' % test_number)
+        else:
+            msgutil.send_message(request, 'FAIL: Message #%d: Received unexpected message: %r' % (test_number, message))
+
+
+def all_distinct_bytes():
+    return ''.join([chr(i) for i in xrange(256)])
diff --git a/LayoutTests/http/tests/websocket/tests/hybi/send-empty-expected.txt b/LayoutTests/http/tests/websocket/tests/hybi/send-empty-expected.txt
new file mode 100644 (file)
index 0000000..0c70f1f
--- /dev/null
@@ -0,0 +1,12 @@
+WebSocket: Calling send() without arguments should raise SyntaxError.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS ws.send() threw exception SyntaxError: Not enough arguments.
+PASS closeEvent.wasClean is true
+PASS receivedMessages.length is 1
+PASS receivedMessages[0] is "Goodbye"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/websocket/tests/hybi/send-empty.html b/LayoutTests/http/tests/websocket/tests/hybi/send-empty.html
new file mode 100644 (file)
index 0000000..c8c8996
--- /dev/null
@@ -0,0 +1,49 @@
+<!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: Calling send() without arguments should raise SyntaxError.");
+
+window.jsTestIsAsync = true;
+if (window.layoutTestController)
+    layoutTestController.overridePreference("WebKitHixie76WebSocketProtocolEnabled", 0);
+
+var ws = new WebSocket("ws://127.0.0.1:8880/websocket/tests/hybi/echo");
+
+var closeEvent;
+var receivedMessages = [];
+var expectedMessages = ["Goodbye"];
+
+ws.onopen = function()
+{
+    shouldThrow("ws.send()");
+    ws.send("Goodbye");
+};
+
+ws.onmessage = function(event)
+{
+    receivedMessages.push(event.data);
+};
+
+ws.onclose = function(event)
+{
+    closeEvent = event;
+    shouldBeTrue("closeEvent.wasClean");
+
+    shouldEvaluateTo("receivedMessages.length", expectedMessages.length);
+    for (var i = 0; i < expectedMessages.length; ++i)
+        shouldBeEqualToString("receivedMessages[" + i + "]", expectedMessages[i]);
+    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/send-file-blob-expected.txt b/LayoutTests/http/tests/websocket/tests/hybi/send-file-blob-expected.txt
new file mode 100644 (file)
index 0000000..51649ce
--- /dev/null
@@ -0,0 +1,16 @@
+WebSocket: Send a File.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+Got FileSystem object.
+File created.
+PASS fileEntry.isFile is true
+Wrote to file.
+Got File object.
+PASS PASS: Message #0.
+PASS closeEvent.wasClean is true
+Deleting the file.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/websocket/tests/hybi/send-file-blob-fail-expected.txt b/LayoutTests/http/tests/websocket/tests/hybi/send-file-blob-fail-expected.txt
new file mode 100644 (file)
index 0000000..9d718f9
--- /dev/null
@@ -0,0 +1,16 @@
+CONSOLE MESSAGE: line 0: Failed to load Blob: error code = 1
+WebSocket should fail the connection if it has failed to read a Blob.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+Got FileSystem object.
+File created.
+PASS fileEntry.isFile is true
+Wrote to file.
+Got File object.
+File deleted.
+PASS closeEvent.wasClean is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/websocket/tests/hybi/send-file-blob-fail.html b/LayoutTests/http/tests/websocket/tests/hybi/send-file-blob-fail.html
new file mode 100644 (file)
index 0000000..92626d8
--- /dev/null
@@ -0,0 +1,126 @@
+<!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 should fail the connection if it has failed to read a Blob.");
+
+window.jsTestIsAsync = true;
+if (window.layoutTestController)
+    layoutTestController.overridePreference("WebKitHixie76WebSocketProtocolEnabled", 0);
+
+function startsWith(target, prefix)
+{
+    return target.indexOf(prefix) === 0;
+}
+
+var fileSystemSize = 1024;
+var fileName = "websocket-send-file-blob-fail.txt";
+var messageToWrite = "This message shouldn't be sent.";
+
+function runTest()
+{
+    if (!window.webkitRequestFileSystem) {
+        testFailed("window.webkitRequestFileSystem is not available.");
+        finishJSTest();
+        return;
+    }
+
+    webkitRequestFileSystem(TEMPORARY, fileSystemSize, didGetFileSystem, didFail);
+}
+
+function didGetFileSystem(fileSystem)
+{
+    debug("Got FileSystem object.");
+    fileSystem.root.getFile(fileName, {create: true}, didCreateFile, didFail);
+}
+
+var fileEntry;
+
+function didCreateFile(entry)
+{
+    debug("File created.");
+    fileEntry = entry;
+    shouldBeTrue("fileEntry.isFile");
+    fileEntry.createWriter(didGetFileWriter, didFail);
+}
+
+function didGetFileWriter(writer)
+{
+    writer.truncate(0);
+    writer.onerror = function()
+    {
+        testFailed("FileWriter operation failed.");
+        endTest();
+    };
+    writer.onwrite = function()
+    {
+        var builder = new WebKitBlobBuilder();
+        builder.append(messageToWrite);
+        writer.write(builder.getBlob());
+        writer.onwrite = didWriteFile;
+    };
+}
+
+function didWriteFile()
+{
+    debug("Wrote to file.");
+    fileEntry.file(didGetFile, didFail);
+}
+
+var fileObject;
+
+function didGetFile(file)
+{
+    debug("Got File object.");
+    fileObject = file;
+
+    // Delete the file object before it is read. This should cause the subsequent read operation
+    // to fail reliably.
+    fileEntry.remove(didRemoveFile, didFail);
+}
+
+function didRemoveFile()
+{
+    debug("File deleted.");
+    fileEntry = null; // To prevent the file from getting deleted again.
+    var ws = new WebSocket("ws://127.0.0.1:8880/websocket/tests/hybi/echo");
+    ws.onopen = function()
+    {
+        ws.send(fileObject); // This operation should fail and the connection should be aborted.
+    };
+    ws.onclose = function(event)
+    {
+        closeEvent = event;
+        shouldBeFalse("closeEvent.wasClean");
+        endTest();
+    };
+}
+
+function didFail(fileError)
+{
+    testFailed("FileSystem API operation failed: error code = " + fileError.code);
+    endTest();
+}
+
+function endTest()
+{
+    if (fileEntry) {
+        debug("Deleting the file.");
+        fileEntry.remove(finishJSTest, finishJSTest);
+    } else
+        finishJSTest();
+}
+
+runTest();
+
+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/send-file-blob.html b/LayoutTests/http/tests/websocket/tests/hybi/send-file-blob.html
new file mode 100644 (file)
index 0000000..064cb67
--- /dev/null
@@ -0,0 +1,123 @@
+<!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 a File.");
+
+window.jsTestIsAsync = true;
+if (window.layoutTestController)
+    layoutTestController.overridePreference("WebKitHixie76WebSocketProtocolEnabled", 0);
+
+function startsWith(target, prefix)
+{
+    return target.indexOf(prefix) === 0;
+}
+
+var fileSystemSize = 1024;
+var fileName = "websocket-send-file-blob.txt";
+var messageToWrite = "Hello, world!";
+
+function runTest()
+{
+    if (!window.webkitRequestFileSystem) {
+        testFailed("window.webkitRequestFileSystem is not available.");
+        finishJSTest();
+        return;
+    }
+
+    webkitRequestFileSystem(TEMPORARY, fileSystemSize, didGetFileSystem, didFail);
+}
+
+function didGetFileSystem(fileSystem)
+{
+    debug("Got FileSystem object.");
+    fileSystem.root.getFile(fileName, {create: true}, didCreateFile, didFail);
+}
+
+var fileEntry;
+
+function didCreateFile(entry)
+{
+    debug("File created.");
+    fileEntry = entry;
+    shouldBeTrue("fileEntry.isFile");
+    fileEntry.createWriter(didGetFileWriter, didFail);
+}
+
+function didGetFileWriter(writer)
+{
+    writer.truncate(0);
+    writer.onerror = function()
+    {
+        testFailed("FileWriter operation failed.");
+        endTest();
+    };
+    writer.onwrite = function()
+    {
+        var builder = new WebKitBlobBuilder();
+        builder.append(messageToWrite);
+        writer.write(builder.getBlob());
+        writer.onwrite = didWriteFile;
+    };
+}
+
+function didWriteFile()
+{
+    debug("Wrote to file.");
+    fileEntry.file(didGetFile, didFail);
+}
+
+var closeEvent;
+
+function didGetFile(file)
+{
+    debug("Got File object.");
+    var ws = new WebSocket("ws://127.0.0.1:8880/websocket/tests/hybi/send-file-blob");
+    ws.onopen = function()
+    {
+        ws.send(file);
+    };
+    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");
+        endTest();
+    };
+}
+
+function didFail(fileError)
+{
+    testFailed("FileSystem API operation failed: error code = " + fileError.code);
+    endTest();
+}
+
+function endTest()
+{
+    if (fileEntry) {
+        debug("Deleting the file.");
+        fileEntry.remove(finishJSTest, finishJSTest);
+    } else
+        finishJSTest();
+}
+
+runTest();
+
+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/send-file-blob_wsh.py b/LayoutTests/http/tests/websocket/tests/hybi/send-file-blob_wsh.py
new file mode 100644 (file)
index 0000000..daa4404
--- /dev/null
@@ -0,0 +1,22 @@
+from mod_pywebsocket import common
+from mod_pywebsocket import msgutil
+
+
+def web_socket_do_extra_handshake(request):
+    pass # Always accept.
+
+
+def web_socket_transfer_data(request):
+    expected_messages = ['Hello, world!']
+
+    for test_number, expected_message in enumerate(expected_messages):
+        # FIXME: Use better API.
+        opcode, payload, final, unused_reserved1, unused_reserved2, unused_reserved3 = request.ws_stream._receive_frame()
+        if opcode == common.OPCODE_BINARY and payload == expected_message and final:
+            msgutil.send_message(request, 'PASS: Message #%d.' % test_number)
+        else:
+            msgutil.send_message(request, 'FAIL: Message #%d: Received unexpected frame: opcode = %r, payload = %r, final = %r' % (test_number, opcode, payload, final))
+
+
+def all_distinct_bytes():
+    return ''.join([chr(i) for i in xrange(256)])
diff --git a/LayoutTests/http/tests/websocket/tests/hybi/workers/resources/send-blob.js b/LayoutTests/http/tests/websocket/tests/hybi/workers/resources/send-blob.js
new file mode 100644 (file)
index 0000000..cea0503
--- /dev/null
@@ -0,0 +1,51 @@
+function startsWith(target, prefix)
+{
+    return target.indexOf(prefix) === 0;
+}
+
+function createBlobContainingHelloWorld()
+{
+    var builder = new WebKitBlobBuilder();
+    builder.append("Hello, world!");
+    return builder.getBlob();
+}
+
+function createEmptyBlob()
+{
+    var builder = new WebKitBlobBuilder();
+    return builder.getBlob();
+}
+
+function createBlobContainingAllDistinctBytes()
+{
+    var array = new Uint8Array(256);
+    for (var i = 0; i < 256; ++i)
+        array[i] = i;
+    var builder = new WebKitBlobBuilder();
+    builder.append(array.buffer);
+    return builder.getBlob();
+}
+
+var url = "ws://127.0.0.1:8880/websocket/tests/hybi/workers/resources/send-blob";
+var ws = new WebSocket(url);
+
+ws.onopen = function()
+{
+    ws.send(createBlobContainingHelloWorld());
+    ws.send(createEmptyBlob());
+    ws.send(createBlobContainingAllDistinctBytes());
+};
+
+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");
+};
diff --git a/LayoutTests/http/tests/websocket/tests/hybi/workers/resources/send-blob_wsh.py b/LayoutTests/http/tests/websocket/tests/hybi/workers/resources/send-blob_wsh.py
new file mode 100644 (file)
index 0000000..024e3f4
--- /dev/null
@@ -0,0 +1,21 @@
+from mod_pywebsocket import common
+from mod_pywebsocket import msgutil
+
+
+def web_socket_do_extra_handshake(request):
+    pass # Always accept.
+
+
+def web_socket_transfer_data(request):
+    expected_messages = ['Hello, world!', '', all_distinct_bytes()]
+
+    for test_number, expected_message in enumerate(expected_messages):
+        message = msgutil.receive_message(request)
+        if type(message) == str and message == expected_message:
+            msgutil.send_message(request, 'PASS: Message #%d.' % test_number)
+        else:
+            msgutil.send_message(request, 'FAIL: Message #%d: Received unexpected message: %r' % (test_number, message))
+
+
+def all_distinct_bytes():
+    return ''.join([chr(i) for i in xrange(256)])
diff --git a/LayoutTests/http/tests/websocket/tests/hybi/workers/send-blob-expected.txt b/LayoutTests/http/tests/websocket/tests/hybi/workers/send-blob-expected.txt
new file mode 100644 (file)
index 0000000..633bb7e
--- /dev/null
@@ -0,0 +1,13 @@
+WebSocket: Send Blobs 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-blob.html b/LayoutTests/http/tests/websocket/tests/hybi/workers/send-blob.html
new file mode 100644 (file)
index 0000000..15746eb
--- /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 Blobs 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-blob.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 e9b6f1b..71eb1bd 100644 (file)
@@ -366,6 +366,8 @@ fast/filesystem
 http/tests/filesystem
 http/tests/local/fileapi
 http/tests/security/filesystem-iframe-from-remote.html
+http/tests/websocket/tests/hybi/send-file-blob.html
+http/tests/websocket/tests/hybi/send-file-blob-fail.html
 
 # Requires WebP support.
 fast/images/webp-image-decoding.html
index 156dbcc..9693919 100644 (file)
@@ -277,6 +277,8 @@ http/tests/media/video-buffered.html
 fast/filesystem
 http/tests/filesystem
 http/tests/security/filesystem-iframe-from-remote.html
+http/tests/websocket/tests/hybi/send-file-blob.html
+http/tests/websocket/tests/hybi/send-file-blob-fail.html
 
 # https://bugs.webkit.org/show_bug.cgi?id=46223
 # The WebKit plugin implementation does not support iframe shims.
index 34a4cfd..9bcdcd2 100644 (file)
@@ -99,6 +99,8 @@ svg/webarchive
 fast/filesystem
 http/tests/filesystem
 http/tests/security/filesystem-iframe-from-remote.html
+http/tests/websocket/tests/hybi/send-file-blob.html
+http/tests/websocket/tests/hybi/send-file-blob-fail.html
 
 # ENABLE(QUOTA) is disabled.
 storage/storageinfo-query-usage.html
index 1e4cc8c..3d3b64f 100644 (file)
@@ -1202,6 +1202,8 @@ fast/parser/pre-html5-parser-quirks.html
 fast/filesystem
 http/tests/filesystem
 http/tests/security/filesystem-iframe-from-remote.html
+http/tests/websocket/tests/hybi/send-file-blob.html
+http/tests/websocket/tests/hybi/send-file-blob-fail.html
 
 # LayoutTestController::nodesFromRect is not supported.
 fast/dom/nodesFromRect-basic.html
index 8ea2143..84dbfe9 100644 (file)
@@ -1,3 +1,31 @@
+2011-09-02  Yuta Kitamura  <yutak@chromium.org>
+
+        WebSocket: Send Blob as WebSocket binary message
+        https://bugs.webkit.org/show_bug.cgi?id=67465
+
+        Reviewed by Kent Tamura.
+
+        Re-lands r94399 with a fix for Leopard builds.
+
+        * bindings/js/JSWebSocketCustom.cpp:
+        (WebCore::JSWebSocket::send):
+        * bindings/v8/custom/V8WebSocketCustom.cpp:
+        (WebCore::V8WebSocket::sendCallback):
+        * websockets/ThreadableWebSocketChannel.h:
+        * websockets/WebSocket.cpp:
+        (WebCore::WebSocket::send):
+        * websockets/WebSocket.h:
+        * websockets/WebSocket.idl:
+        * websockets/WebSocketChannel.cpp:
+        (WebCore::WebSocketChannel::send):
+        * websockets/WebSocketChannel.h:
+        * websockets/WorkerThreadableWebSocketChannel.cpp:
+        (WebCore::WorkerThreadableWebSocketChannel::send):
+        (WebCore::WorkerThreadableWebSocketChannel::Peer::send):
+        (WebCore::WorkerThreadableWebSocketChannel::mainThreadSendBlob):
+        (WebCore::WorkerThreadableWebSocketChannel::Bridge::send):
+        * websockets/WorkerThreadableWebSocketChannel.h:
+
 2011-09-02  Patrick Gansterer  <paroga@webkit.org>
 
         [GTK] Generate gobject bindings for Notification and NotificationCenter
index 6b3598b..4f92f40 100644 (file)
@@ -36,8 +36,9 @@
 #include "JSWebSocket.h"
 
 #include "ExceptionCode.h"
-#include "KURL.h"
+#include "JSBlob.h"
 #include "JSEventListener.h"
+#include "KURL.h"
 #include "WebSocket.h"
 #include "WebSocketChannel.h"
 #include <runtime/Error.h>
@@ -88,6 +89,30 @@ EncodedJSValue JSC_HOST_CALL JSWebSocketConstructor::constructJSWebSocket(ExecSt
     return JSValue::encode(CREATE_DOM_WRAPPER(exec, jsConstructor->globalObject(), WebSocket, webSocket.get()));
 }
 
+JSValue JSWebSocket::send(ExecState* exec)
+{
+    if (!exec->argumentCount())
+        return throwError(exec, createSyntaxError(exec, "Not enough arguments"));
+
+    JSValue message = exec->argument(0);
+    ExceptionCode ec = 0;
+    bool result;
+    if (message.inherits(&JSBlob::s_info))
+        result = impl()->send(toBlob(message), ec);
+    else {
+        String stringMessage = ustringToString(message.toString(exec));
+        if (exec->hadException())
+            return jsUndefined();
+        result = impl()->send(stringMessage, ec);
+    }
+    if (ec) {
+        setDOMException(exec, ec);
+        return jsUndefined();
+    }
+
+    return jsBoolean(result);
+}
+
 JSValue JSWebSocket::close(ExecState* exec)
 {
     // FIXME: We should implement [Clamp] for IDL binding code generator, and
index d7dfa10..d237047 100644 (file)
@@ -38,6 +38,7 @@
 #include "Frame.h"
 #include "Settings.h"
 #include "V8Binding.h"
+#include "V8Blob.h"
 #include "V8Proxy.h"
 #include "V8Utilities.h"
 #include "WebSocket.h"
@@ -111,6 +112,34 @@ v8::Handle<v8::Value> V8WebSocket::constructorCallback(const v8::Arguments& args
     return args.Holder();
 }
 
+v8::Handle<v8::Value> V8WebSocket::sendCallback(const v8::Arguments& args)
+{
+    INC_STATS("DOM.WebSocket.send()");
+
+    if (!args.Length())
+        return throwError("Not enough arguments", V8Proxy::SyntaxError);
+
+    WebSocket* webSocket = V8WebSocket::toNative(args.Holder());
+    v8::Handle<v8::Value> message = args[0];
+    ExceptionCode ec = 0;
+    bool result;
+    if (V8Blob::HasInstance(message)) {
+        Blob* blob = V8Blob::toNative(v8::Handle<v8::Object>::Cast(message));
+        ASSERT(blob);
+        result = webSocket->send(blob, ec);
+    } else {
+        v8::TryCatch tryCatch;
+        v8::Handle<v8::String> stringMessage = message->ToString();
+        if (tryCatch.HasCaught())
+            return throwError(tryCatch.Exception());
+        result = webSocket->send(toWebCoreString(message), ec);
+    }
+    if (ec)
+        return throwError(ec);
+
+    return v8Boolean(result);
+}
+
 v8::Handle<v8::Value> V8WebSocket::closeCallback(const v8::Arguments& args)
 {
     // FIXME: We should implement [Clamp] for IDL binding code generator, and
index 09f81b5..ca0b372 100644 (file)
@@ -39,6 +39,7 @@
 
 namespace WebCore {
 
+class Blob;
 class KURL;
 class ScriptExecutionContext;
 class WebSocketChannelClient;
@@ -53,6 +54,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 Blob&) = 0;
     virtual unsigned long bufferedAmount() const = 0;
     virtual void close(int code, const String& reason) = 0;
     // Log the reason text and close the connection. Will call didClose().
index 88f2eed..f3b1845 100644 (file)
@@ -265,6 +265,25 @@ bool WebSocket::send(const String& message, ExceptionCode& ec)
     return m_channel->send(message);
 }
 
+bool WebSocket::send(Blob* binaryData, ExceptionCode& ec)
+{
+    LOG(Network, "WebSocket %p send blob %s", this, binaryData->url().string().utf8().data());
+    ASSERT(binaryData);
+    if (m_useHixie76Protocol)
+        return send("[object Blob]", ec);
+    if (m_state == CONNECTING) {
+        ec = INVALID_STATE_ERR;
+        return false;
+    }
+    if (m_state == CLOSING || m_state == CLOSED) {
+        unsigned long payloadSize = static_cast<unsigned long>(binaryData->size());
+        m_bufferedAmountAfterClose += payloadSize + getFramingOverhead(payloadSize);
+        return false;
+    }
+    ASSERT(m_channel);
+    return m_channel->send(*binaryData);
+}
+
 void WebSocket::close(int code, const String& reason, ExceptionCode& ec)
 {
     if (code == WebSocketChannel::CloseEventCodeNotSpecified)
index 04c27c3..cbb8d60 100644 (file)
@@ -46,6 +46,7 @@
 
 namespace WebCore {
 
+class Blob;
 class ThreadableWebSocketChannel;
 
 class WebSocket : public RefCounted<WebSocket>, public EventTarget, public ActiveDOMObject, public WebSocketChannelClient {
@@ -67,6 +68,7 @@ public:
     void connect(const String& url, const Vector<String>& protocols, ExceptionCode&);
 
     bool send(const String& message, ExceptionCode&);
+    bool send(Blob*, ExceptionCode&);
 
     void close(int code, const String& reason, ExceptionCode&);
 
index 936e603..0dc23e7 100644 (file)
@@ -63,7 +63,15 @@ module websockets {
         attribute [ConvertNullStringTo=Undefined] DOMString binaryType
             setter raises(DOMException);
 
-        [RequiresAllArguments] boolean send(in DOMString data) raises(DOMException);
+        // 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.
+        // [RequiresAllArguments] boolean send(in Blob data) raises(DOMException);
+        // [RequiresAllArguments] boolean send(in DOMString data) raises(DOMException);
+        [Custom] boolean send(in DOMString data) raises(DOMException);
+
         // FIXME: Implement and apply [Clamp] attribute instead of [Custom].
         [Custom] void close(in [Optional] unsigned short code, in [Optional] DOMString reason) raises(DOMException);
 
index 2007e6d..ae5c1ac 100644 (file)
@@ -170,6 +170,14 @@ bool WebSocketChannel::send(const String& message)
     return true;
 }
 
+bool WebSocketChannel::send(const Blob& binaryData)
+{
+    LOG(Network, "WebSocketChannel %p send blob %s", this, binaryData.url().string().utf8().data());
+    ASSERT(!m_useHixie76Protocol);
+    enqueueBlobFrame(OpCodeBinary, binaryData);
+    return true;
+}
+
 unsigned long WebSocketChannel::bufferedAmount() const
 {
     LOG(Network, "WebSocketChannel %p bufferedAmount", this);
index 9703162..3e89e85 100644 (file)
@@ -66,6 +66,7 @@ public:
     virtual void connect(const KURL&, const String& protocol);
     virtual String subprotocol();
     virtual bool send(const String& message);
+    virtual bool send(const Blob&);
     virtual unsigned long bufferedAmount() const;
     virtual void close(int code, const String& reason); // Start closing handshake.
     virtual void fail(const String& reason);
index 44988f6..604645a 100644 (file)
@@ -34,6 +34,7 @@
 
 #include "WorkerThreadableWebSocketChannel.h"
 
+#include "Blob.h"
 #include "CrossThreadTask.h"
 #include "PlatformString.h"
 #include "ScriptExecutionContext.h"
@@ -87,6 +88,13 @@ bool WorkerThreadableWebSocketChannel::send(const String& message)
     return m_bridge->send(message);
 }
 
+bool WorkerThreadableWebSocketChannel::send(const Blob& binaryData)
+{
+    if (!m_bridge)
+        return false;
+    return m_bridge->send(binaryData);
+}
+
 unsigned long WorkerThreadableWebSocketChannel::bufferedAmount() const
 {
     if (!m_bridge)
@@ -172,6 +180,15 @@ void WorkerThreadableWebSocketChannel::Peer::send(const String& message)
     m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&workerContextDidSend, m_workerClientWrapper, sent), m_taskMode);
 }
 
+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);
+}
+
 static void workerContextDidGetBufferedAmount(ScriptExecutionContext* context, PassRefPtr<ThreadableWebSocketChannelClientWrapper> workerClientWrapper, unsigned long bufferedAmount)
 {
     ASSERT_UNUSED(context, context->isWorkerContext());
@@ -358,6 +375,16 @@ void WorkerThreadableWebSocketChannel::mainThreadSend(ScriptExecutionContext* co
     peer->send(message);
 }
 
+void WorkerThreadableWebSocketChannel::mainThreadSendBlob(ScriptExecutionContext* context, Peer* peer, const KURL& url, const String& type, long long size)
+{
+    ASSERT(isMainThread());
+    ASSERT_UNUSED(context, context->isDocument());
+    ASSERT(peer);
+
+    RefPtr<Blob> blob = Blob::create(url, type, size);
+    peer->send(*blob);
+}
+
 bool WorkerThreadableWebSocketChannel::Bridge::send(const String& message)
 {
     if (!m_workerClientWrapper)
@@ -371,6 +398,19 @@ bool WorkerThreadableWebSocketChannel::Bridge::send(const String& message)
     return clientWrapper && clientWrapper->sent();
 }
 
+bool WorkerThreadableWebSocketChannel::Bridge::send(const Blob& binaryData)
+{
+    if (!m_workerClientWrapper)
+        return false;
+    ASSERT(m_peer);
+    setMethodNotCompleted();
+    m_loaderProxy.postTaskToLoader(createCallbackTask(&WorkerThreadableWebSocketChannel::mainThreadSendBlob, AllowCrossThreadAccess(m_peer), binaryData.url(), binaryData.type(), binaryData.size()));
+    RefPtr<Bridge> protect(this);
+    waitForMethodCompletion();
+    ThreadableWebSocketChannelClientWrapper* clientWrapper = m_workerClientWrapper.get();
+    return clientWrapper && clientWrapper->sent();
+}
+
 void WorkerThreadableWebSocketChannel::mainThreadBufferedAmount(ScriptExecutionContext* context, Peer* peer)
 {
     ASSERT(isMainThread());
index a8d133d..7e2ec1b 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 Blob&);
     virtual unsigned long bufferedAmount() const;
     virtual void close(int code, const String& reason);
     virtual void fail(const String& reason);
@@ -93,6 +94,7 @@ private:
         bool useHixie76Protocol();
         void connect(const KURL&, const String& protocol);
         void send(const String& message);
+        void send(const Blob&);
         void bufferedAmount();
         void close(int code, const String& reason);
         void fail(const String& reason);
@@ -125,6 +127,7 @@ private:
         ~Bridge();
         void connect(const KURL&, const String& protocol);
         bool send(const String& message);
+        bool send(const Blob&);
         unsigned long bufferedAmount();
         void close(int code, const String& reason);
         void fail(const String& reason);
@@ -160,6 +163,7 @@ private:
 
     static void mainThreadConnect(ScriptExecutionContext*, Peer*, const KURL&, const String& protocol);
     static void mainThreadSend(ScriptExecutionContext*, Peer*, const String& message);
+    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);
     static void mainThreadFail(ScriptExecutionContext*, Peer*, const String& reason);