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(
39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const GURL& url, net::SocketStream::Delegate* delegate,
40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    net::URLRequestContext* context, net::CookieStore* cookie_store) {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::WebSocketJob* job = new net::WebSocketJob(delegate);
42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  job->InitSocketStream(new net::SocketStream(url, job, context, cookie_store));
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return job;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class WebSocketJobInitSingleton {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend struct base::DefaultLazyInstanceTraits<WebSocketJobInitSingleton>;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebSocketJobInitSingleton() {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net::SocketStreamJob::RegisterProtocolFactory("ws", WebSocketJobFactory);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    net::SocketStreamJob::RegisterProtocolFactory("wss", WebSocketJobFactory);
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static base::LazyInstance<WebSocketJobInitSingleton> g_websocket_job_init =
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LAZY_INSTANCE_INITIALIZER;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // anonymous namespace
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::EnsureInit() {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_websocket_job_init.Get();
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WebSocketJob::WebSocketJob(SocketStream::Delegate* delegate)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : delegate_(delegate),
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      state_(INITIALIZED),
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      waiting_(false),
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      handshake_request_(new WebSocketHandshakeRequestHandler),
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      handshake_response_(new WebSocketHandshakeResponseHandler),
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      started_to_send_handshake_request_(false),
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      handshake_request_sent_(0),
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      response_cookies_save_index_(0),
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      spdy_protocol_version_(0),
7790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      save_next_cookie_running_(false),
7890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      callback_pending_(false),
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_ptr_factory_(this),
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_ptr_factory_for_send_pending_(this) {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WebSocketJob::~WebSocketJob() {
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(CLOSED, state_);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!delegate_);
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!socket_.get());
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::Connect() {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(socket_.get());
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(state_, INITIALIZED);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = CONNECTING;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  socket_->Connect();
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WebSocketJob::SendData(const char* data, int len) {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (state_) {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case INITIALIZED:
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CONNECTING:
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return SendHandshakeRequest(data, len);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case OPEN:
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        scoped_refptr<IOBufferWithSize> buffer = new IOBufferWithSize(len);
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        memcpy(buffer->data(), data, len);
108868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        if (current_send_buffer_.get() || !send_buffer_queue_.empty()) {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          send_buffer_queue_.push_back(buffer);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return true;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        current_send_buffer_ = new DrainableIOBuffer(buffer.get(), len);
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return SendDataInternal(current_send_buffer_->data(),
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                current_send_buffer_->BytesRemaining());
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CLOSING:
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CLOSED:
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::Close() {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == CLOSED)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = CLOSING;
129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (current_send_buffer_.get()) {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Will close in SendPending.
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = CLOSED;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseInternal();
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::RestartWithAuth(const AuthCredentials& credentials) {
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = CONNECTING;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  socket_->RestartWithAuth(credentials);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::DetachDelegate() {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = CLOSED;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebSocketThrottle::GetInstance()->RemoveFromQueue(this);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<WebSocketJob> protect(this);
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  weak_ptr_factory_.InvalidateWeakPtrs();
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  weak_ptr_factory_for_send_pending_.InvalidateWeakPtrs();
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_ = NULL;
151868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (socket_.get())
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    socket_->DetachDelegate();
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  socket_ = NULL;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!callback_.is_null()) {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    waiting_ = false;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback_.Reset();
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Release();  // Balanced with OnStartOpenConnection().
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int WebSocketJob::OnStartOpenConnection(
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SocketStream* socket, const CompletionCallback& callback) {
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(callback_.is_null());
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = CONNECTING;
165ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  addresses_ = socket->address_list();
167ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (!WebSocketThrottle::GetInstance()->PutInQueue(this)) {
168ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return ERR_WS_THROTTLE_QUEUE_TOO_LARGE;
169ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
170ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delegate_) {
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int result = delegate_->OnStartOpenConnection(socket, callback);
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ(OK, result);
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (waiting_) {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // PutInQueue() may set |waiting_| true for throttling. In this case,
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Wakeup() will be called later.
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback_ = callback;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddRef();  // Balanced when callback_ is cleared.
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ERR_IO_PENDING;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return TrySpdyStream();
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::OnConnected(
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SocketStream* socket, int max_pending_send_allowed) {
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == CLOSED)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(CONNECTING, state_);
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delegate_)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->OnConnected(socket, max_pending_send_allowed);
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::OnSentData(SocketStream* socket, int amount_sent) {
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(INITIALIZED, state_);
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GT(amount_sent, 0);
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == CLOSED)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == CONNECTING) {
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnSentHandshakeRequest(socket, amount_sent);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delegate_) {
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(state_ == OPEN || state_ == CLOSING);
205868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!current_send_buffer_.get()) {
206868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      VLOG(1)
207868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          << "OnSentData current_send_buffer=NULL amount_sent=" << amount_sent;
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    current_send_buffer_->DidConsume(amount_sent);
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (current_send_buffer_->BytesRemaining() > 0)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We need to report amount_sent of original buffer size, instead of
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // amount sent to |socket|.
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    amount_sent = current_send_buffer_->size();
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_GT(amount_sent, 0);
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    current_send_buffer_ = NULL;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!weak_ptr_factory_for_send_pending_.HasWeakPtrs()) {
22090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      base::MessageLoopForIO::current()->PostTask(
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          FROM_HERE,
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::Bind(&WebSocketJob::SendPending,
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     weak_ptr_factory_for_send_pending_.GetWeakPtr()));
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->OnSentData(socket, amount_sent);
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::OnReceivedData(
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SocketStream* socket, const char* data, int len) {
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(INITIALIZED, state_);
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == CLOSED)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == CONNECTING) {
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnReceivedHandshakeResponse(socket, data, len);
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(state_ == OPEN || state_ == CLOSING);
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delegate_ && len > 0)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->OnReceivedData(socket, data, len);
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::OnClose(SocketStream* socket) {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = CLOSED;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebSocketThrottle::GetInstance()->RemoveFromQueue(this);
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<WebSocketJob> protect(this);
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  weak_ptr_factory_.InvalidateWeakPtrs();
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SocketStream::Delegate* delegate = delegate_;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delegate_ = NULL;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  socket_ = NULL;
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!callback_.is_null()) {
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    waiting_ = false;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback_.Reset();
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Release();  // Balanced with OnStartOpenConnection().
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delegate)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate->OnClose(socket);
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::OnAuthRequired(
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SocketStream* socket, AuthChallengeInfo* auth_info) {
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delegate_)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->OnAuthRequired(socket, auth_info);
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::OnSSLCertificateError(
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SocketStream* socket, const SSLInfo& ssl_info, bool fatal) {
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delegate_)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->OnSSLCertificateError(socket, ssl_info, fatal);
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::OnError(const SocketStream* socket, int error) {
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (delegate_ && error != ERR_PROTOCOL_SWITCHED)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delegate_->OnError(socket, error);
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::OnCreatedSpdyStream(int result) {
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(spdy_websocket_stream_.get());
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(socket_.get());
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(ERR_IO_PENDING, result);
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == CLOSED) {
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = ERR_ABORTED;
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (result == OK) {
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    state_ = CONNECTING;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = ERR_PROTOCOL_SWITCHED;
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    spdy_websocket_stream_.reset();
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CompleteIO(result);
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void WebSocketJob::OnSentSpdyHeaders() {
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(INITIALIZED, state_);
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ != CONNECTING)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
300c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  size_t original_length = handshake_request_->original_length();
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  handshake_request_.reset();
302c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (delegate_)
303c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    delegate_->OnSentData(socket_.get(), original_length);
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
306eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid WebSocketJob::OnSpdyResponseHeadersUpdated(
307eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const SpdyHeaderBlock& response_headers) {
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(INITIALIZED, state_);
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ != CONNECTING)
310eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(toyoshim): Fallback to non-spdy connection?
312eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  handshake_response_->ParseResponseHeaderBlock(response_headers,
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                challenge_,
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                spdy_protocol_version_);
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
316c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SaveCookiesAndNotifyHeadersComplete();
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
319c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void WebSocketJob::OnSentSpdyData(size_t bytes_sent) {
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(INITIALIZED, state_);
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(CONNECTING, state_);
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == CLOSED)
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!spdy_websocket_stream_.get())
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
326868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  OnSentData(socket_.get(), static_cast<int>(bytes_sent));
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void WebSocketJob::OnReceivedSpdyData(scoped_ptr<SpdyBuffer> buffer) {
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(INITIALIZED, state_);
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(CONNECTING, state_);
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == CLOSED)
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!spdy_websocket_stream_.get())
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
336c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (buffer) {
337868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    OnReceivedData(
338868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        socket_.get(), buffer->GetRemainingData(), buffer->GetRemainingSize());
339c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  } else {
340868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    OnReceivedData(socket_.get(), NULL, 0);
341c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::OnCloseSpdyStream() {
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  spdy_websocket_stream_.reset();
346868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  OnClose(socket_.get());
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WebSocketJob::SendHandshakeRequest(const char* data, int len) {
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(state_, CONNECTING);
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (started_to_send_handshake_request_)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!handshake_request_->ParseRequest(data, len))
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddCookieHeaderAndSend();
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::AddCookieHeaderAndSend() {
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool allow = true;
362868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (delegate_ && !delegate_->CanGetCookies(socket_.get(), GetURLForCookies()))
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    allow = false;
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (socket_.get() && delegate_ && state_ == CONNECTING) {
366868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    handshake_request_->RemoveHeaders(kCookieHeaders,
367868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                      arraysize(kCookieHeaders));
368a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (allow && socket_->cookie_store()) {
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Add cookies, including HttpOnly cookies.
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CookieOptions cookie_options;
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cookie_options.set_include_httponly();
372a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      socket_->cookie_store()->GetCookiesWithOptionsAsync(
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GetURLForCookies(), cookie_options,
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::Bind(&WebSocketJob::LoadCookieCallback,
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr()));
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DoSendData();
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::LoadCookieCallback(const std::string& cookie) {
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!cookie.empty())
38490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // TODO(tyoshino): Sending cookie means that connection doesn't need
385e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    // PRIVACY_MODE_ENABLED as cookies may be server-bound and channel id
38690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // wouldn't negatively affect privacy anyway. Need to restart connection
38790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // or refactor to determine cookie status prior to connecting.
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    handshake_request_->AppendHeaderIfMissing("Cookie", cookie);
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DoSendData();
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::DoSendData() {
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (spdy_websocket_stream_.get()) {
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock);
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    handshake_request_->GetRequestHeaderBlock(
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        socket_->url(), headers.get(), &challenge_, spdy_protocol_version_);
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    spdy_websocket_stream_->SendRequest(headers.Pass());
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& handshake_request =
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        handshake_request_->GetRawRequest();
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    handshake_request_sent_ = 0;
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    socket_->net_log()->AddEvent(
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NetLog::TYPE_WEB_SOCKET_SEND_REQUEST_HEADERS,
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&NetLogWebSocketHandshakeCallback, &handshake_request));
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    socket_->SendData(handshake_request.data(),
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      handshake_request.size());
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Just buffered in |handshake_request_|.
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  started_to_send_handshake_request_ = true;
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::OnSentHandshakeRequest(
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SocketStream* socket, int amount_sent) {
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(state_, CONNECTING);
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  handshake_request_sent_ += amount_sent;
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(handshake_request_sent_, handshake_request_->raw_length());
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (handshake_request_sent_ >= handshake_request_->raw_length()) {
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // handshake request has been sent.
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // notify original size of handshake request to delegate.
420c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // Reset the handshake_request_ first in case this object is deleted by the
421c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    // delegate.
422c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    size_t original_length = handshake_request_->original_length();
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    handshake_request_.reset();
424c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if (delegate_)
425c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      delegate_->OnSentData(socket, original_length);
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::OnReceivedHandshakeResponse(
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SocketStream* socket, const char* data, int len) {
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(state_, CONNECTING);
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (handshake_response_->HasResponse()) {
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we already has handshake response, received data should be frame
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // data, not handshake message.
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    received_data_after_handshake_.insert(
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        received_data_after_handshake_.end(), data, data + len);
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t response_length = handshake_response_->ParseRawResponse(data, len);
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!handshake_response_->HasResponse()) {
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // not yet. we need more data.
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // handshake message is completed.
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string raw_response = handshake_response_->GetRawResponse();
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  socket_->net_log()->AddEvent(
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NetLog::TYPE_WEB_SOCKET_READ_RESPONSE_HEADERS,
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&NetLogWebSocketHandshakeCallback, &raw_response));
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (len - response_length > 0) {
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we received extra data, it should be frame data.
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(received_data_after_handshake_.empty());
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    received_data_after_handshake_.assign(data + response_length, data + len);
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
455c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SaveCookiesAndNotifyHeadersComplete();
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
458c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void WebSocketJob::SaveCookiesAndNotifyHeadersComplete() {
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // handshake message is completed.
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(handshake_response_->HasResponse());
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
462c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Extract cookies from the handshake response into a temporary vector.
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  response_cookies_.clear();
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  response_cookies_save_index_ = 0;
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  handshake_response_->GetHeaders(
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kSetCookieHeaders, arraysize(kSetCookieHeaders), &response_cookies_);
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now, loop over the response cookies, and attempt to persist each.
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SaveNextCookie();
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
473c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void WebSocketJob::NotifyHeadersComplete() {
474c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Remove cookie headers, with malformed headers preserved.
475b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // Actual handshake should be done in Blink.
476c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  handshake_response_->RemoveHeaders(
477c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      kSetCookieHeaders, arraysize(kSetCookieHeaders));
478c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string handshake_response = handshake_response_->GetResponse();
479b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  handshake_response_.reset();
480c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::vector<char> received_data(handshake_response.begin(),
481c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                  handshake_response.end());
482c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  received_data.insert(received_data.end(),
483c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       received_data_after_handshake_.begin(),
484c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       received_data_after_handshake_.end());
485c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  received_data_after_handshake_.clear();
486c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
487c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  state_ = OPEN;
488c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
489c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!received_data.empty());
490c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (delegate_)
491c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    delegate_->OnReceivedData(
492868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        socket_.get(), &received_data.front(), received_data.size());
493c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
494c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  WebSocketThrottle::GetInstance()->RemoveFromQueue(this);
495c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
496c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::SaveNextCookie() {
498868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!socket_.get() || !delegate_ || state_ != CONNECTING)
49990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  callback_pending_ = false;
50290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  save_next_cookie_running_ = true;
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
504a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (socket_->cookie_store()) {
50590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    GURL url_for_cookies = GetURLForCookies();
50690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
50790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    CookieOptions options;
50890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    options.set_include_httponly();
50990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
51090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Loop as long as SetCookieWithOptionsAsync completes synchronously. Since
51190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // CookieMonster's asynchronous operation APIs queue the callback to run it
51290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // on the thread where the API was called, there won't be race. I.e. unless
51390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // the callback is run synchronously, it won't be run in parallel with this
51490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // method.
51590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    while (!callback_pending_ &&
51690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)           response_cookies_save_index_ < response_cookies_.size()) {
51790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      std::string cookie = response_cookies_[response_cookies_save_index_];
51890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      response_cookies_save_index_++;
51990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
520868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if (!delegate_->CanSetCookie(
521868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)              socket_.get(), url_for_cookies, cookie, &options))
52290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        continue;
52390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
52490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      callback_pending_ = true;
525a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      socket_->cookie_store()->SetCookieWithOptionsAsync(
52690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          url_for_cookies, cookie, options,
52790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          base::Bind(&WebSocketJob::OnCookieSaved,
52890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr()));
52990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
53290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  save_next_cookie_running_ = false;
53390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
53490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (callback_pending_)
535b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return;
536b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
53790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  response_cookies_.clear();
53890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  response_cookies_save_index_ = 0;
539b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
54090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  NotifyHeadersComplete();
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void WebSocketJob::OnCookieSaved(bool cookie_status) {
54490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Tell the caller of SetCookieWithOptionsAsync() that this completion
54590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // callback is invoked.
54690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // - If the caller checks callback_pending earlier than this callback, the
54790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  //   caller exits to let this method continue iteration.
54890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // - Otherwise, the caller continues iteration.
54990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  callback_pending_ = false;
55090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
55190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Resume SaveNextCookie if the caller of SetCookieWithOptionsAsync() exited
55290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // the loop. Otherwise, return.
55390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (save_next_cookie_running_)
55490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
55590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SaveNextCookie();
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GURL WebSocketJob::GetURLForCookies() const {
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GURL url = socket_->url();
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string scheme = socket_->is_secure() ? "https" : "http";
5625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  url::Replacements<char> replacements;
5635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  replacements.SetScheme(scheme.c_str(), url::Component(0, scheme.length()));
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return url.ReplaceComponents(replacements);
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const AddressList& WebSocketJob::address_list() const {
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return addresses_;
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int WebSocketJob::TrySpdyStream() {
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!socket_.get())
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ERR_FAILED;
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check if we have a SPDY session available.
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HttpTransactionFactory* factory =
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      socket_->context()->http_transaction_factory();
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!factory)
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return OK;
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<HttpNetworkSession> session = factory->GetSession();
58146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!session.get() || !session->params().enable_websocket_over_spdy)
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return OK;
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SpdySessionPool* spdy_pool = session->spdy_session_pool();
58490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  PrivacyMode privacy_mode = socket_->privacy_mode();
58590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const SpdySessionKey key(HostPortPair::FromURL(socket_->url()),
5867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                           socket_->proxy_server(), privacy_mode);
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Forbid wss downgrade to SPDY without SSL.
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(toyoshim): Does it realize the same policy with HTTP?
589ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  base::WeakPtr<SpdySession> spdy_session =
5907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      spdy_pool->FindAvailableSession(key, *socket_->net_log());
5917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!spdy_session)
5927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return OK;
5937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SSLInfo ssl_info;
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool was_npn_negotiated;
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NextProto protocol_negotiated = kProtoUnknown;
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool use_ssl = spdy_session->GetSSLInfo(
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &ssl_info, &was_npn_negotiated, &protocol_negotiated);
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (socket_->is_secure() && !use_ssl)
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return OK;
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create SpdyWebSocketStream.
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  spdy_protocol_version_ = spdy_session->GetProtocolVersion();
604ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  spdy_websocket_stream_.reset(new SpdyWebSocketStream(spdy_session, this));
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int result = spdy_websocket_stream_->InitializeStream(
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      socket_->url(), MEDIUM, *socket_->net_log());
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result == OK) {
609868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    OnConnected(socket_.get(), kMaxPendingSendAllowed);
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ERR_PROTOCOL_SWITCHED;
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result != ERR_IO_PENDING) {
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    spdy_websocket_stream_.reset();
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return OK;
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ERR_IO_PENDING;
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::SetWaiting() {
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  waiting_ = true;
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WebSocketJob::IsWaiting() const {
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return waiting_;
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::Wakeup() {
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!waiting_)
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  waiting_ = false;
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!callback_.is_null());
63390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoopForIO::current()->PostTask(
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&WebSocketJob::RetryPendingIO,
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 weak_ptr_factory_.GetWeakPtr()));
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::RetryPendingIO() {
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int result = TrySpdyStream();
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In the case of ERR_IO_PENDING, CompleteIO() will be called from
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // OnCreatedSpdyStream().
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result != ERR_IO_PENDING)
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CompleteIO(result);
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::CompleteIO(int result) {
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |callback_| may be null if OnClose() or DetachDelegate() was called.
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!callback_.is_null()) {
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CompletionCallback callback = callback_;
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback_.Reset();
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback.Run(result);
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Release();  // Balanced with OnStartOpenConnection().
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WebSocketJob::SendDataInternal(const char* data, int length) {
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (spdy_websocket_stream_.get())
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ERR_IO_PENDING == spdy_websocket_stream_->SendData(data, length);
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (socket_.get())
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return socket_->SendData(data, length);
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::CloseInternal() {
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (spdy_websocket_stream_.get())
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    spdy_websocket_stream_->Close();
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (socket_.get())
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    socket_->Close();
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebSocketJob::SendPending() {
674868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (current_send_buffer_.get())
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Current buffer has been sent. Try next if any.
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (send_buffer_queue_.empty()) {
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No more data to send.
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (state_ == CLOSING)
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CloseInternal();
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<IOBufferWithSize> next_buffer = send_buffer_queue_.front();
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  send_buffer_queue_.pop_front();
687868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  current_send_buffer_ =
688868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      new DrainableIOBuffer(next_buffer.get(), next_buffer->size());
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SendDataInternal(current_send_buffer_->data(),
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   current_send_buffer_->BytesRemaining());
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
694