xref: /aosp_15_r20/external/cronet/net/base/proxy_chain_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2023 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/base/proxy_chain.h"
6 
7 #include <optional>
8 #include <sstream>
9 
10 #include "base/strings/string_number_conversions.h"
11 #include "base/test/gtest_util.h"
12 #include "net/base/proxy_server.h"
13 #include "net/base/proxy_string_util.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 
16 namespace net {
17 
18 namespace {
19 
TEST(ProxyChainTest,DefaultConstructor)20 TEST(ProxyChainTest, DefaultConstructor) {
21   ProxyChain proxy_chain;
22   EXPECT_FALSE(proxy_chain.IsValid());
23 }
24 
TEST(ProxyChainTest,ConstructorsAndAssignmentOperators)25 TEST(ProxyChainTest, ConstructorsAndAssignmentOperators) {
26   std::vector proxy_servers = {
27       ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS),
28       ProxyUriToProxyServer("foo:666", ProxyServer::SCHEME_HTTPS)};
29 
30   ProxyChain proxy_chain = ProxyChain(proxy_servers);
31 
32   ProxyChain copy_constructed(proxy_chain);
33   EXPECT_EQ(proxy_chain, copy_constructed);
34 
35   ProxyChain copy_assigned = proxy_chain;
36   EXPECT_EQ(proxy_chain, copy_assigned);
37 
38   ProxyChain move_constructed{std::move(copy_constructed)};
39   EXPECT_EQ(proxy_chain, move_constructed);
40 
41   ProxyChain move_assigned = std::move(copy_assigned);
42   EXPECT_EQ(proxy_chain, move_assigned);
43 }
44 
TEST(ProxyChainTest,DirectProxy)45 TEST(ProxyChainTest, DirectProxy) {
46   ProxyChain proxy_chain1 = ProxyChain::Direct();
47   ProxyChain proxy_chain2 = ProxyChain(std::vector<ProxyServer>());
48   std::vector<ProxyServer> proxy_servers = {};
49 
50   // Equal and valid proxy chains.
51   ASSERT_EQ(proxy_chain1, proxy_chain2);
52   EXPECT_TRUE(proxy_chain1.IsValid());
53   EXPECT_TRUE(proxy_chain2.IsValid());
54 
55   EXPECT_TRUE(proxy_chain1.is_direct());
56   EXPECT_FALSE(proxy_chain1.is_single_proxy());
57   EXPECT_FALSE(proxy_chain1.is_multi_proxy());
58   ASSERT_EQ(proxy_chain1.length(), 0u);
59   ASSERT_EQ(proxy_chain1.proxy_servers(), proxy_servers);
60 }
61 
TEST(ProxyChainTest,Ostream)62 TEST(ProxyChainTest, Ostream) {
63   ProxyChain proxy_chain =
64       ProxyChain::FromSchemeHostAndPort(ProxyServer::SCHEME_HTTP, "foo", 80);
65   std::ostringstream out;
66   out << proxy_chain;
67   EXPECT_EQ(out.str(), "[foo:80]");
68 }
69 
TEST(ProxyChainTest,ToDebugString)70 TEST(ProxyChainTest, ToDebugString) {
71   ProxyChain proxy_chain1 =
72       ProxyChain(ProxyUriToProxyServer("foo:333", ProxyServer::SCHEME_SOCKS5));
73   EXPECT_EQ(proxy_chain1.ToDebugString(), "[socks5://foo:333]");
74 
75   ProxyChain proxy_chain2 =
76       ProxyChain({ProxyUriToProxyServer("foo:444", ProxyServer::SCHEME_HTTPS),
77                   ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS)});
78   EXPECT_EQ(proxy_chain2.ToDebugString(), "[https://foo:444, https://foo:555]");
79 
80   ProxyChain direct_proxy_chain = ProxyChain::Direct();
81   EXPECT_EQ(direct_proxy_chain.ToDebugString(), "[direct://]");
82 
83   ProxyChain ip_protection_proxy_chain = ProxyChain::ForIpProtection(
84       {ProxyUriToProxyServer("foo:444", ProxyServer::SCHEME_HTTPS),
85        ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS)});
86   EXPECT_EQ(ip_protection_proxy_chain.ToDebugString(),
87             "[https://foo:444, https://foo:555] (IP Protection)");
88 
89   ProxyChain invalid_proxy_chain = ProxyChain();
90   EXPECT_EQ(invalid_proxy_chain.ToDebugString(), "INVALID PROXY CHAIN");
91 }
92 
TEST(ProxyChainTest,FromSchemeHostAndPort)93 TEST(ProxyChainTest, FromSchemeHostAndPort) {
94   const struct {
95     const ProxyServer::Scheme input_scheme;
96     const char* const input_host;
97     const std::optional<uint16_t> input_port;
98     const char* const input_port_str;
99     const char* const expected_host;
100     const uint16_t expected_port;
101   } tests[] = {
102       {ProxyServer::SCHEME_HTTP, "foopy", 80, "80", "foopy", 80},
103 
104       // Non-standard port
105       {ProxyServer::SCHEME_HTTP, "foopy", 10, "10", "foopy", 10},
106       {ProxyServer::SCHEME_HTTP, "foopy", 0, "0", "foopy", 0},
107 
108       // Hostname canonicalization
109       {ProxyServer::SCHEME_HTTP, "FoOpY", 80, "80", "foopy", 80},
110       {ProxyServer::SCHEME_HTTP, "f\u00fcpy", 80, "80", "xn--fpy-hoa", 80},
111 
112       // IPv4 literal
113       {ProxyServer::SCHEME_HTTP, "1.2.3.4", 80, "80", "1.2.3.4", 80},
114 
115       // IPv4 literal canonicalization
116       {ProxyServer::SCHEME_HTTP, "127.1", 80, "80", "127.0.0.1", 80},
117       {ProxyServer::SCHEME_HTTP, "0x7F.0x1", 80, "80", "127.0.0.1", 80},
118       {ProxyServer::SCHEME_HTTP, "0177.01", 80, "80", "127.0.0.1", 80},
119 
120       // IPv6 literal
121       {ProxyServer::SCHEME_HTTP, "[3ffe:2a00:100:7031::1]", 80, "80",
122        "[3ffe:2a00:100:7031::1]", 80},
123       {ProxyServer::SCHEME_HTTP, "3ffe:2a00:100:7031::1", 80, "80",
124        "[3ffe:2a00:100:7031::1]", 80},
125 
126       // IPv6 literal canonicalization
127       {ProxyServer::SCHEME_HTTP, "FEDC:BA98:7654:3210:FEDC:BA98:7654:3210", 80,
128        "80", "[fedc:ba98:7654:3210:fedc:ba98:7654:3210]", 80},
129       {ProxyServer::SCHEME_HTTP, "::192.9.5.5", 80, "80", "[::c009:505]", 80},
130 
131       // Other schemes
132       {ProxyServer::SCHEME_HTTPS, "foopy", 111, "111", "foopy", 111},
133       {ProxyServer::SCHEME_SOCKS4, "foopy", 111, "111", "foopy", 111},
134       {ProxyServer::SCHEME_SOCKS5, "foopy", 111, "111", "foopy", 111},
135 
136       // Default ports
137       {ProxyServer::SCHEME_HTTP, "foopy", std::nullopt, "", "foopy", 80},
138       {ProxyServer::SCHEME_HTTPS, "foopy", std::nullopt, "", "foopy", 443},
139       {ProxyServer::SCHEME_SOCKS4, "foopy", std::nullopt, "", "foopy", 1080},
140       {ProxyServer::SCHEME_SOCKS5, "foopy", std::nullopt, "", "foopy", 1080},
141   };
142 
143   for (size_t i = 0; i < std::size(tests); ++i) {
144     SCOPED_TRACE(base::NumberToString(i) + ": " + tests[i].input_host + ":" +
145                  base::NumberToString(tests[i].input_port.value_or(-1)));
146     auto chain = ProxyChain::FromSchemeHostAndPort(
147         tests[i].input_scheme, tests[i].input_host, tests[i].input_port);
148     auto proxy = chain.First();
149 
150     ASSERT_TRUE(proxy.is_valid());
151     EXPECT_EQ(proxy.scheme(), tests[i].input_scheme);
152     EXPECT_EQ(proxy.GetHost(), tests[i].expected_host);
153     EXPECT_EQ(proxy.GetPort(), tests[i].expected_port);
154 
155     auto chain_from_string_port = ProxyChain::FromSchemeHostAndPort(
156         tests[i].input_scheme, tests[i].input_host, tests[i].input_port_str);
157     auto proxy_from_string_port = chain_from_string_port.First();
158     EXPECT_TRUE(proxy_from_string_port.is_valid());
159     EXPECT_EQ(proxy, proxy_from_string_port);
160   }
161 }
162 
TEST(ProxyChainTest,InvalidHostname)163 TEST(ProxyChainTest, InvalidHostname) {
164   const char* const tests[]{
165       "",
166       "[]",
167       "[foo]",
168       "foo:",
169       "foo:80",
170       ":",
171       "http://foo",
172       "3ffe:2a00:100:7031::1]",
173       "[3ffe:2a00:100:7031::1",
174       "foo.80",
175   };
176 
177   for (size_t i = 0; i < std::size(tests); ++i) {
178     SCOPED_TRACE(base::NumberToString(i) + ": " + tests[i]);
179     auto proxy = ProxyChain::FromSchemeHostAndPort(ProxyServer::SCHEME_HTTP,
180                                                    tests[i], 80);
181     EXPECT_FALSE(proxy.IsValid());
182   }
183 }
184 
TEST(ProxyChainTest,InvalidPort)185 TEST(ProxyChainTest, InvalidPort) {
186   const char* const tests[]{
187       "-1",
188       "65536",
189       "foo",
190       "0x35",
191   };
192 
193   for (size_t i = 0; i < std::size(tests); ++i) {
194     SCOPED_TRACE(base::NumberToString(i) + ": " + tests[i]);
195     auto proxy = ProxyChain::FromSchemeHostAndPort(ProxyServer::SCHEME_HTTP,
196                                                    "foopy", tests[i]);
197     EXPECT_FALSE(proxy.IsValid());
198   }
199 }
200 
TEST(ProxyChainTest,SingleProxyChain)201 TEST(ProxyChainTest, SingleProxyChain) {
202   auto proxy_server =
203       ProxyUriToProxyServer("foo:333", ProxyServer::SCHEME_HTTPS);
204 
205   std::vector<ProxyServer> proxy_servers = {proxy_server};
206   auto proxy = ProxyChain(proxy_servers);
207 
208   EXPECT_FALSE(proxy.is_direct());
209   EXPECT_TRUE(proxy.is_single_proxy());
210   EXPECT_FALSE(proxy.is_multi_proxy());
211   ASSERT_EQ(proxy.proxy_servers(), proxy_servers);
212   ASSERT_EQ(proxy.length(), 1u);
213   ASSERT_EQ(proxy.GetProxyServer(0), proxy_server);
214 }
215 
TEST(ProxyChainTest,MultiProxyChain)216 TEST(ProxyChainTest, MultiProxyChain) {
217   auto proxy_server1 =
218       ProxyUriToProxyServer("foo:333", ProxyServer::SCHEME_HTTPS);
219   auto proxy_server2 =
220       ProxyUriToProxyServer("foo:444", ProxyServer::SCHEME_HTTPS);
221   auto proxy_server3 =
222       ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS);
223 
224   std::vector<ProxyServer> proxy_servers = {proxy_server1, proxy_server2,
225                                             proxy_server3};
226   auto proxy = ProxyChain(proxy_servers);
227 
228   EXPECT_FALSE(proxy.is_direct());
229   EXPECT_FALSE(proxy.is_single_proxy());
230   EXPECT_TRUE(proxy.is_multi_proxy());
231   ASSERT_EQ(proxy.proxy_servers(), proxy_servers);
232   ASSERT_EQ(proxy.length(), 3u);
233   ASSERT_EQ(proxy.GetProxyServer(0), proxy_server1);
234   ASSERT_EQ(proxy.GetProxyServer(1), proxy_server2);
235   ASSERT_EQ(proxy.GetProxyServer(2), proxy_server3);
236 }
237 
TEST(ProxyChainTest,SplitLast)238 TEST(ProxyChainTest, SplitLast) {
239   auto proxy_server1 =
240       ProxyUriToProxyServer("foo:333", ProxyServer::SCHEME_HTTPS);
241   auto proxy_server2 =
242       ProxyUriToProxyServer("foo:444", ProxyServer::SCHEME_HTTPS);
243   auto proxy_server3 =
244       ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS);
245 
246   auto chain3 = ProxyChain::ForIpProtection(
247       {proxy_server1, proxy_server2, proxy_server3});
248   EXPECT_EQ(chain3.SplitLast(),
249             std::make_pair(
250                 ProxyChain::ForIpProtection({proxy_server1, proxy_server2}),
251                 proxy_server3));
252 
253   auto chain2 = ProxyChain({proxy_server1, proxy_server2});
254   EXPECT_EQ(chain2.SplitLast(),
255             std::make_pair(ProxyChain({proxy_server1}), proxy_server2));
256 
257   auto chain1 = ProxyChain({proxy_server1});
258   EXPECT_EQ(chain1.SplitLast(),
259             std::make_pair(ProxyChain::Direct(), proxy_server1));
260 }
261 
TEST(ProxyChainTest,Prefix)262 TEST(ProxyChainTest, Prefix) {
263   auto proxy_server1 =
264       ProxyUriToProxyServer("foo:333", ProxyServer::SCHEME_HTTPS);
265   auto proxy_server2 =
266       ProxyUriToProxyServer("foo:444", ProxyServer::SCHEME_HTTPS);
267   auto proxy_server3 =
268       ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS);
269   auto chain = ProxyChain::ForIpProtection(
270       {proxy_server1, proxy_server2, proxy_server3}, /*chain_id=*/2);
271   EXPECT_EQ(chain.Prefix(0), ProxyChain::ForIpProtection({}, /*chain_id=*/2));
272   EXPECT_EQ(chain.Prefix(1),
273             ProxyChain::ForIpProtection({proxy_server1}, /*chain_id=*/2));
274   EXPECT_EQ(chain.Prefix(2),
275             ProxyChain::ForIpProtection({proxy_server1, proxy_server2},
276                                         /*chain_id=*/2));
277   EXPECT_EQ(chain.Prefix(3),
278             ProxyChain::ForIpProtection(
279                 {proxy_server1, proxy_server2, proxy_server3}, /*chain_id=*/2));
280 }
281 
TEST(ProxyChainTest,First)282 TEST(ProxyChainTest, First) {
283   auto proxy_server1 =
284       ProxyUriToProxyServer("foo:333", ProxyServer::SCHEME_HTTPS);
285   auto proxy_server2 =
286       ProxyUriToProxyServer("foo:444", ProxyServer::SCHEME_HTTPS);
287 
288   auto chain = ProxyChain({proxy_server1, proxy_server2});
289   EXPECT_EQ(chain.First(), proxy_server1);
290 
291   chain = ProxyChain({proxy_server1});
292   EXPECT_EQ(chain.First(), proxy_server1);
293 }
294 
TEST(ProxyChainTest,Last)295 TEST(ProxyChainTest, Last) {
296   auto proxy_server1 =
297       ProxyUriToProxyServer("foo:333", ProxyServer::SCHEME_HTTPS);
298   auto proxy_server2 =
299       ProxyUriToProxyServer("foo:444", ProxyServer::SCHEME_HTTPS);
300 
301   auto chain = ProxyChain({proxy_server1, proxy_server2});
302   EXPECT_EQ(chain.Last(), proxy_server2);
303 
304   chain = ProxyChain({proxy_server1});
305   EXPECT_EQ(chain.Last(), proxy_server1);
306 }
307 
TEST(ProxyChainTest,IsForIpProtection)308 TEST(ProxyChainTest, IsForIpProtection) {
309   auto regular_proxy_chain1 = ProxyChain::Direct();
310   EXPECT_FALSE(regular_proxy_chain1.is_for_ip_protection());
311 
312   auto ip_protection_proxy_chain1 =
313       ProxyChain::ForIpProtection(std::vector<ProxyServer>());
314   EXPECT_TRUE(ip_protection_proxy_chain1.is_for_ip_protection());
315 
316   auto regular_proxy_chain2 =
317       ProxyChain({ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS),
318                   ProxyUriToProxyServer("foo:666", ProxyServer::SCHEME_HTTPS)});
319   EXPECT_FALSE(regular_proxy_chain2.is_for_ip_protection());
320 
321   auto ip_protection_proxy_chain2 = ProxyChain::ForIpProtection(
322       {ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS),
323        ProxyUriToProxyServer("foo:666", ProxyServer::SCHEME_HTTPS)});
324   EXPECT_TRUE(ip_protection_proxy_chain2.is_for_ip_protection());
325 }
326 
TEST(ProxyChainTest,ForIpProtection)327 TEST(ProxyChainTest, ForIpProtection) {
328   auto ip_protection_proxy_chain1 =
329       ProxyChain::ForIpProtection(std::vector<ProxyServer>());
330   EXPECT_TRUE(ip_protection_proxy_chain1.is_direct());
331   EXPECT_TRUE(ip_protection_proxy_chain1.is_for_ip_protection());
332   EXPECT_EQ(ip_protection_proxy_chain1.ip_protection_chain_id(),
333             ProxyChain::kDefaultIpProtectionChainId);
334 
335   auto regular_proxy_chain2 =
336       ProxyChain({ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS),
337                   ProxyUriToProxyServer("foo:666", ProxyServer::SCHEME_HTTPS)});
338   auto ip_protection_proxy_chain2 = ProxyChain::ForIpProtection(
339       {ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS),
340        ProxyUriToProxyServer("foo:666", ProxyServer::SCHEME_HTTPS)});
341   EXPECT_TRUE(ip_protection_proxy_chain2.is_for_ip_protection());
342   EXPECT_EQ(ip_protection_proxy_chain2.ip_protection_chain_id(),
343             ProxyChain::kDefaultIpProtectionChainId);
344   EXPECT_EQ(regular_proxy_chain2.proxy_servers(),
345             ip_protection_proxy_chain2.proxy_servers());
346 
347   auto self_assignable_proxy_chain =
348       ProxyChain({ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS),
349                   ProxyUriToProxyServer("foo:666", ProxyServer::SCHEME_HTTPS)});
350   auto copied_proxy_chain = self_assignable_proxy_chain;
351 
352   EXPECT_FALSE(self_assignable_proxy_chain.is_for_ip_protection());
353   EXPECT_EQ(self_assignable_proxy_chain.ip_protection_chain_id(),
354             ProxyChain::kNotIpProtectionChainId);
355 
356   self_assignable_proxy_chain = ProxyChain::ForIpProtection(
357       std::move(self_assignable_proxy_chain.proxy_servers()));
358   EXPECT_TRUE(self_assignable_proxy_chain.is_for_ip_protection());
359   EXPECT_EQ(self_assignable_proxy_chain.proxy_servers(),
360             copied_proxy_chain.proxy_servers());
361   EXPECT_EQ(self_assignable_proxy_chain.ip_protection_chain_id(),
362             ProxyChain::kDefaultIpProtectionChainId);
363 
364   auto chain_with_id = ProxyChain::ForIpProtection(
365       {ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS),
366        ProxyUriToProxyServer("foo:666", ProxyServer::SCHEME_HTTPS)},
367       /*chain_id=*/3);
368   EXPECT_FALSE(chain_with_id.is_direct());
369   EXPECT_TRUE(chain_with_id.is_for_ip_protection());
370   EXPECT_EQ(chain_with_id.ip_protection_chain_id(), 3);
371 }
372 
TEST(ProxyChainTest,IsGetToProxyAllowed)373 TEST(ProxyChainTest, IsGetToProxyAllowed) {
374   auto https_server1 =
375       ProxyUriToProxyServer("foo:333", ProxyServer::SCHEME_HTTPS);
376   auto https_server2 =
377       ProxyUriToProxyServer("foo:444", ProxyServer::SCHEME_HTTPS);
378   auto http_server = ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTP);
379   auto socks_server =
380       ProxyUriToProxyServer("foo:666", ProxyServer::SCHEME_SOCKS4);
381 
382   EXPECT_FALSE(ProxyChain::Direct().is_get_to_proxy_allowed());
383   EXPECT_TRUE(ProxyChain({https_server1}).is_get_to_proxy_allowed());
384   EXPECT_TRUE(ProxyChain({http_server}).is_get_to_proxy_allowed());
385   EXPECT_FALSE(ProxyChain({socks_server}).is_get_to_proxy_allowed());
386   EXPECT_FALSE(
387       ProxyChain({https_server1, https_server2}).is_get_to_proxy_allowed());
388 }
389 
TEST(ProxyChainTest,IsValid)390 TEST(ProxyChainTest, IsValid) {
391   // Single hop proxy of type Direct is valid.
392   EXPECT_TRUE(ProxyChain::Direct().IsValid());
393 
394   auto https1 = ProxyUriToProxyServer("foo:444", ProxyServer::SCHEME_HTTPS);
395   auto https2 = ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS);
396   auto quic1 = ProxyUriToProxyServer("foo:666", ProxyServer::SCHEME_QUIC);
397   auto quic2 = ProxyUriToProxyServer("foo:777", ProxyServer::SCHEME_QUIC);
398   auto socks = ProxyUriToProxyServer("foo:777", ProxyServer::SCHEME_SOCKS5);
399 
400   EXPECT_TRUE(ProxyChain({https1}).IsValid());
401   EXPECT_FALSE(ProxyChain({quic1}).IsValid());
402   EXPECT_TRUE(ProxyChain({https1, https2}).IsValid());
403   EXPECT_FALSE(ProxyChain({quic1, https1}).IsValid());
404   EXPECT_FALSE(ProxyChain({quic1, quic2, https1, https2}).IsValid());
405   EXPECT_FALSE(ProxyChain({https1, quic2}).IsValid());
406   EXPECT_FALSE(ProxyChain({https1, https2, quic1, quic2}).IsValid());
407   EXPECT_FALSE(ProxyChain({socks, https1}).IsValid());
408   EXPECT_FALSE(ProxyChain({socks, https1, https2}).IsValid());
409   EXPECT_FALSE(ProxyChain({https1, socks}).IsValid());
410   EXPECT_FALSE(ProxyChain({https1, https2, socks}).IsValid());
411 
412   // IP protection accepts chains with SCHEME_QUIC, but CHECKs on failure
413   // instead of just creating an invalid chain.
414   auto IppChain = [](std::vector<ProxyServer> proxy_servers) {
415     return ProxyChain::ForIpProtection(std::move(proxy_servers));
416   };
417   EXPECT_TRUE(IppChain({https1}).IsValid());
418   EXPECT_TRUE(IppChain({quic1}).IsValid());
419   EXPECT_TRUE(IppChain({https1, https2}).IsValid());
420   EXPECT_TRUE(IppChain({quic1, https1}).IsValid());
421   EXPECT_TRUE(IppChain({quic1, quic2, https1, https2}).IsValid());
422   EXPECT_CHECK_DEATH(IppChain({https1, quic2}).IsValid());
423   EXPECT_CHECK_DEATH(IppChain({https1, https2, quic1, quic2}).IsValid());
424   EXPECT_CHECK_DEATH(IppChain({socks, https1}).IsValid());
425   EXPECT_CHECK_DEATH(IppChain({socks, https1, https2}).IsValid());
426   EXPECT_CHECK_DEATH(IppChain({https1, socks}).IsValid());
427   EXPECT_CHECK_DEATH(IppChain({https1, https2, socks}).IsValid());
428 }
429 
TEST(ProxyChainTest,Unequal)430 TEST(ProxyChainTest, Unequal) {
431   // Ordered proxy chains.
432   std::vector<ProxyChain> proxy_chain_list = {
433       ProxyChain::Direct(),
434       ProxyUriToProxyChain("foo:333", ProxyServer::SCHEME_HTTP),
435       ProxyUriToProxyChain("foo:444", ProxyServer::SCHEME_HTTP),
436       ProxyChain({ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS),
437                   ProxyUriToProxyServer("foo:666", ProxyServer::SCHEME_HTTPS)}),
438       ProxyUriToProxyChain("socks4://foo:33", ProxyServer::SCHEME_SOCKS4),
439       ProxyUriToProxyChain("http://foo:33", ProxyServer::SCHEME_HTTP),
440       ProxyChain({ProxyUriToProxyChain("bar:33", ProxyServer::SCHEME_HTTP)}),
441       ProxyChain::ForIpProtection(
442           {ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS),
443            ProxyUriToProxyServer("foo:666", ProxyServer::SCHEME_HTTPS)})};
444 
445   // Unordered proxy chains.
446   std::set<ProxyChain> proxy_chain_set(proxy_chain_list.begin(),
447                                        proxy_chain_list.end());
448 
449   // Initial proxy chain list and set are equal.
450   ASSERT_EQ(proxy_chain_list.size(), proxy_chain_set.size());
451 
452   for (const ProxyChain& proxy_chain1 : proxy_chain_list) {
453     auto proxy_chain2 = proxy_chain_set.begin();
454     // Chain set entries less than `proxy_chain1`.
455     while (*proxy_chain2 < proxy_chain1) {
456       EXPECT_TRUE(*proxy_chain2 < proxy_chain1);
457       EXPECT_FALSE(proxy_chain1 < *proxy_chain2);
458       EXPECT_FALSE(*proxy_chain2 == proxy_chain1);
459       EXPECT_FALSE(proxy_chain1 == *proxy_chain2);
460       ++proxy_chain2;
461     }
462 
463     // Chain set entry for `proxy_chain1`.
464     EXPECT_FALSE(*proxy_chain2 < proxy_chain1);
465     EXPECT_FALSE(proxy_chain1 < *proxy_chain2);
466     EXPECT_TRUE(*proxy_chain2 == proxy_chain1);
467     EXPECT_TRUE(proxy_chain1 == *proxy_chain2);
468     ++proxy_chain2;
469 
470     // Chain set entries greater than `proxy_chain1`.
471     while (proxy_chain2 != proxy_chain_set.end() &&
472            proxy_chain1 < *proxy_chain2) {
473       EXPECT_FALSE(*proxy_chain2 < proxy_chain1);
474       EXPECT_TRUE(proxy_chain1 < *proxy_chain2);
475       EXPECT_FALSE(*proxy_chain2 == proxy_chain1);
476       EXPECT_FALSE(proxy_chain1 == *proxy_chain2);
477       ++proxy_chain2;
478     }
479     ASSERT_EQ(proxy_chain2, proxy_chain_set.end());
480   }
481 }
482 
TEST(ProxyChainTest,Equal)483 TEST(ProxyChainTest, Equal) {
484   ProxyServer proxy_server =
485       ProxyUriToProxyServer("foo:11", ProxyServer::SCHEME_HTTP);
486 
487   ProxyChain proxy_chain1 = ProxyChain(proxy_server);
488   ProxyChain proxy_chain2 = ProxyChain(std::vector<ProxyServer>{proxy_server});
489   ProxyChain proxy_chain3 =
490       ProxyChain(ProxyServer::SCHEME_HTTP, HostPortPair("foo", 11));
491 
492   EXPECT_FALSE(proxy_chain1 < proxy_chain2);
493   EXPECT_FALSE(proxy_chain2 < proxy_chain1);
494   EXPECT_TRUE(proxy_chain2 == proxy_chain1);
495   EXPECT_TRUE(proxy_chain2 == proxy_chain1);
496 
497   EXPECT_FALSE(proxy_chain2 < proxy_chain3);
498   EXPECT_FALSE(proxy_chain3 < proxy_chain2);
499   EXPECT_TRUE(proxy_chain3 == proxy_chain2);
500   EXPECT_TRUE(proxy_chain3 == proxy_chain2);
501 }
502 
503 }  // namespace
504 
505 }  // namespace net
506