Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1950)

Unified Diff: WebCore/websockets/WebSocketChannel.cpp

Issue 155079: WebSocket implementation in WebKit (Closed)
Patch Set: Rewrite to use SocketStreamHandle Created 11 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « WebCore/websockets/WebSocketChannel.h ('k') | WebCore/websockets/WebSocketChannelClient.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: WebCore/websockets/WebSocketChannel.cpp
diff --git a/WebCore/websockets/WebSocketChannel.cpp b/WebCore/websockets/WebSocketChannel.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..37abd5d056c7a3d614e13949551892c70d12766e
--- /dev/null
+++ b/WebCore/websockets/WebSocketChannel.cpp
@@ -0,0 +1,219 @@
+/*
+ * 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"
+#include "WebSocketChannel.h"
+
+#include "CString.h"
+#include "Logging.h"
+#include "PlatformString.h"
+#include "ScriptExecutionContext.h"
+#include "SharedBuffer.h"
+#include "SocketStreamHandle.h"
+#include "StringHash.h"
+#include "WebSocketChannelClient.h"
+
+#include <wtf/HashMap.h>
+#include <wtf/Deque.h>
+
+#include "NotImplemented.h"
+
+#undef LOG
+#define LOG(channel, ...) do { fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); } while (0);
+
+namespace {
+
+bool CheckWebSocketHandshake(const WebCore::WebSocketRequest &req, const WebCore::WebSocketResponse& resp)
+{
+ if (!resp.isValidHeader()) {
+ LOG(Network, "Wrong response header");
+ return false;
+ }
+ if (req.origin() != resp.websocket_origin()) {
+ LOG(Network, "Mismatch origin: %s != %s", req.origin().utf8().data(), resp.websocket_origin().utf8().data());
+ return false;
+ }
+ if (req.location() != resp.websocket_location()) {
+ LOG(Network, "Mismatch location: %s != %s", req.location().utf8().data(), resp.websocket_location().utf8().data());
+ return false;
+ }
+ if (!req.protocol().isEmpty() && req.protocol() != resp.websocket_protocol()) {
+ LOG(Network, "Mismatch protocol: %s != %s", req.protocol().utf8().data(), resp.websocket_protocol().utf8().data());
+ return false;
+ }
+ return true;
+}
+
+} // anonymous namespace
+
+namespace WebCore {
+
+WebSocketChannel::WebSocketChannel(ScriptExecutionContext* context, WebSocketChannelClient* client, const WebSocketRequest& request)
+ : m_context(context)
+ , m_client(client)
+ , m_request(request)
+ , m_handshaked(false)
+ , m_buffered_amount(0)
+ , m_buffer(SharedBuffer::create())
+{
+ // TODO(ukai): additional parameters?
+}
+
+WebSocketChannel::~WebSocketChannel()
+{
+}
+
+void WebSocketChannel::connect()
+{
+ LOG(Network, "WebSocketChannel %p connect", this);
+
+ // ??? defer connection in SocketStreamHandle
+ m_handle = SocketStreamHandle::create(m_request.url(), this);
+}
+
+bool WebSocketChannel::send(const String& msg)
+{
+ LOG(Network, "WebSocketChannel %p send %s", this, msg.utf8().data());
+ static const char frame_type[1] = {'\0'};
+ static const char frame_end[1] = {'\xff'};
+ RefPtr<SharedBuffer> buf(SharedBuffer::create());
+ buf->append(frame_type, sizeof(frame_type));
+ buf->append(msg.utf8().data(), msg.utf8().length());
+ buf->append(frame_end, sizeof(frame_end));
+ m_buffered_amount += buf->size();
+ return m_handle->send(buf->data(), buf->size());
+}
+
+unsigned long WebSocketChannel::bufferedAmount() const
+{
+ LOG(Network, "WebSocketChannel %p bufferedAmount", this);
+ return m_buffered_amount;
+}
+
+void WebSocketChannel::close()
+{
+ LOG(Network, "WebSocketChannel %p close", this);
+ if (m_handle.get()) {
+ m_handle->close(); // will call didClose()
+ }
+}
+
+void WebSocketChannel::didOpen(SocketStreamHandle* handle)
+{
+ LOG(Network, "WebSocketChannel %p didConnect", this);
+ ASSERT(handle == m_handle.get() || m_handle.get() == 0);
+ if (m_handle.get() == 0)
+ return;
+ const CString& request_message = m_request.flattenToString();
+ m_handle->send(request_message.data(), request_message.length());
+}
+
+void WebSocketChannel::didClose(SocketStreamHandle* handle)
+{
+ LOG(Network, "WebSocketChannel %p didClose", this);
+ ASSERT(handle == m_handle.get() || m_handle.get() == 0);
+ if (m_handle.get() == 0)
+ return;
+ m_handle = NULL;
+ WebSocketChannelClient* client = m_client;
+ m_client = NULL;
+ client->didClose();
+}
+
+void WebSocketChannel::didReceivedData(SocketStreamHandle* handle, const char* data, int len)
+{
+ LOG(Network, "WebSocketChannel %p didReceiveData %d", this, len);
+ ASSERT(handle == m_handle.get() || m_handle.get() == 0);
+ if (m_handle.get() == 0)
+ return;
+ m_buffer->append(data, len);
+ if (!m_handshaked) {
+ int header_len = m_response.readHandshakeResponse(m_buffer->data(), m_buffer->size());
+ if (header_len <= 0)
+ return;
+ m_handshaked = CheckWebSocketHandshake(m_request, m_response);
+ if (m_handshaked) {
+ LOG(Network, "WebSocketChannel %p connected", this);
+ m_client->didConnect();
+ } else {
+ LOG(Network, "WebSocketChannel %p connection failed", this);
+ didClose(handle);
+ }
+ if (header_len == len)
+ return;
+ RefPtr<SharedBuffer> buf(SharedBuffer::create());
+ buf->append(m_buffer->data() + header_len, m_buffer->size() - header_len);
+ m_buffer.swap(buf);
+ }
+ RefPtr<SharedBuffer> buf(SharedBuffer::create());
+ buf.swap(m_buffer);
+
+ const char *next_frame = buf->data();
+ const char *p = buf->data();
+ const char *end = p + buf->size();
+ while (p < end) {
+ unsigned char frame_byte = static_cast<unsigned char>(*p++);
+ if ((frame_byte & 0x80) == 0x80) {
+ // TODO(ukai): overflow check
+ int length = 0;
+ while (p < end && (*p & 0x80) == 0x80) {
+ length = length * 127 + *p & 0x7f;
+ ++p;
+ }
+ if (p + length < end) {
+ p += length;
+ next_frame = p;
+ }
+ } else {
+ const char *msg_start = p;
+ while (p < end && *p != '\xff') {
+ ++p;
+ }
+ if (p < end && *p == '\xff') {
+ if (frame_byte == 0x00)
+ m_client->didReceiveMessage(String::fromUTF8(msg_start, p - msg_start));
+ ++p;
+ next_frame = p;
+ }
+ }
+ }
+ if (next_frame < end) {
+ m_buffer->append(next_frame, end - next_frame);
+ }
+}
+
+void WebSocketChannel::didFail(SocketStreamHandle* handle, const SocketStreamHandleError& err)
+{
+ LOG(Network, "WebSocketChannel %p didFaile", this);
+ ASSERT(handle == m_handle.get() || m_handle.get() == 0);
+ didClose(handle);
+}
+
+} // namespace WebCore
« no previous file with comments | « WebCore/websockets/WebSocketChannel.h ('k') | WebCore/websockets/WebSocketChannelClient.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698