socket_stream.cc revision 21d179b334e59e9a3bfcaed4c4430bef1bc5759d
1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file.
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//
5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// TODO(ukai): code is similar with http_network_transaction.cc.  We should
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//   think about ways to share code, if possible.
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/socket_stream/socket_stream.h"
9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include <set>
11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <string>
12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/compiler_specific.h"
14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/logging.h"
15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/message_loop.h"
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/string_util.h"
173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/stringprintf.h"
183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h"
19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/auth.h"
20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/host_resolver.h"
21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/io_buffer.h"
22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/net_errors.h"
23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/net_util.h"
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/http/http_auth_handler_factory.h"
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/http/http_request_info.h"
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_response_headers.h"
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_util.h"
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/socket/client_socket_factory.h"
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/socket/socks5_client_socket.h"
30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/socket/socks_client_socket.h"
313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "net/socket/ssl_client_socket.h"
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/socket/tcp_client_socket.h"
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/socket_stream/socket_stream_metrics.h"
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/url_request/url_request.h"
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const int kMaxPendingSendAllowed = 32768;  // 32 kilobytes.
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstatic const int kReadBufferSize = 4096;
38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace net {
40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSocketStream::ResponseHeaders::ResponseHeaders() : IOBuffer() {}
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSocketStream::ResponseHeaders::~ResponseHeaders() { data_ = NULL; }
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SocketStream::ResponseHeaders::Realloc(size_t new_size) {
45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  headers_.reset(static_cast<char*>(realloc(headers_.release(), new_size)));
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottSocketStream::SocketStream(const GURL& url, Delegate* delegate)
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : delegate_(delegate),
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      url_(url),
51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      max_pending_send_allowed_(kMaxPendingSendAllowed),
52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      next_state_(STATE_NONE),
5321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      host_resolver_(NULL),
5421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      cert_verifier_(NULL),
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      http_auth_handler_factory_(NULL),
56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      factory_(ClientSocketFactory::GetDefaultFactory()),
57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      proxy_mode_(kDirectConnection),
58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      proxy_url_(url),
59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      pac_request_(NULL),
60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      ALLOW_THIS_IN_INITIALIZER_LIST(
61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          io_callback_(this, &SocketStream::OnIOCompleted)),
62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      ALLOW_THIS_IN_INITIALIZER_LIST(
63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          read_callback_(this, &SocketStream::OnReadCompleted)),
64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      ALLOW_THIS_IN_INITIALIZER_LIST(
65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          write_callback_(this, &SocketStream::OnWriteCompleted)),
66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      read_buf_(NULL),
67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      write_buf_(NULL),
68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      current_write_buf_(NULL),
69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      write_buf_offset_(0),
70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      write_buf_size_(0),
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      closing_(false),
723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      server_closed_(false),
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      metrics_(new SocketStreamMetrics(url)) {
74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(MessageLoop::current()) <<
75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      "The current MessageLoop must exist";
76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_EQ(MessageLoop::TYPE_IO, MessageLoop::current()->type()) <<
77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      "The current MessageLoop must be TYPE_IO";
78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(delegate_);
79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottSocketStream::~SocketStream() {
82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  set_context(NULL);
83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(!delegate_);
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!pac_request_);
85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottSocketStream::UserData* SocketStream::GetUserData(
88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const void* key) const {
89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  UserDataMap::const_iterator found = user_data_.find(key);
90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (found != user_data_.end())
91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return found->second.get();
92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return NULL;
93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SocketStream::SetUserData(const void* key, UserData* data) {
96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  user_data_[key] = linked_ptr<UserData>(data);
97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SocketStream::set_context(URLRequestContext* context) {
100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_refptr<URLRequestContext> prev_context = context_;
101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  context_ = context;
103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (prev_context != context) {
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (prev_context && pac_request_) {
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      prev_context->proxy_service()->CancelPacRequest(pac_request_);
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      pac_request_ = NULL;
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    net_log_.EndEvent(NetLog::TYPE_REQUEST_ALIVE, NULL);
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    net_log_ = BoundNetLog();
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (context) {
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      net_log_ = BoundNetLog::Make(
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          context->net_log(),
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          NetLog::SOURCE_SOCKET_STREAM);
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      net_log_.BeginEvent(NetLog::TYPE_REQUEST_ALIVE, NULL);
119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (context_) {
123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    host_resolver_ = context_->host_resolver();
12421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    cert_verifier_ = context_->cert_verifier();
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    http_auth_handler_factory_ = context_->http_auth_handler_factory();
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SocketStream::Connect() {
130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(MessageLoop::current()) <<
131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      "The current MessageLoop must exist";
132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_EQ(MessageLoop::TYPE_IO, MessageLoop::current()->type()) <<
133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      "The current MessageLoop must be TYPE_IO";
134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (context_)
135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    ssl_config_service()->GetSSLConfig(&ssl_config_);
136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_EQ(next_state_, STATE_NONE);
137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  AddRef();  // Released in Finish()
139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Open a connection asynchronously, so that delegate won't be called
140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // back before returning Connect().
141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  next_state_ = STATE_RESOLVE_PROXY;
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  net_log_.BeginEvent(
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NetLog::TYPE_SOCKET_STREAM_CONNECT,
144513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      make_scoped_refptr(
145513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          new NetLogStringParameter("url", url_.possibly_invalid_spec())));
146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  MessageLoop::current()->PostTask(
147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      FROM_HERE,
148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      NewRunnableMethod(this, &SocketStream::DoLoop, OK));
149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool SocketStream::SendData(const char* data, int len) {
152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(MessageLoop::current()) <<
153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      "The current MessageLoop must exist";
154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_EQ(MessageLoop::TYPE_IO, MessageLoop::current()->type()) <<
155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      "The current MessageLoop must be TYPE_IO";
156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!socket_.get() || !socket_->IsConnected() || next_state_ == STATE_NONE)
157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return false;
158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (write_buf_) {
159c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int current_amount_send = write_buf_size_ - write_buf_offset_;
160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    for (PendingDataQueue::const_iterator iter = pending_write_bufs_.begin();
161c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott         iter != pending_write_bufs_.end();
162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott         ++iter)
163c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      current_amount_send += (*iter)->size();
164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    current_amount_send += len;
166c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (current_amount_send > max_pending_send_allowed_)
167c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return false;
168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
169513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    pending_write_bufs_.push_back(make_scoped_refptr(
170513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        new IOBufferWithSize(len)));
171c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    memcpy(pending_write_bufs_.back()->data(), data, len);
172c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return true;
173c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
174c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(!current_write_buf_);
175c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  write_buf_ = new IOBuffer(len);
176c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  memcpy(write_buf_->data(), data, len);
177c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  write_buf_size_ = len;
178c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  write_buf_offset_ = 0;
179c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Send pending data asynchronously, so that delegate won't be called
180c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // back before returning SendData().
181c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  MessageLoop::current()->PostTask(
182c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      FROM_HERE,
183c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      NewRunnableMethod(this, &SocketStream::DoLoop, OK));
184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return true;
185c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
186c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
187c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SocketStream::Close() {
188c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(MessageLoop::current()) <<
189c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      "The current MessageLoop must exist";
190c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_EQ(MessageLoop::TYPE_IO, MessageLoop::current()->type()) <<
191c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      "The current MessageLoop must be TYPE_IO";
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If next_state_ is STATE_NONE, the socket was not opened, or already
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // closed.  So, return immediately.
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Otherwise, it might call Finish() more than once, so breaks balance
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // of AddRef() and Release() in Connect() and Finish(), respectively.
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (next_state_ == STATE_NONE)
197c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return;
198c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  MessageLoop::current()->PostTask(
199c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      FROM_HERE,
2003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      NewRunnableMethod(this, &SocketStream::DoClose));
2013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid SocketStream::DoClose() {
2043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  closing_ = true;
2053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // If next_state_ is STATE_TCP_CONNECT, it's waiting other socket establishing
2063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // connection.  If next_state_ is STATE_AUTH_REQUIRED, it's waiting for
2073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // restarting.  In these states, we'll close the SocketStream now.
2083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (next_state_ == STATE_TCP_CONNECT || next_state_ == STATE_AUTH_REQUIRED) {
2093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DoLoop(ERR_ABORTED);
2103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
2113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
2123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // If next_state_ is STATE_READ_WRITE, we'll run DoLoop and close
2133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // the SocketStream.
2143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // If it's writing now, we should defer the closing after the current
2153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // writing is completed.
2163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (next_state_ == STATE_READ_WRITE && !current_write_buf_)
2173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DoLoop(ERR_ABORTED);
2183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // In other next_state_, we'll wait for callback of other APIs, such as
2203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // ResolveProxy().
221c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
222c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
223c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SocketStream::RestartWithAuth(
2243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const string16& username, const string16& password) {
225c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(MessageLoop::current()) <<
226c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      "The current MessageLoop must exist";
227c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_EQ(MessageLoop::TYPE_IO, MessageLoop::current()->type()) <<
228c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      "The current MessageLoop must be TYPE_IO";
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(auth_handler_.get());
230c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!socket_.get()) {
231c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    LOG(ERROR) << "Socket is closed before restarting with auth.";
232c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return;
233c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
234c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
235c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (auth_identity_.invalid) {
236c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Update the username/password.
237c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    auth_identity_.source = HttpAuth::IDENT_SRC_EXTERNAL;
238c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    auth_identity_.invalid = false;
239c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    auth_identity_.username = username;
240c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    auth_identity_.password = password;
241c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
242c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
243c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  MessageLoop::current()->PostTask(
244c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      FROM_HERE,
245c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      NewRunnableMethod(this, &SocketStream::DoRestartWithAuth));
246c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
247c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
248c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SocketStream::DetachDelegate() {
249c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!delegate_)
250c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return;
251c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  delegate_ = NULL;
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  net_log_.AddEvent(NetLog::TYPE_CANCELLED, NULL);
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We don't need to send pending data when client detach the delegate.
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  pending_write_bufs_.clear();
255c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Close();
256c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
257c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
258c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SocketStream::Finish(int result) {
259c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(MessageLoop::current()) <<
260c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      "The current MessageLoop must exist";
261c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_EQ(MessageLoop::TYPE_IO, MessageLoop::current()->type()) <<
262c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      "The current MessageLoop must be TYPE_IO";
263c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_LE(result, OK);
264c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (result == OK)
265c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    result = ERR_CONNECTION_CLOSED;
266c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_EQ(next_state_, STATE_NONE);
267731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DVLOG(1) << "Finish result=" << net::ErrorToString(result);
268c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (delegate_)
269c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    delegate_->OnError(this, result);
270c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
271c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  metrics_->OnClose();
272c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Delegate* delegate = delegate_;
273c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  delegate_ = NULL;
274c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (delegate) {
275c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    delegate->OnClose(this);
276c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
277c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Release();
278c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
279c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
280c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SocketStream::SetHostResolver(HostResolver* host_resolver) {
281c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(host_resolver);
282c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  host_resolver_ = host_resolver;
283c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
284c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
285c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SocketStream::SetClientSocketFactory(
286c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    ClientSocketFactory* factory) {
287c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(factory);
288c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  factory_ = factory;
289c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
290c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
291c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SocketStream::CopyAddrInfo(struct addrinfo* head) {
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  addresses_.Copy(head, true);
293c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
294c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
295c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SocketStream::DidEstablishConnection() {
296c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!socket_.get() || !socket_->IsConnected()) {
297c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_CLOSE;
298c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return ERR_CONNECTION_FAILED;
299c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
300c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  next_state_ = STATE_READ_WRITE;
301c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  metrics_->OnConnected();
302c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  net_log_.EndEvent(NetLog::TYPE_SOCKET_STREAM_CONNECT, NULL);
304c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (delegate_)
305c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    delegate_->OnConnected(this, max_pending_send_allowed_);
306c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
307c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return OK;
308c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
309c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
310c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SocketStream::DidReceiveData(int result) {
311c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(read_buf_);
312c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_GT(result, 0);
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  net_log_.AddEvent(NetLog::TYPE_SOCKET_STREAM_RECEIVED, NULL);
314c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int len = result;
315c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  metrics_->OnRead(len);
316c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (delegate_) {
317c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Notify recevied data to delegate.
318c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    delegate_->OnReceivedData(this, read_buf_->data(), len);
319c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
320c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  read_buf_ = NULL;
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return OK;
322c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
323c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
324c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SocketStream::DidSendData(int result) {
325c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_GT(result, 0);
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  net_log_.AddEvent(NetLog::TYPE_SOCKET_STREAM_SENT, NULL);
327c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int len = result;
328c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  metrics_->OnWrite(len);
329c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  current_write_buf_ = NULL;
330c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (delegate_)
331c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    delegate_->OnSentData(this, len);
332c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
333c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int remaining_size = write_buf_size_ - write_buf_offset_ - len;
334c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (remaining_size == 0) {
335c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (!pending_write_bufs_.empty()) {
336c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      write_buf_size_ = pending_write_bufs_.front()->size();
337c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      write_buf_ = pending_write_bufs_.front();
338c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      pending_write_bufs_.pop_front();
339c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    } else {
340c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      write_buf_size_ = 0;
341c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      write_buf_ = NULL;
342c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
343c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    write_buf_offset_ = 0;
344c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else {
345c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    write_buf_offset_ += len;
346c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return OK;
348c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
349c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
350c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SocketStream::OnIOCompleted(int result) {
351c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DoLoop(result);
352c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
353c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
354c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SocketStream::OnReadCompleted(int result) {
355c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (result == 0) {
356c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // 0 indicates end-of-file, so socket was closed.
3573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // Don't close the socket if it's still writing.
3583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    server_closed_ = true;
359c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else if (result > 0 && read_buf_) {
360c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    result = DidReceiveData(result);
361c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
362c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DoLoop(result);
363c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
364c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
365c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SocketStream::OnWriteCompleted(int result) {
366c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (result >= 0 && write_buf_) {
367c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    result = DidSendData(result);
368c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
369c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DoLoop(result);
370c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
371c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
372c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SocketStream::DoLoop(int result) {
373c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // If context was not set, close immediately.
374c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!context_)
375c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_CLOSE;
376c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
377c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (next_state_ == STATE_NONE)
378c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return;
379c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
380c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  do {
381c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    State state = next_state_;
382c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_NONE;
383c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    switch (state) {
384c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case STATE_RESOLVE_PROXY:
385c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        DCHECK_EQ(OK, result);
386c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        result = DoResolveProxy();
387c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
388c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case STATE_RESOLVE_PROXY_COMPLETE:
389c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        result = DoResolveProxyComplete(result);
390c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
391c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case STATE_RESOLVE_HOST:
392c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        DCHECK_EQ(OK, result);
393c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        result = DoResolveHost();
394c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
395c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case STATE_RESOLVE_HOST_COMPLETE:
396c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        result = DoResolveHostComplete(result);
397c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
398c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case STATE_TCP_CONNECT:
3993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        result = DoTcpConnect(result);
400c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
401c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case STATE_TCP_CONNECT_COMPLETE:
402c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        result = DoTcpConnectComplete(result);
403c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
404c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case STATE_WRITE_TUNNEL_HEADERS:
405c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        DCHECK_EQ(OK, result);
406c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        result = DoWriteTunnelHeaders();
407c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
408c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case STATE_WRITE_TUNNEL_HEADERS_COMPLETE:
409c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        result = DoWriteTunnelHeadersComplete(result);
410c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
411c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case STATE_READ_TUNNEL_HEADERS:
412c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        DCHECK_EQ(OK, result);
413c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        result = DoReadTunnelHeaders();
414c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
415c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case STATE_READ_TUNNEL_HEADERS_COMPLETE:
416c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        result = DoReadTunnelHeadersComplete(result);
417c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
418c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case STATE_SOCKS_CONNECT:
419c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        DCHECK_EQ(OK, result);
420c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        result = DoSOCKSConnect();
421c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
422c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case STATE_SOCKS_CONNECT_COMPLETE:
423c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        result = DoSOCKSConnectComplete(result);
424c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
425c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case STATE_SSL_CONNECT:
426c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        DCHECK_EQ(OK, result);
427c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        result = DoSSLConnect();
428c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
429c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case STATE_SSL_CONNECT_COMPLETE:
430c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        result = DoSSLConnectComplete(result);
431c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
432c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case STATE_READ_WRITE:
433c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        result = DoReadWrite(result);
434c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        break;
4353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      case STATE_AUTH_REQUIRED:
4363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        // It might be called when DoClose is called while waiting in
4373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        // STATE_AUTH_REQUIRED.
4383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        Finish(result);
4393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        return;
440c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      case STATE_CLOSE:
441c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        DCHECK_LE(result, OK);
442c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        Finish(result);
443c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        return;
444c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      default:
4453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        NOTREACHED() << "bad state " << state;
446c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        Finish(result);
447c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        return;
448c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
449c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // If the connection is not established yet and had actual errors,
450c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // close the connection.
451c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (state != STATE_READ_WRITE && result < ERR_IO_PENDING) {
452c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      DCHECK_EQ(next_state_, STATE_CLOSE);
453513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      net_log_.EndEvent(
454513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          NetLog::TYPE_SOCKET_STREAM_CONNECT,
455513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          make_scoped_refptr(new NetLogIntegerParameter("net_error", result)));
456c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
457c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } while (result != ERR_IO_PENDING);
458c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
459c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
460c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SocketStream::DoResolveProxy() {
461c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(!pac_request_);
462c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
463c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
464c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!proxy_url_.is_valid()) {
465c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_CLOSE;
466c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return ERR_INVALID_ARGUMENT;
467c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
468c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
469c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return proxy_service()->ResolveProxy(
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      proxy_url_, &proxy_info_, &io_callback_, &pac_request_, net_log_);
471c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
472c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
473c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SocketStream::DoResolveProxyComplete(int result) {
474c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  pac_request_ = NULL;
475c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (result != OK) {
476c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    LOG(ERROR) << "Failed to resolve proxy: " << result;
477c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (delegate_)
478c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      delegate_->OnError(this, result);
479c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    proxy_info_.UseDirect();
480c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
481c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (proxy_info_.is_direct()) {
482c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // If proxy was not found for original URL (i.e. websocket URL),
483c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // try again with https URL, like Safari implementation.
484c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Note that we don't want to use http proxy, because we'll use tunnel
485c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // proxy using CONNECT method, which is used by https proxy.
486c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (!proxy_url_.SchemeIs("https")) {
487c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      const std::string scheme = "https";
488c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      GURL::Replacements repl;
489c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      repl.SetSchemeStr(scheme);
490c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      proxy_url_ = url_.ReplaceComponents(repl);
491731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      DVLOG(1) << "Try https proxy: " << proxy_url_;
492c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      next_state_ = STATE_RESOLVE_PROXY;
493c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return OK;
494c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
495c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
496c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (proxy_info_.is_empty()) {
498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // No proxies/direct to choose from. This happens when we don't support any
499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // of the proxies in the returned list.
500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return ERR_NO_SUPPORTED_PROXIES;
501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  next_state_ = STATE_RESOLVE_HOST;
504c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return OK;
505c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
506c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
507c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SocketStream::DoResolveHost() {
508c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  next_state_ = STATE_RESOLVE_HOST_COMPLETE;
509c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!proxy_info_.is_empty());
511c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (proxy_info_.is_direct())
512c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    proxy_mode_ = kDirectConnection;
513c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  else if (proxy_info_.proxy_server().is_socks())
514c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    proxy_mode_ = kSOCKSProxy;
515c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  else
516c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    proxy_mode_ = kTunnelProxy;
517c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
518c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Determine the host and port to connect to.
5193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  HostPortPair host_port_pair;
520c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (proxy_mode_ != kDirectConnection) {
5213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    host_port_pair = proxy_info_.proxy_server().host_port_pair();
522c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else {
5233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    host_port_pair = HostPortPair::FromURL(url_);
524c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
525c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
5263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  HostResolver::RequestInfo resolve_info(host_port_pair);
527c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
528731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(host_resolver_);
529731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  resolver_.reset(new SingleRequestHostResolver(host_resolver_));
530c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return resolver_->Resolve(resolve_info, &addresses_, &io_callback_,
531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            net_log_);
532c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
533c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
534c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SocketStream::DoResolveHostComplete(int result) {
5353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (result == OK && delegate_) {
536c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_TCP_CONNECT;
537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result = delegate_->OnStartOpenConnection(this, &io_callback_);
538c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (result == net::ERR_IO_PENDING)
539c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      metrics_->OnWaitConnection();
540c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else {
541c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_CLOSE;
542c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
543c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // TODO(ukai): if error occured, reconsider proxy after error.
544c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return result;
545c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
546c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
5473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickint SocketStream::DoTcpConnect(int result) {
5483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (result != OK) {
5493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    next_state_ = STATE_CLOSE;
5503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return result;
5513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
552c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  next_state_ = STATE_TCP_CONNECT_COMPLETE;
553c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(factory_);
554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  socket_.reset(factory_->CreateTCPClientSocket(addresses_,
5553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                                net_log_.net_log(),
5563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                                net_log_.source()));
557c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  metrics_->OnStartConnection();
558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return socket_->Connect(&io_callback_);
559c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
560c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
561c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SocketStream::DoTcpConnectComplete(int result) {
562c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // TODO(ukai): if error occured, reconsider proxy after error.
563c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (result != OK) {
564c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_CLOSE;
565c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return result;
566c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
567c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
568c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (proxy_mode_ == kTunnelProxy)
569c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_WRITE_TUNNEL_HEADERS;
570c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  else if (proxy_mode_ == kSOCKSProxy)
571c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_SOCKS_CONNECT;
572c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  else if (is_secure()) {
573c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_SSL_CONNECT;
574c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else {
575c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    result = DidEstablishConnection();
576c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
577c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return result;
578c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
579c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
580c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SocketStream::DoWriteTunnelHeaders() {
581c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_EQ(kTunnelProxy, proxy_mode_);
582c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
583c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  next_state_ = STATE_WRITE_TUNNEL_HEADERS_COMPLETE;
584c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
585c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!tunnel_request_headers_.get()) {
586c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    metrics_->OnTunnelProxy();
587c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    tunnel_request_headers_ = new RequestHeaders();
588c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    tunnel_request_headers_bytes_sent_ = 0;
589c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
590c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (tunnel_request_headers_->headers_.empty()) {
591c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    std::string authorization_headers;
592c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
593c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (!auth_handler_.get()) {
594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Do preemptive authentication.
595c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      HttpAuthCache::Entry* entry = auth_cache_.LookupByPath(
596c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          ProxyAuthOrigin(), std::string());
597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (entry) {
598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        scoped_ptr<HttpAuthHandler> handler_preemptive;
599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        int rv_create = http_auth_handler_factory_->
600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            CreatePreemptiveAuthHandlerFromString(
601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                entry->auth_challenge(), HttpAuth::AUTH_PROXY,
602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                ProxyAuthOrigin(), entry->IncrementNonceCount(),
603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                net_log_, &handler_preemptive);
604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (rv_create == OK) {
605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          auth_identity_.source = HttpAuth::IDENT_SRC_PATH_LOOKUP;
606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          auth_identity_.invalid = false;
607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          auth_identity_.username = entry->username();
608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          auth_identity_.password = entry->password();
609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          auth_handler_.swap(handler_preemptive);
610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
611c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      }
612c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
613c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
614c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Support basic authentication scheme only, because we don't have
615c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // HttpRequestInfo.
616c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // TODO(ukai): Add support other authentication scheme.
617c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (auth_handler_.get() && auth_handler_->scheme() == "basic") {
618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      HttpRequestInfo request_info;
619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      std::string auth_token;
620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      int rv = auth_handler_->GenerateAuthToken(
621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          &auth_identity_.username,
622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          &auth_identity_.password,
623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          &request_info,
624c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          NULL,
625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          &auth_token);
626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // TODO(cbentzel): Support async auth handlers.
627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      DCHECK_NE(ERR_IO_PENDING, rv);
628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (rv != OK)
629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return rv;
630c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      authorization_headers.append(
631c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          HttpAuth::GetAuthorizationHeaderName(HttpAuth::AUTH_PROXY) +
632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          ": " + auth_token + "\r\n");
633c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
634c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
6353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    tunnel_request_headers_->headers_ = base::StringPrintf(
636c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        "CONNECT %s HTTP/1.1\r\n"
637c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        "Host: %s\r\n"
638c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        "Proxy-Connection: keep-alive\r\n",
639c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        GetHostAndPort(url_).c_str(),
640c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        GetHostAndOptionalPort(url_).c_str());
641c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (!authorization_headers.empty())
642c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      tunnel_request_headers_->headers_ += authorization_headers;
643c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    tunnel_request_headers_->headers_ += "\r\n";
644c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
645c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tunnel_request_headers_->SetDataOffset(tunnel_request_headers_bytes_sent_);
646c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int buf_len = static_cast<int>(tunnel_request_headers_->headers_.size() -
647c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                                 tunnel_request_headers_bytes_sent_);
648c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_GT(buf_len, 0);
649c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return socket_->Write(tunnel_request_headers_, buf_len, &io_callback_);
650c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
651c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
652c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SocketStream::DoWriteTunnelHeadersComplete(int result) {
653c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_EQ(kTunnelProxy, proxy_mode_);
654c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
655c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (result < 0) {
656c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_CLOSE;
657c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return result;
658c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
659c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
660c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tunnel_request_headers_bytes_sent_ += result;
661c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (tunnel_request_headers_bytes_sent_ <
662c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      tunnel_request_headers_->headers_.size())
663c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_WRITE_TUNNEL_HEADERS;
664c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  else
665c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_READ_TUNNEL_HEADERS;
666c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return OK;
667c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
668c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
669c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SocketStream::DoReadTunnelHeaders() {
670c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_EQ(kTunnelProxy, proxy_mode_);
671c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
672c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  next_state_ = STATE_READ_TUNNEL_HEADERS_COMPLETE;
673c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
674c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!tunnel_response_headers_.get()) {
675c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    tunnel_response_headers_ = new ResponseHeaders();
676c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    tunnel_response_headers_capacity_ = kMaxTunnelResponseHeadersSize;
677c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    tunnel_response_headers_->Realloc(tunnel_response_headers_capacity_);
678c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    tunnel_response_headers_len_ = 0;
679c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
680c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
681c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int buf_len = tunnel_response_headers_capacity_ -
682c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      tunnel_response_headers_len_;
683c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tunnel_response_headers_->SetDataOffset(tunnel_response_headers_len_);
684c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CHECK(tunnel_response_headers_->data());
685c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
686c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return socket_->Read(tunnel_response_headers_, buf_len, &io_callback_);
687c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
688c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
689c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SocketStream::DoReadTunnelHeadersComplete(int result) {
690c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_EQ(kTunnelProxy, proxy_mode_);
691c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
692c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (result < 0) {
693c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_CLOSE;
694c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return result;
695c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
696c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
697c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (result == 0) {
698c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // 0 indicates end-of-file, so socket was closed.
699c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_CLOSE;
700c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return ERR_CONNECTION_CLOSED;
701c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
702c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
703c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tunnel_response_headers_len_ += result;
704c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(tunnel_response_headers_len_ <= tunnel_response_headers_capacity_);
705c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
706c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int eoh = HttpUtil::LocateEndOfHeaders(
707c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      tunnel_response_headers_->headers(), tunnel_response_headers_len_, 0);
708c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (eoh == -1) {
709c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (tunnel_response_headers_len_ >= kMaxTunnelResponseHeadersSize) {
710c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      next_state_ = STATE_CLOSE;
711c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return ERR_RESPONSE_HEADERS_TOO_BIG;
712c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
713c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
714c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_READ_TUNNEL_HEADERS;
715c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return OK;
716c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
717c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // DidReadResponseHeaders
718c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_refptr<HttpResponseHeaders> headers;
719c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  headers = new HttpResponseHeaders(
720c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      HttpUtil::AssembleRawHeaders(tunnel_response_headers_->headers(), eoh));
721c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (headers->GetParsedHttpVersion() < HttpVersion(1, 0)) {
722c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Require the "HTTP/1.x" status line.
723c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_CLOSE;
724c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return ERR_TUNNEL_CONNECTION_FAILED;
725c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
726c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  switch (headers->response_code()) {
727c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case 200:  // OK
728c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      if (is_secure()) {
729c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        DCHECK_EQ(eoh, tunnel_response_headers_len_);
730c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        next_state_ = STATE_SSL_CONNECT;
731c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      } else {
732c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        result = DidEstablishConnection();
733c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        if (result < 0) {
734c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          next_state_ = STATE_CLOSE;
735c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          return result;
736c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        }
737c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        if ((eoh < tunnel_response_headers_len_) && delegate_)
738c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          delegate_->OnReceivedData(
739c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott              this, tunnel_response_headers_->headers() + eoh,
740c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott              tunnel_response_headers_len_ - eoh);
741c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      }
742c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return OK;
743c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case 407:  // Proxy Authentication Required.
744c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      result = HandleAuthChallenge(headers.get());
745c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (result == ERR_PROXY_AUTH_UNSUPPORTED &&
746c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          auth_handler_.get() && delegate_) {
747c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        DCHECK(!proxy_info_.is_empty());
748c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        auth_info_ = new AuthChallengeInfo;
749c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        auth_info_->is_proxy = true;
750c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        auth_info_->host_and_port =
7513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick            ASCIIToWide(proxy_info_.proxy_server().host_port_pair().ToString());
752c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        auth_info_->scheme = ASCIIToWide(auth_handler_->scheme());
753c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        auth_info_->realm = ASCIIToWide(auth_handler_->realm());
754c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        // Wait until RestartWithAuth or Close is called.
755c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        MessageLoop::current()->PostTask(
756c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            FROM_HERE,
757c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott            NewRunnableMethod(this, &SocketStream::DoAuthRequired));
758c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        next_state_ = STATE_AUTH_REQUIRED;
759c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        return ERR_IO_PENDING;
760c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      }
761c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    default:
762c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      break;
763c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
764c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  next_state_ = STATE_CLOSE;
765c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return ERR_TUNNEL_CONNECTION_FAILED;
766c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
767c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
768c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SocketStream::DoSOCKSConnect() {
769c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_EQ(kSOCKSProxy, proxy_mode_);
770c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
771c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  next_state_ = STATE_SOCKS_CONNECT_COMPLETE;
772c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
773c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  ClientSocket* s = socket_.release();
7743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  HostResolver::RequestInfo req_info(HostPortPair::FromURL(url_));
775c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
776c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!proxy_info_.is_empty());
777c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (proxy_info_.proxy_server().scheme() == ProxyServer::SCHEME_SOCKS5)
778c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    s = new SOCKS5ClientSocket(s, req_info);
779c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  else
780731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    s = new SOCKSClientSocket(s, req_info, host_resolver_);
781c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  socket_.reset(s);
782c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  metrics_->OnSOCKSProxy();
783c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return socket_->Connect(&io_callback_);
784c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
785c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
786c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SocketStream::DoSOCKSConnectComplete(int result) {
787c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_EQ(kSOCKSProxy, proxy_mode_);
788c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
789c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (result == OK) {
790c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (is_secure())
791c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      next_state_ = STATE_SSL_CONNECT;
792c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    else
793c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      result = DidEstablishConnection();
794c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else {
795c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_CLOSE;
796c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
797c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return result;
798c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
799c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
800c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SocketStream::DoSSLConnect() {
801c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK(factory_);
802731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // TODO(agl): look into plumbing SSLHostInfo here.
8034a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  socket_.reset(factory_->CreateSSLClientSocket(socket_.release(),
8044a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                                HostPortPair::FromURL(url_),
8054a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                                ssl_config_,
80621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                                NULL /* ssl_host_info */,
80721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                                cert_verifier_));
808c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  next_state_ = STATE_SSL_CONNECT_COMPLETE;
809c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  metrics_->OnSSLConnection();
810c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return socket_->Connect(&io_callback_);
811c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
812c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
813c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SocketStream::DoSSLConnectComplete(int result) {
814c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (IsCertificateError(result)) {
815c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (socket_->IsConnectedAndIdle()) {
816c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      result = HandleCertificateError(result);
817c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    } else {
818c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // SSLClientSocket for Mac will report socket is not connected,
819c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // if it returns cert verification error.  It didn't perform
820c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // SSLHandshake yet.
821c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // So, we should restart establishing connection with the
822c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // certificate in allowed bad certificates in |ssl_config_|.
823c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // See also net/http/http_network_transaction.cc
824c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      //  HandleCertificateError() and RestartIgnoringLastError().
825c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      SSLClientSocket* ssl_socket =
826c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        reinterpret_cast<SSLClientSocket*>(socket_.get());
827c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      SSLInfo ssl_info;
828c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      ssl_socket->GetSSLInfo(&ssl_info);
829c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      SSLConfig::CertAndStatus bad_cert;
830c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      bad_cert.cert = ssl_info.cert;
831c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      bad_cert.cert_status = ssl_info.cert_status;
832c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      if (ssl_config_.IsAllowedBadCert(ssl_info.cert)) {
833c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        // If we already have the certificate in the set of allowed bad
834c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        // certificates, we did try it and failed again, so we should not
835c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        // retry again: the connection should fail at last.
836c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        next_state_ = STATE_CLOSE;
837c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        return result;
838c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      }
839c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // Add the bad certificate to the set of allowed certificates in the
840c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // SSL info object.
841c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      ssl_config_.allowed_bad_certs.push_back(bad_cert);
842c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // Restart connection ignoring the bad certificate.
843c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      socket_->Disconnect();
844c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      socket_.reset();
845c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      next_state_ = STATE_TCP_CONNECT;
846c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return OK;
847c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
848c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
849c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
850c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (result == OK)
851c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    result = DidEstablishConnection();
852c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  else
853c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_CLOSE;
854c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return result;
855c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
856c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
857c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SocketStream::DoReadWrite(int result) {
858c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (result < OK) {
859c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_CLOSE;
860c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return result;
861c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
862c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!socket_.get() || !socket_->IsConnected()) {
863c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    next_state_ = STATE_CLOSE;
864c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return ERR_CONNECTION_CLOSED;
865c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
866c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
867c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If client has requested close(), and there's nothing to write, then
868c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // let's close the socket.
869c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We don't care about receiving data after the socket is closed.
870c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (closing_ && !write_buf_ && pending_write_bufs_.empty()) {
871c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    socket_->Disconnect();
872c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    next_state_ = STATE_CLOSE;
873c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return OK;
874c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
875c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
876c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  next_state_ = STATE_READ_WRITE;
877c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
8783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // If server already closed the socket, we don't try to read.
8793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!server_closed_) {
8803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!read_buf_) {
8813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // No read pending and server didn't close the socket.
8823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      read_buf_ = new IOBuffer(kReadBufferSize);
8833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      result = socket_->Read(read_buf_, kReadBufferSize, &read_callback_);
8843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if (result > 0) {
8853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        return DidReceiveData(result);
8863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      } else if (result == 0) {
8873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        // 0 indicates end-of-file, so socket was closed.
8883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        next_state_ = STATE_CLOSE;
8893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        server_closed_ = true;
8903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        return ERR_CONNECTION_CLOSED;
8913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      }
8923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // If read is pending, try write as well.
8933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // Otherwise, return the result and do next loop (to close the
8943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // connection).
8953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if (result != ERR_IO_PENDING) {
8963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        next_state_ = STATE_CLOSE;
8973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        server_closed_ = true;
8983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        return result;
8993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      }
900c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
9013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // Read is pending.
9023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DCHECK(read_buf_);
903c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
904c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
905c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (write_buf_ && !current_write_buf_) {
906c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // No write pending.
907c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    current_write_buf_ = new DrainableIOBuffer(write_buf_, write_buf_size_);
908c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    current_write_buf_->SetOffset(write_buf_offset_);
909c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    result = socket_->Write(current_write_buf_,
910c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                            current_write_buf_->BytesRemaining(),
911c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                            &write_callback_);
912c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (result > 0) {
913c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return DidSendData(result);
914c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
915c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // If write is not pending, return the result and do next loop (to close
916c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // the connection).
917c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (result != 0 && result != ERR_IO_PENDING) {
918c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      next_state_ = STATE_CLOSE;
919c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return result;
920c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
921c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return result;
922c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
923c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
924c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // We arrived here when both operation is pending.
925c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return ERR_IO_PENDING;
926c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
927c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
928c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottGURL SocketStream::ProxyAuthOrigin() const {
929c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!proxy_info_.is_empty());
9303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return GURL("http://" +
9313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick              proxy_info_.proxy_server().host_port_pair().ToString());
932c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
933c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
934c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SocketStream::HandleAuthChallenge(const HttpResponseHeaders* headers) {
935c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  GURL auth_origin(ProxyAuthOrigin());
936c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
937731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  VLOG(1) << "The proxy " << auth_origin << " requested auth";
938c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
9393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // TODO(cbentzel): Since SocketStream only suppports basic authentication
9403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // right now, another challenge is always treated as a rejection.
9413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Ultimately this should be converted to use HttpAuthController like the
9423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // HttpNetworkTransaction has.
9433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (auth_handler_.get() && !auth_identity_.invalid) {
944c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (auth_identity_.source != HttpAuth::IDENT_SRC_PATH_LOOKUP)
945c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      auth_cache_.Remove(auth_origin,
946c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                         auth_handler_->realm(),
947c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         auth_handler_->scheme(),
948c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                         auth_identity_.username,
949c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                         auth_identity_.password);
950c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    auth_handler_.reset();
951c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    auth_identity_ = HttpAuth::Identity();
952c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
953c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
954c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  auth_identity_.invalid = true;
955c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::set<std::string> disabled_schemes;
956c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  HttpAuth::ChooseBestChallenge(http_auth_handler_factory_, headers,
957c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                HttpAuth::AUTH_PROXY,
958c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                auth_origin, disabled_schemes,
959c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                net_log_, &auth_handler_);
960c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!auth_handler_.get()) {
961c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    LOG(ERROR) << "Can't perform auth to the proxy " << auth_origin;
962c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    return ERR_TUNNEL_CONNECTION_FAILED;
963c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
964c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (auth_handler_->NeedsIdentity()) {
965c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We only support basic authentication scheme now.
966c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // TODO(ukai): Support other authentication scheme.
967c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    HttpAuthCache::Entry* entry =
968c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      auth_cache_.Lookup(auth_origin, auth_handler_->realm(), "basic");
969c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (entry) {
970c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      auth_identity_.source = HttpAuth::IDENT_SRC_REALM_LOOKUP;
971c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      auth_identity_.invalid = false;
972c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      auth_identity_.username = entry->username();
973c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      auth_identity_.password = entry->password();
974c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      // Restart with auth info.
975c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
976c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return ERR_PROXY_AUTH_UNSUPPORTED;
977c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else {
978c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    auth_identity_.invalid = false;
979c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
980c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return ERR_TUNNEL_CONNECTION_FAILED;
981c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
982c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
983c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SocketStream::DoAuthRequired() {
984c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (delegate_ && auth_info_.get())
985c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    delegate_->OnAuthRequired(this, auth_info_.get());
986c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  else
987c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DoLoop(net::ERR_UNEXPECTED);
988c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
989c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
990c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid SocketStream::DoRestartWithAuth() {
991c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DCHECK_EQ(next_state_, STATE_AUTH_REQUIRED);
992c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  auth_cache_.Add(ProxyAuthOrigin(),
993c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  auth_handler_->realm(),
994c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  auth_handler_->scheme(),
995c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  auth_handler_->challenge(),
996c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  auth_identity_.username,
997c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  auth_identity_.password,
998c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott                  std::string());
999c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
1000c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tunnel_request_headers_ = NULL;
1001c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tunnel_request_headers_bytes_sent_ = 0;
1002c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tunnel_response_headers_ = NULL;
1003c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tunnel_response_headers_capacity_ = 0;
1004c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  tunnel_response_headers_len_ = 0;
1005c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
1006c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  next_state_ = STATE_TCP_CONNECT;
1007c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  DoLoop(OK);
1008c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
1009c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
1010c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint SocketStream::HandleCertificateError(int result) {
1011c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // TODO(ukai): handle cert error properly.
1012c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  switch (result) {
1013c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case ERR_CERT_COMMON_NAME_INVALID:
1014c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case ERR_CERT_DATE_INVALID:
1015c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    case ERR_CERT_AUTHORITY_INVALID:
1016c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      result = OK;
1017c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      break;
1018c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    default:
1019c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      break;
1020c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
1021c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return result;
1022c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
1023c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
1024c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool SocketStream::is_secure() const {
1025c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return url_.SchemeIs("wss");
1026c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
1027c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
1028c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottSSLConfigService* SocketStream::ssl_config_service() const {
1029c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return context_->ssl_config_service();
1030c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
1031c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
1032c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottProxyService* SocketStream::proxy_service() const {
1033c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return context_->proxy_service();
1034c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
1035c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
1036c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}  // namespace net
1037