2010-01-06 Fumitoshi Ukai <ukai@chromium.org>
authorukai@chromium.org <ukai@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 7 Jan 2010 02:33:35 +0000 (02:33 +0000)
committerukai@chromium.org <ukai@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 7 Jan 2010 02:33:35 +0000 (02:33 +0000)
        Reviewed by David Levin

        Add WebSocket feature in Worker
        https://bugs.webkit.org/show_bug.cgi?id=32214

        * websocket/tests/workers/resources/simple_wsh.py: Copied from LayoutTests/websocket/tests/simple_wsh.py.
        * websocket/tests/workers/resources/worker-simple.js: Added.
        * websocket/tests/workers/worker-simple-expected.txt: Added.
        * websocket/tests/workers/worker-simple.html: Added.
2010-01-06  Fumitoshi Ukai  <ukai@chromium.org>

        Reviewed by David Levin.

        Add WebSocket feature in Worker
        https://bugs.webkit.org/show_bug.cgi?id=32214

        Introduce ThreadableWebSocketChannel interface and add
        WorkerThreadableWebSocketChannel for Worker.
        WorkerThreadableWebSocketChannel uses WebSocketChannel in the
        main thread, which is managed by Peer and communicated via Bridge.

        Test: websocket/tests/workers/worker-simple.html

        * GNUmakefile.am:
        * WebCore.gypi:
        * WebCore.pro:
        * WebCore.vcproj/WebCore.vcproj:
        * WebCore.xcodeproj/project.pbxproj:
        * bindings/js/JSWebSocketConstructor.h:
        * bindings/js/JSWorkerContextCustom.cpp:
        (WebCore::JSWorkerContext::webSocket):
        * bindings/v8/WorkerContextExecutionProxy.cpp:
        (WebCore::WorkerContextExecutionProxy::convertEventTargetToV8Object):
        * bindings/v8/custom/V8WebSocketCustom.cpp:
        (WebCore::V8Custom::v8WebSocketConstructorCallback):
        * bindings/v8/custom/V8WorkerContextCustom.cpp:
        * platform/CrossThreadCopier.cpp:
        (WebCore::::copy):
        * platform/CrossThreadCopier.h:
        (WebCore::):
        * websockets/ThreadableWebSocketChannel.cpp: Added.
        * websockets/ThreadableWebSocketChannel.h: Added.
        * websockets/ThreadableWebSocketChannelClientWrapper.h: Added.
        * websockets/WebSocket.cpp:
        (WebCore::WebSocket::connect):
        (WebCore::WebSocket::didReceiveMessage):
        * websockets/WebSocket.h:
        * websockets/WebSocketChannel.h:
        (WebCore::WebSocketChannel::refThreadableWebSocketChannel):
        (WebCore::WebSocketChannel::derefThreadableWebSocketChannel):
        * websockets/WebSocketChannelClient.h:
        * websockets/WebSocketHandshake.h:
        * websockets/WorkerThreadableWebSocketChannel.cpp: Added.
        * websockets/WorkerThreadableWebSocketChannel.h: Added.
        * workers/WorkerContext.idl:

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

29 files changed:
LayoutTests/ChangeLog
LayoutTests/websocket/tests/workers/resources/simple_wsh.py [new file with mode: 0644]
LayoutTests/websocket/tests/workers/resources/worker-simple.js [new file with mode: 0644]
LayoutTests/websocket/tests/workers/worker-simple-expected.txt [new file with mode: 0644]
LayoutTests/websocket/tests/workers/worker-simple.html [new file with mode: 0644]
WebCore/ChangeLog
WebCore/GNUmakefile.am
WebCore/WebCore.gypi
WebCore/WebCore.pro
WebCore/WebCore.vcproj/WebCore.vcproj
WebCore/WebCore.xcodeproj/project.pbxproj
WebCore/bindings/js/JSWebSocketConstructor.h
WebCore/bindings/js/JSWorkerContextCustom.cpp
WebCore/bindings/v8/WorkerContextExecutionProxy.cpp
WebCore/bindings/v8/custom/V8WebSocketCustom.cpp
WebCore/bindings/v8/custom/V8WorkerContextCustom.cpp
WebCore/platform/CrossThreadCopier.cpp
WebCore/platform/CrossThreadCopier.h
WebCore/websockets/ThreadableWebSocketChannel.cpp [new file with mode: 0644]
WebCore/websockets/ThreadableWebSocketChannel.h [new file with mode: 0644]
WebCore/websockets/ThreadableWebSocketChannelClientWrapper.h [new file with mode: 0644]
WebCore/websockets/WebSocket.cpp
WebCore/websockets/WebSocket.h
WebCore/websockets/WebSocketChannel.h
WebCore/websockets/WebSocketChannelClient.h
WebCore/websockets/WebSocketHandshake.h
WebCore/websockets/WorkerThreadableWebSocketChannel.cpp [new file with mode: 0644]
WebCore/websockets/WorkerThreadableWebSocketChannel.h [new file with mode: 0644]
WebCore/workers/WorkerContext.idl

index eb78230..ddfcb81 100644 (file)
@@ -1,3 +1,15 @@
+2010-01-06  Fumitoshi Ukai  <ukai@chromium.org>
+
+        Reviewed by David Levin
+
+        Add WebSocket feature in Worker
+        https://bugs.webkit.org/show_bug.cgi?id=32214
+
+        * websocket/tests/workers/resources/simple_wsh.py: Copied from LayoutTests/websocket/tests/simple_wsh.py.
+        * websocket/tests/workers/resources/worker-simple.js: Added.
+        * websocket/tests/workers/worker-simple-expected.txt: Added.
+        * websocket/tests/workers/worker-simple.html: Added.
+
 2010-01-06  Adam Bergkvist  <adam.bergkvist@ericsson.com>
 
         Reviewed by Darin Adler.
