• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Chromium Authors
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_connect_job.h"
6 
7 #include "base/containers/flat_set.h"
8 #include "base/containers/span.h"
9 #include "base/functional/callback.h"
10 #include "base/run_loop.h"
11 #include "base/test/task_environment.h"
12 #include "base/time/time.h"
13 #include "build/build_config.h"
14 #include "net/base/load_states.h"
15 #include "net/base/load_timing_info.h"
16 #include "net/base/load_timing_info_test_util.h"
17 #include "net/base/net_errors.h"
18 #include "net/base/network_isolation_key.h"
19 #include "net/dns/mock_host_resolver.h"
20 #include "net/dns/public/secure_dns_policy.h"
21 #include "net/log/net_log.h"
22 #include "net/socket/client_socket_factory.h"
23 #include "net/socket/client_socket_handle.h"
24 #include "net/socket/connect_job_test_util.h"
25 #include "net/socket/socket_tag.h"
26 #include "net/socket/socket_test_util.h"
27 #include "net/socket/socks_connect_job.h"
28 #include "net/socket/transport_client_socket_pool_test_util.h"
29 #include "net/socket/transport_connect_job.h"
30 #include "net/test/gtest_util.h"
31 #include "net/test/test_with_task_environment.h"
32 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
33 #include "net/url_request/static_http_user_agent_settings.h"
34 #include "testing/gmock/include/gmock/gmock.h"
35 #include "testing/gtest/include/gtest/gtest.h"
36 
37 namespace net {
38 namespace {
39 
40 const char kProxyHostName[] = "proxy.test";
41 const int kProxyPort = 4321;
42 
43 constexpr base::TimeDelta kTinyTime = base::Microseconds(1);
44 
45 class SOCKSConnectJobTest : public testing::Test, public WithTaskEnvironment {
46  public:
47   enum class SOCKSVersion {
48     V4,
49     V5,
50   };
51 
SOCKSConnectJobTest()52   SOCKSConnectJobTest()
53       : WithTaskEnvironment(base::test::TaskEnvironment::TimeSource::MOCK_TIME),
54         common_connect_job_params_(
55             &client_socket_factory_,
56             &host_resolver_,
57             /*http_auth_cache=*/nullptr,
58             /*http_auth_handler_factory=*/nullptr,
59             /*spdy_session_pool=*/nullptr,
60             /*quic_supported_versions=*/nullptr,
61             /*quic_session_pool=*/nullptr,
62             /*proxy_delegate=*/nullptr,
63             &http_user_agent_settings_,
64             /*ssl_client_context=*/nullptr,
65             /*socket_performance_watcher_factory=*/nullptr,
66             /*network_quality_estimator=*/nullptr,
67             NetLog::Get(),
68             /*websocket_endpoint_lock_manager=*/nullptr,
69             /*http_server_properties=*/nullptr,
70             /*alpn_protos=*/nullptr,
71             /*application_settings=*/nullptr,
72             /*ignore_certificate_errors=*/nullptr,
73             /*early_data_enabled=*/nullptr) {}
74 
75   ~SOCKSConnectJobTest() override = default;
76 
CreateSOCKSParams(SOCKSVersion socks_version,SecureDnsPolicy secure_dns_policy=SecureDnsPolicy::kAllow)77   static scoped_refptr<SOCKSSocketParams> CreateSOCKSParams(
78       SOCKSVersion socks_version,
79       SecureDnsPolicy secure_dns_policy = SecureDnsPolicy::kAllow) {
80     return base::MakeRefCounted<SOCKSSocketParams>(
81         ConnectJobParams(base::MakeRefCounted<TransportSocketParams>(
82             HostPortPair(kProxyHostName, kProxyPort), NetworkAnonymizationKey(),
83             secure_dns_policy, OnHostResolutionCallback(),
84             /*supported_alpns=*/base::flat_set<std::string>())),
85         socks_version == SOCKSVersion::V5,
86         socks_version == SOCKSVersion::V4
87             ? HostPortPair(kSOCKS4TestHost, kSOCKS4TestPort)
88             : HostPortPair(kSOCKS5TestHost, kSOCKS5TestPort),
89         NetworkAnonymizationKey(), TRAFFIC_ANNOTATION_FOR_TESTS);
90   }
91 
92  protected:
93   MockHostResolver host_resolver_{/*default_result=*/MockHostResolverBase::
94                                       RuleResolver::GetLocalhostResult()};
95   MockTaggingClientSocketFactory client_socket_factory_;
96   const StaticHttpUserAgentSettings http_user_agent_settings_ = {"*",
97                                                                  "test-ua"};
98   const CommonConnectJobParams common_connect_job_params_;
99 };
100 
TEST_F(SOCKSConnectJobTest,HostResolutionFailure)101 TEST_F(SOCKSConnectJobTest, HostResolutionFailure) {
102   host_resolver_.rules()->AddSimulatedTimeoutFailure(kProxyHostName);
103 
104   for (bool failure_synchronous : {false, true}) {
105     host_resolver_.set_synchronous_mode(failure_synchronous);
106     TestConnectJobDelegate test_delegate;
107     SOCKSConnectJob socks_connect_job(DEFAULT_PRIORITY, SocketTag(),
108                                       &common_connect_job_params_,
109                                       CreateSOCKSParams(SOCKSVersion::V5),
110                                       &test_delegate, nullptr /* net_log */);
111     test_delegate.StartJobExpectingResult(
112         &socks_connect_job, ERR_PROXY_CONNECTION_FAILED, failure_synchronous);
113     EXPECT_THAT(socks_connect_job.GetResolveErrorInfo().error,
114                 test::IsError(ERR_DNS_TIMED_OUT));
115   }
116 }
117 
TEST_F(SOCKSConnectJobTest,HostResolutionFailureSOCKS4Endpoint)118 TEST_F(SOCKSConnectJobTest, HostResolutionFailureSOCKS4Endpoint) {
119   const char hostname[] = "google.com";
120   host_resolver_.rules()->AddSimulatedTimeoutFailure(hostname);
121 
122   for (bool failure_synchronous : {false, true}) {
123     host_resolver_.set_synchronous_mode(failure_synchronous);
124 
125     SequencedSocketData sequenced_socket_data{base::span<MockRead>(),
126                                               base::span<MockWrite>()};
127     sequenced_socket_data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
128     client_socket_factory_.AddSocketDataProvider(&sequenced_socket_data);
129 
130     scoped_refptr<SOCKSSocketParams> socket_params =
131         base::MakeRefCounted<SOCKSSocketParams>(
132             ConnectJobParams(base::MakeRefCounted<TransportSocketParams>(
133                 HostPortPair(kProxyHostName, kProxyPort),
134                 NetworkAnonymizationKey(), SecureDnsPolicy::kAllow,
135                 OnHostResolutionCallback(),
136                 /*supported_alpns=*/base::flat_set<std::string>())),
137             false /* socks_v5 */, HostPortPair(hostname, kSOCKS4TestPort),
138             NetworkAnonymizationKey(), TRAFFIC_ANNOTATION_FOR_TESTS);
139 
140     TestConnectJobDelegate test_delegate;
141     SOCKSConnectJob socks_connect_job(
142         DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
143         socket_params, &test_delegate, nullptr /* net_log */);
144     test_delegate.StartJobExpectingResult(
145         &socks_connect_job, ERR_NAME_NOT_RESOLVED, failure_synchronous);
146     EXPECT_THAT(socks_connect_job.GetResolveErrorInfo().error,
147                 test::IsError(ERR_DNS_TIMED_OUT));
148   }
149 }
150 
TEST_F(SOCKSConnectJobTest,HandshakeError)151 TEST_F(SOCKSConnectJobTest, HandshakeError) {
152   for (bool host_resolution_synchronous : {false, true}) {
153     for (bool write_failure_synchronous : {false, true}) {
154       host_resolver_.set_synchronous_mode(host_resolution_synchronous);
155 
156       // No need to distinguish which part of the handshake fails. Those details
157       // are all handled at the StreamSocket layer, not the SOCKSConnectJob.
158       MockWrite writes[] = {
159           MockWrite(write_failure_synchronous ? SYNCHRONOUS : ASYNC,
160                     ERR_UNEXPECTED, 0),
161       };
162       SequencedSocketData sequenced_socket_data(base::span<MockRead>(), writes);
163       // Host resolution is used to switch between sync and async connection
164       // behavior. The SOCKS layer can't distinguish between sync and async host
165       // resolution vs sync and async connection establishment, so just always
166       // make connection establishment synchroonous.
167       sequenced_socket_data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
168       client_socket_factory_.AddSocketDataProvider(&sequenced_socket_data);
169 
170       TestConnectJobDelegate test_delegate;
171       SOCKSConnectJob socks_connect_job(DEFAULT_PRIORITY, SocketTag(),
172                                         &common_connect_job_params_,
173                                         CreateSOCKSParams(SOCKSVersion::V5),
174                                         &test_delegate, nullptr /* net_log */);
175       test_delegate.StartJobExpectingResult(
176           &socks_connect_job, ERR_UNEXPECTED,
177           host_resolution_synchronous && write_failure_synchronous);
178     }
179   }
180 }
181 
TEST_F(SOCKSConnectJobTest,SOCKS4)182 TEST_F(SOCKSConnectJobTest, SOCKS4) {
183   for (bool host_resolution_synchronous : {false, true}) {
184     for (bool read_and_writes_synchronous : {true}) {
185       host_resolver_.set_synchronous_mode(host_resolution_synchronous);
186 
187       MockWrite writes[] = {
188           MockWrite(SYNCHRONOUS, kSOCKS4OkRequestLocalHostPort80,
189                     kSOCKS4OkRequestLocalHostPort80Length, 0),
190       };
191 
192       MockRead reads[] = {
193           MockRead(SYNCHRONOUS, kSOCKS4OkReply, kSOCKS4OkReplyLength, 1),
194       };
195 
196       SequencedSocketData sequenced_socket_data(reads, writes);
197       // Host resolution is used to switch between sync and async connection
198       // behavior. The SOCKS layer can't distinguish between sync and async host
199       // resolution vs sync and async connection establishment, so just always
200       // make connection establishment synchroonous.
201       sequenced_socket_data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
202       client_socket_factory_.AddSocketDataProvider(&sequenced_socket_data);
203 
204       TestConnectJobDelegate test_delegate;
205       SOCKSConnectJob socks_connect_job(DEFAULT_PRIORITY, SocketTag(),
206                                         &common_connect_job_params_,
207                                         CreateSOCKSParams(SOCKSVersion::V4),
208                                         &test_delegate, nullptr /* net_log */);
209       test_delegate.StartJobExpectingResult(
210           &socks_connect_job, OK,
211           host_resolution_synchronous && read_and_writes_synchronous);
212 
213       // Proxies should not set any DNS aliases.
214       EXPECT_TRUE(test_delegate.socket()->GetDnsAliases().empty());
215     }
216   }
217 }
218 
TEST_F(SOCKSConnectJobTest,SOCKS5)219 TEST_F(SOCKSConnectJobTest, SOCKS5) {
220   for (bool host_resolution_synchronous : {false, true}) {
221     for (bool read_and_writes_synchronous : {true}) {
222       host_resolver_.set_synchronous_mode(host_resolution_synchronous);
223 
224       MockWrite writes[] = {
225           MockWrite(SYNCHRONOUS, kSOCKS5GreetRequest, kSOCKS5GreetRequestLength,
226                     0),
227           MockWrite(SYNCHRONOUS, kSOCKS5OkRequest, kSOCKS5OkRequestLength, 2),
228       };
229 
230       MockRead reads[] = {
231           MockRead(SYNCHRONOUS, kSOCKS5GreetResponse,
232                    kSOCKS5GreetResponseLength, 1),
233           MockRead(SYNCHRONOUS, kSOCKS5OkResponse, kSOCKS5OkResponseLength, 3),
234       };
235 
236       SequencedSocketData sequenced_socket_data(reads, writes);
237       // Host resolution is used to switch between sync and async connection
238       // behavior. The SOCKS layer can't distinguish between sync and async host
239       // resolution vs sync and async connection establishment, so just always
240       // make connection establishment synchroonous.
241       sequenced_socket_data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
242       client_socket_factory_.AddSocketDataProvider(&sequenced_socket_data);
243 
244       TestConnectJobDelegate test_delegate;
245       SOCKSConnectJob socks_connect_job(DEFAULT_PRIORITY, SocketTag(),
246                                         &common_connect_job_params_,
247                                         CreateSOCKSParams(SOCKSVersion::V5),
248                                         &test_delegate, nullptr /* net_log */);
249       test_delegate.StartJobExpectingResult(
250           &socks_connect_job, OK,
251           host_resolution_synchronous && read_and_writes_synchronous);
252 
253       // Proxies should not set any DNS aliases.
254       EXPECT_TRUE(test_delegate.socket()->GetDnsAliases().empty());
255     }
256   }
257 }
258 
TEST_F(SOCKSConnectJobTest,HasEstablishedConnection)259 TEST_F(SOCKSConnectJobTest, HasEstablishedConnection) {
260   host_resolver_.set_ondemand_mode(true);
261   MockWrite writes[] = {
262       MockWrite(ASYNC, kSOCKS4OkRequestLocalHostPort80,
263                 kSOCKS4OkRequestLocalHostPort80Length, 0),
264   };
265 
266   MockRead reads[] = {
267       MockRead(ASYNC, ERR_IO_PENDING, 1),
268       MockRead(ASYNC, kSOCKS4OkReply, kSOCKS4OkReplyLength, 2),
269   };
270 
271   SequencedSocketData sequenced_socket_data(reads, writes);
272   sequenced_socket_data.set_connect_data(MockConnect(ASYNC, OK));
273   client_socket_factory_.AddSocketDataProvider(&sequenced_socket_data);
274 
275   TestConnectJobDelegate test_delegate;
276   SOCKSConnectJob socks_connect_job(DEFAULT_PRIORITY, SocketTag(),
277                                     &common_connect_job_params_,
278                                     CreateSOCKSParams(SOCKSVersion::V4),
279                                     &test_delegate, nullptr /* net_log */);
280   socks_connect_job.Connect();
281   EXPECT_EQ(LOAD_STATE_RESOLVING_HOST, socks_connect_job.GetLoadState());
282   EXPECT_FALSE(socks_connect_job.HasEstablishedConnection());
283 
284   host_resolver_.ResolveNow(1);
285   EXPECT_EQ(LOAD_STATE_CONNECTING, socks_connect_job.GetLoadState());
286   EXPECT_FALSE(socks_connect_job.HasEstablishedConnection());
287 
288   sequenced_socket_data.RunUntilPaused();
289   // "LOAD_STATE_CONNECTING" is also returned when negotiating a SOCKS
290   // connection.
291   EXPECT_EQ(LOAD_STATE_CONNECTING, socks_connect_job.GetLoadState());
292   EXPECT_TRUE(socks_connect_job.HasEstablishedConnection());
293   EXPECT_FALSE(test_delegate.has_result());
294 
295   sequenced_socket_data.Resume();
296   EXPECT_THAT(test_delegate.WaitForResult(), test::IsOk());
297   EXPECT_TRUE(test_delegate.has_result());
298 }
299 
300 // Check that TransportConnectJob's timeout is respected for the nested
301 // TransportConnectJob.
TEST_F(SOCKSConnectJobTest,TimeoutDuringDnsResolution)302 TEST_F(SOCKSConnectJobTest, TimeoutDuringDnsResolution) {
303   // Set HostResolver to hang.
304   host_resolver_.set_ondemand_mode(true);
305 
306   TestConnectJobDelegate test_delegate;
307   SOCKSConnectJob socks_connect_job(DEFAULT_PRIORITY, SocketTag(),
308                                     &common_connect_job_params_,
309                                     CreateSOCKSParams(SOCKSVersion::V5),
310                                     &test_delegate, nullptr /* net_log */);
311   socks_connect_job.Connect();
312 
313   // Just before the TransportConnectJob's timeout, nothing should have
314   // happened.
315   FastForwardBy(TransportConnectJob::ConnectionTimeout() - kTinyTime);
316   EXPECT_TRUE(host_resolver_.has_pending_requests());
317   EXPECT_FALSE(test_delegate.has_result());
318 
319   // Wait for exactly the TransportConnectJob's timeout to have passed. The Job
320   // should time out.
321   FastForwardBy(kTinyTime);
322   EXPECT_TRUE(test_delegate.has_result());
323   EXPECT_THAT(test_delegate.WaitForResult(),
324               test::IsError(ERR_PROXY_CONNECTION_FAILED));
325 }
326 
327 // Check that SOCKSConnectJob's timeout is respected for the handshake phase.
TEST_F(SOCKSConnectJobTest,TimeoutDuringHandshake)328 TEST_F(SOCKSConnectJobTest, TimeoutDuringHandshake) {
329   host_resolver_.set_ondemand_mode(true);
330 
331   MockWrite writes[] = {
332       MockWrite(SYNCHRONOUS, ERR_IO_PENDING, 0),
333   };
334 
335   SequencedSocketData sequenced_socket_data(base::span<MockRead>(), writes);
336   sequenced_socket_data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
337   client_socket_factory_.AddSocketDataProvider(&sequenced_socket_data);
338 
339   TestConnectJobDelegate test_delegate;
340   SOCKSConnectJob socks_connect_job(DEFAULT_PRIORITY, SocketTag(),
341                                     &common_connect_job_params_,
342                                     CreateSOCKSParams(SOCKSVersion::V5),
343                                     &test_delegate, nullptr /* net_log */);
344   socks_connect_job.Connect();
345 
346   // Just before the TransportConnectJob's timeout, nothing should have
347   // happened.
348   FastForwardBy(TransportConnectJob::ConnectionTimeout() - kTinyTime);
349   EXPECT_FALSE(test_delegate.has_result());
350   EXPECT_TRUE(host_resolver_.has_pending_requests());
351 
352   // DNS resolution completes, and the socket connects.  The request should not
353   // time out, even after the TransportConnectJob's timeout passes. The
354   // SOCKSConnectJob's handshake timer should also be started.
355   host_resolver_.ResolveAllPending();
356 
357   // Waiting until just before the SOCKS handshake times out. There should cause
358   // no observable change in the SOCKSConnectJob's status.
359   FastForwardBy(SOCKSConnectJob::HandshakeTimeoutForTesting() - kTinyTime);
360   EXPECT_FALSE(test_delegate.has_result());
361 
362   // Wait for exactly the SOCKSConnectJob's handshake timeout has fully elapsed.
363   // The Job should time out.
364   FastForwardBy(kTinyTime);
365   EXPECT_FALSE(host_resolver_.has_pending_requests());
366   EXPECT_TRUE(test_delegate.has_result());
367   EXPECT_THAT(test_delegate.WaitForResult(), test::IsError(ERR_TIMED_OUT));
368 }
369 
370 // Check initial priority is passed to the HostResolver, and priority can be
371 // modified.
TEST_F(SOCKSConnectJobTest,Priority)372 TEST_F(SOCKSConnectJobTest, Priority) {
373   host_resolver_.set_ondemand_mode(true);
374   for (int initial_priority = MINIMUM_PRIORITY;
375        initial_priority <= MAXIMUM_PRIORITY; ++initial_priority) {
376     for (int new_priority = MINIMUM_PRIORITY; new_priority <= MAXIMUM_PRIORITY;
377          ++new_priority) {
378       // Don't try changing priority to itself, as APIs may not allow that.
379       if (new_priority == initial_priority) {
380         continue;
381       }
382       TestConnectJobDelegate test_delegate;
383       SOCKSConnectJob socks_connect_job(
384           static_cast<RequestPriority>(initial_priority), SocketTag(),
385           &common_connect_job_params_, CreateSOCKSParams(SOCKSVersion::V4),
386           &test_delegate, nullptr /* net_log */);
387       ASSERT_THAT(socks_connect_job.Connect(), test::IsError(ERR_IO_PENDING));
388       ASSERT_TRUE(host_resolver_.has_pending_requests());
389       int request_id = host_resolver_.num_resolve();
390       EXPECT_EQ(initial_priority, host_resolver_.request_priority(request_id));
391 
392       // Change priority.
393       socks_connect_job.ChangePriority(
394           static_cast<RequestPriority>(new_priority));
395       EXPECT_EQ(new_priority, host_resolver_.request_priority(request_id));
396 
397       // Restore initial priority.
398       socks_connect_job.ChangePriority(
399           static_cast<RequestPriority>(initial_priority));
400       EXPECT_EQ(initial_priority, host_resolver_.request_priority(request_id));
401     }
402   }
403 }
404 
TEST_F(SOCKSConnectJobTest,SecureDnsPolicy)405 TEST_F(SOCKSConnectJobTest, SecureDnsPolicy) {
406   for (auto secure_dns_policy :
407        {SecureDnsPolicy::kAllow, SecureDnsPolicy::kDisable}) {
408     TestConnectJobDelegate test_delegate;
409     SOCKSConnectJob socks_connect_job(
410         DEFAULT_PRIORITY, SocketTag(), &common_connect_job_params_,
411         CreateSOCKSParams(SOCKSVersion::V4, secure_dns_policy), &test_delegate,
412         nullptr /* net_log */);
413     ASSERT_THAT(socks_connect_job.Connect(), test::IsError(ERR_IO_PENDING));
414     EXPECT_EQ(secure_dns_policy, host_resolver_.last_secure_dns_policy());
415   }
416 }
417 
TEST_F(SOCKSConnectJobTest,ConnectTiming)418 TEST_F(SOCKSConnectJobTest, ConnectTiming) {
419   host_resolver_.set_ondemand_mode(true);
420 
421   MockWrite writes[] = {
422       MockWrite(ASYNC, ERR_IO_PENDING, 0),
423       MockWrite(ASYNC, kSOCKS5GreetRequest, kSOCKS5GreetRequestLength, 1),
424       MockWrite(SYNCHRONOUS, kSOCKS5OkRequest, kSOCKS5OkRequestLength, 3),
425   };
426 
427   MockRead reads[] = {
428       MockRead(SYNCHRONOUS, kSOCKS5GreetResponse, kSOCKS5GreetResponseLength,
429                2),
430       MockRead(SYNCHRONOUS, kSOCKS5OkResponse, kSOCKS5OkResponseLength, 4),
431   };
432 
433   SequencedSocketData sequenced_socket_data(reads, writes);
434   // Host resolution is used to switch between sync and async connection
435   // behavior. The SOCKS layer can't distinguish between sync and async host
436   // resolution vs sync and async connection establishment, so just always
437   // make connection establishment synchroonous.
438   sequenced_socket_data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
439   client_socket_factory_.AddSocketDataProvider(&sequenced_socket_data);
440 
441   TestConnectJobDelegate test_delegate;
442   SOCKSConnectJob socks_connect_job(DEFAULT_PRIORITY, SocketTag(),
443                                     &common_connect_job_params_,
444                                     CreateSOCKSParams(SOCKSVersion::V5),
445                                     &test_delegate, nullptr /* net_log */);
446   base::TimeTicks start = base::TimeTicks::Now();
447   socks_connect_job.Connect();
448 
449   // DNS resolution completes after a short delay. The connection should be
450   // immediately established as well. The first write to the socket stalls.
451   FastForwardBy(kTinyTime);
452   host_resolver_.ResolveAllPending();
453   RunUntilIdle();
454 
455   // After another short delay, data is received from the server.
456   FastForwardBy(kTinyTime);
457   sequenced_socket_data.Resume();
458 
459   EXPECT_THAT(test_delegate.WaitForResult(), test::IsOk());
460   // Proxy name resolution is not considered resolving the host name for
461   // ConnectionInfo. For SOCKS4, where the host name is also looked up via DNS,
462   // the resolution time is not currently reported.
463   EXPECT_EQ(base::TimeTicks(),
464             socks_connect_job.connect_timing().domain_lookup_start);
465   EXPECT_EQ(base::TimeTicks(),
466             socks_connect_job.connect_timing().domain_lookup_end);
467 
468   // The "connect" time for socks proxies includes DNS resolution time.
469   EXPECT_EQ(start, socks_connect_job.connect_timing().connect_start);
470   EXPECT_EQ(start + 2 * kTinyTime,
471             socks_connect_job.connect_timing().connect_end);
472 
473   // Since SSL was not negotiated, SSL times are null.
474   EXPECT_EQ(base::TimeTicks(), socks_connect_job.connect_timing().ssl_start);
475   EXPECT_EQ(base::TimeTicks(), socks_connect_job.connect_timing().ssl_end);
476 }
477 
TEST_F(SOCKSConnectJobTest,CancelDuringDnsResolution)478 TEST_F(SOCKSConnectJobTest, CancelDuringDnsResolution) {
479   // Set HostResolver to hang.
480   host_resolver_.set_ondemand_mode(true);
481 
482   TestConnectJobDelegate test_delegate;
483   std::unique_ptr<SOCKSConnectJob> socks_connect_job =
484       std::make_unique<SOCKSConnectJob>(DEFAULT_PRIORITY, SocketTag(),
485                                         &common_connect_job_params_,
486                                         CreateSOCKSParams(SOCKSVersion::V5),
487                                         &test_delegate, nullptr /* net_log */);
488   socks_connect_job->Connect();
489 
490   EXPECT_TRUE(host_resolver_.has_pending_requests());
491 
492   socks_connect_job.reset();
493   RunUntilIdle();
494   EXPECT_FALSE(host_resolver_.has_pending_requests());
495   EXPECT_FALSE(test_delegate.has_result());
496 }
497 
TEST_F(SOCKSConnectJobTest,CancelDuringConnect)498 TEST_F(SOCKSConnectJobTest, CancelDuringConnect) {
499   host_resolver_.set_synchronous_mode(true);
500 
501   SequencedSocketData sequenced_socket_data{base::span<MockRead>(),
502                                             base::span<MockWrite>()};
503   sequenced_socket_data.set_connect_data(MockConnect(ASYNC, OK));
504   client_socket_factory_.AddSocketDataProvider(&sequenced_socket_data);
505 
506   TestConnectJobDelegate test_delegate;
507   std::unique_ptr<SOCKSConnectJob> socks_connect_job =
508       std::make_unique<SOCKSConnectJob>(DEFAULT_PRIORITY, SocketTag(),
509                                         &common_connect_job_params_,
510                                         CreateSOCKSParams(SOCKSVersion::V5),
511                                         &test_delegate, nullptr /* net_log */);
512   socks_connect_job->Connect();
513   // Host resolution should resolve immediately. The ConnectJob should currently
514   // be trying to connect.
515   EXPECT_FALSE(host_resolver_.has_pending_requests());
516 
517   socks_connect_job.reset();
518   RunUntilIdle();
519   EXPECT_FALSE(test_delegate.has_result());
520   // Socket should have been destroyed.
521   EXPECT_FALSE(sequenced_socket_data.socket());
522 }
523 
TEST_F(SOCKSConnectJobTest,CancelDuringHandshake)524 TEST_F(SOCKSConnectJobTest, CancelDuringHandshake) {
525   host_resolver_.set_synchronous_mode(true);
526 
527   // Hang at start of handshake.
528   MockWrite writes[] = {
529       MockWrite(SYNCHRONOUS, ERR_IO_PENDING, 0),
530   };
531   SequencedSocketData sequenced_socket_data(base::span<MockRead>(), writes);
532   sequenced_socket_data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
533   client_socket_factory_.AddSocketDataProvider(&sequenced_socket_data);
534 
535   TestConnectJobDelegate test_delegate;
536   std::unique_ptr<SOCKSConnectJob> socks_connect_job =
537       std::make_unique<SOCKSConnectJob>(DEFAULT_PRIORITY, SocketTag(),
538                                         &common_connect_job_params_,
539                                         CreateSOCKSParams(SOCKSVersion::V5),
540                                         &test_delegate, nullptr /* net_log */);
541   socks_connect_job->Connect();
542   // Host resolution should resolve immediately. The socket connecting, and the
543   // ConnectJob should currently be trying to send the SOCKS handshake.
544   EXPECT_FALSE(host_resolver_.has_pending_requests());
545 
546   socks_connect_job.reset();
547   RunUntilIdle();
548   EXPECT_FALSE(test_delegate.has_result());
549   // Socket should have been destroyed.
550   EXPECT_FALSE(sequenced_socket_data.socket());
551   EXPECT_TRUE(sequenced_socket_data.AllWriteDataConsumed());
552 }
553 
554 }  // namespace
555 }  // namespace net
556