Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / net / socket / socks_client_socket_unittest.cc
blob27b4c70aa9574e3656ae5489d686e8287af53e59
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.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "net/base/address_list.h"
9 #include "net/base/test_completion_callback.h"
10 #include "net/base/winsock_init.h"
11 #include "net/dns/host_resolver.h"
12 #include "net/dns/mock_host_resolver.h"
13 #include "net/log/net_log.h"
14 #include "net/log/test_net_log.h"
15 #include "net/log/test_net_log_entry.h"
16 #include "net/log/test_net_log_util.h"
17 #include "net/socket/client_socket_factory.h"
18 #include "net/socket/socket_test_util.h"
19 #include "net/socket/tcp_client_socket.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 #include "testing/platform_test.h"
23 //-----------------------------------------------------------------------------
25 namespace net {
27 const char kSOCKSOkRequest[] = { 0x04, 0x01, 0x00, 0x50, 127, 0, 0, 1, 0 };
28 const char kSOCKSOkReply[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 };
30 class SOCKSClientSocketTest : public PlatformTest {
31 public:
32 SOCKSClientSocketTest();
33 // Create a SOCKSClientSocket on top of a MockSocket.
34 scoped_ptr<SOCKSClientSocket> BuildMockSocket(
35 MockRead reads[], size_t reads_count,
36 MockWrite writes[], size_t writes_count,
37 HostResolver* host_resolver,
38 const std::string& hostname, int port,
39 NetLog* net_log);
40 void SetUp() override;
42 protected:
43 scoped_ptr<SOCKSClientSocket> user_sock_;
44 AddressList address_list_;
45 // Filled in by BuildMockSocket() and owned by its return value
46 // (which |user_sock| is set to).
47 StreamSocket* tcp_sock_;
48 TestCompletionCallback callback_;
49 scoped_ptr<MockHostResolver> host_resolver_;
50 scoped_ptr<SocketDataProvider> data_;
53 SOCKSClientSocketTest::SOCKSClientSocketTest()
54 : host_resolver_(new MockHostResolver) {
57 // Set up platform before every test case
58 void SOCKSClientSocketTest::SetUp() {
59 PlatformTest::SetUp();
62 scoped_ptr<SOCKSClientSocket> SOCKSClientSocketTest::BuildMockSocket(
63 MockRead reads[],
64 size_t reads_count,
65 MockWrite writes[],
66 size_t writes_count,
67 HostResolver* host_resolver,
68 const std::string& hostname,
69 int port,
70 NetLog* net_log) {
72 TestCompletionCallback callback;
73 data_.reset(new StaticSocketDataProvider(reads, reads_count,
74 writes, writes_count));
75 tcp_sock_ = new MockTCPClientSocket(address_list_, net_log, data_.get());
77 int rv = tcp_sock_->Connect(callback.callback());
78 EXPECT_EQ(ERR_IO_PENDING, rv);
79 rv = callback.WaitForResult();
80 EXPECT_EQ(OK, rv);
81 EXPECT_TRUE(tcp_sock_->IsConnected());
83 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
84 // |connection| takes ownership of |tcp_sock_|, but keep a
85 // non-owning pointer to it.
86 connection->SetSocket(scoped_ptr<StreamSocket>(tcp_sock_));
87 return scoped_ptr<SOCKSClientSocket>(new SOCKSClientSocket(
88 connection.Pass(),
89 HostResolver::RequestInfo(HostPortPair(hostname, port)),
90 DEFAULT_PRIORITY,
91 host_resolver));
94 // Implementation of HostResolver that never completes its resolve request.
95 // We use this in the test "DisconnectWhileHostResolveInProgress" to make
96 // sure that the outstanding resolve request gets cancelled.
97 class HangingHostResolverWithCancel : public HostResolver {
98 public:
99 HangingHostResolverWithCancel() : outstanding_request_(NULL) {}
101 int Resolve(const RequestInfo& info,
102 RequestPriority priority,
103 AddressList* addresses,
104 const CompletionCallback& callback,
105 RequestHandle* out_req,
106 const BoundNetLog& net_log) override {
107 DCHECK(addresses);
108 DCHECK_EQ(false, callback.is_null());
109 EXPECT_FALSE(HasOutstandingRequest());
110 outstanding_request_ = reinterpret_cast<RequestHandle>(1);
111 *out_req = outstanding_request_;
112 return ERR_IO_PENDING;
115 int ResolveFromCache(const RequestInfo& info,
116 AddressList* addresses,
117 const BoundNetLog& net_log) override {
118 NOTIMPLEMENTED();
119 return ERR_UNEXPECTED;
122 void CancelRequest(RequestHandle req) override {
123 EXPECT_TRUE(HasOutstandingRequest());
124 EXPECT_EQ(outstanding_request_, req);
125 outstanding_request_ = NULL;
128 bool HasOutstandingRequest() {
129 return outstanding_request_ != NULL;
132 private:
133 RequestHandle outstanding_request_;
135 DISALLOW_COPY_AND_ASSIGN(HangingHostResolverWithCancel);
138 // Tests a complete handshake and the disconnection.
139 TEST_F(SOCKSClientSocketTest, CompleteHandshake) {
140 const std::string payload_write = "random data";
141 const std::string payload_read = "moar random data";
143 MockWrite data_writes[] = {
144 MockWrite(ASYNC, kSOCKSOkRequest, arraysize(kSOCKSOkRequest)),
145 MockWrite(ASYNC, payload_write.data(), payload_write.size()) };
146 MockRead data_reads[] = {
147 MockRead(ASYNC, kSOCKSOkReply, arraysize(kSOCKSOkReply)),
148 MockRead(ASYNC, payload_read.data(), payload_read.size()) };
149 TestNetLog log;
151 user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
152 data_writes, arraysize(data_writes),
153 host_resolver_.get(),
154 "localhost", 80,
155 &log);
157 // At this state the TCP connection is completed but not the SOCKS handshake.
158 EXPECT_TRUE(tcp_sock_->IsConnected());
159 EXPECT_FALSE(user_sock_->IsConnected());
161 int rv = user_sock_->Connect(callback_.callback());
162 EXPECT_EQ(ERR_IO_PENDING, rv);
164 TestNetLogEntry::List entries;
165 log.GetEntries(&entries);
166 EXPECT_TRUE(
167 LogContainsBeginEvent(entries, 0, NetLog::TYPE_SOCKS_CONNECT));
168 EXPECT_FALSE(user_sock_->IsConnected());
170 rv = callback_.WaitForResult();
171 EXPECT_EQ(OK, rv);
172 EXPECT_TRUE(user_sock_->IsConnected());
173 log.GetEntries(&entries);
174 EXPECT_TRUE(LogContainsEndEvent(
175 entries, -1, NetLog::TYPE_SOCKS_CONNECT));
177 scoped_refptr<IOBuffer> buffer(new IOBuffer(payload_write.size()));
178 memcpy(buffer->data(), payload_write.data(), payload_write.size());
179 rv = user_sock_->Write(
180 buffer.get(), payload_write.size(), callback_.callback());
181 EXPECT_EQ(ERR_IO_PENDING, rv);
182 rv = callback_.WaitForResult();
183 EXPECT_EQ(static_cast<int>(payload_write.size()), rv);
185 buffer = new IOBuffer(payload_read.size());
186 rv =
187 user_sock_->Read(buffer.get(), payload_read.size(), callback_.callback());
188 EXPECT_EQ(ERR_IO_PENDING, rv);
189 rv = callback_.WaitForResult();
190 EXPECT_EQ(static_cast<int>(payload_read.size()), rv);
191 EXPECT_EQ(payload_read, std::string(buffer->data(), payload_read.size()));
193 user_sock_->Disconnect();
194 EXPECT_FALSE(tcp_sock_->IsConnected());
195 EXPECT_FALSE(user_sock_->IsConnected());
198 // List of responses from the socks server and the errors they should
199 // throw up are tested here.
200 TEST_F(SOCKSClientSocketTest, HandshakeFailures) {
201 const struct {
202 const char fail_reply[8];
203 Error fail_code;
204 } tests[] = {
205 // Failure of the server response code
207 { 0x01, 0x5A, 0x00, 0x00, 0, 0, 0, 0 },
208 ERR_SOCKS_CONNECTION_FAILED,
210 // Failure of the null byte
212 { 0x00, 0x5B, 0x00, 0x00, 0, 0, 0, 0 },
213 ERR_SOCKS_CONNECTION_FAILED,
217 //---------------------------------------
219 for (size_t i = 0; i < arraysize(tests); ++i) {
220 MockWrite data_writes[] = {
221 MockWrite(SYNCHRONOUS, kSOCKSOkRequest, arraysize(kSOCKSOkRequest)) };
222 MockRead data_reads[] = {
223 MockRead(SYNCHRONOUS, tests[i].fail_reply,
224 arraysize(tests[i].fail_reply)) };
225 TestNetLog log;
227 user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
228 data_writes, arraysize(data_writes),
229 host_resolver_.get(),
230 "localhost", 80,
231 &log);
233 int rv = user_sock_->Connect(callback_.callback());
234 EXPECT_EQ(ERR_IO_PENDING, rv);
236 TestNetLogEntry::List entries;
237 log.GetEntries(&entries);
238 EXPECT_TRUE(LogContainsBeginEvent(
239 entries, 0, NetLog::TYPE_SOCKS_CONNECT));
241 rv = callback_.WaitForResult();
242 EXPECT_EQ(tests[i].fail_code, rv);
243 EXPECT_FALSE(user_sock_->IsConnected());
244 EXPECT_TRUE(tcp_sock_->IsConnected());
245 log.GetEntries(&entries);
246 EXPECT_TRUE(LogContainsEndEvent(
247 entries, -1, NetLog::TYPE_SOCKS_CONNECT));
251 // Tests scenario when the server sends the handshake response in
252 // more than one packet.
253 TEST_F(SOCKSClientSocketTest, PartialServerReads) {
254 const char kSOCKSPartialReply1[] = { 0x00 };
255 const char kSOCKSPartialReply2[] = { 0x5A, 0x00, 0x00, 0, 0, 0, 0 };
257 MockWrite data_writes[] = {
258 MockWrite(ASYNC, kSOCKSOkRequest, arraysize(kSOCKSOkRequest)) };
259 MockRead data_reads[] = {
260 MockRead(ASYNC, kSOCKSPartialReply1, arraysize(kSOCKSPartialReply1)),
261 MockRead(ASYNC, kSOCKSPartialReply2, arraysize(kSOCKSPartialReply2)) };
262 TestNetLog log;
264 user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
265 data_writes, arraysize(data_writes),
266 host_resolver_.get(),
267 "localhost", 80,
268 &log);
270 int rv = user_sock_->Connect(callback_.callback());
271 EXPECT_EQ(ERR_IO_PENDING, rv);
272 TestNetLogEntry::List entries;
273 log.GetEntries(&entries);
274 EXPECT_TRUE(LogContainsBeginEvent(
275 entries, 0, NetLog::TYPE_SOCKS_CONNECT));
277 rv = callback_.WaitForResult();
278 EXPECT_EQ(OK, rv);
279 EXPECT_TRUE(user_sock_->IsConnected());
280 log.GetEntries(&entries);
281 EXPECT_TRUE(LogContainsEndEvent(
282 entries, -1, NetLog::TYPE_SOCKS_CONNECT));
285 // Tests scenario when the client sends the handshake request in
286 // more than one packet.
287 TEST_F(SOCKSClientSocketTest, PartialClientWrites) {
288 const char kSOCKSPartialRequest1[] = { 0x04, 0x01 };
289 const char kSOCKSPartialRequest2[] = { 0x00, 0x50, 127, 0, 0, 1, 0 };
291 MockWrite data_writes[] = {
292 MockWrite(ASYNC, kSOCKSPartialRequest1, arraysize(kSOCKSPartialRequest1)),
293 // simulate some empty writes
294 MockWrite(ASYNC, 0),
295 MockWrite(ASYNC, 0),
296 MockWrite(ASYNC, kSOCKSPartialRequest2, arraysize(kSOCKSPartialRequest2)),
298 MockRead data_reads[] = {
299 MockRead(ASYNC, kSOCKSOkReply, arraysize(kSOCKSOkReply)) };
300 TestNetLog log;
302 user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
303 data_writes, arraysize(data_writes),
304 host_resolver_.get(),
305 "localhost", 80,
306 &log);
308 int rv = user_sock_->Connect(callback_.callback());
309 EXPECT_EQ(ERR_IO_PENDING, rv);
310 TestNetLogEntry::List entries;
311 log.GetEntries(&entries);
312 EXPECT_TRUE(LogContainsBeginEvent(
313 entries, 0, NetLog::TYPE_SOCKS_CONNECT));
315 rv = callback_.WaitForResult();
316 EXPECT_EQ(OK, rv);
317 EXPECT_TRUE(user_sock_->IsConnected());
318 log.GetEntries(&entries);
319 EXPECT_TRUE(LogContainsEndEvent(
320 entries, -1, NetLog::TYPE_SOCKS_CONNECT));
323 // Tests the case when the server sends a smaller sized handshake data
324 // and closes the connection.
325 TEST_F(SOCKSClientSocketTest, FailedSocketRead) {
326 MockWrite data_writes[] = {
327 MockWrite(ASYNC, kSOCKSOkRequest, arraysize(kSOCKSOkRequest)) };
328 MockRead data_reads[] = {
329 MockRead(ASYNC, kSOCKSOkReply, arraysize(kSOCKSOkReply) - 2),
330 // close connection unexpectedly
331 MockRead(SYNCHRONOUS, 0) };
332 TestNetLog log;
334 user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
335 data_writes, arraysize(data_writes),
336 host_resolver_.get(),
337 "localhost", 80,
338 &log);
340 int rv = user_sock_->Connect(callback_.callback());
341 EXPECT_EQ(ERR_IO_PENDING, rv);
342 TestNetLogEntry::List entries;
343 log.GetEntries(&entries);
344 EXPECT_TRUE(LogContainsBeginEvent(
345 entries, 0, NetLog::TYPE_SOCKS_CONNECT));
347 rv = callback_.WaitForResult();
348 EXPECT_EQ(ERR_CONNECTION_CLOSED, rv);
349 EXPECT_FALSE(user_sock_->IsConnected());
350 log.GetEntries(&entries);
351 EXPECT_TRUE(LogContainsEndEvent(
352 entries, -1, NetLog::TYPE_SOCKS_CONNECT));
355 // Tries to connect to an unknown hostname. Should fail rather than
356 // falling back to SOCKS4a.
357 TEST_F(SOCKSClientSocketTest, FailedDNS) {
358 const char hostname[] = "unresolved.ipv4.address";
360 host_resolver_->rules()->AddSimulatedFailure(hostname);
362 TestNetLog log;
364 user_sock_ = BuildMockSocket(NULL, 0,
365 NULL, 0,
366 host_resolver_.get(),
367 hostname, 80,
368 &log);
370 int rv = user_sock_->Connect(callback_.callback());
371 EXPECT_EQ(ERR_IO_PENDING, rv);
372 TestNetLogEntry::List entries;
373 log.GetEntries(&entries);
374 EXPECT_TRUE(LogContainsBeginEvent(
375 entries, 0, NetLog::TYPE_SOCKS_CONNECT));
377 rv = callback_.WaitForResult();
378 EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv);
379 EXPECT_FALSE(user_sock_->IsConnected());
380 log.GetEntries(&entries);
381 EXPECT_TRUE(LogContainsEndEvent(
382 entries, -1, NetLog::TYPE_SOCKS_CONNECT));
385 // Calls Disconnect() while a host resolve is in progress. The outstanding host
386 // resolve should be cancelled.
387 TEST_F(SOCKSClientSocketTest, DisconnectWhileHostResolveInProgress) {
388 scoped_ptr<HangingHostResolverWithCancel> hanging_resolver(
389 new HangingHostResolverWithCancel());
391 // Doesn't matter what the socket data is, we will never use it -- garbage.
392 MockWrite data_writes[] = { MockWrite(SYNCHRONOUS, "", 0) };
393 MockRead data_reads[] = { MockRead(SYNCHRONOUS, "", 0) };
395 user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
396 data_writes, arraysize(data_writes),
397 hanging_resolver.get(),
398 "foo", 80,
399 NULL);
401 // Start connecting (will get stuck waiting for the host to resolve).
402 int rv = user_sock_->Connect(callback_.callback());
403 EXPECT_EQ(ERR_IO_PENDING, rv);
405 EXPECT_FALSE(user_sock_->IsConnected());
406 EXPECT_FALSE(user_sock_->IsConnectedAndIdle());
408 // The host resolver should have received the resolve request.
409 EXPECT_TRUE(hanging_resolver->HasOutstandingRequest());
411 // Disconnect the SOCKS socket -- this should cancel the outstanding resolve.
412 user_sock_->Disconnect();
414 EXPECT_FALSE(hanging_resolver->HasOutstandingRequest());
416 EXPECT_FALSE(user_sock_->IsConnected());
417 EXPECT_FALSE(user_sock_->IsConnectedAndIdle());
420 // Tries to connect to an IPv6 IP. Should fail, as SOCKS4 does not support
421 // IPv6.
422 TEST_F(SOCKSClientSocketTest, NoIPv6) {
423 const char kHostName[] = "::1";
425 user_sock_ = BuildMockSocket(NULL, 0,
426 NULL, 0,
427 host_resolver_.get(),
428 kHostName, 80,
429 NULL);
431 EXPECT_EQ(ERR_NAME_NOT_RESOLVED,
432 callback_.GetResult(user_sock_->Connect(callback_.callback())));
435 // Same as above, but with a real resolver, to protect against regressions.
436 TEST_F(SOCKSClientSocketTest, NoIPv6RealResolver) {
437 const char kHostName[] = "::1";
439 scoped_ptr<HostResolver> host_resolver(
440 HostResolver::CreateSystemResolver(HostResolver::Options(), NULL));
442 user_sock_ = BuildMockSocket(NULL, 0,
443 NULL, 0,
444 host_resolver.get(),
445 kHostName, 80,
446 NULL);
448 EXPECT_EQ(ERR_NAME_NOT_RESOLVED,
449 callback_.GetResult(user_sock_->Connect(callback_.callback())));
452 } // namespace net