1 // Copyright (c) 2011 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.
4
5 #include "net/socket/socks_client_socket_pool.h"
6
7 #include "base/callback.h"
8 #include "base/compiler_specific.h"
9 #include "base/time.h"
10 #include "net/base/mock_host_resolver.h"
11 #include "net/base/net_errors.h"
12 #include "net/base/test_completion_callback.h"
13 #include "net/socket/client_socket_factory.h"
14 #include "net/socket/client_socket_handle.h"
15 #include "net/socket/client_socket_pool_histograms.h"
16 #include "net/socket/socket_test_util.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18
19 namespace net {
20
21 namespace {
22
23 const int kMaxSockets = 32;
24 const int kMaxSocketsPerGroup = 6;
25
26 class SOCKSClientSocketPoolTest : public testing::Test {
27 protected:
28 class SOCKS5MockData {
29 public:
SOCKS5MockData(bool async)30 explicit SOCKS5MockData(bool async) {
31 writes_.reset(new MockWrite[3]);
32 writes_[0] = MockWrite(async, kSOCKS5GreetRequest,
33 kSOCKS5GreetRequestLength);
34 writes_[1] = MockWrite(async, kSOCKS5OkRequest, kSOCKS5OkRequestLength);
35 writes_[2] = MockWrite(async, 0);
36
37 reads_.reset(new MockRead[3]);
38 reads_[0] = MockRead(async, kSOCKS5GreetResponse,
39 kSOCKS5GreetResponseLength);
40 reads_[1] = MockRead(async, kSOCKS5OkResponse, kSOCKS5OkResponseLength);
41 reads_[2] = MockRead(async, 0);
42
43 data_.reset(new StaticSocketDataProvider(reads_.get(), 3,
44 writes_.get(), 3));
45 }
46
data_provider()47 SocketDataProvider* data_provider() { return data_.get(); }
48
49 private:
50 scoped_ptr<StaticSocketDataProvider> data_;
51 scoped_array<MockWrite> writes_;
52 scoped_array<MockWrite> reads_;
53 };
54
SOCKSClientSocketPoolTest()55 SOCKSClientSocketPoolTest()
56 : ignored_transport_socket_params_(new TransportSocketParams(
57 HostPortPair("proxy", 80), MEDIUM, GURL(), false, false)),
58 transport_histograms_("MockTCP"),
59 transport_socket_pool_(
60 kMaxSockets, kMaxSocketsPerGroup,
61 &transport_histograms_,
62 &transport_client_socket_factory_),
63 ignored_socket_params_(new SOCKSSocketParams(
64 ignored_transport_socket_params_, true, HostPortPair("host", 80),
65 MEDIUM, GURL())),
66 socks_histograms_("SOCKSUnitTest"),
67 pool_(kMaxSockets, kMaxSocketsPerGroup,
68 &socks_histograms_,
69 NULL,
70 &transport_socket_pool_,
71 NULL) {
72 }
73
~SOCKSClientSocketPoolTest()74 virtual ~SOCKSClientSocketPoolTest() {}
75
StartRequest(const std::string & group_name,RequestPriority priority)76 int StartRequest(const std::string& group_name, RequestPriority priority) {
77 return test_base_.StartRequestUsingPool(
78 &pool_, group_name, priority, ignored_socket_params_);
79 }
80
GetOrderOfRequest(size_t index) const81 int GetOrderOfRequest(size_t index) const {
82 return test_base_.GetOrderOfRequest(index);
83 }
84
requests()85 ScopedVector<TestSocketRequest>* requests() { return test_base_.requests(); }
86
87 scoped_refptr<TransportSocketParams> ignored_transport_socket_params_;
88 ClientSocketPoolHistograms transport_histograms_;
89 MockClientSocketFactory transport_client_socket_factory_;
90 MockTransportClientSocketPool transport_socket_pool_;
91
92 scoped_refptr<SOCKSSocketParams> ignored_socket_params_;
93 ClientSocketPoolHistograms socks_histograms_;
94 SOCKSClientSocketPool pool_;
95 ClientSocketPoolTest test_base_;
96 };
97
TEST_F(SOCKSClientSocketPoolTest,Simple)98 TEST_F(SOCKSClientSocketPoolTest, Simple) {
99 SOCKS5MockData data(false);
100 data.data_provider()->set_connect_data(MockConnect(false, 0));
101 transport_client_socket_factory_.AddSocketDataProvider(data.data_provider());
102
103 ClientSocketHandle handle;
104 int rv = handle.Init("a", ignored_socket_params_, LOW, NULL, &pool_,
105 BoundNetLog());
106 EXPECT_EQ(OK, rv);
107 EXPECT_TRUE(handle.is_initialized());
108 EXPECT_TRUE(handle.socket());
109 }
110
TEST_F(SOCKSClientSocketPoolTest,Async)111 TEST_F(SOCKSClientSocketPoolTest, Async) {
112 SOCKS5MockData data(true);
113 transport_client_socket_factory_.AddSocketDataProvider(data.data_provider());
114
115 TestCompletionCallback callback;
116 ClientSocketHandle handle;
117 int rv = handle.Init("a", ignored_socket_params_, LOW, &callback, &pool_,
118 BoundNetLog());
119 EXPECT_EQ(ERR_IO_PENDING, rv);
120 EXPECT_FALSE(handle.is_initialized());
121 EXPECT_FALSE(handle.socket());
122
123 EXPECT_EQ(OK, callback.WaitForResult());
124 EXPECT_TRUE(handle.is_initialized());
125 EXPECT_TRUE(handle.socket());
126 }
127
TEST_F(SOCKSClientSocketPoolTest,TransportConnectError)128 TEST_F(SOCKSClientSocketPoolTest, TransportConnectError) {
129 scoped_ptr<SocketDataProvider> socket_data(new StaticSocketDataProvider());
130 socket_data->set_connect_data(MockConnect(false, ERR_CONNECTION_REFUSED));
131 transport_client_socket_factory_.AddSocketDataProvider(socket_data.get());
132
133 ClientSocketHandle handle;
134 int rv = handle.Init("a", ignored_socket_params_, LOW, NULL, &pool_,
135 BoundNetLog());
136 EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, rv);
137 EXPECT_FALSE(handle.is_initialized());
138 EXPECT_FALSE(handle.socket());
139 }
140
TEST_F(SOCKSClientSocketPoolTest,AsyncTransportConnectError)141 TEST_F(SOCKSClientSocketPoolTest, AsyncTransportConnectError) {
142 scoped_ptr<SocketDataProvider> socket_data(new StaticSocketDataProvider());
143 socket_data->set_connect_data(MockConnect(true, ERR_CONNECTION_REFUSED));
144 transport_client_socket_factory_.AddSocketDataProvider(socket_data.get());
145
146 TestCompletionCallback callback;
147 ClientSocketHandle handle;
148 int rv = handle.Init("a", ignored_socket_params_, LOW, &callback, &pool_,
149 BoundNetLog());
150 EXPECT_EQ(ERR_IO_PENDING, rv);
151 EXPECT_FALSE(handle.is_initialized());
152 EXPECT_FALSE(handle.socket());
153
154 EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, callback.WaitForResult());
155 EXPECT_FALSE(handle.is_initialized());
156 EXPECT_FALSE(handle.socket());
157 }
158
TEST_F(SOCKSClientSocketPoolTest,SOCKSConnectError)159 TEST_F(SOCKSClientSocketPoolTest, SOCKSConnectError) {
160 MockRead failed_read[] = {
161 MockRead(false, 0),
162 };
163 scoped_ptr<SocketDataProvider> socket_data(new StaticSocketDataProvider(
164 failed_read, arraysize(failed_read), NULL, 0));
165 socket_data->set_connect_data(MockConnect(false, 0));
166 transport_client_socket_factory_.AddSocketDataProvider(socket_data.get());
167
168 ClientSocketHandle handle;
169 EXPECT_EQ(0, transport_socket_pool_.release_count());
170 int rv = handle.Init("a", ignored_socket_params_, LOW, NULL, &pool_,
171 BoundNetLog());
172 EXPECT_EQ(ERR_SOCKS_CONNECTION_FAILED, rv);
173 EXPECT_FALSE(handle.is_initialized());
174 EXPECT_FALSE(handle.socket());
175 EXPECT_EQ(1, transport_socket_pool_.release_count());
176 }
177
TEST_F(SOCKSClientSocketPoolTest,AsyncSOCKSConnectError)178 TEST_F(SOCKSClientSocketPoolTest, AsyncSOCKSConnectError) {
179 MockRead failed_read[] = {
180 MockRead(true, 0),
181 };
182 scoped_ptr<SocketDataProvider> socket_data(new StaticSocketDataProvider(
183 failed_read, arraysize(failed_read), NULL, 0));
184 socket_data->set_connect_data(MockConnect(false, 0));
185 transport_client_socket_factory_.AddSocketDataProvider(socket_data.get());
186
187 TestCompletionCallback callback;
188 ClientSocketHandle handle;
189 EXPECT_EQ(0, transport_socket_pool_.release_count());
190 int rv = handle.Init("a", ignored_socket_params_, LOW, &callback, &pool_,
191 BoundNetLog());
192 EXPECT_EQ(ERR_IO_PENDING, rv);
193 EXPECT_FALSE(handle.is_initialized());
194 EXPECT_FALSE(handle.socket());
195
196 EXPECT_EQ(ERR_SOCKS_CONNECTION_FAILED, callback.WaitForResult());
197 EXPECT_FALSE(handle.is_initialized());
198 EXPECT_FALSE(handle.socket());
199 EXPECT_EQ(1, transport_socket_pool_.release_count());
200 }
201
TEST_F(SOCKSClientSocketPoolTest,CancelDuringTransportConnect)202 TEST_F(SOCKSClientSocketPoolTest, CancelDuringTransportConnect) {
203 SOCKS5MockData data(false);
204 transport_client_socket_factory_.AddSocketDataProvider(data.data_provider());
205 // We need two connections because the pool base lets one cancelled
206 // connect job proceed for potential future use.
207 SOCKS5MockData data2(false);
208 transport_client_socket_factory_.AddSocketDataProvider(data2.data_provider());
209
210 EXPECT_EQ(0, transport_socket_pool_.cancel_count());
211 int rv = StartRequest("a", LOW);
212 EXPECT_EQ(ERR_IO_PENDING, rv);
213
214 rv = StartRequest("a", LOW);
215 EXPECT_EQ(ERR_IO_PENDING, rv);
216
217 pool_.CancelRequest("a", (*requests())[0]->handle());
218 pool_.CancelRequest("a", (*requests())[1]->handle());
219 // Requests in the connect phase don't actually get cancelled.
220 EXPECT_EQ(0, transport_socket_pool_.cancel_count());
221
222 // Now wait for the TCP sockets to connect.
223 MessageLoop::current()->RunAllPending();
224
225 EXPECT_EQ(ClientSocketPoolTest::kRequestNotFound, GetOrderOfRequest(1));
226 EXPECT_EQ(ClientSocketPoolTest::kRequestNotFound, GetOrderOfRequest(2));
227 EXPECT_EQ(0, transport_socket_pool_.cancel_count());
228 EXPECT_EQ(2, pool_.IdleSocketCount());
229
230 (*requests())[0]->handle()->Reset();
231 (*requests())[1]->handle()->Reset();
232 }
233
TEST_F(SOCKSClientSocketPoolTest,CancelDuringSOCKSConnect)234 TEST_F(SOCKSClientSocketPoolTest, CancelDuringSOCKSConnect) {
235 SOCKS5MockData data(true);
236 data.data_provider()->set_connect_data(MockConnect(false, 0));
237 transport_client_socket_factory_.AddSocketDataProvider(data.data_provider());
238 // We need two connections because the pool base lets one cancelled
239 // connect job proceed for potential future use.
240 SOCKS5MockData data2(true);
241 data2.data_provider()->set_connect_data(MockConnect(false, 0));
242 transport_client_socket_factory_.AddSocketDataProvider(data2.data_provider());
243
244 EXPECT_EQ(0, transport_socket_pool_.cancel_count());
245 EXPECT_EQ(0, transport_socket_pool_.release_count());
246 int rv = StartRequest("a", LOW);
247 EXPECT_EQ(ERR_IO_PENDING, rv);
248
249 rv = StartRequest("a", LOW);
250 EXPECT_EQ(ERR_IO_PENDING, rv);
251
252 pool_.CancelRequest("a", (*requests())[0]->handle());
253 pool_.CancelRequest("a", (*requests())[1]->handle());
254 EXPECT_EQ(0, transport_socket_pool_.cancel_count());
255 // Requests in the connect phase don't actually get cancelled.
256 EXPECT_EQ(0, transport_socket_pool_.release_count());
257
258 // Now wait for the async data to reach the SOCKS connect jobs.
259 MessageLoop::current()->RunAllPending();
260
261 EXPECT_EQ(ClientSocketPoolTest::kRequestNotFound, GetOrderOfRequest(1));
262 EXPECT_EQ(ClientSocketPoolTest::kRequestNotFound, GetOrderOfRequest(2));
263 EXPECT_EQ(0, transport_socket_pool_.cancel_count());
264 EXPECT_EQ(0, transport_socket_pool_.release_count());
265 EXPECT_EQ(2, pool_.IdleSocketCount());
266
267 (*requests())[0]->handle()->Reset();
268 (*requests())[1]->handle()->Reset();
269 }
270
271 // It would be nice to also test the timeouts in SOCKSClientSocketPool.
272
273 } // namespace
274
275 } // namespace net
276