Diff
Modified: trunk/LayoutTests/ChangeLog (107787 => 107788)
--- trunk/LayoutTests/ChangeLog 2012-02-15 08:26:30 UTC (rev 107787)
+++ trunk/LayoutTests/ChangeLog 2012-02-15 08:43:48 UTC (rev 107788)
@@ -1,3 +1,19 @@
+2012-02-15 Yuta Kitamura <[email protected]>
+
+ WebSocket: MessageEvent fired during send() on workers
+ https://bugs.webkit.org/show_bug.cgi?id=76521
+
+ Reviewed by David Levin.
+
+ * http/tests/websocket/tests/hybi/workers/no-onmessage-in-sync-op-expected.txt: Added.
+ * http/tests/websocket/tests/hybi/workers/no-onmessage-in-sync-op.html: Added.
+ * http/tests/websocket/tests/hybi/workers/resources/no-onmessage-in-sync-op.js:
+ Added. The server sends messages immediately after the connection is established, but
+ these messages should not be delivered until the script exits the current cycle of
+ the event loop. The script calls a few synchronous operations to make sure we don't
+ fire MessageEvents while we are waiting for these operations to finish.
+ * http/tests/websocket/tests/hybi/workers/resources/no-onmessage-in-sync-op_wsh.py: Added.
+
2012-02-15 Noel Gordon <[email protected]>
[chromium] Rebaseline JPEG image results after r107389
Added: trunk/LayoutTests/http/tests/websocket/tests/hybi/workers/no-onmessage-in-sync-op-expected.txt (0 => 107788)
--- trunk/LayoutTests/http/tests/websocket/tests/hybi/workers/no-onmessage-in-sync-op-expected.txt (rev 0)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/workers/no-onmessage-in-sync-op-expected.txt 2012-02-15 08:43:48 UTC (rev 107788)
@@ -0,0 +1,21 @@
+WebSocket's message event should not be invoked while we are waiting for the result of a synchronous operation (such as WebSocket.send()) on workers.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+INFO: Waiting for two seconds to make sure we receive messages from the server.
+PASS PASS: closeEvent.wasClean is true
+PASS PASS: event.length is 9
+PASS PASS: events[0] is "Got bufferedAmount: 0"
+PASS PASS: events[1] is "Got bufferedAmount: 0"
+PASS PASS: events[2] is "Got bufferedAmount: 0"
+PASS PASS: events[3] is "Sent message: 1"
+PASS PASS: events[4] is "Sent message: 2"
+PASS PASS: events[5] is "Sent message: 3"
+PASS PASS: events[6] is "Received message: 1"
+PASS PASS: events[7] is "Received message: 2"
+PASS PASS: events[8] is "Received message: 3"
+DONE
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/http/tests/websocket/tests/hybi/workers/no-onmessage-in-sync-op.html (0 => 107788)
--- trunk/LayoutTests/http/tests/websocket/tests/hybi/workers/no-onmessage-in-sync-op.html (rev 0)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/workers/no-onmessage-in-sync-op.html 2012-02-15 08:43:48 UTC (rev 107788)
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<script type="text/_javascript_">
+description("WebSocket's message event should not be invoked while we are waiting for the result of a synchronous operation (such as WebSocket.send()) on 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/no-onmessage-in-sync-op.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();
+};
+
+</script>
+<script src=""
+</body>
+</html>
Added: trunk/LayoutTests/http/tests/websocket/tests/hybi/workers/resources/no-onmessage-in-sync-op.js (0 => 107788)
--- trunk/LayoutTests/http/tests/websocket/tests/hybi/workers/resources/no-onmessage-in-sync-op.js (rev 0)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/workers/resources/no-onmessage-in-sync-op.js 2012-02-15 08:43:48 UTC (rev 107788)
@@ -0,0 +1,62 @@
+var ws = new WebSocket("ws://127.0.0.1:8880/websocket/tests/hybi/workers/resources/no-onmessage-in-sync-op");
+
+var events = [];
+// Message receipt should be recorded after bufferedAmount and send() calls.
+var expectedEvents = ["Got bufferedAmount: 0",
+ "Got bufferedAmount: 0",
+ "Got bufferedAmount: 0",
+ "Sent message: 1",
+ "Sent message: 2",
+ "Sent message: 3",
+ "Received message: 1",
+ "Received message: 2",
+ "Received message: 3"];
+
+ws._onopen_ = function()
+{
+ // After handshake, the server will send three messages immediately, but they should not be received
+ // until we exit this event loop.
+ postMessage("INFO: Waiting for two seconds to make sure we receive messages from the server.");
+ var start = (new Date()).getTime();
+ while ((new Date()).getTime() - start < 2000) {}
+
+ var bufferedAmount = ws.bufferedAmount;
+ events.push("Got bufferedAmount: " + bufferedAmount);
+ bufferedAmount = ws.bufferedAmount;
+ events.push("Got bufferedAmount: " + bufferedAmount);
+ bufferedAmount = ws.bufferedAmount;
+ events.push("Got bufferedAmount: " + bufferedAmount);
+ ws.send("1");
+ events.push("Sent message: 1");
+ ws.send("2");
+ events.push("Sent message: 2");
+ ws.send("3");
+ events.push("Sent message: 3");
+};
+
+ws._onmessage_ = function(messageEvent)
+{
+ events.push("Received message: " + messageEvent.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 + "\"");
+
+ if (events.length === expectedEvents.length)
+ postMessage("PASS: event.length is " + expectedEvents.length);
+ else
+ postMessage("FAIL: event.length should be " + expectedEvents.length + " but was \"" + events.length + "\"");
+
+ for (var i = 0; i < expectedEvents.length; ++i) {
+ if (events[i] === expectedEvents[i])
+ postMessage("PASS: events[" + i + "] is \"" + expectedEvents[i] + "\"");
+ else
+ postMessage("FAIL: events[" + i + "] should be \"" + expectedEvents[i] + "\" but was \"" + events[i] + "\"");
+ }
+
+ postMessage("DONE");
+};
Added: trunk/LayoutTests/http/tests/websocket/tests/hybi/workers/resources/no-onmessage-in-sync-op_wsh.py (0 => 107788)
--- trunk/LayoutTests/http/tests/websocket/tests/hybi/workers/resources/no-onmessage-in-sync-op_wsh.py (rev 0)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/workers/resources/no-onmessage-in-sync-op_wsh.py 2012-02-15 08:43:48 UTC (rev 107788)
@@ -0,0 +1,18 @@
+from mod_pywebsocket import handshake
+from mod_pywebsocket import msgutil
+
+
+def web_socket_do_extra_handshake(request):
+ pass
+
+
+def web_socket_transfer_data(request):
+ # Send three messages, and then wait for three messages.
+ msgutil.send_message(request, '1')
+ msgutil.send_message(request, '2')
+ msgutil.send_message(request, '3')
+
+ for expected in (u'1', u'2', u'3'):
+ message = msgutil.receive_message(request)
+ if type(message) != unicode or message != expected:
+ raise handshake.AbortedByUserException('Abort the connection')
Modified: trunk/Source/WebCore/ChangeLog (107787 => 107788)
--- trunk/Source/WebCore/ChangeLog 2012-02-15 08:26:30 UTC (rev 107787)
+++ trunk/Source/WebCore/ChangeLog 2012-02-15 08:43:48 UTC (rev 107788)
@@ -1,3 +1,28 @@
+2012-02-15 Yuta Kitamura <[email protected]>
+
+ WebSocket: MessageEvent fired during send() on workers
+ https://bugs.webkit.org/show_bug.cgi?id=76521
+
+ Reviewed by David Levin.
+
+ WebSocket's message event should not be invoked while a synchronous operation
+ (send() and bufferedAmount) is in progress.
+
+ Test: http/tests/websocket/tests/hybi/workers/no-onmessage-in-sync-op.html
+
+ * websockets/ThreadableWebSocketChannelClientWrapper.cpp:
+ Added #if ENABLE(WORKERS) because ThreadableWebSocketChannelClientWrapper is not used
+ if Web Workers is not available.
+ Changed access label because private members were declared as protected with no good reason.
+ (WebCore::ThreadableWebSocketChannelClientWrapper::ThreadableWebSocketChannelClientWrapper):
+ Receive ScriptExecutionContext so we can post a task that should be executed later.
+ (WebCore::ThreadableWebSocketChannelClientWrapper::create):
+ (WebCore::ThreadableWebSocketChannelClientWrapper::processPendingTasksCallback):
+ (WebCore::ThreadableWebSocketChannelClientWrapper::processPendingTasks):
+ * websockets/ThreadableWebSocketChannelClientWrapper.h:
+ * websockets/WorkerThreadableWebSocketChannel.cpp:
+ (WebCore::WorkerThreadableWebSocketChannel::WorkerThreadableWebSocketChannel):
+
2012-02-15 No'am Rosenthal <[email protected]>
[Texmap] Divide TextureMapperNode.cpp to 3 files.
Modified: trunk/Source/WebCore/websockets/ThreadableWebSocketChannelClientWrapper.cpp (107787 => 107788)
--- trunk/Source/WebCore/websockets/ThreadableWebSocketChannelClientWrapper.cpp 2012-02-15 08:26:30 UTC (rev 107787)
+++ trunk/Source/WebCore/websockets/ThreadableWebSocketChannelClientWrapper.cpp 2012-02-15 08:43:48 UTC (rev 107788)
@@ -29,20 +29,22 @@
*/
#include "config.h"
-#if ENABLE(WEB_SOCKETS)
+#if ENABLE(WEB_SOCKETS) && ENABLE(WORKERS)
#include "ThreadableWebSocketChannelClientWrapper.h"
#include "CrossThreadCopier.h"
#include "CrossThreadTask.h"
+#include "ScriptExecutionContext.h"
#include "WebSocketChannelClient.h"
#include <wtf/PassRefPtr.h>
#include <wtf/RefPtr.h>
namespace WebCore {
-ThreadableWebSocketChannelClientWrapper::ThreadableWebSocketChannelClientWrapper(WebSocketChannelClient* client)
- : m_client(client)
- , m_syncMethodDone(false)
+ThreadableWebSocketChannelClientWrapper::ThreadableWebSocketChannelClientWrapper(ScriptExecutionContext* context, WebSocketChannelClient* client)
+ : m_context(context)
+ , m_client(client)
+ , m_syncMethodDone(true)
, m_useHixie76Protocol(true)
, m_sendRequestResult(false)
, m_bufferedAmount(0)
@@ -50,9 +52,9 @@
{
}
-PassRefPtr<ThreadableWebSocketChannelClientWrapper> ThreadableWebSocketChannelClientWrapper::create(WebSocketChannelClient* client)
+PassRefPtr<ThreadableWebSocketChannelClientWrapper> ThreadableWebSocketChannelClientWrapper::create(ScriptExecutionContext* context, WebSocketChannelClient* client)
{
- return adoptRef(new ThreadableWebSocketChannelClientWrapper(client));
+ return adoptRef(new ThreadableWebSocketChannelClientWrapper(context, client));
}
void ThreadableWebSocketChannelClientWrapper::clearSyncMethodDone()
@@ -190,9 +192,22 @@
processPendingTasks();
}
+void ThreadableWebSocketChannelClientWrapper::processPendingTasksCallback(ScriptExecutionContext* context, PassRefPtr<ThreadableWebSocketChannelClientWrapper> wrapper)
+{
+ ASSERT_UNUSED(context, context->isWorkerContext());
+ wrapper->processPendingTasks();
+}
+
void ThreadableWebSocketChannelClientWrapper::processPendingTasks()
{
- ASSERT(!m_suspended);
+ if (m_suspended)
+ return;
+ if (!m_syncMethodDone) {
+ // When a synchronous operation is in progress (i.e. the execution stack contains
+ // WorkerThreadableWebSocketChannel::waitForMethodCompletion()), we cannot invoke callbacks in this run loop.
+ m_context->postTask(createCallbackTask(&ThreadableWebSocketChannelClientWrapper::processPendingTasksCallback, this));
+ return;
+ }
Vector<OwnPtr<ScriptExecutionContext::Task> > tasks;
tasks.swap(m_pendingTasks);
for (Vector<OwnPtr<ScriptExecutionContext::Task> >::const_iterator iter = tasks.begin(); iter != tasks.end(); ++iter)
Modified: trunk/Source/WebCore/websockets/ThreadableWebSocketChannelClientWrapper.h (107787 => 107788)
--- trunk/Source/WebCore/websockets/ThreadableWebSocketChannelClientWrapper.h 2012-02-15 08:26:30 UTC (rev 107787)
+++ trunk/Source/WebCore/websockets/ThreadableWebSocketChannelClientWrapper.h 2012-02-15 08:43:48 UTC (rev 107788)
@@ -31,7 +31,7 @@
#ifndef ThreadableWebSocketChannelClientWrapper_h
#define ThreadableWebSocketChannelClientWrapper_h
-#if ENABLE(WEB_SOCKETS)
+#if ENABLE(WEB_SOCKETS) && ENABLE(WORKERS)
#include "PlatformString.h"
#include "ScriptExecutionContext.h"
@@ -44,11 +44,12 @@
namespace WebCore {
+class ScriptExecutionContext;
class WebSocketChannelClient;
class ThreadableWebSocketChannelClientWrapper : public ThreadSafeRefCounted<ThreadableWebSocketChannelClientWrapper> {
public:
- static PassRefPtr<ThreadableWebSocketChannelClientWrapper> create(WebSocketChannelClient*);
+ static PassRefPtr<ThreadableWebSocketChannelClientWrapper> create(ScriptExecutionContext*, WebSocketChannelClient*);
void clearSyncMethodDone();
void setSyncMethodDone();
@@ -83,17 +84,20 @@
void suspend();
void resume();
-protected:
- ThreadableWebSocketChannelClientWrapper(WebSocketChannelClient*);
+private:
+ ThreadableWebSocketChannelClientWrapper(ScriptExecutionContext*, WebSocketChannelClient*);
void processPendingTasks();
+
static void didConnectCallback(ScriptExecutionContext*, PassRefPtr<ThreadableWebSocketChannelClientWrapper>);
static void didReceiveMessageCallback(ScriptExecutionContext*, PassRefPtr<ThreadableWebSocketChannelClientWrapper>, const String& message);
static void didReceiveBinaryDataCallback(ScriptExecutionContext*, PassRefPtr<ThreadableWebSocketChannelClientWrapper>, PassOwnPtr<Vector<char> >);
static void didUpdateBufferedAmountCallback(ScriptExecutionContext*, PassRefPtr<ThreadableWebSocketChannelClientWrapper>, unsigned long bufferedAmount);
static void didStartClosingHandshakeCallback(ScriptExecutionContext*, PassRefPtr<ThreadableWebSocketChannelClientWrapper>);
static void didCloseCallback(ScriptExecutionContext*, PassRefPtr<ThreadableWebSocketChannelClientWrapper>, unsigned long unhandledBufferedAmount, WebSocketChannelClient::ClosingHandshakeCompletionStatus, unsigned short code, const String& reason);
+ static void processPendingTasksCallback(ScriptExecutionContext*, PassRefPtr<ThreadableWebSocketChannelClientWrapper>);
+ ScriptExecutionContext* m_context;
WebSocketChannelClient* m_client;
bool m_syncMethodDone;
bool m_useHixie76Protocol;
Modified: trunk/Source/WebCore/websockets/WorkerThreadableWebSocketChannel.cpp (107787 => 107788)
--- trunk/Source/WebCore/websockets/WorkerThreadableWebSocketChannel.cpp 2012-02-15 08:26:30 UTC (rev 107787)
+++ trunk/Source/WebCore/websockets/WorkerThreadableWebSocketChannel.cpp 2012-02-15 08:43:48 UTC (rev 107788)
@@ -54,7 +54,7 @@
WorkerThreadableWebSocketChannel::WorkerThreadableWebSocketChannel(WorkerContext* context, WebSocketChannelClient* client, const String& taskMode)
: m_workerContext(context)
- , m_workerClientWrapper(ThreadableWebSocketChannelClientWrapper::create(client))
+ , m_workerClientWrapper(ThreadableWebSocketChannelClientWrapper::create(context, client))
, m_bridge(Bridge::create(m_workerClientWrapper, m_workerContext, taskMode))
{
}