websocket_job.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/websockets/websocket_job.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/lazy_instance.h"
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/base/io_buffer.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_log.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/cookies/cookie_store.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_network_session.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_transaction_factory.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_util.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/spdy/spdy_session.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/spdy/spdy_session_pool.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_context.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/websockets/websocket_handshake_handler.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/websockets/websocket_net_log_params.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/websockets/websocket_throttle.h"
247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMaxPendingSendAllowed = 32768;  // 32 kilobytes.
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// lower-case header names.
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* const kCookieHeaders[] = {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  "cookie", "cookie2"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* const kSetCookieHeaders[] = {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  "set-cookie", "set-cookie2"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)net::SocketStreamJob* WebSocketJobFactory(
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url, net::SocketStream::Delegate* delegate) {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::WebSocketJob* job = new net::WebSocketJob(delegate);
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  job->InitSocketStream(new net::SocketStream(url, job));
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return job;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class WebSocketJobInitSingleton {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend struct base::DefaultLazyInstanceTraits<WebSocketJobInitSingleton>;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebSocketJobInitSingleton() {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net::SocketStreamJob::RegisterProtocolFactory("ws", WebSocketJobFactory);
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net::SocketStreamJob::RegisterProtocolFactory("wss", WebSocketJobFactory);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static base::LazyInstance<WebSocketJobInitSingleton> g_websocket_job_init =
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LAZY_INSTANCE_INITIALIZER;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // anonymous namespace
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WebSocketJob::websocket_over_spdy_enabled_ = false;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::EnsureInit() {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_websocket_job_init.Get();
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::set_websocket_over_spdy_enabled(bool enabled) {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  websocket_over_spdy_enabled_ = enabled;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WebSocketJob::WebSocketJob(SocketStream::Delegate* delegate)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : delegate_(delegate),
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      state_(INITIALIZED),
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      waiting_(false),
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      handshake_request_(new WebSocketHandshakeRequestHandler),
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      handshake_response_(new WebSocketHandshakeResponseHandler),
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      started_to_send_handshake_request_(false),
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      handshake_request_sent_(0),
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      response_cookies_save_index_(0),
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      spdy_protocol_version_(0),
8390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      save_next_cookie_running_(false),
8490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      callback_pending_(false),
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_ptr_factory_(this),
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_ptr_factory_for_send_pending_(this) {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WebSocketJob::~WebSocketJob() {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(CLOSED, state_);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!delegate_);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!socket_.get());
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::Connect() {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(socket_.get());
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(state_, INITIALIZED);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = CONNECTING;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  socket_->Connect();
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WebSocketJob::SendData(const char* data, int len) {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (state_) {
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case INITIALIZED:
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CONNECTING:
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return SendHandshakeRequest(data, len);
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case OPEN:
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        scoped_refptr<IOBufferWithSize> buffer = new IOBufferWithSize(len);
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        memcpy(buffer->data(), data, len);
114868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        if (current_send_buffer_.get() || !send_buffer_queue_.empty()) {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          send_buffer_queue_.push_back(buffer);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return true;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        current_send_buffer_ = new DrainableIOBuffer(buffer.get(), len);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return SendDataInternal(current_send_buffer_->data(),
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                current_send_buffer_->BytesRemaining());
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CLOSING:
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CLOSED:
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::Close() {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == CLOSED)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = CLOSING;
135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (current_send_buffer_.get()) {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Will close in SendPending.
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = CLOSED;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseInternal();
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::RestartWithAuth(const AuthCredentials& credentials) {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = CONNECTING;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  socket_->RestartWithAuth(credentials);
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::DetachDelegate() {
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = CLOSED;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebSocketThrottle::GetInstance()->RemoveFromQueue(this);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebSocketThrottle::GetInstance()->WakeupSocketIfNecessary();
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<WebSocketJob> protect(this);
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  weak_ptr_factory_.InvalidateWeakPtrs();
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  weak_ptr_factory_for_send_pending_.InvalidateWeakPtrs();
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_ = NULL;
158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (socket_.get())
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    socket_->DetachDelegate();
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  socket_ = NULL;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!callback_.is_null()) {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    waiting_ = false;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback_.Reset();
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Release();  // Balanced with OnStartOpenConnection().
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int WebSocketJob::OnStartOpenConnection(
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SocketStream* socket, const CompletionCallback& callback) {
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(callback_.is_null());
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = CONNECTING;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  addresses_ = socket->address_list();
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebSocketThrottle::GetInstance()->PutInQueue(this);
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delegate_) {
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int result = delegate_->OnStartOpenConnection(socket, callback);
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ(OK, result);
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (waiting_) {
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // PutInQueue() may set |waiting_| true for throttling. In this case,
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Wakeup() will be called later.
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback_ = callback;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddRef();  // Balanced when callback_ is cleared.
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ERR_IO_PENDING;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return TrySpdyStream();
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::OnConnected(
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SocketStream* socket, int max_pending_send_allowed) {
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == CLOSED)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(CONNECTING, state_);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delegate_)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->OnConnected(socket, max_pending_send_allowed);
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::OnSentData(SocketStream* socket, int amount_sent) {
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(INITIALIZED, state_);
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GT(amount_sent, 0);
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == CLOSED)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == CONNECTING) {
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnSentHandshakeRequest(socket, amount_sent);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delegate_) {
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(state_ == OPEN || state_ == CLOSING);
208868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!current_send_buffer_.get()) {
209868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      VLOG(1)
210868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          << "OnSentData current_send_buffer=NULL amount_sent=" << amount_sent;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    current_send_buffer_->DidConsume(amount_sent);
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (current_send_buffer_->BytesRemaining() > 0)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We need to report amount_sent of original buffer size, instead of
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // amount sent to |socket|.
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    amount_sent = current_send_buffer_->size();
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_GT(amount_sent, 0);
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    current_send_buffer_ = NULL;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!weak_ptr_factory_for_send_pending_.HasWeakPtrs()) {
22390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      base::MessageLoopForIO::current()->PostTask(
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FROM_HERE,
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::Bind(&WebSocketJob::SendPending,
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     weak_ptr_factory_for_send_pending_.GetWeakPtr()));
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->OnSentData(socket, amount_sent);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::OnReceivedData(
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SocketStream* socket, const char* data, int len) {
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(INITIALIZED, state_);
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == CLOSED)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == CONNECTING) {
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnReceivedHandshakeResponse(socket, data, len);
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(state_ == OPEN || state_ == CLOSING);
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delegate_ && len > 0)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->OnReceivedData(socket, data, len);
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::OnClose(SocketStream* socket) {
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = CLOSED;
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebSocketThrottle::GetInstance()->RemoveFromQueue(this);
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebSocketThrottle::GetInstance()->WakeupSocketIfNecessary();
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<WebSocketJob> protect(this);
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  weak_ptr_factory_.InvalidateWeakPtrs();
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SocketStream::Delegate* delegate = delegate_;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_ = NULL;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  socket_ = NULL;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!callback_.is_null()) {
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    waiting_ = false;
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback_.Reset();
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Release();  // Balanced with OnStartOpenConnection().
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delegate)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate->OnClose(socket);
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::OnAuthRequired(
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SocketStream* socket, AuthChallengeInfo* auth_info) {
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delegate_)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->OnAuthRequired(socket, auth_info);
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::OnSSLCertificateError(
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SocketStream* socket, const SSLInfo& ssl_info, bool fatal) {
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delegate_)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->OnSSLCertificateError(socket, ssl_info, fatal);
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::OnError(const SocketStream* socket, int error) {
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delegate_ && error != ERR_PROTOCOL_SWITCHED)
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->OnError(socket, error);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::OnCreatedSpdyStream(int result) {
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(spdy_websocket_stream_.get());
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(socket_.get());
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(ERR_IO_PENDING, result);
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == CLOSED) {
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = ERR_ABORTED;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (result == OK) {
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    state_ = CONNECTING;
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = ERR_PROTOCOL_SWITCHED;
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    spdy_websocket_stream_.reset();
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CompleteIO(result);
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
300c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void WebSocketJob::OnSentSpdyHeaders() {
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(INITIALIZED, state_);
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ != CONNECTING)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delegate_)
305868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    delegate_->OnSentData(socket_.get(), handshake_request_->original_length());
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  handshake_request_.reset();
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
309eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid WebSocketJob::OnSpdyResponseHeadersUpdated(
310eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const SpdyHeaderBlock& response_headers) {
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(INITIALIZED, state_);
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ != CONNECTING)
313eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(toyoshim): Fallback to non-spdy connection?
315eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  handshake_response_->ParseResponseHeaderBlock(response_headers,
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                challenge_,
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                spdy_protocol_version_);
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
319c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SaveCookiesAndNotifyHeadersComplete();
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
322c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void WebSocketJob::OnSentSpdyData(size_t bytes_sent) {
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(INITIALIZED, state_);
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(CONNECTING, state_);
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == CLOSED)
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!spdy_websocket_stream_.get())
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
329868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  OnSentData(socket_.get(), static_cast<int>(bytes_sent));
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
332c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void WebSocketJob::OnReceivedSpdyData(scoped_ptr<SpdyBuffer> buffer) {
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(INITIALIZED, state_);
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(CONNECTING, state_);
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == CLOSED)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!spdy_websocket_stream_.get())
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
339c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (buffer) {
340868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    OnReceivedData(
341868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        socket_.get(), buffer->GetRemainingData(), buffer->GetRemainingSize());
342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
343868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    OnReceivedData(socket_.get(), NULL, 0);
344c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::OnCloseSpdyStream() {
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  spdy_websocket_stream_.reset();
349868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  OnClose(socket_.get());
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WebSocketJob::SendHandshakeRequest(const char* data, int len) {
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(state_, CONNECTING);
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (started_to_send_handshake_request_)
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!handshake_request_->ParseRequest(data, len))
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // handshake message is completed.
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  handshake_response_->set_protocol_version(
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      handshake_request_->protocol_version());
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddCookieHeaderAndSend();
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::AddCookieHeaderAndSend() {
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool allow = true;
368868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (delegate_ && !delegate_->CanGetCookies(socket_.get(), GetURLForCookies()))
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    allow = false;
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
371868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (socket_.get() && delegate_ && state_ == CONNECTING) {
372868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    handshake_request_->RemoveHeaders(kCookieHeaders,
373868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                      arraysize(kCookieHeaders));
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (allow && socket_->context()->cookie_store()) {
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Add cookies, including HttpOnly cookies.
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CookieOptions cookie_options;
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cookie_options.set_include_httponly();
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      socket_->context()->cookie_store()->GetCookiesWithOptionsAsync(
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GetURLForCookies(), cookie_options,
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::Bind(&WebSocketJob::LoadCookieCallback,
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr()));
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DoSendData();
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::LoadCookieCallback(const std::string& cookie) {
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!cookie.empty())
39090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // TODO(tyoshino): Sending cookie means that connection doesn't need
39190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // kPrivacyModeEnabled as cookies may be server-bound and channel id
39290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // wouldn't negatively affect privacy anyway. Need to restart connection
39390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // or refactor to determine cookie status prior to connecting.
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    handshake_request_->AppendHeaderIfMissing("Cookie", cookie);
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DoSendData();
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::DoSendData() {
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (spdy_websocket_stream_.get()) {
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock);
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    handshake_request_->GetRequestHeaderBlock(
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        socket_->url(), headers.get(), &challenge_, spdy_protocol_version_);
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    spdy_websocket_stream_->SendRequest(headers.Pass());
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& handshake_request =
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        handshake_request_->GetRawRequest();
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    handshake_request_sent_ = 0;
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    socket_->net_log()->AddEvent(
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NetLog::TYPE_WEB_SOCKET_SEND_REQUEST_HEADERS,
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&NetLogWebSocketHandshakeCallback, &handshake_request));
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    socket_->SendData(handshake_request.data(),
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      handshake_request.size());
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Just buffered in |handshake_request_|.
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  started_to_send_handshake_request_ = true;
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::OnSentHandshakeRequest(
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SocketStream* socket, int amount_sent) {
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(state_, CONNECTING);
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  handshake_request_sent_ += amount_sent;
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(handshake_request_sent_, handshake_request_->raw_length());
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (handshake_request_sent_ >= handshake_request_->raw_length()) {
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // handshake request has been sent.
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // notify original size of handshake request to delegate.
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (delegate_)
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delegate_->OnSentData(
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          socket,
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          handshake_request_->original_length());
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    handshake_request_.reset();
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::OnReceivedHandshakeResponse(
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SocketStream* socket, const char* data, int len) {
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(state_, CONNECTING);
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (handshake_response_->HasResponse()) {
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we already has handshake response, received data should be frame
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // data, not handshake message.
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    received_data_after_handshake_.insert(
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        received_data_after_handshake_.end(), data, data + len);
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t response_length = handshake_response_->ParseRawResponse(data, len);
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!handshake_response_->HasResponse()) {
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // not yet. we need more data.
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // handshake message is completed.
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string raw_response = handshake_response_->GetRawResponse();
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  socket_->net_log()->AddEvent(
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NetLog::TYPE_WEB_SOCKET_READ_RESPONSE_HEADERS,
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&NetLogWebSocketHandshakeCallback, &raw_response));
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (len - response_length > 0) {
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we received extra data, it should be frame data.
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(received_data_after_handshake_.empty());
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    received_data_after_handshake_.assign(data + response_length, data + len);
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
460c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SaveCookiesAndNotifyHeadersComplete();
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
463c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void WebSocketJob::SaveCookiesAndNotifyHeadersComplete() {
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // handshake message is completed.
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(handshake_response_->HasResponse());
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
467c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Extract cookies from the handshake response into a temporary vector.
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  response_cookies_.clear();
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  response_cookies_save_index_ = 0;
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  handshake_response_->GetHeaders(
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kSetCookieHeaders, arraysize(kSetCookieHeaders), &response_cookies_);
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now, loop over the response cookies, and attempt to persist each.
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SaveNextCookie();
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
478c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void WebSocketJob::NotifyHeadersComplete() {
479c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Remove cookie headers, with malformed headers preserved.
480b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // Actual handshake should be done in Blink.
481c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  handshake_response_->RemoveHeaders(
482c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      kSetCookieHeaders, arraysize(kSetCookieHeaders));
483c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string handshake_response = handshake_response_->GetResponse();
484b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  handshake_response_.reset();
485c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::vector<char> received_data(handshake_response.begin(),
486c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                  handshake_response.end());
487c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  received_data.insert(received_data.end(),
488c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       received_data_after_handshake_.begin(),
489c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       received_data_after_handshake_.end());
490c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  received_data_after_handshake_.clear();
491c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
492c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  state_ = OPEN;
493c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
494c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!received_data.empty());
495c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (delegate_)
496c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    delegate_->OnReceivedData(
497868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        socket_.get(), &received_data.front(), received_data.size());
498c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
499c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  WebSocketThrottle::GetInstance()->RemoveFromQueue(this);
500c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  WebSocketThrottle::GetInstance()->WakeupSocketIfNecessary();
501c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
502c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::SaveNextCookie() {
504868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!socket_.get() || !delegate_ || state_ != CONNECTING)
50590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  callback_pending_ = false;
50890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  save_next_cookie_running_ = true;
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (socket_->context()->cookie_store()) {
51190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    GURL url_for_cookies = GetURLForCookies();
51290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
51390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    CookieOptions options;
51490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    options.set_include_httponly();
51590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
51690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Loop as long as SetCookieWithOptionsAsync completes synchronously. Since
51790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // CookieMonster's asynchronous operation APIs queue the callback to run it
51890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // on the thread where the API was called, there won't be race. I.e. unless
51990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // the callback is run synchronously, it won't be run in parallel with this
52090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // method.
52190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    while (!callback_pending_ &&
52290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)           response_cookies_save_index_ < response_cookies_.size()) {
52390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      std::string cookie = response_cookies_[response_cookies_save_index_];
52490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      response_cookies_save_index_++;
52590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
526868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if (!delegate_->CanSetCookie(
527868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)              socket_.get(), url_for_cookies, cookie, &options))
52890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        continue;
52990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
53090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      callback_pending_ = true;
53190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      socket_->context()->cookie_store()->SetCookieWithOptionsAsync(
53290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          url_for_cookies, cookie, options,
53390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          base::Bind(&WebSocketJob::OnCookieSaved,
53490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr()));
53590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
53890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  save_next_cookie_running_ = false;
53990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
54090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (callback_pending_)
541b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return;
542b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
54390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  response_cookies_.clear();
54490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  response_cookies_save_index_ = 0;
545b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
54690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  NotifyHeadersComplete();
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void WebSocketJob::OnCookieSaved(bool cookie_status) {
55090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Tell the caller of SetCookieWithOptionsAsync() that this completion
55190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // callback is invoked.
55290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // - If the caller checks callback_pending earlier than this callback, the
55390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  //   caller exits to let this method continue iteration.
55490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // - Otherwise, the caller continues iteration.
55590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  callback_pending_ = false;
55690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
55790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Resume SaveNextCookie if the caller of SetCookieWithOptionsAsync() exited
55890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // the loop. Otherwise, return.
55990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (save_next_cookie_running_)
56090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
56190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SaveNextCookie();
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GURL WebSocketJob::GetURLForCookies() const {
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL url = socket_->url();
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string scheme = socket_->is_secure() ? "https" : "http";
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_canon::Replacements<char> replacements;
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  replacements.SetScheme(scheme.c_str(),
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         url_parse::Component(0, scheme.length()));
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return url.ReplaceComponents(replacements);
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const AddressList& WebSocketJob::address_list() const {
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return addresses_;
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int WebSocketJob::TrySpdyStream() {
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!socket_.get())
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ERR_FAILED;
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!websocket_over_spdy_enabled_)
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return OK;
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check if we have a SPDY session available.
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HttpTransactionFactory* factory =
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      socket_->context()->http_transaction_factory();
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!factory)
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return OK;
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<HttpNetworkSession> session = factory->GetSession();
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!session.get())
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return OK;
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SpdySessionPool* spdy_pool = session->spdy_session_pool();
59490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  PrivacyMode privacy_mode = socket_->privacy_mode();
59590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const SpdySessionKey key(HostPortPair::FromURL(socket_->url()),
5967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                           socket_->proxy_server(), privacy_mode);
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Forbid wss downgrade to SPDY without SSL.
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(toyoshim): Does it realize the same policy with HTTP?
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<SpdySession> spdy_session =
6007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      spdy_pool->FindAvailableSession(key, *socket_->net_log());
6017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!spdy_session)
6027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return OK;
6037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SSLInfo ssl_info;
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool was_npn_negotiated;
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NextProto protocol_negotiated = kProtoUnknown;
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool use_ssl = spdy_session->GetSSLInfo(
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &ssl_info, &was_npn_negotiated, &protocol_negotiated);
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (socket_->is_secure() && !use_ssl)
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return OK;
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create SpdyWebSocketStream.
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  spdy_protocol_version_ = spdy_session->GetProtocolVersion();
614868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  spdy_websocket_stream_.reset(
615868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      new SpdyWebSocketStream(spdy_session.get(), this));
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int result = spdy_websocket_stream_->InitializeStream(
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      socket_->url(), MEDIUM, *socket_->net_log());
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result == OK) {
620868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    OnConnected(socket_.get(), kMaxPendingSendAllowed);
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ERR_PROTOCOL_SWITCHED;
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result != ERR_IO_PENDING) {
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    spdy_websocket_stream_.reset();
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return OK;
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ERR_IO_PENDING;
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::SetWaiting() {
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  waiting_ = true;
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WebSocketJob::IsWaiting() const {
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return waiting_;
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::Wakeup() {
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!waiting_)
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  waiting_ = false;
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!callback_.is_null());
64490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoopForIO::current()->PostTask(
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&WebSocketJob::RetryPendingIO,
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr()));
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::RetryPendingIO() {
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int result = TrySpdyStream();
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In the case of ERR_IO_PENDING, CompleteIO() will be called from
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // OnCreatedSpdyStream().
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result != ERR_IO_PENDING)
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CompleteIO(result);
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::CompleteIO(int result) {
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |callback_| may be null if OnClose() or DetachDelegate() was called.
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!callback_.is_null()) {
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CompletionCallback callback = callback_;
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback_.Reset();
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback.Run(result);
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Release();  // Balanced with OnStartOpenConnection().
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WebSocketJob::SendDataInternal(const char* data, int length) {
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (spdy_websocket_stream_.get())
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ERR_IO_PENDING == spdy_websocket_stream_->SendData(data, length);
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (socket_.get())
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return socket_->SendData(data, length);
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::CloseInternal() {
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (spdy_websocket_stream_.get())
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    spdy_websocket_stream_->Close();
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (socket_.get())
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    socket_->Close();
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::SendPending() {
685868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (current_send_buffer_.get())
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Current buffer has been sent. Try next if any.
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (send_buffer_queue_.empty()) {
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No more data to send.
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (state_ == CLOSING)
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CloseInternal();
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<IOBufferWithSize> next_buffer = send_buffer_queue_.front();
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  send_buffer_queue_.pop_front();
698868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  current_send_buffer_ =
699868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      new DrainableIOBuffer(next_buffer.get(), next_buffer->size());
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SendDataInternal(current_send_buffer_->data(),
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   current_send_buffer_->BytesRemaining());
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
705