ssl_client_socket_unittest.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// Use of this source code is governed by a BSD-style license that can be
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// found in the LICENSE file.
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com#include "net/socket/ssl_client_socket.h"
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com#include "base/callback_helpers.h"
8ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com#include "base/memory/ref_counted.h"
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "net/base/address_list.h"
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "net/base/io_buffer.h"
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "net/base/net_errors.h"
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "net/base/net_log.h"
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "net/base/net_log_unittest.h"
142e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org#include "net/base/test_completion_callback.h"
152e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org#include "net/base/test_data_directory.h"
162e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org#include "net/cert/mock_cert_verifier.h"
172e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org#include "net/cert/test_root_certs.h"
18945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com#include "net/dns/host_resolver.h"
19945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com#include "net/http/transport_security_state.h"
20945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com#include "net/socket/client_socket_factory.h"
212e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org#include "net/socket/client_socket_handle.h"
222e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org#include "net/socket/socket_test_util.h"
232e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org#include "net/socket/tcp_client_socket.h"
242e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org#include "net/ssl/ssl_cert_request_info.h"
25945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com#include "net/ssl/ssl_config_service.h"
262e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org#include "net/test/cert_test_util.h"
27945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com#include "net/test/spawned_test_server/spawned_test_server.h"
28945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com#include "testing/gtest/include/gtest/gtest.h"
29945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com#include "testing/platform_test.h"
30945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com
31945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com//-----------------------------------------------------------------------------
32945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com
33945a139553a9c9da03766213661d7f5fd6ed3042reed@android.comnamespace net {
34945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com
35945a139553a9c9da03766213661d7f5fd6ed3042reed@android.comnamespace {
362e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org
37945a139553a9c9da03766213661d7f5fd6ed3042reed@android.comconst SSLConfig kDefaultSSLConfig;
38945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com
392e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org// WrappedStreamSocket is a base class that wraps an existing StreamSocket,
402e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org// forwarding the Socket and StreamSocket interfaces to the underlying
412e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org// transport.
422e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org// This is to provide a common base class for subclasses to override specific
432e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org// StreamSocket methods for testing, while still communicating with a 'real'
442e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org// StreamSocket.
452e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.orgclass WrappedStreamSocket : public StreamSocket {
462e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org public:
472e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  explicit WrappedStreamSocket(scoped_ptr<StreamSocket> transport)
482e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org      : transport_(transport.Pass()) {}
492e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  virtual ~WrappedStreamSocket() {}
502e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org
512e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  // StreamSocket implementation:
522e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  virtual int Connect(const CompletionCallback& callback) OVERRIDE {
532e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org    return transport_->Connect(callback);
542e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  }
552e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  virtual void Disconnect() OVERRIDE { transport_->Disconnect(); }
562e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  virtual bool IsConnected() const OVERRIDE {
57945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com    return transport_->IsConnected();
58945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  }
59945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  virtual bool IsConnectedAndIdle() const OVERRIDE {
60945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com    return transport_->IsConnectedAndIdle();
61945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  }
62945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  virtual int GetPeerAddress(IPEndPoint* address) const OVERRIDE {
63945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com    return transport_->GetPeerAddress(address);
64945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  }
65945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  virtual int GetLocalAddress(IPEndPoint* address) const OVERRIDE {
66945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com    return transport_->GetLocalAddress(address);
678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  virtual const BoundNetLog& NetLog() const OVERRIDE {
698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return transport_->NetLog();
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  virtual void SetSubresourceSpeculation() OVERRIDE {
728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    transport_->SetSubresourceSpeculation();
738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  virtual void SetOmniboxSpeculation() OVERRIDE {
758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    transport_->SetOmniboxSpeculation();
768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  virtual bool WasEverUsed() const OVERRIDE {
788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return transport_->WasEverUsed();
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  virtual bool UsingTCPFastOpen() const OVERRIDE {
818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return transport_->UsingTCPFastOpen();
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  virtual bool WasNpnNegotiated() const OVERRIDE {
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return transport_->WasNpnNegotiated();
858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  virtual NextProto GetNegotiatedProtocol() const OVERRIDE {
878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return transport_->GetNegotiatedProtocol();
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  virtual bool GetSSLInfo(SSLInfo* ssl_info) OVERRIDE {
908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return transport_->GetSSLInfo(ssl_info);
918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Socket implementation:
948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  virtual int Read(IOBuffer* buf,
958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                   int buf_len,
968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                   const CompletionCallback& callback) OVERRIDE {
978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return transport_->Read(buf, buf_len, callback);
988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  virtual int Write(IOBuffer* buf,
1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    int buf_len,
1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    const CompletionCallback& callback) OVERRIDE {
1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return transport_->Write(buf, buf_len, callback);
1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  virtual bool SetReceiveBufferSize(int32 size) OVERRIDE {
1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return transport_->SetReceiveBufferSize(size);
1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  virtual bool SetSendBufferSize(int32 size) OVERRIDE {
1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return transport_->SetSendBufferSize(size);
1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com protected:
1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_ptr<StreamSocket> transport_;
1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// ReadBufferingStreamSocket is a wrapper for an existing StreamSocket that
1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// will ensure a certain amount of data is internally buffered before
1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// satisfying a Read() request. It exists to mimic OS-level internal
1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// buffering, but in a way to guarantee that X number of bytes will be
11915161620bee33efcb706685486c9ce0fb51a72bbreed@android.com// returned to callers of Read(), regardless of how quickly the OS receives
12015161620bee33efcb706685486c9ce0fb51a72bbreed@android.com// them from the TestServer.
12115161620bee33efcb706685486c9ce0fb51a72bbreed@android.comclass ReadBufferingStreamSocket : public WrappedStreamSocket {
1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com public:
1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  explicit ReadBufferingStreamSocket(scoped_ptr<StreamSocket> transport);
1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  virtual ~ReadBufferingStreamSocket() {}
1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Socket implementation:
1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  virtual int Read(IOBuffer* buf,
1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                   int buf_len,
1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                   const CompletionCallback& callback) OVERRIDE;
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Sets the internal buffer to |size|. This must not be greater than
1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // the largest value supplied to Read() - that is, it does not handle
1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // having "leftovers" at the end of Read().
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Each call to Read() will be prevented from completion until at least
1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // |size| data has been read.
1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Set to 0 to turn off buffering, causing Read() to transparently
1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // read via the underlying transport.
1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  void SetBufferSize(int size);
1398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com private:
1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  enum State {
1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    STATE_NONE,
1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    STATE_READ,
1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    STATE_READ_COMPLETE,
1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  };
14615161620bee33efcb706685486c9ce0fb51a72bbreed@android.com
1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  int DoLoop(int result);
14815161620bee33efcb706685486c9ce0fb51a72bbreed@android.com  int DoRead();
1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  int DoReadComplete(int result);
1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  void OnReadCompleted(int result);
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  State state_;
1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_refptr<GrowableIOBuffer> read_buffer_;
1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  int buffer_size_;
1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_refptr<IOBuffer> user_read_buf_;
1578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  CompletionCallback user_read_callback_;
1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
1598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comReadBufferingStreamSocket::ReadBufferingStreamSocket(
1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    scoped_ptr<StreamSocket> transport)
1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    : WrappedStreamSocket(transport.Pass()),
1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      read_buffer_(new GrowableIOBuffer()),
1648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      buffer_size_(0) {}
1658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid ReadBufferingStreamSocket::SetBufferSize(int size) {
1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  DCHECK(!user_read_buf_.get());
1688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  buffer_size_ = size;
1698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  read_buffer_->SetCapacity(size);
1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint ReadBufferingStreamSocket::Read(IOBuffer* buf,
1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                    int buf_len,
1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                    const CompletionCallback& callback) {
1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  if (buffer_size_ == 0)
1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return transport_->Read(buf, buf_len, callback);
1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  if (buf_len < buffer_size_)
1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return ERR_UNEXPECTED;
1808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  state_ = STATE_READ;
1828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  user_read_buf_ = buf;
1838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  int result = DoLoop(OK);
1848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  if (result == ERR_IO_PENDING)
1858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    user_read_callback_ = callback;
1868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  else
1878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    user_read_buf_ = NULL;
1888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  return result;
1898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint ReadBufferingStreamSocket::DoLoop(int result) {
1928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  int rv = result;
1938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  do {
1948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    State current_state = state_;
1958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    state_ = STATE_NONE;
1968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    switch (current_state) {
1978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      case STATE_READ:
1988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        rv = DoRead();
1998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        break;
2008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      case STATE_READ_COMPLETE:
2018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        rv = DoReadComplete(rv);
2028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        break;
2038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      case STATE_NONE:
2048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      default:
2058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        NOTREACHED() << "Unexpected state: " << current_state;
2068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        rv = ERR_UNEXPECTED;
207fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com        break;
2088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  } while (rv != ERR_IO_PENDING && state_ != STATE_NONE);
2108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  return rv;
2118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint ReadBufferingStreamSocket::DoRead() {
2148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  state_ = STATE_READ_COMPLETE;
2158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  int rv =
2168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      transport_->Read(read_buffer_.get(),
2178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                       read_buffer_->RemainingCapacity(),
2188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                       base::Bind(&ReadBufferingStreamSocket::OnReadCompleted,
2198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                  base::Unretained(this)));
2208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  return rv;
2218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint ReadBufferingStreamSocket::DoReadComplete(int result) {
2248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  state_ = STATE_NONE;
2258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  if (result <= 0)
2268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return result;
2278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  read_buffer_->set_offset(read_buffer_->offset() + result);
2298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  if (read_buffer_->RemainingCapacity() > 0) {
2308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    state_ = STATE_READ;
2318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return OK;
2328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
2338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  memcpy(user_read_buf_->data(),
2358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         read_buffer_->StartOfBuffer(),
2368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         read_buffer_->capacity());
2378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  read_buffer_->set_offset(0);
2388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  return read_buffer_->capacity();
2398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid ReadBufferingStreamSocket::OnReadCompleted(int result) {
2428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  result = DoLoop(result);
2438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  if (result == ERR_IO_PENDING)
2448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return;
2458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  user_read_buf_ = NULL;
2478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  base::ResetAndReturn(&user_read_callback_).Run(result);
2488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// Simulates synchronously receiving an error during Read() or Write()
2518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass SynchronousErrorStreamSocket : public WrappedStreamSocket {
2528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com public:
2538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  explicit SynchronousErrorStreamSocket(scoped_ptr<StreamSocket> transport);
2548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  virtual ~SynchronousErrorStreamSocket() {}
2558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Socket implementation:
2578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  virtual int Read(IOBuffer* buf,
2588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                   int buf_len,
2598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                   const CompletionCallback& callback) OVERRIDE;
2608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  virtual int Write(IOBuffer* buf,
2618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    int buf_len,
2628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    const CompletionCallback& callback) OVERRIDE;
2638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Sets the next Read() call and all future calls to return |error|.
2658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // If there is already a pending asynchronous read, the configured error
2668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // will not be returned until that asynchronous read has completed and Read()
2678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // is called again.
2688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  void SetNextReadError(Error error) {
2698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DCHECK_GE(0, error);
2708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    have_read_error_ = true;
2718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    pending_read_error_ = error;
2728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
2738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Sets the next Write() call and all future calls to return |error|.
2758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // If there is already a pending asynchronous write, the configured error
2768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // will not be returned until that asynchronous write has completed and
2778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Write() is called again.
2788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  void SetNextWriteError(Error error) {
2798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    DCHECK_GE(0, error);
2808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    have_write_error_ = true;
2818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    pending_write_error_ = error;
2828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
2838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com private:
2858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  bool have_read_error_;
2868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  int pending_read_error_;
2878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  bool have_write_error_;
2898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  int pending_write_error_;
2908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  DISALLOW_COPY_AND_ASSIGN(SynchronousErrorStreamSocket);
2928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
2938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSynchronousErrorStreamSocket::SynchronousErrorStreamSocket(
2958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    scoped_ptr<StreamSocket> transport)
2968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    : WrappedStreamSocket(transport.Pass()),
2978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      have_read_error_(false),
2988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      pending_read_error_(OK),
2998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      have_write_error_(false),
3008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      pending_write_error_(OK) {}
3018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SynchronousErrorStreamSocket::Read(IOBuffer* buf,
3038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                       int buf_len,
3048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                       const CompletionCallback& callback) {
3058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  if (have_read_error_)
3068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return pending_read_error_;
307fc25abdabff76f913fb9d4f373418c10a1eca92breed@android.com  return transport_->Read(buf, buf_len, callback);
3088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SynchronousErrorStreamSocket::Write(IOBuffer* buf,
3118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                        int buf_len,
3128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                        const CompletionCallback& callback) {
31377f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com  if (have_write_error_)
31477f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com    return pending_write_error_;
3158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  return transport_->Write(buf, buf_len, callback);
3168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// FakeBlockingStreamSocket wraps an existing StreamSocket and simulates the
319fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com// underlying transport needing to complete things asynchronously in a
3208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// deterministic manner (e.g.: independent of the TestServer and the OS's
3218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// semantics).
3228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass FakeBlockingStreamSocket : public WrappedStreamSocket {
3238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com public:
3248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  explicit FakeBlockingStreamSocket(scoped_ptr<StreamSocket> transport);
3258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  virtual ~FakeBlockingStreamSocket() {}
3268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
327fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com  // Socket implementation:
3288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  virtual int Read(IOBuffer* buf,
3298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                   int buf_len,
3308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                   const CompletionCallback& callback) OVERRIDE {
3318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return read_state_.RunWrappedFunction(buf, buf_len, callback);
332fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com  }
3338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  virtual int Write(IOBuffer* buf,
3348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    int buf_len,
3358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    const CompletionCallback& callback) OVERRIDE {
336fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    return write_state_.RunWrappedFunction(buf, buf_len, callback);
3378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
3388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Causes the next call to Read() to return ERR_IO_PENDING, not completing
3408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // (invoking the callback) until UnblockRead() has been called and the
3418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // underlying transport has completed.
3428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  void SetNextReadShouldBlock() { read_state_.SetShouldBlock(); }
3438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  void UnblockRead() { read_state_.Unblock(); }
3448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Causes the next call to Write() to return ERR_IO_PENDING, not completing
3468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // (invoking the callback) until UnblockWrite() has been called and the
3478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // underlying transport has completed.
3488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  void SetNextWriteShouldBlock() { write_state_.SetShouldBlock(); }
3498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  void UnblockWrite() { write_state_.Unblock(); }
3508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com private:
3528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Tracks the state for simulating a blocking Read/Write operation.
3538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  class BlockingState {
3548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com   public:
3558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // Wrapper for the underlying Socket function to call (ie: Read/Write).
35677f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com    typedef base::Callback<int(IOBuffer*, int, const CompletionCallback&)>
35777f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com        WrappedSocketFunction;
35877f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com
35977f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com    explicit BlockingState(const WrappedSocketFunction& function);
36077f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com    ~BlockingState() {}
36177f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com
36277f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com    // Sets the next call to RunWrappedFunction() to block, returning
363fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    // ERR_IO_PENDING and not invoking the user callback until Unblock() is
36477f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com    // called.
36577f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com    void SetShouldBlock();
36677f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com
367fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    // Unblocks the currently blocked pending function, invoking the user
36877f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com    // callback if the results are immediately available.
36977f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com    // Note: It's not valid to call this unless SetShouldBlock() has been
37077f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com    // called beforehand.
37177f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com    void Unblock();
37277f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com
37377f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com    // Performs the wrapped socket function on the underlying transport. If
37477f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com    // configured to block via SetShouldBlock(), then |user_callback| will not
37577f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com    // be invoked until Unblock() has been called.
37677f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com    int RunWrappedFunction(IOBuffer* buf,
37777f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com                           int len,
37877f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com                           const CompletionCallback& user_callback);
37977f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com
38077f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com   private:
38177f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com    // Handles completion from the underlying wrapped socket function.
38277f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com    void OnCompleted(int result);
38377f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com
38477f0ef726f1f8b6769ed2509171afce8bac00b23reed@android.com    WrappedSocketFunction wrapped_function_;
3858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool should_block_;
3868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool have_result_;
3878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int pending_result_;
3888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    CompletionCallback user_callback_;
3898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  };
3908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  BlockingState read_state_;
3928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  BlockingState write_state_;
3938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  DISALLOW_COPY_AND_ASSIGN(FakeBlockingStreamSocket);
3958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
3968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3975383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.comFakeBlockingStreamSocket::FakeBlockingStreamSocket(
3988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    scoped_ptr<StreamSocket> transport)
3998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    : WrappedStreamSocket(transport.Pass()),
4008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      read_state_(base::Bind(&Socket::Read,
4018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                             base::Unretained(transport_.get()))),
4028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      write_state_(base::Bind(&Socket::Write,
4038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                              base::Unretained(transport_.get()))) {}
4048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comFakeBlockingStreamSocket::BlockingState::BlockingState(
4068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const WrappedSocketFunction& function)
4078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    : wrapped_function_(function),
4088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      should_block_(false),
4098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      have_result_(false),
4108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      pending_result_(OK) {}
4118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid FakeBlockingStreamSocket::BlockingState::SetShouldBlock() {
4138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  DCHECK(!should_block_);
4148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  should_block_ = true;
4158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid FakeBlockingStreamSocket::BlockingState::Unblock() {
4188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  DCHECK(should_block_);
4198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  should_block_ = false;
4208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // If the operation is still pending in the underlying transport, immediately
4228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // return - OnCompleted() will handle invoking the callback once the transport
4238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // has completed.
4248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  if (!have_result_)
4258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return;
4268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  have_result_ = false;
4288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4295383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com  base::ResetAndReturn(&user_callback_).Run(pending_result_);
4305383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com}
4318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4325383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.comint FakeBlockingStreamSocket::BlockingState::RunWrappedFunction(
4335383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com    IOBuffer* buf,
4345383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com    int len,
4355383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com    const CompletionCallback& callback) {
4368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // The callback to be called by the underlying transport. Either forward
4385383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com  // directly to the user's callback if not set to block, or intercept it with
4398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // OnCompleted so that the user's callback is not invoked until Unblock() is
4408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // called.
4418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  CompletionCallback transport_callback =
4428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      !should_block_ ? callback : base::Bind(&BlockingState::OnCompleted,
4438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                             base::Unretained(this));
4446fc321a18acc8c6437735007240eefe7054e83b0reed@google.com  int rv = wrapped_function_.Run(buf, len, transport_callback);
4456fc321a18acc8c6437735007240eefe7054e83b0reed@google.com  if (should_block_) {
4466fc321a18acc8c6437735007240eefe7054e83b0reed@google.com    user_callback_ = callback;
4476fc321a18acc8c6437735007240eefe7054e83b0reed@google.com    // May have completed synchronously.
4486fc321a18acc8c6437735007240eefe7054e83b0reed@google.com    have_result_ = (rv != ERR_IO_PENDING);
4496fc321a18acc8c6437735007240eefe7054e83b0reed@google.com    pending_result_ = rv;
4506fc321a18acc8c6437735007240eefe7054e83b0reed@google.com    return ERR_IO_PENDING;
4516fc321a18acc8c6437735007240eefe7054e83b0reed@google.com  }
4526fc321a18acc8c6437735007240eefe7054e83b0reed@google.com
4536fc321a18acc8c6437735007240eefe7054e83b0reed@google.com  return rv;
4546fc321a18acc8c6437735007240eefe7054e83b0reed@google.com}
4556fc321a18acc8c6437735007240eefe7054e83b0reed@google.com
4566fc321a18acc8c6437735007240eefe7054e83b0reed@google.comvoid FakeBlockingStreamSocket::BlockingState::OnCompleted(int result) {
4576fc321a18acc8c6437735007240eefe7054e83b0reed@google.com  if (should_block_) {
458945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com    // Store the result so that the callback can be invoked once Unblock() is
459945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com    // called.
4608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    have_result_ = true;
4618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    pending_result_ = result;
4628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return;
4638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
4648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Otherwise, the Unblock() function was called before the underlying
4668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // transport completed, so run the user's callback immediately.
4678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  base::ResetAndReturn(&user_callback_).Run(result);
4688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// CompletionCallback that will delete the associated StreamSocket when
4718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// the callback is invoked.
4728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass DeleteSocketCallback : public TestCompletionCallbackBase {
4738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com public:
4748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  explicit DeleteSocketCallback(StreamSocket* socket)
4758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      : socket_(socket),
4768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        callback_(base::Bind(&DeleteSocketCallback::OnComplete,
4778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                             base::Unretained(this))) {}
4788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  virtual ~DeleteSocketCallback() {}
4798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  const CompletionCallback& callback() const { return callback_; }
4818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com private:
4838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  void OnComplete(int result) {
4848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (socket_) {
4858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      delete socket_;
4868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      socket_ = NULL;
4878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
4888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      ADD_FAILURE() << "Deleting socket twice";
4898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SetResult(result);
4918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
4928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  StreamSocket* socket_;
4948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  CompletionCallback callback_;
4958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  DISALLOW_COPY_AND_ASSIGN(DeleteSocketCallback);
4978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
4988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass SSLClientSocketTest : public PlatformTest {
5008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com public:
5018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  SSLClientSocketTest()
5028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      : socket_factory_(ClientSocketFactory::GetDefaultFactory()),
5038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        cert_verifier_(new MockCertVerifier),
5048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        transport_security_state_(new TransportSecurityState) {
5058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    cert_verifier_->set_default_result(OK);
5068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    context_.cert_verifier = cert_verifier_.get();
5078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    context_.transport_security_state = transport_security_state_.get();
5088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
5098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com protected:
5118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_ptr<SSLClientSocket> CreateSSLClientSocket(
5128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      scoped_ptr<StreamSocket> transport_socket,
5138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      const HostPortPair& host_and_port,
5148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      const SSLConfig& ssl_config) {
5158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
5168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    connection->SetSocket(transport_socket.Pass());
5178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return socket_factory_->CreateSSLClientSocket(
5188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        connection.Pass(), host_and_port, ssl_config, context_);
5198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
5208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ClientSocketFactory* socket_factory_;
5228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_ptr<MockCertVerifier> cert_verifier_;
5238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_ptr<TransportSecurityState> transport_security_state_;
5248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  SSLClientSocketContext context_;
5258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
5268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// Verifies the correctness of GetSSLCertRequestInfo.
5288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass SSLClientSocketCertRequestInfoTest : public SSLClientSocketTest {
5298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com protected:
5308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Creates a test server with the given SSLOptions, connects to it and returns
5318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // the SSLCertRequestInfo reported by the socket.
5328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_refptr<SSLCertRequestInfo> GetCertRequest(
5338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      SpawnedTestServer::SSLOptions ssl_options) {
5348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SpawnedTestServer test_server(
5358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SpawnedTestServer::TYPE_HTTPS, ssl_options, base::FilePath());
5368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (!test_server.Start())
5378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      return NULL;
5388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    AddressList addr;
5408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (!test_server.GetAddressList(&addr))
5418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      return NULL;
5428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    TestCompletionCallback callback;
5448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    CapturingNetLog log;
5458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    scoped_ptr<StreamSocket> transport(
5468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        new TCPClientSocket(addr, &log, NetLog::Source()));
5478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int rv = transport->Connect(callback.callback());
5488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (rv == ERR_IO_PENDING)
5498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      rv = callback.WaitForResult();
5508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    EXPECT_EQ(OK, rv);
5518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
5538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        transport.Pass(), test_server.host_port_pair(), kDefaultSSLConfig));
5548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    EXPECT_FALSE(sock->IsConnected());
5558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    rv = sock->Connect(callback.callback());
5578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (rv == ERR_IO_PENDING)
5588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      rv = callback.WaitForResult();
5598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    scoped_refptr<SSLCertRequestInfo> request_info = new SSLCertRequestInfo();
5608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    sock->GetSSLCertRequestInfo(request_info.get());
5618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    sock->Disconnect();
5628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    EXPECT_FALSE(sock->IsConnected());
5638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return request_info;
5658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
5668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
5678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//-----------------------------------------------------------------------------
5698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// LogContainsSSLConnectEndEvent returns true if the given index in the given
5718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// log is an SSL connect end event. The NSS sockets will cork in an attempt to
5728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// merge the first application data record with the Finished message when false
5738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// starting. However, in order to avoid the server timing out the handshake,
5748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// they'll give up waiting for application data and send the Finished after a
5758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// timeout. This means that an SSL connect end event may appear as a socket
5768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// write.
5778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic bool LogContainsSSLConnectEndEvent(
5788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const CapturingNetLog::CapturedEntryList& log,
5798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int i) {
5808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  return LogContainsEndEvent(log, i, NetLog::TYPE_SSL_CONNECT) ||
5818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com         LogContainsEvent(
5828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com             log, i, NetLog::TYPE_SOCKET_BYTES_SENT, NetLog::PHASE_NONE);
5838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}  // namespace
5868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comTEST_F(SSLClientSocketTest, Connect) {
5888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
5898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                SpawnedTestServer::kLocalhost,
5908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                base::FilePath());
5918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ASSERT_TRUE(test_server.Start());
5928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  AddressList addr;
5948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ASSERT_TRUE(test_server.GetAddressList(&addr));
595a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com
596fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com  TestCompletionCallback callback;
597a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com  CapturingNetLog log;
598a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com  scoped_ptr<StreamSocket> transport(
599a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com      new TCPClientSocket(addr, &log, NetLog::Source()));
600a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com  int rv = transport->Connect(callback.callback());
601a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com  if (rv == ERR_IO_PENDING)
602a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com    rv = callback.WaitForResult();
603a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com  EXPECT_EQ(OK, rv);
604a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com
605a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
606a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com      transport.Pass(), test_server.host_port_pair(), kDefaultSSLConfig));
607a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com
608a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com  EXPECT_FALSE(sock->IsConnected());
609a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com
610a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com  rv = sock->Connect(callback.callback());
611a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com
612a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com  CapturingNetLog::CapturedEntryList entries;
613a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com  log.GetEntries(&entries);
614a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com  EXPECT_TRUE(LogContainsBeginEvent(entries, 5, NetLog::TYPE_SSL_CONNECT));
615a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com  if (rv == ERR_IO_PENDING)
616a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com    rv = callback.WaitForResult();
617a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com  EXPECT_EQ(OK, rv);
6188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_TRUE(sock->IsConnected());
6198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  log.GetEntries(&entries);
6208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_TRUE(LogContainsSSLConnectEndEvent(entries, -1));
6218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  sock->Disconnect();
6238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_FALSE(sock->IsConnected());
6248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comTEST_F(SSLClientSocketTest, ConnectExpired) {
6278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  SpawnedTestServer::SSLOptions ssl_options(
6288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      SpawnedTestServer::SSLOptions::CERT_EXPIRED);
6298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  SpawnedTestServer test_server(
6308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      SpawnedTestServer::TYPE_HTTPS, ssl_options, base::FilePath());
6318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ASSERT_TRUE(test_server.Start());
6328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  cert_verifier_->set_default_result(ERR_CERT_DATE_INVALID);
6348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  AddressList addr;
6368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ASSERT_TRUE(test_server.GetAddressList(&addr));
6378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  TestCompletionCallback callback;
6398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  CapturingNetLog log;
6408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_ptr<StreamSocket> transport(
6418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      new TCPClientSocket(addr, &log, NetLog::Source()));
6428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  int rv = transport->Connect(callback.callback());
6438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  if (rv == ERR_IO_PENDING)
6448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    rv = callback.WaitForResult();
6458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(OK, rv);
6468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
647a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
6488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      transport.Pass(), test_server.host_port_pair(), kDefaultSSLConfig));
6498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
650a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com  EXPECT_FALSE(sock->IsConnected());
651a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com
652a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com  rv = sock->Connect(callback.callback());
653a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com
654a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com  CapturingNetLog::CapturedEntryList entries;
655a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com  log.GetEntries(&entries);
656a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com  EXPECT_TRUE(LogContainsBeginEvent(entries, 5, NetLog::TYPE_SSL_CONNECT));
657a964028843ec3f69b3b2e556426ff881d1fcb4b2reed@android.com  if (rv == ERR_IO_PENDING)
6588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    rv = callback.WaitForResult();
6598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(ERR_CERT_DATE_INVALID, rv);
6618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Rather than testing whether or not the underlying socket is connected,
6638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // test that the handshake has finished. This is because it may be
6648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // desirable to disconnect the socket before showing a user prompt, since
6658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // the user may take indefinitely long to respond.
6668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  log.GetEntries(&entries);
6678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_TRUE(LogContainsSSLConnectEndEvent(entries, -1));
6688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comTEST_F(SSLClientSocketTest, ConnectMismatched) {
6718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  SpawnedTestServer::SSLOptions ssl_options(
6728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      SpawnedTestServer::SSLOptions::CERT_MISMATCHED_NAME);
6738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  SpawnedTestServer test_server(
6748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      SpawnedTestServer::TYPE_HTTPS, ssl_options, base::FilePath());
6758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ASSERT_TRUE(test_server.Start());
6768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  cert_verifier_->set_default_result(ERR_CERT_COMMON_NAME_INVALID);
6788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  AddressList addr;
6808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ASSERT_TRUE(test_server.GetAddressList(&addr));
6818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  TestCompletionCallback callback;
6838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  CapturingNetLog log;
6848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_ptr<StreamSocket> transport(
6858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      new TCPClientSocket(addr, &log, NetLog::Source()));
6868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  int rv = transport->Connect(callback.callback());
6878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  if (rv == ERR_IO_PENDING)
6888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    rv = callback.WaitForResult();
6898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(OK, rv);
6908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
6928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      transport.Pass(), test_server.host_port_pair(), kDefaultSSLConfig));
6938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_FALSE(sock->IsConnected());
6958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  rv = sock->Connect(callback.callback());
6978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  CapturingNetLog::CapturedEntryList entries;
699bb13586591bd412a0372aeb85d44159d2fa3f947reed@android.com  log.GetEntries(&entries);
7008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_TRUE(LogContainsBeginEvent(entries, 5, NetLog::TYPE_SSL_CONNECT));
701bb13586591bd412a0372aeb85d44159d2fa3f947reed@android.com  if (rv == ERR_IO_PENDING)
702bb13586591bd412a0372aeb85d44159d2fa3f947reed@android.com    rv = callback.WaitForResult();
703fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
7048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(ERR_CERT_COMMON_NAME_INVALID, rv);
705bb13586591bd412a0372aeb85d44159d2fa3f947reed@android.com
7068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Rather than testing whether or not the underlying socket is connected,
7078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // test that the handshake has finished. This is because it may be
708bb13586591bd412a0372aeb85d44159d2fa3f947reed@android.com  // desirable to disconnect the socket before showing a user prompt, since
7098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // the user may take indefinitely long to respond.
710bb13586591bd412a0372aeb85d44159d2fa3f947reed@android.com  log.GetEntries(&entries);
711bb13586591bd412a0372aeb85d44159d2fa3f947reed@android.com  EXPECT_TRUE(LogContainsSSLConnectEndEvent(entries, -1));
712bb13586591bd412a0372aeb85d44159d2fa3f947reed@android.com}
713bb13586591bd412a0372aeb85d44159d2fa3f947reed@android.com
714bb13586591bd412a0372aeb85d44159d2fa3f947reed@android.com// Attempt to connect to a page which requests a client certificate. It should
715bb13586591bd412a0372aeb85d44159d2fa3f947reed@android.com// return an error code on connect.
716bb13586591bd412a0372aeb85d44159d2fa3f947reed@android.comTEST_F(SSLClientSocketTest, ConnectClientAuthCertRequested) {
717bb13586591bd412a0372aeb85d44159d2fa3f947reed@android.com  SpawnedTestServer::SSLOptions ssl_options;
718bb13586591bd412a0372aeb85d44159d2fa3f947reed@android.com  ssl_options.request_client_certificate = true;
719fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com  SpawnedTestServer test_server(
720bb13586591bd412a0372aeb85d44159d2fa3f947reed@android.com      SpawnedTestServer::TYPE_HTTPS, ssl_options, base::FilePath());
721bb13586591bd412a0372aeb85d44159d2fa3f947reed@android.com  ASSERT_TRUE(test_server.Start());
722bb13586591bd412a0372aeb85d44159d2fa3f947reed@android.com
723bb13586591bd412a0372aeb85d44159d2fa3f947reed@android.com  AddressList addr;
724bb13586591bd412a0372aeb85d44159d2fa3f947reed@android.com  ASSERT_TRUE(test_server.GetAddressList(&addr));
725bb13586591bd412a0372aeb85d44159d2fa3f947reed@android.com
726bb13586591bd412a0372aeb85d44159d2fa3f947reed@android.com  TestCompletionCallback callback;
7278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  CapturingNetLog log;
7288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_ptr<StreamSocket> transport(
7298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      new TCPClientSocket(addr, &log, NetLog::Source()));
7308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  int rv = transport->Connect(callback.callback());
7318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  if (rv == ERR_IO_PENDING)
7328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    rv = callback.WaitForResult();
7338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(OK, rv);
7348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
7368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      transport.Pass(), test_server.host_port_pair(), kDefaultSSLConfig));
7378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_FALSE(sock->IsConnected());
7398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  rv = sock->Connect(callback.callback());
7418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  CapturingNetLog::CapturedEntryList entries;
7438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  log.GetEntries(&entries);
7448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_TRUE(LogContainsBeginEvent(entries, 5, NetLog::TYPE_SSL_CONNECT));
7458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  if (rv == ERR_IO_PENDING)
7468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    rv = callback.WaitForResult();
7478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  log.GetEntries(&entries);
7498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Because we prematurely kill the handshake at CertificateRequest,
7508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // the server may still send data (notably the ServerHelloDone)
7518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // after the error is returned. As a result, the SSL_CONNECT may not
7528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // be the last entry. See http://crbug.com/54445. We use
7538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // ExpectLogContainsSomewhere instead of
7548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // LogContainsSSLConnectEndEvent to avoid assuming, e.g., only one
7558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // extra read instead of two. This occurs before the handshake ends,
7568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // so the corking logic of LogContainsSSLConnectEndEvent isn't
7578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // necessary.
7588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  //
7598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // TODO(davidben): When SSL_RestartHandshakeAfterCertReq in NSS is
7608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // fixed and we can respond to the first CertificateRequest
7618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // without closing the socket, add a unit test for sending the
7628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // certificate. This test may still be useful as we'll want to close
7638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // the socket on a timeout if the user takes a long time to pick a
7648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // cert. Related bug: https://bugzilla.mozilla.org/show_bug.cgi?id=542832
7658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ExpectLogContainsSomewhere(
7668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      entries, 0, NetLog::TYPE_SSL_CONNECT, NetLog::PHASE_END);
7678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv);
7688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_FALSE(sock->IsConnected());
7698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
7708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// Connect to a server requesting optional client authentication. Send it a
7728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// null certificate. It should allow the connection.
7738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//
7748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// TODO(davidben): Also test providing an actual certificate.
7758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comTEST_F(SSLClientSocketTest, ConnectClientAuthSendNullCert) {
7768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  SpawnedTestServer::SSLOptions ssl_options;
7778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ssl_options.request_client_certificate = true;
7788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  SpawnedTestServer test_server(
7798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      SpawnedTestServer::TYPE_HTTPS, ssl_options, base::FilePath());
7808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ASSERT_TRUE(test_server.Start());
7818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  AddressList addr;
7838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ASSERT_TRUE(test_server.GetAddressList(&addr));
7848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  TestCompletionCallback callback;
7868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  CapturingNetLog log;
7878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_ptr<StreamSocket> transport(
7888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      new TCPClientSocket(addr, &log, NetLog::Source()));
7898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  int rv = transport->Connect(callback.callback());
7908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  if (rv == ERR_IO_PENDING)
7918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    rv = callback.WaitForResult();
7928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(OK, rv);
7938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  SSLConfig ssl_config = kDefaultSSLConfig;
7958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ssl_config.send_client_cert = true;
7968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ssl_config.client_cert = NULL;
7978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
7998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      transport.Pass(), test_server.host_port_pair(), ssl_config));
8008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_FALSE(sock->IsConnected());
8028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Our test server accepts certificate-less connections.
8048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // TODO(davidben): Add a test which requires them and verify the error.
8058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  rv = sock->Connect(callback.callback());
8068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  CapturingNetLog::CapturedEntryList entries;
8088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  log.GetEntries(&entries);
8098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_TRUE(LogContainsBeginEvent(entries, 5, NetLog::TYPE_SSL_CONNECT));
8108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  if (rv == ERR_IO_PENDING)
8118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    rv = callback.WaitForResult();
8128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(OK, rv);
8148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_TRUE(sock->IsConnected());
8158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  log.GetEntries(&entries);
8168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_TRUE(LogContainsSSLConnectEndEvent(entries, -1));
8178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // We responded to the server's certificate request with a Certificate
8198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // message with no client certificate in it.  ssl_info.client_cert_sent
8208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // should be false in this case.
8218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  SSLInfo ssl_info;
8228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  sock->GetSSLInfo(&ssl_info);
8238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_FALSE(ssl_info.client_cert_sent);
8248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  sock->Disconnect();
8268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_FALSE(sock->IsConnected());
8278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// TODO(wtc): Add unit tests for IsConnectedAndIdle:
8308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//   - Server closes an SSL connection (with a close_notify alert message).
8318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//   - Server closes the underlying TCP connection directly.
8328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//   - Server sends data unexpectedly.
8338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comTEST_F(SSLClientSocketTest, Read) {
8358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
8368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                SpawnedTestServer::kLocalhost,
8378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                base::FilePath());
838087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  ASSERT_TRUE(test_server.Start());
839087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com
840087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  AddressList addr;
841087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  ASSERT_TRUE(test_server.GetAddressList(&addr));
842087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com
843087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  TestCompletionCallback callback;
844087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  scoped_ptr<StreamSocket> transport(
845087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com      new TCPClientSocket(addr, NULL, NetLog::Source()));
846087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  int rv = transport->Connect(callback.callback());
847087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  if (rv == ERR_IO_PENDING)
848087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com    rv = callback.WaitForResult();
849087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  EXPECT_EQ(OK, rv);
850087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com
851087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
852087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com      transport.Pass(), test_server.host_port_pair(), kDefaultSSLConfig));
853087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com
854087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  rv = sock->Connect(callback.callback());
855087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  if (rv == ERR_IO_PENDING)
856087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com    rv = callback.WaitForResult();
857087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  EXPECT_EQ(OK, rv);
858087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  EXPECT_TRUE(sock->IsConnected());
859087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com
860087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
861087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  scoped_refptr<IOBuffer> request_buffer(
862087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com      new IOBuffer(arraysize(request_text) - 1));
863087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
864087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com
865087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  rv = sock->Write(
866087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com      request_buffer.get(), arraysize(request_text) - 1, callback.callback());
867087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  EXPECT_TRUE(rv >= 0 || rv == ERR_IO_PENDING);
868087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com
869087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  if (rv == ERR_IO_PENDING)
870087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com    rv = callback.WaitForResult();
871087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  EXPECT_EQ(static_cast<int>(arraysize(request_text) - 1), rv);
872087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com
873087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  scoped_refptr<IOBuffer> buf(new IOBuffer(4096));
874087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  for (;;) {
875087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com    rv = sock->Read(buf.get(), 4096, callback.callback());
876087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com    EXPECT_TRUE(rv >= 0 || rv == ERR_IO_PENDING);
877087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com
878087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com    if (rv == ERR_IO_PENDING)
879087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com      rv = callback.WaitForResult();
880087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com
881087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com    EXPECT_GE(rv, 0);
882087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com    if (rv <= 0)
883087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com      break;
884087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  }
885087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com}
886087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com
887087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com// Tests that the SSLClientSocket properly handles when the underlying transport
888087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com// synchronously returns an error code - such as if an intermediary terminates
889087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com// the socket connection uncleanly.
890087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com// This is a regression test for http://crbug.com/238536
891087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.comTEST_F(SSLClientSocketTest, Read_WithSynchronousError) {
892087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
893087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com                                SpawnedTestServer::kLocalhost,
894087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com                                base::FilePath());
895087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  ASSERT_TRUE(test_server.Start());
8968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  AddressList addr;
8988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ASSERT_TRUE(test_server.GetAddressList(&addr));
8998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  TestCompletionCallback callback;
9018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_ptr<StreamSocket> real_transport(
9028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      new TCPClientSocket(addr, NULL, NetLog::Source()));
903fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com  scoped_ptr<SynchronousErrorStreamSocket> transport(
904087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com      new SynchronousErrorStreamSocket(real_transport.Pass()));
905087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  int rv = callback.GetResult(transport->Connect(callback.callback()));
9068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(OK, rv);
9078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Disable TLS False Start to avoid handshake non-determinism.
9098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  SSLConfig ssl_config;
9108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ssl_config.false_start_enabled = false;
9118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  SynchronousErrorStreamSocket* raw_transport = transport.get();
9138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_ptr<SSLClientSocket> sock(
9148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      CreateSSLClientSocket(transport.PassAs<StreamSocket>(),
9158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            test_server.host_port_pair(),
9168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            ssl_config));
9178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  rv = callback.GetResult(sock->Connect(callback.callback()));
9198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(OK, rv);
9208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_TRUE(sock->IsConnected());
9218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
9238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  static const int kRequestTextSize =
9248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      static_cast<int>(arraysize(request_text) - 1);
9258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_refptr<IOBuffer> request_buffer(new IOBuffer(kRequestTextSize));
9268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  memcpy(request_buffer->data(), request_text, kRequestTextSize);
9278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  rv = callback.GetResult(
9298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      sock->Write(request_buffer.get(), kRequestTextSize, callback.callback()));
9308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(kRequestTextSize, rv);
9318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Simulate an unclean/forcible shutdown.
9338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  raw_transport->SetNextReadError(ERR_CONNECTION_RESET);
9348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_refptr<IOBuffer> buf(new IOBuffer(4096));
9368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Note: This test will hang if this bug has regressed. Simply checking that
9388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // rv != ERR_IO_PENDING is insufficient, as ERR_IO_PENDING is a legitimate
9398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // result when using a dedicated task runner for NSS.
9408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  rv = callback.GetResult(sock->Read(buf.get(), 4096, callback.callback()));
9418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#if !defined(USE_OPENSSL)
9438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // SSLClientSocketNSS records the error exactly
9448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(ERR_CONNECTION_RESET, rv);
9458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#else
9468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // SSLClientSocketOpenSSL treats any errors as a simple EOF.
9478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(0, rv);
9488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
9498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
9508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// Tests that the SSLClientSocket properly handles when the underlying transport
9528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// asynchronously returns an error code while writing data - such as if an
9538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// intermediary terminates the socket connection uncleanly.
9548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// This is a regression test for http://crbug.com/249848
9558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comTEST_F(SSLClientSocketTest, Write_WithSynchronousError) {
9568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
9578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                SpawnedTestServer::kLocalhost,
9588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                base::FilePath());
9598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ASSERT_TRUE(test_server.Start());
960087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com
961087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  AddressList addr;
9628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ASSERT_TRUE(test_server.GetAddressList(&addr));
963087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com
964087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  TestCompletionCallback callback;
965087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  scoped_ptr<StreamSocket> real_transport(
966087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com      new TCPClientSocket(addr, NULL, NetLog::Source()));
967087d5aafb18b88dfc6c6a5dbf59160c8be914e62reed@google.com  // Note: |error_socket|'s ownership is handed to |transport|, but a pointer
9688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // is retained in order to configure additional errors.
9698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_ptr<SynchronousErrorStreamSocket> error_socket(
9708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      new SynchronousErrorStreamSocket(real_transport.Pass()));
9718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  SynchronousErrorStreamSocket* raw_error_socket = error_socket.get();
9728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_ptr<FakeBlockingStreamSocket> transport(
9738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      new FakeBlockingStreamSocket(error_socket.PassAs<StreamSocket>()));
9748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  FakeBlockingStreamSocket* raw_transport = transport.get();
9758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  int rv = callback.GetResult(transport->Connect(callback.callback()));
9768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(OK, rv);
9778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Disable TLS False Start to avoid handshake non-determinism.
9798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  SSLConfig ssl_config;
9808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ssl_config.false_start_enabled = false;
9818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_ptr<SSLClientSocket> sock(
9838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      CreateSSLClientSocket(transport.PassAs<StreamSocket>(),
9848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            test_server.host_port_pair(),
9858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            ssl_config));
9868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  rv = callback.GetResult(sock->Connect(callback.callback()));
988fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com  EXPECT_EQ(OK, rv);
9898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_TRUE(sock->IsConnected());
9908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
9928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  static const int kRequestTextSize =
9938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      static_cast<int>(arraysize(request_text) - 1);
9948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_refptr<IOBuffer> request_buffer(new IOBuffer(kRequestTextSize));
9958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  memcpy(request_buffer->data(), request_text, kRequestTextSize);
9968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Simulate an unclean/forcible shutdown on the underlying socket.
9988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // However, simulate this error asynchronously.
9998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  raw_error_socket->SetNextWriteError(ERR_CONNECTION_RESET);
10008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  raw_transport->SetNextWriteShouldBlock();
10018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // This write should complete synchronously, because the TLS ciphertext
10038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // can be created and placed into the outgoing buffers independent of the
10048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // underlying transport.
10058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  rv = callback.GetResult(
10068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      sock->Write(request_buffer.get(), kRequestTextSize, callback.callback()));
10078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(kRequestTextSize, rv);
10088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_refptr<IOBuffer> buf(new IOBuffer(4096));
10108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  rv = sock->Read(buf.get(), 4096, callback.callback());
10128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(ERR_IO_PENDING, rv);
10138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Now unblock the outgoing request, having it fail with the connection
10158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // being reset.
10168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  raw_transport->UnblockWrite();
10178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Note: This will cause an inifite loop if this bug has regressed. Simply
10198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // checking that rv != ERR_IO_PENDING is insufficient, as ERR_IO_PENDING
1020fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com  // is a legitimate result when using a dedicated task runner for NSS.
10218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  rv = callback.GetResult(rv);
10228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#if !defined(USE_OPENSSL)
10248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // SSLClientSocketNSS records the error exactly
10258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(ERR_CONNECTION_RESET, rv);
10268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#else
10278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // SSLClientSocketOpenSSL treats any errors as a simple EOF.
10288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(0, rv);
10298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
10308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
10318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// Test the full duplex mode, with Read and Write pending at the same time.
10338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// This test also serves as a regression test for http://crbug.com/29815.
10348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comTEST_F(SSLClientSocketTest, Read_FullDuplex) {
10358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
10368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                SpawnedTestServer::kLocalhost,
10378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                base::FilePath());
10388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ASSERT_TRUE(test_server.Start());
10398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  AddressList addr;
10418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ASSERT_TRUE(test_server.GetAddressList(&addr));
10428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  TestCompletionCallback callback;  // Used for everything except Write.
10448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_ptr<StreamSocket> transport(
10468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      new TCPClientSocket(addr, NULL, NetLog::Source()));
10478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  int rv = transport->Connect(callback.callback());
10488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  if (rv == ERR_IO_PENDING)
10498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    rv = callback.WaitForResult();
10508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(OK, rv);
10518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
10538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      transport.Pass(), test_server.host_port_pair(), kDefaultSSLConfig));
10548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  rv = sock->Connect(callback.callback());
10568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  if (rv == ERR_IO_PENDING)
10578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    rv = callback.WaitForResult();
10588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(OK, rv);
10598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_TRUE(sock->IsConnected());
10608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Issue a "hanging" Read first.
10628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_refptr<IOBuffer> buf(new IOBuffer(4096));
10638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  rv = sock->Read(buf.get(), 4096, callback.callback());
10648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // We haven't written the request, so there should be no response yet.
10655383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com  ASSERT_EQ(ERR_IO_PENDING, rv);
10668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Write the request.
10688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // The request is padded with a User-Agent header to a size that causes the
10698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // memio circular buffer (4k bytes) in SSLClientSocketNSS to wrap around.
10708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // This tests the fix for http://crbug.com/29815.
10718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  std::string request_text = "GET / HTTP/1.1\r\nUser-Agent: long browser name ";
10728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  for (int i = 0; i < 3770; ++i)
10738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    request_text.push_back('*');
10742e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  request_text.append("\r\n\r\n");
10752e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  scoped_refptr<IOBuffer> request_buffer(new StringIOBuffer(request_text));
10762e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org
10772e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  TestCompletionCallback callback2;  // Used for Write only.
10782e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  rv = sock->Write(
1079945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com      request_buffer.get(), request_text.size(), callback2.callback());
1080945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  EXPECT_TRUE(rv >= 0 || rv == ERR_IO_PENDING);
1081945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com
1082945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  if (rv == ERR_IO_PENDING)
1083945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com    rv = callback2.WaitForResult();
1084945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  EXPECT_EQ(static_cast<int>(request_text.size()), rv);
1085945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com
1086945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  // Now get the Read result.
1087945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  rv = callback.WaitForResult();
10882e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  EXPECT_GT(rv, 0);
10892e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org}
10902e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org
1091945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com// Attempts to Read() and Write() from an SSLClientSocketNSS in full duplex
1092945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com// mode when the underlying transport is blocked on sending data. When the
1093945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com// underlying transport completes due to an error, it should invoke both the
10942e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org// Read() and Write() callbacks. If the socket is deleted by the Read()
10952e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org// callback, the Write() callback should not be invoked.
1096945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com// Regression test for http://crbug.com/232633
1097945a139553a9c9da03766213661d7f5fd6ed3042reed@android.comTEST_F(SSLClientSocketTest, Read_DeleteWhilePendingFullDuplex) {
1098945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
1099945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com                                SpawnedTestServer::kLocalhost,
1100945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com                                base::FilePath());
1101945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  ASSERT_TRUE(test_server.Start());
1102945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com
1103945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  AddressList addr;
11042e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  ASSERT_TRUE(test_server.GetAddressList(&addr));
11052e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org
11062e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  TestCompletionCallback callback;
1107945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  scoped_ptr<StreamSocket> real_transport(
1108945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com      new TCPClientSocket(addr, NULL, NetLog::Source()));
1109945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  // Note: |error_socket|'s ownership is handed to |transport|, but a pointer
1110945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  // is retained in order to configure additional errors.
1111945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  scoped_ptr<SynchronousErrorStreamSocket> error_socket(
1112945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com      new SynchronousErrorStreamSocket(real_transport.Pass()));
1113945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  SynchronousErrorStreamSocket* raw_error_socket = error_socket.get();
1114945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  scoped_ptr<FakeBlockingStreamSocket> transport(
1115945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com      new FakeBlockingStreamSocket(error_socket.PassAs<StreamSocket>()));
1116945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  FakeBlockingStreamSocket* raw_transport = transport.get();
1117945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com
1118945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  int rv = callback.GetResult(transport->Connect(callback.callback()));
1119945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  EXPECT_EQ(OK, rv);
1120945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com
1121945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  // Disable TLS False Start to avoid handshake non-determinism.
1122945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  SSLConfig ssl_config;
1123945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  ssl_config.false_start_enabled = false;
1124945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com
1125945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  scoped_ptr<SSLClientSocket> sock =
1126945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com      CreateSSLClientSocket(transport.PassAs<StreamSocket>(),
1127945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com                            test_server.host_port_pair(),
1128945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com                            ssl_config);
1129945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com
1130945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  rv = callback.GetResult(sock->Connect(callback.callback()));
1131945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  EXPECT_EQ(OK, rv);
1132945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  EXPECT_TRUE(sock->IsConnected());
1133945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com
1134945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  std::string request_text = "GET / HTTP/1.1\r\nUser-Agent: long browser name ";
1135945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  request_text.append(20 * 1024, '*');
1136945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  request_text.append("\r\n\r\n");
1137945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  scoped_refptr<DrainableIOBuffer> request_buffer(new DrainableIOBuffer(
1138945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com      new StringIOBuffer(request_text), request_text.size()));
1139945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com
1140945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  // Simulate errors being returned from the underlying Read() and Write() ...
1141945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  raw_error_socket->SetNextReadError(ERR_CONNECTION_RESET);
1142945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  raw_error_socket->SetNextWriteError(ERR_CONNECTION_RESET);
1143945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  // ... but have those errors returned asynchronously. Because the Write() will
1144945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  // return first, this will trigger the error.
1145945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  raw_transport->SetNextReadShouldBlock();
1146945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  raw_transport->SetNextWriteShouldBlock();
1147945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com
1148945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  // Enqueue a Read() before calling Write(), which should "hang" due to
1149945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  // the ERR_IO_PENDING caused by SetReadShouldBlock() and thus return.
1150945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  SSLClientSocket* raw_sock = sock.get();
1151945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  DeleteSocketCallback read_callback(sock.release());
1152945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  scoped_refptr<IOBuffer> read_buf(new IOBuffer(4096));
11532e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  rv = raw_sock->Read(read_buf.get(), 4096, read_callback.callback());
11542e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org
11552e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  // Ensure things didn't complete synchronously, otherwise |sock| is invalid.
1156945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  ASSERT_EQ(ERR_IO_PENDING, rv);
1157945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  ASSERT_FALSE(read_callback.have_result());
1158945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com
1159945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com#if !defined(USE_OPENSSL)
1160945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  // NSS follows a pattern where a call to PR_Write will only consume as
11612e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  // much data as it can encode into application data records before the
1162945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  // internal memio buffer is full, which should only fill if writing a large
1163945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  // amount of data and the underlying transport is blocked. Once this happens,
1164945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  // NSS will return (total size of all application data records it wrote) - 1,
11652e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  // with the caller expected to resume with the remaining unsent data.
11662e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  //
11672e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  // This causes SSLClientSocketNSS::Write to return that it wrote some data
11682e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  // before it will return ERR_IO_PENDING, so make an extra call to Write() to
11692e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  // get the socket in the state needed for the test below.
1170945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  //
11712e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  // This is not needed for OpenSSL, because for OpenSSL,
11722e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  // SSL_MODE_ENABLE_PARTIAL_WRITE is not specified - thus
11732e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  // SSLClientSocketOpenSSL::Write() will not return until all of
1174945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  // |request_buffer| has been written to the underlying BIO (although not
11752e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  // necessarily the underlying transport).
1176945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  rv = callback.GetResult(raw_sock->Write(request_buffer.get(),
11772e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org                                          request_buffer->BytesRemaining(),
11782e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org                                          callback.callback()));
11792e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  ASSERT_LT(0, rv);
1180945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  request_buffer->DidConsume(rv);
11812e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org
1182945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com  // Guard to ensure that |request_buffer| was larger than all of the internal
11832e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  // buffers (transport, memio, NSS) along the way - otherwise the next call
11842e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  // to Write() will crash with an invalid buffer.
11852e086190e55a01dc2f7b74df6f2828e8cac2b9abkbr@chromium.org  ASSERT_LT(0, request_buffer->BytesRemaining());
1186945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com#endif
1187945a139553a9c9da03766213661d7f5fd6ed3042reed@android.com
11888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Attempt to write the remaining data. NSS will not be able to consume the
11898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // application data because the internal buffers are full, while OpenSSL will
11908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // return that its blocked because the underlying transport is blocked.
11918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  rv = raw_sock->Write(request_buffer.get(),
11928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                       request_buffer->BytesRemaining(),
11938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                       callback.callback());
11948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ASSERT_EQ(ERR_IO_PENDING, rv);
11958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ASSERT_FALSE(callback.have_result());
11968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Now unblock Write(), which will invoke OnSendComplete and (eventually)
11988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // call the Read() callback, deleting the socket and thus aborting calling
11998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // the Write() callback.
12008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  raw_transport->UnblockWrite();
12018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  rv = read_callback.WaitForResult();
12038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#if !defined(USE_OPENSSL)
12058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // NSS records the error exactly.
12068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(ERR_CONNECTION_RESET, rv);
1207e1b75b4096c8ba9a569ae33d580806edd3c4a97arobertphillips@google.com#else
1208b0889a5aa610552bf306edc8d9a35d2d601acdb9robertphillips@google.com  // OpenSSL treats any errors as a simple EOF.
12099e1ec1a52985cce9db3a0d0e8d448b82a32e70cbskia.committer@gmail.com  EXPECT_EQ(0, rv);
1210e1b75b4096c8ba9a569ae33d580806edd3c4a97arobertphillips@google.com#endif
12118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1212e1b75b4096c8ba9a569ae33d580806edd3c4a97arobertphillips@google.com  // The Write callback should not have been called.
12138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_FALSE(callback.have_result());
12148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
12158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// Tests that the SSLClientSocket does not crash if data is received on the
12178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// transport socket after a failing write. This can occur if we have a Write
12188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// error in a SPDY socket.
12198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// Regression test for http://crbug.com/335557
12208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comTEST_F(SSLClientSocketTest, Read_WithWriteError) {
12218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
12228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                SpawnedTestServer::kLocalhost,
12238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                base::FilePath());
12248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ASSERT_TRUE(test_server.Start());
12258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  AddressList addr;
12278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ASSERT_TRUE(test_server.GetAddressList(&addr));
12288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  TestCompletionCallback callback;
12308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_ptr<StreamSocket> real_transport(
12318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      new TCPClientSocket(addr, NULL, NetLog::Source()));
12328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Note: |error_socket|'s ownership is handed to |transport|, but a pointer
1233e1b75b4096c8ba9a569ae33d580806edd3c4a97arobertphillips@google.com  // is retained in order to configure additional errors.
1234b0889a5aa610552bf306edc8d9a35d2d601acdb9robertphillips@google.com  scoped_ptr<SynchronousErrorStreamSocket> error_socket(
12358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      new SynchronousErrorStreamSocket(real_transport.Pass()));
12368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  SynchronousErrorStreamSocket* raw_error_socket = error_socket.get();
12378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_ptr<FakeBlockingStreamSocket> transport(
12388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      new FakeBlockingStreamSocket(error_socket.PassAs<StreamSocket>()));
12398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  FakeBlockingStreamSocket* raw_transport = transport.get();
12408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  int rv = callback.GetResult(transport->Connect(callback.callback()));
1242fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com  EXPECT_EQ(OK, rv);
12438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Disable TLS False Start to avoid handshake non-determinism.
12458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  SSLConfig ssl_config;
12468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ssl_config.false_start_enabled = false;
12478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_ptr<SSLClientSocket> sock(
12498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      CreateSSLClientSocket(transport.PassAs<StreamSocket>(),
12508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            test_server.host_port_pair(),
1251e1b75b4096c8ba9a569ae33d580806edd3c4a97arobertphillips@google.com                            ssl_config));
1252e1b75b4096c8ba9a569ae33d580806edd3c4a97arobertphillips@google.com
12538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  rv = callback.GetResult(sock->Connect(callback.callback()));
12548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(OK, rv);
12558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_TRUE(sock->IsConnected());
12568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Send a request so there is something to read from the socket.
12588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
1259b95eaa8d0842a8bba97f0bc7e19cfd9172d09722robertphillips@google.com  static const int kRequestTextSize =
1260dff53c26e7ef80da4767433ecfe17741a059e247reed@google.com      static_cast<int>(arraysize(request_text) - 1);
1261b95eaa8d0842a8bba97f0bc7e19cfd9172d09722robertphillips@google.com  scoped_refptr<IOBuffer> request_buffer(new IOBuffer(kRequestTextSize));
1262b0889a5aa610552bf306edc8d9a35d2d601acdb9robertphillips@google.com  memcpy(request_buffer->data(), request_text, kRequestTextSize);
1263b0889a5aa610552bf306edc8d9a35d2d601acdb9robertphillips@google.com
1264b0889a5aa610552bf306edc8d9a35d2d601acdb9robertphillips@google.com  rv = callback.GetResult(
1265b0889a5aa610552bf306edc8d9a35d2d601acdb9robertphillips@google.com      sock->Write(request_buffer.get(), kRequestTextSize, callback.callback()));
1266b0889a5aa610552bf306edc8d9a35d2d601acdb9robertphillips@google.com  EXPECT_EQ(kRequestTextSize, rv);
1267b0889a5aa610552bf306edc8d9a35d2d601acdb9robertphillips@google.com
1268b0889a5aa610552bf306edc8d9a35d2d601acdb9robertphillips@google.com  // Start a hanging read.
1269c7a37c7bb2279d8c15d6fcbaf38f59dbd727eb6crobertphillips@google.com  TestCompletionCallback read_callback;
1270b0889a5aa610552bf306edc8d9a35d2d601acdb9robertphillips@google.com  raw_transport->SetNextReadShouldBlock();
1271b95eaa8d0842a8bba97f0bc7e19cfd9172d09722robertphillips@google.com  scoped_refptr<IOBuffer> buf(new IOBuffer(4096));
1272b95eaa8d0842a8bba97f0bc7e19cfd9172d09722robertphillips@google.com  rv = sock->Read(buf.get(), 4096, read_callback.callback());
1273b95eaa8d0842a8bba97f0bc7e19cfd9172d09722robertphillips@google.com  EXPECT_EQ(ERR_IO_PENDING, rv);
12748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1275b95eaa8d0842a8bba97f0bc7e19cfd9172d09722robertphillips@google.com  // Perform another write, but have it fail. Write a request larger than the
1276b0889a5aa610552bf306edc8d9a35d2d601acdb9robertphillips@google.com  // internal socket buffers so that the request hits the underlying transport
1277b0889a5aa610552bf306edc8d9a35d2d601acdb9robertphillips@google.com  // socket and detects the error.
1278b0889a5aa610552bf306edc8d9a35d2d601acdb9robertphillips@google.com  std::string long_request_text =
1279b95eaa8d0842a8bba97f0bc7e19cfd9172d09722robertphillips@google.com      "GET / HTTP/1.1\r\nUser-Agent: long browser name ";
1280b95eaa8d0842a8bba97f0bc7e19cfd9172d09722robertphillips@google.com  long_request_text.append(20 * 1024, '*');
1281b0889a5aa610552bf306edc8d9a35d2d601acdb9robertphillips@google.com  long_request_text.append("\r\n\r\n");
1282b0889a5aa610552bf306edc8d9a35d2d601acdb9robertphillips@google.com  scoped_refptr<DrainableIOBuffer> long_request_buffer(new DrainableIOBuffer(
1283b0889a5aa610552bf306edc8d9a35d2d601acdb9robertphillips@google.com      new StringIOBuffer(long_request_text), long_request_text.size()));
1284b95eaa8d0842a8bba97f0bc7e19cfd9172d09722robertphillips@google.com
1285b95eaa8d0842a8bba97f0bc7e19cfd9172d09722robertphillips@google.com  raw_error_socket->SetNextWriteError(ERR_CONNECTION_RESET);
1286b0889a5aa610552bf306edc8d9a35d2d601acdb9robertphillips@google.com
1287b0889a5aa610552bf306edc8d9a35d2d601acdb9robertphillips@google.com  // Write as much data as possible until hitting an error. This is necessary
1288b0889a5aa610552bf306edc8d9a35d2d601acdb9robertphillips@google.com  // for NSS. PR_Write will only consume as much data as it can encode into
1289b95eaa8d0842a8bba97f0bc7e19cfd9172d09722robertphillips@google.com  // application data records before the internal memio buffer is full, which
1290b95eaa8d0842a8bba97f0bc7e19cfd9172d09722robertphillips@google.com  // should only fill if writing a large amount of data and the underlying
1291b0889a5aa610552bf306edc8d9a35d2d601acdb9robertphillips@google.com  // transport is blocked. Once this happens, NSS will return (total size of all
1292b0889a5aa610552bf306edc8d9a35d2d601acdb9robertphillips@google.com  // application data records it wrote) - 1, with the caller expected to resume
1293b0889a5aa610552bf306edc8d9a35d2d601acdb9robertphillips@google.com  // with the remaining unsent data.
1294b95eaa8d0842a8bba97f0bc7e19cfd9172d09722robertphillips@google.com  do {
1295b95eaa8d0842a8bba97f0bc7e19cfd9172d09722robertphillips@google.com    rv = callback.GetResult(sock->Write(long_request_buffer.get(),
12968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                        long_request_buffer->BytesRemaining(),
12978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                        callback.callback()));
12988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (rv > 0) {
12998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      long_request_buffer->DidConsume(rv);
13008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      // Abort if the entire buffer is ever consumed.
13018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      ASSERT_LT(0, long_request_buffer->BytesRemaining());
13028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
13038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  } while (rv > 0);
13048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#if !defined(USE_OPENSSL)
13068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // NSS records the error exactly.
13078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(ERR_CONNECTION_RESET, rv);
13088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#else
13098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // OpenSSL treats the reset as a generic protocol error.
13108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(ERR_SSL_PROTOCOL_ERROR, rv);
13118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
13128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // Release the read. Some bytes should go through.
13148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  raw_transport->UnblockRead();
13158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  rv = read_callback.WaitForResult();
13168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1317fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com  // Per the fix for http://crbug.com/249848, write failures currently break
13188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  // reads. Change this assertion if they're changed to not collide.
13198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(ERR_CONNECTION_RESET, rv);
13208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
13218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comTEST_F(SSLClientSocketTest, Read_SmallChunks) {
13238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
13248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                SpawnedTestServer::kLocalhost,
13258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                base::FilePath());
13268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ASSERT_TRUE(test_server.Start());
13278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  AddressList addr;
13298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  ASSERT_TRUE(test_server.GetAddressList(&addr));
13308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  TestCompletionCallback callback;
13328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_ptr<StreamSocket> transport(
13338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      new TCPClientSocket(addr, NULL, NetLog::Source()));
13348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  int rv = transport->Connect(callback.callback());
13358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  if (rv == ERR_IO_PENDING)
13368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    rv = callback.WaitForResult();
13378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(OK, rv);
13388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
13408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      transport.Pass(), test_server.host_port_pair(), kDefaultSSLConfig));
13418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  rv = sock->Connect(callback.callback());
13438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  if (rv == ERR_IO_PENDING)
13448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    rv = callback.WaitForResult();
13458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(OK, rv);
13468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
13488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_refptr<IOBuffer> request_buffer(
13498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      new IOBuffer(arraysize(request_text) - 1));
13508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
13518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  rv = sock->Write(
13538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      request_buffer.get(), arraysize(request_text) - 1, callback.callback());
13548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_TRUE(rv >= 0 || rv == ERR_IO_PENDING);
13558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  if (rv == ERR_IO_PENDING)
13578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    rv = callback.WaitForResult();
13588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  EXPECT_EQ(static_cast<int>(arraysize(request_text) - 1), rv);
1359e1b75b4096c8ba9a569ae33d580806edd3c4a97arobertphillips@google.com
13608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  scoped_refptr<IOBuffer> buf(new IOBuffer(1));
13618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  for (;;) {
13628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    rv = sock->Read(buf.get(), 1, callback.callback());
13638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    EXPECT_TRUE(rv >= 0 || rv == ERR_IO_PENDING);
13648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (rv == ERR_IO_PENDING)
13668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      rv = callback.WaitForResult();
13678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    EXPECT_GE(rv, 0);
13698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (rv <= 0)
13708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com      break;
13718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  }
13728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
13738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
13748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comTEST_F(SSLClientSocketTest, Read_ManySmallRecords) {
13758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
13768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                SpawnedTestServer::kLocalhost,
13778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                base::FilePath());
1378c518710d9a99c4d0adf759a102f4a1cb582f5939reed@google.com  ASSERT_TRUE(test_server.Start());
1379c518710d9a99c4d0adf759a102f4a1cb582f5939reed@google.com
1380c518710d9a99c4d0adf759a102f4a1cb582f5939reed@google.com  AddressList addr;
138117a2c919d095797c364d407a5dbdb4d60533b953reed@google.com  ASSERT_TRUE(test_server.GetAddressList(&addr));
138217a2c919d095797c364d407a5dbdb4d60533b953reed@google.com
138317a2c919d095797c364d407a5dbdb4d60533b953reed@google.com  TestCompletionCallback callback;
138417a2c919d095797c364d407a5dbdb4d60533b953reed@google.com
138517a2c919d095797c364d407a5dbdb4d60533b953reed@google.com  scoped_ptr<StreamSocket> real_transport(
138617a2c919d095797c364d407a5dbdb4d60533b953reed@google.com      new TCPClientSocket(addr, NULL, NetLog::Source()));
138717a2c919d095797c364d407a5dbdb4d60533b953reed@google.com  scoped_ptr<ReadBufferingStreamSocket> transport(
138817a2c919d095797c364d407a5dbdb4d60533b953reed@google.com      new ReadBufferingStreamSocket(real_transport.Pass()));
138917a2c919d095797c364d407a5dbdb4d60533b953reed@google.com  ReadBufferingStreamSocket* raw_transport = transport.get();
139017a2c919d095797c364d407a5dbdb4d60533b953reed@google.com  int rv = callback.GetResult(transport->Connect(callback.callback()));
139117a2c919d095797c364d407a5dbdb4d60533b953reed@google.com  ASSERT_EQ(OK, rv);
139217a2c919d095797c364d407a5dbdb4d60533b953reed@google.com
139317a2c919d095797c364d407a5dbdb4d60533b953reed@google.com  scoped_ptr<SSLClientSocket> sock(
139417a2c919d095797c364d407a5dbdb4d60533b953reed@google.com      CreateSSLClientSocket(transport.PassAs<StreamSocket>(),
139517a2c919d095797c364d407a5dbdb4d60533b953reed@google.com                            test_server.host_port_pair(),
13966862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.org                            kDefaultSSLConfig));
13970c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org
13980c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  rv = callback.GetResult(sock->Connect(callback.callback()));
139945fb8b60137c65106b7903285672d0f8a8041f97skia.committer@gmail.com  ASSERT_EQ(OK, rv);
14000c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  ASSERT_TRUE(sock->IsConnected());
14010c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org
14020c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  const char request_text[] = "GET /ssl-many-small-records HTTP/1.0\r\n\r\n";
14030c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  scoped_refptr<IOBuffer> request_buffer(
14040c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org      new IOBuffer(arraysize(request_text) - 1));
140545fb8b60137c65106b7903285672d0f8a8041f97skia.committer@gmail.com  memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
14060c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org
14070c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  rv = callback.GetResult(sock->Write(
14080c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org      request_buffer.get(), arraysize(request_text) - 1, callback.callback()));
14090c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  ASSERT_GT(rv, 0);
141045fb8b60137c65106b7903285672d0f8a8041f97skia.committer@gmail.com  ASSERT_EQ(static_cast<int>(arraysize(request_text) - 1), rv);
14110c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org
14120c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  // Note: This relies on SSLClientSocketNSS attempting to read up to 17K of
141317a2c919d095797c364d407a5dbdb4d60533b953reed@google.com  // data (the max SSL record size) at a time. Ensure that at least 15K worth
14140c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  // of SSL data is buffered first. The 15K of buffered data is made up of
14150c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  // many smaller SSL records (the TestServer writes along 1350 byte
14166862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.org  // plaintext boundaries), although there may also be a few records that are
14176862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.org  // smaller or larger, due to timing and SSL False Start.
14186862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.org  // 15K was chosen because 15K is smaller than the 17K (max) read issued by
14196862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.org  // the SSLClientSocket implementation, and larger than the minimum amount
14206862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.org  // of ciphertext necessary to contain the 8K of plaintext requested below.
14216862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.org  raw_transport->SetBufferSize(15000);
14220c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org
142317a2c919d095797c364d407a5dbdb4d60533b953reed@google.com  scoped_refptr<IOBuffer> buffer(new IOBuffer(8192));
14246862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.org  rv = callback.GetResult(sock->Read(buffer.get(), 8192, callback.callback()));
14256862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.org  ASSERT_EQ(rv, 8192);
142617a2c919d095797c364d407a5dbdb4d60533b953reed@google.com}
14276862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.org
14286862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.orgTEST_F(SSLClientSocketTest, Read_Interrupted) {
14296862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.org  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
14306862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.org                                SpawnedTestServer::kLocalhost,
14316862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.org                                base::FilePath());
14326862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.org  ASSERT_TRUE(test_server.Start());
14336862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.org
14346862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.org  AddressList addr;
14356862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.org  ASSERT_TRUE(test_server.GetAddressList(&addr));
14366862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.org
14376862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.org  TestCompletionCallback callback;
14386862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.org  scoped_ptr<StreamSocket> transport(
14396862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.org      new TCPClientSocket(addr, NULL, NetLog::Source()));
14400c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  int rv = transport->Connect(callback.callback());
14410c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  if (rv == ERR_IO_PENDING)
14426862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.org    rv = callback.WaitForResult();
14430c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  EXPECT_EQ(OK, rv);
14446862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.org
14450c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
14460c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org      transport.Pass(), test_server.host_port_pair(), kDefaultSSLConfig));
14470c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org
14480c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  rv = sock->Connect(callback.callback());
144945fb8b60137c65106b7903285672d0f8a8041f97skia.committer@gmail.com  if (rv == ERR_IO_PENDING)
14500c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org    rv = callback.WaitForResult();
14510c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  EXPECT_EQ(OK, rv);
14520c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org
14530c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
14540c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  scoped_refptr<IOBuffer> request_buffer(
145517a2c919d095797c364d407a5dbdb4d60533b953reed@google.com      new IOBuffer(arraysize(request_text) - 1));
145617a2c919d095797c364d407a5dbdb4d60533b953reed@google.com  memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
14570d099557feb99707c8f601746f46f5a295eb33b7reed@google.com
14580d099557feb99707c8f601746f46f5a295eb33b7reed@google.com  rv = sock->Write(
14594bb50b22fce5c4031549976cf7b04d63cc22e624skia.committer@gmail.com      request_buffer.get(), arraysize(request_text) - 1, callback.callback());
14600d099557feb99707c8f601746f46f5a295eb33b7reed@google.com  EXPECT_TRUE(rv >= 0 || rv == ERR_IO_PENDING);
14610d099557feb99707c8f601746f46f5a295eb33b7reed@google.com
14620d099557feb99707c8f601746f46f5a295eb33b7reed@google.com  if (rv == ERR_IO_PENDING)
14634bb50b22fce5c4031549976cf7b04d63cc22e624skia.committer@gmail.com    rv = callback.WaitForResult();
14640d099557feb99707c8f601746f46f5a295eb33b7reed@google.com  EXPECT_EQ(static_cast<int>(arraysize(request_text) - 1), rv);
14650d099557feb99707c8f601746f46f5a295eb33b7reed@google.com
14660d099557feb99707c8f601746f46f5a295eb33b7reed@google.com  // Do a partial read and then exit.  This test should not crash!
14670d099557feb99707c8f601746f46f5a295eb33b7reed@google.com  scoped_refptr<IOBuffer> buf(new IOBuffer(512));
14680d099557feb99707c8f601746f46f5a295eb33b7reed@google.com  rv = sock->Read(buf.get(), 512, callback.callback());
14690d099557feb99707c8f601746f46f5a295eb33b7reed@google.com  EXPECT_TRUE(rv > 0 || rv == ERR_IO_PENDING);
14700d099557feb99707c8f601746f46f5a295eb33b7reed@google.com
14710d099557feb99707c8f601746f46f5a295eb33b7reed@google.com  if (rv == ERR_IO_PENDING)
14720d099557feb99707c8f601746f46f5a295eb33b7reed@google.com    rv = callback.WaitForResult();
14730d099557feb99707c8f601746f46f5a295eb33b7reed@google.com
14740d099557feb99707c8f601746f46f5a295eb33b7reed@google.com  EXPECT_GT(rv, 0);
14750d099557feb99707c8f601746f46f5a295eb33b7reed@google.com}
14760d099557feb99707c8f601746f46f5a295eb33b7reed@google.com
14770d099557feb99707c8f601746f46f5a295eb33b7reed@google.comTEST_F(SSLClientSocketTest, Read_FullLogging) {
14780d099557feb99707c8f601746f46f5a295eb33b7reed@google.com  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
14790d099557feb99707c8f601746f46f5a295eb33b7reed@google.com                                SpawnedTestServer::kLocalhost,
14800d099557feb99707c8f601746f46f5a295eb33b7reed@google.com                                base::FilePath());
14810d099557feb99707c8f601746f46f5a295eb33b7reed@google.com  ASSERT_TRUE(test_server.Start());
14820d099557feb99707c8f601746f46f5a295eb33b7reed@google.com
14830d099557feb99707c8f601746f46f5a295eb33b7reed@google.com  AddressList addr;
14840d099557feb99707c8f601746f46f5a295eb33b7reed@google.com  ASSERT_TRUE(test_server.GetAddressList(&addr));
148524bd210f2e2cf66f356b4e98f7801631089b8aa3reed@google.com
1486c518710d9a99c4d0adf759a102f4a1cb582f5939reed@google.com  TestCompletionCallback callback;
14874bb50b22fce5c4031549976cf7b04d63cc22e624skia.committer@gmail.com  CapturingNetLog log;
1488c518710d9a99c4d0adf759a102f4a1cb582f5939reed@google.com  log.SetLogLevel(NetLog::LOG_ALL);
14896862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.org  scoped_ptr<StreamSocket> transport(
14906862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.org      new TCPClientSocket(addr, &log, NetLog::Source()));
1491c518710d9a99c4d0adf759a102f4a1cb582f5939reed@google.com  int rv = transport->Connect(callback.callback());
149224bd210f2e2cf66f356b4e98f7801631089b8aa3reed@google.com  if (rv == ERR_IO_PENDING)
149324bd210f2e2cf66f356b4e98f7801631089b8aa3reed@google.com    rv = callback.WaitForResult();
149424bd210f2e2cf66f356b4e98f7801631089b8aa3reed@google.com  EXPECT_EQ(OK, rv);
149524bd210f2e2cf66f356b4e98f7801631089b8aa3reed@google.com
1496c518710d9a99c4d0adf759a102f4a1cb582f5939reed@google.com  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
1497c518710d9a99c4d0adf759a102f4a1cb582f5939reed@google.com      transport.Pass(), test_server.host_port_pair(), kDefaultSSLConfig));
149828552e12a019bf5ae55c9e8602bbe216562d7a3emike@reedtribe.org
14990d099557feb99707c8f601746f46f5a295eb33b7reed@google.com  rv = sock->Connect(callback.callback());
15000d099557feb99707c8f601746f46f5a295eb33b7reed@google.com  if (rv == ERR_IO_PENDING)
15010d099557feb99707c8f601746f46f5a295eb33b7reed@google.com    rv = callback.WaitForResult();
15024bb50b22fce5c4031549976cf7b04d63cc22e624skia.committer@gmail.com  EXPECT_EQ(OK, rv);
15030d099557feb99707c8f601746f46f5a295eb33b7reed@google.com  EXPECT_TRUE(sock->IsConnected());
15040d099557feb99707c8f601746f46f5a295eb33b7reed@google.com
15050d099557feb99707c8f601746f46f5a295eb33b7reed@google.com  const char request_text[] = "GET / HTTP/1.0\r\n\r\n";
15064bb50b22fce5c4031549976cf7b04d63cc22e624skia.committer@gmail.com  scoped_refptr<IOBuffer> request_buffer(
15070d099557feb99707c8f601746f46f5a295eb33b7reed@google.com      new IOBuffer(arraysize(request_text) - 1));
15080d099557feb99707c8f601746f46f5a295eb33b7reed@google.com  memcpy(request_buffer->data(), request_text, arraysize(request_text) - 1);
15090d099557feb99707c8f601746f46f5a295eb33b7reed@google.com
15100d099557feb99707c8f601746f46f5a295eb33b7reed@google.com  rv = sock->Write(
15110d099557feb99707c8f601746f46f5a295eb33b7reed@google.com      request_buffer.get(), arraysize(request_text) - 1, callback.callback());
15120d099557feb99707c8f601746f46f5a295eb33b7reed@google.com  EXPECT_TRUE(rv >= 0 || rv == ERR_IO_PENDING);
15134af6280aa366a02540f34c48f89ea73ce3d27974mike@reedtribe.org
15144af6280aa366a02540f34c48f89ea73ce3d27974mike@reedtribe.org  if (rv == ERR_IO_PENDING)
15154af6280aa366a02540f34c48f89ea73ce3d27974mike@reedtribe.org    rv = callback.WaitForResult();
15164af6280aa366a02540f34c48f89ea73ce3d27974mike@reedtribe.org  EXPECT_EQ(static_cast<int>(arraysize(request_text) - 1), rv);
15174af6280aa366a02540f34c48f89ea73ce3d27974mike@reedtribe.org
15184af6280aa366a02540f34c48f89ea73ce3d27974mike@reedtribe.org  CapturingNetLog::CapturedEntryList entries;
15194af6280aa366a02540f34c48f89ea73ce3d27974mike@reedtribe.org  log.GetEntries(&entries);
15204af6280aa366a02540f34c48f89ea73ce3d27974mike@reedtribe.org  size_t last_index = ExpectLogContainsSomewhereAfter(
15214af6280aa366a02540f34c48f89ea73ce3d27974mike@reedtribe.org      entries, 5, NetLog::TYPE_SSL_SOCKET_BYTES_SENT, NetLog::PHASE_NONE);
15224af6280aa366a02540f34c48f89ea73ce3d27974mike@reedtribe.org
1523c518710d9a99c4d0adf759a102f4a1cb582f5939reed@google.com  scoped_refptr<IOBuffer> buf(new IOBuffer(4096));
15248d551011966a1bc14a654dbde704f343c0e222b6mike@reedtribe.org  for (;;) {
15253df87cb36e9f9d2e04d2f81ac64cf3d778c33847mike@reedtribe.org    rv = sock->Read(buf.get(), 4096, callback.callback());
15266862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.org    EXPECT_TRUE(rv >= 0 || rv == ERR_IO_PENDING);
15273df87cb36e9f9d2e04d2f81ac64cf3d778c33847mike@reedtribe.org
15283df87cb36e9f9d2e04d2f81ac64cf3d778c33847mike@reedtribe.org    if (rv == ERR_IO_PENDING)
152928552e12a019bf5ae55c9e8602bbe216562d7a3emike@reedtribe.org      rv = callback.WaitForResult();
15308d551011966a1bc14a654dbde704f343c0e222b6mike@reedtribe.org
15318d551011966a1bc14a654dbde704f343c0e222b6mike@reedtribe.org    EXPECT_GE(rv, 0);
15328d551011966a1bc14a654dbde704f343c0e222b6mike@reedtribe.org    if (rv <= 0)
15338d551011966a1bc14a654dbde704f343c0e222b6mike@reedtribe.org      break;
15348d551011966a1bc14a654dbde704f343c0e222b6mike@reedtribe.org
15358d551011966a1bc14a654dbde704f343c0e222b6mike@reedtribe.org    log.GetEntries(&entries);
15368d551011966a1bc14a654dbde704f343c0e222b6mike@reedtribe.org    last_index =
15378d551011966a1bc14a654dbde704f343c0e222b6mike@reedtribe.org        ExpectLogContainsSomewhereAfter(entries,
15388d551011966a1bc14a654dbde704f343c0e222b6mike@reedtribe.org                                        last_index + 1,
15398d551011966a1bc14a654dbde704f343c0e222b6mike@reedtribe.org                                        NetLog::TYPE_SSL_SOCKET_BYTES_RECEIVED,
15408d551011966a1bc14a654dbde704f343c0e222b6mike@reedtribe.org                                        NetLog::PHASE_NONE);
15418d551011966a1bc14a654dbde704f343c0e222b6mike@reedtribe.org  }
15428d551011966a1bc14a654dbde704f343c0e222b6mike@reedtribe.org}
15438d551011966a1bc14a654dbde704f343c0e222b6mike@reedtribe.org
15448d551011966a1bc14a654dbde704f343c0e222b6mike@reedtribe.org// Regression test for http://crbug.com/42538
15458d551011966a1bc14a654dbde704f343c0e222b6mike@reedtribe.orgTEST_F(SSLClientSocketTest, PrematureApplicationData) {
15463df87cb36e9f9d2e04d2f81ac64cf3d778c33847mike@reedtribe.org  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
15473df87cb36e9f9d2e04d2f81ac64cf3d778c33847mike@reedtribe.org                                SpawnedTestServer::kLocalhost,
15483df87cb36e9f9d2e04d2f81ac64cf3d778c33847mike@reedtribe.org                                base::FilePath());
154997514f22e4cb85a0d79b089a1eecd54d4a952291mike@reedtribe.org  ASSERT_TRUE(test_server.Start());
155097514f22e4cb85a0d79b089a1eecd54d4a952291mike@reedtribe.org
155197514f22e4cb85a0d79b089a1eecd54d4a952291mike@reedtribe.org  AddressList addr;
155297514f22e4cb85a0d79b089a1eecd54d4a952291mike@reedtribe.org  TestCompletionCallback callback;
1553af5c506cd6b63f43a0ebee2fb171ea55ba98e09fmike@reedtribe.org
1554af5c506cd6b63f43a0ebee2fb171ea55ba98e09fmike@reedtribe.org  static const unsigned char application_data[] = {
1555af5c506cd6b63f43a0ebee2fb171ea55ba98e09fmike@reedtribe.org      0x17, 0x03, 0x01, 0x00, 0x4a, 0x02, 0x00, 0x00, 0x46, 0x03, 0x01, 0x4b,
1556af5c506cd6b63f43a0ebee2fb171ea55ba98e09fmike@reedtribe.org      0xc2, 0xf8, 0xb2, 0xc1, 0x56, 0x42, 0xb9, 0x57, 0x7f, 0xde, 0x87, 0x46,
1557af5c506cd6b63f43a0ebee2fb171ea55ba98e09fmike@reedtribe.org      0xf7, 0xa3, 0x52, 0x42, 0x21, 0xf0, 0x13, 0x1c, 0x9c, 0x83, 0x88, 0xd6,
1558af5c506cd6b63f43a0ebee2fb171ea55ba98e09fmike@reedtribe.org      0x93, 0x0c, 0xf6, 0x36, 0x30, 0x05, 0x7e, 0x20, 0xb5, 0xb5, 0x73, 0x36,
1559af5c506cd6b63f43a0ebee2fb171ea55ba98e09fmike@reedtribe.org      0x53, 0x83, 0x0a, 0xfc, 0x17, 0x63, 0xbf, 0xa0, 0xe4, 0x42, 0x90, 0x0d,
1560af5c506cd6b63f43a0ebee2fb171ea55ba98e09fmike@reedtribe.org      0x2f, 0x18, 0x6d, 0x20, 0xd8, 0x36, 0x3f, 0xfc, 0xe6, 0x01, 0xfa, 0x0f,
1561af5c506cd6b63f43a0ebee2fb171ea55ba98e09fmike@reedtribe.org      0xa5, 0x75, 0x7f, 0x09, 0x00, 0x04, 0x00, 0x16, 0x03, 0x01, 0x11, 0x57,
1562af5c506cd6b63f43a0ebee2fb171ea55ba98e09fmike@reedtribe.org      0x0b, 0x00, 0x11, 0x53, 0x00, 0x11, 0x50, 0x00, 0x06, 0x22, 0x30, 0x82,
1563af5c506cd6b63f43a0ebee2fb171ea55ba98e09fmike@reedtribe.org      0x06, 0x1e, 0x30, 0x82, 0x05, 0x06, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
1564af5c506cd6b63f43a0ebee2fb171ea55ba98e09fmike@reedtribe.org      0x0a};
1565af5c506cd6b63f43a0ebee2fb171ea55ba98e09fmike@reedtribe.org
1566af5c506cd6b63f43a0ebee2fb171ea55ba98e09fmike@reedtribe.org  // All reads and writes complete synchronously (async=false).
156797514f22e4cb85a0d79b089a1eecd54d4a952291mike@reedtribe.org  MockRead data_reads[] = {
15687841c63136e8aa2d3aadbeab8432405abcd73c32skia.committer@gmail.com      MockRead(SYNCHRONOUS,
156997514f22e4cb85a0d79b089a1eecd54d4a952291mike@reedtribe.org               reinterpret_cast<const char*>(application_data),
1570af5c506cd6b63f43a0ebee2fb171ea55ba98e09fmike@reedtribe.org               arraysize(application_data)),
1571af5c506cd6b63f43a0ebee2fb171ea55ba98e09fmike@reedtribe.org      MockRead(SYNCHRONOUS, OK), };
1572af5c506cd6b63f43a0ebee2fb171ea55ba98e09fmike@reedtribe.org
1573af5c506cd6b63f43a0ebee2fb171ea55ba98e09fmike@reedtribe.org  StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0);
157497514f22e4cb85a0d79b089a1eecd54d4a952291mike@reedtribe.org
15753df87cb36e9f9d2e04d2f81ac64cf3d778c33847mike@reedtribe.org  scoped_ptr<StreamSocket> transport(
157697514f22e4cb85a0d79b089a1eecd54d4a952291mike@reedtribe.org      new MockTCPClientSocket(addr, NULL, &data));
1577af5c506cd6b63f43a0ebee2fb171ea55ba98e09fmike@reedtribe.org  int rv = transport->Connect(callback.callback());
15783df87cb36e9f9d2e04d2f81ac64cf3d778c33847mike@reedtribe.org  if (rv == ERR_IO_PENDING)
15793df87cb36e9f9d2e04d2f81ac64cf3d778c33847mike@reedtribe.org    rv = callback.WaitForResult();
158028552e12a019bf5ae55c9e8602bbe216562d7a3emike@reedtribe.org  EXPECT_EQ(OK, rv);
15813df87cb36e9f9d2e04d2f81ac64cf3d778c33847mike@reedtribe.org
1582af5c506cd6b63f43a0ebee2fb171ea55ba98e09fmike@reedtribe.org  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
15833df87cb36e9f9d2e04d2f81ac64cf3d778c33847mike@reedtribe.org      transport.Pass(), test_server.host_port_pair(), kDefaultSSLConfig));
15843df87cb36e9f9d2e04d2f81ac64cf3d778c33847mike@reedtribe.org
15853df87cb36e9f9d2e04d2f81ac64cf3d778c33847mike@reedtribe.org  rv = sock->Connect(callback.callback());
15863df87cb36e9f9d2e04d2f81ac64cf3d778c33847mike@reedtribe.org  if (rv == ERR_IO_PENDING)
158728552e12a019bf5ae55c9e8602bbe216562d7a3emike@reedtribe.org    rv = callback.WaitForResult();
15883df87cb36e9f9d2e04d2f81ac64cf3d778c33847mike@reedtribe.org  EXPECT_EQ(ERR_SSL_PROTOCOL_ERROR, rv);
15893df87cb36e9f9d2e04d2f81ac64cf3d778c33847mike@reedtribe.org}
15903df87cb36e9f9d2e04d2f81ac64cf3d778c33847mike@reedtribe.org
15913df87cb36e9f9d2e04d2f81ac64cf3d778c33847mike@reedtribe.orgTEST_F(SSLClientSocketTest, CipherSuiteDisables) {
15923df87cb36e9f9d2e04d2f81ac64cf3d778c33847mike@reedtribe.org  // Rather than exhaustively disabling every RC4 ciphersuite defined at
15938d551011966a1bc14a654dbde704f343c0e222b6mike@reedtribe.org  // http://www.iana.org/assignments/tls-parameters/tls-parameters.xml,
15943df87cb36e9f9d2e04d2f81ac64cf3d778c33847mike@reedtribe.org  // only disabling those cipher suites that the test server actually
159528552e12a019bf5ae55c9e8602bbe216562d7a3emike@reedtribe.org  // implements.
1596af5c506cd6b63f43a0ebee2fb171ea55ba98e09fmike@reedtribe.org  const uint16 kCiphersToDisable[] = {0x0005,  // TLS_RSA_WITH_RC4_128_SHA
15973df87cb36e9f9d2e04d2f81ac64cf3d778c33847mike@reedtribe.org  };
1598aebfa7e1b1e94f693f3e7beb6ad43cfcb0f69e98reed@google.com
15993df87cb36e9f9d2e04d2f81ac64cf3d778c33847mike@reedtribe.org  SpawnedTestServer::SSLOptions ssl_options;
16003df87cb36e9f9d2e04d2f81ac64cf3d778c33847mike@reedtribe.org  // Enable only RC4 on the test server.
16013df87cb36e9f9d2e04d2f81ac64cf3d778c33847mike@reedtribe.org  ssl_options.bulk_ciphers = SpawnedTestServer::SSLOptions::BULK_CIPHER_RC4;
16020c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  SpawnedTestServer test_server(
160328552e12a019bf5ae55c9e8602bbe216562d7a3emike@reedtribe.org      SpawnedTestServer::TYPE_HTTPS, ssl_options, base::FilePath());
16046862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.org  ASSERT_TRUE(test_server.Start());
16050c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org
16060c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  AddressList addr;
160728552e12a019bf5ae55c9e8602bbe216562d7a3emike@reedtribe.org  ASSERT_TRUE(test_server.GetAddressList(&addr));
16086862cbad085729acb77825392c8c2a4f888a99cfmike@reedtribe.org
16090c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  TestCompletionCallback callback;
16100c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  CapturingNetLog log;
161128552e12a019bf5ae55c9e8602bbe216562d7a3emike@reedtribe.org  scoped_ptr<StreamSocket> transport(
16120c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org      new TCPClientSocket(addr, &log, NetLog::Source()));
16130c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  int rv = transport->Connect(callback.callback());
16140c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  if (rv == ERR_IO_PENDING)
16150c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org    rv = callback.WaitForResult();
16160c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  EXPECT_EQ(OK, rv);
16170c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org
16180c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  SSLConfig ssl_config;
16190c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  for (size_t i = 0; i < arraysize(kCiphersToDisable); ++i)
16200c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org    ssl_config.disabled_cipher_suites.push_back(kCiphersToDisable[i]);
16210c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org
16220c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
16230c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org      transport.Pass(), test_server.host_port_pair(), ssl_config));
16240c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org
16250c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  EXPECT_FALSE(sock->IsConnected());
162628552e12a019bf5ae55c9e8602bbe216562d7a3emike@reedtribe.org
16270c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  rv = sock->Connect(callback.callback());
16280c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  CapturingNetLog::CapturedEntryList entries;
16290c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  log.GetEntries(&entries);
16300c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  EXPECT_TRUE(LogContainsBeginEvent(entries, 5, NetLog::TYPE_SSL_CONNECT));
16310c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org
16320c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  // NSS has special handling that maps a handshake_failure alert received
16330c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  // immediately after a client_hello to be a mismatched cipher suite error,
16340c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  // leading to ERR_SSL_VERSION_OR_CIPHER_MISMATCH. When using OpenSSL or
16350c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  // Secure Transport (OS X), the handshake_failure is bubbled up without any
16360c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  // interpretation, leading to ERR_SSL_PROTOCOL_ERROR. Either way, a failure
16370c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  // indicates that no cipher suite was negotiated with the test server.
16380c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  if (rv == ERR_IO_PENDING)
16390c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org    rv = callback.WaitForResult();
16400c5c3867bdbde1005a7bbb9de9df93cc10e27782mike@reedtribe.org  EXPECT_TRUE(rv == ERR_SSL_VERSION_OR_CIPHER_MISMATCH ||
164128552e12a019bf5ae55c9e8602bbe216562d7a3emike@reedtribe.org              rv == ERR_SSL_PROTOCOL_ERROR);
16425c082a14acbb70eec2fd6dc5a4c134799f3d8535mike@reedtribe.org  // The exact ordering differs between SSLClientSocketNSS (which issues an
16435c082a14acbb70eec2fd6dc5a4c134799f3d8535mike@reedtribe.org  // extra read) and SSLClientSocketMac (which does not). Just make sure the
16445c082a14acbb70eec2fd6dc5a4c134799f3d8535mike@reedtribe.org  // error appears somewhere in the log.
16455c082a14acbb70eec2fd6dc5a4c134799f3d8535mike@reedtribe.org  log.GetEntries(&entries);
16465c082a14acbb70eec2fd6dc5a4c134799f3d8535mike@reedtribe.org  ExpectLogContainsSomewhere(
16475c082a14acbb70eec2fd6dc5a4c134799f3d8535mike@reedtribe.org      entries, 0, NetLog::TYPE_SSL_HANDSHAKE_ERROR, NetLog::PHASE_NONE);
16485c082a14acbb70eec2fd6dc5a4c134799f3d8535mike@reedtribe.org
16495c082a14acbb70eec2fd6dc5a4c134799f3d8535mike@reedtribe.org  // We cannot test sock->IsConnected(), as the NSS implementation disconnects
16505c082a14acbb70eec2fd6dc5a4c134799f3d8535mike@reedtribe.org  // the socket when it encounters an error, whereas other implementations
16515c082a14acbb70eec2fd6dc5a4c134799f3d8535mike@reedtribe.org  // leave it connected.
16525c082a14acbb70eec2fd6dc5a4c134799f3d8535mike@reedtribe.org  // Because this an error that the test server is mutually aware of, as opposed
16535c082a14acbb70eec2fd6dc5a4c134799f3d8535mike@reedtribe.org  // to being an error such as a certificate name mismatch, which is
16545c082a14acbb70eec2fd6dc5a4c134799f3d8535mike@reedtribe.org  // client-only, the exact index of the SSL connect end depends on how
16555c082a14acbb70eec2fd6dc5a4c134799f3d8535mike@reedtribe.org  // quickly the test server closes the underlying socket. If the test server
16565c082a14acbb70eec2fd6dc5a4c134799f3d8535mike@reedtribe.org  // closes before the IO message loop pumps messages, there may be a 0-byte
165728552e12a019bf5ae55c9e8602bbe216562d7a3emike@reedtribe.org  // Read event in the NetLog due to TCPClientSocket picking up the EOF. As a
16585c082a14acbb70eec2fd6dc5a4c134799f3d8535mike@reedtribe.org  // result, the SSL connect end event will be the second-to-last entry,
16595c082a14acbb70eec2fd6dc5a4c134799f3d8535mike@reedtribe.org  // rather than the last entry.
1660  EXPECT_TRUE(LogContainsSSLConnectEndEvent(entries, -1) ||
1661              LogContainsSSLConnectEndEvent(entries, -2));
1662}
1663
1664// When creating an SSLClientSocket, it is allowed to pass in a
1665// ClientSocketHandle that is not obtained from a client socket pool.
1666// Here we verify that such a simple ClientSocketHandle, not associated with any
1667// client socket pool, can be destroyed safely.
1668TEST_F(SSLClientSocketTest, ClientSocketHandleNotFromPool) {
1669  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
1670                                SpawnedTestServer::kLocalhost,
1671                                base::FilePath());
1672  ASSERT_TRUE(test_server.Start());
1673
1674  AddressList addr;
1675  ASSERT_TRUE(test_server.GetAddressList(&addr));
1676
1677  TestCompletionCallback callback;
1678  scoped_ptr<StreamSocket> transport(
1679      new TCPClientSocket(addr, NULL, NetLog::Source()));
1680  int rv = transport->Connect(callback.callback());
1681  if (rv == ERR_IO_PENDING)
1682    rv = callback.WaitForResult();
1683  EXPECT_EQ(OK, rv);
1684
1685  scoped_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle());
1686  socket_handle->SetSocket(transport.Pass());
1687
1688  scoped_ptr<SSLClientSocket> sock(
1689      socket_factory_->CreateSSLClientSocket(socket_handle.Pass(),
1690                                             test_server.host_port_pair(),
1691                                             kDefaultSSLConfig,
1692                                             context_));
1693
1694  EXPECT_FALSE(sock->IsConnected());
1695  rv = sock->Connect(callback.callback());
1696  if (rv == ERR_IO_PENDING)
1697    rv = callback.WaitForResult();
1698  EXPECT_EQ(OK, rv);
1699}
1700
1701// Verifies that SSLClientSocket::ExportKeyingMaterial return a success
1702// code and different keying label results in different keying material.
1703TEST_F(SSLClientSocketTest, ExportKeyingMaterial) {
1704  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
1705                                SpawnedTestServer::kLocalhost,
1706                                base::FilePath());
1707  ASSERT_TRUE(test_server.Start());
1708
1709  AddressList addr;
1710  ASSERT_TRUE(test_server.GetAddressList(&addr));
1711
1712  TestCompletionCallback callback;
1713
1714  scoped_ptr<StreamSocket> transport(
1715      new TCPClientSocket(addr, NULL, NetLog::Source()));
1716  int rv = transport->Connect(callback.callback());
1717  if (rv == ERR_IO_PENDING)
1718    rv = callback.WaitForResult();
1719  EXPECT_EQ(OK, rv);
1720
1721  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
1722      transport.Pass(), test_server.host_port_pair(), kDefaultSSLConfig));
1723
1724  rv = sock->Connect(callback.callback());
1725  if (rv == ERR_IO_PENDING)
1726    rv = callback.WaitForResult();
1727  EXPECT_EQ(OK, rv);
1728  EXPECT_TRUE(sock->IsConnected());
1729
1730  const int kKeyingMaterialSize = 32;
1731  const char* kKeyingLabel1 = "client-socket-test-1";
1732  const char* kKeyingContext = "";
1733  unsigned char client_out1[kKeyingMaterialSize];
1734  memset(client_out1, 0, sizeof(client_out1));
1735  rv = sock->ExportKeyingMaterial(
1736      kKeyingLabel1, false, kKeyingContext, client_out1, sizeof(client_out1));
1737  EXPECT_EQ(rv, OK);
1738
1739  const char* kKeyingLabel2 = "client-socket-test-2";
1740  unsigned char client_out2[kKeyingMaterialSize];
1741  memset(client_out2, 0, sizeof(client_out2));
1742  rv = sock->ExportKeyingMaterial(
1743      kKeyingLabel2, false, kKeyingContext, client_out2, sizeof(client_out2));
1744  EXPECT_EQ(rv, OK);
1745  EXPECT_NE(memcmp(client_out1, client_out2, kKeyingMaterialSize), 0);
1746}
1747
1748// Verifies that SSLClientSocket::ClearSessionCache can be called without
1749// explicit NSS initialization.
1750TEST(SSLClientSocket, ClearSessionCache) {
1751  SSLClientSocket::ClearSessionCache();
1752}
1753
1754// Test that the server certificates are properly retrieved from the underlying
1755// SSL stack.
1756TEST_F(SSLClientSocketTest, VerifyServerChainProperlyOrdered) {
1757  // The connection does not have to be successful.
1758  cert_verifier_->set_default_result(ERR_CERT_INVALID);
1759
1760  // Set up a test server with CERT_CHAIN_WRONG_ROOT.
1761  // This makes the server present redundant-server-chain.pem, which contains
1762  // intermediate certificates.
1763  SpawnedTestServer::SSLOptions ssl_options(
1764      SpawnedTestServer::SSLOptions::CERT_CHAIN_WRONG_ROOT);
1765  SpawnedTestServer test_server(
1766      SpawnedTestServer::TYPE_HTTPS, ssl_options, base::FilePath());
1767  ASSERT_TRUE(test_server.Start());
1768
1769  AddressList addr;
1770  ASSERT_TRUE(test_server.GetAddressList(&addr));
1771
1772  TestCompletionCallback callback;
1773  scoped_ptr<StreamSocket> transport(
1774      new TCPClientSocket(addr, NULL, NetLog::Source()));
1775  int rv = transport->Connect(callback.callback());
1776  rv = callback.GetResult(rv);
1777  EXPECT_EQ(OK, rv);
1778
1779  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
1780      transport.Pass(), test_server.host_port_pair(), kDefaultSSLConfig));
1781  EXPECT_FALSE(sock->IsConnected());
1782  rv = sock->Connect(callback.callback());
1783  rv = callback.GetResult(rv);
1784
1785  EXPECT_EQ(ERR_CERT_INVALID, rv);
1786  EXPECT_TRUE(sock->IsConnected());
1787
1788  // When given option CERT_CHAIN_WRONG_ROOT, SpawnedTestServer will present
1789  // certs from redundant-server-chain.pem.
1790  CertificateList server_certs =
1791      CreateCertificateListFromFile(GetTestCertsDirectory(),
1792                                    "redundant-server-chain.pem",
1793                                    X509Certificate::FORMAT_AUTO);
1794
1795  // Get the server certificate as received client side.
1796  scoped_refptr<X509Certificate> server_certificate =
1797      sock->GetUnverifiedServerCertificateChain();
1798
1799  // Get the intermediates as received  client side.
1800  const X509Certificate::OSCertHandles& server_intermediates =
1801      server_certificate->GetIntermediateCertificates();
1802
1803  // Check that the unverified server certificate chain is properly retrieved
1804  // from the underlying ssl stack.
1805  ASSERT_EQ(4U, server_certs.size());
1806
1807  EXPECT_TRUE(X509Certificate::IsSameOSCert(
1808      server_certificate->os_cert_handle(), server_certs[0]->os_cert_handle()));
1809
1810  ASSERT_EQ(3U, server_intermediates.size());
1811
1812  EXPECT_TRUE(X509Certificate::IsSameOSCert(server_intermediates[0],
1813                                            server_certs[1]->os_cert_handle()));
1814  EXPECT_TRUE(X509Certificate::IsSameOSCert(server_intermediates[1],
1815                                            server_certs[2]->os_cert_handle()));
1816  EXPECT_TRUE(X509Certificate::IsSameOSCert(server_intermediates[2],
1817                                            server_certs[3]->os_cert_handle()));
1818
1819  sock->Disconnect();
1820  EXPECT_FALSE(sock->IsConnected());
1821}
1822
1823// This tests that SSLInfo contains a properly re-constructed certificate
1824// chain. That, in turn, verifies that GetSSLInfo is giving us the chain as
1825// verified, not the chain as served by the server. (They may be different.)
1826//
1827// CERT_CHAIN_WRONG_ROOT is redundant-server-chain.pem. It contains A
1828// (end-entity) -> B -> C, and C is signed by D. redundant-validated-chain.pem
1829// contains a chain of A -> B -> C2, where C2 is the same public key as C, but
1830// a self-signed root. Such a situation can occur when a new root (C2) is
1831// cross-certified by an old root (D) and has two different versions of its
1832// floating around. Servers may supply C2 as an intermediate, but the
1833// SSLClientSocket should return the chain that was verified, from
1834// verify_result, instead.
1835TEST_F(SSLClientSocketTest, VerifyReturnChainProperlyOrdered) {
1836  // By default, cause the CertVerifier to treat all certificates as
1837  // expired.
1838  cert_verifier_->set_default_result(ERR_CERT_DATE_INVALID);
1839
1840  // We will expect SSLInfo to ultimately contain this chain.
1841  CertificateList certs =
1842      CreateCertificateListFromFile(GetTestCertsDirectory(),
1843                                    "redundant-validated-chain.pem",
1844                                    X509Certificate::FORMAT_AUTO);
1845  ASSERT_EQ(3U, certs.size());
1846
1847  X509Certificate::OSCertHandles temp_intermediates;
1848  temp_intermediates.push_back(certs[1]->os_cert_handle());
1849  temp_intermediates.push_back(certs[2]->os_cert_handle());
1850
1851  CertVerifyResult verify_result;
1852  verify_result.verified_cert = X509Certificate::CreateFromHandle(
1853      certs[0]->os_cert_handle(), temp_intermediates);
1854
1855  // Add a rule that maps the server cert (A) to the chain of A->B->C2
1856  // rather than A->B->C.
1857  cert_verifier_->AddResultForCert(certs[0].get(), verify_result, OK);
1858
1859  // Load and install the root for the validated chain.
1860  scoped_refptr<X509Certificate> root_cert = ImportCertFromFile(
1861      GetTestCertsDirectory(), "redundant-validated-chain-root.pem");
1862  ASSERT_NE(static_cast<X509Certificate*>(NULL), root_cert);
1863  ScopedTestRoot scoped_root(root_cert.get());
1864
1865  // Set up a test server with CERT_CHAIN_WRONG_ROOT.
1866  SpawnedTestServer::SSLOptions ssl_options(
1867      SpawnedTestServer::SSLOptions::CERT_CHAIN_WRONG_ROOT);
1868  SpawnedTestServer test_server(
1869      SpawnedTestServer::TYPE_HTTPS,
1870      ssl_options,
1871      base::FilePath(FILE_PATH_LITERAL("net/data/ssl")));
1872  ASSERT_TRUE(test_server.Start());
1873
1874  AddressList addr;
1875  ASSERT_TRUE(test_server.GetAddressList(&addr));
1876
1877  TestCompletionCallback callback;
1878  CapturingNetLog log;
1879  scoped_ptr<StreamSocket> transport(
1880      new TCPClientSocket(addr, &log, NetLog::Source()));
1881  int rv = transport->Connect(callback.callback());
1882  if (rv == ERR_IO_PENDING)
1883    rv = callback.WaitForResult();
1884  EXPECT_EQ(OK, rv);
1885
1886  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
1887      transport.Pass(), test_server.host_port_pair(), kDefaultSSLConfig));
1888  EXPECT_FALSE(sock->IsConnected());
1889  rv = sock->Connect(callback.callback());
1890
1891  CapturingNetLog::CapturedEntryList entries;
1892  log.GetEntries(&entries);
1893  EXPECT_TRUE(LogContainsBeginEvent(entries, 5, NetLog::TYPE_SSL_CONNECT));
1894  if (rv == ERR_IO_PENDING)
1895    rv = callback.WaitForResult();
1896
1897  EXPECT_EQ(OK, rv);
1898  EXPECT_TRUE(sock->IsConnected());
1899  log.GetEntries(&entries);
1900  EXPECT_TRUE(LogContainsSSLConnectEndEvent(entries, -1));
1901
1902  SSLInfo ssl_info;
1903  sock->GetSSLInfo(&ssl_info);
1904
1905  // Verify that SSLInfo contains the corrected re-constructed chain A -> B
1906  // -> C2.
1907  const X509Certificate::OSCertHandles& intermediates =
1908      ssl_info.cert->GetIntermediateCertificates();
1909  ASSERT_EQ(2U, intermediates.size());
1910  EXPECT_TRUE(X509Certificate::IsSameOSCert(ssl_info.cert->os_cert_handle(),
1911                                            certs[0]->os_cert_handle()));
1912  EXPECT_TRUE(X509Certificate::IsSameOSCert(intermediates[0],
1913                                            certs[1]->os_cert_handle()));
1914  EXPECT_TRUE(X509Certificate::IsSameOSCert(intermediates[1],
1915                                            certs[2]->os_cert_handle()));
1916
1917  sock->Disconnect();
1918  EXPECT_FALSE(sock->IsConnected());
1919}
1920
1921TEST_F(SSLClientSocketCertRequestInfoTest, NoAuthorities) {
1922  SpawnedTestServer::SSLOptions ssl_options;
1923  ssl_options.request_client_certificate = true;
1924  scoped_refptr<SSLCertRequestInfo> request_info = GetCertRequest(ssl_options);
1925  ASSERT_TRUE(request_info.get());
1926  EXPECT_EQ(0u, request_info->cert_authorities.size());
1927}
1928
1929TEST_F(SSLClientSocketCertRequestInfoTest, TwoAuthorities) {
1930  const base::FilePath::CharType kThawteFile[] =
1931      FILE_PATH_LITERAL("thawte.single.pem");
1932  const unsigned char kThawteDN[] = {
1933      0x30, 0x4c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
1934      0x02, 0x5a, 0x41, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x0a,
1935      0x13, 0x1c, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x43, 0x6f, 0x6e,
1936      0x73, 0x75, 0x6c, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x28, 0x50, 0x74, 0x79,
1937      0x29, 0x20, 0x4c, 0x74, 0x64, 0x2e, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03,
1938      0x55, 0x04, 0x03, 0x13, 0x0d, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20,
1939      0x53, 0x47, 0x43, 0x20, 0x43, 0x41};
1940  const size_t kThawteLen = sizeof(kThawteDN);
1941
1942  const base::FilePath::CharType kDiginotarFile[] =
1943      FILE_PATH_LITERAL("diginotar_root_ca.pem");
1944  const unsigned char kDiginotarDN[] = {
1945      0x30, 0x5f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
1946      0x02, 0x4e, 0x4c, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a,
1947      0x13, 0x09, 0x44, 0x69, 0x67, 0x69, 0x4e, 0x6f, 0x74, 0x61, 0x72, 0x31,
1948      0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x11, 0x44, 0x69,
1949      0x67, 0x69, 0x4e, 0x6f, 0x74, 0x61, 0x72, 0x20, 0x52, 0x6f, 0x6f, 0x74,
1950      0x20, 0x43, 0x41, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x09, 0x2a, 0x86, 0x48,
1951      0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x11, 0x69, 0x6e, 0x66, 0x6f,
1952      0x40, 0x64, 0x69, 0x67, 0x69, 0x6e, 0x6f, 0x74, 0x61, 0x72, 0x2e, 0x6e,
1953      0x6c};
1954  const size_t kDiginotarLen = sizeof(kDiginotarDN);
1955
1956  SpawnedTestServer::SSLOptions ssl_options;
1957  ssl_options.request_client_certificate = true;
1958  ssl_options.client_authorities.push_back(
1959      GetTestClientCertsDirectory().Append(kThawteFile));
1960  ssl_options.client_authorities.push_back(
1961      GetTestClientCertsDirectory().Append(kDiginotarFile));
1962  scoped_refptr<SSLCertRequestInfo> request_info = GetCertRequest(ssl_options);
1963  ASSERT_TRUE(request_info.get());
1964  ASSERT_EQ(2u, request_info->cert_authorities.size());
1965  EXPECT_EQ(std::string(reinterpret_cast<const char*>(kThawteDN), kThawteLen),
1966            request_info->cert_authorities[0]);
1967  EXPECT_EQ(
1968      std::string(reinterpret_cast<const char*>(kDiginotarDN), kDiginotarLen),
1969      request_info->cert_authorities[1]);
1970}
1971
1972TEST_F(SSLClientSocketTest, ConnectSignedCertTimestampsEnabledTLSExtension) {
1973  SpawnedTestServer::SSLOptions ssl_options;
1974  ssl_options.signed_cert_timestamps_tls_ext = "test";
1975
1976  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
1977                                ssl_options,
1978                                base::FilePath());
1979  ASSERT_TRUE(test_server.Start());
1980
1981  AddressList addr;
1982  ASSERT_TRUE(test_server.GetAddressList(&addr));
1983
1984  TestCompletionCallback callback;
1985  CapturingNetLog log;
1986  scoped_ptr<StreamSocket> transport(
1987      new TCPClientSocket(addr, &log, NetLog::Source()));
1988  int rv = transport->Connect(callback.callback());
1989  if (rv == ERR_IO_PENDING)
1990    rv = callback.WaitForResult();
1991  EXPECT_EQ(OK, rv);
1992
1993  SSLConfig ssl_config;
1994  ssl_config.signed_cert_timestamps_enabled = true;
1995
1996  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
1997      transport.Pass(), test_server.host_port_pair(), ssl_config));
1998
1999  EXPECT_FALSE(sock->IsConnected());
2000
2001  rv = sock->Connect(callback.callback());
2002
2003  CapturingNetLog::CapturedEntryList entries;
2004  log.GetEntries(&entries);
2005  EXPECT_TRUE(LogContainsBeginEvent(entries, 5, NetLog::TYPE_SSL_CONNECT));
2006  if (rv == ERR_IO_PENDING)
2007    rv = callback.WaitForResult();
2008  EXPECT_EQ(OK, rv);
2009  EXPECT_TRUE(sock->IsConnected());
2010  log.GetEntries(&entries);
2011  EXPECT_TRUE(LogContainsSSLConnectEndEvent(entries, -1));
2012
2013#if !defined(USE_OPENSSL)
2014  EXPECT_TRUE(sock->signed_cert_timestamps_received_);
2015#else
2016  // Enabling CT for OpenSSL is currently a noop.
2017  EXPECT_FALSE(sock->signed_cert_timestamps_received_);
2018#endif
2019
2020  sock->Disconnect();
2021  EXPECT_FALSE(sock->IsConnected());
2022}
2023
2024// Test that enabling Signed Certificate Timestamps enables OCSP stapling.
2025TEST_F(SSLClientSocketTest, ConnectSignedCertTimestampsEnabledOCSP) {
2026  SpawnedTestServer::SSLOptions ssl_options;
2027  ssl_options.staple_ocsp_response = true;
2028  // The test server currently only knows how to generate OCSP responses
2029  // for a freshly minted certificate.
2030  ssl_options.server_certificate = SpawnedTestServer::SSLOptions::CERT_AUTO;
2031
2032  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
2033                                ssl_options,
2034                                base::FilePath());
2035  ASSERT_TRUE(test_server.Start());
2036
2037  AddressList addr;
2038  ASSERT_TRUE(test_server.GetAddressList(&addr));
2039
2040  TestCompletionCallback callback;
2041  CapturingNetLog log;
2042  scoped_ptr<StreamSocket> transport(
2043      new TCPClientSocket(addr, &log, NetLog::Source()));
2044  int rv = transport->Connect(callback.callback());
2045  if (rv == ERR_IO_PENDING)
2046    rv = callback.WaitForResult();
2047  EXPECT_EQ(OK, rv);
2048
2049  SSLConfig ssl_config;
2050  // Enabling Signed Cert Timestamps ensures we request OCSP stapling for
2051  // Certificate Transparency verification regardless of whether the platform
2052  // is able to process the OCSP status itself.
2053  ssl_config.signed_cert_timestamps_enabled = true;
2054
2055  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
2056      transport.Pass(), test_server.host_port_pair(), ssl_config));
2057
2058  EXPECT_FALSE(sock->IsConnected());
2059
2060  rv = sock->Connect(callback.callback());
2061
2062  CapturingNetLog::CapturedEntryList entries;
2063  log.GetEntries(&entries);
2064  EXPECT_TRUE(LogContainsBeginEvent(entries, 5, NetLog::TYPE_SSL_CONNECT));
2065  if (rv == ERR_IO_PENDING)
2066    rv = callback.WaitForResult();
2067  EXPECT_EQ(OK, rv);
2068  EXPECT_TRUE(sock->IsConnected());
2069  log.GetEntries(&entries);
2070  EXPECT_TRUE(LogContainsSSLConnectEndEvent(entries, -1));
2071
2072#if !defined(USE_OPENSSL)
2073  EXPECT_TRUE(sock->stapled_ocsp_response_received_);
2074#else
2075  // OCSP stapling isn't currently supported in the OpenSSL socket.
2076  EXPECT_FALSE(sock->stapled_ocsp_response_received_);
2077#endif
2078
2079  sock->Disconnect();
2080  EXPECT_FALSE(sock->IsConnected());
2081}
2082
2083TEST_F(SSLClientSocketTest, ConnectSignedCertTimestampsDisabled) {
2084  SpawnedTestServer::SSLOptions ssl_options;
2085  ssl_options.signed_cert_timestamps_tls_ext = "test";
2086
2087  SpawnedTestServer test_server(SpawnedTestServer::TYPE_HTTPS,
2088                                ssl_options,
2089                                base::FilePath());
2090  ASSERT_TRUE(test_server.Start());
2091
2092  AddressList addr;
2093  ASSERT_TRUE(test_server.GetAddressList(&addr));
2094
2095  TestCompletionCallback callback;
2096  CapturingNetLog log;
2097  scoped_ptr<StreamSocket> transport(
2098      new TCPClientSocket(addr, &log, NetLog::Source()));
2099  int rv = transport->Connect(callback.callback());
2100  if (rv == ERR_IO_PENDING)
2101    rv = callback.WaitForResult();
2102  EXPECT_EQ(OK, rv);
2103
2104  SSLConfig ssl_config;
2105  ssl_config.signed_cert_timestamps_enabled = false;
2106
2107  scoped_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
2108      transport.Pass(), test_server.host_port_pair(), ssl_config));
2109
2110  EXPECT_FALSE(sock->IsConnected());
2111
2112  rv = sock->Connect(callback.callback());
2113
2114  CapturingNetLog::CapturedEntryList entries;
2115  log.GetEntries(&entries);
2116  EXPECT_TRUE(LogContainsBeginEvent(entries, 5, NetLog::TYPE_SSL_CONNECT));
2117  if (rv == ERR_IO_PENDING)
2118    rv = callback.WaitForResult();
2119  EXPECT_EQ(OK, rv);
2120  EXPECT_TRUE(sock->IsConnected());
2121  log.GetEntries(&entries);
2122  EXPECT_TRUE(LogContainsSSLConnectEndEvent(entries, -1));
2123
2124  EXPECT_FALSE(sock->signed_cert_timestamps_received_);
2125
2126  sock->Disconnect();
2127  EXPECT_FALSE(sock->IsConnected());
2128}
2129
2130}  // namespace net
2131