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
3 // found in the LICENSE file.
5 #include "net/socket/socks_client_socket_pool.h"
7 #include "base/callback.h"
8 #include "base/compiler_specific.h"
9 #include "base/time/time.h"
10 #include "net/base/load_timing_info.h"
11 #include "net/base/load_timing_info_test_util.h"
12 #include "net/base/net_errors.h"
13 #include "net/base/test_completion_callback.h"
14 #include "net/dns/mock_host_resolver.h"
15 #include "net/socket/client_socket_factory.h"
16 #include "net/socket/client_socket_handle.h"
17 #include "net/socket/socket_test_util.h"
18 #include "testing/gtest/include/gtest/gtest.h"
24 const int kMaxSockets
= 32;
25 const int kMaxSocketsPerGroup
= 6;
27 // Make sure |handle|'s load times are set correctly. Only connect times should
29 void TestLoadTimingInfo(const ClientSocketHandle
& handle
) {
30 LoadTimingInfo load_timing_info
;
31 EXPECT_TRUE(handle
.GetLoadTimingInfo(false, &load_timing_info
));
33 // None of these tests use a NetLog.
34 EXPECT_EQ(NetLog::Source::kInvalidId
, load_timing_info
.socket_log_id
);
36 EXPECT_FALSE(load_timing_info
.socket_reused
);
38 ExpectConnectTimingHasTimes(load_timing_info
.connect_timing
,
39 CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY
);
40 ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info
);
44 scoped_refptr
<TransportSocketParams
> CreateProxyHostParams() {
45 return new TransportSocketParams(
46 HostPortPair("proxy", 80), false, false, OnHostResolutionCallback(),
47 TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT
);
50 scoped_refptr
<SOCKSSocketParams
> CreateSOCKSv4Params() {
51 return new SOCKSSocketParams(
52 CreateProxyHostParams(), false /* socks_v5 */,
53 HostPortPair("host", 80));
56 scoped_refptr
<SOCKSSocketParams
> CreateSOCKSv5Params() {
57 return new SOCKSSocketParams(
58 CreateProxyHostParams(), true /* socks_v5 */,
59 HostPortPair("host", 80));
62 class SOCKSClientSocketPoolTest
: public testing::Test
{
64 class SOCKS5MockData
{
66 explicit SOCKS5MockData(IoMode mode
) {
67 writes_
.reset(new MockWrite
[3]);
68 writes_
[0] = MockWrite(mode
, kSOCKS5GreetRequest
,
69 kSOCKS5GreetRequestLength
);
70 writes_
[1] = MockWrite(mode
, kSOCKS5OkRequest
, kSOCKS5OkRequestLength
);
71 writes_
[2] = MockWrite(mode
, 0);
73 reads_
.reset(new MockRead
[3]);
74 reads_
[0] = MockRead(mode
, kSOCKS5GreetResponse
,
75 kSOCKS5GreetResponseLength
);
76 reads_
[1] = MockRead(mode
, kSOCKS5OkResponse
, kSOCKS5OkResponseLength
);
77 reads_
[2] = MockRead(mode
, 0);
79 data_
.reset(new StaticSocketDataProvider(reads_
.get(), 3,
83 SocketDataProvider
* data_provider() { return data_
.get(); }
86 scoped_ptr
<StaticSocketDataProvider
> data_
;
87 scoped_ptr
<MockWrite
[]> writes_
;
88 scoped_ptr
<MockRead
[]> reads_
;
91 SOCKSClientSocketPoolTest()
92 : transport_socket_pool_(kMaxSockets
,
94 &transport_client_socket_factory_
),
98 &transport_socket_pool_
,
101 ~SOCKSClientSocketPoolTest() override
{}
103 int StartRequestV5(const std::string
& group_name
, RequestPriority priority
) {
104 return test_base_
.StartRequestUsingPool(
105 &pool_
, group_name
, priority
, CreateSOCKSv5Params());
108 int GetOrderOfRequest(size_t index
) const {
109 return test_base_
.GetOrderOfRequest(index
);
112 ScopedVector
<TestSocketRequest
>* requests() { return test_base_
.requests(); }
114 MockClientSocketFactory transport_client_socket_factory_
;
115 MockTransportClientSocketPool transport_socket_pool_
;
117 MockHostResolver host_resolver_
;
118 SOCKSClientSocketPool pool_
;
119 ClientSocketPoolTest test_base_
;
122 TEST_F(SOCKSClientSocketPoolTest
, Simple
) {
123 SOCKS5MockData
data(SYNCHRONOUS
);
124 data
.data_provider()->set_connect_data(MockConnect(SYNCHRONOUS
, OK
));
125 transport_client_socket_factory_
.AddSocketDataProvider(data
.data_provider());
127 ClientSocketHandle handle
;
128 int rv
= handle
.Init("a", CreateSOCKSv5Params(), LOW
, CompletionCallback(),
129 &pool_
, BoundNetLog());
131 EXPECT_TRUE(handle
.is_initialized());
132 EXPECT_TRUE(handle
.socket());
133 TestLoadTimingInfo(handle
);
136 // Make sure that SOCKSConnectJob passes on its priority to its
137 // socket request on Init.
138 TEST_F(SOCKSClientSocketPoolTest
, SetSocketRequestPriorityOnInit
) {
139 for (int i
= MINIMUM_PRIORITY
; i
<= MAXIMUM_PRIORITY
; ++i
) {
140 RequestPriority priority
= static_cast<RequestPriority
>(i
);
141 SOCKS5MockData
data(SYNCHRONOUS
);
142 data
.data_provider()->set_connect_data(MockConnect(SYNCHRONOUS
, OK
));
143 transport_client_socket_factory_
.AddSocketDataProvider(
144 data
.data_provider());
146 ClientSocketHandle handle
;
148 handle
.Init("a", CreateSOCKSv5Params(), priority
,
149 CompletionCallback(), &pool_
, BoundNetLog()));
150 EXPECT_EQ(priority
, transport_socket_pool_
.last_request_priority());
151 handle
.socket()->Disconnect();
155 // Make sure that SOCKSConnectJob passes on its priority to its
156 // HostResolver request (for non-SOCKS5) on Init.
157 TEST_F(SOCKSClientSocketPoolTest
, SetResolvePriorityOnInit
) {
158 for (int i
= MINIMUM_PRIORITY
; i
<= MAXIMUM_PRIORITY
; ++i
) {
159 RequestPriority priority
= static_cast<RequestPriority
>(i
);
160 SOCKS5MockData
data(SYNCHRONOUS
);
161 data
.data_provider()->set_connect_data(MockConnect(SYNCHRONOUS
, OK
));
162 transport_client_socket_factory_
.AddSocketDataProvider(
163 data
.data_provider());
165 ClientSocketHandle handle
;
166 EXPECT_EQ(ERR_IO_PENDING
,
167 handle
.Init("a", CreateSOCKSv4Params(), priority
,
168 CompletionCallback(), &pool_
, BoundNetLog()));
169 EXPECT_EQ(priority
, transport_socket_pool_
.last_request_priority());
170 EXPECT_EQ(priority
, host_resolver_
.last_request_priority());
171 EXPECT_TRUE(handle
.socket() == NULL
);
175 TEST_F(SOCKSClientSocketPoolTest
, Async
) {
176 SOCKS5MockData
data(ASYNC
);
177 transport_client_socket_factory_
.AddSocketDataProvider(data
.data_provider());
179 TestCompletionCallback callback
;
180 ClientSocketHandle handle
;
181 int rv
= handle
.Init("a", CreateSOCKSv5Params(), LOW
, callback
.callback(),
182 &pool_
, BoundNetLog());
183 EXPECT_EQ(ERR_IO_PENDING
, rv
);
184 EXPECT_FALSE(handle
.is_initialized());
185 EXPECT_FALSE(handle
.socket());
187 EXPECT_EQ(OK
, callback
.WaitForResult());
188 EXPECT_TRUE(handle
.is_initialized());
189 EXPECT_TRUE(handle
.socket());
190 TestLoadTimingInfo(handle
);
193 TEST_F(SOCKSClientSocketPoolTest
, TransportConnectError
) {
194 StaticSocketDataProvider socket_data
;
195 socket_data
.set_connect_data(MockConnect(SYNCHRONOUS
,
196 ERR_CONNECTION_REFUSED
));
197 transport_client_socket_factory_
.AddSocketDataProvider(&socket_data
);
199 ClientSocketHandle handle
;
200 int rv
= handle
.Init("a", CreateSOCKSv5Params(), LOW
, CompletionCallback(),
201 &pool_
, BoundNetLog());
202 EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED
, rv
);
203 EXPECT_FALSE(handle
.is_initialized());
204 EXPECT_FALSE(handle
.socket());
207 TEST_F(SOCKSClientSocketPoolTest
, AsyncTransportConnectError
) {
208 StaticSocketDataProvider socket_data
;
209 socket_data
.set_connect_data(MockConnect(ASYNC
, ERR_CONNECTION_REFUSED
));
210 transport_client_socket_factory_
.AddSocketDataProvider(&socket_data
);
212 TestCompletionCallback callback
;
213 ClientSocketHandle handle
;
214 int rv
= handle
.Init("a", CreateSOCKSv5Params(), LOW
, callback
.callback(),
215 &pool_
, BoundNetLog());
216 EXPECT_EQ(ERR_IO_PENDING
, rv
);
217 EXPECT_FALSE(handle
.is_initialized());
218 EXPECT_FALSE(handle
.socket());
220 EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED
, callback
.WaitForResult());
221 EXPECT_FALSE(handle
.is_initialized());
222 EXPECT_FALSE(handle
.socket());
225 TEST_F(SOCKSClientSocketPoolTest
, SOCKSConnectError
) {
226 MockRead failed_read
[] = {
227 MockRead(SYNCHRONOUS
, 0),
229 StaticSocketDataProvider
socket_data(
230 failed_read
, arraysize(failed_read
), NULL
, 0);
231 socket_data
.set_connect_data(MockConnect(SYNCHRONOUS
, OK
));
232 transport_client_socket_factory_
.AddSocketDataProvider(&socket_data
);
234 ClientSocketHandle handle
;
235 EXPECT_EQ(0, transport_socket_pool_
.release_count());
236 int rv
= handle
.Init("a", CreateSOCKSv5Params(), LOW
, CompletionCallback(),
237 &pool_
, BoundNetLog());
238 EXPECT_EQ(ERR_SOCKS_CONNECTION_FAILED
, rv
);
239 EXPECT_FALSE(handle
.is_initialized());
240 EXPECT_FALSE(handle
.socket());
241 EXPECT_EQ(1, transport_socket_pool_
.release_count());
244 TEST_F(SOCKSClientSocketPoolTest
, AsyncSOCKSConnectError
) {
245 MockRead failed_read
[] = {
248 StaticSocketDataProvider
socket_data(
249 failed_read
, arraysize(failed_read
), NULL
, 0);
250 socket_data
.set_connect_data(MockConnect(SYNCHRONOUS
, OK
));
251 transport_client_socket_factory_
.AddSocketDataProvider(&socket_data
);
253 TestCompletionCallback callback
;
254 ClientSocketHandle handle
;
255 EXPECT_EQ(0, transport_socket_pool_
.release_count());
256 int rv
= handle
.Init("a", CreateSOCKSv5Params(), LOW
, callback
.callback(),
257 &pool_
, BoundNetLog());
258 EXPECT_EQ(ERR_IO_PENDING
, rv
);
259 EXPECT_FALSE(handle
.is_initialized());
260 EXPECT_FALSE(handle
.socket());
262 EXPECT_EQ(ERR_SOCKS_CONNECTION_FAILED
, callback
.WaitForResult());
263 EXPECT_FALSE(handle
.is_initialized());
264 EXPECT_FALSE(handle
.socket());
265 EXPECT_EQ(1, transport_socket_pool_
.release_count());
268 TEST_F(SOCKSClientSocketPoolTest
, CancelDuringTransportConnect
) {
269 SOCKS5MockData
data(SYNCHRONOUS
);
270 transport_client_socket_factory_
.AddSocketDataProvider(data
.data_provider());
271 // We need two connections because the pool base lets one cancelled
272 // connect job proceed for potential future use.
273 SOCKS5MockData
data2(SYNCHRONOUS
);
274 transport_client_socket_factory_
.AddSocketDataProvider(data2
.data_provider());
276 EXPECT_EQ(0, transport_socket_pool_
.cancel_count());
277 int rv
= StartRequestV5("a", LOW
);
278 EXPECT_EQ(ERR_IO_PENDING
, rv
);
280 rv
= StartRequestV5("a", LOW
);
281 EXPECT_EQ(ERR_IO_PENDING
, rv
);
283 pool_
.CancelRequest("a", (*requests())[0]->handle());
284 pool_
.CancelRequest("a", (*requests())[1]->handle());
285 // Requests in the connect phase don't actually get cancelled.
286 EXPECT_EQ(0, transport_socket_pool_
.cancel_count());
288 // Now wait for the TCP sockets to connect.
289 base::MessageLoop::current()->RunUntilIdle();
291 EXPECT_EQ(ClientSocketPoolTest::kRequestNotFound
, GetOrderOfRequest(1));
292 EXPECT_EQ(ClientSocketPoolTest::kRequestNotFound
, GetOrderOfRequest(2));
293 EXPECT_EQ(0, transport_socket_pool_
.cancel_count());
294 EXPECT_EQ(2, pool_
.IdleSocketCount());
296 (*requests())[0]->handle()->Reset();
297 (*requests())[1]->handle()->Reset();
300 TEST_F(SOCKSClientSocketPoolTest
, CancelDuringSOCKSConnect
) {
301 SOCKS5MockData
data(ASYNC
);
302 data
.data_provider()->set_connect_data(MockConnect(SYNCHRONOUS
, OK
));
303 transport_client_socket_factory_
.AddSocketDataProvider(data
.data_provider());
304 // We need two connections because the pool base lets one cancelled
305 // connect job proceed for potential future use.
306 SOCKS5MockData
data2(ASYNC
);
307 data2
.data_provider()->set_connect_data(MockConnect(SYNCHRONOUS
, OK
));
308 transport_client_socket_factory_
.AddSocketDataProvider(data2
.data_provider());
310 EXPECT_EQ(0, transport_socket_pool_
.cancel_count());
311 EXPECT_EQ(0, transport_socket_pool_
.release_count());
312 int rv
= StartRequestV5("a", LOW
);
313 EXPECT_EQ(ERR_IO_PENDING
, rv
);
315 rv
= StartRequestV5("a", LOW
);
316 EXPECT_EQ(ERR_IO_PENDING
, rv
);
318 pool_
.CancelRequest("a", (*requests())[0]->handle());
319 pool_
.CancelRequest("a", (*requests())[1]->handle());
320 EXPECT_EQ(0, transport_socket_pool_
.cancel_count());
321 // Requests in the connect phase don't actually get cancelled.
322 EXPECT_EQ(0, transport_socket_pool_
.release_count());
324 // Now wait for the async data to reach the SOCKS connect jobs.
325 base::MessageLoop::current()->RunUntilIdle();
327 EXPECT_EQ(ClientSocketPoolTest::kRequestNotFound
, GetOrderOfRequest(1));
328 EXPECT_EQ(ClientSocketPoolTest::kRequestNotFound
, GetOrderOfRequest(2));
329 EXPECT_EQ(0, transport_socket_pool_
.cancel_count());
330 EXPECT_EQ(0, transport_socket_pool_
.release_count());
331 EXPECT_EQ(2, pool_
.IdleSocketCount());
333 (*requests())[0]->handle()->Reset();
334 (*requests())[1]->handle()->Reset();
337 // It would be nice to also test the timeouts in SOCKSClientSocketPool.