| Index: net/socket/client_socket_pool_base_unittest.cc
 | 
| diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc
 | 
| index 33db24fa21d0db42debe74d9717e8254aebc19db..3a6b8936ab4f6c2c946553038db1d56a978370d2 100644
 | 
| --- a/net/socket/client_socket_pool_base_unittest.cc
 | 
| +++ b/net/socket/client_socket_pool_base_unittest.cc
 | 
| @@ -94,7 +94,7 @@ class MockClientSocketFactory : public ClientSocketFactory {
 | 
|    }
 | 
|  
 | 
|    virtual SSLClientSocket* CreateSSLClientSocket(
 | 
| -      ClientSocket* transport_socket,
 | 
| +      ClientSocketHandle* transport_socket,
 | 
|        const std::string& hostname,
 | 
|        const SSLConfig& ssl_config) {
 | 
|      NOTIMPLEMENTED();
 | 
| @@ -122,6 +122,8 @@ class TestConnectJob : public ConnectJob {
 | 
|      kMockAdvancingLoadStateJob,
 | 
|      kMockRecoverableJob,
 | 
|      kMockPendingRecoverableJob,
 | 
| +    kMockAdditionalErrorStateJob,
 | 
| +    kMockPendingAdditionalErrorStateJob,
 | 
|    };
 | 
|  
 | 
|    TestConnectJob(JobType job_type,
 | 
| @@ -136,7 +138,8 @@ class TestConnectJob : public ConnectJob {
 | 
|          job_type_(job_type),
 | 
|          client_socket_factory_(client_socket_factory),
 | 
|          method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
 | 
| -        load_state_(LOAD_STATE_IDLE) {}
 | 
| +        load_state_(LOAD_STATE_IDLE),
 | 
| +        store_additional_error_state_(false) {}
 | 
|  
 | 
|    void Signal() {
 | 
|      DoConnect(waiting_success_, true /* async */, false /* recoverable */);
 | 
| @@ -144,6 +147,15 @@ class TestConnectJob : public ConnectJob {
 | 
|  
 | 
|    virtual LoadState GetLoadState() const { return load_state_; }
 | 
|  
 | 
| +  virtual void GetAdditionalErrorState(ClientSocketHandle* handle) {
 | 
| +    if (store_additional_error_state_) {
 | 
| +      // Set all of the additional error state fields in some way.
 | 
| +      handle->set_is_ssl_error(true);
 | 
| +      scoped_refptr<HttpResponseHeaders> headers(new HttpResponseHeaders(""));
 | 
| +      handle->set_tunnel_auth_response_info(headers, NULL);
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
|   private:
 | 
|    // ConnectJob methods:
 | 
|  
 | 
| @@ -216,6 +228,22 @@ class TestConnectJob : public ConnectJob {
 | 
|                  true  /* recoverable */),
 | 
|              2);
 | 
|          return ERR_IO_PENDING;
 | 
| +      case kMockAdditionalErrorStateJob:
 | 
| +        store_additional_error_state_ = true;
 | 
| +        return DoConnect(false /* error */, false /* sync */,
 | 
| +                         false /* recoverable */);
 | 
| +      case kMockPendingAdditionalErrorStateJob:
 | 
| +        set_load_state(LOAD_STATE_CONNECTING);
 | 
| +        store_additional_error_state_ = true;
 | 
| +        MessageLoop::current()->PostDelayedTask(
 | 
| +            FROM_HERE,
 | 
| +            method_factory_.NewRunnableMethod(
 | 
| +                &TestConnectJob::DoConnect,
 | 
| +                false /* error */,
 | 
| +                true  /* async */,
 | 
| +                false /* recoverable */),
 | 
| +            2);
 | 
| +        return ERR_IO_PENDING;
 | 
|        default:
 | 
|          NOTREACHED();
 | 
|          set_socket(NULL);
 | 
| @@ -263,6 +291,7 @@ class TestConnectJob : public ConnectJob {
 | 
|    MockClientSocketFactory* const client_socket_factory_;
 | 
|    ScopedRunnableMethodFactory<TestConnectJob> method_factory_;
 | 
|    LoadState load_state_;
 | 
| +  bool store_additional_error_state_;
 | 
|  
 | 
|    DISALLOW_COPY_AND_ASSIGN(TestConnectJob);
 | 
|  };
 | 
| @@ -589,10 +618,16 @@ TEST_F(ClientSocketPoolBaseTest, InitConnectionFailure) {
 | 
|    CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
 | 
|  
 | 
|    TestSocketRequest req(&request_order_, &completion_count_);
 | 
| +  // Set the additional error state members to ensure that they get cleared.
 | 
| +  req.handle()->set_is_ssl_error(true);
 | 
| +  scoped_refptr<HttpResponseHeaders> headers(new HttpResponseHeaders(""));
 | 
| +  req.handle()->set_tunnel_auth_response_info(headers, NULL);
 | 
|    EXPECT_EQ(ERR_CONNECTION_FAILED, req.handle()->Init("a", params_,
 | 
|                                                        kDefaultPriority, &req,
 | 
|                                                        pool_, log.bound()));
 | 
|    EXPECT_FALSE(req.handle()->socket());
 | 
| +  EXPECT_FALSE(req.handle()->is_ssl_error());
 | 
| +  EXPECT_TRUE(req.handle()->tunnel_auth_response_info().headers.get() == NULL);
 | 
|  
 | 
|    EXPECT_EQ(3u, log.entries().size());
 | 
|    EXPECT_TRUE(LogContainsBeginEvent(
 | 
| @@ -1345,10 +1380,16 @@ TEST_F(ClientSocketPoolBaseTest,
 | 
|    connect_job_factory_->set_job_type(TestConnectJob::kMockPendingFailingJob);
 | 
|    TestSocketRequest req(&request_order_, &completion_count_);
 | 
|    CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
 | 
| +  // Set the additional error state members to ensure that they get cleared.
 | 
| +  req.handle()->set_is_ssl_error(true);
 | 
| +  scoped_refptr<HttpResponseHeaders> headers(new HttpResponseHeaders(""));
 | 
| +  req.handle()->set_tunnel_auth_response_info(headers, NULL);
 | 
|    EXPECT_EQ(ERR_IO_PENDING, req.handle()->Init("a", params_, kDefaultPriority,
 | 
|                                                 &req, pool_, log.bound()));
 | 
|    EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", req.handle()));
 | 
|    EXPECT_EQ(ERR_CONNECTION_FAILED, req.WaitForResult());
 | 
| +  EXPECT_FALSE(req.handle()->is_ssl_error());
 | 
| +  EXPECT_TRUE(req.handle()->tunnel_auth_response_info().headers.get() == NULL);
 | 
|  
 | 
|    EXPECT_EQ(3u, log.entries().size());
 | 
|    EXPECT_TRUE(LogContainsBeginEvent(
 | 
| @@ -1541,6 +1582,39 @@ TEST_F(ClientSocketPoolBaseTest, AsyncRecoverable) {
 | 
|    req.handle()->Reset();
 | 
|  }
 | 
|  
 | 
| +TEST_F(ClientSocketPoolBaseTest, AdditionalErrorStateSynchronous) {
 | 
| +  CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
 | 
| +  connect_job_factory_->set_job_type(
 | 
| +      TestConnectJob::kMockAdditionalErrorStateJob);
 | 
| +
 | 
| +  TestSocketRequest req(&request_order_, &completion_count_);
 | 
| +  EXPECT_EQ(ERR_CONNECTION_FAILED, req.handle()->Init("a", params_,
 | 
| +                                                      kDefaultPriority, &req,
 | 
| +                                                      pool_, BoundNetLog()));
 | 
| +  EXPECT_FALSE(req.handle()->is_initialized());
 | 
| +  EXPECT_FALSE(req.handle()->socket());
 | 
| +  EXPECT_TRUE(req.handle()->is_ssl_error());
 | 
| +  EXPECT_FALSE(req.handle()->tunnel_auth_response_info().headers.get() == NULL);
 | 
| +  req.handle()->Reset();
 | 
| +}
 | 
| +
 | 
| +TEST_F(ClientSocketPoolBaseTest, AdditionalErrorStateAsynchronous) {
 | 
| +  CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
 | 
| +
 | 
| +  connect_job_factory_->set_job_type(
 | 
| +      TestConnectJob::kMockPendingAdditionalErrorStateJob);
 | 
| +  TestSocketRequest req(&request_order_, &completion_count_);
 | 
| +  EXPECT_EQ(ERR_IO_PENDING, req.handle()->Init("a", params_, kDefaultPriority,
 | 
| +                                               &req, pool_, BoundNetLog()));
 | 
| +  EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", req.handle()));
 | 
| +  EXPECT_EQ(ERR_CONNECTION_FAILED, req.WaitForResult());
 | 
| +  EXPECT_FALSE(req.handle()->is_initialized());
 | 
| +  EXPECT_FALSE(req.handle()->socket());
 | 
| +  EXPECT_TRUE(req.handle()->is_ssl_error());
 | 
| +  EXPECT_FALSE(req.handle()->tunnel_auth_response_info().headers.get() == NULL);
 | 
| +  req.handle()->Reset();
 | 
| +}
 | 
| +
 | 
|  TEST_F(ClientSocketPoolBaseTest, CleanupTimedOutIdleSockets) {
 | 
|    CreatePoolWithIdleTimeouts(
 | 
|        kDefaultMaxSockets, kDefaultMaxSocketsPerGroup,
 | 
| @@ -1728,8 +1802,11 @@ TEST_F(ClientSocketPoolBaseTest,
 | 
|  
 | 
|  class TestReleasingSocketRequest : public CallbackRunner< Tuple1<int> > {
 | 
|   public:
 | 
| -  explicit TestReleasingSocketRequest(TestClientSocketPool* pool)
 | 
| -      : pool_(pool) {}
 | 
| +  TestReleasingSocketRequest(TestClientSocketPool* pool, int expected_result,
 | 
| +                             bool reset_releasing_handle)
 | 
| +      : pool_(pool),
 | 
| +        expected_result_(expected_result),
 | 
| +        reset_releasing_handle_(reset_releasing_handle) {}
 | 
|  
 | 
|    ClientSocketHandle* handle() { return &handle_; }
 | 
|  
 | 
| @@ -1739,20 +1816,50 @@ class TestReleasingSocketRequest : public CallbackRunner< Tuple1<int> > {
 | 
|  
 | 
|    virtual void RunWithParams(const Tuple1<int>& params) {
 | 
|      callback_.RunWithParams(params);
 | 
| -    handle_.Reset();
 | 
| +    if (reset_releasing_handle_)
 | 
| +                      handle_.Reset();
 | 
|      scoped_refptr<TestSocketParams> con_params = new TestSocketParams();
 | 
| -    EXPECT_EQ(ERR_IO_PENDING, handle2_.Init("a", con_params, kDefaultPriority,
 | 
| -                                            &callback2_, pool_, BoundNetLog()));
 | 
| +    EXPECT_EQ(expected_result_, handle2_.Init("a", con_params, kDefaultPriority,
 | 
| +                                              &callback2_, pool_,
 | 
| +                                              BoundNetLog()));
 | 
|    }
 | 
|  
 | 
|   private:
 | 
|    scoped_refptr<TestClientSocketPool> pool_;
 | 
| +  int expected_result_;
 | 
| +  bool reset_releasing_handle_;
 | 
|    ClientSocketHandle handle_;
 | 
|    ClientSocketHandle handle2_;
 | 
|    TestCompletionCallback callback_;
 | 
|    TestCompletionCallback callback2_;
 | 
|  };
 | 
|  
 | 
| +
 | 
| +TEST_F(ClientSocketPoolBaseTest, AdditionalErrorSocketsDontUseSlot) {
 | 
| +  CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
 | 
| +
 | 
| +  EXPECT_EQ(OK, StartRequest("b", kDefaultPriority));
 | 
| +  EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
 | 
| +  EXPECT_EQ(OK, StartRequest("b", kDefaultPriority));
 | 
| +
 | 
| +  EXPECT_EQ(static_cast<int>(requests_.size()),
 | 
| +            client_socket_factory_.allocation_count());
 | 
| +
 | 
| +  connect_job_factory_->set_job_type(
 | 
| +      TestConnectJob::kMockPendingAdditionalErrorStateJob);
 | 
| +  TestReleasingSocketRequest req(pool_.get(), OK, false);
 | 
| +  EXPECT_EQ(ERR_IO_PENDING, req.handle()->Init("a", params_, kDefaultPriority,
 | 
| +                                               &req, pool_, BoundNetLog()));
 | 
| +  // The next job should complete synchronously
 | 
| +  connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
 | 
| +
 | 
| +  EXPECT_EQ(ERR_CONNECTION_FAILED, req.WaitForResult());
 | 
| +  EXPECT_FALSE(req.handle()->is_initialized());
 | 
| +  EXPECT_FALSE(req.handle()->socket());
 | 
| +  EXPECT_TRUE(req.handle()->is_ssl_error());
 | 
| +  EXPECT_FALSE(req.handle()->tunnel_auth_response_info().headers.get() == NULL);
 | 
| +}
 | 
| +
 | 
|  // http://crbug.com/44724 regression test.
 | 
|  // We start releasing the pool when we flush on network change.  When that
 | 
|  // happens, the only active references are in the ClientSocketHandles.  When a
 | 
| 
 |