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