1 // Copyright 2021 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_string_util.h"
6
7 #include "net/base/proxy_chain.h"
8 #include "net/base/proxy_server.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10
11 namespace net {
12 namespace {
13
14 // Test the creation of ProxyServer using ProxyUriToProxyServer, which parses
15 // inputs of the form [<scheme>"://"]<host>[":"<port>]. Verify that each part
16 // was labelled correctly, and the accessors all give the right data.
TEST(ProxySpecificationUtilTest,ProxyUriToProxyServer)17 TEST(ProxySpecificationUtilTest, ProxyUriToProxyServer) {
18 const struct {
19 const char* const input_uri;
20 const char* const expected_uri;
21 ProxyServer::Scheme expected_scheme;
22 const char* const expected_host;
23 int expected_port;
24 const char* const expected_pac_string;
25 } tests[] = {
26 // HTTP proxy URIs:
27 {"foopy:10", // No scheme.
28 "foopy:10", ProxyServer::SCHEME_HTTP, "foopy", 10, "PROXY foopy:10"},
29 {"http://foopy", // No port.
30 "foopy:80", ProxyServer::SCHEME_HTTP, "foopy", 80, "PROXY foopy:80"},
31 {"http://foopy:10", "foopy:10", ProxyServer::SCHEME_HTTP, "foopy", 10,
32 "PROXY foopy:10"},
33
34 // IPv6 HTTP proxy URIs:
35 {"[fedc:ba98:7654:3210:fedc:ba98:7654:3210]:10", // No scheme.
36 "[fedc:ba98:7654:3210:fedc:ba98:7654:3210]:10", ProxyServer::SCHEME_HTTP,
37 "fedc:ba98:7654:3210:fedc:ba98:7654:3210", 10,
38 "PROXY [fedc:ba98:7654:3210:fedc:ba98:7654:3210]:10"},
39 {"http://[3ffe:2a00:100:7031::1]", // No port.
40 "[3ffe:2a00:100:7031::1]:80", ProxyServer::SCHEME_HTTP,
41 "3ffe:2a00:100:7031::1", 80, "PROXY [3ffe:2a00:100:7031::1]:80"},
42
43 // SOCKS4 proxy URIs:
44 {"socks4://foopy", // No port.
45 "socks4://foopy:1080", ProxyServer::SCHEME_SOCKS4, "foopy", 1080,
46 "SOCKS foopy:1080"},
47 {"socks4://foopy:10", "socks4://foopy:10", ProxyServer::SCHEME_SOCKS4,
48 "foopy", 10, "SOCKS foopy:10"},
49
50 // SOCKS5 proxy URIs:
51 {"socks5://foopy", // No port.
52 "socks5://foopy:1080", ProxyServer::SCHEME_SOCKS5, "foopy", 1080,
53 "SOCKS5 foopy:1080"},
54 {"socks5://foopy:10", "socks5://foopy:10", ProxyServer::SCHEME_SOCKS5,
55 "foopy", 10, "SOCKS5 foopy:10"},
56
57 // SOCKS proxy URIs (should default to SOCKS5)
58 {"socks://foopy", // No port.
59 "socks5://foopy:1080", ProxyServer::SCHEME_SOCKS5, "foopy", 1080,
60 "SOCKS5 foopy:1080"},
61 {"socks://foopy:10", "socks5://foopy:10", ProxyServer::SCHEME_SOCKS5,
62 "foopy", 10, "SOCKS5 foopy:10"},
63
64 // HTTPS proxy URIs:
65 {"https://foopy", // No port
66 "https://foopy:443", ProxyServer::SCHEME_HTTPS, "foopy", 443,
67 "HTTPS foopy:443"},
68 {"https://foopy:10", // Non-standard port
69 "https://foopy:10", ProxyServer::SCHEME_HTTPS, "foopy", 10,
70 "HTTPS foopy:10"},
71 {"https://1.2.3.4:10", // IP Address
72 "https://1.2.3.4:10", ProxyServer::SCHEME_HTTPS, "1.2.3.4", 10,
73 "HTTPS 1.2.3.4:10"},
74
75 // Hostname canonicalization:
76 {"[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:10", // No scheme.
77 "[fedc:ba98:7654:3210:fedc:ba98:7654:3210]:10", ProxyServer::SCHEME_HTTP,
78 "fedc:ba98:7654:3210:fedc:ba98:7654:3210", 10,
79 "PROXY [fedc:ba98:7654:3210:fedc:ba98:7654:3210]:10"},
80 {"http://[::192.9.5.5]", "[::c009:505]:80", ProxyServer::SCHEME_HTTP,
81 "::c009:505", 80, "PROXY [::c009:505]:80"},
82 {"http://[::FFFF:129.144.52.38]:80", "[::ffff:8190:3426]:80",
83 ProxyServer::SCHEME_HTTP, "::ffff:8190:3426", 80,
84 "PROXY [::ffff:8190:3426]:80"},
85 {"http://f\u00fcpy:85", "xn--fpy-hoa:85", ProxyServer::SCHEME_HTTP,
86 "xn--fpy-hoa", 85, "PROXY xn--fpy-hoa:85"},
87 {"https://0xA.020.3.4:443", "https://10.16.3.4:443",
88 ProxyServer::SCHEME_HTTPS, "10.16.3.4", 443, "HTTPS 10.16.3.4:443"},
89 {"http://FoO.tEsT:80", "foo.test:80", ProxyServer::SCHEME_HTTP,
90 "foo.test", 80, "PROXY foo.test:80"},
91 };
92
93 for (const auto& test : tests) {
94 ProxyServer uri =
95 ProxyUriToProxyServer(test.input_uri, ProxyServer::SCHEME_HTTP);
96 EXPECT_TRUE(uri.is_valid());
97 EXPECT_EQ(test.expected_uri, ProxyServerToProxyUri(uri));
98 EXPECT_EQ(test.expected_scheme, uri.scheme());
99 EXPECT_EQ(test.expected_host, uri.host_port_pair().host());
100 EXPECT_EQ(test.expected_port, uri.host_port_pair().port());
101 EXPECT_EQ(test.expected_pac_string, ProxyServerToPacResultElement(uri));
102 }
103 }
104
105 // Test parsing of the special URI form "direct://".
TEST(ProxySpecificationUtilTest,DirectProxyUriToProxyChain)106 TEST(ProxySpecificationUtilTest, DirectProxyUriToProxyChain) {
107 const char* const uris[] = {
108 "direct://",
109 "DIRECT://",
110 "DiReCt://",
111 };
112
113 for (const char* uri : uris) {
114 ProxyChain valid_uri = ProxyUriToProxyChain(uri, ProxyServer::SCHEME_HTTP);
115 EXPECT_TRUE(valid_uri.IsValid());
116 EXPECT_TRUE(valid_uri.is_direct());
117 }
118
119 // Direct is not allowed a host/port.
120 ProxyChain invalid_uri =
121 ProxyUriToProxyChain("direct://xyz", ProxyServer::SCHEME_HTTP);
122 EXPECT_FALSE(invalid_uri.IsValid());
123 EXPECT_FALSE(invalid_uri.is_direct());
124 }
125
126 // Test parsing some invalid inputs.
TEST(ProxySpecificationUtilTest,InvalidProxyUriToProxyServer)127 TEST(ProxySpecificationUtilTest, InvalidProxyUriToProxyServer) {
128 const char* const tests[] = {
129 "",
130 " ",
131 "dddf:", // not a valid port
132 "dddd:d", // not a valid port
133 "http://", // not a valid host/port.
134 "direct://", // direct is not a valid proxy server.
135 "http:/", // ambiguous, but will fail because of bad port.
136 "http:", // ambiguous, but will fail because of bad port.
137 "foopy.111", // Interpreted as invalid IPv4 address.
138 "foo.test/" // Paths disallowed.
139 "foo.test:123/" // Paths disallowed.
140 "foo.test/foo" // Paths disallowed.
141 };
142
143 for (const char* test : tests) {
144 SCOPED_TRACE(test);
145 ProxyServer uri = ProxyUriToProxyServer(test, ProxyServer::SCHEME_HTTP);
146 EXPECT_FALSE(uri.is_valid());
147 EXPECT_FALSE(uri.is_http());
148 EXPECT_FALSE(uri.is_socks());
149 }
150 }
151
152 // Test that LWS (SP | HT) is disregarded from the ends.
TEST(ProxySpecificationUtilTest,WhitespaceProxyUriToProxyServer)153 TEST(ProxySpecificationUtilTest, WhitespaceProxyUriToProxyServer) {
154 const char* const tests[] = {
155 " foopy:80",
156 "foopy:80 \t",
157 " \tfoopy:80 ",
158 };
159
160 for (const char* test : tests) {
161 ProxyServer uri = ProxyUriToProxyServer(test, ProxyServer::SCHEME_HTTP);
162 EXPECT_EQ("foopy:80", ProxyServerToProxyUri(uri));
163 }
164 }
165
166 // Test parsing a ProxyServer from a PAC representation.
TEST(ProxySpecificationUtilTest,PacResultElementToProxyServer)167 TEST(ProxySpecificationUtilTest, PacResultElementToProxyServer) {
168 const struct {
169 const char* const input_pac;
170 const char* const expected_uri;
171 } tests[] = {
172 {
173 "PROXY foopy:10",
174 "foopy:10",
175 },
176 {
177 " PROXY foopy:10 ",
178 "foopy:10",
179 },
180 {
181 "pRoXy foopy:10",
182 "foopy:10",
183 },
184 {
185 "PROXY foopy", // No port.
186 "foopy:80",
187 },
188 {
189 "socks foopy",
190 "socks4://foopy:1080",
191 },
192 {
193 "socks4 foopy",
194 "socks4://foopy:1080",
195 },
196 {
197 "socks5 foopy",
198 "socks5://foopy:1080",
199 },
200 {
201 "socks5 foopy:11",
202 "socks5://foopy:11",
203 },
204 {
205 "https foopy",
206 "https://foopy:443",
207 },
208 {
209 "https foopy:10",
210 "https://foopy:10",
211 },
212 {"PROXY [FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:10",
213 "[fedc:ba98:7654:3210:fedc:ba98:7654:3210]:10"},
214 {"PROXY f\u00fcpy:85", "xn--fpy-hoa:85"},
215 };
216
217 for (const auto& test : tests) {
218 SCOPED_TRACE(test.input_pac);
219 ProxyServer server = PacResultElementToProxyServer(test.input_pac);
220 EXPECT_TRUE(server.is_valid());
221 EXPECT_EQ(test.expected_uri, ProxyServerToProxyUri(server));
222
223 ProxyChain chain = PacResultElementToProxyChain(test.input_pac);
224 EXPECT_TRUE(chain.IsValid());
225 if (!chain.is_direct()) {
226 EXPECT_EQ(test.expected_uri, ProxyServerToProxyUri(chain.First()));
227 }
228 }
229 }
230
231 // Test parsing a ProxyServer from an invalid PAC representation.
TEST(ProxySpecificationUtilTest,InvalidPacResultElementToProxyServer)232 TEST(ProxySpecificationUtilTest, InvalidPacResultElementToProxyServer) {
233 const char* const tests[] = {
234 "PROXY", // missing host/port.
235 "HTTPS", // missing host/port.
236 "SOCKS", // missing host/port.
237 "DIRECT foopy:10", // direct cannot have host/port.
238 "INVALIDSCHEME", // unrecognized scheme.
239 "INVALIDSCHEME foopy:10", // unrecognized scheme.
240 "HTTP foopy:10", // http scheme should be "PROXY"
241 };
242
243 for (const char* test : tests) {
244 SCOPED_TRACE(test);
245 ProxyServer server = PacResultElementToProxyServer(test);
246 EXPECT_FALSE(server.is_valid());
247
248 ProxyChain chain = PacResultElementToProxyChain(test);
249 EXPECT_FALSE(chain.IsValid());
250 }
251 }
252
253 } // namespace
254 } // namespace net
255