diff --git a/LayoutTests/websocket/tests/workers/resources/simple_wsh.py b/LayoutTests/websocket/tests/workers/resources/simple_wsh.py
new file mode 100644 (file)
index 0000000..fc0271c
--- /dev/null
@@ -0,0 +1,38 @@
+# Copyright (C) 2009 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+from mod_pywebsocket import msgutil
+
+
+def web_socket_do_extra_handshake(request):
+    pass # Always accept.
+
+
+def web_socket_transfer_data(request):
+    msgutil.send_message(request, 'Hello from Simple WSH.')
diff --git a/LayoutTests/websocket/tests/workers/resources/worker-simple.js b/LayoutTests/websocket/tests/workers/resources/worker-simple.js
new file mode 100644 (file)
index 0000000..9825b48
--- /dev/null
@@ -0,0 +1,37 @@
+if (self.postMessage)
+    runTests();
+else
+    onconnect = handleConnect();
+
+function handleConnect(evevnt)
+{
+    // For shared workers, create a faux postMessage() API to send message back to the parent page.
+    self.postMessage = function (message) { event.ports[0].postMessage(message); };
+    runTests();
+};
+
+function runTests()
+{
+    try {
+        postMessage("PASS: worker: init");
+        if ('WebSocket' in self)
+            postMessage("PASS: worker: WebSocket exists");
+        else
+            postMessage("PASS: worker: no WebSocket");
+        ws = new WebSocket('ws://localhost:8880/websocket/tests/workers/resources/simple');
+        ws.onopen = function() {
+            postMessage("PASS: worker: Connected.");
+        };
+        ws.onmessage = function(evt) {
+            postMessage("PASS: worker: Received: '" + evt.data + "'");
+        };
+        ws.onclose = function() {
+            postMessage("PASS: worker: Closed.");
+            postMessage("DONE");
+        };
+    } catch (e) {
+        postMessage("FAIL: worker: Unexpected exception: " + e);
+    } finally {
+        postMessage("PASS: worker: successfullyParsed:" + ws);
+    }
+};
diff --git a/LayoutTests/websocket/tests/workers/worker-simple-expected.txt b/LayoutTests/websocket/tests/workers/worker-simple-expected.txt
new file mode 100644 (file)
index 0000000..165a842
--- /dev/null
@@ -0,0 +1,13 @@
+Test for Web Socket in Worker.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+PASS: worker: init
+PASS: worker: WebSocket exists
+PASS: worker: successfullyParsed:[object WebSocket]
+PASS: worker: Connected.
+PASS: worker: Received: 'Hello from Simple WSH.'
+PASS: worker: Closed.
+DONE
+TEST COMPLETE
+
diff --git a/LayoutTests/websocket/tests/workers/worker-simple.html b/LayoutTests/websocket/tests/workers/worker-simple.html
new file mode 100644 (file)
index 0000000..bc24e72
--- /dev/null
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head></head>
+<body>
+<p>Test for Web Socket in Worker.</p>
+<p></p>
+<p>On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".</p>
+<pre id=log>
+</pre>
+<script>
+if (window.layoutTestController) {
+    layoutTestController.dumpAsText();
+    layoutTestController.waitUntilDone();
+}
+
+function log(message)
+{
+    document.getElementById("log").innerHTML += message + "\n";
+}
+
+function endTest()
+{
+    log("TEST COMPLETE");
+    if (window.layoutTestController)
+        layoutTestController.notifyDone();
+}
+var worker = new Worker('resources/worker-simple.js');
+worker.onmessage = function (evt) {
+    log(evt.data);
+    if (evt.data == "DONE")
+        endTest();
+};
+</script>
+</body>
+</html>
index 68b3fdc..f8f4c35 100644 (file)
@@ -1,3 +1,50 @@
+2010-01-06  Fumitoshi Ukai  <ukai@chromium.org>
+
+        Reviewed by David Levin.
+
+        Add WebSocket feature in Worker
+        https://bugs.webkit.org/show_bug.cgi?id=32214
+
+        Introduce ThreadableWebSocketChannel interface and add
+        WorkerThreadableWebSocketChannel for Worker.
+        WorkerThreadableWebSocketChannel uses WebSocketChannel in the
+        main thread, which is managed by Peer and communicated via Bridge.
+
+        Test: websocket/tests/workers/worker-simple.html
+
+        * GNUmakefile.am:
+        * WebCore.gypi:
+        * WebCore.pro:
+        * WebCore.vcproj/WebCore.vcproj:
+        * WebCore.xcodeproj/project.pbxproj:
+        * bindings/js/JSWebSocketConstructor.h:
+        * bindings/js/JSWorkerContextCustom.cpp:
+        (WebCore::JSWorkerContext::webSocket):
+        * bindings/v8/WorkerContextExecutionProxy.cpp:
+        (WebCore::WorkerContextExecutionProxy::convertEventTargetToV8Object):
+        * bindings/v8/custom/V8WebSocketCustom.cpp:
+        (WebCore::V8Custom::v8WebSocketConstructorCallback):
+        * bindings/v8/custom/V8WorkerContextCustom.cpp:
+        * platform/CrossThreadCopier.cpp:
+        (WebCore::::copy):
+        * platform/CrossThreadCopier.h:
+        (WebCore::):
+        * websockets/ThreadableWebSocketChannel.cpp: Added.
+        * websockets/ThreadableWebSocketChannel.h: Added.
+        * websockets/ThreadableWebSocketChannelClientWrapper.h: Added.
+        * websockets/WebSocket.cpp:
+        (WebCore::WebSocket::connect):
+        (WebCore::WebSocket::didReceiveMessage):
+        * websockets/WebSocket.h:
+        * websockets/WebSocketChannel.h:
+        (WebCore::WebSocketChannel::refThreadableWebSocketChannel):
+        (WebCore::WebSocketChannel::derefThreadableWebSocketChannel):
+        * websockets/WebSocketChannelClient.h:
+        * websockets/WebSocketHandshake.h:
+        * websockets/WorkerThreadableWebSocketChannel.cpp: Added.
+        * websockets/WorkerThreadableWebSocketChannel.h: Added.
+        * workers/WorkerContext.idl:
+
 2010-01-06  Adam Bergkvist  <adam.bergkvist@ericsson.com>
 
         Reviewed by Darin Adler.
index c142afb..67b671c 100644 (file)
@@ -3386,6 +3386,15 @@ webcore_sources += \
        WebCore/websockets/WebSocketHandshake.cpp \
        WebCore/websockets/WebSocketHandshake.h
 
+if ENABLE_WORKERS
+webcore_sources += \
+       WebCore/websockets/ThreadableWebSocketChannel.cpp \
+       WebCore/websockets/ThreadableWebSocketChannel.h \
+       WebCore/websockets/ThreadableWebSocketChannelClientWrapper.h \
+       WebCore/websockets/WorkerThreadableWebSocketChannel.cpp \
+       WebCore/websockets/WorkerThreadableWebSocketChannel.h
+endif
+
 webcoregtk_sources += \
        WebCore/platform/network/soup/SocketStreamError.h \
        WebCore/platform/network/soup/SocketStreamHandle.h \
index 339b6fb..ec1092e 100644 (file)
             'svg/SynchronizablePropertyController.cpp',
             'svg/SynchronizablePropertyController.h',
             'svg/SynchronizableTypeWrapper.h',
+            'websockets/ThreadableWebSocketChannel.cpp',
+            'websockets/ThreadableWebSocketChannel.h',
+            'websockets/ThreadableWebSocketChannelClientWrapper.h',
             'websockets/WebSocket.cpp',
             'websockets/WebSocket.h',
             'websockets/WebSocketChannel.cpp',
             'websockets/WebSocketChannelClient.h',
             'websockets/WebSocketHandshake.cpp',
             'websockets/WebSocketHandshake.h',
+            'websockets/WorkerThreadableWebSocketChannel.cpp',
+            'websockets/WorkerThreadableWebSocketChannel.h',
             'workers/AbstractWorker.cpp',
             'workers/AbstractWorker.h',
             'workers/DedicatedWorkerContext.cpp',
index 422e3ef..4d3e9e6 100644 (file)
@@ -3222,6 +3222,12 @@ SOURCES += \
     platform/network/qt/SocketStreamHandleSoup.cpp \
     bindings/js/JSWebSocketCustom.cpp \
     bindings/js/JSWebSocketConstructor.cpp
+
+contains(DEFINES, ENABLE_WORKERS=1) {
+SOURCES += \
+    websockets/ThreadableWebSocketChannel.cpp \
+    websockets/WorkerThreadableWebSocketChannel.cpp
+}
 }
 
 # GENERATOR 1: IDL compiler
index f0eac43..9e30a53 100644 (file)
                        Name="websockets"\r
                        >\r
                        <File\r
