1/*
2 * Copyright 2013-present Facebook, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <folly/Uri.h>
18#include <folly/portability/GTest.h>
19
20#include <boost/algorithm/string.hpp>
21#include <glog/logging.h>
22#include <map>
23
24using namespace folly;
25
26TEST(Uri, Simple) {
27 {
28 fbstring s("http://www.facebook.com/hello/world?query#fragment");
29 Uri u(s);
30 EXPECT_EQ("http", u.scheme());
31 EXPECT_EQ("", u.username());
32 EXPECT_EQ("", u.password());
33 EXPECT_EQ("www.facebook.com", u.host());
34 EXPECT_EQ(0, u.port());
35 EXPECT_EQ("www.facebook.com", u.authority());
36 EXPECT_EQ("/hello/world", u.path());
37 EXPECT_EQ("query", u.query());
38 EXPECT_EQ("fragment", u.fragment());
39 EXPECT_EQ(s, u.fbstr()); // canonical
40 }
41
42 {
43 fbstring s("http://www.facebook.com:8080/hello/world?query#fragment");
44 Uri u(s);
45 EXPECT_EQ("http", u.scheme());
46 EXPECT_EQ("", u.username());
47 EXPECT_EQ("", u.password());
48 EXPECT_EQ("www.facebook.com", u.host());
49 EXPECT_EQ(8080, u.port());
50 EXPECT_EQ("www.facebook.com:8080", u.authority());
51 EXPECT_EQ("/hello/world", u.path());
52 EXPECT_EQ("query", u.query());
53 EXPECT_EQ("fragment", u.fragment());
54 EXPECT_EQ(s, u.fbstr()); // canonical
55 }
56
57 {
58 fbstring s("http://127.0.0.1:8080/hello/world?query#fragment");
59 Uri u(s);
60 EXPECT_EQ("http", u.scheme());
61 EXPECT_EQ("", u.username());
62 EXPECT_EQ("", u.password());
63 EXPECT_EQ("127.0.0.1", u.host());
64 EXPECT_EQ(8080, u.port());
65 EXPECT_EQ("127.0.0.1:8080", u.authority());
66 EXPECT_EQ("/hello/world", u.path());
67 EXPECT_EQ("query", u.query());
68 EXPECT_EQ("fragment", u.fragment());
69 EXPECT_EQ(s, u.fbstr()); // canonical
70 }
71
72 {
73 fbstring s("http://[::1]:8080/hello/world?query#fragment");
74 Uri u(s);
75 EXPECT_EQ("http", u.scheme());
76 EXPECT_EQ("", u.username());
77 EXPECT_EQ("", u.password());
78 EXPECT_EQ("[::1]", u.host());
79 EXPECT_EQ("::1", u.hostname());
80 EXPECT_EQ(8080, u.port());
81 EXPECT_EQ("[::1]:8080", u.authority());
82 EXPECT_EQ("/hello/world", u.path());
83 EXPECT_EQ("query", u.query());
84 EXPECT_EQ("fragment", u.fragment());
85 EXPECT_EQ(s, u.fbstr()); // canonical
86 }
87
88 {
89 fbstring s("http://[2401:db00:20:7004:face:0:29:0]:8080/hello/world?query");
90 Uri u(s);
91 EXPECT_EQ("http", u.scheme());
92 EXPECT_EQ("", u.username());
93 EXPECT_EQ("", u.password());
94 EXPECT_EQ("[2401:db00:20:7004:face:0:29:0]", u.host());
95 EXPECT_EQ("2401:db00:20:7004:face:0:29:0", u.hostname());
96 EXPECT_EQ(8080, u.port());
97 EXPECT_EQ("[2401:db00:20:7004:face:0:29:0]:8080", u.authority());
98 EXPECT_EQ("/hello/world", u.path());
99 EXPECT_EQ("query", u.query());
100 EXPECT_EQ("", u.fragment());
101 EXPECT_EQ(s, u.fbstr()); // canonical
102 }
103
104 {
105 fbstring s("http://[2401:db00:20:7004:face:0:29:0]/hello/world?query");
106 Uri u(s);
107 EXPECT_EQ("http", u.scheme());
108 EXPECT_EQ("", u.username());
109 EXPECT_EQ("", u.password());
110 EXPECT_EQ("[2401:db00:20:7004:face:0:29:0]", u.host());
111 EXPECT_EQ("2401:db00:20:7004:face:0:29:0", u.hostname());
112 EXPECT_EQ(0, u.port());
113 EXPECT_EQ("[2401:db00:20:7004:face:0:29:0]", u.authority());
114 EXPECT_EQ("/hello/world", u.path());
115 EXPECT_EQ("query", u.query());
116 EXPECT_EQ("", u.fragment());
117 EXPECT_EQ(s, u.fbstr()); // canonical
118 }
119
120 {
121 fbstring s("http://user:pass@host.com/");
122 Uri u(s);
123 EXPECT_EQ("http", u.scheme());
124 EXPECT_EQ("user", u.username());
125 EXPECT_EQ("pass", u.password());
126 EXPECT_EQ("host.com", u.host());
127 EXPECT_EQ(0, u.port());
128 EXPECT_EQ("user:pass@host.com", u.authority());
129 EXPECT_EQ("/", u.path());
130 EXPECT_EQ("", u.query());
131 EXPECT_EQ("", u.fragment());
132 EXPECT_EQ(s, u.fbstr());
133 }
134
135 {
136 fbstring s("http://user@host.com/");
137 Uri u(s);
138 EXPECT_EQ("http", u.scheme());
139 EXPECT_EQ("user", u.username());
140 EXPECT_EQ("", u.password());
141 EXPECT_EQ("host.com", u.host());
142 EXPECT_EQ(0, u.port());
143 EXPECT_EQ("user@host.com", u.authority());
144 EXPECT_EQ("/", u.path());
145 EXPECT_EQ("", u.query());
146 EXPECT_EQ("", u.fragment());
147 EXPECT_EQ(s, u.fbstr());
148 }
149
150 {
151 fbstring s("http://user:@host.com/");
152 Uri u(s);
153 EXPECT_EQ("http", u.scheme());
154 EXPECT_EQ("user", u.username());
155 EXPECT_EQ("", u.password());
156 EXPECT_EQ("host.com", u.host());
157 EXPECT_EQ(0, u.port());
158 EXPECT_EQ("user@host.com", u.authority());
159 EXPECT_EQ("/", u.path());
160 EXPECT_EQ("", u.query());
161 EXPECT_EQ("", u.fragment());
162 EXPECT_EQ("http://user@host.com/", u.fbstr());
163 }
164
165 {
166 fbstring s("http://:pass@host.com/");
167 Uri u(s);
168 EXPECT_EQ("http", u.scheme());
169 EXPECT_EQ("", u.username());
170 EXPECT_EQ("pass", u.password());
171 EXPECT_EQ("host.com", u.host());
172 EXPECT_EQ(0, u.port());
173 EXPECT_EQ(":pass@host.com", u.authority());
174 EXPECT_EQ("/", u.path());
175 EXPECT_EQ("", u.query());
176 EXPECT_EQ("", u.fragment());
177 EXPECT_EQ(s, u.fbstr());
178 }
179
180 {
181 fbstring s("http://@host.com/");
182 Uri u(s);
183 EXPECT_EQ("http", u.scheme());
184 EXPECT_EQ("", u.username());
185 EXPECT_EQ("", u.password());
186 EXPECT_EQ("host.com", u.host());
187 EXPECT_EQ(0, u.port());
188 EXPECT_EQ("host.com", u.authority());
189 EXPECT_EQ("/", u.path());
190 EXPECT_EQ("", u.query());
191 EXPECT_EQ("", u.fragment());
192 EXPECT_EQ("http://host.com/", u.fbstr());
193 }
194
195 {
196 fbstring s("http://:@host.com/");
197 Uri u(s);
198 EXPECT_EQ("http", u.scheme());
199 EXPECT_EQ("", u.username());
200 EXPECT_EQ("", u.password());
201 EXPECT_EQ("host.com", u.host());
202 EXPECT_EQ(0, u.port());
203 EXPECT_EQ("host.com", u.authority());
204 EXPECT_EQ("/", u.path());
205 EXPECT_EQ("", u.query());
206 EXPECT_EQ("", u.fragment());
207 EXPECT_EQ("http://host.com/", u.fbstr());
208 }
209
210 {
211 fbstring s("file:///etc/motd");
212 Uri u(s);
213 EXPECT_EQ("file", u.scheme());
214 EXPECT_EQ("", u.username());
215 EXPECT_EQ("", u.password());
216 EXPECT_EQ("", u.host());
217 EXPECT_EQ(0, u.port());
218 EXPECT_EQ("", u.authority());
219 EXPECT_EQ("/etc/motd", u.path());
220 EXPECT_EQ("", u.query());
221 EXPECT_EQ("", u.fragment());
222 EXPECT_EQ(s, u.fbstr());
223 }
224
225 {
226 fbstring s("file:/etc/motd");
227 Uri u(s);
228 EXPECT_EQ("file", u.scheme());
229 EXPECT_EQ("", u.username());
230 EXPECT_EQ("", u.password());
231 EXPECT_EQ("", u.host());
232 EXPECT_EQ(0, u.port());
233 EXPECT_EQ("", u.authority());
234 EXPECT_EQ("/etc/motd", u.path());
235 EXPECT_EQ("", u.query());
236 EXPECT_EQ("", u.fragment());
237 EXPECT_EQ("file:/etc/motd", u.fbstr());
238 }
239
240 {
241 fbstring s("file://etc/motd");
242 Uri u(s);
243 EXPECT_EQ("file", u.scheme());
244 EXPECT_EQ("", u.username());
245 EXPECT_EQ("", u.password());
246 EXPECT_EQ("etc", u.host());
247 EXPECT_EQ(0, u.port());
248 EXPECT_EQ("etc", u.authority());
249 EXPECT_EQ("/motd", u.path());
250 EXPECT_EQ("", u.query());
251 EXPECT_EQ("", u.fragment());
252 EXPECT_EQ(s, u.fbstr());
253 }
254
255 {
256 // test query parameters
257 fbstring s("http://localhost?&key1=foo&key2=&key3&=bar&=bar=&");
258 Uri u(s);
259 auto paramsList = u.getQueryParams();
260 std::map<fbstring, fbstring> params;
261 for (auto& param : paramsList) {
262 params[param.first] = param.second;
263 }
264 EXPECT_EQ(3, params.size());
265 EXPECT_EQ("foo", params["key1"]);
266 EXPECT_NE(params.end(), params.find("key2"));
267 EXPECT_EQ("", params["key2"]);
268 EXPECT_NE(params.end(), params.find("key3"));
269 EXPECT_EQ("", params["key3"]);
270 }
271
272 {
273 // test query parameters
274 fbstring s("http://localhost?&&&&&&&&&&&&&&&");
275 Uri u(s);
276 auto params = u.getQueryParams();
277 EXPECT_TRUE(params.empty());
278 }
279
280 {
281 // test query parameters
282 fbstring s("http://localhost?&=invalid_key&key2&key3=foo");
283 Uri u(s);
284 auto paramsList = u.getQueryParams();
285 std::map<fbstring, fbstring> params;
286 for (auto& param : paramsList) {
287 params[param.first] = param.second;
288 }
289 EXPECT_EQ(2, params.size());
290 EXPECT_NE(params.end(), params.find("key2"));
291 EXPECT_EQ("", params["key2"]);
292 EXPECT_EQ("foo", params["key3"]);
293 }
294
295 {
296 // test query parameters
297 fbstring s("http://localhost?&key1=====&&=key2&key3=");
298 Uri u(s);
299 auto paramsList = u.getQueryParams();
300 std::map<fbstring, fbstring> params;
301 for (auto& param : paramsList) {
302 params[param.first] = param.second;
303 }
304 EXPECT_EQ(1, params.size());
305 EXPECT_NE(params.end(), params.find("key3"));
306 EXPECT_EQ("", params["key3"]);
307 }
308
309 {
310 // test query parameters
311 fbstring s("http://localhost?key1=foo=bar&key2=foobar&");
312 Uri u(s);
313 auto paramsList = u.getQueryParams();
314 std::map<fbstring, fbstring> params;
315 for (auto& param : paramsList) {
316 params[param.first] = param.second;
317 }
318 EXPECT_EQ(1, params.size());
319 EXPECT_EQ("foobar", params["key2"]);
320 }
321
322 {
323 fbstring s("2http://www.facebook.com");
324
325 try {
326 Uri u(s);
327 CHECK(false) << "Control should not have reached here";
328 } catch (const std::invalid_argument& ex) {
329 EXPECT_TRUE(boost::algorithm::ends_with(ex.what(), s));
330 }
331 }
332
333 {
334 fbstring s("www[facebook]com");
335
336 try {
337 Uri u("http://" + s);
338 CHECK(false) << "Control should not have reached here";
339 } catch (const std::invalid_argument& ex) {
340 EXPECT_TRUE(boost::algorithm::ends_with(ex.what(), s));
341 }
342 }
343
344 {
345 fbstring s("http://[::1:8080/hello/world?query#fragment");
346
347 try {
348 Uri u(s);
349 CHECK(false) << "Control should not have reached here";
350 } catch (const std::invalid_argument&) {
351 // success
352 }
353 }
354
355 {
356 fbstring s("http://::1]:8080/hello/world?query#fragment");
357
358 try {
359 Uri u(s);
360 CHECK(false) << "Control should not have reached here";
361 } catch (const std::invalid_argument&) {
362 // success
363 }
364 }
365
366 {
367 fbstring s("http://::1:8080/hello/world?query#fragment");
368
369 try {
370 Uri u(s);
371 CHECK(false) << "Control should not have reached here";
372 } catch (const std::invalid_argument&) {
373 // success
374 }
375 }
376
377 {
378 fbstring s("http://2401:db00:20:7004:face:0:29:0/hello/world?query");
379
380 try {
381 Uri u(s);
382 CHECK(false) << "Control should not have reached here";
383 } catch (const std::invalid_argument&) {
384 // success
385 }
386 }
387
388 // No authority (no "//") is valid
389 {
390 fbstring s("this:is/a/valid/uri");
391 Uri u(s);
392 EXPECT_EQ("this", u.scheme());
393 EXPECT_EQ("is/a/valid/uri", u.path());
394 EXPECT_EQ(s, u.fbstr());
395 }
396 {
397 fbstring s("this:is:another:valid:uri");
398 Uri u(s);
399 EXPECT_EQ("this", u.scheme());
400 EXPECT_EQ("is:another:valid:uri", u.path());
401 EXPECT_EQ(s, u.fbstr());
402 }
403 {
404 fbstring s("this:is@another:valid:uri");
405 Uri u(s);
406 EXPECT_EQ("this", u.scheme());
407 EXPECT_EQ("is@another:valid:uri", u.path());
408 EXPECT_EQ(s, u.fbstr());
409 }
410}
411