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 | |
24 | using namespace folly; |
25 | |
26 | TEST(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 | |