Roll src/third_party/WebKit a3b4a2e:7441784 (svn 202551:202552)
[chromium-blink-merge.git] / net / socket / socks5_client_socket_unittest.cc
blob76146c7ab83e959bc4998e18cc2ab10412789a83
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/socks5_client_socket.h"
7 #include <algorithm>
8 #include <iterator>
9 #include <map>
11 #include "base/sys_byteorder.h"
12 #include "net/base/address_list.h"
13 #include "net/base/test_completion_callback.h"
14 #include "net/base/winsock_init.h"
15 #include "net/dns/mock_host_resolver.h"
16 #include "net/log/net_log.h"
17 #include "net/log/test_net_log.h"
18 #include "net/log/test_net_log_entry.h"
19 #include "net/log/test_net_log_util.h"
20 #include "net/socket/client_socket_factory.h"
21 #include "net/socket/socket_test_util.h"
22 #include "net/socket/tcp_client_socket.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 #include "testing/platform_test.h"
26 //-----------------------------------------------------------------------------
28 namespace net {
30 namespace {
32 // Base class to test SOCKS5ClientSocket
33 class SOCKS5ClientSocketTest : public PlatformTest {
34 public:
35 SOCKS5ClientSocketTest();
36 // Create a SOCKSClientSocket on top of a MockSocket.
37 scoped_ptr<SOCKS5ClientSocket> BuildMockSocket(MockRead reads[],
38 size_t reads_count,
39 MockWrite writes[],
40 size_t writes_count,
41 const std::string& hostname,
42 int port,
43 NetLog* net_log);
45 void SetUp() override;
47 protected:
48 const uint16 kNwPort;
49 TestNetLog net_log_;
50 scoped_ptr<SOCKS5ClientSocket> user_sock_;
51 AddressList address_list_;
52 // Filled in by BuildMockSocket() and owned by its return value
53 // (which |user_sock| is set to).
54 StreamSocket* tcp_sock_;
55 TestCompletionCallback callback_;
56 scoped_ptr<MockHostResolver> host_resolver_;
57 scoped_ptr<SocketDataProvider> data_;
59 private:
60 DISALLOW_COPY_AND_ASSIGN(SOCKS5ClientSocketTest);
63 SOCKS5ClientSocketTest::SOCKS5ClientSocketTest()
64 : kNwPort(base::HostToNet16(80)),
65 host_resolver_(new MockHostResolver) {
68 // Set up platform before every test case
69 void SOCKS5ClientSocketTest::SetUp() {
70 PlatformTest::SetUp();
72 // Resolve the "localhost" AddressList used by the TCP connection to connect.
73 HostResolver::RequestInfo info(HostPortPair("www.socks-proxy.com", 1080));
74 TestCompletionCallback callback;
75 int rv = host_resolver_->Resolve(info,
76 DEFAULT_PRIORITY,
77 &address_list_,
78 callback.callback(),
79 NULL,
80 BoundNetLog());
81 ASSERT_EQ(ERR_IO_PENDING, rv);
82 rv = callback.WaitForResult();
83 ASSERT_EQ(OK, rv);
86 scoped_ptr<SOCKS5ClientSocket> SOCKS5ClientSocketTest::BuildMockSocket(
87 MockRead reads[],
88 size_t reads_count,
89 MockWrite writes[],
90 size_t writes_count,
91 const std::string& hostname,
92 int port,
93 NetLog* net_log) {
94 TestCompletionCallback callback;
95 data_.reset(new StaticSocketDataProvider(reads, reads_count,
96 writes, writes_count));
97 tcp_sock_ = new MockTCPClientSocket(address_list_, net_log, data_.get());
99 int rv = tcp_sock_->Connect(callback.callback());
100 EXPECT_EQ(ERR_IO_PENDING, rv);
101 rv = callback.WaitForResult();
102 EXPECT_EQ(OK, rv);
103 EXPECT_TRUE(tcp_sock_->IsConnected());
105 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
106 // |connection| takes ownership of |tcp_sock_|, but keep a
107 // non-owning pointer to it.
108 connection->SetSocket(scoped_ptr<StreamSocket>(tcp_sock_));
109 return scoped_ptr<SOCKS5ClientSocket>(new SOCKS5ClientSocket(
110 connection.Pass(),
111 HostResolver::RequestInfo(HostPortPair(hostname, port))));
114 // Tests a complete SOCKS5 handshake and the disconnection.
115 TEST_F(SOCKS5ClientSocketTest, CompleteHandshake) {
116 const std::string payload_write = "random data";
117 const std::string payload_read = "moar random data";
119 const char kOkRequest[] = {
120 0x05, // Version
121 0x01, // Command (CONNECT)
122 0x00, // Reserved.
123 0x03, // Address type (DOMAINNAME).
124 0x09, // Length of domain (9)
125 // Domain string:
126 'l', 'o', 'c', 'a', 'l', 'h', 'o', 's', 't',
127 0x00, 0x50, // 16-bit port (80)
130 MockWrite data_writes[] = {
131 MockWrite(ASYNC, kSOCKS5GreetRequest, kSOCKS5GreetRequestLength),
132 MockWrite(ASYNC, kOkRequest, arraysize(kOkRequest)),
133 MockWrite(ASYNC, payload_write.data(), payload_write.size()) };
134 MockRead data_reads[] = {
135 MockRead(ASYNC, kSOCKS5GreetResponse, kSOCKS5GreetResponseLength),
136 MockRead(ASYNC, kSOCKS5OkResponse, kSOCKS5OkResponseLength),
137 MockRead(ASYNC, payload_read.data(), payload_read.size()) };
139 user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
140 data_writes, arraysize(data_writes),
141 "localhost", 80, &net_log_);
143 // At this state the TCP connection is completed but not the SOCKS handshake.
144 EXPECT_TRUE(tcp_sock_->IsConnected());
145 EXPECT_FALSE(user_sock_->IsConnected());
147 int rv = user_sock_->Connect(callback_.callback());
148 EXPECT_EQ(ERR_IO_PENDING, rv);
149 EXPECT_FALSE(user_sock_->IsConnected());
151 TestNetLogEntry::List net_log_entries;
152 net_log_.GetEntries(&net_log_entries);
153 EXPECT_TRUE(LogContainsBeginEvent(net_log_entries, 0,
154 NetLog::TYPE_SOCKS5_CONNECT));
156 rv = callback_.WaitForResult();
158 EXPECT_EQ(OK, rv);
159 EXPECT_TRUE(user_sock_->IsConnected());
161 net_log_.GetEntries(&net_log_entries);
162 EXPECT_TRUE(LogContainsEndEvent(net_log_entries, -1,
163 NetLog::TYPE_SOCKS5_CONNECT));
165 scoped_refptr<IOBuffer> buffer(new IOBuffer(payload_write.size()));
166 memcpy(buffer->data(), payload_write.data(), payload_write.size());
167 rv = user_sock_->Write(
168 buffer.get(), payload_write.size(), callback_.callback());
169 EXPECT_EQ(ERR_IO_PENDING, rv);
170 rv = callback_.WaitForResult();
171 EXPECT_EQ(static_cast<int>(payload_write.size()), rv);
173 buffer = new IOBuffer(payload_read.size());
174 rv =
175 user_sock_->Read(buffer.get(), payload_read.size(), callback_.callback());
176 EXPECT_EQ(ERR_IO_PENDING, rv);
177 rv = callback_.WaitForResult();
178 EXPECT_EQ(static_cast<int>(payload_read.size()), rv);
179 EXPECT_EQ(payload_read, std::string(buffer->data(), payload_read.size()));
181 user_sock_->Disconnect();
182 EXPECT_FALSE(tcp_sock_->IsConnected());
183 EXPECT_FALSE(user_sock_->IsConnected());
186 // Test that you can call Connect() again after having called Disconnect().
187 TEST_F(SOCKS5ClientSocketTest, ConnectAndDisconnectTwice) {
188 const std::string hostname = "my-host-name";
189 const char kSOCKS5DomainRequest[] = {
190 0x05, // VER
191 0x01, // CMD
192 0x00, // RSV
193 0x03, // ATYPE
196 std::string request(kSOCKS5DomainRequest, arraysize(kSOCKS5DomainRequest));
197 request.push_back(hostname.size());
198 request.append(hostname);
199 request.append(reinterpret_cast<const char*>(&kNwPort), sizeof(kNwPort));
201 for (int i = 0; i < 2; ++i) {
202 MockWrite data_writes[] = {
203 MockWrite(SYNCHRONOUS, kSOCKS5GreetRequest, kSOCKS5GreetRequestLength),
204 MockWrite(SYNCHRONOUS, request.data(), request.size())
206 MockRead data_reads[] = {
207 MockRead(SYNCHRONOUS, kSOCKS5GreetResponse, kSOCKS5GreetResponseLength),
208 MockRead(SYNCHRONOUS, kSOCKS5OkResponse, kSOCKS5OkResponseLength)
211 user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
212 data_writes, arraysize(data_writes),
213 hostname, 80, NULL);
215 int rv = user_sock_->Connect(callback_.callback());
216 EXPECT_EQ(OK, rv);
217 EXPECT_TRUE(user_sock_->IsConnected());
219 user_sock_->Disconnect();
220 EXPECT_FALSE(user_sock_->IsConnected());
224 // Test that we fail trying to connect to a hosname longer than 255 bytes.
225 TEST_F(SOCKS5ClientSocketTest, LargeHostNameFails) {
226 // Create a string of length 256, where each character is 'x'.
227 std::string large_host_name;
228 std::fill_n(std::back_inserter(large_host_name), 256, 'x');
230 // Create a SOCKS socket, with mock transport socket.
231 MockWrite data_writes[] = {MockWrite()};
232 MockRead data_reads[] = {MockRead()};
233 user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
234 data_writes, arraysize(data_writes),
235 large_host_name, 80, NULL);
237 // Try to connect -- should fail (without having read/written anything to
238 // the transport socket first) because the hostname is too long.
239 TestCompletionCallback callback;
240 int rv = user_sock_->Connect(callback.callback());
241 EXPECT_EQ(ERR_SOCKS_CONNECTION_FAILED, rv);
244 TEST_F(SOCKS5ClientSocketTest, PartialReadWrites) {
245 const std::string hostname = "www.google.com";
247 const char kOkRequest[] = {
248 0x05, // Version
249 0x01, // Command (CONNECT)
250 0x00, // Reserved.
251 0x03, // Address type (DOMAINNAME).
252 0x0E, // Length of domain (14)
253 // Domain string:
254 'w', 'w', 'w', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'c', 'o', 'm',
255 0x00, 0x50, // 16-bit port (80)
258 // Test for partial greet request write
260 const char partial1[] = { 0x05, 0x01 };
261 const char partial2[] = { 0x00 };
262 MockWrite data_writes[] = {
263 MockWrite(ASYNC, partial1, arraysize(partial1)),
264 MockWrite(ASYNC, partial2, arraysize(partial2)),
265 MockWrite(ASYNC, kOkRequest, arraysize(kOkRequest)) };
266 MockRead data_reads[] = {
267 MockRead(ASYNC, kSOCKS5GreetResponse, kSOCKS5GreetResponseLength),
268 MockRead(ASYNC, kSOCKS5OkResponse, kSOCKS5OkResponseLength) };
269 user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
270 data_writes, arraysize(data_writes),
271 hostname, 80, &net_log_);
272 int rv = user_sock_->Connect(callback_.callback());
273 EXPECT_EQ(ERR_IO_PENDING, rv);
275 TestNetLogEntry::List net_log_entries;
276 net_log_.GetEntries(&net_log_entries);
277 EXPECT_TRUE(LogContainsBeginEvent(net_log_entries, 0,
278 NetLog::TYPE_SOCKS5_CONNECT));
280 rv = callback_.WaitForResult();
281 EXPECT_EQ(OK, rv);
282 EXPECT_TRUE(user_sock_->IsConnected());
284 net_log_.GetEntries(&net_log_entries);
285 EXPECT_TRUE(LogContainsEndEvent(net_log_entries, -1,
286 NetLog::TYPE_SOCKS5_CONNECT));
289 // Test for partial greet response read
291 const char partial1[] = { 0x05 };
292 const char partial2[] = { 0x00 };
293 MockWrite data_writes[] = {
294 MockWrite(ASYNC, kSOCKS5GreetRequest, kSOCKS5GreetRequestLength),
295 MockWrite(ASYNC, kOkRequest, arraysize(kOkRequest)) };
296 MockRead data_reads[] = {
297 MockRead(ASYNC, partial1, arraysize(partial1)),
298 MockRead(ASYNC, partial2, arraysize(partial2)),
299 MockRead(ASYNC, kSOCKS5OkResponse, kSOCKS5OkResponseLength) };
300 user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
301 data_writes, arraysize(data_writes),
302 hostname, 80, &net_log_);
303 int rv = user_sock_->Connect(callback_.callback());
304 EXPECT_EQ(ERR_IO_PENDING, rv);
306 TestNetLogEntry::List net_log_entries;
307 net_log_.GetEntries(&net_log_entries);
308 EXPECT_TRUE(LogContainsBeginEvent(net_log_entries, 0,
309 NetLog::TYPE_SOCKS5_CONNECT));
310 rv = callback_.WaitForResult();
311 EXPECT_EQ(OK, rv);
312 EXPECT_TRUE(user_sock_->IsConnected());
313 net_log_.GetEntries(&net_log_entries);
314 EXPECT_TRUE(LogContainsEndEvent(net_log_entries, -1,
315 NetLog::TYPE_SOCKS5_CONNECT));
318 // Test for partial handshake request write.
320 const int kSplitPoint = 3; // Break handshake write into two parts.
321 MockWrite data_writes[] = {
322 MockWrite(ASYNC, kSOCKS5GreetRequest, kSOCKS5GreetRequestLength),
323 MockWrite(ASYNC, kOkRequest, kSplitPoint),
324 MockWrite(ASYNC, kOkRequest + kSplitPoint,
325 arraysize(kOkRequest) - kSplitPoint)
327 MockRead data_reads[] = {
328 MockRead(ASYNC, kSOCKS5GreetResponse, kSOCKS5GreetResponseLength),
329 MockRead(ASYNC, kSOCKS5OkResponse, kSOCKS5OkResponseLength) };
330 user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
331 data_writes, arraysize(data_writes),
332 hostname, 80, &net_log_);
333 int rv = user_sock_->Connect(callback_.callback());
334 EXPECT_EQ(ERR_IO_PENDING, rv);
335 TestNetLogEntry::List net_log_entries;
336 net_log_.GetEntries(&net_log_entries);
337 EXPECT_TRUE(LogContainsBeginEvent(net_log_entries, 0,
338 NetLog::TYPE_SOCKS5_CONNECT));
339 rv = callback_.WaitForResult();
340 EXPECT_EQ(OK, rv);
341 EXPECT_TRUE(user_sock_->IsConnected());
342 net_log_.GetEntries(&net_log_entries);
343 EXPECT_TRUE(LogContainsEndEvent(net_log_entries, -1,
344 NetLog::TYPE_SOCKS5_CONNECT));
347 // Test for partial handshake response read
349 const int kSplitPoint = 6; // Break the handshake read into two parts.
350 MockWrite data_writes[] = {
351 MockWrite(ASYNC, kSOCKS5GreetRequest, kSOCKS5GreetRequestLength),
352 MockWrite(ASYNC, kOkRequest, arraysize(kOkRequest))
354 MockRead data_reads[] = {
355 MockRead(ASYNC, kSOCKS5GreetResponse, kSOCKS5GreetResponseLength),
356 MockRead(ASYNC, kSOCKS5OkResponse, kSplitPoint),
357 MockRead(ASYNC, kSOCKS5OkResponse + kSplitPoint,
358 kSOCKS5OkResponseLength - kSplitPoint)
361 user_sock_ = BuildMockSocket(data_reads, arraysize(data_reads),
362 data_writes, arraysize(data_writes),
363 hostname, 80, &net_log_);
364 int rv = user_sock_->Connect(callback_.callback());
365 EXPECT_EQ(ERR_IO_PENDING, rv);
366 TestNetLogEntry::List net_log_entries;
367 net_log_.GetEntries(&net_log_entries);
368 EXPECT_TRUE(LogContainsBeginEvent(net_log_entries, 0,
369 NetLog::TYPE_SOCKS5_CONNECT));
370 rv = callback_.WaitForResult();
371 EXPECT_EQ(OK, rv);
372 EXPECT_TRUE(user_sock_->IsConnected());
373 net_log_.GetEntries(&net_log_entries);
374 EXPECT_TRUE(LogContainsEndEvent(net_log_entries, -1,
375 NetLog::TYPE_SOCKS5_CONNECT));
379 } // namespace
381 } // namespace net