diff options
author | toyoshim@chromium.org <toyoshim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-03 11:23:25 +0000 |
---|---|---|
committer | toyoshim@chromium.org <toyoshim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-03 11:23:25 +0000 |
commit | c4d45d1e5535ba2f268d2d05e54d3e523cb8d9d4 (patch) | |
tree | 0393fa7b0aa23920e36d475686edaa6d21945339 /net/websockets | |
parent | d1833ba1c6c70abd72782608f52f0d1f49688284 (diff) | |
download | chromium_src-c4d45d1e5535ba2f268d2d05e54d3e523cb8d9d4.zip chromium_src-c4d45d1e5535ba2f268d2d05e54d3e523cb8d9d4.tar.gz chromium_src-c4d45d1e5535ba2f268d2d05e54d3e523cb8d9d4.tar.bz2 |
WebSocket: Remove obsolete experiments related files
BUG=91489
TEST=NONE
Review URL: http://codereview.chromium.org/7567001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@95232 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/websockets')
-rw-r--r-- | net/websockets/websocket.cc | 484 | ||||
-rw-r--r-- | net/websockets/websocket.h | 235 | ||||
-rw-r--r-- | net/websockets/websocket_handshake.cc | 303 | ||||
-rw-r--r-- | net/websockets/websocket_handshake.h | 119 | ||||
-rw-r--r-- | net/websockets/websocket_handshake_draft75.cc | 154 | ||||
-rw-r--r-- | net/websockets/websocket_handshake_draft75.h | 64 | ||||
-rw-r--r-- | net/websockets/websocket_handshake_draft75_unittest.cc | 218 | ||||
-rw-r--r-- | net/websockets/websocket_handshake_unittest.cc | 331 | ||||
-rw-r--r-- | net/websockets/websocket_unittest.cc | 348 |
9 files changed, 0 insertions, 2256 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 diff --git a/net/websockets/websocket.h b/net/websockets/websocket.h deleted file mode 100644 index da72870..0000000 --- a/net/websockets/websocket.h +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright (c) 2011 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. -// -// WebSocket protocol implementation in chromium. -// It is intended to be used for live experiment of WebSocket connectivity -// metrics. -// Note that it is not used for WebKit's WebSocket communication. -// See third_party/WebKit/Source/WebCore/websockets/ instead. - -#ifndef NET_WEBSOCKETS_WEBSOCKET_H_ -#define NET_WEBSOCKETS_WEBSOCKET_H_ -#pragma once - -#include <deque> -#include <string> - -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "googleurl/src/gurl.h" -#include "net/base/io_buffer.h" -#include "net/base/net_api.h" -#include "net/socket_stream/socket_stream.h" -#include "net/url_request/url_request_context.h" - -class MessageLoop; - -namespace net { - -class ClientSocketFactory; -class HostResolver; - -class WebSocket; -class WebSocketHandshake; - -// Delegate methods will be called on the same message loop as -// WebSocket is constructed. -class WebSocketDelegate { - public: - virtual ~WebSocketDelegate() {} - - // Called when WebSocket connection has been established. - virtual void OnOpen(WebSocket* socket) = 0; - - // Called when |msg| is received at |socket|. - // |msg| should be in UTF-8. - virtual void OnMessage(WebSocket* socket, const std::string& msg) = 0; - - // Called when WebSocket error has been detected. - virtual void OnError(WebSocket* socket) {} - - // Called when |socket| is closed. - virtual void OnClose(WebSocket* socket, bool was_clean) = 0; - - // Called when an error occured on |socket|. - virtual void OnSocketError(const WebSocket* socket, int error) {} -}; - -class NET_API WebSocket : public base::RefCountedThreadSafe<WebSocket>, - public SocketStream::Delegate { - public: - enum State { - INITIALIZED = -1, - CONNECTING = 0, - OPEN = 1, - CLOSING = 2, - CLOSED = 3, - }; - enum ProtocolVersion { - DEFAULT_VERSION = 0, - DRAFT75 = 1, - }; - class Request { - public: - Request(const GURL& url, - const std::string& protocol, - const std::string& origin, - const std::string& location, - ProtocolVersion version, - net::URLRequestContext* context) - : url_(url), - protocol_(protocol), - origin_(origin), - location_(location), - version_(version), - context_(context), - host_resolver_(NULL), - client_socket_factory_(NULL) {} - ~Request() {} - - const GURL& url() const { return url_; } - const std::string& protocol() const { return protocol_; } - const std::string& origin() const { return origin_; } - const std::string& location() const { return location_; } - ProtocolVersion version() const { return version_; } - net::URLRequestContext* context() const { return context_; } - - // Sets an alternative HostResolver. For testing purposes only. - void SetHostResolver(HostResolver* host_resolver) { - host_resolver_ = host_resolver; - } - HostResolver* host_resolver() const { return host_resolver_; } - - // Sets an alternative ClientSocketFactory. Doesn't take ownership of - // |factory|. For testing purposes only. - void SetClientSocketFactory(ClientSocketFactory* factory) { - client_socket_factory_ = factory; - } - ClientSocketFactory* client_socket_factory() const { - return client_socket_factory_; - } - - private: - GURL url_; - std::string protocol_; - std::string origin_; - std::string location_; - ProtocolVersion version_; - scoped_refptr<net::URLRequestContext> context_; - - HostResolver* host_resolver_; - ClientSocketFactory* client_socket_factory_; - - DISALLOW_COPY_AND_ASSIGN(Request); - }; - - // Constructs new WebSocket. - // It takes ownership of |req|. - // |delegate| must be alive while this object is alive. - WebSocket(Request* req, WebSocketDelegate* delegate); - - const Request* request() const { return request_.get(); } - WebSocketDelegate* delegate() const { return delegate_; } - - State ready_state() const { return ready_state_; } - - // Connects new WebSocket. - void Connect(); - - // Sends |msg| on the WebSocket connection. - // |msg| should be in UTF-8. - void Send(const std::string& msg); - - // Closes the WebSocket connection. - void Close(); - - // Detach delegate. Call before delegate is deleted. - // Once delegate is detached, close the WebSocket connection and never call - // delegate back. - void DetachDelegate(); - - // SocketStream::Delegate methods. - // Called on IO thread. - virtual void OnConnected(SocketStream* socket_stream, - int max_pending_send_allowed); - virtual void OnSentData(SocketStream* socket_stream, int amount_sent); - virtual void OnReceivedData(SocketStream* socket_stream, - const char* data, int len); - virtual void OnClose(SocketStream* socket); - virtual void OnError(const SocketStream* socket, int error); - - private: - typedef std::deque< scoped_refptr<IOBufferWithSize> > PendingDataQueue; - - friend class WebSocketTest; - - friend class base::RefCountedThreadSafe<WebSocket>; - virtual ~WebSocket(); - - // Sends pending data in |current_write_buf_| and/or |pending_write_bufs_|. - void SendPending(); - - // Handles received data. - void DoReceivedData(); - - // Processes frame data in |current_read_buf_|. - void ProcessFrameData(); - - // Adds |len| bytes of |data| to |current_read_buf_|. - void AddToReadBuffer(const char* data, int len); - - // Skips |len| bytes in |current_read_buf_|. - void SkipReadBuffer(int len); - - void StartClosingHandshake(); - void DoForceCloseConnection(); - void FailConnection(); - // Handles closed connection. - void DoClose(); - - // Handles socket error report. - void DoSocketError(int error); - - State ready_state_; - scoped_ptr<Request> request_; - scoped_ptr<WebSocketHandshake> handshake_; - WebSocketDelegate* delegate_; - MessageLoop* origin_loop_; - - scoped_refptr<SocketStream> socket_stream_; - int max_pending_send_allowed_; - - // [0..offset) is received data from |socket_stream_|. - // [0..read_consumed_len_) is already processed. - // [read_consumed_len_..offset) is unprocessed data. - // [offset..capacity) is free space. - scoped_refptr<GrowableIOBuffer> current_read_buf_; - int read_consumed_len_; - - // Drainable IOBuffer on the front of |pending_write_bufs_|. - // [0..offset) is already sent to |socket_stream_|. - // [offset..size) is being sent to |socket_stream_|, waiting OnSentData. - scoped_refptr<DrainableIOBuffer> current_write_buf_; - - // Deque of IOBuffers in pending. - // Front IOBuffer is being sent via |current_write_buf_|. - PendingDataQueue pending_write_bufs_; - - // True when the 0xFF frame with length 0x00 is received. - bool server_closing_handshake_; - // True when trying to send 0xFF and 0x00 bytes. - bool client_closing_handshake_; - // True when send 0xFF and 0x00 bytes. - bool closing_handshake_started_; - // Task to close the connection after closing handshake has started and - // |closing_handshake_timeout_|. - CancelableTask* force_close_task_; - int64 closing_handshake_timeout_; - - DISALLOW_COPY_AND_ASSIGN(WebSocket); -}; - -} // namespace net - -#endif // NET_WEBSOCKETS_WEBSOCKET_H_ diff --git a/net/websockets/websocket_handshake.cc b/net/websockets/websocket_handshake.cc deleted file mode 100644 index 789c6df..0000000 --- a/net/websockets/websocket_handshake.cc +++ /dev/null @@ -1,303 +0,0 @@ -// Copyright (c) 2011 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 "net/websockets/websocket_handshake.h" - -#include <algorithm> -#include <vector> - -#include "base/logging.h" -#include "base/md5.h" -#include "base/memory/ref_counted.h" -#include "base/rand_util.h" -#include "base/string_number_conversions.h" -#include "base/string_util.h" -#include "base/stringprintf.h" -#include "net/http/http_response_headers.h" -#include "net/http/http_util.h" - -namespace net { - -const int WebSocketHandshake::kWebSocketPort = 80; -const int WebSocketHandshake::kSecureWebSocketPort = 443; - -WebSocketHandshake::WebSocketHandshake( - const GURL& url, - const std::string& origin, - const std::string& location, - const std::string& protocol) - : url_(url), - origin_(origin), - location_(location), - protocol_(protocol), - mode_(MODE_INCOMPLETE) { -} - -WebSocketHandshake::~WebSocketHandshake() { -} - -bool WebSocketHandshake::is_secure() const { - return url_.SchemeIs("wss"); -} - -std::string WebSocketHandshake::CreateClientHandshakeMessage() { - if (!parameter_.get()) { - parameter_.reset(new Parameter); - parameter_->GenerateKeys(); - } - std::string msg; - - // WebSocket protocol 4.1 Opening handshake. - - msg = "GET "; - msg += GetResourceName(); - msg += " HTTP/1.1\r\n"; - - std::vector<std::string> fields; - - fields.push_back("Upgrade: WebSocket"); - fields.push_back("Connection: Upgrade"); - - fields.push_back("Host: " + GetHostFieldValue()); - - fields.push_back("Origin: " + GetOriginFieldValue()); - - if (!protocol_.empty()) - fields.push_back("Sec-WebSocket-Protocol: " + protocol_); - - // TODO(ukai): Add cookie if necessary. - - fields.push_back("Sec-WebSocket-Key1: " + parameter_->GetSecWebSocketKey1()); - fields.push_back("Sec-WebSocket-Key2: " + parameter_->GetSecWebSocketKey2()); - - std::random_shuffle(fields.begin(), fields.end(), base::RandGenerator); - - for (size_t i = 0; i < fields.size(); i++) { - msg += fields[i] + "\r\n"; - } - msg += "\r\n"; - - msg.append(parameter_->GetKey3()); - return msg; -} - -int WebSocketHandshake::ReadServerHandshake(const char* data, size_t len) { - mode_ = MODE_INCOMPLETE; - int eoh = HttpUtil::LocateEndOfHeaders(data, len); - if (eoh < 0) - return -1; - - scoped_refptr<HttpResponseHeaders> headers( - new HttpResponseHeaders(HttpUtil::AssembleRawHeaders(data, eoh))); - - if (headers->response_code() != 101) { - mode_ = MODE_FAILED; - DVLOG(1) << "Bad response code: " << headers->response_code(); - return eoh; - } - mode_ = MODE_NORMAL; - if (!ProcessHeaders(*headers) || !CheckResponseHeaders()) { - DVLOG(1) << "Process Headers failed: " << std::string(data, eoh); - mode_ = MODE_FAILED; - return eoh; - } - if (len < static_cast<size_t>(eoh + Parameter::kExpectedResponseSize)) { - mode_ = MODE_INCOMPLETE; - return -1; - } - uint8 expected[Parameter::kExpectedResponseSize]; - parameter_->GetExpectedResponse(expected); - if (memcmp(&data[eoh], expected, Parameter::kExpectedResponseSize)) { - mode_ = MODE_FAILED; - return eoh + Parameter::kExpectedResponseSize; - } - mode_ = MODE_CONNECTED; - return eoh + Parameter::kExpectedResponseSize; -} - -std::string WebSocketHandshake::GetResourceName() const { - std::string resource_name = url_.path(); - if (url_.has_query()) { - resource_name += "?"; - resource_name += url_.query(); - } - return resource_name; -} - -std::string WebSocketHandshake::GetHostFieldValue() const { - // url_.host() is expected to be encoded in punnycode here. - std::string host = StringToLowerASCII(url_.host()); - if (url_.has_port()) { - bool secure = is_secure(); - int port = url_.EffectiveIntPort(); - if ((!secure && - port != kWebSocketPort && port != url_parse::PORT_UNSPECIFIED) || - (secure && - port != kSecureWebSocketPort && port != url_parse::PORT_UNSPECIFIED)) { - host += ":"; - host += base::IntToString(port); - } - } - return host; -} - -std::string WebSocketHandshake::GetOriginFieldValue() const { - // It's OK to lowercase the origin as the Origin header does not contain - // the path or query portions, as per - // http://tools.ietf.org/html/draft-abarth-origin-00. - // - // TODO(satorux): Should we trim the port portion here if it's 80 for - // http:// or 443 for https:// ? Or can we assume it's done by the - // client of the library? - return StringToLowerASCII(origin_); -} - -/* static */ -bool WebSocketHandshake::GetSingleHeader(const HttpResponseHeaders& headers, - const std::string& name, - std::string* value) { - std::string first_value; - void* iter = NULL; - if (!headers.EnumerateHeader(&iter, name, &first_value)) - return false; - - // Checks no more |name| found in |headers|. - // Second call of EnumerateHeader() must return false. - std::string second_value; - if (headers.EnumerateHeader(&iter, name, &second_value)) - return false; - *value = first_value; - return true; -} - -bool WebSocketHandshake::ProcessHeaders(const HttpResponseHeaders& headers) { - std::string value; - if (!GetSingleHeader(headers, "upgrade", &value) || - value != "WebSocket") - return false; - - if (!GetSingleHeader(headers, "connection", &value) || - !LowerCaseEqualsASCII(value, "upgrade")) - return false; - - if (!GetSingleHeader(headers, "sec-websocket-origin", &ws_origin_)) - return false; - - if (!GetSingleHeader(headers, "sec-websocket-location", &ws_location_)) - return false; - - // If |protocol_| is not specified by client, we don't care if there's - // protocol field or not as specified in the spec. - if (!protocol_.empty() - && !GetSingleHeader(headers, "sec-websocket-protocol", &ws_protocol_)) - return false; - return true; -} - -bool WebSocketHandshake::CheckResponseHeaders() const { - DCHECK(mode_ == MODE_NORMAL); - if (!LowerCaseEqualsASCII(origin_, ws_origin_.c_str())) - return false; - if (location_ != ws_location_) - return false; - if (!protocol_.empty() && protocol_ != ws_protocol_) - return false; - return true; -} - -namespace { - -// unsigned int version of base::RandInt(). -// we can't use base::RandInt(), because max would be negative if it is -// represented as int, so DCHECK(min <= max) fails. -uint32 RandUint32(uint32 min, uint32 max) { - DCHECK(min <= max); - - uint64 range = static_cast<int64>(max) - min + 1; - uint64 number = base::RandGenerator(range); - uint32 result = min + static_cast<uint32>(number); - DCHECK(result >= min && result <= max); - return result; -} - -} - -uint32 (*WebSocketHandshake::Parameter::rand_)(uint32 min, uint32 max) = - RandUint32; -uint8 randomCharacterInSecWebSocketKey[0x2F - 0x20 + 0x7E - 0x39]; - -WebSocketHandshake::Parameter::Parameter() - : number_1_(0), number_2_(0) { - if (randomCharacterInSecWebSocketKey[0] == '\0') { - int i = 0; - for (int ch = 0x21; ch <= 0x2F; ch++, i++) - randomCharacterInSecWebSocketKey[i] = ch; - for (int ch = 0x3A; ch <= 0x7E; ch++, i++) - randomCharacterInSecWebSocketKey[i] = ch; - } -} - -WebSocketHandshake::Parameter::~Parameter() {} - -void WebSocketHandshake::Parameter::GenerateKeys() { - GenerateSecWebSocketKey(&number_1_, &key_1_); - GenerateSecWebSocketKey(&number_2_, &key_2_); - GenerateKey3(); -} - -static void SetChallengeNumber(uint8* buf, uint32 number) { - uint8* p = buf + 3; - for (int i = 0; i < 4; i++) { - *p = (uint8)(number & 0xFF); - --p; - number >>= 8; - } -} - -void WebSocketHandshake::Parameter::GetExpectedResponse(uint8 *expected) const { - uint8 challenge[kExpectedResponseSize]; - SetChallengeNumber(&challenge[0], number_1_); - SetChallengeNumber(&challenge[4], number_2_); - memcpy(&challenge[8], key_3_.data(), kKey3Size); - base::MD5Digest digest; - base::MD5Sum(challenge, kExpectedResponseSize, &digest); - memcpy(expected, digest.a, kExpectedResponseSize); -} - -/* static */ -void WebSocketHandshake::Parameter::SetRandomNumberGenerator( - uint32 (*rand)(uint32 min, uint32 max)) { - rand_ = rand; -} - -void WebSocketHandshake::Parameter::GenerateSecWebSocketKey( - uint32* number, std::string* key) { - uint32 space = rand_(1, 12); - uint32 max = 4294967295U / space; - *number = rand_(0, max); - uint32 product = *number * space; - - std::string s = base::StringPrintf("%u", product); - int n = rand_(1, 12); - for (int i = 0; i < n; i++) { - int pos = rand_(0, s.length()); - int chpos = rand_(0, sizeof(randomCharacterInSecWebSocketKey) - 1); - s = s.substr(0, pos).append(1, randomCharacterInSecWebSocketKey[chpos]) + - s.substr(pos); - } - for (uint32 i = 0; i < space; i++) { - int pos = rand_(1, s.length() - 1); - s = s.substr(0, pos) + " " + s.substr(pos); - } - *key = s; -} - -void WebSocketHandshake::Parameter::GenerateKey3() { - key_3_.clear(); - for (int i = 0; i < 8; i++) { - key_3_.append(1, rand_(0, 255)); - } -} - -} // namespace net diff --git a/net/websockets/websocket_handshake.h b/net/websockets/websocket_handshake.h deleted file mode 100644 index b0b00a7..0000000 --- a/net/websockets/websocket_handshake.h +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (c) 2011 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. - -#ifndef NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_H_ -#define NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_H_ -#pragma once - -#include <string> - -#include "base/basictypes.h" -#include "base/memory/scoped_ptr.h" -#include "googleurl/src/gurl.h" -#include "net/base/net_api.h" - -namespace net { - -class HttpResponseHeaders; - -class NET_TEST WebSocketHandshake { - public: - static const int kWebSocketPort; - static const int kSecureWebSocketPort; - - enum Mode { - MODE_INCOMPLETE, MODE_NORMAL, MODE_FAILED, MODE_CONNECTED - }; - WebSocketHandshake(const GURL& url, - const std::string& origin, - const std::string& location, - const std::string& protocol); - virtual ~WebSocketHandshake(); - - bool is_secure() const; - // Creates the client handshake message from |this|. - virtual std::string CreateClientHandshakeMessage(); - - // Reads server handshake message in |len| of |data|, updates |mode_| and - // returns number of bytes of the server handshake message. - // Once connection is established, |mode_| will be MODE_CONNECTED. - // If connection establishment failed, |mode_| will be MODE_FAILED. - // Returns negative if the server handshake message is incomplete. - virtual int ReadServerHandshake(const char* data, size_t len); - Mode mode() const { return mode_; } - - protected: - std::string GetResourceName() const; - std::string GetHostFieldValue() const; - std::string GetOriginFieldValue() const; - - // Gets the value of the specified header. - // It assures only one header of |name| in |headers|. - // Returns true iff single header of |name| is found in |headers| - // and |value| is filled with the value. - // Returns false otherwise. - static bool GetSingleHeader(const HttpResponseHeaders& headers, - const std::string& name, - std::string* value); - - GURL url_; - // Handshake messages that the client is going to send out. - std::string origin_; - std::string location_; - std::string protocol_; - - Mode mode_; - - // Handshake messages that server sent. - std::string ws_origin_; - std::string ws_location_; - std::string ws_protocol_; - - private: - friend class WebSocketHandshakeTest; - - class NET_TEST Parameter { - public: - static const int kKey3Size = 8; - static const int kExpectedResponseSize = 16; - Parameter(); - ~Parameter(); - - void GenerateKeys(); - const std::string& GetSecWebSocketKey1() const { return key_1_; } - const std::string& GetSecWebSocketKey2() const { return key_2_; } - const std::string& GetKey3() const { return key_3_; } - - void GetExpectedResponse(uint8* expected) const; - - private: - friend class WebSocketHandshakeTest; - - // Set random number generator. |rand| should return a random number - // between min and max (inclusive). - static void SetRandomNumberGenerator( - uint32 (*rand)(uint32 min, uint32 max)); - void GenerateSecWebSocketKey(uint32* number, std::string* key); - void GenerateKey3(); - - uint32 number_1_; - uint32 number_2_; - std::string key_1_; - std::string key_2_; - std::string key_3_; - - static uint32 (*rand_)(uint32 min, uint32 max); - }; - - virtual bool ProcessHeaders(const HttpResponseHeaders& headers); - virtual bool CheckResponseHeaders() const; - - scoped_ptr<Parameter> parameter_; - - DISALLOW_COPY_AND_ASSIGN(WebSocketHandshake); -}; - -} // namespace net - -#endif // NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_H_ diff --git a/net/websockets/websocket_handshake_draft75.cc b/net/websockets/websocket_handshake_draft75.cc deleted file mode 100644 index 34ecda8..0000000 --- a/net/websockets/websocket_handshake_draft75.cc +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright (c) 2011 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 "net/websockets/websocket_handshake_draft75.h" - -#include "base/memory/ref_counted.h" -#include "base/string_util.h" -#include "net/http/http_response_headers.h" -#include "net/http/http_util.h" - -namespace net { - -const char WebSocketHandshakeDraft75::kServerHandshakeHeader[] = - "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"; -const size_t WebSocketHandshakeDraft75::kServerHandshakeHeaderLength = - sizeof(kServerHandshakeHeader) - 1; - -const char WebSocketHandshakeDraft75::kUpgradeHeader[] = - "Upgrade: WebSocket\r\n"; -const size_t WebSocketHandshakeDraft75::kUpgradeHeaderLength = - sizeof(kUpgradeHeader) - 1; - -const char WebSocketHandshakeDraft75::kConnectionHeader[] = - "Connection: Upgrade\r\n"; -const size_t WebSocketHandshakeDraft75::kConnectionHeaderLength = - sizeof(kConnectionHeader) - 1; - -WebSocketHandshakeDraft75::WebSocketHandshakeDraft75( - const GURL& url, - const std::string& origin, - const std::string& location, - const std::string& protocol) - : WebSocketHandshake(url, origin, location, protocol) { -} - -WebSocketHandshakeDraft75::~WebSocketHandshakeDraft75() { -} - -std::string WebSocketHandshakeDraft75::CreateClientHandshakeMessage() { - std::string msg; - msg = "GET "; - msg += GetResourceName(); - msg += " HTTP/1.1\r\n"; - msg += kUpgradeHeader; - msg += kConnectionHeader; - msg += "Host: "; - msg += GetHostFieldValue(); - msg += "\r\n"; - msg += "Origin: "; - msg += GetOriginFieldValue(); - msg += "\r\n"; - if (!protocol_.empty()) { - msg += "WebSocket-Protocol: "; - msg += protocol_; - msg += "\r\n"; - } - // TODO(ukai): Add cookie if necessary. - msg += "\r\n"; - return msg; -} - -int WebSocketHandshakeDraft75::ReadServerHandshake( - const char* data, size_t len) { - mode_ = MODE_INCOMPLETE; - if (len < kServerHandshakeHeaderLength) { - return -1; - } - if (!memcmp(data, kServerHandshakeHeader, kServerHandshakeHeaderLength)) { - mode_ = MODE_NORMAL; - } else { - int eoh = HttpUtil::LocateEndOfHeaders(data, len); - if (eoh < 0) - return -1; - return eoh; - } - const char* p = data + kServerHandshakeHeaderLength; - const char* end = data + len; - - if (mode_ == MODE_NORMAL) { - size_t header_size = end - p; - if (header_size < kUpgradeHeaderLength) - return -1; - if (memcmp(p, kUpgradeHeader, kUpgradeHeaderLength)) { - mode_ = MODE_FAILED; - DVLOG(1) << "Bad Upgrade Header " << std::string(p, kUpgradeHeaderLength); - return p - data; - } - p += kUpgradeHeaderLength; - header_size = end - p; - if (header_size < kConnectionHeaderLength) - return -1; - if (memcmp(p, kConnectionHeader, kConnectionHeaderLength)) { - mode_ = MODE_FAILED; - DVLOG(1) << "Bad Connection Header " - << std::string(p, kConnectionHeaderLength); - return p - data; - } - p += kConnectionHeaderLength; - } - - int eoh = HttpUtil::LocateEndOfHeaders(data, len); - if (eoh == -1) - return eoh; - - scoped_refptr<HttpResponseHeaders> headers( - new HttpResponseHeaders(HttpUtil::AssembleRawHeaders(data, eoh))); - if (!ProcessHeaders(*headers)) { - DVLOG(1) << "Process Headers failed: " << std::string(data, eoh); - mode_ = MODE_FAILED; - } - switch (mode_) { - case MODE_NORMAL: - if (CheckResponseHeaders()) { - mode_ = MODE_CONNECTED; - } else { - mode_ = MODE_FAILED; - } - break; - default: - mode_ = MODE_FAILED; - break; - } - return eoh; -} - -bool WebSocketHandshakeDraft75::ProcessHeaders( - const HttpResponseHeaders& headers) { - if (!GetSingleHeader(headers, "websocket-origin", &ws_origin_)) - return false; - - if (!GetSingleHeader(headers, "websocket-location", &ws_location_)) - return false; - - // If |protocol_| is not specified by client, we don't care if there's - // protocol field or not as specified in the spec. - if (!protocol_.empty() - && !GetSingleHeader(headers, "websocket-protocol", &ws_protocol_)) - return false; - return true; -} - -bool WebSocketHandshakeDraft75::CheckResponseHeaders() const { - DCHECK(mode_ == MODE_NORMAL); - if (!LowerCaseEqualsASCII(origin_, ws_origin_.c_str())) - return false; - if (location_ != ws_location_) - return false; - if (!protocol_.empty() && protocol_ != ws_protocol_) - return false; - return true; -} - -} // namespace net diff --git a/net/websockets/websocket_handshake_draft75.h b/net/websockets/websocket_handshake_draft75.h deleted file mode 100644 index 12e11e1..0000000 --- a/net/websockets/websocket_handshake_draft75.h +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) 2011 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. - -#ifndef NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_DRAFT75_H_ -#define NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_DRAFT75_H_ -#pragma once - -#include <string> - -#include "base/basictypes.h" -#include "googleurl/src/gurl.h" -#include "net/websockets/websocket_handshake.h" - -namespace net { - -class HttpResponseHeaders; - -class NET_TEST WebSocketHandshakeDraft75 : public WebSocketHandshake { - public: - static const int kWebSocketPort; - static const int kSecureWebSocketPort; - static const char kServerHandshakeHeader[]; - static const size_t kServerHandshakeHeaderLength; - static const char kUpgradeHeader[]; - static const size_t kUpgradeHeaderLength; - static const char kConnectionHeader[]; - static const size_t kConnectionHeaderLength; - - WebSocketHandshakeDraft75(const GURL& url, - const std::string& origin, - const std::string& location, - const std::string& protocol); - virtual ~WebSocketHandshakeDraft75(); - - // Creates the client handshake message from |this|. - virtual std::string CreateClientHandshakeMessage(); - - // Reads server handshake message in |len| of |data|, updates |mode_| and - // returns number of bytes of the server handshake message. - // Once connection is established, |mode_| will be MODE_CONNECTED. - // If connection establishment failed, |mode_| will be MODE_FAILED. - // Returns negative if the server handshake message is incomplete. - virtual int ReadServerHandshake(const char* data, size_t len); - - private: - // Processes server handshake message, parsed as |headers|, and updates - // |ws_origin_|, |ws_location_| and |ws_protocol_|. - // Returns true if it's ok. - // Returns false otherwise (e.g. duplicate WebSocket-Origin: header, etc.) - virtual bool ProcessHeaders(const HttpResponseHeaders& headers); - - // Checks |ws_origin_|, |ws_location_| and |ws_protocol_| are valid - // against |origin_|, |location_| and |protocol_|. - // Returns true if it's ok. - // Returns false otherwise (e.g. origin mismatch, etc.) - virtual bool CheckResponseHeaders() const; - - DISALLOW_COPY_AND_ASSIGN(WebSocketHandshakeDraft75); -}; - -} // namespace net - -#endif // NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_DRAFT75_H_ diff --git a/net/websockets/websocket_handshake_draft75_unittest.cc b/net/websockets/websocket_handshake_draft75_unittest.cc deleted file mode 100644 index 4f5db31..0000000 --- a/net/websockets/websocket_handshake_draft75_unittest.cc +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright (c) 2011 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 "net/websockets/websocket_handshake_draft75.h" - -#include <string> -#include <vector> - -#include "base/memory/scoped_ptr.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/platform_test.h" - -namespace net { - -TEST(WebSocketHandshakeDraft75Test, Connect) { - const std::string kExpectedClientHandshakeMessage = - "GET /demo HTTP/1.1\r\n" - "Upgrade: WebSocket\r\n" - "Connection: Upgrade\r\n" - "Host: example.com\r\n" - "Origin: http://example.com\r\n" - "WebSocket-Protocol: sample\r\n" - "\r\n"; - - scoped_ptr<WebSocketHandshakeDraft75> handshake( - new WebSocketHandshakeDraft75(GURL("ws://example.com/demo"), - "http://example.com", - "ws://example.com/demo", - "sample")); - EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode()); - EXPECT_EQ(kExpectedClientHandshakeMessage, - handshake->CreateClientHandshakeMessage()); - - const char kResponse[] = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" - "Upgrade: WebSocket\r\n" - "Connection: Upgrade\r\n" - "WebSocket-Origin: http://example.com\r\n" - "WebSocket-Location: ws://example.com/demo\r\n" - "WebSocket-Protocol: sample\r\n" - "\r\n"; - - EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode()); - // too short - EXPECT_EQ(-1, handshake->ReadServerHandshake(kResponse, 16)); - EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode()); - // only status line - EXPECT_EQ(-1, handshake->ReadServerHandshake( - kResponse, - WebSocketHandshakeDraft75::kServerHandshakeHeaderLength)); - EXPECT_EQ(WebSocketHandshake::MODE_NORMAL, handshake->mode()); - // by upgrade header - EXPECT_EQ(-1, handshake->ReadServerHandshake( - kResponse, - WebSocketHandshakeDraft75::kServerHandshakeHeaderLength + - WebSocketHandshakeDraft75::kUpgradeHeaderLength)); - EXPECT_EQ(WebSocketHandshake::MODE_NORMAL, handshake->mode()); - // by connection header - EXPECT_EQ(-1, handshake->ReadServerHandshake( - kResponse, - WebSocketHandshakeDraft75::kServerHandshakeHeaderLength + - WebSocketHandshakeDraft75::kUpgradeHeaderLength + - WebSocketHandshakeDraft75::kConnectionHeaderLength)); - EXPECT_EQ(WebSocketHandshake::MODE_NORMAL, handshake->mode()); - - EXPECT_EQ(-1, handshake->ReadServerHandshake( - kResponse, sizeof(kResponse) - 2)); - EXPECT_EQ(WebSocketHandshake::MODE_NORMAL, handshake->mode()); - - int handshake_length = strlen(kResponse); - EXPECT_EQ(handshake_length, handshake->ReadServerHandshake( - kResponse, sizeof(kResponse) - 1)); // -1 for terminating \0 - EXPECT_EQ(WebSocketHandshake::MODE_CONNECTED, handshake->mode()); -} - -TEST(WebSocketHandshakeDraft75Test, ServerSentData) { - const std::string kExpectedClientHandshakeMessage = - "GET /demo HTTP/1.1\r\n" - "Upgrade: WebSocket\r\n" - "Connection: Upgrade\r\n" - "Host: example.com\r\n" - "Origin: http://example.com\r\n" - "WebSocket-Protocol: sample\r\n" - "\r\n"; - scoped_ptr<WebSocketHandshakeDraft75> handshake( - new WebSocketHandshakeDraft75(GURL("ws://example.com/demo"), - "http://example.com", - "ws://example.com/demo", - "sample")); - EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode()); - EXPECT_EQ(kExpectedClientHandshakeMessage, - handshake->CreateClientHandshakeMessage()); - - const char kResponse[] ="HTTP/1.1 101 Web Socket Protocol Handshake\r\n" - "Upgrade: WebSocket\r\n" - "Connection: Upgrade\r\n" - "WebSocket-Origin: http://example.com\r\n" - "WebSocket-Location: ws://example.com/demo\r\n" - "WebSocket-Protocol: sample\r\n" - "\r\n" - "\0Hello\xff"; - - int handshake_length = strlen(kResponse); - EXPECT_EQ(handshake_length, handshake->ReadServerHandshake( - kResponse, sizeof(kResponse) - 1)); // -1 for terminating \0 - EXPECT_EQ(WebSocketHandshake::MODE_CONNECTED, handshake->mode()); -} - -TEST(WebSocketHandshakeDraft75Test, CreateClientHandshakeMessage_Simple) { - scoped_ptr<WebSocketHandshakeDraft75> handshake( - new WebSocketHandshakeDraft75(GURL("ws://example.com/demo"), - "http://example.com", - "ws://example.com/demo", - "sample")); - EXPECT_EQ("GET /demo HTTP/1.1\r\n" - "Upgrade: WebSocket\r\n" - "Connection: Upgrade\r\n" - "Host: example.com\r\n" - "Origin: http://example.com\r\n" - "WebSocket-Protocol: sample\r\n" - "\r\n", - handshake->CreateClientHandshakeMessage()); -} - -TEST(WebSocketHandshakeDraft75Test, CreateClientHandshakeMessage_PathAndQuery) { - scoped_ptr<WebSocketHandshakeDraft75> handshake( - new WebSocketHandshakeDraft75(GURL("ws://example.com/Test?q=xxx&p=%20"), - "http://example.com", - "ws://example.com/demo", - "sample")); - // Path and query should be preserved as-is. - EXPECT_THAT(handshake->CreateClientHandshakeMessage(), - testing::HasSubstr("GET /Test?q=xxx&p=%20 HTTP/1.1\r\n")); -} - -TEST(WebSocketHandshakeDraft75Test, CreateClientHandshakeMessage_Host) { - scoped_ptr<WebSocketHandshakeDraft75> handshake( - new WebSocketHandshakeDraft75(GURL("ws://Example.Com/demo"), - "http://Example.Com", - "ws://Example.Com/demo", - "sample")); - // Host should be lowercased - EXPECT_THAT(handshake->CreateClientHandshakeMessage(), - testing::HasSubstr("Host: example.com\r\n")); - EXPECT_THAT(handshake->CreateClientHandshakeMessage(), - testing::HasSubstr("Origin: http://example.com\r\n")); -} - -TEST(WebSocketHandshakeDraft75Test, CreateClientHandshakeMessage_TrimPort80) { - scoped_ptr<WebSocketHandshakeDraft75> handshake( - new WebSocketHandshakeDraft75(GURL("ws://example.com:80/demo"), - "http://example.com", - "ws://example.com/demo", - "sample")); - // :80 should be trimmed as it's the default port for ws://. - EXPECT_THAT(handshake->CreateClientHandshakeMessage(), - testing::HasSubstr("Host: example.com\r\n")); -} - -TEST(WebSocketHandshakeDraft75Test, CreateClientHandshakeMessage_TrimPort443) { - scoped_ptr<WebSocketHandshakeDraft75> handshake( - new WebSocketHandshakeDraft75(GURL("wss://example.com:443/demo"), - "http://example.com", - "wss://example.com/demo", - "sample")); - // :443 should be trimmed as it's the default port for wss://. - EXPECT_THAT(handshake->CreateClientHandshakeMessage(), - testing::HasSubstr("Host: example.com\r\n")); -} - -TEST(WebSocketHandshakeDraft75Test, - CreateClientHandshakeMessage_NonDefaultPortForWs) { - scoped_ptr<WebSocketHandshakeDraft75> handshake( - new WebSocketHandshakeDraft75(GURL("ws://example.com:8080/demo"), - "http://example.com", - "wss://example.com/demo", - "sample")); - // :8080 should be preserved as it's not the default port for ws://. - EXPECT_THAT(handshake->CreateClientHandshakeMessage(), - testing::HasSubstr("Host: example.com:8080\r\n")); -} - -TEST(WebSocketHandshakeDraft75Test, - CreateClientHandshakeMessage_NonDefaultPortForWss) { - scoped_ptr<WebSocketHandshakeDraft75> handshake( - new WebSocketHandshakeDraft75(GURL("wss://example.com:4443/demo"), - "http://example.com", - "wss://example.com/demo", - "sample")); - // :4443 should be preserved as it's not the default port for wss://. - EXPECT_THAT(handshake->CreateClientHandshakeMessage(), - testing::HasSubstr("Host: example.com:4443\r\n")); -} - -TEST(WebSocketHandshakeDraft75Test, CreateClientHandshakeMessage_WsBut443) { - scoped_ptr<WebSocketHandshakeDraft75> handshake( - new WebSocketHandshakeDraft75(GURL("ws://example.com:443/demo"), - "http://example.com", - "ws://example.com/demo", - "sample")); - // :443 should be preserved as it's not the default port for ws://. - EXPECT_THAT(handshake->CreateClientHandshakeMessage(), - testing::HasSubstr("Host: example.com:443\r\n")); -} - -TEST(WebSocketHandshakeDraft75Test, CreateClientHandshakeMessage_WssBut80) { - scoped_ptr<WebSocketHandshakeDraft75> handshake( - new WebSocketHandshakeDraft75(GURL("wss://example.com:80/demo"), - "http://example.com", - "wss://example.com/demo", - "sample")); - // :80 should be preserved as it's not the default port for wss://. - EXPECT_THAT(handshake->CreateClientHandshakeMessage(), - testing::HasSubstr("Host: example.com:80\r\n")); -} - -} // namespace net diff --git a/net/websockets/websocket_handshake_unittest.cc b/net/websockets/websocket_handshake_unittest.cc deleted file mode 100644 index 61290b2..0000000 --- a/net/websockets/websocket_handshake_unittest.cc +++ /dev/null @@ -1,331 +0,0 @@ -// Copyright (c) 2011 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 "net/websockets/websocket_handshake.h" - -#include <string> -#include <vector> - -#include "base/memory/scoped_ptr.h" -#include "base/string_split.h" -#include "base/string_util.h" -#include "base/stringprintf.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -namespace net { - -class WebSocketHandshakeTest : public testing::Test { - public: - static void SetUpParameter(WebSocketHandshake* handshake, - uint32 number_1, uint32 number_2, - const std::string& key_1, const std::string& key_2, - const std::string& key_3) { - WebSocketHandshake::Parameter* parameter = - new WebSocketHandshake::Parameter; - parameter->number_1_ = number_1; - parameter->number_2_ = number_2; - parameter->key_1_ = key_1; - parameter->key_2_ = key_2; - parameter->key_3_ = key_3; - handshake->parameter_.reset(parameter); - } - - static void ExpectHeaderEquals(const std::string& expected, - const std::string& actual) { - std::vector<std::string> expected_lines; - Tokenize(expected, "\r\n", &expected_lines); - std::vector<std::string> actual_lines; - Tokenize(actual, "\r\n", &actual_lines); - // Request lines. - EXPECT_EQ(expected_lines[0], actual_lines[0]); - - std::vector<std::string> expected_headers; - for (size_t i = 1; i < expected_lines.size(); i++) { - // Finish at first CRLF CRLF. Note that /key_3/ might include CRLF. - if (expected_lines[i] == "") - break; - expected_headers.push_back(expected_lines[i]); - } - sort(expected_headers.begin(), expected_headers.end()); - - std::vector<std::string> actual_headers; - for (size_t i = 1; i < actual_lines.size(); i++) { - // Finish at first CRLF CRLF. Note that /key_3/ might include CRLF. - if (actual_lines[i] == "") - break; - actual_headers.push_back(actual_lines[i]); - } - sort(actual_headers.begin(), actual_headers.end()); - - EXPECT_EQ(expected_headers.size(), actual_headers.size()) - << "expected:" << expected - << "\nactual:" << actual; - for (size_t i = 0; i < expected_headers.size(); i++) { - EXPECT_EQ(expected_headers[i], actual_headers[i]); - } - } - - static void ExpectHandshakeMessageEquals(const std::string& expected, - const std::string& actual) { - // Headers. - ExpectHeaderEquals(expected, actual); - // Compare tailing \r\n\r\n<key3> (4 + 8 bytes). - ASSERT_GT(expected.size(), 12U); - const char* expected_key3 = expected.data() + expected.size() - 12; - EXPECT_GT(actual.size(), 12U); - if (actual.size() <= 12U) - return; - const char* actual_key3 = actual.data() + actual.size() - 12; - EXPECT_TRUE(memcmp(expected_key3, actual_key3, 12) == 0) - << "expected_key3:" << DumpKey(expected_key3, 12) - << ", actual_key3:" << DumpKey(actual_key3, 12); - } - - static std::string DumpKey(const char* buf, int len) { - std::string s; - for (int i = 0; i < len; i++) { - if (isprint(buf[i])) - s += base::StringPrintf("%c", buf[i]); - else - s += base::StringPrintf("\\x%02x", buf[i]); - } - return s; - } - - static std::string GetResourceName(WebSocketHandshake* handshake) { - return handshake->GetResourceName(); - } - static std::string GetHostFieldValue(WebSocketHandshake* handshake) { - return handshake->GetHostFieldValue(); - } - static std::string GetOriginFieldValue(WebSocketHandshake* handshake) { - return handshake->GetOriginFieldValue(); - } -}; - - -TEST_F(WebSocketHandshakeTest, Connect) { - const std::string kExpectedClientHandshakeMessage = - "GET /demo HTTP/1.1\r\n" - "Upgrade: WebSocket\r\n" - "Connection: Upgrade\r\n" - "Host: example.com\r\n" - "Origin: http://example.com\r\n" - "Sec-WebSocket-Protocol: sample\r\n" - "Sec-WebSocket-Key1: 388P O503D&ul7 {K%gX( %7 15\r\n" - "Sec-WebSocket-Key2: 1 N ?|k UT0or 3o 4 I97N 5-S3O 31\r\n" - "\r\n" - "\x47\x30\x22\x2D\x5A\x3F\x47\x58"; - - scoped_ptr<WebSocketHandshake> handshake( - new WebSocketHandshake(GURL("ws://example.com/demo"), - "http://example.com", - "ws://example.com/demo", - "sample")); - SetUpParameter(handshake.get(), 777007543U, 114997259U, - "388P O503D&ul7 {K%gX( %7 15", - "1 N ?|k UT0or 3o 4 I97N 5-S3O 31", - std::string("\x47\x30\x22\x2D\x5A\x3F\x47\x58", 8)); - EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode()); - ExpectHandshakeMessageEquals( - kExpectedClientHandshakeMessage, - handshake->CreateClientHandshakeMessage()); - - const char kResponse[] = "HTTP/1.1 101 WebSocket Protocol Handshake\r\n" - "Upgrade: WebSocket\r\n" - "Connection: Upgrade\r\n" - "Sec-WebSocket-Origin: http://example.com\r\n" - "Sec-WebSocket-Location: ws://example.com/demo\r\n" - "Sec-WebSocket-Protocol: sample\r\n" - "\r\n" - "\x30\x73\x74\x33\x52\x6C\x26\x71\x2D\x32\x5A\x55\x5E\x77\x65\x75"; - std::vector<std::string> response_lines; - base::SplitStringDontTrim(kResponse, '\n', &response_lines); - - EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode()); - // too short - EXPECT_EQ(-1, handshake->ReadServerHandshake(kResponse, 16)); - EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode()); - - // only status line - std::string response = response_lines[0]; - EXPECT_EQ(-1, handshake->ReadServerHandshake( - response.data(), response.size())); - EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode()); - // by upgrade header - response += response_lines[1]; - EXPECT_EQ(-1, handshake->ReadServerHandshake( - response.data(), response.size())); - EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode()); - // by connection header - response += response_lines[2]; - EXPECT_EQ(-1, handshake->ReadServerHandshake( - response.data(), response.size())); - EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode()); - - response += response_lines[3]; // Sec-WebSocket-Origin - response += response_lines[4]; // Sec-WebSocket-Location - response += response_lines[5]; // Sec-WebSocket-Protocol - EXPECT_EQ(-1, handshake->ReadServerHandshake( - response.data(), response.size())); - EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode()); - - response += response_lines[6]; // \r\n - EXPECT_EQ(-1, handshake->ReadServerHandshake( - response.data(), response.size())); - EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode()); - - int handshake_length = sizeof(kResponse) - 1; // -1 for terminating \0 - EXPECT_EQ(handshake_length, handshake->ReadServerHandshake( - kResponse, handshake_length)); // -1 for terminating \0 - EXPECT_EQ(WebSocketHandshake::MODE_CONNECTED, handshake->mode()); -} - -TEST_F(WebSocketHandshakeTest, ServerSentData) { - const std::string kExpectedClientHandshakeMessage = - "GET /demo HTTP/1.1\r\n" - "Upgrade: WebSocket\r\n" - "Connection: Upgrade\r\n" - "Host: example.com\r\n" - "Origin: http://example.com\r\n" - "Sec-WebSocket-Protocol: sample\r\n" - "Sec-WebSocket-Key1: 388P O503D&ul7 {K%gX( %7 15\r\n" - "Sec-WebSocket-Key2: 1 N ?|k UT0or 3o 4 I97N 5-S3O 31\r\n" - "\r\n" - "\x47\x30\x22\x2D\x5A\x3F\x47\x58"; - scoped_ptr<WebSocketHandshake> handshake( - new WebSocketHandshake(GURL("ws://example.com/demo"), - "http://example.com", - "ws://example.com/demo", - "sample")); - SetUpParameter(handshake.get(), 777007543U, 114997259U, - "388P O503D&ul7 {K%gX( %7 15", - "1 N ?|k UT0or 3o 4 I97N 5-S3O 31", - std::string("\x47\x30\x22\x2D\x5A\x3F\x47\x58", 8)); - EXPECT_EQ(WebSocketHandshake::MODE_INCOMPLETE, handshake->mode()); - ExpectHandshakeMessageEquals( - kExpectedClientHandshakeMessage, - handshake->CreateClientHandshakeMessage()); - - const char kResponse[] = "HTTP/1.1 101 WebSocket Protocol Handshake\r\n" - "Upgrade: WebSocket\r\n" - "Connection: Upgrade\r\n" - "Sec-WebSocket-Origin: http://example.com\r\n" - "Sec-WebSocket-Location: ws://example.com/demo\r\n" - "Sec-WebSocket-Protocol: sample\r\n" - "\r\n" - "\x30\x73\x74\x33\x52\x6C\x26\x71\x2D\x32\x5A\x55\x5E\x77\x65\x75" - "\0Hello\xff"; - - int handshake_length = strlen(kResponse); // key3 doesn't contain \0. - EXPECT_EQ(handshake_length, handshake->ReadServerHandshake( - kResponse, sizeof(kResponse) - 1)); // -1 for terminating \0 - EXPECT_EQ(WebSocketHandshake::MODE_CONNECTED, handshake->mode()); -} - -TEST_F(WebSocketHandshakeTest, is_secure_false) { - scoped_ptr<WebSocketHandshake> handshake( - new WebSocketHandshake(GURL("ws://example.com/demo"), - "http://example.com", - "ws://example.com/demo", - "sample")); - EXPECT_FALSE(handshake->is_secure()); -} - -TEST_F(WebSocketHandshakeTest, is_secure_true) { - // wss:// is secure. - scoped_ptr<WebSocketHandshake> handshake( - new WebSocketHandshake(GURL("wss://example.com/demo"), - "http://example.com", - "wss://example.com/demo", - "sample")); - EXPECT_TRUE(handshake->is_secure()); -} - -TEST_F(WebSocketHandshakeTest, CreateClientHandshakeMessage_ResourceName) { - scoped_ptr<WebSocketHandshake> handshake( - new WebSocketHandshake(GURL("ws://example.com/Test?q=xxx&p=%20"), - "http://example.com", - "ws://example.com/demo", - "sample")); - // Path and query should be preserved as-is. - EXPECT_EQ("/Test?q=xxx&p=%20", GetResourceName(handshake.get())); -} - -TEST_F(WebSocketHandshakeTest, CreateClientHandshakeMessage_Host) { - scoped_ptr<WebSocketHandshake> handshake( - new WebSocketHandshake(GURL("ws://Example.Com/demo"), - "http://Example.Com", - "ws://Example.Com/demo", - "sample")); - // Host should be lowercased - EXPECT_EQ("example.com", GetHostFieldValue(handshake.get())); - EXPECT_EQ("http://example.com", GetOriginFieldValue(handshake.get())); -} - -TEST_F(WebSocketHandshakeTest, CreateClientHandshakeMessage_TrimPort80) { - scoped_ptr<WebSocketHandshake> handshake( - new WebSocketHandshake(GURL("ws://example.com:80/demo"), - "http://example.com", - "ws://example.com/demo", - "sample")); - // :80 should be trimmed as it's the default port for ws://. - EXPECT_EQ("example.com", GetHostFieldValue(handshake.get())); -} - -TEST_F(WebSocketHandshakeTest, CreateClientHandshakeMessage_TrimPort443) { - scoped_ptr<WebSocketHandshake> handshake( - new WebSocketHandshake(GURL("wss://example.com:443/demo"), - "http://example.com", - "wss://example.com/demo", - "sample")); - // :443 should be trimmed as it's the default port for wss://. - EXPECT_EQ("example.com", GetHostFieldValue(handshake.get())); -} - -TEST_F(WebSocketHandshakeTest, - CreateClientHandshakeMessage_NonDefaultPortForWs) { - scoped_ptr<WebSocketHandshake> handshake( - new WebSocketHandshake(GURL("ws://example.com:8080/demo"), - "http://example.com", - "wss://example.com/demo", - "sample")); - // :8080 should be preserved as it's not the default port for ws://. - EXPECT_EQ("example.com:8080", GetHostFieldValue(handshake.get())); -} - -TEST_F(WebSocketHandshakeTest, - CreateClientHandshakeMessage_NonDefaultPortForWss) { - scoped_ptr<WebSocketHandshake> handshake( - new WebSocketHandshake(GURL("wss://example.com:4443/demo"), - "http://example.com", - "wss://example.com/demo", - "sample")); - // :4443 should be preserved as it's not the default port for wss://. - EXPECT_EQ("example.com:4443", GetHostFieldValue(handshake.get())); -} - -TEST_F(WebSocketHandshakeTest, CreateClientHandshakeMessage_WsBut443) { - scoped_ptr<WebSocketHandshake> handshake( - new WebSocketHandshake(GURL("ws://example.com:443/demo"), - "http://example.com", - "ws://example.com/demo", - "sample")); - // :443 should be preserved as it's not the default port for ws://. - EXPECT_EQ("example.com:443", GetHostFieldValue(handshake.get())); -} - -TEST_F(WebSocketHandshakeTest, CreateClientHandshakeMessage_WssBut80) { - scoped_ptr<WebSocketHandshake> handshake( - new WebSocketHandshake(GURL("wss://example.com:80/demo"), - "http://example.com", - "wss://example.com/demo", - "sample")); - // :80 should be preserved as it's not the default port for wss://. - EXPECT_EQ("example.com:80", GetHostFieldValue(handshake.get())); -} - -} // namespace net diff --git a/net/websockets/websocket_unittest.cc b/net/websockets/websocket_unittest.cc deleted file mode 100644 index 8a492e7..0000000 --- a/net/websockets/websocket_unittest.cc +++ /dev/null @@ -1,348 +0,0 @@ -// Copyright (c) 2011 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 "net/websockets/websocket.h" - -#include <string> -#include <vector> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/callback.h" -#include "net/base/completion_callback.h" -#include "net/base/io_buffer.h" -#include "net/base/mock_host_resolver.h" -#include "net/base/test_completion_callback.h" -#include "net/socket/socket_test_util.h" -#include "net/url_request/url_request_test_util.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/platform_test.h" - -struct WebSocketEvent { - enum EventType { - EVENT_OPEN, EVENT_MESSAGE, EVENT_ERROR, EVENT_CLOSE, - }; - - WebSocketEvent(EventType type, net::WebSocket* websocket, - const std::string& websocket_msg, bool websocket_flag) - : event_type(type), socket(websocket), msg(websocket_msg), - flag(websocket_flag) {} - - EventType event_type; - net::WebSocket* socket; - std::string msg; - bool flag; -}; - -class WebSocketEventRecorder : public net::WebSocketDelegate { - public: - explicit WebSocketEventRecorder(net::CompletionCallback* callback) - : callback_(callback) {} - virtual ~WebSocketEventRecorder() {} - - void SetOnOpen(const base::Callback<void(WebSocketEvent*)>& callback) { - onopen_ = callback; - } - void SetOnMessage(const base::Callback<void(WebSocketEvent*)>& callback) { - onmessage_ = callback; - } - void SetOnClose(const base::Callback<void(WebSocketEvent*)>& callback) { - onclose_ = callback; - } - - virtual void OnOpen(net::WebSocket* socket) { - events_.push_back( - WebSocketEvent(WebSocketEvent::EVENT_OPEN, socket, - std::string(), false)); - if (!onopen_.is_null()) - onopen_.Run(&events_.back()); - } - - virtual void OnMessage(net::WebSocket* socket, const std::string& msg) { - events_.push_back( - WebSocketEvent(WebSocketEvent::EVENT_MESSAGE, socket, msg, false)); - if (!onmessage_.is_null()) - onmessage_.Run(&events_.back()); - } - virtual void OnError(net::WebSocket* socket) { - events_.push_back( - WebSocketEvent(WebSocketEvent::EVENT_ERROR, socket, - std::string(), false)); - if (!onerror_.is_null()) - onerror_.Run(&events_.back()); - } - virtual void OnClose(net::WebSocket* socket, bool was_clean) { - events_.push_back( - WebSocketEvent(WebSocketEvent::EVENT_CLOSE, socket, - std::string(), was_clean)); - if (!onclose_.is_null()) - onclose_.Run(&events_.back()); - if (callback_) - callback_->Run(net::OK); - } - - void DoClose(WebSocketEvent* event) { - event->socket->Close(); - } - - const std::vector<WebSocketEvent>& GetSeenEvents() const { - return events_; - } - - private: - std::vector<WebSocketEvent> events_; - base::Callback<void(WebSocketEvent*)> onopen_; - base::Callback<void(WebSocketEvent*)> onmessage_; - base::Callback<void(WebSocketEvent*)> onerror_; - base::Callback<void(WebSocketEvent*)> onclose_; - net::CompletionCallback* callback_; - - DISALLOW_COPY_AND_ASSIGN(WebSocketEventRecorder); -}; - -namespace net { - -class WebSocketTest : public PlatformTest { - protected: - void InitReadBuf(WebSocket* websocket) { - // Set up |current_read_buf_|. - websocket->current_read_buf_ = new GrowableIOBuffer(); - } - void SetReadConsumed(WebSocket* websocket, int consumed) { - websocket->read_consumed_len_ = consumed; - } - void AddToReadBuf(WebSocket* websocket, const char* data, int len) { - websocket->AddToReadBuffer(data, len); - } - - void TestProcessFrameData(WebSocket* websocket, - const char* expected_remaining_data, - int expected_remaining_len) { - websocket->ProcessFrameData(); - - const char* actual_remaining_data = - websocket->current_read_buf_->StartOfBuffer() - + websocket->read_consumed_len_; - int actual_remaining_len = - websocket->current_read_buf_->offset() - websocket->read_consumed_len_; - - EXPECT_EQ(expected_remaining_len, actual_remaining_len); - EXPECT_TRUE(!memcmp(expected_remaining_data, actual_remaining_data, - expected_remaining_len)); - } -}; - -TEST_F(WebSocketTest, Connect) { - MockClientSocketFactory mock_socket_factory; - MockRead data_reads[] = { - MockRead("HTTP/1.1 101 Web Socket Protocol Handshake\r\n" - "Upgrade: WebSocket\r\n" - "Connection: Upgrade\r\n" - "WebSocket-Origin: http://example.com\r\n" - "WebSocket-Location: ws://example.com/demo\r\n" - "WebSocket-Protocol: sample\r\n" - "\r\n"), - // Server doesn't close the connection after handshake. - MockRead(true, ERR_IO_PENDING), - }; - MockWrite data_writes[] = { - MockWrite("GET /demo HTTP/1.1\r\n" - "Upgrade: WebSocket\r\n" - "Connection: Upgrade\r\n" - "Host: example.com\r\n" - "Origin: http://example.com\r\n" - "WebSocket-Protocol: sample\r\n" - "\r\n"), - }; - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - mock_socket_factory.AddSocketDataProvider(&data); - MockHostResolver host_resolver; - - WebSocket::Request* request( - new WebSocket::Request(GURL("ws://example.com/demo"), - "sample", - "http://example.com", - "ws://example.com/demo", - WebSocket::DRAFT75, - new TestURLRequestContext())); - request->SetHostResolver(&host_resolver); - request->SetClientSocketFactory(&mock_socket_factory); - - TestCompletionCallback callback; - - scoped_ptr<WebSocketEventRecorder> delegate( - new WebSocketEventRecorder(&callback)); - delegate->SetOnOpen(base::Bind(&WebSocketEventRecorder::DoClose, - base::Unretained(delegate.get()))); - - scoped_refptr<WebSocket> websocket( - new WebSocket(request, delegate.get())); - - EXPECT_EQ(WebSocket::INITIALIZED, websocket->ready_state()); - websocket->Connect(); - - callback.WaitForResult(); - - const std::vector<WebSocketEvent>& events = delegate->GetSeenEvents(); - EXPECT_EQ(2U, events.size()); - - EXPECT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type); - EXPECT_EQ(WebSocketEvent::EVENT_CLOSE, events[1].event_type); -} - -TEST_F(WebSocketTest, ServerSentData) { - MockClientSocketFactory mock_socket_factory; - static const char kMessage[] = "Hello"; - static const char kFrame[] = "\x00Hello\xff"; - static const int kFrameLen = sizeof(kFrame) - 1; - MockRead data_reads[] = { - MockRead("HTTP/1.1 101 Web Socket Protocol Handshake\r\n" - "Upgrade: WebSocket\r\n" - "Connection: Upgrade\r\n" - "WebSocket-Origin: http://example.com\r\n" - "WebSocket-Location: ws://example.com/demo\r\n" - "WebSocket-Protocol: sample\r\n" - "\r\n"), - MockRead(true, kFrame, kFrameLen), - // Server doesn't close the connection after handshake. - MockRead(true, ERR_IO_PENDING), - }; - MockWrite data_writes[] = { - MockWrite("GET /demo HTTP/1.1\r\n" - "Upgrade: WebSocket\r\n" - "Connection: Upgrade\r\n" - "Host: example.com\r\n" - "Origin: http://example.com\r\n" - "WebSocket-Protocol: sample\r\n" - "\r\n"), - }; - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - mock_socket_factory.AddSocketDataProvider(&data); - MockHostResolver host_resolver; - - WebSocket::Request* request( - new WebSocket::Request(GURL("ws://example.com/demo"), - "sample", - "http://example.com", - "ws://example.com/demo", - WebSocket::DRAFT75, - new TestURLRequestContext())); - request->SetHostResolver(&host_resolver); - request->SetClientSocketFactory(&mock_socket_factory); - - TestCompletionCallback callback; - - scoped_ptr<WebSocketEventRecorder> delegate( - new WebSocketEventRecorder(&callback)); - delegate->SetOnMessage(base::Bind(&WebSocketEventRecorder::DoClose, - base::Unretained(delegate.get()))); - - scoped_refptr<WebSocket> websocket( - new WebSocket(request, delegate.get())); - - EXPECT_EQ(WebSocket::INITIALIZED, websocket->ready_state()); - websocket->Connect(); - - callback.WaitForResult(); - - const std::vector<WebSocketEvent>& events = delegate->GetSeenEvents(); - EXPECT_EQ(3U, events.size()); - - EXPECT_EQ(WebSocketEvent::EVENT_OPEN, events[0].event_type); - EXPECT_EQ(WebSocketEvent::EVENT_MESSAGE, events[1].event_type); - EXPECT_EQ(kMessage, events[1].msg); - EXPECT_EQ(WebSocketEvent::EVENT_CLOSE, events[2].event_type); -} - -TEST_F(WebSocketTest, ProcessFrameDataForLengthCalculation) { - WebSocket::Request* request( - new WebSocket::Request(GURL("ws://example.com/demo"), - "sample", - "http://example.com", - "ws://example.com/demo", - WebSocket::DRAFT75, - new TestURLRequestContext())); - TestCompletionCallback callback; - scoped_ptr<WebSocketEventRecorder> delegate( - new WebSocketEventRecorder(&callback)); - - scoped_refptr<WebSocket> websocket( - new WebSocket(request, delegate.get())); - - // Frame data: skip length 1 ('x'), and try to skip length 129 - // (1 * 128 + 1) bytes after \x81\x01, but buffer is too short to skip. - static const char kTestLengthFrame[] = - "\x80\x01x\x80\x81\x01\x01\x00unexpected data\xFF"; - const int kTestLengthFrameLength = sizeof(kTestLengthFrame) - 1; - InitReadBuf(websocket.get()); - AddToReadBuf(websocket.get(), kTestLengthFrame, kTestLengthFrameLength); - SetReadConsumed(websocket.get(), 0); - - static const char kExpectedRemainingFrame[] = - "\x80\x81\x01\x01\x00unexpected data\xFF"; - const int kExpectedRemainingLength = sizeof(kExpectedRemainingFrame) - 1; - TestProcessFrameData(websocket.get(), - kExpectedRemainingFrame, kExpectedRemainingLength); - // No onmessage event expected. - const std::vector<WebSocketEvent>& events = delegate->GetSeenEvents(); - EXPECT_EQ(1U, events.size()); - - EXPECT_EQ(WebSocketEvent::EVENT_ERROR, events[0].event_type); - - websocket->DetachDelegate(); -} - -TEST_F(WebSocketTest, ProcessFrameDataForUnterminatedString) { - WebSocket::Request* request( - new WebSocket::Request(GURL("ws://example.com/demo"), - "sample", - "http://example.com", - "ws://example.com/demo", - WebSocket::DRAFT75, - new TestURLRequestContext())); - TestCompletionCallback callback; - scoped_ptr<WebSocketEventRecorder> delegate( - new WebSocketEventRecorder(&callback)); - - scoped_refptr<WebSocket> websocket( - new WebSocket(request, delegate.get())); - - static const char kTestUnterminatedFrame[] = - "\x00unterminated frame"; - const int kTestUnterminatedFrameLength = sizeof(kTestUnterminatedFrame) - 1; - InitReadBuf(websocket.get()); - AddToReadBuf(websocket.get(), kTestUnterminatedFrame, - kTestUnterminatedFrameLength); - SetReadConsumed(websocket.get(), 0); - TestProcessFrameData(websocket.get(), - kTestUnterminatedFrame, kTestUnterminatedFrameLength); - { - // No onmessage event expected. - const std::vector<WebSocketEvent>& events = delegate->GetSeenEvents(); - EXPECT_EQ(0U, events.size()); - } - - static const char kTestTerminateFrame[] = " is terminated in next read\xff"; - const int kTestTerminateFrameLength = sizeof(kTestTerminateFrame) - 1; - AddToReadBuf(websocket.get(), kTestTerminateFrame, - kTestTerminateFrameLength); - TestProcessFrameData(websocket.get(), "", 0); - - static const char kExpectedMsg[] = - "unterminated frame is terminated in next read"; - { - const std::vector<WebSocketEvent>& events = delegate->GetSeenEvents(); - EXPECT_EQ(1U, events.size()); - - EXPECT_EQ(WebSocketEvent::EVENT_MESSAGE, events[0].event_type); - EXPECT_EQ(kExpectedMsg, events[0].msg); - } - - websocket->DetachDelegate(); -} - -} // namespace net |