summaryrefslogtreecommitdiffstats
path: root/WebCore/websockets
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/websockets')
-rw-r--r--WebCore/websockets/ThreadableWebSocketChannel.cpp74
-rw-r--r--WebCore/websockets/ThreadableWebSocketChannel.h69
-rw-r--r--WebCore/websockets/ThreadableWebSocketChannelClientWrapper.h127
-rw-r--r--WebCore/websockets/WebSocket.cpp36
-rw-r--r--WebCore/websockets/WebSocket.h20
-rw-r--r--WebCore/websockets/WebSocket.idl1
-rw-r--r--WebCore/websockets/WebSocketChannel.cpp8
-rw-r--r--WebCore/websockets/WebSocketChannel.h28
-rw-r--r--WebCore/websockets/WebSocketChannelClient.h6
-rw-r--r--WebCore/websockets/WebSocketHandshake.cpp64
-rw-r--r--WebCore/websockets/WebSocketHandshake.h6
-rw-r--r--WebCore/websockets/WorkerThreadableWebSocketChannel.cpp362
-rw-r--r--WebCore/websockets/WorkerThreadableWebSocketChannel.h155
13 files changed, 895 insertions, 61 deletions
diff --git a/WebCore/websockets/ThreadableWebSocketChannel.cpp b/WebCore/websockets/ThreadableWebSocketChannel.cpp
new file mode 100644
index 0000000..28b9263
--- /dev/null
+++ b/WebCore/websockets/ThreadableWebSocketChannel.cpp
@@ -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
index 0000000..74ea4b4
--- /dev/null
+++ b/WebCore/websockets/ThreadableWebSocketChannel.h
@@ -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
index 0000000..8bf51fa
--- /dev/null
+++ b/WebCore/websockets/ThreadableWebSocketChannelClientWrapper.h
@@ -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
diff --git a/WebCore/websockets/WebSocket.cpp b/WebCore/websockets/WebSocket.cpp
index ee78174..0435490 100644
--- a/WebCore/websockets/WebSocket.cpp
+++ b/WebCore/websockets/WebSocket.cpp
@@ -43,12 +43,14 @@
#include "Logging.h"
#include "MessageEvent.h"
#include "ScriptExecutionContext.h"
+#include "StringBuilder.h"
+#include "ThreadableWebSocketChannel.h"
#include "WebSocketChannel.h"
#include <wtf/StdLibExtras.h>
namespace WebCore {
-static bool isValidProtocolString(const WebCore::String& protocol)
+static bool isValidProtocolString(const String& protocol)
{
if (protocol.isNull())
return true;
@@ -62,6 +64,20 @@ static bool isValidProtocolString(const WebCore::String& protocol)
return true;
}
+static String encodeProtocolString(const String& protocol)
+{
+ StringBuilder builder;
+ for (size_t i = 0; i < protocol.length(); i++) {
+ if (protocol[i] < 0x20 || protocol[i] > 0x7E)
+ builder.append(String::format("\\u%04X", protocol[i]));
+ else if (protocol[i] == 0x5c)
+ builder.append("\\\\");
+ else
+ builder.append(protocol[i]);
+ }
+ return builder.toString();
+}
+
#if USE(V8)
static bool webSocketsAvailable = false;
@@ -101,32 +117,39 @@ void WebSocket::connect(const KURL& url, const String& protocol, ExceptionCode&
m_url = url;
m_protocol = protocol;
+ if (!m_url.isValid()) {
+ scriptExecutionContext()->addMessage(ConsoleDestination, JSMessageSource, LogMessageType, ErrorMessageLevel, "Invalid url for WebSocket " + url.string(), 0, scriptExecutionContext()->securityOrigin()->toString());
+ m_state = CLOSED;
+ ec = SYNTAX_ERR;
+ return;
+ }
+
if (!m_url.protocolIs("ws") && !m_url.protocolIs("wss")) {
- LOG(Network, "Wrong url scheme for WebSocket %s", url.string().utf8().data());
+ scriptExecutionContext()->addMessage(ConsoleDestination, JSMessageSource, LogMessageType, ErrorMessageLevel, "Wrong url scheme for WebSocket " + url.string(), 0, scriptExecutionContext()->securityOrigin()->toString());
m_state = CLOSED;
ec = SYNTAX_ERR;
return;
}
if (m_url.hasFragmentIdentifier()) {
- LOG(Network, "URL has fragment component %s", url.string().utf8().data());
+ scriptExecutionContext()->addMessage(ConsoleDestination, JSMessageSource, LogMessageType, ErrorMessageLevel, "URL has fragment component " + url.string(), 0, scriptExecutionContext()->securityOrigin()->toString());
m_state = CLOSED;
ec = SYNTAX_ERR;
return;
}
if (!isValidProtocolString(m_protocol)) {
- LOG(Network, "Wrong protocol for WebSocket %s", m_protocol.utf8().data());
+ scriptExecutionContext()->addMessage(ConsoleDestination, JSMessageSource, LogMessageType, ErrorMessageLevel, "Wrong protocol for WebSocket '" + encodeProtocolString(m_protocol) + "'", 0, scriptExecutionContext()->securityOrigin()->toString());
m_state = CLOSED;
ec = SYNTAX_ERR;
return;
}
if (!portAllowed(url)) {
- LOG(Network, "WebSocket port %d blocked", url.port());
+ scriptExecutionContext()->addMessage(ConsoleDestination, JSMessageSource, LogMessageType, ErrorMessageLevel, String::format("WebSocket port %d blocked", url.port()), 0, scriptExecutionContext()->securityOrigin()->toString());
m_state = CLOSED;
ec = SECURITY_ERR;
return;
}
- m_channel = WebSocketChannel::create(scriptExecutionContext(), this, m_url, m_protocol);
+ m_channel = ThreadableWebSocketChannel::create(scriptExecutionContext(), this, m_url, m_protocol);
m_channel->connect();
}
@@ -192,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);
}
diff --git a/WebCore/websockets/WebSocket.h b/WebCore/websockets/WebSocket.h
index 9ecbed7..18e2b25 100644
--- a/WebCore/websockets/WebSocket.h
+++ b/WebCore/websockets/WebSocket.h
@@ -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
diff --git a/WebCore/websockets/WebSocket.idl b/WebCore/websockets/WebSocket.idl
index c662940..c9552d9 100644
--- a/WebCore/websockets/WebSocket.idl
+++ b/WebCore/websockets/WebSocket.idl
@@ -32,6 +32,7 @@ module websockets {
interface [
Conditional=WEB_SOCKETS,
+ CustomConstructor,
EventTarget,
NoStaticTables
] WebSocket {
diff --git a/WebCore/websockets/WebSocketChannel.cpp b/WebCore/websockets/WebSocketChannel.cpp
index a222b4d..5c0f4c3 100644
--- a/WebCore/websockets/WebSocketChannel.cpp
+++ b/WebCore/websockets/WebSocketChannel.cpp
@@ -118,7 +118,7 @@ void WebSocketChannel::didOpen(SocketStreamHandle* handle)
ASSERT(handle == m_handle);
const CString& handshakeMessage = m_handshake.clientHandshakeMessage();
if (!handle->send(handshakeMessage.data(), handshakeMessage.length())) {
- LOG(Network, "Error in sending handshake message.");
+ m_context->addMessage(ConsoleDestination, JSMessageSource, LogMessageType, ErrorMessageLevel, "Error sending handshake message.", 0, m_handshake.clientOrigin());
handle->close();
}
}
@@ -150,7 +150,7 @@ void WebSocketChannel::didReceiveData(SocketStreamHandle* handle, const char* da
handle->close();
return;
}
- if (m_handshake.mode() != WebSocketHandshake::Connected) {
+ if (m_handshake.mode() == WebSocketHandshake::Incomplete) {
int headerLength = m_handshake.readServerHandshake(m_buffer, m_bufferSize);
if (headerLength <= 0)
return;
@@ -179,6 +179,8 @@ void WebSocketChannel::didReceiveData(SocketStreamHandle* handle, const char* da
return;
LOG(Network, "remaining in read buf %ul", m_bufferSize);
}
+ if (m_handshake.mode() != WebSocketHandshake::Connected)
+ return;
const char* nextFrame = m_buffer;
const char* p = m_buffer;
@@ -246,7 +248,7 @@ bool WebSocketChannel::appendToBuffer(const char* data, int len)
m_bufferSize += len;
return true;
}
- LOG(Network, "Too long WebSocket frame %d", m_bufferSize + len);
+ m_context->addMessage(ConsoleDestination, JSMessageSource, LogMessageType, ErrorMessageLevel, String::format("WebSocket frame (at %d bytes) is too long.", m_bufferSize + len), 0, m_handshake.clientOrigin());
return false;
}
diff --git a/WebCore/websockets/WebSocketChannel.h b/WebCore/websockets/WebSocketChannel.h
index 14b1e8c..7ec826c 100644
--- a/WebCore/websockets/WebSocketChannel.h
+++ b/WebCore/websockets/WebSocketChannel.h
@@ -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
diff --git a/WebCore/websockets/WebSocketChannelClient.h b/WebCore/websockets/WebSocketChannelClient.h
index 463cada..163070f 100644
--- a/WebCore/websockets/WebSocketChannelClient.h
+++ b/WebCore/websockets/WebSocketChannelClient.h
@@ -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
diff --git a/WebCore/websockets/WebSocketHandshake.cpp b/WebCore/websockets/WebSocketHandshake.cpp
index d1da443..883f84b 100644
--- a/WebCore/websockets/WebSocketHandshake.cpp
+++ b/WebCore/websockets/WebSocketHandshake.cpp
@@ -76,9 +76,14 @@ static String extractResponseCode(const char* header, int len)
static String resourceName(const KURL& url)
{
- if (url.query().isNull())
- return url.path();
- return url.path() + "?" + url.query();
+ String name = url.path();
+ if (name.isEmpty())
+ name = "/";
+ if (!url.query().isNull())
+ name += "?" + url.query();
+ ASSERT(!name.isEmpty());
+ ASSERT(!name.contains(' '));
+ return name;
}
WebSocketHandshake::WebSocketHandshake(const KURL& url, const String& protocol, ScriptExecutionContext* context)
@@ -216,19 +221,22 @@ int WebSocketHandshake::readServerHandshake(const char* header, size_t len)
else {
const String& code = extractResponseCode(header, len);
if (code.isNull()) {
- LOG(Network, "short server handshake: %s", header);
+ m_context->addMessage(ConsoleDestination, JSMessageSource, LogMessageType, ErrorMessageLevel, "Short server handshake: " + String(header, len), 0, clientOrigin());
return -1;
}
if (code.isEmpty()) {
- LOG(Network, "no response code found: %s", header);
+ m_mode = Failed;
+ m_context->addMessage(ConsoleDestination, JSMessageSource, LogMessageType, ErrorMessageLevel, "No response code found: " + String(header, len), 0, clientOrigin());
return len;
}
LOG(Network, "response code: %s", code.utf8().data());
if (code == "401") {
- LOG(Network, "Authentication required");
+ m_mode = Failed;
+ m_context->addMessage(ConsoleDestination, JSMessageSource, LogMessageType, ErrorMessageLevel, "Authentication required, but not implemented yet.", 0, clientOrigin());
return len;
} else {
- LOG(Network, "Mismatch server handshake: %s", header);
+ m_mode = Failed;
+ m_context->addMessage(ConsoleDestination, JSMessageSource, LogMessageType, ErrorMessageLevel, "Unexpected response code:" + code, 0, clientOrigin());
return len;
}
}
@@ -237,19 +245,25 @@ int WebSocketHandshake::readServerHandshake(const char* header, size_t len)
if (m_mode == Normal) {
size_t headerSize = end - p;
- if (headerSize < sizeof(webSocketUpgradeHeader) - 1)
+ if (headerSize < sizeof(webSocketUpgradeHeader) - 1) {
+ m_mode = Incomplete;
return 0;
+ }
if (memcmp(p, webSocketUpgradeHeader, sizeof(webSocketUpgradeHeader) - 1)) {
- LOG(Network, "Bad upgrade header: %s", p);
+ m_mode = Failed;
+ m_context->addMessage(ConsoleDestination, JSMessageSource, LogMessageType, ErrorMessageLevel, "Bad Upgrade header: " + String(p, end - p), 0, clientOrigin());
return p - header + sizeof(webSocketUpgradeHeader) - 1;
}
p += sizeof(webSocketUpgradeHeader) - 1;
headerSize = end - p;
- if (headerSize < sizeof(webSocketConnectionHeader) - 1)
+ if (headerSize < sizeof(webSocketConnectionHeader) - 1) {
+ m_mode = Incomplete;
return -1;
+ }
if (memcmp(p, webSocketConnectionHeader, sizeof(webSocketConnectionHeader) - 1)) {
- LOG(Network, "Bad connection header: %s", p);
+ m_mode = Failed;
+ m_context->addMessage(ConsoleDestination, JSMessageSource, LogMessageType, ErrorMessageLevel, "Bad Connection header: " + String(p, end - p), 0, clientOrigin());
return p - header + sizeof(webSocketConnectionHeader) - 1;
}
p += sizeof(webSocketConnectionHeader) - 1;
@@ -257,6 +271,7 @@ int WebSocketHandshake::readServerHandshake(const char* header, size_t len)
if (!strnstr(p, "\r\n\r\n", end - p)) {
// Just hasn't been received fully yet.
+ m_mode = Incomplete;
return -1;
}
HTTPHeaderMap headers;
@@ -340,7 +355,8 @@ void WebSocketHandshake::setServerSetCookie2(const String& setCookie2)
KURL WebSocketHandshake::httpURLForAuthenticationAndCookies() const
{
KURL url = m_url.copy();
- url.setProtocol(m_secure ? "https" : "http");
+ bool couldSetProtocol = url.setProtocol(m_secure ? "https" : "http");
+ ASSERT_UNUSED(couldSetProtocol, couldSetProtocol);
return url;
}
@@ -358,13 +374,13 @@ const char* WebSocketHandshake::readHTTPHeaders(const char* start, const char* e
if (name.isEmpty()) {
if (p + 1 < end && *(p + 1) == '\n')
return p + 2;
- LOG(Network, "CR doesn't follow LF p=%p end=%p", p, end);
+ m_context->addMessage(ConsoleDestination, JSMessageSource, LogMessageType, ErrorMessageLevel, "CR doesn't follow LF at " + String(p, end - p), 0, clientOrigin());
return 0;
}
- LOG(Network, "Unexpected CR in name");
+ m_context->addMessage(ConsoleDestination, JSMessageSource, LogMessageType, ErrorMessageLevel, "Unexpected CR in name at " + String(p, end - p), 0, clientOrigin());
return 0;
case '\n':
- LOG(Network, "Unexpected LF in name");
+ m_context->addMessage(ConsoleDestination, JSMessageSource, LogMessageType, ErrorMessageLevel, "Unexpected LF in name at " + String(p, end - p), 0, clientOrigin());
return 0;
case ':':
break;
@@ -388,7 +404,7 @@ const char* WebSocketHandshake::readHTTPHeaders(const char* start, const char* e
case '\r':
break;
case '\n':
- LOG(Network, "Unexpected LF in value");
+ m_context->addMessage(ConsoleDestination, JSMessageSource, LogMessageType, ErrorMessageLevel, "Unexpected LF in value at " + String(p, end - p), 0, clientOrigin());
return 0;
default:
value.append(*p);
@@ -399,7 +415,7 @@ const char* WebSocketHandshake::readHTTPHeaders(const char* start, const char* e
}
}
if (p >= end || *p != '\n') {
- LOG(Network, "CR doesn't follow LF after value p=%p end=%p", p, end);
+ m_context->addMessage(ConsoleDestination, JSMessageSource, LogMessageType, ErrorMessageLevel, "CR doesn't follow LF after value at " + String(p, end - p), 0, clientOrigin());
return 0;
}
AtomicString nameStr(String::fromUTF8(name.data(), name.size()));
@@ -441,19 +457,25 @@ void WebSocketHandshake::checkResponseHeaders()
{
ASSERT(m_mode == Normal);
m_mode = Failed;
- if (m_wsOrigin.isNull() || m_wsLocation.isNull())
+ if (m_wsOrigin.isNull()) {
+ m_context->addMessage(ConsoleDestination, JSMessageSource, LogMessageType, ErrorMessageLevel, "Error during WebSocket handshake: 'websocket-origin' header is missing", 0, clientOrigin());
return;
+ }
+ if (m_wsLocation.isNull()) {
+ m_context->addMessage(ConsoleDestination, JSMessageSource, LogMessageType, ErrorMessageLevel, "Error during WebSocket handshake: 'websocket-location' header is missing", 0, clientOrigin());
+ return;
+ }
if (clientOrigin() != m_wsOrigin) {
- LOG(Network, "Mismatch origin: %s != %s", clientOrigin().utf8().data(), m_wsOrigin.utf8().data());
+ m_context->addMessage(ConsoleDestination, JSMessageSource, LogMessageType, ErrorMessageLevel, "Error during WebSocket handshake: origin mismatch: " + clientOrigin() + " != " + m_wsOrigin, 0, clientOrigin());
return;
}
if (clientLocation() != m_wsLocation) {
- LOG(Network, "Mismatch location: %s != %s", clientLocation().utf8().data(), m_wsLocation.utf8().data());
+ m_context->addMessage(ConsoleDestination, JSMessageSource, LogMessageType, ErrorMessageLevel, "Error during WebSocket handshake: location mismatch: " + clientLocation() + " != " + m_wsLocation, 0, clientOrigin());
return;
}
if (!m_clientProtocol.isEmpty() && m_clientProtocol != m_wsProtocol) {
- LOG(Network, "Mismatch protocol: %s != %s", m_clientProtocol.utf8().data(), m_wsProtocol.utf8().data());
+ m_context->addMessage(ConsoleDestination, JSMessageSource, LogMessageType, ErrorMessageLevel, "Error during WebSocket handshake: protocol mismatch: " + m_clientProtocol + " != " + m_wsProtocol, 0, clientOrigin());
return;
}
m_mode = Connected;
diff --git a/WebCore/websockets/WebSocketHandshake.h b/WebCore/websockets/WebSocketHandshake.h
index d5dbe68..bda320a 100644
--- a/WebCore/websockets/WebSocketHandshake.h
+++ b/WebCore/websockets/WebSocketHandshake.h
@@ -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
index 0000000..8db81b7
--- /dev/null
+++ b/WebCore/websockets/WorkerThreadableWebSocketChannel.cpp
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2009, 2010 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<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<ThreadableWebSocketChannelClientWrapper> workerClientWrapper, bool sent)
+{
+ ASSERT_UNUSED(context, context->isWorkerContext());
+ workerClientWrapper->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<ThreadableWebSocketChannelClientWrapper> workerClientWrapper, unsigned long bufferedAmount)
+{
+ ASSERT_UNUSED(context, context->isWorkerContext());
+ workerClientWrapper->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<ThreadableWebSocketChannelClientWrapper> workerClientWrapper)
+{
+ ASSERT_UNUSED(context, context->isWorkerContext());
+ workerClientWrapper->didConnect();
+}
+
+void WorkerThreadableWebSocketChannel::Peer::didConnect()
+{
+ ASSERT(isMainThread());
+ m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&workerContextDidConnect, m_workerClientWrapper), m_taskMode);
+}
+
+static void workerContextDidReceiveMessage(ScriptExecutionContext* context, RefPtr<ThreadableWebSocketChannelClientWrapper> workerClientWrapper, const String& message)
+{
+ ASSERT_UNUSED(context, context->isWorkerContext());
+ workerClientWrapper->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<ThreadableWebSocketChannelClientWrapper> workerClientWrapper)
+{
+ ASSERT_UNUSED(context, context->isWorkerContext());
+ workerClientWrapper->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<ThreadableWebSocketChannelClientWrapper> workerClientWrapper)
+{
+ ASSERT_UNUSED(context, context->isWorkerContext());
+ thisPtr->m_peer = peer;
+ workerClientWrapper->setSyncMethodDone();
+}
+
+void WorkerThreadableWebSocketChannel::Bridge::mainThreadCreateWebSocketChannel(ScriptExecutionContext* context, Bridge* thisPtr, RefPtr<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(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 = 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 = 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));
+ }
+ m_workerContext = 0;
+}
+
+void WorkerThreadableWebSocketChannel::Bridge::clearClientWrapper()
+{
+ m_workerClientWrapper->clearClient();
+}
+
+void WorkerThreadableWebSocketChannel::Bridge::setMethodNotCompleted()
+{
+ ASSERT(m_workerClientWrapper);
+ m_workerClientWrapper->clearSyncMethodDone();
+}
+
+void WorkerThreadableWebSocketChannel::Bridge::waitForMethodCompletion()
+{
+ if (!m_workerContext)
+ return;
+ WorkerRunLoop& runLoop = m_workerContext->thread()->runLoop();
+ MessageQueueWaitResult result = MessageQueueMessageReceived;
+ ThreadableWebSocketChannelClientWrapper* clientWrapper = m_workerClientWrapper.get();
+ while (clientWrapper && !clientWrapper->syncMethodDone() && result != MessageQueueTerminated) {
+ result = runLoop.runInMode(m_workerContext.get(), m_taskMode);
+ clientWrapper = 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
index 0000000..1106f43
--- /dev/null
+++ b/WebCore/websockets/WorkerThreadableWebSocketChannel.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2009, 2010 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 Noncopyable {
+ public:
+ static Peer* create(RefPtr<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<ThreadableWebSocketChannelClientWrapper>, WorkerLoaderProxy&, ScriptExecutionContext*, const String& taskMode, const KURL&, const String& protocol);
+
+ RefPtr<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<ThreadableWebSocketChannelClientWrapper>);
+
+ // Executed on the main thread to create a Peer for this bridge.
+ static void mainThreadCreateWebSocketChannel(ScriptExecutionContext*, Bridge* thisPtr, RefPtr<ThreadableWebSocketChannelClientWrapper>, const String& taskMode, const KURL&, const String& protocol);
+
+ // Executed on the worker context's thread.
+ void clearClientWrapper();
+
+ void setMethodNotCompleted();
+ void waitForMethodCompletion();
+
+ RefPtr<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