Index: net/websockets/websocket.cc |
diff --git a/net/websockets/websocket.cc b/net/websockets/websocket.cc |
deleted file mode 100644 |
index f8d9eb91b5b5bb51ffe35f0b21580ecfcc7d8cbc..0000000000000000000000000000000000000000 |
--- 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 |