• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #include "net/base/proxy_chain.h"
11 
12 #include <optional>
13 #include <sstream>
14 
15 #include "base/pickle.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/test/gtest_util.h"
18 #include "build/buildflag.h"
19 #include "net/base/proxy_server.h"
20 #include "net/base/proxy_string_util.h"
21 #include "net/net_buildflags.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23 
24 namespace net {
25 
26 namespace {
27 
TEST(ProxyChainTest,DefaultConstructor)28 TEST(ProxyChainTest, DefaultConstructor) {
29   ProxyChain proxy_chain;
30   EXPECT_FALSE(proxy_chain.IsValid());
31 }
32 
TEST(ProxyChainTest,ConstructorsAndAssignmentOperators)33 TEST(ProxyChainTest, ConstructorsAndAssignmentOperators) {
34   std::vector proxy_servers = {
35       ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS),
36       ProxyUriToProxyServer("foo:666", ProxyServer::SCHEME_HTTPS)};
37 
38   ProxyChain proxy_chain = ProxyChain(proxy_servers);
39 
40   ProxyChain copy_constructed(proxy_chain);
41   EXPECT_EQ(proxy_chain, copy_constructed);
42 
43   ProxyChain copy_assigned = proxy_chain;
44   EXPECT_EQ(proxy_chain, copy_assigned);
45 
46   ProxyChain move_constructed{std::move(copy_constructed)};
47   EXPECT_EQ(proxy_chain, move_constructed);
48 
49   ProxyChain move_assigned = std::move(copy_assigned);
50   EXPECT_EQ(proxy_chain, move_assigned);
51 }
52 
TEST(ProxyChainTest,DirectProxy)53 TEST(ProxyChainTest, DirectProxy) {
54   ProxyChain proxy_chain1 = ProxyChain::Direct();
55   ProxyChain proxy_chain2 = ProxyChain(std::vector<ProxyServer>());
56   std::vector<ProxyServer> proxy_servers = {};
57 
58   // Equal and valid proxy chains.
59   ASSERT_EQ(proxy_chain1, proxy_chain2);
60   EXPECT_TRUE(proxy_chain1.IsValid());
61   EXPECT_TRUE(proxy_chain2.IsValid());
62 
63   EXPECT_TRUE(proxy_chain1.is_direct());
64   EXPECT_FALSE(proxy_chain1.is_single_proxy());
65   EXPECT_FALSE(proxy_chain1.is_multi_proxy());
66   ASSERT_EQ(proxy_chain1.length(), 0u);
67   ASSERT_EQ(proxy_chain1.proxy_servers(), proxy_servers);
68 }
69 
TEST(ProxyChainTest,Ostream)70 TEST(ProxyChainTest, Ostream) {
71   ProxyChain proxy_chain =
72       ProxyChain::FromSchemeHostAndPort(ProxyServer::SCHEME_HTTP, "foo", 80);
73   std::ostringstream out;
74   out << proxy_chain;
75   EXPECT_EQ(out.str(), "[foo:80]");
76 }
77 
TEST(ProxyChainTest,ToDebugString)78 TEST(ProxyChainTest, ToDebugString) {
79   ProxyChain proxy_chain1 =
80       ProxyChain(ProxyUriToProxyServer("foo:333", ProxyServer::SCHEME_SOCKS5));
81   EXPECT_EQ(proxy_chain1.ToDebugString(), "[socks5://foo:333]");
82 
83   ProxyChain direct_proxy_chain = ProxyChain::Direct();
84   EXPECT_EQ(direct_proxy_chain.ToDebugString(), "[direct://]");
85 
86   ProxyChain ip_protection_proxy_chain = ProxyChain::ForIpProtection(
87       {ProxyUriToProxyServer("foo:444", ProxyServer::SCHEME_HTTPS),
88        ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS)});
89   EXPECT_EQ(ip_protection_proxy_chain.ToDebugString(),
90             "[https://foo:444, https://foo:555] (IP Protection)");
91 
92   ProxyChain invalid_proxy_chain = ProxyChain();
93   EXPECT_EQ(invalid_proxy_chain.ToDebugString(), "INVALID PROXY CHAIN");
94 
95 // Multi-proxy chains can only be created outside of Ip Protection in debug
96 // builds.
97 #if BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
98   ProxyChain proxy_chain2 =
99       ProxyChain({ProxyUriToProxyServer("foo:444", ProxyServer::SCHEME_HTTPS),
100                   ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS)});
101   EXPECT_EQ(proxy_chain2.ToDebugString(), "[https://foo:444, https://foo:555]");
102 #endif  // BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
103 }
104 
TEST(ProxyChainTest,FromSchemeHostAndPort)105 TEST(ProxyChainTest, FromSchemeHostAndPort) {
106   const struct {
107     const ProxyServer::Scheme input_scheme;
108     const char* const input_host;
109     const std::optional<uint16_t> input_port;
110     const char* const input_port_str;
111     const char* const expected_host;
112     const uint16_t expected_port;
113   } tests[] = {
114       {ProxyServer::SCHEME_HTTP, "foopy", 80, "80", "foopy", 80},
115 
116       // Non-standard port
117       {ProxyServer::SCHEME_HTTP, "foopy", 10, "10", "foopy", 10},
118       {ProxyServer::SCHEME_HTTP, "foopy", 0, "0", "foopy", 0},
119 
120       // Hostname canonicalization
121       {ProxyServer::SCHEME_HTTP, "FoOpY", 80, "80", "foopy", 80},
122       {ProxyServer::SCHEME_HTTP, "f\u00fcpy", 80, "80", "xn--fpy-hoa", 80},
123 
124       // IPv4 literal
125       {ProxyServer::SCHEME_HTTP, "1.2.3.4", 80, "80", "1.2.3.4", 80},
126 
127       // IPv4 literal canonicalization
128       {ProxyServer::SCHEME_HTTP, "127.1", 80, "80", "127.0.0.1", 80},
129       {ProxyServer::SCHEME_HTTP, "0x7F.0x1", 80, "80", "127.0.0.1", 80},
130       {ProxyServer::SCHEME_HTTP, "0177.01", 80, "80", "127.0.0.1", 80},
131 
132       // IPv6 literal
133       {ProxyServer::SCHEME_HTTP, "[3ffe:2a00:100:7031::1]", 80, "80",
134        "[3ffe:2a00:100:7031::1]", 80},
135       {ProxyServer::SCHEME_HTTP, "3ffe:2a00:100:7031::1", 80, "80",
136        "[3ffe:2a00:100:7031::1]", 80},
137 
138       // IPv6 literal canonicalization
139       {ProxyServer::SCHEME_HTTP, "FEDC:BA98:7654:3210:FEDC:BA98:7654:3210", 80,
140        "80", "[fedc:ba98:7654:3210:fedc:ba98:7654:3210]", 80},
141       {ProxyServer::SCHEME_HTTP, "::192.9.5.5", 80, "80", "[::c009:505]", 80},
142 
143       // Other schemes
144       {ProxyServer::SCHEME_HTTPS, "foopy", 111, "111", "foopy", 111},
145       {ProxyServer::SCHEME_SOCKS4, "foopy", 111, "111", "foopy", 111},
146       {ProxyServer::SCHEME_SOCKS5, "foopy", 111, "111", "foopy", 111},
147 
148       // Default ports
149       {ProxyServer::SCHEME_HTTP, "foopy", std::nullopt, "", "foopy", 80},
150       {ProxyServer::SCHEME_HTTPS, "foopy", std::nullopt, "", "foopy", 443},
151       {ProxyServer::SCHEME_SOCKS4, "foopy", std::nullopt, "", "foopy", 1080},
152       {ProxyServer::SCHEME_SOCKS5, "foopy", std::nullopt, "", "foopy", 1080},
153   };
154 
155   for (size_t i = 0; i < std::size(tests); ++i) {
156     SCOPED_TRACE(base::NumberToString(i) + ": " + tests[i].input_host + ":" +
157                  base::NumberToString(tests[i].input_port.value_or(-1)));
158     auto chain = ProxyChain::FromSchemeHostAndPort(
159         tests[i].input_scheme, tests[i].input_host, tests[i].input_port);
160     auto proxy = chain.First();
161 
162     ASSERT_TRUE(proxy.is_valid());
163     EXPECT_EQ(proxy.scheme(), tests[i].input_scheme);
164     EXPECT_EQ(proxy.GetHost(), tests[i].expected_host);
165     EXPECT_EQ(proxy.GetPort(), tests[i].expected_port);
166 
167     auto chain_from_string_port = ProxyChain::FromSchemeHostAndPort(
168         tests[i].input_scheme, tests[i].input_host, tests[i].input_port_str);
169     auto proxy_from_string_port = chain_from_string_port.First();
170     EXPECT_TRUE(proxy_from_string_port.is_valid());
171     EXPECT_EQ(proxy, proxy_from_string_port);
172   }
173 }
174 
TEST(ProxyChainTest,InvalidHostname)175 TEST(ProxyChainTest, InvalidHostname) {
176   const char* const tests[]{
177       "",
178       "[]",
179       "[foo]",
180       "foo:",
181       "foo:80",
182       ":",
183       "http://foo",
184       "3ffe:2a00:100:7031::1]",
185       "[3ffe:2a00:100:7031::1",
186       "foo.80",
187   };
188 
189   for (size_t i = 0; i < std::size(tests); ++i) {
190     SCOPED_TRACE(base::NumberToString(i) + ": " + tests[i]);
191     auto proxy = ProxyChain::FromSchemeHostAndPort(ProxyServer::SCHEME_HTTP,
192                                                    tests[i], 80);
193     EXPECT_FALSE(proxy.IsValid());
194   }
195 }
196 
TEST(ProxyChainTest,InvalidPort)197 TEST(ProxyChainTest, InvalidPort) {
198   const char* const tests[]{
199       "-1",
200       "65536",
201       "foo",
202       "0x35",
203   };
204 
205   for (size_t i = 0; i < std::size(tests); ++i) {
206     SCOPED_TRACE(base::NumberToString(i) + ": " + tests[i]);
207     auto proxy = ProxyChain::FromSchemeHostAndPort(ProxyServer::SCHEME_HTTP,
208                                                    "foopy", tests[i]);
209     EXPECT_FALSE(proxy.IsValid());
210   }
211 }
212 
TEST(ProxyChainTest,SingleProxyChain)213 TEST(ProxyChainTest, SingleProxyChain) {
214   auto proxy_server =
215       ProxyUriToProxyServer("foo:333", ProxyServer::SCHEME_HTTPS);
216 
217   std::vector<ProxyServer> proxy_servers = {proxy_server};
218   auto proxy = ProxyChain(proxy_servers);
219 
220   EXPECT_FALSE(proxy.is_direct());
221   EXPECT_TRUE(proxy.is_single_proxy());
222   EXPECT_FALSE(proxy.is_multi_proxy());
223   ASSERT_EQ(proxy.proxy_servers(), proxy_servers);
224   ASSERT_EQ(proxy.length(), 1u);
225   ASSERT_EQ(proxy.GetProxyServer(0), proxy_server);
226 }
227 
TEST(ProxyChainTest,SplitLast)228 TEST(ProxyChainTest, SplitLast) {
229   auto proxy_server1 =
230       ProxyUriToProxyServer("foo:333", ProxyServer::SCHEME_HTTPS);
231   auto proxy_server2 =
232       ProxyUriToProxyServer("foo:444", ProxyServer::SCHEME_HTTPS);
233   auto proxy_server3 =
234       ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS);
235 
236   auto chain3 = ProxyChain::ForIpProtection(
237       {proxy_server1, proxy_server2, proxy_server3});
238   EXPECT_EQ(chain3.SplitLast(),
239             std::make_pair(
240                 ProxyChain::ForIpProtection({proxy_server1, proxy_server2}),
241                 proxy_server3));
242 
243   auto chain1 = ProxyChain({proxy_server1});
244   EXPECT_EQ(chain1.SplitLast(),
245             std::make_pair(ProxyChain::Direct(), proxy_server1));
246 
247 #if BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
248   // Multi-proxy chains (not for Ip Protection) are only valid in debug builds.
249   auto chain2 = ProxyChain({proxy_server1, proxy_server2});
250   EXPECT_EQ(chain2.SplitLast(),
251             std::make_pair(ProxyChain({proxy_server1}), proxy_server2));
252 #endif  // BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
253 }
254 
TEST(ProxyChainTest,Prefix)255 TEST(ProxyChainTest, Prefix) {
256   auto proxy_server1 =
257       ProxyUriToProxyServer("foo:333", ProxyServer::SCHEME_HTTPS);
258   auto proxy_server2 =
259       ProxyUriToProxyServer("foo:444", ProxyServer::SCHEME_HTTPS);
260   auto proxy_server3 =
261       ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS);
262   auto chain = ProxyChain::ForIpProtection(
263       {proxy_server1, proxy_server2, proxy_server3}, /*chain_id=*/2);
264   EXPECT_EQ(chain.Prefix(0), ProxyChain::ForIpProtection({}, /*chain_id=*/2));
265   EXPECT_EQ(chain.Prefix(1),
266             ProxyChain::ForIpProtection({proxy_server1}, /*chain_id=*/2));
267   EXPECT_EQ(chain.Prefix(2),
268             ProxyChain::ForIpProtection({proxy_server1, proxy_server2},
269                                         /*chain_id=*/2));
270   EXPECT_EQ(chain.Prefix(3),
271             ProxyChain::ForIpProtection(
272                 {proxy_server1, proxy_server2, proxy_server3}, /*chain_id=*/2));
273 }
274 
TEST(ProxyChainTest,First)275 TEST(ProxyChainTest, First) {
276   auto proxy_server1 =
277       ProxyUriToProxyServer("foo:333", ProxyServer::SCHEME_HTTPS);
278 
279   auto chain = ProxyChain({proxy_server1});
280   EXPECT_EQ(chain.First(), proxy_server1);
281 
282 #if BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
283   // Multi-proxy chains (not for Ip Protection) are only valid in debug builds.
284   auto proxy_server2 =
285       ProxyUriToProxyServer("foo:444", ProxyServer::SCHEME_HTTPS);
286 
287   chain = ProxyChain({proxy_server1, proxy_server2});
288   EXPECT_EQ(chain.First(), proxy_server1);
289 #endif  // BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
290 }
291 
TEST(ProxyChainTest,Last)292 TEST(ProxyChainTest, Last) {
293   auto proxy_server1 =
294       ProxyUriToProxyServer("foo:333", ProxyServer::SCHEME_HTTPS);
295 
296   auto chain = ProxyChain({proxy_server1});
297   EXPECT_EQ(chain.Last(), proxy_server1);
298 
299 #if BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
300   // Multi-proxy chains (not for Ip Protection) are only valid in debug builds.
301   auto proxy_server2 =
302       ProxyUriToProxyServer("foo:444", ProxyServer::SCHEME_HTTPS);
303 
304   chain = ProxyChain({proxy_server1, proxy_server2});
305   EXPECT_EQ(chain.Last(), proxy_server2);
306 #endif  // BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
307 }
308 
TEST(ProxyChainTest,IsForIpProtection)309 TEST(ProxyChainTest, IsForIpProtection) {
310   auto regular_proxy_chain1 = ProxyChain::Direct();
311   EXPECT_FALSE(regular_proxy_chain1.is_for_ip_protection());
312 
313   auto ip_protection_proxy_chain1 =
314       ProxyChain::ForIpProtection(std::vector<ProxyServer>());
315   EXPECT_TRUE(ip_protection_proxy_chain1.is_for_ip_protection());
316 
317   auto regular_proxy_chain2 =
318       ProxyChain({ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS),
319                   ProxyUriToProxyServer("foo:666", ProxyServer::SCHEME_HTTPS)});
320   EXPECT_FALSE(regular_proxy_chain2.is_for_ip_protection());
321 
322   auto ip_protection_proxy_chain2 = ProxyChain::ForIpProtection(
323       {ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS),
324        ProxyUriToProxyServer("foo:666", ProxyServer::SCHEME_HTTPS)});
325   EXPECT_TRUE(ip_protection_proxy_chain2.is_for_ip_protection());
326 }
327 
TEST(ProxyChainTest,ForIpProtection)328 TEST(ProxyChainTest, ForIpProtection) {
329   auto ip_protection_proxy_chain1 =
330       ProxyChain::ForIpProtection(std::vector<ProxyServer>());
331   EXPECT_TRUE(ip_protection_proxy_chain1.is_direct());
332   EXPECT_TRUE(ip_protection_proxy_chain1.is_for_ip_protection());
333   EXPECT_EQ(ip_protection_proxy_chain1.ip_protection_chain_id(),
334             ProxyChain::kDefaultIpProtectionChainId);
335 
336   // Ensure that ProxyChain can be reassigned a new value created using its own
337   // `proxy_severs()`.
338   auto proxy_chain =
339       ProxyChain({ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS)});
340   auto copied_proxy_chain = proxy_chain;
341 
342   // Assert that the newly created `ProxyChain` is not for IP protection.
343   EXPECT_FALSE(proxy_chain.is_for_ip_protection());
344   EXPECT_EQ(proxy_chain.ip_protection_chain_id(),
345             ProxyChain::kNotIpProtectionChainId);
346 
347   // Re-assign new value to `proxy_chain` by using its own proxy servers to
348   // create a proxy chain for IP protection.
349   proxy_chain =
350       ProxyChain::ForIpProtection(std::move(proxy_chain.proxy_servers()));
351 
352   // Assert re-assigned proxy chain is now for IP protection and contains the
353   // same servers from the original copy.
354   EXPECT_TRUE(proxy_chain.is_for_ip_protection());
355   EXPECT_EQ(proxy_chain.ip_protection_chain_id(),
356             ProxyChain::kDefaultIpProtectionChainId);
357   EXPECT_FALSE(copied_proxy_chain.is_for_ip_protection());
358   EXPECT_EQ(proxy_chain.proxy_servers(), copied_proxy_chain.proxy_servers());
359 
360   auto chain_with_id = ProxyChain::ForIpProtection(
361       {ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS),
362        ProxyUriToProxyServer("foo:666", ProxyServer::SCHEME_HTTPS)},
363       /*chain_id=*/3);
364   EXPECT_FALSE(chain_with_id.is_direct());
365   EXPECT_TRUE(chain_with_id.is_for_ip_protection());
366   EXPECT_EQ(chain_with_id.ip_protection_chain_id(), 3);
367 }
368 
TEST(ProxyChainTest,IsGetToProxyAllowed)369 TEST(ProxyChainTest, IsGetToProxyAllowed) {
370   auto https_server1 =
371       ProxyUriToProxyServer("foo:333", ProxyServer::SCHEME_HTTPS);
372   auto https_server2 =
373       ProxyUriToProxyServer("foo:444", ProxyServer::SCHEME_HTTPS);
374   auto http_server = ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTP);
375   auto socks_server =
376       ProxyUriToProxyServer("foo:666", ProxyServer::SCHEME_SOCKS4);
377 
378   EXPECT_FALSE(ProxyChain::Direct().is_get_to_proxy_allowed());
379   EXPECT_TRUE(ProxyChain({https_server1}).is_get_to_proxy_allowed());
380   EXPECT_TRUE(ProxyChain({http_server}).is_get_to_proxy_allowed());
381   EXPECT_FALSE(ProxyChain({socks_server}).is_get_to_proxy_allowed());
382   EXPECT_FALSE(
383       ProxyChain({https_server1, https_server2}).is_get_to_proxy_allowed());
384 }
385 
TEST(ProxyChainTest,IsValid)386 TEST(ProxyChainTest, IsValid) {
387   // Single hop proxy of type Direct is valid.
388   EXPECT_TRUE(ProxyChain::Direct().IsValid());
389 
390   auto https1 = ProxyUriToProxyServer("foo:444", ProxyServer::SCHEME_HTTPS);
391   auto https2 = ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS);
392   auto quic1 = ProxyUriToProxyServer("foo:666", ProxyServer::SCHEME_QUIC);
393   auto quic2 = ProxyUriToProxyServer("foo:777", ProxyServer::SCHEME_QUIC);
394   auto socks = ProxyUriToProxyServer("foo:777", ProxyServer::SCHEME_SOCKS5);
395 
396   // Single proxy chain is valid.
397   EXPECT_TRUE(ProxyChain({https1}).IsValid());
398 
399   // Invalid Chains.
400   //
401   // If multi-proxy chain support is disabled, any chain greater
402   // than length 1 is considered invalid. If multi-proxy support is enabled AND
403   // QUIC proxy support is enabled, these chains remain invalid due to the
404   // sequence of schemes.
405   EXPECT_FALSE(ProxyChain({https1, quic2}).IsValid());
406   EXPECT_FALSE(ProxyChain({https1, https2, quic1, quic2}).IsValid());
407   // ProxyChain cannot contains socks server. Only QUIC and HTTPS.
408   EXPECT_FALSE(ProxyChain({socks, https1}).IsValid());
409   EXPECT_FALSE(ProxyChain({socks, https1, https2}).IsValid());
410   EXPECT_FALSE(ProxyChain({https1, socks}).IsValid());
411   EXPECT_FALSE(ProxyChain({https1, https2, socks}).IsValid());
412 
413   // IP protection accepts chains with SCHEME_QUIC and/or multi-proxy chains
414   EXPECT_TRUE(ProxyChain::ForIpProtection({https1}).IsValid());
415   EXPECT_TRUE(ProxyChain::ForIpProtection({quic1}).IsValid());
416   EXPECT_TRUE(ProxyChain::ForIpProtection({https1, https2}).IsValid());
417   EXPECT_TRUE(ProxyChain::ForIpProtection({quic1, https1}).IsValid());
418   EXPECT_TRUE(
419       ProxyChain::ForIpProtection({quic1, quic2, https1, https2}).IsValid());
420 
421   // IP protection CHECKs on failure instead of just creating an invalid chain.
422   // QUIC cannot follow HTTPS proxy server.
423   EXPECT_CHECK_DEATH(ProxyChain::ForIpProtection({https1, quic2}).IsValid());
424   EXPECT_CHECK_DEATH(
425       ProxyChain::ForIpProtection({https1, https2, quic1, quic2}).IsValid());
426   // Socks proxy server is not valid for multi-proxy chain.
427   EXPECT_CHECK_DEATH(ProxyChain::ForIpProtection({socks, https1}).IsValid());
428   EXPECT_CHECK_DEATH(
429       ProxyChain::ForIpProtection({socks, https1, https2}).IsValid());
430   EXPECT_CHECK_DEATH(ProxyChain::ForIpProtection({https1, socks}).IsValid());
431   EXPECT_CHECK_DEATH(
432       ProxyChain::ForIpProtection({https1, https2, socks}).IsValid());
433 
434 #if !BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
435   bool multi_proxy_chain_supported = false;
436 #else  // BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
437   bool multi_proxy_chain_supported = true;
438 #endif
439   // Multi-proxy chains are only supported in debug mode.
440   EXPECT_EQ(ProxyChain({https1, https2}).IsValid(),
441             multi_proxy_chain_supported);
442 
443 #if !BUILDFLAG(ENABLE_QUIC_PROXY_SUPPORT)
444   bool is_quic_supported = false;
445 #else  // BUILDFLAG(ENABLE_QUIC_PROXY_SUPPORT)
446   bool is_quic_supported = true;
447 #endif
448   // Multi-proxy chains are only supported in debug mode.
449   EXPECT_EQ(ProxyChain({quic1}).IsValid(), is_quic_supported);
450 
451 // If quic proxy support is enabled AND multi-proxy chain support is
452 // enabled, the following chains are valid. Otherwise, they are invalid.
453 #if !BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS) || \
454     !BUILDFLAG(ENABLE_QUIC_PROXY_SUPPORT)
455   bool is_multi_proxy_quic_supported = false;
456 #else
457   bool is_multi_proxy_quic_supported = true;
458 #endif
459   EXPECT_EQ(ProxyChain({quic1, https1}).IsValid(),
460             is_multi_proxy_quic_supported);
461   EXPECT_EQ(ProxyChain({quic1, quic2, https1, https2}).IsValid(),
462             is_multi_proxy_quic_supported);
463 }
464 
TEST(ProxyChainTest,Unequal)465 TEST(ProxyChainTest, Unequal) {
466   // Ordered proxy chains.
467   std::vector<ProxyChain> proxy_chain_list = {
468       ProxyChain::Direct(),
469       ProxyUriToProxyChain("foo:333", ProxyServer::SCHEME_HTTP),
470       ProxyUriToProxyChain("foo:444", ProxyServer::SCHEME_HTTP),
471       ProxyChain({ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS),
472                   ProxyUriToProxyServer("foo:666", ProxyServer::SCHEME_HTTPS)}),
473       ProxyUriToProxyChain("socks4://foo:33", ProxyServer::SCHEME_SOCKS4),
474       ProxyUriToProxyChain("http://foo:33", ProxyServer::SCHEME_HTTP),
475       ProxyChain({ProxyUriToProxyChain("bar:33", ProxyServer::SCHEME_HTTP)}),
476       ProxyChain::ForIpProtection(
477           {ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS),
478            ProxyUriToProxyServer("foo:666", ProxyServer::SCHEME_HTTPS)})};
479 
480   // Unordered proxy chains.
481   std::set<ProxyChain> proxy_chain_set(proxy_chain_list.begin(),
482                                        proxy_chain_list.end());
483 
484   // Initial proxy chain list and set are equal.
485   ASSERT_EQ(proxy_chain_list.size(), proxy_chain_set.size());
486 
487   for (const ProxyChain& proxy_chain1 : proxy_chain_list) {
488     auto proxy_chain2 = proxy_chain_set.begin();
489     // Chain set entries less than `proxy_chain1`.
490     while (*proxy_chain2 < proxy_chain1) {
491       EXPECT_TRUE(*proxy_chain2 < proxy_chain1);
492       EXPECT_FALSE(proxy_chain1 < *proxy_chain2);
493       EXPECT_FALSE(*proxy_chain2 == proxy_chain1);
494       EXPECT_FALSE(proxy_chain1 == *proxy_chain2);
495       ++proxy_chain2;
496     }
497 
498     // Chain set entry for `proxy_chain1`.
499     EXPECT_FALSE(*proxy_chain2 < proxy_chain1);
500     EXPECT_FALSE(proxy_chain1 < *proxy_chain2);
501     EXPECT_TRUE(*proxy_chain2 == proxy_chain1);
502     EXPECT_TRUE(proxy_chain1 == *proxy_chain2);
503     ++proxy_chain2;
504 
505     // Chain set entries greater than `proxy_chain1`.
506     while (proxy_chain2 != proxy_chain_set.end() &&
507            proxy_chain1 < *proxy_chain2) {
508       EXPECT_FALSE(*proxy_chain2 < proxy_chain1);
509       EXPECT_TRUE(proxy_chain1 < *proxy_chain2);
510       EXPECT_FALSE(*proxy_chain2 == proxy_chain1);
511       EXPECT_FALSE(proxy_chain1 == *proxy_chain2);
512       ++proxy_chain2;
513     }
514     ASSERT_EQ(proxy_chain2, proxy_chain_set.end());
515   }
516 }
517 
TEST(ProxyChainTest,Equal)518 TEST(ProxyChainTest, Equal) {
519   ProxyServer proxy_server =
520       ProxyUriToProxyServer("foo:11", ProxyServer::SCHEME_HTTP);
521 
522   ProxyChain proxy_chain1 = ProxyChain(proxy_server);
523   ProxyChain proxy_chain2 = ProxyChain(std::vector<ProxyServer>{proxy_server});
524   ProxyChain proxy_chain3 =
525       ProxyChain(ProxyServer::SCHEME_HTTP, HostPortPair("foo", 11));
526 
527   EXPECT_FALSE(proxy_chain1 < proxy_chain2);
528   EXPECT_FALSE(proxy_chain2 < proxy_chain1);
529   EXPECT_TRUE(proxy_chain2 == proxy_chain1);
530   EXPECT_TRUE(proxy_chain2 == proxy_chain1);
531 
532   EXPECT_FALSE(proxy_chain2 < proxy_chain3);
533   EXPECT_FALSE(proxy_chain3 < proxy_chain2);
534   EXPECT_TRUE(proxy_chain3 == proxy_chain2);
535   EXPECT_TRUE(proxy_chain3 == proxy_chain2);
536 }
537 
TEST(ProxyChainTest,PickleDirect)538 TEST(ProxyChainTest, PickleDirect) {
539   ProxyChain proxy_chain = ProxyChain::Direct();
540   base::Pickle pickle;
541   proxy_chain.Persist(&pickle);
542   base::PickleIterator iter(pickle);
543   ProxyChain proxy_chain_from_pickle;
544   EXPECT_TRUE(proxy_chain_from_pickle.InitFromPickle(&iter));
545   EXPECT_EQ(proxy_chain, proxy_chain_from_pickle);
546 }
547 
TEST(ProxyChainTest,PickleOneProxy)548 TEST(ProxyChainTest, PickleOneProxy) {
549   ProxyChain proxy_chain =
550       ProxyChain(ProxyUriToProxyServer("foo:11", ProxyServer::SCHEME_HTTPS));
551   base::Pickle pickle;
552   proxy_chain.Persist(&pickle);
553   base::PickleIterator iter(pickle);
554   ProxyChain proxy_chain_from_pickle;
555   EXPECT_TRUE(proxy_chain_from_pickle.InitFromPickle(&iter));
556   EXPECT_EQ(proxy_chain, proxy_chain_from_pickle);
557 }
558 
TEST(ProxyChainTest,UnpickleInvalidProxy)559 TEST(ProxyChainTest, UnpickleInvalidProxy) {
560   ProxyServer invalid_proxy_server;
561   // Manually pickle a proxcy chain with an invalid proxy server.
562   base::Pickle pickle;
563   pickle.WriteInt(ProxyChain::kNotIpProtectionChainId);
564   pickle.WriteInt(1);  // Length of the chain
565   invalid_proxy_server.Persist(&pickle);
566 
567   base::PickleIterator iter(pickle);
568   ProxyChain invalid_proxy_chain_from_pickle;
569   // Unpickling should fail and leave us with an invalid proxy chain.
570   EXPECT_FALSE(invalid_proxy_chain_from_pickle.InitFromPickle(&iter));
571   // Make sure that we unpickled the invalid proxy server.
572   EXPECT_TRUE(iter.ReachedEnd());
573   EXPECT_FALSE(invalid_proxy_chain_from_pickle.IsValid());
574 }
575 
576 #if !BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
577 // Multi-proxy chains that are not for Ip Protection are not allowed in release
578 // builds. If created, it should be considered invalid.
TEST(ProxyChainTest,MultiProxyChainNotForIpProtectionInvalidProxyChain)579 TEST(ProxyChainTest, MultiProxyChainNotForIpProtectionInvalidProxyChain) {
580   ProxyChain invalid_chain =
581       ProxyChain({ProxyUriToProxyServer("foo:11", ProxyServer::SCHEME_HTTPS),
582                   ProxyUriToProxyServer("hoo:11", ProxyServer::SCHEME_HTTPS)});
583 
584   EXPECT_FALSE(invalid_chain.IsValid());
585 }
586 #else  // BUILDFLAG(ENABLE_BRACKETED_PROXY_URIS)
TEST(ProxyChainTest,MultiProxyChain)587 TEST(ProxyChainTest, MultiProxyChain) {
588   auto proxy_server1 =
589       ProxyUriToProxyServer("foo:333", ProxyServer::SCHEME_HTTPS);
590   auto proxy_server2 =
591       ProxyUriToProxyServer("foo:444", ProxyServer::SCHEME_HTTPS);
592   auto proxy_server3 =
593       ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS);
594 
595   std::vector<ProxyServer> proxy_servers = {proxy_server1, proxy_server2,
596                                             proxy_server3};
597   auto proxy = ProxyChain(proxy_servers);
598 
599   EXPECT_FALSE(proxy.is_direct());
600   EXPECT_FALSE(proxy.is_single_proxy());
601   EXPECT_TRUE(proxy.is_multi_proxy());
602   ASSERT_EQ(proxy.proxy_servers(), proxy_servers);
603   ASSERT_EQ(proxy.length(), 3u);
604   ASSERT_EQ(proxy.GetProxyServer(0), proxy_server1);
605   ASSERT_EQ(proxy.GetProxyServer(1), proxy_server2);
606   ASSERT_EQ(proxy.GetProxyServer(2), proxy_server3);
607 
608   // Ensure that proxy chains are equal even if one is for IP Protection.
609   auto regular_proxy_chain = ProxyChain({proxy_server1, proxy_server2});
610   auto ip_protection_proxy_chain =
611       ProxyChain::ForIpProtection({proxy_server1, proxy_server2});
612   EXPECT_TRUE(ip_protection_proxy_chain.is_for_ip_protection());
613   EXPECT_EQ(regular_proxy_chain.proxy_servers(),
614             ip_protection_proxy_chain.proxy_servers());
615 }
616 
TEST(ProxyChainTest,MultiProxyChainsCanBeConvertedToForIpProtection)617 TEST(ProxyChainTest, MultiProxyChainsCanBeConvertedToForIpProtection) {
618   ProxyChain proxy_chain =
619       ProxyChain({ProxyUriToProxyServer("foo:555", ProxyServer::SCHEME_HTTPS),
620                   ProxyUriToProxyServer("foo:666", ProxyServer::SCHEME_HTTPS)});
621   ProxyChain copied_proxy_chain = proxy_chain;
622 
623   // Assert the proxy chain is currently not for ip protection.
624   EXPECT_FALSE(proxy_chain.is_for_ip_protection());
625   EXPECT_EQ(proxy_chain.ip_protection_chain_id(),
626             ProxyChain::kNotIpProtectionChainId);
627 
628   // Convert proxy_chain to be for IP protection.
629   proxy_chain =
630       ProxyChain::ForIpProtection(std::move(proxy_chain.proxy_servers()));
631 
632   // Assert proxy_chain now shows it is for IP protection while copied proxy
633   // chain still isn't.
634   EXPECT_TRUE(proxy_chain.is_for_ip_protection());
635   EXPECT_EQ(proxy_chain.ip_protection_chain_id(),
636             ProxyChain::kDefaultIpProtectionChainId);
637   EXPECT_FALSE(copied_proxy_chain.is_for_ip_protection());
638   EXPECT_EQ(copied_proxy_chain.ip_protection_chain_id(),
639             ProxyChain::kNotIpProtectionChainId);
640 
641   // Ensure servers contained are still equal.
642   EXPECT_EQ(proxy_chain.proxy_servers(), copied_proxy_chain.proxy_servers());
643 }
644 
TEST(ProxyChainTest,PickleTwoProxies)645 TEST(ProxyChainTest, PickleTwoProxies) {
646   ProxyChain proxy_chain =
647       ProxyChain({ProxyUriToProxyServer("foo:11", ProxyServer::SCHEME_HTTPS),
648                   ProxyUriToProxyServer("foo:22", ProxyServer::SCHEME_HTTPS)});
649   base::Pickle pickle;
650   proxy_chain.Persist(&pickle);
651   base::PickleIterator iter(pickle);
652   ProxyChain proxy_chain_from_pickle;
653   EXPECT_TRUE(proxy_chain_from_pickle.InitFromPickle(&iter));
654   EXPECT_EQ(proxy_chain, proxy_chain_from_pickle);
655 }
656 #endif
657 
658 }  // namespace
659 
660 }  // namespace net
661