OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/socket/client_socket_pool_base.h" | 5 #include "net/socket/client_socket_pool_base.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
109 ~TestSocketParams() {} | 109 ~TestSocketParams() {} |
110 | 110 |
111 const bool ignore_limits_; | 111 const bool ignore_limits_; |
112 }; | 112 }; |
113 typedef ClientSocketPoolBase<TestSocketParams> TestClientSocketPoolBase; | 113 typedef ClientSocketPoolBase<TestSocketParams> TestClientSocketPoolBase; |
114 | 114 |
115 class MockClientSocket : public StreamSocket { | 115 class MockClientSocket : public StreamSocket { |
116 public: | 116 public: |
117 explicit MockClientSocket(net::NetLog* net_log) | 117 explicit MockClientSocket(net::NetLog* net_log) |
118 : connected_(false), | 118 : connected_(false), |
| 119 has_unread_data_(false), |
119 net_log_(BoundNetLog::Make(net_log, net::NetLog::SOURCE_SOCKET)), | 120 net_log_(BoundNetLog::Make(net_log, net::NetLog::SOURCE_SOCKET)), |
120 was_used_to_convey_data_(false) { | 121 was_used_to_convey_data_(false) { |
121 } | 122 } |
122 | 123 |
| 124 // Sets whether the socket has unread data. If true, the next call to Read() |
| 125 // will return 1 byte and IsConnectedAndIdle() will return false. |
| 126 void set_has_unread_data(bool has_unread_data) { |
| 127 has_unread_data_ = has_unread_data; |
| 128 } |
| 129 |
123 // Socket implementation. | 130 // Socket implementation. |
124 virtual int Read( | 131 virtual int Read( |
125 IOBuffer* /* buf */, int len, | 132 IOBuffer* /* buf */, int len, |
126 const CompletionCallback& /* callback */) OVERRIDE { | 133 const CompletionCallback& /* callback */) OVERRIDE { |
| 134 if (has_unread_data_ && len > 0) { |
| 135 has_unread_data_ = false; |
| 136 was_used_to_convey_data_ = true; |
| 137 return 1; |
| 138 } |
127 return ERR_UNEXPECTED; | 139 return ERR_UNEXPECTED; |
128 } | 140 } |
129 | 141 |
130 virtual int Write( | 142 virtual int Write( |
131 IOBuffer* /* buf */, int len, | 143 IOBuffer* /* buf */, int len, |
132 const CompletionCallback& /* callback */) OVERRIDE { | 144 const CompletionCallback& /* callback */) OVERRIDE { |
133 was_used_to_convey_data_ = true; | 145 was_used_to_convey_data_ = true; |
134 return len; | 146 return len; |
135 } | 147 } |
136 virtual bool SetReceiveBufferSize(int32 size) OVERRIDE { return true; } | 148 virtual bool SetReceiveBufferSize(int32 size) OVERRIDE { return true; } |
137 virtual bool SetSendBufferSize(int32 size) OVERRIDE { return true; } | 149 virtual bool SetSendBufferSize(int32 size) OVERRIDE { return true; } |
138 | 150 |
139 // StreamSocket implementation. | 151 // StreamSocket implementation. |
140 virtual int Connect(const CompletionCallback& callback) OVERRIDE { | 152 virtual int Connect(const CompletionCallback& callback) OVERRIDE { |
141 connected_ = true; | 153 connected_ = true; |
142 return OK; | 154 return OK; |
143 } | 155 } |
144 | 156 |
145 virtual void Disconnect() OVERRIDE { connected_ = false; } | 157 virtual void Disconnect() OVERRIDE { connected_ = false; } |
146 virtual bool IsConnected() const OVERRIDE { return connected_; } | 158 virtual bool IsConnected() const OVERRIDE { return connected_; } |
147 virtual bool IsConnectedAndIdle() const OVERRIDE { return connected_; } | 159 virtual bool IsConnectedAndIdle() const OVERRIDE { |
| 160 return connected_ && !has_unread_data_; |
| 161 } |
148 | 162 |
149 virtual int GetPeerAddress(IPEndPoint* /* address */) const OVERRIDE { | 163 virtual int GetPeerAddress(IPEndPoint* /* address */) const OVERRIDE { |
150 return ERR_UNEXPECTED; | 164 return ERR_UNEXPECTED; |
151 } | 165 } |
152 | 166 |
153 virtual int GetLocalAddress(IPEndPoint* /* address */) const OVERRIDE { | 167 virtual int GetLocalAddress(IPEndPoint* /* address */) const OVERRIDE { |
154 return ERR_UNEXPECTED; | 168 return ERR_UNEXPECTED; |
155 } | 169 } |
156 | 170 |
157 virtual const BoundNetLog& NetLog() const OVERRIDE { | 171 virtual const BoundNetLog& NetLog() const OVERRIDE { |
(...skipping 11 matching lines...) Expand all Loading... |
169 } | 183 } |
170 virtual NextProto GetNegotiatedProtocol() const OVERRIDE { | 184 virtual NextProto GetNegotiatedProtocol() const OVERRIDE { |
171 return kProtoUnknown; | 185 return kProtoUnknown; |
172 } | 186 } |
173 virtual bool GetSSLInfo(SSLInfo* ssl_info) OVERRIDE { | 187 virtual bool GetSSLInfo(SSLInfo* ssl_info) OVERRIDE { |
174 return false; | 188 return false; |
175 } | 189 } |
176 | 190 |
177 private: | 191 private: |
178 bool connected_; | 192 bool connected_; |
| 193 bool has_unread_data_; |
179 BoundNetLog net_log_; | 194 BoundNetLog net_log_; |
180 bool was_used_to_convey_data_; | 195 bool was_used_to_convey_data_; |
181 | 196 |
182 DISALLOW_COPY_AND_ASSIGN(MockClientSocket); | 197 DISALLOW_COPY_AND_ASSIGN(MockClientSocket); |
183 }; | 198 }; |
184 | 199 |
185 class TestConnectJob; | 200 class TestConnectJob; |
186 | 201 |
187 class MockClientSocketFactory : public ClientSocketFactory { | 202 class MockClientSocketFactory : public ClientSocketFactory { |
188 public: | 203 public: |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
238 enum JobType { | 253 enum JobType { |
239 kMockJob, | 254 kMockJob, |
240 kMockFailingJob, | 255 kMockFailingJob, |
241 kMockPendingJob, | 256 kMockPendingJob, |
242 kMockPendingFailingJob, | 257 kMockPendingFailingJob, |
243 kMockWaitingJob, | 258 kMockWaitingJob, |
244 kMockRecoverableJob, | 259 kMockRecoverableJob, |
245 kMockPendingRecoverableJob, | 260 kMockPendingRecoverableJob, |
246 kMockAdditionalErrorStateJob, | 261 kMockAdditionalErrorStateJob, |
247 kMockPendingAdditionalErrorStateJob, | 262 kMockPendingAdditionalErrorStateJob, |
| 263 kMockUnreadDataJob, |
248 }; | 264 }; |
249 | 265 |
250 // The kMockPendingJob uses a slight delay before allowing the connect | 266 // The kMockPendingJob uses a slight delay before allowing the connect |
251 // to complete. | 267 // to complete. |
252 static const int kPendingConnectDelay = 2; | 268 static const int kPendingConnectDelay = 2; |
253 | 269 |
254 TestConnectJob(JobType job_type, | 270 TestConnectJob(JobType job_type, |
255 const std::string& group_name, | 271 const std::string& group_name, |
256 const TestClientSocketPoolBase::Request& request, | 272 const TestClientSocketPoolBase::Request& request, |
257 base::TimeDelta timeout_duration, | 273 base::TimeDelta timeout_duration, |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
365 store_additional_error_state_ = true; | 381 store_additional_error_state_ = true; |
366 base::MessageLoop::current()->PostDelayedTask( | 382 base::MessageLoop::current()->PostDelayedTask( |
367 FROM_HERE, | 383 FROM_HERE, |
368 base::Bind(base::IgnoreResult(&TestConnectJob::DoConnect), | 384 base::Bind(base::IgnoreResult(&TestConnectJob::DoConnect), |
369 weak_factory_.GetWeakPtr(), | 385 weak_factory_.GetWeakPtr(), |
370 false /* error */, | 386 false /* error */, |
371 true /* async */, | 387 true /* async */, |
372 false /* recoverable */), | 388 false /* recoverable */), |
373 base::TimeDelta::FromMilliseconds(2)); | 389 base::TimeDelta::FromMilliseconds(2)); |
374 return ERR_IO_PENDING; | 390 return ERR_IO_PENDING; |
| 391 case kMockUnreadDataJob: { |
| 392 int ret = DoConnect(true /* successful */, false /* sync */, |
| 393 false /* recoverable */); |
| 394 static_cast<MockClientSocket*>(socket())->set_has_unread_data(true); |
| 395 return ret; |
| 396 } |
375 default: | 397 default: |
376 NOTREACHED(); | 398 NOTREACHED(); |
377 SetSocket(scoped_ptr<StreamSocket>()); | 399 SetSocket(scoped_ptr<StreamSocket>()); |
378 return ERR_FAILED; | 400 return ERR_FAILED; |
379 } | 401 } |
380 } | 402 } |
381 | 403 |
382 int DoConnect(bool succeed, bool was_async, bool recoverable) { | 404 int DoConnect(bool succeed, bool was_async, bool recoverable) { |
383 int result = OK; | 405 int result = OK; |
384 if (succeed) { | 406 if (succeed) { |
(...skipping 3149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3534 callback1.callback(), | 3556 callback1.callback(), |
3535 pool_.get(), | 3557 pool_.get(), |
3536 BoundNetLog())); | 3558 BoundNetLog())); |
3537 | 3559 |
3538 EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a")); | 3560 EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a")); |
3539 EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a")); | 3561 EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a")); |
3540 EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a")); | 3562 EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a")); |
3541 | 3563 |
3542 ASSERT_EQ(OK, callback1.WaitForResult()); | 3564 ASSERT_EQ(OK, callback1.WaitForResult()); |
3543 | 3565 |
3544 // Make sure if a preconneced socket is not fully connected when a request | 3566 // Make sure if a preconnected socket is not fully connected when a request |
3545 // starts, it has a connect start time. | 3567 // starts, it has a connect start time. |
3546 TestLoadTimingInfoConnectedNotReused(handle1); | 3568 TestLoadTimingInfoConnectedNotReused(handle1); |
3547 handle1.Reset(); | 3569 handle1.Reset(); |
3548 | 3570 |
3549 EXPECT_EQ(1, pool_->IdleSocketCountInGroup("a")); | 3571 EXPECT_EQ(1, pool_->IdleSocketCountInGroup("a")); |
3550 } | 3572 } |
3551 | 3573 |
3552 // Checks that fully connected preconnect jobs have no connect times, and are | 3574 // Checks that fully connected preconnect jobs have no connect times, and are |
3553 // marked as reused. | 3575 // marked as reused. |
3554 TEST_F(ClientSocketPoolBaseTest, ConnectedPreconnectJobsHaveNoConnectTimes) { | 3576 TEST_F(ClientSocketPoolBaseTest, ConnectedPreconnectJobsHaveNoConnectTimes) { |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3713 ASSERT_EQ(OK, callback.WaitForResult()); | 3735 ASSERT_EQ(OK, callback.WaitForResult()); |
3714 | 3736 |
3715 // The hung connect job should still be there, but everything else should be | 3737 // The hung connect job should still be there, but everything else should be |
3716 // complete. | 3738 // complete. |
3717 EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a")); | 3739 EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a")); |
3718 EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a")); | 3740 EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a")); |
3719 EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a")); | 3741 EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a")); |
3720 EXPECT_EQ(1, pool_->NumActiveSocketsInGroup("a")); | 3742 EXPECT_EQ(1, pool_->NumActiveSocketsInGroup("a")); |
3721 } | 3743 } |
3722 | 3744 |
| 3745 // Tests that a preconnect that starts out with unread data can still be used. |
| 3746 // http://crbug.com/334467 |
| 3747 TEST_F(ClientSocketPoolBaseTest, PreconnectWithUnreadData) { |
| 3748 CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup); |
| 3749 connect_job_factory_->set_job_type(TestConnectJob::kMockUnreadDataJob); |
| 3750 |
| 3751 pool_->RequestSockets("a", ¶ms_, 1, BoundNetLog()); |
| 3752 |
| 3753 ASSERT_TRUE(pool_->HasGroup("a")); |
| 3754 EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a")); |
| 3755 EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a")); |
| 3756 EXPECT_EQ(1, pool_->IdleSocketCountInGroup("a")); |
| 3757 |
| 3758 // Fail future jobs to be sure that handle receives the preconnected socket |
| 3759 // rather than closing it and making a new one. |
| 3760 connect_job_factory_->set_job_type(TestConnectJob::kMockFailingJob); |
| 3761 ClientSocketHandle handle; |
| 3762 TestCompletionCallback callback; |
| 3763 EXPECT_EQ(OK, handle.Init("a", |
| 3764 params_, |
| 3765 DEFAULT_PRIORITY, |
| 3766 callback.callback(), |
| 3767 pool_.get(), |
| 3768 BoundNetLog())); |
| 3769 |
| 3770 ASSERT_TRUE(pool_->HasGroup("a")); |
| 3771 EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a")); |
| 3772 EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a")); |
| 3773 EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a")); |
| 3774 |
| 3775 // Drain the pending read. |
| 3776 EXPECT_EQ(1, handle.socket()->Read(NULL, 1, CompletionCallback())); |
| 3777 |
| 3778 TestLoadTimingInfoConnectedReused(handle); |
| 3779 handle.Reset(); |
| 3780 |
| 3781 // The socket should be usable now that it's idle again. |
| 3782 EXPECT_EQ(1, pool_->IdleSocketCountInGroup("a")); |
| 3783 } |
| 3784 |
3723 class MockLayeredPool : public HigherLayeredPool { | 3785 class MockLayeredPool : public HigherLayeredPool { |
3724 public: | 3786 public: |
3725 MockLayeredPool(TestClientSocketPool* pool, | 3787 MockLayeredPool(TestClientSocketPool* pool, |
3726 const std::string& group_name) | 3788 const std::string& group_name) |
3727 : pool_(pool), | 3789 : pool_(pool), |
3728 group_name_(group_name), | 3790 group_name_(group_name), |
3729 can_release_connection_(true) { | 3791 can_release_connection_(true) { |
3730 pool_->AddHigherLayeredPool(this); | 3792 pool_->AddHigherLayeredPool(this); |
3731 } | 3793 } |
3732 | 3794 |
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4058 request(1)->handle()->Reset(); | 4120 request(1)->handle()->Reset(); |
4059 ASSERT_EQ(1, pool_->NumConnectJobsInGroup("a")); | 4121 ASSERT_EQ(1, pool_->NumConnectJobsInGroup("a")); |
4060 | 4122 |
4061 EXPECT_EQ(OK, request(2)->WaitForResult()); | 4123 EXPECT_EQ(OK, request(2)->WaitForResult()); |
4062 EXPECT_FALSE(request(1)->have_result()); | 4124 EXPECT_FALSE(request(1)->have_result()); |
4063 } | 4125 } |
4064 | 4126 |
4065 } // namespace | 4127 } // namespace |
4066 | 4128 |
4067 } // namespace net | 4129 } // namespace net |
OLD | NEW |