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