diff options
Diffstat (limited to 'net/websockets/websocket.cc')
-rw-r--r-- | net/websockets/websocket.cc | 484 |
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 |