xref: /aosp_15_r20/external/cronet/net/proxy_resolution/proxy_config_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2012 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/proxy_resolution/proxy_config.h"
6 
7 #include "base/json/json_writer.h"
8 #include "base/values.h"
9 #include "net/base/proxy_string_util.h"
10 #include "net/proxy_resolution/proxy_config_service_common_unittest.h"
11 #include "net/proxy_resolution/proxy_info.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 
14 namespace net {
15 namespace {
16 
ExpectProxyServerEquals(const char * expectation,const ProxyList & proxy_list)17 void ExpectProxyServerEquals(const char* expectation,
18                              const ProxyList& proxy_list) {
19   if (expectation == nullptr) {
20     EXPECT_TRUE(proxy_list.IsEmpty());
21   } else {
22     EXPECT_EQ(expectation, proxy_list.ToDebugString());
23   }
24 }
25 
TEST(ProxyConfigTest,Equals)26 TEST(ProxyConfigTest, Equals) {
27   // Test |ProxyConfig::auto_detect|.
28 
29   ProxyConfig config1;
30   config1.set_auto_detect(true);
31 
32   ProxyConfig config2;
33   config2.set_auto_detect(false);
34 
35   EXPECT_FALSE(config1.Equals(config2));
36   EXPECT_FALSE(config2.Equals(config1));
37 
38   config2.set_auto_detect(true);
39 
40   EXPECT_TRUE(config1.Equals(config2));
41   EXPECT_TRUE(config2.Equals(config1));
42 
43   // Test |ProxyConfig::pac_url|.
44 
45   config2.set_pac_url(GURL("http://wpad/wpad.dat"));
46 
47   EXPECT_FALSE(config1.Equals(config2));
48   EXPECT_FALSE(config2.Equals(config1));
49 
50   config1.set_pac_url(GURL("http://wpad/wpad.dat"));
51 
52   EXPECT_TRUE(config1.Equals(config2));
53   EXPECT_TRUE(config2.Equals(config1));
54 
55   // Test |ProxyConfig::proxy_rules|.
56 
57   config2.proxy_rules().type = ProxyConfig::ProxyRules::Type::PROXY_LIST;
58   config2.proxy_rules().single_proxies.SetSingleProxyServer(
59       ProxyUriToProxyServer("myproxy:80", ProxyServer::SCHEME_HTTP));
60 
61   EXPECT_FALSE(config1.Equals(config2));
62   EXPECT_FALSE(config2.Equals(config1));
63 
64   config1.proxy_rules().type = ProxyConfig::ProxyRules::Type::PROXY_LIST;
65   config1.proxy_rules().single_proxies.SetSingleProxyServer(
66       ProxyUriToProxyServer("myproxy:100", ProxyServer::SCHEME_HTTP));
67 
68   EXPECT_FALSE(config1.Equals(config2));
69   EXPECT_FALSE(config2.Equals(config1));
70 
71   config1.proxy_rules().single_proxies.SetSingleProxyServer(
72       ProxyUriToProxyServer("myproxy", ProxyServer::SCHEME_HTTP));
73 
74   EXPECT_TRUE(config1.Equals(config2));
75   EXPECT_TRUE(config2.Equals(config1));
76 
77   // Test |ProxyConfig::bypass_rules|.
78 
79   config2.proxy_rules().bypass_rules.AddRuleFromString("*.google.com");
80 
81   EXPECT_FALSE(config1.Equals(config2));
82   EXPECT_FALSE(config2.Equals(config1));
83 
84   config1.proxy_rules().bypass_rules.AddRuleFromString("*.google.com");
85 
86   EXPECT_TRUE(config1.Equals(config2));
87   EXPECT_TRUE(config2.Equals(config1));
88 
89   // Test |ProxyConfig::proxy_rules.reverse_bypass|.
90 
91   config2.proxy_rules().reverse_bypass = true;
92 
93   EXPECT_FALSE(config1.Equals(config2));
94   EXPECT_FALSE(config2.Equals(config1));
95 
96   config1.proxy_rules().reverse_bypass = true;
97 
98   EXPECT_TRUE(config1.Equals(config2));
99   EXPECT_TRUE(config2.Equals(config1));
100 }
101 
102 struct ProxyConfigToValueTestCase {
103   ProxyConfig config;
104   const char* expected_value_json;
105 };
106 
107 class ProxyConfigToValueTest
108     : public ::testing::TestWithParam<ProxyConfigToValueTestCase> {};
109 
TEST_P(ProxyConfigToValueTest,ToValueJSON)110 TEST_P(ProxyConfigToValueTest, ToValueJSON) {
111   const ProxyConfigToValueTestCase& test_case = GetParam();
112 
113   base::Value value = test_case.config.ToValue();
114 
115   std::string json_string;
116   ASSERT_TRUE(base::JSONWriter::Write(value, &json_string));
117 
118   EXPECT_EQ(std::string(test_case.expected_value_json), json_string);
119 }
120 
GetTestCaseDirect()121 ProxyConfigToValueTestCase GetTestCaseDirect() {
122   return {ProxyConfig::CreateDirect(), "{}"};
123 }
124 
GetTestCaseAutoDetect()125 ProxyConfigToValueTestCase GetTestCaseAutoDetect() {
126   return {ProxyConfig::CreateAutoDetect(), "{\"auto_detect\":true}"};
127 }
128 
GetTestCasePacUrl()129 ProxyConfigToValueTestCase GetTestCasePacUrl() {
130   ProxyConfig config;
131   config.set_pac_url(GURL("http://www.example.com/test.pac"));
132 
133   return {std::move(config),
134           "{\"pac_url\":\"http://www.example.com/test.pac\"}"};
135 }
136 
GetTestCasePacUrlMandatory()137 ProxyConfigToValueTestCase GetTestCasePacUrlMandatory() {
138   ProxyConfig config;
139   config.set_pac_url(GURL("http://www.example.com/test.pac"));
140   config.set_pac_mandatory(true);
141 
142   return {std::move(config),
143           "{\"pac_mandatory\":true,\"pac_url\":\"http://www.example.com/"
144           "test.pac\"}"};
145 }
146 
GetTestCasePacUrlAndAutoDetect()147 ProxyConfigToValueTestCase GetTestCasePacUrlAndAutoDetect() {
148   ProxyConfig config = ProxyConfig::CreateAutoDetect();
149   config.set_pac_url(GURL("http://www.example.com/test.pac"));
150 
151   return {
152       std::move(config),
153       "{\"auto_detect\":true,\"pac_url\":\"http://www.example.com/test.pac\"}"};
154 }
155 
GetTestCaseSingleProxy()156 ProxyConfigToValueTestCase GetTestCaseSingleProxy() {
157   ProxyConfig config;
158   config.proxy_rules().ParseFromString("https://proxy1:8080");
159 
160   return {std::move(config), "{\"single_proxy\":[\"[https://proxy1:8080]\"]}"};
161 }
162 
GetTestCaseSingleProxyWithBypass()163 ProxyConfigToValueTestCase GetTestCaseSingleProxyWithBypass() {
164   ProxyConfig config;
165   config.proxy_rules().ParseFromString("https://proxy1:8080");
166   config.proxy_rules().bypass_rules.AddRuleFromString("*.google.com");
167   config.proxy_rules().bypass_rules.AddRuleFromString("192.168.0.1/16");
168 
169   return {std::move(config),
170           "{\"bypass_list\":[\"*.google.com\",\"192.168.0.1/"
171           "16\"],\"single_proxy\":[\"[https://proxy1:8080]\"]}"};
172 }
173 
GetTestCaseSingleProxyWithReversedBypass()174 ProxyConfigToValueTestCase GetTestCaseSingleProxyWithReversedBypass() {
175   ProxyConfig config;
176   config.proxy_rules().ParseFromString("https://proxy1:8080");
177   config.proxy_rules().bypass_rules.AddRuleFromString("*.google.com");
178   config.proxy_rules().reverse_bypass = true;
179 
180   return {std::move(config),
181           "{\"bypass_list\":[\"*.google.com\"],\"reverse_bypass\":true,"
182           "\"single_proxy\":[\"[https://proxy1:8080]\"]}"};
183 }
184 
GetTestCaseProxyPerScheme()185 ProxyConfigToValueTestCase GetTestCaseProxyPerScheme() {
186   ProxyConfig config;
187   config.proxy_rules().ParseFromString(
188       "http=https://proxy1:8080;https=socks5://proxy2");
189   config.proxy_rules().bypass_rules.AddRuleFromString("*.google.com");
190   config.set_pac_url(GURL("http://wpad/wpad.dat"));
191   config.set_auto_detect(true);
192 
193   return {
194       std::move(config),
195       "{\"auto_detect\":true,\"bypass_list\":[\"*.google.com\"],\"pac_url\":"
196       "\"http://wpad/wpad.dat\",\"proxy_per_scheme\":{\"http\":[\"[https://"
197       "proxy1:8080]\"],\"https\":[\"[socks5://proxy2:1080]\"]}}"};
198 }
199 
GetTestCaseSingleProxyList()200 ProxyConfigToValueTestCase GetTestCaseSingleProxyList() {
201   ProxyConfig config;
202   config.proxy_rules().ParseFromString(
203       "https://proxy1:8080,http://proxy2,direct://");
204 
205   return {
206       std::move(config),
207       "{\"single_proxy\":[\"[https://proxy1:8080]\",\"[proxy2:80]\",\"direct://"
208       "\"]}"};
209 }
210 
211 INSTANTIATE_TEST_SUITE_P(
212     All,
213     ProxyConfigToValueTest,
214     testing::Values(GetTestCaseDirect(),
215                     GetTestCaseAutoDetect(),
216                     GetTestCasePacUrl(),
217                     GetTestCasePacUrlMandatory(),
218                     GetTestCasePacUrlAndAutoDetect(),
219                     GetTestCaseSingleProxy(),
220                     GetTestCaseSingleProxyWithBypass(),
221                     GetTestCaseSingleProxyWithReversedBypass(),
222                     GetTestCaseProxyPerScheme(),
223                     GetTestCaseSingleProxyList()));
224 
TEST(ProxyConfigTest,ParseProxyRules)225 TEST(ProxyConfigTest, ParseProxyRules) {
226   const struct {
227     const char* proxy_rules;
228 
229     ProxyConfig::ProxyRules::Type type;
230     // These will be PAC-stle strings, eg 'PROXY foo.com'
231     const char* single_proxy;
232     const char* proxy_for_http;
233     const char* proxy_for_https;
234     const char* proxy_for_ftp;
235     const char* fallback_proxy;
236   } tests[] = {
237       // One HTTP proxy for all schemes.
238       {
239           "myproxy:80",
240 
241           ProxyConfig::ProxyRules::Type::PROXY_LIST,
242           "PROXY myproxy:80",
243           nullptr,
244           nullptr,
245           nullptr,
246           nullptr,
247       },
248 
249       // Multiple HTTP proxies for all schemes.
250       {
251           "myproxy:80,https://myotherproxy",
252 
253           ProxyConfig::ProxyRules::Type::PROXY_LIST,
254           "PROXY myproxy:80;HTTPS myotherproxy:443",
255           nullptr,
256           nullptr,
257           nullptr,
258           nullptr,
259       },
260 
261       // Only specify a proxy server for "http://" urls.
262       {
263           "http=myproxy:80",
264 
265           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
266           nullptr,
267           "PROXY myproxy:80",
268           nullptr,
269           nullptr,
270           nullptr,
271       },
272 
273       // Specify an HTTP proxy for "ftp://" and a SOCKS proxy for "https://"
274       // urls.
275       {
276           "ftp=ftp-proxy ; https=socks4://foopy",
277 
278           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
279           nullptr,
280           nullptr,
281           "SOCKS foopy:1080",
282           "PROXY ftp-proxy:80",
283           nullptr,
284       },
285 
286       // Give a scheme-specific proxy as well as a non-scheme specific.
287       // The first entry "foopy" takes precedance marking this list as
288       // Type::PROXY_LIST.
289       {
290           "foopy ; ftp=ftp-proxy",
291 
292           ProxyConfig::ProxyRules::Type::PROXY_LIST,
293           "PROXY foopy:80",
294           nullptr,
295           nullptr,
296           nullptr,
297           nullptr,
298       },
299 
300       // Give a scheme-specific proxy as well as a non-scheme specific.
301       // The first entry "ftp=ftp-proxy" takes precedance marking this list as
302       // Type::PROXY_LIST_PER_SCHEME.
303       {
304           "ftp=ftp-proxy ; foopy",
305 
306           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
307           nullptr,
308           nullptr,
309           nullptr,
310           "PROXY ftp-proxy:80",
311           nullptr,
312       },
313 
314       // Include a list of entries for a single scheme.
315       {
316           "ftp=ftp1,ftp2,ftp3",
317 
318           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
319           nullptr,
320           nullptr,
321           nullptr,
322           "PROXY ftp1:80;PROXY ftp2:80;PROXY ftp3:80",
323           nullptr,
324       },
325 
326       // Include multiple entries for the same scheme -- they accumulate.
327       {
328           "http=http1,http2; http=http3",
329 
330           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
331           nullptr,
332           "PROXY http1:80;PROXY http2:80;PROXY http3:80",
333           nullptr,
334           nullptr,
335           nullptr,
336       },
337 
338       // Include lists of entries for multiple schemes.
339       {
340           "ftp=ftp1,ftp2,ftp3 ; http=http1,http2; ",
341 
342           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
343           nullptr,
344           "PROXY http1:80;PROXY http2:80",
345           nullptr,
346           "PROXY ftp1:80;PROXY ftp2:80;PROXY ftp3:80",
347           nullptr,
348       },
349 
350       // Include non-default proxy schemes.
351       {
352           "http=https://secure_proxy; ftp=socks4://socks_proxy; "
353           "https=socks://foo",
354 
355           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
356           nullptr,
357           "HTTPS secure_proxy:443",
358           "SOCKS5 foo:1080",
359           "SOCKS socks_proxy:1080",
360           nullptr,
361       },
362 
363       // Only SOCKS proxy present, others being blank.
364       {
365           "socks=foopy",
366 
367           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
368           nullptr,
369           nullptr,
370           nullptr,
371           nullptr,
372           "SOCKS foopy:1080",
373       },
374 
375       // SOCKS proxy present along with other proxies too
376       {
377           "http=httpproxy ; https=httpsproxy ; ftp=ftpproxy ; socks=foopy ",
378 
379           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
380           nullptr,
381           "PROXY httpproxy:80",
382           "PROXY httpsproxy:80",
383           "PROXY ftpproxy:80",
384           "SOCKS foopy:1080",
385       },
386 
387       // SOCKS proxy (with modifier) present along with some proxies
388       // (FTP being blank)
389       {
390           "http=httpproxy ; https=httpsproxy ; socks=socks5://foopy ",
391 
392           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
393           nullptr,
394           "PROXY httpproxy:80",
395           "PROXY httpsproxy:80",
396           nullptr,
397           "SOCKS5 foopy:1080",
398       },
399 
400       // Include unsupported schemes -- they are discarded.
401       {
402           "crazy=foopy ; foo=bar ; https=myhttpsproxy",
403 
404           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
405           nullptr,
406           nullptr,
407           "PROXY myhttpsproxy:80",
408           nullptr,
409           nullptr,
410       },
411 
412       // direct:// as first option for a scheme.
413       {
414           "http=direct://,myhttpproxy; https=direct://",
415 
416           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
417           nullptr,
418           "DIRECT;PROXY myhttpproxy:80",
419           "DIRECT",
420           nullptr,
421           nullptr,
422       },
423 
424       // direct:// as a second option for a scheme.
425       {
426           "http=myhttpproxy,direct://",
427 
428           ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME,
429           nullptr,
430           "PROXY myhttpproxy:80;DIRECT",
431           nullptr,
432           nullptr,
433           nullptr,
434       },
435 
436   };
437 
438   ProxyConfig config;
439 
440   for (const auto& test : tests) {
441     config.proxy_rules().ParseFromString(test.proxy_rules);
442 
443     EXPECT_EQ(test.type, config.proxy_rules().type);
444     ExpectProxyServerEquals(test.single_proxy,
445                             config.proxy_rules().single_proxies);
446     ExpectProxyServerEquals(test.proxy_for_http,
447                             config.proxy_rules().proxies_for_http);
448     ExpectProxyServerEquals(test.proxy_for_https,
449                             config.proxy_rules().proxies_for_https);
450     ExpectProxyServerEquals(test.proxy_for_ftp,
451                             config.proxy_rules().proxies_for_ftp);
452     ExpectProxyServerEquals(test.fallback_proxy,
453                             config.proxy_rules().fallback_proxies);
454   }
455 }
456 
TEST(ProxyConfigTest,ProxyRulesSetBypassFlag)457 TEST(ProxyConfigTest, ProxyRulesSetBypassFlag) {
458   // Test whether the did_bypass_proxy() flag is set in proxy info correctly.
459   ProxyConfig::ProxyRules rules;
460   ProxyInfo  result;
461 
462   rules.ParseFromString("http=httpproxy:80");
463   rules.bypass_rules.AddRuleFromString(".com");
464 
465   rules.Apply(GURL("http://example.com"), &result);
466   EXPECT_TRUE(result.is_direct_only());
467   EXPECT_TRUE(result.did_bypass_proxy());
468 
469   rules.Apply(GURL("http://example.org"), &result);
470   EXPECT_FALSE(result.is_direct());
471   EXPECT_FALSE(result.did_bypass_proxy());
472 
473   // Try with reversed bypass rules.
474   rules.reverse_bypass = true;
475 
476   rules.Apply(GURL("http://example.org"), &result);
477   EXPECT_TRUE(result.is_direct_only());
478   EXPECT_TRUE(result.did_bypass_proxy());
479 
480   rules.Apply(GURL("http://example.com"), &result);
481   EXPECT_FALSE(result.is_direct());
482   EXPECT_FALSE(result.did_bypass_proxy());
483 }
484 
485 static const char kWsUrl[] = "ws://example.com/echo";
486 static const char kWssUrl[] = "wss://example.com/echo";
487 
488 class ProxyConfigWebSocketTest : public ::testing::Test {
489  protected:
ParseFromString(const std::string & rules)490   void ParseFromString(const std::string& rules) {
491     rules_.ParseFromString(rules);
492   }
Apply(const GURL & gurl)493   void Apply(const GURL& gurl) { rules_.Apply(gurl, &info_); }
ToDebugString() const494   std::string ToDebugString() const { return info_.ToDebugString(); }
495 
WsUrl()496   static GURL WsUrl() { return GURL(kWsUrl); }
WssUrl()497   static GURL WssUrl() { return GURL(kWssUrl); }
498 
499   ProxyConfig::ProxyRules rules_;
500   ProxyInfo info_;
501 };
502 
503 // If a single proxy is set for all protocols, WebSocket uses it.
TEST_F(ProxyConfigWebSocketTest,UsesProxy)504 TEST_F(ProxyConfigWebSocketTest, UsesProxy) {
505   ParseFromString("proxy:3128");
506   Apply(WsUrl());
507   EXPECT_EQ("PROXY proxy:3128", ToDebugString());
508 }
509 
510 // See RFC6455 Section 4.1. item 3, "_Proxy Usage_". Note that this favors a
511 // SOCKSv4 proxy (although technically the spec only notes SOCKSv5).
TEST_F(ProxyConfigWebSocketTest,PrefersSocksV4)512 TEST_F(ProxyConfigWebSocketTest, PrefersSocksV4) {
513   ParseFromString(
514       "http=proxy:3128 ; https=sslproxy:3128 ; socks=socksproxy:1080");
515   Apply(WsUrl());
516   EXPECT_EQ("SOCKS socksproxy:1080", ToDebugString());
517 }
518 
519 // See RFC6455 Section 4.1. item 3, "_Proxy Usage_".
TEST_F(ProxyConfigWebSocketTest,PrefersSocksV5)520 TEST_F(ProxyConfigWebSocketTest, PrefersSocksV5) {
521   ParseFromString(
522       "http=proxy:3128 ; https=sslproxy:3128 ; socks=socks5://socksproxy:1080");
523   Apply(WsUrl());
524   EXPECT_EQ("SOCKS5 socksproxy:1080", ToDebugString());
525 }
526 
TEST_F(ProxyConfigWebSocketTest,PrefersHttpsToHttp)527 TEST_F(ProxyConfigWebSocketTest, PrefersHttpsToHttp) {
528   ParseFromString("http=proxy:3128 ; https=sslproxy:3128");
529   Apply(WssUrl());
530   EXPECT_EQ("PROXY sslproxy:3128", ToDebugString());
531 }
532 
533 // Tests when a proxy-per-url-scheme configuration was used, and proxies are
534 // specified for http://, https://, and a fallback proxy (non-SOCKS).
535 // Even though the fallback proxy is not SOCKS, it is still favored over the
536 // proxy for http://* and https://*.
TEST_F(ProxyConfigWebSocketTest,PrefersNonSocksFallbackOverHttps)537 TEST_F(ProxyConfigWebSocketTest, PrefersNonSocksFallbackOverHttps) {
538   // The notation for "socks=" is abused to set the "fallback proxy".
539   ParseFromString(
540       "http=proxy:3128 ; https=sslproxy:3128; socks=https://httpsproxy");
541   EXPECT_EQ("HTTPS httpsproxy:443", rules_.fallback_proxies.ToDebugString());
542   Apply(WssUrl());
543   EXPECT_EQ("HTTPS httpsproxy:443", ToDebugString());
544 }
545 
546 // Tests when a proxy-per-url-scheme configuration was used, and the fallback
547 // proxy is a non-SOCKS proxy, and no proxy was given for https://* or
548 // http://*. The fallback proxy is used.
TEST_F(ProxyConfigWebSocketTest,UsesNonSocksFallbackProxy)549 TEST_F(ProxyConfigWebSocketTest, UsesNonSocksFallbackProxy) {
550   // The notation for "socks=" is abused to set the "fallback proxy".
551   ParseFromString("ftp=ftpproxy:3128; socks=https://httpsproxy");
552   EXPECT_EQ("HTTPS httpsproxy:443", rules_.fallback_proxies.ToDebugString());
553   Apply(WssUrl());
554   EXPECT_EQ("HTTPS httpsproxy:443", ToDebugString());
555 }
556 
TEST_F(ProxyConfigWebSocketTest,PrefersHttpsEvenForWs)557 TEST_F(ProxyConfigWebSocketTest, PrefersHttpsEvenForWs) {
558   ParseFromString("http=proxy:3128 ; https=sslproxy:3128");
559   Apply(WsUrl());
560   EXPECT_EQ("PROXY sslproxy:3128", ToDebugString());
561 }
562 
TEST_F(ProxyConfigWebSocketTest,PrefersHttpToDirect)563 TEST_F(ProxyConfigWebSocketTest, PrefersHttpToDirect) {
564   ParseFromString("http=proxy:3128");
565   Apply(WssUrl());
566   EXPECT_EQ("PROXY proxy:3128", ToDebugString());
567 }
568 
TEST_F(ProxyConfigWebSocketTest,IgnoresFtpProxy)569 TEST_F(ProxyConfigWebSocketTest, IgnoresFtpProxy) {
570   ParseFromString("ftp=ftpproxy:3128");
571   Apply(WssUrl());
572   EXPECT_EQ("DIRECT", ToDebugString());
573 }
574 
TEST_F(ProxyConfigWebSocketTest,ObeysBypassRules)575 TEST_F(ProxyConfigWebSocketTest, ObeysBypassRules) {
576   ParseFromString("http=proxy:3128 ; https=sslproxy:3128");
577   rules_.bypass_rules.AddRuleFromString(".chromium.org");
578   Apply(GURL("wss://codereview.chromium.org/feed"));
579   EXPECT_EQ("DIRECT", ToDebugString());
580 }
581 
TEST_F(ProxyConfigWebSocketTest,ObeysLocalBypass)582 TEST_F(ProxyConfigWebSocketTest, ObeysLocalBypass) {
583   ParseFromString("http=proxy:3128 ; https=sslproxy:3128");
584   rules_.bypass_rules.AddRuleFromString("<local>");
585   Apply(GURL("ws://localhost/feed"));
586   EXPECT_EQ("DIRECT", ToDebugString());
587 }
588 
589 }  // namespace
590 }  // namespace net
591