+                               RelativePath="..\websockets\ThreadableWebSocketChannel.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\websockets\ThreadableWebSocketChannel.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\websockets\ThreadableWebSocketChannelClientWrapper.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
                                RelativePath="..\websockets\WebSocket.cpp"\r
                                >\r
                        </File>\r
                                RelativePath="..\websockets\WebSocketHandshake.h"\r
                                >\r
                        </File>\r
+                       <File\r
+                               RelativePath="..\websockets\WorkerThreadableWebSocketChannel.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\websockets\WorkerThreadableWebSocketChannel.h"\r
+                               >\r
+                       </File>\r
                </Filter>\r
                <File\r
                        RelativePath="..\config.h"\r
index 6918033..2770b1e 100644 (file)
                510D4A4E103177A20049EA54 /* WebSocketChannel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 510D4A47103177A20049EA54 /* WebSocketChannel.cpp */; };
                510D4A4F103177A20049EA54 /* WebSocketChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = 510D4A48103177A20049EA54 /* WebSocketChannel.h */; };
                510D4A50103177A20049EA54 /* WebSocketChannelClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 510D4A49103177A20049EA54 /* WebSocketChannelClient.h */; };
+               5112247210CFB8C6008099D7 /* ThreadableWebSocketChannel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5112247110CFB8C6008099D7 /* ThreadableWebSocketChannel.cpp */; };
+               5112247410CFB8D8008099D7 /* ThreadableWebSocketChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = 5112247310CFB8D8008099D7 /* ThreadableWebSocketChannel.h */; };
+               5112247610CFB8E8008099D7 /* ThreadableWebSocketChannelClientWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 5112247510CFB8E8008099D7 /* ThreadableWebSocketChannelClientWrapper.h */; };
+               5112247810CFB8F4008099D7 /* WorkerThreadableWebSocketChannel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5112247710CFB8F4008099D7 /* WorkerThreadableWebSocketChannel.cpp */; };
+               5112247A10CFB8FF008099D7 /* WorkerThreadableWebSocketChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = 5112247910CFB8FF008099D7 /* WorkerThreadableWebSocketChannel.h */; };
                5116D9770CF177BD00C2B84D /* DatabaseDetails.h in Headers */ = {isa = PBXBuildFile; fileRef = 5116D9750CF177BD00C2B84D /* DatabaseDetails.h */; settings = {ATTRIBUTES = (Private, ); }; };
                511F23170DC160DA004F0032 /* LocalStorageTask.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 511F23130DC160DA004F0032 /* LocalStorageTask.cpp */; };
                511F23180DC160DA004F0032 /* LocalStorageTask.h in Headers */ = {isa = PBXBuildFile; fileRef = 511F23140DC160DA004F0032 /* LocalStorageTask.h */; };
                510D4A47103177A20049EA54 /* WebSocketChannel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebSocketChannel.cpp; sourceTree = "<group>"; };
                510D4A48103177A20049EA54 /* WebSocketChannel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebSocketChannel.h; sourceTree = "<group>"; };
                510D4A49103177A20049EA54 /* WebSocketChannelClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebSocketChannelClient.h; sourceTree = "<group>"; };
+               5112247110CFB8C6008099D7 /* ThreadableWebSocketChannel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ThreadableWebSocketChannel.cpp; sourceTree = "<group>"; };
+               5112247310CFB8D8008099D7 /* ThreadableWebSocketChannel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadableWebSocketChannel.h; sourceTree = "<group>"; };
+               5112247510CFB8E8008099D7 /* ThreadableWebSocketChannelClientWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadableWebSocketChannelClientWrapper.h; sourceTree = "<group>"; };
+               5112247710CFB8F4008099D7 /* WorkerThreadableWebSocketChannel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WorkerThreadableWebSocketChannel.cpp; sourceTree = "<group>"; };
+               5112247910CFB8FF008099D7 /* WorkerThreadableWebSocketChannel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WorkerThreadableWebSocketChannel.h; sourceTree = "<group>"; };
                5116D9750CF177BD00C2B84D /* DatabaseDetails.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DatabaseDetails.h; sourceTree = "<group>"; };
                511F23130DC160DA004F0032 /* LocalStorageTask.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LocalStorageTask.cpp; sourceTree = "<group>"; };
                511F23140DC160DA004F0032 /* LocalStorageTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LocalStorageTask.h; sourceTree = "<group>"; };
                518A34BD1026C831001B6896 /* websockets */ = {
                        isa = PBXGroup;
                        children = (
+                               5112247910CFB8FF008099D7 /* WorkerThreadableWebSocketChannel.h */,
+                               5112247710CFB8F4008099D7 /* WorkerThreadableWebSocketChannel.cpp */,
+                               5112247510CFB8E8008099D7 /* ThreadableWebSocketChannelClientWrapper.h */,
+                               5112247310CFB8D8008099D7 /* ThreadableWebSocketChannel.h */,
+                               5112247110CFB8C6008099D7 /* ThreadableWebSocketChannel.cpp */,
                                518A34BE1026C831001B6896 /* WebSocket.cpp */,
                                518A34BF1026C831001B6896 /* WebSocket.h */,
                                518A34C01026C831001B6896 /* WebSocket.idl */,
                                08735FB910E91232006D6FAD /* SVGMarkerLayoutInfo.h in Headers */,
                                08385FF610F0186000BFE07B /* SVGMarkerData.h in Headers */,
                                0AFDAC3D10F5448C00E1F3D2 /* PluginWidget.h in Headers */,
+                               5112247410CFB8D8008099D7 /* ThreadableWebSocketChannel.h in Headers */,
+                               5112247610CFB8E8008099D7 /* ThreadableWebSocketChannelClientWrapper.h in Headers */,
+                               5112247A10CFB8FF008099D7 /* WorkerThreadableWebSocketChannel.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                BC56CB2110D5AC8000A77C64 /* GeolocationController.cpp in Sources */,
                                08735FB810E91232006D6FAD /* SVGMarkerLayoutInfo.cpp in Sources */,
                                0AFDAC3B10F5448300E1F3D2 /* PluginWidgetMac.mm in Sources */,
+                               5112247210CFB8C6008099D7 /* ThreadableWebSocketChannel.cpp in Sources */,
+                               5112247810CFB8F4008099D7 /* WorkerThreadableWebSocketChannel.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index 069647a..633e612 100644 (file)
@@ -31,6 +31,8 @@
 #ifndef JSWebSocketConstructor_h
 #define JSWebSocketConstructor_h
 
+#if ENABLE(WEB_SOCKETS)
+
 #include "JSDOMBinding.h"
 
 namespace WebCore {
@@ -45,6 +47,8 @@ class JSWebSocketConstructor : public DOMConstructorObject {
     virtual const JSC::ClassInfo* classInfo() const { return &s_info; }
 };
 
-}  // namespace WebCore
+} // namespace WebCore
+
+#endif // ENABLE(WEB_SOCKETS)
 
-#endif  // JSWebSocketConstructor_h
+#endif // JSWebSocketConstructor_h
index 490d9b1..ab28674 100644 (file)
 #include "JSDOMBinding.h"
 #include "JSDOMGlobalObject.h"
 #include "JSEventListener.h"
+#include "JSEventSourceConstructor.h"
 #include "JSMessageChannelConstructor.h"
 #include "JSMessagePort.h"
+#include "JSWebSocketConstructor.h"
 #include "JSWorkerLocation.h"
 #include "JSWorkerNavigator.h"
 #include "JSXMLHttpRequestConstructor.h"
 #include "WorkerNavigator.h"
 #include <interpreter/Interpreter.h>
 
-#if ENABLE(EVENTSOURCE)
-#include "JSEventSourceConstructor.h"
-#endif
-
 using namespace JSC;
 
 namespace WebCore {
@@ -93,6 +91,13 @@ JSValue JSWorkerContext::xmlHttpRequest(ExecState* exec) const
     return getDOMConstructor<JSXMLHttpRequestConstructor>(exec, this);
 }
 
+#if ENABLE(WEB_SOCKETS)
+JSValue JSWorkerContext::webSocket(ExecState* exec) const
+{
+    return getDOMConstructor<JSWebSocketConstructor>(exec, this);
+}
+#endif
+
 JSValue JSWorkerContext::importScripts(ExecState* exec, const ArgList& args)
 {
     if (!args.size())
index 412fde0..7e3c543 100644 (file)
@@ -319,6 +319,12 @@ v8::Handle<v8::Value> WorkerContextExecutionProxy::convertEventTargetToV8Object(
     if (mp)
         return convertToV8Object(V8ClassIndex::MESSAGEPORT, mp);
 
+#if ENABLE(WEB_SOCKETS)
+    WebSocket* webSocket = target->toWebSocket();
+    if (webSocket)
+        return convertToV8Object(V8ClassIndex::WEBSOCKET, webSocket);
+#endif
+
     ASSERT_NOT_REACHED();
     return v8::Handle<v8::Value>();
 }
index c9b4136..855ab7d 100644 (file)
@@ -93,14 +93,9 @@ v8::Handle<v8::Value> V8Custom::v8WebSocketConstructorCallback(const v8::Argumen
         return throwError("Empty URL", V8Proxy::SyntaxError);
 
     // Get the script execution context.
-    ScriptExecutionContext* context = 0;
-    // TODO: Workers
-    if (!context) {
-        Frame* frame = V8Proxy::retrieveFrameForCurrentContext();
-        if (!frame)
-            return throwError("WebSocket constructor's associated frame is not available", V8Proxy::ReferenceError);
-        context = frame->document();
-    }
+    ScriptExecutionContext* context = getScriptExecutionContext();
+    if (!context)
+        return throwError("WebSocket constructor's associated frame is not available", V8Proxy::ReferenceError);
 
     const KURL& url = context->completeURL(toWebCoreString(urlstring));
 
index b4a6381..d257fe4 100644 (file)
@@ -42,6 +42,7 @@
 #include "V8Proxy.h"
 #include "V8Utilities.h"
 #include "V8WorkerContextEventListener.h"
+#include "WebSocket.h"
 #include "WorkerContext.h"
 #include "WorkerContextExecutionProxy.h"
 
index d02da6c..c1979c4 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "CrossThreadCopier.h"
 
+#include "KURL.h"
 #include "PlatformString.h"
 #include "ResourceError.h"
 #include "ResourceRequest.h"
 
 namespace WebCore {
 
+CrossThreadCopierBase<false, KURL>::Type CrossThreadCopierBase<false, KURL>::copy(const KURL& url)
+{
+    return url.copy();
+}
+
 CrossThreadCopierBase<false, String>::Type CrossThreadCopierBase<false, String>::copy(const String& str)
 {
     return str.crossThreadString();
index 2bdf57d..591a545 100644 (file)
@@ -40,6 +40,7 @@
 
 namespace WebCore {
 
+    class KURL;
     class ResourceError;
     class ResourceRequest;
     class ResourceResponse;
@@ -94,6 +95,11 @@ namespace WebCore {
         }
     };
 
+    template<> struct CrossThreadCopierBase<false, KURL> {
+        typedef KURL Type;
+        static Type copy(const KURL&);
+    };
+
     template<> struct CrossThreadCopierBase<false, String> {
         typedef String Type;
         static Type copy(const String&);
diff --git a/WebCore/websockets/ThreadableWebSocketChannel.cpp b/WebCore/websockets/ThreadableWebSocketChannel.cpp
new file mode 100644 (file)
index 0000000..28b9263
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2009 Google Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEB_SOCKETS)
+
+#include "ThreadableWebSocketChannel.h"
+
+#include "PlatformString.h"
+#include "ScriptExecutionContext.h"
+#include "ThreadableWebSocketChannelClientWrapper.h"
+#include "WebSocketChannel.h"
+#include "WebSocketChannelClient.h"
+#include "WorkerContext.h"
+#include "WorkerRunLoop.h"
+#include "WorkerThread.h"
+#include "WorkerThreadableWebSocketChannel.h"
+
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+static const char webSocketChannelMode[] = "webSocketChannelMode";
+
+PassRefPtr<ThreadableWebSocketChannel> ThreadableWebSocketChannel::create(ScriptExecutionContext* context, WebSocketChannelClient* client, const KURL& url, const String& protocol)
+{
+    ASSERT(context);
+    ASSERT(client);
+
+#if ENABLE(WORKERS)
+    if (context->isWorkerContext()) {
+        WorkerContext* workerContext = static_cast<WorkerContext*>(context);
+        WorkerRunLoop& runLoop = workerContext->thread()->runLoop();
+        String mode = webSocketChannelMode;
+        mode.append(String::number(runLoop.createUniqueId()));
+        return WorkerThreadableWebSocketChannel::create(workerContext, client, mode, url, protocol);
+    }
+#endif // ENABLE(WORKERS)
+
+    ASSERT(context->isDocument());
+    return WebSocketChannel::create(context, client, url, protocol);
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_SOCKETS)
diff --git a/WebCore/websockets/ThreadableWebSocketChannel.h b/WebCore/websockets/ThreadableWebSocketChannel.h
new file mode 100644 (file)
index 0000000..74ea4b4
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2009 Google Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ThreadableWebSocketChannel_h
+#define ThreadableWebSocketChannel_h
+
+#if ENABLE(WEB_SOCKETS)
+
+#include <wtf/Noncopyable.h>
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+class KURL;
+class ScriptExecutionContext;
+class String;
+class WebSocketChannelClient;
+
+class ThreadableWebSocketChannel : public Noncopyable {
+public:
+    static PassRefPtr<ThreadableWebSocketChannel> create(ScriptExecutionContext*, WebSocketChannelClient*, const KURL&, const String& protocol);
+
+    virtual void connect() = 0;
+    virtual bool send(const String& message) = 0;
+    virtual unsigned long bufferedAmount() const = 0;
+    virtual void close() = 0;
+    virtual void disconnect() = 0; // Will suppress didClose().
+
+    void ref() { refThreadableWebSocketChannel(); }
+    void deref() { derefThreadableWebSocketChannel(); }
+
+protected:
+    virtual ~ThreadableWebSocketChannel() { }
+    virtual void refThreadableWebSocketChannel() = 0;
+    virtual void derefThreadableWebSocketChannel() = 0;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_SOCKETS)
+
+#endif // ThreadableWebSocketChannel_h
diff --git a/WebCore/websockets/ThreadableWebSocketChannelClientWrapper.h b/WebCore/websockets/ThreadableWebSocketChannelClientWrapper.h
new file mode 100644 (file)
index 0000000..8bf51fa
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2009 Google Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ThreadableWebSocketChannelClientWrapper_h
+#define ThreadableWebSocketChannelClientWrapper_h
+
+#if ENABLE(WEB_SOCKETS)
+
+#include "WebSocketChannelClient.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/Threading.h>
+
+namespace WebCore {
+
+class String;
+
+class ThreadableWebSocketChannelClientWrapper : public ThreadSafeShared<ThreadableWebSocketChannelClientWrapper> {
+public:
+    static PassRefPtr<ThreadableWebSocketChannelClientWrapper> create(WebSocketChannelClient* client)
+    {
+        return adoptRef(new ThreadableWebSocketChannelClientWrapper(client));
+    }
+
+    void clearSyncMethodDone()
+    {
+        m_syncMethodDone = false;
+    }
+    void setSyncMethodDone()
+    {
+        m_syncMethodDone = true;
+    }
+
+    bool syncMethodDone() const
+    {
+        return m_syncMethodDone;
+    }
+
+    bool sent() const
+    {
+        return m_sent;
+    }
+    void setSent(bool sent)
+    {
+        m_sent = sent;
+        m_syncMethodDone = true;
+    }
+
+    unsigned long bufferedAmount() const
+    {
+        return m_bufferedAmount;
+    }
+    void setBufferedAmount(unsigned long bufferedAmount)
+    {
+        m_bufferedAmount = bufferedAmount;
+        m_syncMethodDone = true;
+    }
+
+    void clearClient()
+    {
+        m_client = 0;
+    }
+
+    void didConnect()
+    {
+        if (m_client)
+            m_client->didConnect();
+    }
+
+    void didReceiveMessage(const String& msg)
+    {
+        if (m_client)
+            m_client->didReceiveMessage(msg);
+    }
+
+    void didClose()
+    {
+        if (m_client)
+            m_client->didClose();
+    }
+
+protected:
+    ThreadableWebSocketChannelClientWrapper(WebSocketChannelClient* client)
+        : m_client(client)
+        , m_syncMethodDone(false)
+        , m_sent(false)
+        , m_bufferedAmount(0)
+    {
+    }
+
+    WebSocketChannelClient* m_client;
+    bool m_syncMethodDone;
+    bool m_sent;
+    unsigned long m_bufferedAmount;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_SOCKETS)
+
+#endif // ThreadableWebSocketChannelClientWrapper_h
index bd62cfa..0435490 100644 (file)
@@ -44,6 +44,7 @@
 #include "MessageEvent.h"
 #include "ScriptExecutionContext.h"
 #include "StringBuilder.h"
+#include "ThreadableWebSocketChannel.h"
 #include "WebSocketChannel.h"
 #include <wtf/StdLibExtras.h>
 
@@ -148,7 +149,7 @@ void WebSocket::connect(const KURL& url, const String& protocol, ExceptionCode&
         return;
     }
 
-    m_channel = WebSocketChannel::create(scriptExecutionContext(), this, m_url, m_protocol);
+    m_channel = ThreadableWebSocketChannel::create(scriptExecutionContext(), this, m_url, m_protocol);
     m_channel->connect();
 }
 
@@ -214,7 +215,6 @@ void WebSocket::didReceiveMessage(const String& msg)
     if (m_state != OPEN || !scriptExecutionContext())
         return;
     RefPtr<MessageEvent> evt = MessageEvent::create();
-    // FIXME: origin, lastEventId, source, messagePort.
     evt->initMessageEvent(eventNames().messageEvent, false, false, SerializedScriptValue::create(msg), "", "", 0, 0);
     dispatchEvent(evt);
 }
index 9ecbed7..18e2b25 100644 (file)
@@ -46,7 +46,7 @@
 namespace WebCore {
 
     class String;
-    class WebSocketChannel;
+    class ThreadableWebSocketChannel;
 
     class WebSocket : public RefCounted<WebSocket>, public EventTarget, public ActiveDOMObject, public WebSocketChannelClient {
     public:
@@ -83,20 +83,12 @@ namespace WebCore {
 
         virtual ScriptExecutionContext* scriptExecutionContext() const;
 
-        // ActiveDOMObject
-        //  virtual bool hasPendingActivity() const;
-        // virtual void contextDestroyed();
-        // virtual bool canSuspend() const;
-        // virtual void suspend();
-        // virtual void resume();
-        // virtual void stop();
-
         using RefCounted<WebSocket>::ref;
         using RefCounted<WebSocket>::deref;
 
         // WebSocketChannelClient
         virtual void didConnect();
-        virtual void didReceiveMessage(const String& msg);
+        virtual void didReceiveMessage(const String& message);
         virtual void didClose();
 
     private:
@@ -111,7 +103,7 @@ namespace WebCore {
         void dispatchMessageEvent(Event*);
         void dispatchCloseEvent(Event*);
 
-        RefPtr<WebSocketChannel> m_channel;
+        RefPtr<ThreadableWebSocketChannel> m_channel;
 
         State m_state;
         KURL m_url;
@@ -119,8 +111,8 @@ namespace WebCore {
         EventTargetData m_eventTargetData;
     };
 
-}  // namespace WebCore
+} // namespace WebCore
 
-#endif  // ENABLE(WEB_SOCKETS)
+#endif // ENABLE(WEB_SOCKETS)
 
-#endif  // WebSocket_h
+#endif // WebSocket_h
index 14b1e8c..7ec826c 100644 (file)
@@ -34,6 +34,7 @@
 #if ENABLE(WEB_SOCKETS)
 
 #include "SocketStreamHandleClient.h"
+#include "ThreadableWebSocketChannel.h"
 #include "WebSocketHandshake.h"
 #include <wtf/RefCounted.h>
 
@@ -45,16 +46,16 @@ namespace WebCore {
     class SocketStreamError;
     class WebSocketChannelClient;
 
-    class WebSocketChannel : public RefCounted<WebSocketChannel>, public SocketStreamHandleClient {
+    class WebSocketChannel : public RefCounted<WebSocketChannel>, public SocketStreamHandleClient, public ThreadableWebSocketChannel {
     public:
         static PassRefPtr<WebSocketChannel> create(ScriptExecutionContext* context, WebSocketChannelClient* client, const KURL& url, const String& protocol) { return adoptRef(new WebSocketChannel(context, client, url, protocol)); }
         virtual ~WebSocketChannel();
 
-        void connect();
-        bool send(const String& msg);
-        unsigned long bufferedAmount() const;
-        void close();
-        void disconnect(); // Will suppress didClose().
+        virtual void connect();
+        virtual bool send(const String& message);
+        virtual unsigned long bufferedAmount() const;
+        virtual void close();
+        virtual void disconnect(); // Will suppress didClose().
 
         virtual void didOpen(SocketStreamHandle*);
         virtual void didClose(SocketStreamHandle*);
@@ -63,8 +64,15 @@ namespace WebCore {
         virtual void didReceiveAuthenticationChallenge(SocketStreamHandle*, const AuthenticationChallenge&);
         virtual void didCancelAuthenticationChallenge(SocketStreamHandle*, const AuthenticationChallenge&);
 
+        using RefCounted<WebSocketChannel>::ref;
+        using RefCounted<WebSocketChannel>::deref;
+
+    protected:
+        virtual void refThreadableWebSocketChannel() { ref(); }
+        virtual void derefThreadableWebSocketChannel() { deref(); }
+
     private:
-        WebSocketChannel(ScriptExecutionContext*, WebSocketChannelClient*, const KURL&, const String&);
+        WebSocketChannel(ScriptExecutionContext*, WebSocketChannelClient*, const KURL&, const String& protocol);
 
         bool appendToBuffer(const char* data, int len);
         void skipBuffer(int len);
@@ -78,8 +86,8 @@ namespace WebCore {
         unsigned long m_unhandledBufferSize;
     };
 
-}  // namespace WebCore
+} // namespace WebCore
 
-#endif  // ENABLE(WEB_SOCKETS)
+#endif // ENABLE(WEB_SOCKETS)
 
-#endif  // WebSocketChannel_h
+#endif // WebSocketChannel_h
index 463cada..163070f 100644 (file)
@@ -46,8 +46,8 @@ namespace WebCore {
         WebSocketChannelClient() { }
     };
 
-}  // namespace WebCore
+} // namespace WebCore
 
-#endif  // ENABLE(WEB_SOCKETS)
+#endif // ENABLE(WEB_SOCKETS)
 
-#endif  // WebSocketChannelClient_h
+#endif // WebSocketChannelClient_h
index d5dbe68..bda320a 100644 (file)
@@ -106,8 +106,8 @@ namespace WebCore {
         String m_setCookie2;
     };
 
-}  // namespace WebCore
+} // namespace WebCore
 
-#endif  // ENABLE(WEB_SOCKETS)
+#endif // ENABLE(WEB_SOCKETS)
 
-#endif  // WebSocketHandshake_h
+#endif // WebSocketHandshake_h
diff --git a/WebCore/websockets/WorkerThreadableWebSocketChannel.cpp b/WebCore/websockets/WorkerThreadableWebSocketChannel.cpp
new file mode 100644 (file)
index 0000000..b15c151
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2009 Google Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEB_SOCKETS) && ENABLE(WORKERS)
+
+#include "WorkerThreadableWebSocketChannel.h"
+
+#include "GenericWorkerTask.h"
+#include "PlatformString.h"
+#include "ScriptExecutionContext.h"
+#include "ThreadableWebSocketChannelClientWrapper.h"
+#include "WebSocketChannel.h"
+#include "WebSocketChannelClient.h"
+#include "WorkerContext.h"
+#include "WorkerLoaderProxy.h"
+#include "WorkerRunLoop.h"
+#include "WorkerThread.h"
+
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+WorkerThreadableWebSocketChannel::WorkerThreadableWebSocketChannel(WorkerContext* context, WebSocketChannelClient* client, const String& taskMode, const KURL& url, const String& protocol)
+    : m_workerContext(context)
+    , m_workerClientWrapper(ThreadableWebSocketChannelClientWrapper::create(client))
+    , m_bridge(new Bridge(m_workerClientWrapper, m_workerContext, taskMode, url, protocol))
+{
+}
+
+WorkerThreadableWebSocketChannel::~WorkerThreadableWebSocketChannel()
+{
+    if (m_bridge)
+        m_bridge->disconnect();
+}
+
+void WorkerThreadableWebSocketChannel::connect()
+{
+    if (m_bridge)
+        m_bridge->connect();
+}
+
+bool WorkerThreadableWebSocketChannel::send(const String& message)
+{
+    if (!m_bridge)
+        return false;
+    return m_bridge->send(message);
+}
+
+unsigned long WorkerThreadableWebSocketChannel::bufferedAmount() const
+{
+    if (!m_bridge)
+        return 0;
+    return m_bridge->bufferedAmount();
+}
+
+void WorkerThreadableWebSocketChannel::close()
+{
+    if (!m_bridge)
+        m_bridge->close();
+}
+
+void WorkerThreadableWebSocketChannel::disconnect()
+{
+    m_bridge->disconnect();
+    m_bridge.clear();
+}
+
+WorkerThreadableWebSocketChannel::Peer::Peer(RefPtr<ThreadSafeShared<ThreadableWebSocketChannelClientWrapper> > clientWrapper, WorkerLoaderProxy& loaderProxy, ScriptExecutionContext* context, const String& taskMode, const KURL& url, const String& protocol)
+    : m_workerClientWrapper(clientWrapper)
+    , m_loaderProxy(loaderProxy)
+    , m_mainWebSocketChannel(WebSocketChannel::create(context, this, url, protocol))
+    , m_taskMode(taskMode)
+{
+    ASSERT(isMainThread());
+}
+
+WorkerThreadableWebSocketChannel::Peer::~Peer()
+{
+    ASSERT(isMainThread());
+    if (m_mainWebSocketChannel)
+        m_mainWebSocketChannel->disconnect();
+}
+
+void WorkerThreadableWebSocketChannel::Peer::connect()
+{
+    ASSERT(isMainThread());
+    if (!m_mainWebSocketChannel)
+        return;
+    m_mainWebSocketChannel->connect();
+}
+
+static void workerContextDidSend(ScriptExecutionContext* context, RefPtr<ThreadSafeShared<ThreadableWebSocketChannelClientWrapper> > workerClientWrapper, bool sent)
+{
+    ASSERT_UNUSED(context, context->isWorkerContext());
+    static_cast<ThreadableWebSocketChannelClientWrapper*>(workerClientWrapper.get())->setSent(sent);
+}
+
+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);
+}
+
+static void workerContextDidGetBufferedAmount(ScriptExecutionContext* context, RefPtr<ThreadSafeShared<ThreadableWebSocketChannelClientWrapper> > workerClientWrapper, unsigned long bufferedAmount)
+{
+    ASSERT_UNUSED(context, context->isWorkerContext());
+    static_cast<ThreadableWebSocketChannelClientWrapper*>(workerClientWrapper.get())->setBufferedAmount(bufferedAmount);
+}
+
+void WorkerThreadableWebSocketChannel::Peer::bufferedAmount()
+{
+    ASSERT(isMainThread());
+    if (!m_mainWebSocketChannel || !m_workerClientWrapper)
+        return;
+    unsigned long bufferedAmount = m_mainWebSocketChannel->bufferedAmount();
+    m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&workerContextDidGetBufferedAmount, m_workerClientWrapper, bufferedAmount), m_taskMode);
+}
+
+void WorkerThreadableWebSocketChannel::Peer::close()
+{
+    ASSERT(isMainThread());
+    if (!m_mainWebSocketChannel)
+        return;
+    m_mainWebSocketChannel->close();
+    m_mainWebSocketChannel = 0;
+}
+
+void WorkerThreadableWebSocketChannel::Peer::disconnect()
+{
+    ASSERT(isMainThread());
+    if (!m_mainWebSocketChannel)
+        return;
+    m_mainWebSocketChannel->disconnect();
+    m_mainWebSocketChannel = 0;
+}
+
+static void workerContextDidConnect(ScriptExecutionContext* context, RefPtr<ThreadSafeShared<ThreadableWebSocketChannelClientWrapper> > workerClientWrapper)
+{
+    ASSERT_UNUSED(context, context->isWorkerContext());
+    static_cast<ThreadableWebSocketChannelClientWrapper*>(workerClientWrapper.get())->didConnect();
+}
+
+void WorkerThreadableWebSocketChannel::Peer::didConnect()
+{
+    ASSERT(isMainThread());
+    m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&workerContextDidConnect, m_workerClientWrapper), m_taskMode);
+}
+
+static void workerContextDidReceiveMessage(ScriptExecutionContext* context, RefPtr<ThreadSafeShared<ThreadableWebSocketChannelClientWrapper> > workerClientWrapper, const String& message)
+{
+    ASSERT_UNUSED(context, context->isWorkerContext());
+    static_cast<ThreadableWebSocketChannelClientWrapper*>(workerClientWrapper.get())->didReceiveMessage(message);
+}
+
+void WorkerThreadableWebSocketChannel::Peer::didReceiveMessage(const String& message)
+{
+    ASSERT(isMainThread());
+    m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&workerContextDidReceiveMessage, m_workerClientWrapper, message), m_taskMode);
+}
+
+static void workerContextDidClose(ScriptExecutionContext* context, RefPtr<ThreadSafeShared<ThreadableWebSocketChannelClientWrapper> > workerClientWrapper)
+{
+    ASSERT_UNUSED(context, context->isWorkerContext());
+    static_cast<ThreadableWebSocketChannelClientWrapper*>(workerClientWrapper.get())->didClose();
+}
+
+void WorkerThreadableWebSocketChannel::Peer::didClose()
+{
+    ASSERT(isMainThread());
+    m_mainWebSocketChannel = 0;
+    m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&workerContextDidClose, m_workerClientWrapper), m_taskMode);
+}
+
+void WorkerThreadableWebSocketChannel::Bridge::setWebSocketChannel(ScriptExecutionContext* context, Bridge* thisPtr, Peer* peer, RefPtr<ThreadSafeShared<ThreadableWebSocketChannelClientWrapper> > workerClientWrapper)
+{
+    ASSERT_UNUSED(context, context->isWorkerContext());
+    thisPtr->m_peer = peer;
+    static_cast<ThreadableWebSocketChannelClientWrapper*>(workerClientWrapper.get())->setSyncMethodDone();
+}
+
+void WorkerThreadableWebSocketChannel::Bridge::mainThreadCreateWebSocketChannel(ScriptExecutionContext* context, Bridge* thisPtr, RefPtr<ThreadSafeShared<ThreadableWebSocketChannelClientWrapper> > clientWrapper, const String& taskMode, const KURL& url, const String& protocol)
+{
+    ASSERT(isMainThread());
+    ASSERT_UNUSED(context, context->isDocument());
+
+    Peer* peer = Peer::create(clientWrapper, thisPtr->m_loaderProxy, context, taskMode, url, protocol);
+    thisPtr->m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&Bridge::setWebSocketChannel, thisPtr, peer, clientWrapper), taskMode);
+}
+
+WorkerThreadableWebSocketChannel::Bridge::Bridge(PassRefPtr<ThreadableWebSocketChannelClientWrapper> workerClientWrapper, PassRefPtr<WorkerContext> workerContext, const String& taskMode, const KURL& url, const String& protocol)
+    : m_workerClientWrapper(workerClientWrapper)
+    , m_workerContext(workerContext)
+    , m_loaderProxy(m_workerContext->thread()->workerLoaderProxy())
+    , m_taskMode(taskMode)
+    , m_peer(0)
+{
+    ASSERT(context->isWorkerContext());
+    ASSERT(m_workerClientWrapper.get());
+    setMethodNotCompleted();
+    m_loaderProxy.postTaskToLoader(createCallbackTask(&Bridge::mainThreadCreateWebSocketChannel, this, m_workerClientWrapper, m_taskMode, url, protocol));
+    waitForMethodCompletion();
+    ASSERT(m_peer);
+}
+
+WorkerThreadableWebSocketChannel::Bridge::~Bridge()
+{
+    disconnect();
+}
+
+void WorkerThreadableWebSocketChannel::mainThreadConnect(ScriptExecutionContext* context, Peer* peer)
+{
+    ASSERT(isMainThread());
+    ASSERT_UNUSED(context, context->isDocument());
+    ASSERT(peer);
+
+    peer->connect();
+}
+
+void WorkerThreadableWebSocketChannel::Bridge::connect()
+{
+    ASSERT(m_workerClientWrapper);
+    ASSERT(m_peer);
+    m_loaderProxy.postTaskToLoader(createCallbackTask(&WorkerThreadableWebSocketChannel::mainThreadConnect, m_peer));
+}
+
+void WorkerThreadableWebSocketChannel::mainThreadSend(ScriptExecutionContext* context, Peer* peer, const String& message)
+{
+    ASSERT(isMainThread());
+    ASSERT_UNUSED(context, context->isDocument());
+    ASSERT(peer);
+
+    peer->send(message);
+}
+
+bool WorkerThreadableWebSocketChannel::Bridge::send(const String& message)
+{
+    if (!m_workerClientWrapper)
+        return false;
+    ASSERT(m_peer);
+    setMethodNotCompleted();
+    m_loaderProxy.postTaskToLoader(createCallbackTask(&WorkerThreadableWebSocketChannel::mainThreadSend, m_peer, message));
+    waitForMethodCompletion();
+    ThreadableWebSocketChannelClientWrapper* clientWrapper = static_cast<ThreadableWebSocketChannelClientWrapper*>(m_workerClientWrapper.get());
+    return clientWrapper && clientWrapper->sent();
+}
+
+void WorkerThreadableWebSocketChannel::mainThreadBufferedAmount(ScriptExecutionContext* context, Peer* peer)
+{
+    ASSERT(isMainThread());
+    ASSERT_UNUSED(context, context->isDocument());
+    ASSERT(peer);
+
+    peer->bufferedAmount();
+}
+
+unsigned long WorkerThreadableWebSocketChannel::Bridge::bufferedAmount()
+{
+    if (!m_workerClientWrapper)
+        return 0;
+    ASSERT(m_peer);
+    setMethodNotCompleted();
+    m_loaderProxy.postTaskToLoader(createCallbackTask(&WorkerThreadableWebSocketChannel::mainThreadBufferedAmount, m_peer));
+    waitForMethodCompletion();
+    ThreadableWebSocketChannelClientWrapper* clientWrapper = static_cast<ThreadableWebSocketChannelClientWrapper*>(m_workerClientWrapper.get());
+    if (clientWrapper)
+        return clientWrapper->bufferedAmount();
+    return 0;
+}
+
+void WorkerThreadableWebSocketChannel::mainThreadClose(ScriptExecutionContext* context, Peer* peer)
+{
+    ASSERT(isMainThread());
+    ASSERT_UNUSED(context, context->isDocument());
+    ASSERT(peer);
+
+    peer->close();
+}
+
+void WorkerThreadableWebSocketChannel::Bridge::close()
+{
+    ASSERT(m_peer);
+    m_loaderProxy.postTaskToLoader(createCallbackTask(&WorkerThreadableWebSocketChannel::mainThreadClose, m_peer));
+}
+
+void WorkerThreadableWebSocketChannel::mainThreadDestroy(ScriptExecutionContext* context, Peer* peer)
+{
+    ASSERT(isMainThread());
+    ASSERT_UNUSED(context, context->isDocument());
+    ASSERT(peer);
+
+    delete peer;
+}
+
+void WorkerThreadableWebSocketChannel::Bridge::disconnect()
+{
+    clearClientWrapper();
+    if (m_peer) {
+        Peer* peer = m_peer;
+        m_peer = 0;
+        m_loaderProxy.postTaskToLoader(createCallbackTask(&mainThreadDestroy, peer));
+    }
+}
+
+void WorkerThreadableWebSocketChannel::Bridge::clearClientWrapper()
+{
+    static_cast<ThreadableWebSocketChannelClientWrapper*>(m_workerClientWrapper.get())->clearClient();
+}
+
+void WorkerThreadableWebSocketChannel::Bridge::setMethodNotCompleted()
+{
+    ASSERT(m_workerClientWrapper);
+    static_cast<ThreadableWebSocketChannelClientWrapper*>(m_workerClientWrapper.get())->clearSyncMethodDone();
+}
+
+void WorkerThreadableWebSocketChannel::Bridge::waitForMethodCompletion()
+{
+    WorkerRunLoop& runLoop = m_workerContext->thread()->runLoop();
+    MessageQueueWaitResult result = MessageQueueMessageReceived;
+    ThreadableWebSocketChannelClientWrapper* clientWrapper = static_cast<ThreadableWebSocketChannelClientWrapper*>(m_workerClientWrapper.get());
+    while (clientWrapper && !clientWrapper->syncMethodDone() && result != MessageQueueTerminated) {
+        result = runLoop.runInMode(m_workerContext.get(), m_taskMode);
+        clientWrapper = static_cast<ThreadableWebSocketChannelClientWrapper*>(m_workerClientWrapper.get());
+    }
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_SOCKETS)
diff --git a/WebCore/websockets/WorkerThreadableWebSocketChannel.h b/WebCore/websockets/WorkerThreadableWebSocketChannel.h
new file mode 100644 (file)
index 0000000..35bebc3
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2009 Google Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WorkerThreadableWebSocketChannel_h
+#define WorkerThreadableWebSocketChannel_h
+
+#if ENABLE(WEB_SOCKETS) && ENABLE(WORKERS)
+
+#include "PlatformString.h"
+#include "ThreadableWebSocketChannel.h"
+#include "WebSocketChannelClient.h"
+
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Threading.h>
+
+namespace WebCore {
+
+class KURL;
+class ScriptExecutionContext;
+class ThreadableWebSocketChannelClientWrapper;
+class WorkerContext;
+class WorkerLoaderProxy;
+class WorkerRunLoop;
+
+class WorkerThreadableWebSocketChannel : public RefCounted<WorkerThreadableWebSocketChannel>, public ThreadableWebSocketChannel {
+public:
+    static PassRefPtr<ThreadableWebSocketChannel> create(WorkerContext* workerContext, WebSocketChannelClient* client, const String& taskMode, const KURL& url, const String& protocol)
+    {
+        return adoptRef(new WorkerThreadableWebSocketChannel(workerContext, client, taskMode, url, protocol));
+    }
+    virtual ~WorkerThreadableWebSocketChannel();
+
+    virtual void connect();
+    virtual bool send(const String& message);
+    virtual unsigned long bufferedAmount() const;
+    virtual void close();
+    virtual void disconnect(); // Will suppress didClose().
+
+    using RefCounted<WorkerThreadableWebSocketChannel>::ref;
+    using RefCounted<WorkerThreadableWebSocketChannel>::deref;
+
+protected:
+    virtual void refThreadableWebSocketChannel() { ref(); }
+    virtual void derefThreadableWebSocketChannel() { deref(); }
+
+private:
+    // Generated by the bridge.  The Peer and its bridge should have identical
+    // lifetimes.
+    class Peer : public WebSocketChannelClient {
+    public:
+        static Peer* create(RefPtr<ThreadSafeShared<ThreadableWebSocketChannelClientWrapper> > clientWrapper, WorkerLoaderProxy& loaderProxy, ScriptExecutionContext* context, const String& taskMode, const KURL& url, const String& protocol)
+        {
+            return new Peer(clientWrapper, loaderProxy, context, taskMode, url, protocol);
+        }
+        ~Peer();
+
+        void connect();
+        void send(const String& message);
+        void bufferedAmount();
+        void close();
+        void disconnect();
+
+        virtual void didConnect();
+        virtual void didReceiveMessage(const String& message);
+        virtual void didClose();
+
+    private:
+        Peer(RefPtr<ThreadSafeShared<ThreadableWebSocketChannelClientWrapper> >, WorkerLoaderProxy&, ScriptExecutionContext*, const String& taskMode, const KURL&, const String& protocol);
+
+        RefPtr<ThreadSafeShared<ThreadableWebSocketChannelClientWrapper> > m_workerClientWrapper;
+        WorkerLoaderProxy& m_loaderProxy;
+        RefPtr<ThreadableWebSocketChannel> m_mainWebSocketChannel;
+        String m_taskMode;
+    };
+
+    // Bridge for Peer.  Running on the worker thread.
+    class Bridge : public RefCounted<Bridge> {
+    public:
+        Bridge(PassRefPtr<ThreadableWebSocketChannelClientWrapper>, PassRefPtr<WorkerContext>, const String& taskMode, const KURL&, const String& protocol);
+        ~Bridge();
+        void connect();
+        bool send(const String& message);
+        unsigned long bufferedAmount();
+        void close();
+        void disconnect();
+
+        using RefCounted<Bridge>::ref;
+        using RefCounted<Bridge>::deref;
+
+    private:
+        static void setWebSocketChannel(ScriptExecutionContext*, Bridge* thisPtr, Peer*, RefPtr<ThreadSafeShared<ThreadableWebSocketChannelClientWrapper> >);
+
+        // Executed on the main thread to create a Peer for this bridge.
+        static void mainThreadCreateWebSocketChannel(ScriptExecutionContext*, Bridge* thisPtr, RefPtr<ThreadSafeShared<ThreadableWebSocketChannelClientWrapper> >, const String& taskMode, const KURL&, const String& protocol);
+
+        // Executed on the worker context's thread.
+        void clearClientWrapper();
+
+        void setMethodNotCompleted();
+        void waitForMethodCompletion();
+
+        RefPtr<ThreadSafeShared<ThreadableWebSocketChannelClientWrapper> > m_workerClientWrapper;
+        RefPtr<WorkerContext> m_workerContext;
+        WorkerLoaderProxy& m_loaderProxy;
+        String m_taskMode;
+        Peer* m_peer;
+    };
+
+    WorkerThreadableWebSocketChannel(WorkerContext*, WebSocketChannelClient*, const String& taskMode, const KURL&, const String& protocol);
+
+    static void mainThreadConnect(ScriptExecutionContext*, Peer*);
+    static void mainThreadSend(ScriptExecutionContext*, Peer*, const String& message);
+    static void mainThreadBufferedAmount(ScriptExecutionContext*, Peer*);
+    static void mainThreadClose(ScriptExecutionContext*, Peer*);
+    static void mainThreadDestroy(ScriptExecutionContext*, Peer*);
+
+    RefPtr<WorkerContext> m_workerContext;
+    RefPtr<ThreadableWebSocketChannelClientWrapper> m_workerClientWrapper;
+    RefPtr<Bridge> m_bridge;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_SOCKETS)
+
+#endif // WorkerThreadableWebSocketChannel_h
index ffbf9cc..bce4f53 100644 (file)
@@ -87,6 +87,9 @@ module threads {
         attribute [JSCCustomGetter] EventSourceConstructor EventSource;
 #endif
         attribute [JSCCustomGetter] XMLHttpRequestConstructor XMLHttpRequest;
+#if defined(ENABLE_WEB_SOCKETS) && ENABLE_WEB_SOCKETS
+        attribute [JSCCustomGetter,EnabledAtRuntime] WebSocketConstructor WebSocket; // Usable with the new operator
+#endif
     };
 
 }