Title: [107788] trunk
Revision
107788
Author
[email protected]
Date
2012-02-15 00:43:48 -0800 (Wed, 15 Feb 2012)

Log Message

WebSocket: MessageEvent fired during send() on workers
https://bugs.webkit.org/show_bug.cgi?id=76521

Reviewed by David Levin.

Source/WebCore:

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):

LayoutTests:

* 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.

Modified Paths

Added Paths

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))
 {
 }
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to