3 #include <glog/logging.h>
14 {"foo://dude@example.com:8042/over/there?name=ferret#nose",
15 {"foo", "dude@example.com:8042", "dude", "example.com", "8042", "/over/there", "name=ferret", "nose", }, },
17 {"foo://example.com:8042/over/there?name=ferret#nose",
18 {"foo", "example.com:8042", {}, "example.com", "8042", "/over/there", "name=ferret", "nose", }, },
20 {"ftp://cnn.example.com&story=breaking_news@10.0.0.1/top_story.htm",
21 {"ftp", "cnn.example.com&story=breaking_news@10.0.0.1", "cnn.example.com&story=breaking_news", "10.0.0.1", {}, "/top_story.htm", {}, {}, }, },
24 {"ftp", "foo.bar", {}, "foo.bar", {}, "/baz", {}, {}, }, },
26 {"ftp://ftp.is.co.za/rfc/rfc1808.txt",
27 {"ftp", "ftp.is.co.za", {}, "ftp.is.co.za", {}, "/rfc/rfc1808.txt", {}, {}, }, },
29 {"http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com",
30 {"http", "-.~_!$&'()*+,;=:%40:80%2f::::::@example.com", "-.~_!$&'()*+,;=:%40:80%2f::::::", "example.com", {}, "", {}, {}, }, },
33 {"http", "1337.net", {}, "1337.net", {}, "", {}, {}, }, },
35 {"http://142.42.1.1/",
36 {"http", "142.42.1.1", {}, "142.42.1.1", {}, "/", {}, {}, }, },
38 {"http://142.42.1.1:8080/",
39 {"http", "142.42.1.1:8080", {}, "142.42.1.1", "8080", "/", {}, {}, }, },
41 {"http://223.255.255.254",
42 {"http", "223.255.255.254", {}, "223.255.255.254", {}, "", {}, {}, }, },
45 {"http", "a.b-c.de", {}, "a.b-c.de", {}, "", {}, {}, }, },
47 {"http://code.google.com/events/#&product=browser",
48 {"http", "code.google.com", {}, "code.google.com", {}, "/events/", {}, "&product=browser", }, },
50 {"http://example.com",
51 {"http", "example.com", {}, "example.com", {}, "", {}, {}, }, },
53 {"http://example.com/",
54 {"http", "example.com", {}, "example.com", {}, "/", {}, {}, }, },
56 {"http://example.com:",
57 {"http", "example.com:", {}, "example.com", "", "", {}, {}, }, },
59 {"http://example.com:/",
60 {"http", "example.com:", {}, "example.com", "", "/", {}, {}, }, },
62 {"http://example.com:80",
63 {"http", "example.com:80", {}, "example.com", "80", "", {}, {}, }, },
65 {"http://example.com:80/",
66 {"http", "example.com:80", {}, "example.com", "80", "/", {}, {}, }, },
68 {"http://foo.bar/?q=Test%20URL-encoded%20stuff",
69 {"http", "foo.bar", {}, "foo.bar", {}, "/", "q=Test%20URL-encoded%20stuff", {}, }, },
71 {"http://foo.com/(something)?after=parens",
72 {"http", "foo.com", {}, "foo.com", {}, "/(something)", "after=parens", {}, }, },
74 {"http://foo.com/blah_(wikipedia)#cite-1",
75 {"http", "foo.com", {}, "foo.com", {}, "/blah_(wikipedia)", {}, "cite-1", }, },
77 {"http://foo.com/blah_(wikipedia)_blah#cite-1",
78 {"http", "foo.com", {}, "foo.com", {}, "/blah_(wikipedia)_blah", {}, "cite-1", }, },
80 {"http://foo.com/blah_blah",
81 {"http", "foo.com", {}, "foo.com", {}, "/blah_blah", {}, {}, }, },
83 {"http://foo.com/blah_blah/",
84 {"http", "foo.com", {}, "foo.com", {}, "/blah_blah/", {}, {}, }, },
86 {"http://foo.com/blah_blah_(wikipedia)",
87 {"http", "foo.com", {}, "foo.com", {}, "/blah_blah_(wikipedia)", {}, {}, }, },
89 {"http://foo.com/blah_blah_(wikipedia)_(again)",
90 {"http", "foo.com", {}, "foo.com", {}, "/blah_blah_(wikipedia)_(again)", {}, {}, }, },
92 {"http://foo.com/unicode_(✪)_in_parens",
93 {"http", "foo.com", {}, "foo.com", {}, "/unicode_(✪)_in_parens", {}, {}, }, },
96 {"http", "j.mp", {}, "j.mp", {}, "", {}, {}, }, },
98 {"http://userid:password@example.com",
99 {"http", "userid:password@example.com", "userid:password", "example.com", {}, "", {}, {}, }, },
101 {"http://userid:password@example.com/",
102 {"http", "userid:password@example.com", "userid:password", "example.com", {}, "/", {}, {}, }, },
104 {"http://userid:password@example.com:8080",
105 {"http", "userid:password@example.com:8080", "userid:password", "example.com", "8080", "", {}, {}, }, },
107 {"http://userid:password@example.com:8080/",
108 {"http", "userid:password@example.com:8080", "userid:password", "example.com", "8080", "/", {}, {}, }, },
110 {"http://userid@example.com",
111 {"http", "userid@example.com", "userid", "example.com", {}, "", {}, {}, }, },
113 {"http://userid@example.com/",
114 {"http", "userid@example.com", "userid", "example.com", {}, "/", {}, {}, }, },
116 {"http://userid@example.com:8080",
117 {"http", "userid@example.com:8080", "userid", "example.com", "8080", "", {}, {}, }, },
119 {"http://userid@example.com:8080/",
120 {"http", "userid@example.com:8080", "userid", "example.com", "8080", "/", {}, {}, }, },
122 {"http://www.example.com/wpstyle/?p=364",
123 {"http", "www.example.com", {}, "www.example.com", {}, "/wpstyle/", "p=364", {}, }, },
125 {"http://www.ics.uci.edu/pub/ietf/uri/#Related",
126 {"http", "www.ics.uci.edu", {}, "www.ics.uci.edu", {}, "/pub/ietf/uri/", {}, "Related", }, },
128 {"http://www.ietf.org/rfc/rfc2396.txt",
129 {"http", "www.ietf.org", {}, "www.ietf.org", {}, "/rfc/rfc2396.txt", {}, {}, }, },
131 {"http://مثال.إختبار",
132 {"http", "مثال.إختبار", {}, "مثال.إختبار", {}, "", {}, {}, }, },
134 {"http://उदाहरण.परीक्षा",
135 {"http", "उदाहरण.परीक्षा", {}, "उदाहरण.परीक्षा", {}, "", {}, {}, }, },
138 {"http", "⌘.ws", {}, "⌘.ws", {}, "", {}, {}, }, },
141 {"http", "⌘.ws", {}, "⌘.ws", {}, "/", {}, {}, }, },
143 {"http://☺.damowmow.com/",
144 {"http", "☺.damowmow.com", {}, "☺.damowmow.com", {}, "/", {}, {}, }, },
146 {"http://✪df.ws/123",
147 {"http", "✪df.ws", {}, "✪df.ws", {}, "/123", {}, {}, }, },
150 {"http", "➡.ws", {}, "➡.ws", {}, "/䨹", {}, {}, }, },
153 {"http", "例子.测试", {}, "例子.测试", {}, "", {}, {}, }, },
155 {"https://tools.ietf.org/html/rfc3986#appendix-B",
156 {"https", "tools.ietf.org", {}, "tools.ietf.org", {}, "/html/rfc3986", {}, "appendix-B", }, },
158 {"https://www.example.com/foo/?bar=baz&inga=42&quux",
159 {"https", "www.example.com", {}, "www.example.com", {}, "/foo/", "bar=baz&inga=42&quux", {}, }, },
161 {"https://xn%2D%2Dui8h%2Edigilicious%2Ecom/",
162 {"https", "xn%2D%2Dui8h%2Edigilicious%2Ecom", {}, "xn%2D%2Dui8h%2Edigilicious%2Ecom", {}, "/", {}, {}, }, },
164 {"https://xn--ui8h%2Edigilicious%2Ecom/",
165 {"https", "xn--ui8h%2Edigilicious%2Ecom", {}, "xn--ui8h%2Edigilicious%2Ecom", {}, "/", {}, {}, }, },
167 {"https://xn--ui8h.digilicious.com/",
168 {"https", "xn--ui8h.digilicious.com", {}, "xn--ui8h.digilicious.com", {}, "/", {}, {}, }, },
170 {"https://🍔.digilicious.com/",
171 {"https", "🍔.digilicious.com", {}, "🍔.digilicious.com", {}, "/", {}, {}, }, },
173 {"ldap://[2001:db8::7]/c=GB?objectClass?one",
174 {"ldap", "[2001:db8::7]", {}, "[2001:db8::7]", {}, "/c=GB", "objectClass?one", {}, }, },
176 {"mailto:John.Doe@example.com",
177 {"mailto", {}, {}, {}, {}, "John.Doe@example.com", {}, {}, }, },
179 {"news:comp.infosystems.www.servers.unix",
180 {"news", {}, {}, {}, {}, "comp.infosystems.www.servers.unix", {}, {}, }, },
182 {"tel:+1-816-555-1212",
183 {"tel", {}, {}, {}, {}, "+1-816-555-1212", {}, {}, }, },
185 {"telnet://192.0.2.16:80/",
186 {"telnet", "192.0.2.16:80", {}, "192.0.2.16", "80", "/", {}, {}, }, },
188 {"urn:example:animal:ferret:nose",
189 {"urn", {}, {}, {}, {}, "example:animal:ferret:nose", {}, {}, }, },
191 {"urn:oasis:names:specification:docbook:dtd:xml:4.1.2",
192 {"urn", {}, {}, {}, {}, "oasis:names:specification:docbook:dtd:xml:4.1.2", {}, {}, }, },
198 for (auto&& test
: tests
) {
199 uri::generic u
{test
.uri
};
200 if (test
.parts
!= u
.parts()) {
201 std::cerr
<< test
.uri
<< " failed to check\n";
203 std::cout
<< "URL:\n";
205 std::cout
<< "scheme() == " << *u
.scheme() << '\n';
207 std::cout
<< "authority() == " << *u
.authority() << '\n';
209 std::cout
<< "userinfo() == " << *u
.userinfo() << '\n';
211 std::cout
<< "host() == " << *u
.host() << '\n';
213 std::cout
<< "port() == " << *u
.port() << '\n';
215 std::cout
<< "path() == " << *u
.path() << '\n';
217 std::cout
<< "query() == " << *u
.query() << '\n';
219 std::cout
<< "fragment() == " << *u
.fragment() << '\n';
221 std::cout
<< "\ntest:\n";
223 if (test
.parts
.scheme
)
224 std::cout
<< "scheme == " << *test
.parts
.scheme
<< '\n';
225 if (test
.parts
.authority
)
226 std::cout
<< "authority == " << *test
.parts
.authority
<< '\n';
227 if (test
.parts
.userinfo
)
228 std::cout
<< "userinfo == " << *test
.parts
.userinfo
<< '\n';
230 std::cout
<< "host == " << *test
.parts
.host
<< '\n';
232 std::cout
<< "port == " << *test
.parts
.port
<< '\n';
234 std::cout
<< "path == " << *test
.parts
.path
<< '\n';
235 if (test
.parts
.query
)
236 std::cout
<< "query == " << *test
.parts
.query
<< '\n';
237 if (test
.parts
.fragment
)
238 std::cout
<< "fragment == " << *test
.parts
.fragment
<< '\n';
251 // Verify a bunch of bad URIs all throw exceptions.
254 char const* bad_uris
[]{
265 "http://foo.bar?q=Spaces should be encoded",
272 "http:// shouldfail.com",
274 "http://foo.bar/foo(bar)baz quux",
275 "http://-error-.invalid/",
279 "http://.www.foo.bar/",
280 "http://.www.foo.bar./",
283 // I have to confess, I don't know what's wrong with these:
285 // "ftps://foo.bar/",
286 // "http://a.b--c.de/",
290 // "http://10.1.1.0",
291 // "http://10.1.1.255",
292 // "http://224.1.1.1",
293 // "http://123.123.123",
294 // "http://3628126748",
295 // "http://10.1.1.1",
296 // "http://10.1.1.254",
297 // "http://www.foo.bar./",
299 for (auto uri
: bad_uris
) {
302 LOG(ERROR
) << "should not parse \"" << uri
<< "\" as \"" << u
<< "\"\n";
305 catch (uri::syntax_error
const& e
) {
308 catch (std::exception
const& e
) {
309 LOG(FATAL
) << "unexpected exception " << e
.what() << '\n';
316 int test_resolution()
320 char const* resolved
;
324 test_case tests
[] = {
326 // 5.4.1. Normal Examples
329 {"g", "http://a/b/c/g"},
330 {"./g", "http://a/b/c/g"},
331 {"g/", "http://a/b/c/g/"},
332 {"/g", "http://a/g"},
334 {"?y", "http://a/b/c/d;p?y"},
335 {"g?y", "http://a/b/c/g?y"},
336 {"#s", "http://a/b/c/d;p?q#s"},
337 {"g#s", "http://a/b/c/g#s"},
338 {"g?y#s", "http://a/b/c/g?y#s"},
339 {";x", "http://a/b/c/;x"},
340 {"g;x", "http://a/b/c/g;x"},
341 {"g;x?y#s", "http://a/b/c/g;x?y#s"},
342 {"", "http://a/b/c/d;p?q"},
343 {".", "http://a/b/c/"},
344 {"./", "http://a/b/c/"},
345 {"..", "http://a/b/"},
346 {"../", "http://a/b/"},
347 {"../g", "http://a/b/g"},
348 {"../..", "http://a/"},
349 {"../../", "http://a/"},
350 {"../../g", "http://a/g"},
352 // 5.4.2. Abnormal Examples
354 {"../../../g", "http://a/g"},
355 {"../../../../g", "http://a/g"},
357 {"/./g", "http://a/g"},
358 {"/../g", "http://a/g"},
359 {"g.", "http://a/b/c/g."},
360 {".g", "http://a/b/c/.g"},
361 {"g..", "http://a/b/c/g.."},
362 {"..g", "http://a/b/c/..g"},
364 {"g?y/./x", "http://a/b/c/g?y/./x"},
365 {"g?y/../x", "http://a/b/c/g?y/../x"},
366 {"g#s/./x", "http://a/b/c/g#s/./x"},
367 {"g#s/../x", "http://a/b/c/g#s/../x"},
369 {"http:g", "http:g"}, // for strict parsers
373 // 5.4. Reference Resolution Examples
375 uri::absolute
base("http://a/b/c/d;p?q");
379 for (auto&& test
: tests
) {
380 uri::reference
ref(test
.ref
);
381 auto resolved
= uri::resolve_ref(base
, ref
);
382 auto resolved_str
= uri::to_string(resolved
);
383 if (resolved_str
!= test
.resolved
) {
384 LOG(ERROR
) << "##### Failure #####";
385 LOG(ERROR
) << "for input == " << test
.ref
<< '\n';
386 LOG(ERROR
) << "ref == " << ref
;
387 LOG(ERROR
) << "resolved == " << resolved
;
388 LOG(ERROR
) << "should match == " << test
.resolved
;
396 int main(int argc
, char* argv
[])
400 failures
+= test_good();
401 failures
+= test_bad();
402 failures
+= test_resolution();
405 // the two explicit tests from RFC 3986:
406 uri::components parts
;
407 parts
.path
= "/a/b/c/./../../g";
408 CHECK_EQ(uri::normalize(parts
), "/a/g");
409 parts
.path
= "mid/content=5/../6";
410 CHECK_EQ(uri::normalize(parts
), "mid/6");
413 // Parse command line args as URIs.
415 for (auto i
= 1; i
< argc
; ++i
) {
416 uri::reference u
{argv
[i
]};
418 std::cout
<< "scheme == " << (u
.scheme() ? *u
.scheme() : "{}") << '\n'
419 << "auth == " << (u
.authority() ? *u
.authority() : "{}") << '\n'
420 << "user == " << (u
.userinfo() ? *u
.userinfo() : "{}") << '\n'
421 << "host == " << (u
.host() ? *u
.host() : "{}") << '\n'
422 << "port == " << (u
.port() ? *u
.port() : "{}") << '\n'
423 << "path == " << (u
.path() ? *u
.path() : "{}") << '\n'
424 << "query == " << (u
.query() ? *u
.query() : "{}") << '\n'
425 << "frag == " << (u
.fragment() ? *u
.fragment() : "{}") << '\n';
427 std::cout
<< "string == " << uri::to_string(u
) << '\n';
429 std::cout
<< "norm == " << uri::normalize(u
.parts()) << '\n';
433 LOG(FATAL
) << "one or more tests failed";