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