1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/websockets/websocket_job.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <algorithm>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/lazy_instance.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_tokenizer.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "googleurl/src/gurl.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/net_errors.h"
133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "net/base/net_log.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/cookie_policy.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/cookie_store.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/io_buffer.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/http/http_util.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/url_request/url_request_context.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/websockets/websocket_frame_handler.h"
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/websockets/websocket_handshake_handler.h"
213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "net/websockets/websocket_net_log_params.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/websockets/websocket_throttle.h"
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// lower-case header names.
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst char* const kCookieHeaders[] = {
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  "cookie", "cookie2"
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst char* const kSetCookieHeaders[] = {
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  "set-cookie", "set-cookie2"
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnet::SocketStreamJob* WebSocketJobFactory(
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const GURL& url, net::SocketStream::Delegate* delegate) {
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  net::WebSocketJob* job = new net::WebSocketJob(delegate);
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  job->InitSocketStream(new net::SocketStream(url, job));
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return job;
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass WebSocketJobInitSingleton {
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
4321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  friend struct base::DefaultLazyInstanceTraits<WebSocketJobInitSingleton>;
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  WebSocketJobInitSingleton() {
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    net::SocketStreamJob::RegisterProtocolFactory("ws", WebSocketJobFactory);
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    net::SocketStreamJob::RegisterProtocolFactory("wss", WebSocketJobFactory);
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenstatic base::LazyInstance<WebSocketJobInitSingleton> g_websocket_job_init(
5121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    base::LINKER_INITIALIZED);
5221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // anonymous namespace
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace net {
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocketJob::EnsureInit() {
5921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  g_websocket_job_init.Get();
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochWebSocketJob::WebSocketJob(SocketStream::Delegate* delegate)
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : delegate_(delegate),
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      state_(INITIALIZED),
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      waiting_(false),
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      callback_(NULL),
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      handshake_request_(new WebSocketHandshakeRequestHandler),
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      handshake_response_(new WebSocketHandshakeResponseHandler),
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      handshake_request_sent_(0),
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      response_cookies_save_index_(0),
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      send_frame_handler_(new WebSocketFrameHandler),
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      receive_frame_handler_(new WebSocketFrameHandler) {
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochWebSocketJob::~WebSocketJob() {
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(CLOSED, state_);
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!delegate_);
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!socket_.get());
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocketJob::Connect() {
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(socket_.get());
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(state_, INITIALIZED);
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  state_ = CONNECTING;
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  socket_->Connect();
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool WebSocketJob::SendData(const char* data, int len) {
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  switch (state_) {
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case INITIALIZED:
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case CONNECTING:
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return SendHandshakeRequest(data, len);
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case OPEN:
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      {
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        send_frame_handler_->AppendData(data, len);
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // If current buffer is sending now, this data will be sent in
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // SendPending() after current data was sent.
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // Do not buffer sending data for now.  Since
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // WebCore::SocketStreamHandle controls traffic to keep number of
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // pending bytes less than max_pending_send_allowed, so when sending
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // larger message than max_pending_send_allowed should not be buffered.
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // If we don't call OnSentData, WebCore::SocketStreamHandle would stop
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // sending more data when pending data reaches max_pending_send_allowed.
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // TODO(ukai): Fix this to support compression for larger message.
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        int err = 0;
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (!send_frame_handler_->GetCurrentBuffer() &&
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            (err = send_frame_handler_->UpdateCurrentBuffer(false)) > 0) {
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          DCHECK(!current_buffer_);
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          current_buffer_ = new DrainableIOBuffer(
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              send_frame_handler_->GetCurrentBuffer(),
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              send_frame_handler_->GetCurrentBufferSize());
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          return socket_->SendData(
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch              current_buffer_->data(), current_buffer_->BytesRemaining());
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return err >= 0;
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case CLOSING:
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case CLOSED:
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return false;
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocketJob::Close() {
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  state_ = CLOSING;
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (current_buffer_) {
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Will close in SendPending.
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  state_ = CLOSED;
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  socket_->Close();
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocketJob::RestartWithAuth(
1393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const string16& username,
1403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const string16& password) {
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  state_ = CONNECTING;
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  socket_->RestartWithAuth(username, password);
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocketJob::DetachDelegate() {
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  state_ = CLOSED;
14721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  WebSocketThrottle::GetInstance()->RemoveFromQueue(this);
14821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  WebSocketThrottle::GetInstance()->WakeupSocketIfNecessary();
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_refptr<WebSocketJob> protect(this);
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delegate_ = NULL;
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (socket_)
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    socket_->DetachDelegate();
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  socket_ = NULL;
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (callback_) {
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    waiting_ = false;
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    callback_ = NULL;
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Release();  // Balanced with OnStartOpenConnection().
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint WebSocketJob::OnStartOpenConnection(
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SocketStream* socket, CompletionCallback* callback) {
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!callback_);
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  state_ = CONNECTING;
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  addresses_.Copy(socket->address_list().head(), true);
16821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  WebSocketThrottle::GetInstance()->PutInQueue(this);
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!waiting_)
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return OK;
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  callback_ = callback;
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddRef();  // Balanced when callback_ becomes NULL.
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return ERR_IO_PENDING;
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocketJob::OnConnected(
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SocketStream* socket, int max_pending_send_allowed) {
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (state_ == CLOSED)
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(CONNECTING, state_);
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (delegate_)
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delegate_->OnConnected(socket, max_pending_send_allowed);
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocketJob::OnSentData(SocketStream* socket, int amount_sent) {
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_NE(INITIALIZED, state_);
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (state_ == CLOSED)
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (state_ == CONNECTING) {
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    OnSentHandshakeRequest(socket, amount_sent);
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (delegate_) {
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(state_ == OPEN || state_ == CLOSING);
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK_GT(amount_sent, 0);
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK(current_buffer_);
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    current_buffer_->DidConsume(amount_sent);
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (current_buffer_->BytesRemaining() > 0)
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We need to report amount_sent of original buffer size, instead of
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // amount sent to |socket|.
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    amount_sent = send_frame_handler_->GetOriginalBufferSize();
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    DCHECK_GT(amount_sent, 0);
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    current_buffer_ = NULL;
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    send_frame_handler_->ReleaseCurrentBuffer();
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delegate_->OnSentData(socket, amount_sent);
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MessageLoopForIO::current()->PostTask(
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        FROM_HERE, NewRunnableMethod(this, &WebSocketJob::SendPending));
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocketJob::OnReceivedData(
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SocketStream* socket, const char* data, int len) {
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_NE(INITIALIZED, state_);
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (state_ == CLOSED)
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (state_ == CONNECTING) {
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    OnReceivedHandshakeResponse(socket, data, len);
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(state_ == OPEN || state_ == CLOSING);
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string received_data;
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  receive_frame_handler_->AppendData(data, len);
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Don't buffer receiving data for now.
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // TODO(ukai): fix performance of WebSocketFrameHandler.
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (receive_frame_handler_->UpdateCurrentBuffer(false) > 0) {
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    received_data +=
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        std::string(receive_frame_handler_->GetCurrentBuffer()->data(),
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    receive_frame_handler_->GetCurrentBufferSize());
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    receive_frame_handler_->ReleaseCurrentBuffer();
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
233dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (delegate_ && !received_data.empty())
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      delegate_->OnReceivedData(
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          socket, received_data.data(), received_data.size());
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocketJob::OnClose(SocketStream* socket) {
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  state_ = CLOSED;
24021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  WebSocketThrottle::GetInstance()->RemoveFromQueue(this);
24121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  WebSocketThrottle::GetInstance()->WakeupSocketIfNecessary();
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_refptr<WebSocketJob> protect(this);
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SocketStream::Delegate* delegate = delegate_;
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delegate_ = NULL;
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  socket_ = NULL;
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (callback_) {
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    waiting_ = false;
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    callback_ = NULL;
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Release();  // Balanced with OnStartOpenConnection().
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (delegate)
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delegate->OnClose(socket);
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocketJob::OnAuthRequired(
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SocketStream* socket, AuthChallengeInfo* auth_info) {
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (delegate_)
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delegate_->OnAuthRequired(socket, auth_info);
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocketJob::OnError(const SocketStream* socket, int error) {
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (delegate_)
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delegate_->OnError(socket, error);
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool WebSocketJob::SendHandshakeRequest(const char* data, int len) {
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(state_, CONNECTING);
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!handshake_request_->ParseRequest(data, len))
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // handshake message is completed.
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddCookieHeaderAndSend();
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Just buffered in |handshake_request_|.
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocketJob::AddCookieHeaderAndSend() {
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int policy = OK;
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (socket_->context()->cookie_policy()) {
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GURL url_for_cookies = GetURLForCookies();
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    policy = socket_->context()->cookie_policy()->CanGetCookies(
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        url_for_cookies,
285ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        url_for_cookies);
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
287ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_NE(ERR_IO_PENDING, policy);
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  OnCanGetCookiesCompleted(policy);
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocketJob::OnCanGetCookiesCompleted(int policy) {
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (socket_ && delegate_ && state_ == CONNECTING) {
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    handshake_request_->RemoveHeaders(
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        kCookieHeaders, arraysize(kCookieHeaders));
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (policy == OK) {
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Add cookies, including HttpOnly cookies.
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (socket_->context()->cookie_store()) {
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        CookieOptions cookie_options;
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        cookie_options.set_include_httponly();
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        std::string cookie =
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            socket_->context()->cookie_store()->GetCookiesWithOptions(
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                GetURLForCookies(), cookie_options);
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (!cookie.empty())
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          handshake_request_->AppendHeaderIfMissing("Cookie", cookie);
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& handshake_request = handshake_request_->GetRawRequest();
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    handshake_request_sent_ = 0;
3103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    socket_->net_log()->AddEvent(
3113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        NetLog::TYPE_WEB_SOCKET_SEND_REQUEST_HEADERS,
312513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        make_scoped_refptr(
313513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch            new NetLogWebSocketHandshakeParameter(handshake_request)));
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    socket_->SendData(handshake_request.data(),
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      handshake_request.size());
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocketJob::OnSentHandshakeRequest(
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SocketStream* socket, int amount_sent) {
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(state_, CONNECTING);
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  handshake_request_sent_ += amount_sent;
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_LE(handshake_request_sent_, handshake_request_->raw_length());
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (handshake_request_sent_ >= handshake_request_->raw_length()) {
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // handshake request has been sent.
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // notify original size of handshake request to delegate.
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (delegate_)
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      delegate_->OnSentData(
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          socket,
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          handshake_request_->original_length());
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    handshake_request_.reset();
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocketJob::OnReceivedHandshakeResponse(
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SocketStream* socket, const char* data, int len) {
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(state_, CONNECTING);
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (handshake_response_->HasResponse()) {
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If we already has handshake response, received data should be frame
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // data, not handshake message.
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    receive_frame_handler_->AppendData(data, len);
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  size_t response_length = handshake_response_->ParseRawResponse(data, len);
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!handshake_response_->HasResponse()) {
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // not yet. we need more data.
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // handshake message is completed.
3513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  socket_->net_log()->AddEvent(
3523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      NetLog::TYPE_WEB_SOCKET_READ_RESPONSE_HEADERS,
353513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      make_scoped_refptr(new NetLogWebSocketHandshakeParameter(
354513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          handshake_response_->GetRawResponse())));
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (len - response_length > 0) {
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If we received extra data, it should be frame data.
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    receive_frame_handler_->AppendData(data + response_length,
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                       len - response_length);
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SaveCookiesAndNotifyHeaderComplete();
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocketJob::SaveCookiesAndNotifyHeaderComplete() {
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // handshake message is completed.
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(handshake_response_->HasResponse());
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  response_cookies_.clear();
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  response_cookies_save_index_ = 0;
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  handshake_response_->GetHeaders(
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      kSetCookieHeaders, arraysize(kSetCookieHeaders), &response_cookies_);
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Now, loop over the response cookies, and attempt to persist each.
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SaveNextCookie();
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocketJob::SaveNextCookie() {
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (response_cookies_save_index_ == response_cookies_.size()) {
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    response_cookies_.clear();
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    response_cookies_save_index_ = 0;
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Remove cookie headers, with malformed headers preserved.
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Actual handshake should be done in WebKit.
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    handshake_response_->RemoveHeaders(
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        kSetCookieHeaders, arraysize(kSetCookieHeaders));
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::string received_data = handshake_response_->GetResponse();
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Don't buffer receiving data for now.
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // TODO(ukai): fix performance of WebSocketFrameHandler.
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    while (receive_frame_handler_->UpdateCurrentBuffer(false) > 0) {
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      received_data +=
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          std::string(receive_frame_handler_->GetCurrentBuffer()->data(),
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      receive_frame_handler_->GetCurrentBufferSize());
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      receive_frame_handler_->ReleaseCurrentBuffer();
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    state_ = OPEN;
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (delegate_)
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      delegate_->OnReceivedData(
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          socket_, received_data.data(), received_data.size());
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    handshake_response_.reset();
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
40321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    WebSocketThrottle::GetInstance()->RemoveFromQueue(this);
40421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    WebSocketThrottle::GetInstance()->WakeupSocketIfNecessary();
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int policy = OK;
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (socket_->context()->cookie_policy()) {
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GURL url_for_cookies = GetURLForCookies();
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    policy = socket_->context()->cookie_policy()->CanSetCookie(
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        url_for_cookies,
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        url_for_cookies,
414ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        response_cookies_[response_cookies_save_index_]);
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
417ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_NE(ERR_IO_PENDING, policy);
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  OnCanSetCookieCompleted(policy);
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocketJob::OnCanSetCookieCompleted(int policy) {
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (socket_ && delegate_ && state_ == CONNECTING) {
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if ((policy == OK || policy == OK_FOR_SESSION_ONLY) &&
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        socket_->context()->cookie_store()) {
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      CookieOptions options;
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      options.set_include_httponly();
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (policy == OK_FOR_SESSION_ONLY)
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        options.set_force_session();
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GURL url_for_cookies = GetURLForCookies();
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      socket_->context()->cookie_store()->SetCookieWithOptions(
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          url_for_cookies, response_cookies_[response_cookies_save_index_],
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          options);
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    response_cookies_save_index_++;
435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SaveNextCookie();
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochGURL WebSocketJob::GetURLForCookies() const {
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GURL url = socket_->url();
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string scheme = socket_->is_secure() ? "https" : "http";
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  url_canon::Replacements<char> replacements;
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  replacements.SetScheme(scheme.c_str(),
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         url_parse::Component(0, scheme.length()));
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return url.ReplaceComponents(replacements);
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst AddressList& WebSocketJob::address_list() const {
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return addresses_;
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocketJob::SetWaiting() {
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  waiting_ = true;
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool WebSocketJob::IsWaiting() const {
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return waiting_;
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocketJob::Wakeup() {
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!waiting_)
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  waiting_ = false;
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(callback_);
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MessageLoopForIO::current()->PostTask(
466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      FROM_HERE,
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewRunnableMethod(this,
468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        &WebSocketJob::DoCallback));
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocketJob::DoCallback() {
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // |callback_| may be NULL if OnClose() or DetachDelegate() was called.
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (callback_) {
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    net::CompletionCallback* callback = callback_;
475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    callback_ = NULL;
476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    callback->Run(net::OK);
477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Release();  // Balanced with OnStartOpenConnection().
478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebSocketJob::SendPending() {
482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (current_buffer_)
483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Current buffer is done.  Try next buffer if any.
485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Don't buffer sending data. See comment on case OPEN in SendData().
486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (send_frame_handler_->UpdateCurrentBuffer(false) <= 0) {
487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // No more data to send.
488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (state_ == CLOSING)
489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      socket_->Close();
490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  current_buffer_ = new DrainableIOBuffer(
493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      send_frame_handler_->GetCurrentBuffer(),
494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      send_frame_handler_->GetCurrentBufferSize());
495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  socket_->SendData(current_buffer_->data(), current_buffer_->BytesRemaining());
496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace net
499