summaryrefslogtreecommitdiffstats
path: root/net/websockets/websocket.cc
diff options
context:
space:
mode:
Diffstat (limited to 'net/websockets/websocket.cc')
-rw-r--r--net/websockets/websocket.cc484
1 files changed, 0 insertions, 484 deletions
diff --git a/net/websockets/websocket.cc b/net/websockets/websocket.cc
deleted file mode 100644
index f8d9eb9..0000000
--- a/net/websockets/websocket.cc
+++ /dev/null
@@ -1,484 +0,0 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <algorithm>
-#include <limits>
-
-#include "net/websockets/websocket.h"
-
-#include "base/message_loop.h"
-#include "net/base/host_resolver.h"
-#include "net/websockets/websocket_handshake.h"
-#include "net/websockets/websocket_handshake_draft75.h"
-
-namespace net {
-
-static const char kClosingFrame[2] = {'\xff', '\x00'};
-static int64 kClosingHandshakeTimeout = 1000; // msec.
-
-WebSocket::WebSocket(Request* request, WebSocketDelegate* delegate)
- : ready_state_(INITIALIZED),
- request_(request),
- handshake_(NULL),
- delegate_(delegate),
- origin_loop_(MessageLoop::current()),
- socket_stream_(NULL),
- max_pending_send_allowed_(0),
- current_read_buf_(NULL),
- read_consumed_len_(0),
- current_write_buf_(NULL),
- server_closing_handshake_(false),
- client_closing_handshake_(false),
- closing_handshake_started_(false),
- force_close_task_(NULL),
- closing_handshake_timeout_(kClosingHandshakeTimeout) {
- DCHECK(request_.get());
- DCHECK(delegate_);
- DCHECK(origin_loop_);
-}
-
-WebSocket::~WebSocket() {
- DCHECK(ready_state_ == INITIALIZED || !delegate_);
- DCHECK(!socket_stream_);
- DCHECK(!delegate_);
-}
-
-void WebSocket::Connect() {
- DCHECK(ready_state_ == INITIALIZED);
- DCHECK(request_.get());
- DCHECK(delegate_);
- DCHECK(!socket_stream_);
- DCHECK(MessageLoop::current() == origin_loop_);
-
- socket_stream_ = new SocketStream(request_->url(), this);
- socket_stream_->set_context(request_->context());
-
- if (request_->host_resolver())
- socket_stream_->SetHostResolver(request_->host_resolver());
- if (request_->client_socket_factory())
- socket_stream_->SetClientSocketFactory(request_->client_socket_factory());
-
- AddRef(); // Release in DoClose().
- ready_state_ = CONNECTING;
- socket_stream_->Connect();
-}
-
-void WebSocket::Send(const std::string& msg) {
- if (ready_state_ == CLOSING || ready_state_ == CLOSED) {
- return;
- }
- if (client_closing_handshake_) {
- // We must not send any data after we start the WebSocket closing handshake.
- return;
- }
- DCHECK(ready_state_ == OPEN);
- DCHECK(MessageLoop::current() == origin_loop_);
-
- IOBufferWithSize* buf = new IOBufferWithSize(msg.size() + 2);
- char* p = buf->data();
- *p = '\0';
- memcpy(p + 1, msg.data(), msg.size());
- *(p + 1 + msg.size()) = '\xff';
- pending_write_bufs_.push_back(make_scoped_refptr(buf));
- SendPending();
-}
-
-void WebSocket::Close() {
- DCHECK(MessageLoop::current() == origin_loop_);
-
- // If connection has not yet started, do nothing.
- if (ready_state_ == INITIALIZED) {
- DCHECK(!socket_stream_);
- ready_state_ = CLOSED;
- return;
- }
-
- // If the readyState attribute is in the CLOSING or CLOSED state, do nothing
- if (ready_state_ == CLOSING || ready_state_ == CLOSED)
- return;
-
- if (request_->version() == DRAFT75) {
- DCHECK(socket_stream_);
- socket_stream_->Close();
- return;
- }
-
- // If the WebSocket connection is not yet established, fail the WebSocket
- // connection and set the readyState attribute's value to CLOSING.
- if (ready_state_ == CONNECTING) {
- ready_state_ = CLOSING;
- origin_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &WebSocket::FailConnection));
- }
-
- // If the WebSocket closing handshake has not yet been started, start
- // the WebSocket closing handshake and set the readyState attribute's value
- // to CLOSING.
- if (!closing_handshake_started_) {
- ready_state_ = CLOSING;
- origin_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &WebSocket::StartClosingHandshake));
- }
-
- // Otherwise, set the readyState attribute's value to CLOSING.
- ready_state_ = CLOSING;
-}
-
-void WebSocket::DetachDelegate() {
- if (!delegate_)
- return;
- delegate_ = NULL;
- if (ready_state_ == INITIALIZED) {
- DCHECK(!socket_stream_);
- ready_state_ = CLOSED;
- return;
- }
- if (ready_state_ != CLOSED) {
- DCHECK(socket_stream_);
- socket_stream_->Close();
- }
-}
-
-void WebSocket::OnConnected(SocketStream* socket_stream,
- int max_pending_send_allowed) {
- DCHECK(socket_stream == socket_stream_);
- max_pending_send_allowed_ = max_pending_send_allowed;
-
- // Use |max_pending_send_allowed| as hint for initial size of read buffer.
- current_read_buf_ = new GrowableIOBuffer();
- current_read_buf_->SetCapacity(max_pending_send_allowed_);
- read_consumed_len_ = 0;
-
- DCHECK(!current_write_buf_);
- DCHECK(!handshake_.get());
- switch (request_->version()) {
- case DEFAULT_VERSION:
- handshake_.reset(new WebSocketHandshake(
- request_->url(), request_->origin(), request_->location(),
- request_->protocol()));
- break;
- case DRAFT75:
- handshake_.reset(new WebSocketHandshakeDraft75(
- request_->url(), request_->origin(), request_->location(),
- request_->protocol()));
- break;
- default:
- NOTREACHED() << "Unexpected protocol version:" << request_->version();
- }
-
- const std::string msg = handshake_->CreateClientHandshakeMessage();
- IOBufferWithSize* buf = new IOBufferWithSize(msg.size());
- memcpy(buf->data(), msg.data(), msg.size());
- pending_write_bufs_.push_back(make_scoped_refptr(buf));
- origin_loop_->PostTask(FROM_HERE,
- NewRunnableMethod(this, &WebSocket::SendPending));
-}
-
-void WebSocket::OnSentData(SocketStream* socket_stream, int amount_sent) {
- DCHECK(socket_stream == socket_stream_);
- DCHECK(current_write_buf_);
- current_write_buf_->DidConsume(amount_sent);
- DCHECK_GE(current_write_buf_->BytesRemaining(), 0);
- if (current_write_buf_->BytesRemaining() == 0) {
- current_write_buf_ = NULL;
- pending_write_bufs_.pop_front();
- }
- origin_loop_->PostTask(FROM_HERE,
- NewRunnableMethod(this, &WebSocket::SendPending));
-}
-
-void WebSocket::OnReceivedData(SocketStream* socket_stream,
- const char* data, int len) {
- DCHECK(socket_stream == socket_stream_);
- AddToReadBuffer(data, len);
- origin_loop_->PostTask(FROM_HERE,
- NewRunnableMethod(this, &WebSocket::DoReceivedData));
-}
-
-void WebSocket::OnClose(SocketStream* socket_stream) {
- origin_loop_->PostTask(FROM_HERE,
- NewRunnableMethod(this, &WebSocket::DoClose));
-}
-
-void WebSocket::OnError(const SocketStream* socket_stream, int error) {
- origin_loop_->PostTask(
- FROM_HERE, NewRunnableMethod(this, &WebSocket::DoSocketError, error));
-}
-
-void WebSocket::SendPending() {
- DCHECK(MessageLoop::current() == origin_loop_);
- if (!socket_stream_) {
- DCHECK_EQ(CLOSED, ready_state_);
- return;
- }
- if (!current_write_buf_) {
- if (pending_write_bufs_.empty()) {
- if (client_closing_handshake_) {
- // Already sent 0xFF and 0x00 bytes.
- // *The WebSocket closing handshake has started.*
- closing_handshake_started_ = true;
- if (server_closing_handshake_) {
- // 4.2 3-8-3 If the WebSocket connection is not already closed,
- // then close the WebSocket connection.
- // *The WebSocket closing handshake has finished*
- socket_stream_->Close();
- } else {
- // 5. Wait a user-agent-determined length of time, or until the
- // WebSocket connection is closed.
- force_close_task_ =
- NewRunnableMethod(this, &WebSocket::DoForceCloseConnection);
- origin_loop_->PostDelayedTask(
- FROM_HERE, force_close_task_, closing_handshake_timeout_);
- }
- }
- return;
- }
- current_write_buf_ = new DrainableIOBuffer(
- pending_write_bufs_.front(), pending_write_bufs_.front()->size());
- }
- DCHECK_GT(current_write_buf_->BytesRemaining(), 0);
- bool sent = socket_stream_->SendData(
- current_write_buf_->data(),
- std::min(current_write_buf_->BytesRemaining(),
- max_pending_send_allowed_));
- DCHECK(sent);
-}
-
-void WebSocket::DoReceivedData() {
- DCHECK(MessageLoop::current() == origin_loop_);
- scoped_refptr<WebSocket> protect(this);
- switch (ready_state_) {
- case CONNECTING:
- {
- DCHECK(handshake_.get());
- DCHECK(current_read_buf_);
- const char* data =
- current_read_buf_->StartOfBuffer() + read_consumed_len_;
- size_t len = current_read_buf_->offset() - read_consumed_len_;
- int eoh = handshake_->ReadServerHandshake(data, len);
- if (eoh < 0) {
- // Not enough data, Retry when more data is available.
- return;
- }
- SkipReadBuffer(eoh);
- }
- if (handshake_->mode() != WebSocketHandshake::MODE_CONNECTED) {
- // Handshake failed.
- socket_stream_->Close();
- return;
- }
- ready_state_ = OPEN;
- if (delegate_)
- delegate_->OnOpen(this);
- if (current_read_buf_->offset() == read_consumed_len_) {
- // No remaining data after handshake message.
- break;
- }
- // FALL THROUGH
- case OPEN:
- case CLOSING: // need to process closing-frame from server.
- ProcessFrameData();
- break;
-
- case CLOSED:
- // Closed just after DoReceivedData is queued on |origin_loop_|.
- break;
- default:
- NOTREACHED();
- break;
- }
-}
-
-void WebSocket::ProcessFrameData() {
- DCHECK(current_read_buf_);
- if (server_closing_handshake_) {
- // Any data on the connection after the 0xFF frame is discarded.
- return;
- }
- scoped_refptr<WebSocket> protect(this);
- const char* start_frame =
- current_read_buf_->StartOfBuffer() + read_consumed_len_;
- const char* next_frame = start_frame;
- const char* p = next_frame;
- const char* end =
- current_read_buf_->StartOfBuffer() + current_read_buf_->offset();
- while (p < end) {
- // Let /error/ be false.
- bool error = false;
-
- // Handle the /frame type/ byte as follows.
- unsigned char frame_byte = static_cast<unsigned char>(*p++);
- if ((frame_byte & 0x80) == 0x80) {
- int length = 0;
- while (p < end) {
- if (length > std::numeric_limits<int>::max() / 128) {
- // frame length overflow.
- socket_stream_->Close();
- return;
- }
- unsigned char c = static_cast<unsigned char>(*p);
- length = length * 128 + (c & 0x7f);
- ++p;
- if ((c & 0x80) != 0x80)
- break;
- }
- // Checks if the frame body hasn't been completely received yet.
- // It also checks the case the frame length bytes haven't been completely
- // received yet, because p == end and length > 0 in such case.
- if (p + length < end) {
- p += length;
- next_frame = p;
- if (request_->version() != DRAFT75 &&
- frame_byte == 0xFF && length == 0) {
- // 4.2 Data framing 3. Handle the /frame type/ byte.
- // 8. If the /frame type/ is 0xFF and the /length/ was 0, then
- // run the following substeps:
- // 1. If the WebSocket closing handshake has not yet started, then
- // start the WebSocket closing handshake.
- server_closing_handshake_ = true;
- if (!closing_handshake_started_) {
- origin_loop_->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &WebSocket::StartClosingHandshake));
- } else {
- // If the WebSocket closing handshake has been started and
- // the WebSocket connection is not already closed, then close
- // the WebSocket connection.
- socket_stream_->Close();
- }
- return;
- }
- // 4.2 3-8 Otherwise, let /error/ be true.
- error = true;
- } else {
- // Not enough data in buffer.
- break;
- }
- } else {
- const char* msg_start = p;
- while (p < end && *p != '\xff')
- ++p;
- if (p < end && *p == '\xff') {
- if (frame_byte == 0x00) {
- if (delegate_) {
- delegate_->OnMessage(this, std::string(msg_start, p - msg_start));
- }
- } else {
- // Otherwise, discard the data and let /error/ to be true.
- error = true;
- }
- ++p;
- next_frame = p;
- }
- }
- // If /error/ is true, then *a WebSocket error has been detected.*
- if (error && delegate_)
- delegate_->OnError(this);
- }
- SkipReadBuffer(next_frame - start_frame);
-}
-
-void WebSocket::AddToReadBuffer(const char* data, int len) {
- DCHECK(current_read_buf_);
- // Check if |current_read_buf_| has enough space to store |len| of |data|.
- if (len >= current_read_buf_->RemainingCapacity()) {
- current_read_buf_->SetCapacity(
- current_read_buf_->offset() + len);
- }
-
- DCHECK(current_read_buf_->RemainingCapacity() >= len);
- memcpy(current_read_buf_->data(), data, len);
- current_read_buf_->set_offset(current_read_buf_->offset() + len);
-}
-
-void WebSocket::SkipReadBuffer(int len) {
- if (len == 0)
- return;
- DCHECK_GT(len, 0);
- read_consumed_len_ += len;
- int remaining = current_read_buf_->offset() - read_consumed_len_;
- DCHECK_GE(remaining, 0);
- if (remaining < read_consumed_len_ &&
- current_read_buf_->RemainingCapacity() < read_consumed_len_) {
- // Pre compaction:
- // 0 v-read_consumed_len_ v-offset v- capacity
- // |..processed..| .. remaining .. | .. RemainingCapacity |
- //
- memmove(current_read_buf_->StartOfBuffer(),
- current_read_buf_->StartOfBuffer() + read_consumed_len_,
- remaining);
- read_consumed_len_ = 0;
- current_read_buf_->set_offset(remaining);
- // Post compaction:
- // 0read_consumed_len_ v- offset v- capacity
- // |.. remaining .. | .. RemainingCapacity ... |
- //
- }
-}
-
-void WebSocket::StartClosingHandshake() {
- // 4.2 *start the WebSocket closing handshake*.
- if (closing_handshake_started_ || client_closing_handshake_) {
- // 1. If the WebSocket closing handshake has started, then abort these
- // steps.
- return;
- }
- // 2.,3. Send a 0xFF and 0x00 byte to the server.
- client_closing_handshake_ = true;
- IOBufferWithSize* buf = new IOBufferWithSize(2);
- memcpy(buf->data(), kClosingFrame, 2);
- pending_write_bufs_.push_back(make_scoped_refptr(buf));
- SendPending();
-}
-
-void WebSocket::DoForceCloseConnection() {
- // 4.2 *start the WebSocket closing handshake*
- // 6. If the WebSocket connection is not already closed, then close the
- // WebSocket connection. (If this happens, then the closing handshake
- // doesn't finish.)
- DCHECK(MessageLoop::current() == origin_loop_);
- force_close_task_ = NULL;
- FailConnection();
-}
-
-void WebSocket::FailConnection() {
- DCHECK(MessageLoop::current() == origin_loop_);
- // 6.1 Client-initiated closure.
- // *fail the WebSocket connection*.
- // the user agent must close the WebSocket connection, and may report the
- // problem to the user.
- if (!socket_stream_)
- return;
- socket_stream_->Close();
-}
-
-void WebSocket::DoClose() {
- DCHECK(MessageLoop::current() == origin_loop_);
- if (force_close_task_) {
- // WebSocket connection is closed while waiting a user-agent-determined
- // length of time after *The WebSocket closing handshake has started*.
- force_close_task_->Cancel();
- force_close_task_ = NULL;
- }
- WebSocketDelegate* delegate = delegate_;
- delegate_ = NULL;
- ready_state_ = CLOSED;
- if (!socket_stream_)
- return;
- socket_stream_ = NULL;
- if (delegate)
- delegate->OnClose(this,
- server_closing_handshake_ && closing_handshake_started_);
- Release();
-}
-
-void WebSocket::DoSocketError(int error) {
- DCHECK(MessageLoop::current() == origin_loop_);
- if (delegate_)
- delegate_->OnSocketError(this, error);
-}
-
-} // namespace net