| 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 46f4e40c0d453e72aea9858a166bccb33f0ed0d4..605af728c5c514b2b9c4cb5fd43fadd9632672c7 100644
|
| --- a/net/socket/client_socket_pool_base_unittest.cc
|
| +++ b/net/socket/client_socket_pool_base_unittest.cc
|
| @@ -116,14 +116,26 @@ class MockClientSocket : public StreamSocket {
|
| public:
|
| explicit MockClientSocket(net::NetLog* net_log)
|
| : connected_(false),
|
| + has_unread_data_(false),
|
| net_log_(BoundNetLog::Make(net_log, net::NetLog::SOURCE_SOCKET)),
|
| was_used_to_convey_data_(false) {
|
| }
|
|
|
| + // Sets whether the socket has unread data. If true, the next call to Read()
|
| + // will return 1 byte and IsConnectedAndIdle() will return false.
|
| + void set_has_unread_data(bool has_unread_data) {
|
| + has_unread_data_ = has_unread_data;
|
| + }
|
| +
|
| // Socket implementation.
|
| virtual int Read(
|
| IOBuffer* /* buf */, int len,
|
| const CompletionCallback& /* callback */) OVERRIDE {
|
| + if (has_unread_data_ && len > 0) {
|
| + has_unread_data_ = false;
|
| + was_used_to_convey_data_ = true;
|
| + return 1;
|
| + }
|
| return ERR_UNEXPECTED;
|
| }
|
|
|
| @@ -144,7 +156,9 @@ class MockClientSocket : public StreamSocket {
|
|
|
| virtual void Disconnect() OVERRIDE { connected_ = false; }
|
| virtual bool IsConnected() const OVERRIDE { return connected_; }
|
| - virtual bool IsConnectedAndIdle() const OVERRIDE { return connected_; }
|
| + virtual bool IsConnectedAndIdle() const OVERRIDE {
|
| + return connected_ && !has_unread_data_;
|
| + }
|
|
|
| virtual int GetPeerAddress(IPEndPoint* /* address */) const OVERRIDE {
|
| return ERR_UNEXPECTED;
|
| @@ -176,6 +190,7 @@ class MockClientSocket : public StreamSocket {
|
|
|
| private:
|
| bool connected_;
|
| + bool has_unread_data_;
|
| BoundNetLog net_log_;
|
| bool was_used_to_convey_data_;
|
|
|
| @@ -245,6 +260,7 @@ class TestConnectJob : public ConnectJob {
|
| kMockPendingRecoverableJob,
|
| kMockAdditionalErrorStateJob,
|
| kMockPendingAdditionalErrorStateJob,
|
| + kMockUnreadDataJob,
|
| };
|
|
|
| // The kMockPendingJob uses a slight delay before allowing the connect
|
| @@ -372,6 +388,12 @@ class TestConnectJob : public ConnectJob {
|
| false /* recoverable */),
|
| base::TimeDelta::FromMilliseconds(2));
|
| return ERR_IO_PENDING;
|
| + case kMockUnreadDataJob: {
|
| + int ret = DoConnect(true /* successful */, false /* sync */,
|
| + false /* recoverable */);
|
| + static_cast<MockClientSocket*>(socket())->set_has_unread_data(true);
|
| + return ret;
|
| + }
|
| default:
|
| NOTREACHED();
|
| SetSocket(scoped_ptr<StreamSocket>());
|
| @@ -3541,7 +3563,7 @@ TEST_F(ClientSocketPoolBaseTest, PreconnectJobsTakenByNormalRequests) {
|
|
|
| ASSERT_EQ(OK, callback1.WaitForResult());
|
|
|
| - // Make sure if a preconneced socket is not fully connected when a request
|
| + // Make sure if a preconnected socket is not fully connected when a request
|
| // starts, it has a connect start time.
|
| TestLoadTimingInfoConnectedNotReused(handle1);
|
| handle1.Reset();
|
| @@ -3720,6 +3742,46 @@ TEST_F(ClientSocketPoolBaseTest, PreconnectWithBackupJob) {
|
| EXPECT_EQ(1, pool_->NumActiveSocketsInGroup("a"));
|
| }
|
|
|
| +// Tests that a preconnect that starts out with unread data can still be used.
|
| +// http://crbug.com/334467
|
| +TEST_F(ClientSocketPoolBaseTest, PreconnectWithUnreadData) {
|
| + CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
|
| + connect_job_factory_->set_job_type(TestConnectJob::kMockUnreadDataJob);
|
| +
|
| + pool_->RequestSockets("a", ¶ms_, 1, BoundNetLog());
|
| +
|
| + ASSERT_TRUE(pool_->HasGroup("a"));
|
| + EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
|
| + EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
|
| + EXPECT_EQ(1, pool_->IdleSocketCountInGroup("a"));
|
| +
|
| + // Fail future jobs to be sure that handle receives the preconnected socket
|
| + // rather than closing it and making a new one.
|
| + connect_job_factory_->set_job_type(TestConnectJob::kMockFailingJob);
|
| + ClientSocketHandle handle;
|
| + TestCompletionCallback callback;
|
| + EXPECT_EQ(OK, handle.Init("a",
|
| + params_,
|
| + DEFAULT_PRIORITY,
|
| + callback.callback(),
|
| + pool_.get(),
|
| + BoundNetLog()));
|
| +
|
| + ASSERT_TRUE(pool_->HasGroup("a"));
|
| + EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
|
| + EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
|
| + EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
|
| +
|
| + // Drain the pending read.
|
| + EXPECT_EQ(1, handle.socket()->Read(NULL, 1, CompletionCallback()));
|
| +
|
| + TestLoadTimingInfoConnectedReused(handle);
|
| + handle.Reset();
|
| +
|
| + // The socket should be usable now that it's idle again.
|
| + EXPECT_EQ(1, pool_->IdleSocketCountInGroup("a"));
|
| +}
|
| +
|
| class MockLayeredPool : public HigherLayeredPool {
|
| public:
|
| MockLayeredPool(TestClientSocketPool* pool,
|
|
|