1c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Copyright (c) 2009 The Chromium Authors. All rights reserved. 2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be 3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file. 4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <algorithm> 6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <limits> 7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/websockets/websocket.h" 9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/message_loop.h" 113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "net/base/host_resolver.h" 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/websockets/websocket_handshake.h" 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/websockets/websocket_handshake_draft75.h" 14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace net { 16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const char kClosingFrame[2] = {'\xff', '\x00'}; 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic int64 kClosingHandshakeTimeout = 1000; // msec. 19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottWebSocket::WebSocket(Request* request, WebSocketDelegate* delegate) 21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott : ready_state_(INITIALIZED), 22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott request_(request), 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch handshake_(NULL), 24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott delegate_(delegate), 25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott origin_loop_(MessageLoop::current()), 26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott socket_stream_(NULL), 27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott max_pending_send_allowed_(0), 28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott current_read_buf_(NULL), 29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott read_consumed_len_(0), 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_write_buf_(NULL), 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch server_closing_handshake_(false), 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch client_closing_handshake_(false), 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch closing_handshake_started_(false), 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch force_close_task_(NULL), 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch closing_handshake_timeout_(kClosingHandshakeTimeout) { 36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(request_.get()); 37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(delegate_); 38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(origin_loop_); 39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottWebSocket::~WebSocket() { 42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(ready_state_ == INITIALIZED || !delegate_); 43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(!socket_stream_); 44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(!delegate_); 45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid WebSocket::Connect() { 48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(ready_state_ == INITIALIZED); 49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(request_.get()); 50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(delegate_); 51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(!socket_stream_); 52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(MessageLoop::current() == origin_loop_); 53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott socket_stream_ = new SocketStream(request_->url(), this); 55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott socket_stream_->set_context(request_->context()); 56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (request_->host_resolver()) 58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott socket_stream_->SetHostResolver(request_->host_resolver()); 59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (request_->client_socket_factory()) 60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott socket_stream_->SetClientSocketFactory(request_->client_socket_factory()); 61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott AddRef(); // Release in DoClose(). 63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ready_state_ = CONNECTING; 64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott socket_stream_->Connect(); 65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid WebSocket::Send(const std::string& msg) { 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (ready_state_ == CLOSING || ready_state_ == CLOSED) { 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (client_closing_handshake_) { 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We must not send any data after we start the WebSocket closing handshake. 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(ready_state_ == OPEN); 76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(MessageLoop::current() == origin_loop_); 77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott IOBufferWithSize* buf = new IOBufferWithSize(msg.size() + 2); 79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott char* p = buf->data(); 80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *p = '\0'; 81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott memcpy(p + 1, msg.data(), msg.size()); 82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *(p + 1 + msg.size()) = '\xff'; 83513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch pending_write_bufs_.push_back(make_scoped_refptr(buf)); 84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SendPending(); 85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid WebSocket::Close() { 88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(MessageLoop::current() == origin_loop_); 89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If connection has not yet started, do nothing. 91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (ready_state_ == INITIALIZED) { 92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(!socket_stream_); 93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ready_state_ = CLOSED; 94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the readyState attribute is in the CLOSING or CLOSED state, do nothing 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (ready_state_ == CLOSING || ready_state_ == CLOSED) 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (request_->version() == DRAFT75) { 102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(socket_stream_); 103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott socket_stream_->Close(); 104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the WebSocket connection is not yet established, fail the WebSocket 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // connection and set the readyState attribute's value to CLOSING. 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (ready_state_ == CONNECTING) { 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ready_state_ = CLOSING; 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch origin_loop_->PostTask( 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FROM_HERE, 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(this, &WebSocket::FailConnection)); 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the WebSocket closing handshake has not yet been started, start 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the WebSocket closing handshake and set the readyState attribute's value 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // to CLOSING. 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!closing_handshake_started_) { 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ready_state_ = CLOSING; 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch origin_loop_->PostTask( 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FROM_HERE, 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(this, &WebSocket::StartClosingHandshake)); 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Otherwise, set the readyState attribute's value to CLOSING. 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ready_state_ = CLOSING; 128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid WebSocket::DetachDelegate() { 131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!delegate_) 132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott delegate_ = NULL; 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (ready_state_ == INITIALIZED) { 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!socket_stream_); 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ready_state_ = CLOSED; 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (ready_state_ != CLOSED) { 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(socket_stream_); 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch socket_stream_->Close(); 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid WebSocket::OnConnected(SocketStream* socket_stream, 146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int max_pending_send_allowed) { 147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(socket_stream == socket_stream_); 148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott max_pending_send_allowed_ = max_pending_send_allowed; 149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Use |max_pending_send_allowed| as hint for initial size of read buffer. 151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott current_read_buf_ = new GrowableIOBuffer(); 152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott current_read_buf_->SetCapacity(max_pending_send_allowed_); 153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott read_consumed_len_ = 0; 154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(!current_write_buf_); 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(!handshake_.get()); 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch switch (request_->version()) { 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case DEFAULT_VERSION: 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch handshake_.reset(new WebSocketHandshake( 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch request_->url(), request_->origin(), request_->location(), 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch request_->protocol())); 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case DRAFT75: 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch handshake_.reset(new WebSocketHandshakeDraft75( 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch request_->url(), request_->origin(), request_->location(), 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch request_->protocol())); 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default: 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED() << "Unexpected protocol version:" << request_->version(); 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const std::string msg = handshake_->CreateClientHandshakeMessage(); 173c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott IOBufferWithSize* buf = new IOBufferWithSize(msg.size()); 174c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott memcpy(buf->data(), msg.data(), msg.size()); 175513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch pending_write_bufs_.push_back(make_scoped_refptr(buf)); 176c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott origin_loop_->PostTask(FROM_HERE, 177c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NewRunnableMethod(this, &WebSocket::SendPending)); 178c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 179c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 180c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid WebSocket::OnSentData(SocketStream* socket_stream, int amount_sent) { 181c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(socket_stream == socket_stream_); 182c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(current_write_buf_); 183c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott current_write_buf_->DidConsume(amount_sent); 184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK_GE(current_write_buf_->BytesRemaining(), 0); 185c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (current_write_buf_->BytesRemaining() == 0) { 186c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott current_write_buf_ = NULL; 187c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott pending_write_bufs_.pop_front(); 188c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 189c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott origin_loop_->PostTask(FROM_HERE, 190c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NewRunnableMethod(this, &WebSocket::SendPending)); 191c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 192c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 193c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid WebSocket::OnReceivedData(SocketStream* socket_stream, 194c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const char* data, int len) { 195c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(socket_stream == socket_stream_); 196c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott AddToReadBuffer(data, len); 197c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott origin_loop_->PostTask(FROM_HERE, 198c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NewRunnableMethod(this, &WebSocket::DoReceivedData)); 199c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 200c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 201c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid WebSocket::OnClose(SocketStream* socket_stream) { 202c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott origin_loop_->PostTask(FROM_HERE, 203c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NewRunnableMethod(this, &WebSocket::DoClose)); 204c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 205c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 206c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid WebSocket::OnError(const SocketStream* socket_stream, int error) { 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch origin_loop_->PostTask( 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FROM_HERE, NewRunnableMethod(this, &WebSocket::DoSocketError, error)); 209c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 210c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 211c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid WebSocket::SendPending() { 212c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(MessageLoop::current() == origin_loop_); 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!socket_stream_) { 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK_EQ(CLOSED, ready_state_); 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 217c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!current_write_buf_) { 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (pending_write_bufs_.empty()) { 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (client_closing_handshake_) { 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Already sent 0xFF and 0x00 bytes. 221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // *The WebSocket closing handshake has started.* 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch closing_handshake_started_ = true; 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (server_closing_handshake_) { 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 4.2 3-8-3 If the WebSocket connection is not already closed, 225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // then close the WebSocket connection. 226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // *The WebSocket closing handshake has finished* 227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch socket_stream_->Close(); 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 5. Wait a user-agent-determined length of time, or until the 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // WebSocket connection is closed. 231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch force_close_task_ = 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(this, &WebSocket::DoForceCloseConnection); 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch origin_loop_->PostDelayedTask( 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FROM_HERE, force_close_task_, closing_handshake_timeout_); 235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 237c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 239c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott current_write_buf_ = new DrainableIOBuffer( 240c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott pending_write_bufs_.front(), pending_write_bufs_.front()->size()); 241c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 242c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK_GT(current_write_buf_->BytesRemaining(), 0); 243c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott bool sent = socket_stream_->SendData( 244c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott current_write_buf_->data(), 245c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::min(current_write_buf_->BytesRemaining(), 246c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott max_pending_send_allowed_)); 247c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(sent); 248c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 249c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 250c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid WebSocket::DoReceivedData() { 251c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(MessageLoop::current() == origin_loop_); 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_refptr<WebSocket> protect(this); 253c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott switch (ready_state_) { 254c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott case CONNECTING: 255c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott { 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(handshake_.get()); 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(current_read_buf_); 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const char* data = 259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch current_read_buf_->StartOfBuffer() + read_consumed_len_; 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t len = current_read_buf_->offset() - read_consumed_len_; 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int eoh = handshake_->ReadServerHandshake(data, len); 262c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (eoh < 0) { 263c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Not enough data, Retry when more data is available. 264c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 265c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 266c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SkipReadBuffer(eoh); 267c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (handshake_->mode() != WebSocketHandshake::MODE_CONNECTED) { 269c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Handshake failed. 270c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott socket_stream_->Close(); 271c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 272c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ready_state_ = OPEN; 274c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (delegate_) 275c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott delegate_->OnOpen(this); 276c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (current_read_buf_->offset() == read_consumed_len_) { 277c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // No remaining data after handshake message. 278c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott break; 279c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 280c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // FALL THROUGH 281c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott case OPEN: 282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case CLOSING: // need to process closing-frame from server. 283c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ProcessFrameData(); 284c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott break; 285c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 286c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott case CLOSED: 287c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Closed just after DoReceivedData is queued on |origin_loop_|. 288c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott break; 289c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott default: 290c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NOTREACHED(); 291c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott break; 292c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 293c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 294c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 295c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid WebSocket::ProcessFrameData() { 296c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(current_read_buf_); 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (server_closing_handshake_) { 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Any data on the connection after the 0xFF frame is discarded. 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_refptr<WebSocket> protect(this); 302c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const char* start_frame = 303c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott current_read_buf_->StartOfBuffer() + read_consumed_len_; 304c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const char* next_frame = start_frame; 305c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const char* p = next_frame; 306c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const char* end = 307c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott current_read_buf_->StartOfBuffer() + current_read_buf_->offset(); 308c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott while (p < end) { 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Let /error/ be false. 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool error = false; 311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Handle the /frame type/ byte as follows. 313c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott unsigned char frame_byte = static_cast<unsigned char>(*p++); 314c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if ((frame_byte & 0x80) == 0x80) { 315c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int length = 0; 316c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott while (p < end) { 317c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (length > std::numeric_limits<int>::max() / 128) { 318c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // frame length overflow. 319c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott socket_stream_->Close(); 320c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 321c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 322c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott unsigned char c = static_cast<unsigned char>(*p); 323c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott length = length * 128 + (c & 0x7f); 324c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ++p; 325c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if ((c & 0x80) != 0x80) 326c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott break; 327c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 328c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Checks if the frame body hasn't been completely received yet. 329c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // It also checks the case the frame length bytes haven't been completely 330c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // received yet, because p == end and length > 0 in such case. 331c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (p + length < end) { 332c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott p += length; 333c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott next_frame = p; 334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (request_->version() != DRAFT75 && 335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch frame_byte == 0xFF && length == 0) { 336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 4.2 Data framing 3. Handle the /frame type/ byte. 337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 8. If the /frame type/ is 0xFF and the /length/ was 0, then 338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // run the following substeps: 339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 1. If the WebSocket closing handshake has not yet started, then 340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // start the WebSocket closing handshake. 341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch server_closing_handshake_ = true; 342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!closing_handshake_started_) { 343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch origin_loop_->PostTask( 344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FROM_HERE, 345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NewRunnableMethod(this, &WebSocket::StartClosingHandshake)); 346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the WebSocket closing handshake has been started and 348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the WebSocket connection is not already closed, then close 349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the WebSocket connection. 350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch socket_stream_->Close(); 351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 4.2 3-8 Otherwise, let /error/ be true. 355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch error = true; 356c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else { 357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Not enough data in buffer. 358c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott break; 359c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 360c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else { 361c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const char* msg_start = p; 362c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott while (p < end && *p != '\xff') 363c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ++p; 364c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (p < end && *p == '\xff') { 365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (frame_byte == 0x00) { 366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (delegate_) { 367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delegate_->OnMessage(this, std::string(msg_start, p - msg_start)); 368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Otherwise, discard the data and let /error/ to be true. 371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch error = true; 372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 373c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ++p; 374c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott next_frame = p; 375c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 376c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If /error/ is true, then *a WebSocket error has been detected.* 378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (error && delegate_) 379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delegate_->OnError(this); 380c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 381c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SkipReadBuffer(next_frame - start_frame); 382c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 383c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 384c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid WebSocket::AddToReadBuffer(const char* data, int len) { 385c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(current_read_buf_); 386c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Check if |current_read_buf_| has enough space to store |len| of |data|. 387c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (len >= current_read_buf_->RemainingCapacity()) { 388c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott current_read_buf_->SetCapacity( 389c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott current_read_buf_->offset() + len); 390c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 391c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 392c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(current_read_buf_->RemainingCapacity() >= len); 393c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott memcpy(current_read_buf_->data(), data, len); 394c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott current_read_buf_->set_offset(current_read_buf_->offset() + len); 395c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 396c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 397c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid WebSocket::SkipReadBuffer(int len) { 398c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (len == 0) 399c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 400c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK_GT(len, 0); 401c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott read_consumed_len_ += len; 402c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int remaining = current_read_buf_->offset() - read_consumed_len_; 403c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK_GE(remaining, 0); 404c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (remaining < read_consumed_len_ && 405c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott current_read_buf_->RemainingCapacity() < read_consumed_len_) { 406c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Pre compaction: 407c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // 0 v-read_consumed_len_ v-offset v- capacity 408c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // |..processed..| .. remaining .. | .. RemainingCapacity | 409c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // 410c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott memmove(current_read_buf_->StartOfBuffer(), 411c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott current_read_buf_->StartOfBuffer() + read_consumed_len_, 412c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott remaining); 413c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott read_consumed_len_ = 0; 414c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott current_read_buf_->set_offset(remaining); 415c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Post compaction: 416c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // 0read_consumed_len_ v- offset v- capacity 417c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // |.. remaining .. | .. RemainingCapacity ... | 418c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // 419c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 420c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 421c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocket::StartClosingHandshake() { 423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 4.2 *start the WebSocket closing handshake*. 424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (closing_handshake_started_ || client_closing_handshake_) { 425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 1. If the WebSocket closing handshake has started, then abort these 426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // steps. 427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 2.,3. Send a 0xFF and 0x00 byte to the server. 430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch client_closing_handshake_ = true; 431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch IOBufferWithSize* buf = new IOBufferWithSize(2); 432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch memcpy(buf->data(), kClosingFrame, 2); 433513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch pending_write_bufs_.push_back(make_scoped_refptr(buf)); 434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SendPending(); 435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocket::DoForceCloseConnection() { 438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 4.2 *start the WebSocket closing handshake* 439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 6. If the WebSocket connection is not already closed, then close the 440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // WebSocket connection. (If this happens, then the closing handshake 441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // doesn't finish.) 442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(MessageLoop::current() == origin_loop_); 443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch force_close_task_ = NULL; 444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FailConnection(); 445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocket::FailConnection() { 448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(MessageLoop::current() == origin_loop_); 449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 6.1 Client-initiated closure. 450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // *fail the WebSocket connection*. 451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the user agent must close the WebSocket connection, and may report the 452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // problem to the user. 453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!socket_stream_) 454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch socket_stream_->Close(); 456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 458c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid WebSocket::DoClose() { 459c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(MessageLoop::current() == origin_loop_); 460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (force_close_task_) { 461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // WebSocket connection is closed while waiting a user-agent-determined 462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // length of time after *The WebSocket closing handshake has started*. 463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch force_close_task_->Cancel(); 464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch force_close_task_ = NULL; 465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 466c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott WebSocketDelegate* delegate = delegate_; 467c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott delegate_ = NULL; 468c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ready_state_ = CLOSED; 469c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!socket_stream_) 470c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 471c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott socket_stream_ = NULL; 472c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (delegate) 473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delegate->OnClose(this, 474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch server_closing_handshake_ && closing_handshake_started_); 475c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Release(); 476c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 477c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocket::DoSocketError(int error) { 479c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(MessageLoop::current() == origin_loop_); 480c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (delegate_) 481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delegate_->OnSocketError(this, error); 482c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 483c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 484c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} // namespace net 485