Index: src/url_canon_unittest.cc |
=================================================================== |
--- src/url_canon_unittest.cc (revision 106) |
+++ src/url_canon_unittest.cc (working copy) |
@@ -48,6 +48,7 @@ |
using url_test_utils::WStringToUTF16; |
using url_test_utils::ConvertUTF8ToUTF16; |
using url_test_utils::ConvertUTF16ToUTF8; |
+using url_canon::CanonHostInfo; |
namespace { |
@@ -69,6 +70,19 @@ |
bool expected_success; |
}; |
+// Test cases for CanonicalizeIPAddress(). The inputs are identical to |
+// DualComponentCase, but the output has extra CanonHostInfo fields. |
+struct IPAddressCase { |
+ const char* input8; |
+ const wchar_t* input16; |
+ const char* expected; |
+ url_parse::Component expected_component; |
+ |
+ // CanonHostInfo fields, for verbose output. |
+ CanonHostInfo::Family expected_family; |
+ int expected_num_ipv4_components; |
+}; |
+ |
struct ReplaceCase { |
const char* base; |
const char* scheme; |
@@ -327,62 +341,66 @@ |
} |
TEST(URLCanonTest, Host) { |
- DualComponentCase host_cases[] = { |
+ IPAddressCase host_cases[] = { |
// Basic canonicalization, uppercase should be converted to lowercase. |
- {"GoOgLe.CoM", L"GoOgLe.CoM", "google.com", url_parse::Component(0, 10), true}, |
+ {"GoOgLe.CoM", L"GoOgLe.CoM", "google.com", url_parse::Component(0, 10), CanonHostInfo::NEUTRAL, -1}, |
// Spaces and some other characters should be escaped. |
- {"Goo%20 goo%7C|.com", L"Goo%20 goo%7C|.com", "goo%20%20goo%7C%7C.com", url_parse::Component(0, 22), true}, |
+ {"Goo%20 goo%7C|.com", L"Goo%20 goo%7C|.com", "goo%20%20goo%7C%7C.com", url_parse::Component(0, 22), CanonHostInfo::NEUTRAL, -1}, |
// Exciting different types of spaces! |
- {NULL, L"GOO\x00a0\x3000goo.com", "goo%20%20goo.com", url_parse::Component(0, 16), true}, |
+ {NULL, L"GOO\x00a0\x3000goo.com", "goo%20%20goo.com", url_parse::Component(0, 16), CanonHostInfo::NEUTRAL, -1}, |
// Other types of space (no-break, zero-width, zero-width-no-break) are |
// name-prepped away to nothing. |
- {NULL, L"GOO\x200b\x2060\xfeffgoo.com", "googoo.com", url_parse::Component(0, 10), true}, |
+ {NULL, L"GOO\x200b\x2060\xfeffgoo.com", "googoo.com", url_parse::Component(0, 10), CanonHostInfo::NEUTRAL, -1}, |
// Ideographic full stop (full-width period for Chinese, etc.) should be |
// treated as a dot. |
- {NULL, L"www.foo\x3002"L"bar.com", "www.foo.bar.com", url_parse::Component(0, 15), true}, |
+ {NULL, L"www.foo\x3002"L"bar.com", "www.foo.bar.com", url_parse::Component(0, 15), CanonHostInfo::NEUTRAL, -1}, |
// Invalid unicode characters should fail... |
// ...In wide input, ICU will barf and we'll end up with the input as |
// escaped UTF-8 (the invalid character should be replaced with the |
// replacement character). |
- {"\xef\xb7\x90zyx.com", L"\xfdd0zyx.com", "%EF%BF%BDzyx.com", url_parse::Component(0, 16), false}, |
+ {"\xef\xb7\x90zyx.com", L"\xfdd0zyx.com", "%EF%BF%BDzyx.com", url_parse::Component(0, 16), CanonHostInfo::BROKEN, -1}, |
// ...This is the same as previous but with with escaped. |
- {"%ef%b7%90zyx.com", L"%ef%b7%90zyx.com", "%EF%BF%BDzyx.com", url_parse::Component(0, 16), false}, |
+ {"%ef%b7%90zyx.com", L"%ef%b7%90zyx.com", "%EF%BF%BDzyx.com", url_parse::Component(0, 16), CanonHostInfo::BROKEN, -1}, |
// Test name prepping, fullwidth input should be converted to ASCII and NOT |
// IDN-ized. This is "Go" in fullwidth UTF-8/UTF-16. |
- {"\xef\xbc\xa7\xef\xbd\x8f.com", L"\xff27\xff4f.com", "go.com", url_parse::Component(0, 6), true}, |
+ {"\xef\xbc\xa7\xef\xbd\x8f.com", L"\xff27\xff4f.com", "go.com", url_parse::Component(0, 6), CanonHostInfo::NEUTRAL, -1}, |
// Test that fullwidth escaped values are properly name-prepped, |
// then converted or rejected. |
// ...%41 in fullwidth = 'A' (also as escaped UTF-8 input) |
- {"\xef\xbc\x85\xef\xbc\x94\xef\xbc\x91.com", L"\xff05\xff14\xff11.com", "a.com", url_parse::Component(0, 5), true}, |
- {"%ef%bc%85%ef%bc%94%ef%bc%91.com", L"%ef%bc%85%ef%bc%94%ef%bc%91.com", "a.com", url_parse::Component(0, 5), true}, |
+ {"\xef\xbc\x85\xef\xbc\x94\xef\xbc\x91.com", L"\xff05\xff14\xff11.com", "a.com", url_parse::Component(0, 5), CanonHostInfo::NEUTRAL, -1}, |
+ {"%ef%bc%85%ef%bc%94%ef%bc%91.com", L"%ef%bc%85%ef%bc%94%ef%bc%91.com", "a.com", url_parse::Component(0, 5), CanonHostInfo::NEUTRAL, -1}, |
// ...%00 in fullwidth should fail (also as escaped UTF-8 input) |
- {"\xef\xbc\x85\xef\xbc\x90\xef\xbc\x90.com", L"\xff05\xff10\xff10.com", "%00.com", url_parse::Component(0, 7), false}, |
- {"%ef%bc%85%ef%bc%90%ef%bc%90.com", L"%ef%bc%85%ef%bc%90%ef%bc%90.com", "%00.com", url_parse::Component(0, 7), false}, |
+ {"\xef\xbc\x85\xef\xbc\x90\xef\xbc\x90.com", L"\xff05\xff10\xff10.com", "%00.com", url_parse::Component(0, 7), CanonHostInfo::BROKEN, -1}, |
+ {"%ef%bc%85%ef%bc%90%ef%bc%90.com", L"%ef%bc%85%ef%bc%90%ef%bc%90.com", "%00.com", url_parse::Component(0, 7), CanonHostInfo::BROKEN, -1}, |
// Basic IDN support, UTF-8 and UTF-16 input should be converted to IDN |
- {"\xe4\xbd\xa0\xe5\xa5\xbd\xe4\xbd\xa0\xe5\xa5\xbd", L"\x4f60\x597d\x4f60\x597d", "xn--6qqa088eba", url_parse::Component(0, 14), true}, |
+ {"\xe4\xbd\xa0\xe5\xa5\xbd\xe4\xbd\xa0\xe5\xa5\xbd", L"\x4f60\x597d\x4f60\x597d", "xn--6qqa088eba", url_parse::Component(0, 14), CanonHostInfo::NEUTRAL, -1}, |
// Mixed UTF-8 and escaped UTF-8 (narrow case) and UTF-16 and escaped |
// UTF-8 (wide case). The output should be equivalent to the true wide |
// character input above). |
- {"%E4%BD%A0%E5%A5%BD\xe4\xbd\xa0\xe5\xa5\xbd", L"%E4%BD%A0%E5%A5%BD\x4f60\x597d", "xn--6qqa088eba", url_parse::Component(0, 14), true}, |
+ {"%E4%BD%A0%E5%A5%BD\xe4\xbd\xa0\xe5\xa5\xbd", L"%E4%BD%A0%E5%A5%BD\x4f60\x597d", "xn--6qqa088eba", url_parse::Component(0, 14), CanonHostInfo::NEUTRAL, -1}, |
// Invalid escaped characters should fail and the percents should be |
// escaped. |
- {"%zz%66%a", L"%zz%66%a", "%25zzf%25a", url_parse::Component(0, 10), false}, |
+ {"%zz%66%a", L"%zz%66%a", "%25zzf%25a", url_parse::Component(0, 10), CanonHostInfo::BROKEN, -1}, |
// If we get an invalid character that has been escaped. |
- {"%25", L"%25", "%25", url_parse::Component(0, 3), false}, |
- {"hello%00", L"hello%00", "hello%00", url_parse::Component(0, 8), false}, |
+ {"%25", L"%25", "%25", url_parse::Component(0, 3), CanonHostInfo::BROKEN, -1}, |
+ {"hello%00", L"hello%00", "hello%00", url_parse::Component(0, 8), CanonHostInfo::BROKEN, -1}, |
// Escaped numbers should be treated like IP addresses if they are. |
- {"%30%78%63%30%2e%30%32%35%30.01", L"%30%78%63%30%2e%30%32%35%30.01", "192.168.0.1", url_parse::Component(0, 11), true}, |
- {"%30%78%63%30%2e%30%32%35%30.01%2e", L"%30%78%63%30%2e%30%32%35%30.01%2e", "192.168.0.1", url_parse::Component(0, 11), true}, |
+ {"%30%78%63%30%2e%30%32%35%30.01", L"%30%78%63%30%2e%30%32%35%30.01", "192.168.0.1", url_parse::Component(0, 11), CanonHostInfo::IPV4, 3}, |
+ {"%30%78%63%30%2e%30%32%35%30.01%2e", L"%30%78%63%30%2e%30%32%35%30.01%2e", "192.168.0.1", url_parse::Component(0, 11), CanonHostInfo::IPV4, 3}, |
// Invalid escaping should trigger the regular host error handling. |
- {"%3g%78%63%30%2e%30%32%35%30%2E.01", L"%3g%78%63%30%2e%30%32%35%30%2E.01", "%253gxc0.0250..01", url_parse::Component(0, 17), false}, |
+ {"%3g%78%63%30%2e%30%32%35%30%2E.01", L"%3g%78%63%30%2e%30%32%35%30%2E.01", "%253gxc0.0250..01", url_parse::Component(0, 17), CanonHostInfo::BROKEN, -1}, |
// Something that isn't exactly an IP should get treated as a host and |
// spaces escaped. |
- {"192.168.0.1 hello", L"192.168.0.1 hello", "192.168.0.1%20hello", url_parse::Component(0, 19), true}, |
+ {"192.168.0.1 hello", L"192.168.0.1 hello", "192.168.0.1%20hello", url_parse::Component(0, 19), CanonHostInfo::NEUTRAL, -1}, |
// Fullwidth and escaped UTF-8 fullwidth should still be treated as IP. |
// These are "0Xc0.0250.01" in fullwidth. |
- {"\xef\xbc\x90%Ef%bc\xb8%ef%Bd%83\xef\xbc\x90%EF%BC%8E\xef\xbc\x90\xef\xbc\x92\xef\xbc\x95\xef\xbc\x90\xef\xbc%8E\xef\xbc\x90\xef\xbc\x91", L"\xff10\xff38\xff43\xff10\xff0e\xff10\xff12\xff15\xff10\xff0e\xff10\xff11", "192.168.0.1", url_parse::Component(0, 11), true}, |
+ {"\xef\xbc\x90%Ef%bc\xb8%ef%Bd%83\xef\xbc\x90%EF%BC%8E\xef\xbc\x90\xef\xbc\x92\xef\xbc\x95\xef\xbc\x90\xef\xbc%8E\xef\xbc\x90\xef\xbc\x91", L"\xff10\xff38\xff43\xff10\xff0e\xff10\xff12\xff15\xff10\xff0e\xff10\xff11", "192.168.0.1", url_parse::Component(0, 11), CanonHostInfo::IPV4, 3}, |
+ // Broken IP addresses get marked as such. |
+ {"192.168.0.257", L"192.168.0.257", "192.168.0.257", url_parse::Component(0, 13), CanonHostInfo::BROKEN, -1}, |
+ {"[google.com]", L"[google.com]", "[google.com]", url_parse::Component(0, 12), CanonHostInfo::BROKEN, -1}, |
}; |
+ // CanonicalizeHost() non-verbose. |
std::string out_str; |
for (size_t i = 0; i < arraysize(host_cases); i++) { |
// Narrow version. |
@@ -398,7 +416,8 @@ |
&output, &out_comp); |
output.Complete(); |
- EXPECT_EQ(host_cases[i].expected_success, success); |
+ EXPECT_EQ(host_cases[i].expected_family != CanonHostInfo::BROKEN, |
+ success); |
EXPECT_EQ(std::string(host_cases[i].expected), out_str); |
EXPECT_EQ(host_cases[i].expected_component.begin, out_comp.begin); |
EXPECT_EQ(host_cases[i].expected_component.len, out_comp.len); |
@@ -418,62 +437,139 @@ |
&output, &out_comp); |
output.Complete(); |
- EXPECT_EQ(host_cases[i].expected_success, success); |
+ EXPECT_EQ(host_cases[i].expected_family != CanonHostInfo::BROKEN, |
+ success); |
EXPECT_EQ(std::string(host_cases[i].expected), out_str); |
EXPECT_EQ(host_cases[i].expected_component.begin, out_comp.begin); |
EXPECT_EQ(host_cases[i].expected_component.len, out_comp.len); |
} |
} |
+ |
+ // CanonicalizeHostVerbose() |
+ for (size_t i = 0; i < arraysize(host_cases); i++) { |
+ // Narrow version. |
+ if (host_cases[i].input8) { |
+ int host_len = static_cast<int>(strlen(host_cases[i].input8)); |
+ url_parse::Component in_comp(0, host_len); |
+ |
+ out_str.clear(); |
+ url_canon::StdStringCanonOutput output(&out_str); |
+ CanonHostInfo host_info; |
+ |
+ url_canon::CanonicalizeHostVerbose(host_cases[i].input8, in_comp, |
+ &output, &host_info); |
+ output.Complete(); |
+ |
+ EXPECT_EQ(host_cases[i].expected_family, host_info.family); |
+ EXPECT_EQ(std::string(host_cases[i].expected), out_str); |
+ EXPECT_EQ(host_cases[i].expected_component.begin, |
+ host_info.out_host.begin); |
+ EXPECT_EQ(host_cases[i].expected_component.len, host_info.out_host.len); |
+ if (host_cases[i].expected_family == CanonHostInfo::IPV4) { |
+ EXPECT_EQ(host_cases[i].expected_num_ipv4_components, |
+ host_info.num_ipv4_components); |
+ } |
+ } |
+ |
+ // Wide version. |
+ if (host_cases[i].input16) { |
+ string16 input16(WStringToUTF16(host_cases[i].input16)); |
+ int host_len = static_cast<int>(input16.length()); |
+ url_parse::Component in_comp(0, host_len); |
+ |
+ out_str.clear(); |
+ url_canon::StdStringCanonOutput output(&out_str); |
+ CanonHostInfo host_info; |
+ |
+ url_canon::CanonicalizeHostVerbose(input16.c_str(), in_comp, |
+ &output, &host_info); |
+ output.Complete(); |
+ |
+ EXPECT_EQ(host_cases[i].expected_family, host_info.family); |
+ EXPECT_EQ(std::string(host_cases[i].expected), out_str); |
+ EXPECT_EQ(host_cases[i].expected_component.begin, |
+ host_info.out_host.begin); |
+ EXPECT_EQ(host_cases[i].expected_component.len, host_info.out_host.len); |
+ if (host_cases[i].expected_family == CanonHostInfo::IPV4) { |
+ EXPECT_EQ(host_cases[i].expected_num_ipv4_components, |
+ host_info.num_ipv4_components); |
+ } |
+ } |
+ } |
} |
TEST(URLCanonTest, IPv4) { |
- DualComponentCase cases[] = { |
+ IPAddressCase cases[] = { |
// Empty is not an IP address. |
- {"", L"", "", url_parse::Component(), false}, |
- {".", L".", "", url_parse::Component(), false}, |
+ {"", L"", "", url_parse::Component(), CanonHostInfo::NEUTRAL, -1}, |
+ {".", L".", "", url_parse::Component(), CanonHostInfo::NEUTRAL, -1}, |
// Regular IP addresses in different bases. |
- {"192.168.0.1", L"192.168.0.1", "192.168.0.1", url_parse::Component(0, 11), true}, |
- {"0300.0250.00.01", L"0300.0250.00.01", "192.168.0.1", url_parse::Component(0, 11), true}, |
- {"0xC0.0Xa8.0x0.0x1", L"0xC0.0Xa8.0x0.0x1", "192.168.0.1", url_parse::Component(0, 11), true}, |
+ {"192.168.0.1", L"192.168.0.1", "192.168.0.1", url_parse::Component(0, 11), CanonHostInfo::IPV4, 4}, |
+ {"0300.0250.00.01", L"0300.0250.00.01", "192.168.0.1", url_parse::Component(0, 11), CanonHostInfo::IPV4, 4}, |
+ {"0xC0.0Xa8.0x0.0x1", L"0xC0.0Xa8.0x0.0x1", "192.168.0.1", url_parse::Component(0, 11), CanonHostInfo::IPV4, 4}, |
// Non-IP addresses due to invalid characters. |
- {"192.168.9.com", L"192.168.9.com", "", url_parse::Component(), false}, |
+ {"192.168.9.com", L"192.168.9.com", "", url_parse::Component(), CanonHostInfo::NEUTRAL, -1}, |
// Invalid characters for the base should be rejected. |
- {"19a.168.0.1", L"19a.168.0.1", "", url_parse::Component(), false}, |
- {"0308.0250.00.01", L"0308.0250.00.01", "", url_parse::Component(), false}, |
- {"0xCG.0xA8.0x0.0x1", L"0xCG.0xA8.0x0.0x1", "", url_parse::Component(), false}, |
+ {"19a.168.0.1", L"19a.168.0.1", "", url_parse::Component(), CanonHostInfo::NEUTRAL, -1}, |
+ {"0308.0250.00.01", L"0308.0250.00.01", "", url_parse::Component(), CanonHostInfo::NEUTRAL, -1}, |
+ {"0xCG.0xA8.0x0.0x1", L"0xCG.0xA8.0x0.0x1", "", url_parse::Component(), CanonHostInfo::NEUTRAL, -1}, |
// If there are not enough components, the last one should fill them out. |
- {"192", L"192", "0.0.0.192", url_parse::Component(0, 9), true}, |
- {"0xC0a80001", L"0xC0a80001", "192.168.0.1", url_parse::Component(0, 11), true}, |
- {"030052000001", L"030052000001", "192.168.0.1", url_parse::Component(0, 11), true}, |
- {"000030052000001", L"000030052000001", "192.168.0.1", url_parse::Component(0, 11), true}, |
- {"192.168", L"192.168", "192.0.0.168", url_parse::Component(0, 11), true}, |
- {"192.0x00A80001", L"192.0x000A80001", "192.168.0.1", url_parse::Component(0, 11), true}, |
- {"0xc0.052000001", L"0xc0.052000001", "192.168.0.1", url_parse::Component(0, 11), true}, |
- {"192.168.1", L"192.168.1", "192.168.0.1", url_parse::Component(0, 11), true}, |
+ {"192", L"192", "0.0.0.192", url_parse::Component(0, 9), CanonHostInfo::IPV4, 1}, |
+ {"0xC0a80001", L"0xC0a80001", "192.168.0.1", url_parse::Component(0, 11), CanonHostInfo::IPV4, 1}, |
+ {"030052000001", L"030052000001", "192.168.0.1", url_parse::Component(0, 11), CanonHostInfo::IPV4, 1}, |
+ {"000030052000001", L"000030052000001", "192.168.0.1", url_parse::Component(0, 11), CanonHostInfo::IPV4, 1}, |
+ {"192.168", L"192.168", "192.0.0.168", url_parse::Component(0, 11), CanonHostInfo::IPV4, 2}, |
+ {"192.0x00A80001", L"192.0x000A80001", "192.168.0.1", url_parse::Component(0, 11), CanonHostInfo::IPV4, 2}, |
+ {"0xc0.052000001", L"0xc0.052000001", "192.168.0.1", url_parse::Component(0, 11), CanonHostInfo::IPV4, 2}, |
+ {"192.168.1", L"192.168.1", "192.168.0.1", url_parse::Component(0, 11), CanonHostInfo::IPV4, 3}, |
// Too many components means not an IP address. |
- {"192.168.0.0.1", L"192.168.0.0.1", "", url_parse::Component(), false}, |
+ {"192.168.0.0.1", L"192.168.0.0.1", "", url_parse::Component(), CanonHostInfo::NEUTRAL, -1}, |
// We allow a single trailing dot. |
- {"192.168.0.1.", L"192.168.0.1.", "192.168.0.1", url_parse::Component(0, 11), true}, |
- {"192.168.0.1. hello", L"192.168.0.1. hello", "", url_parse::Component(), false}, |
- {"192.168.0.1..", L"192.168.0.1..", "", url_parse::Component(), false}, |
+ {"192.168.0.1.", L"192.168.0.1.", "192.168.0.1", url_parse::Component(0, 11), CanonHostInfo::IPV4, 4}, |
+ {"192.168.0.1. hello", L"192.168.0.1. hello", "", url_parse::Component(), CanonHostInfo::NEUTRAL, -1}, |
+ {"192.168.0.1..", L"192.168.0.1..", "", url_parse::Component(), CanonHostInfo::NEUTRAL, -1}, |
// Two dots in a row means not an IP address. |
- {"192.168..1", L"192.168..1", "", url_parse::Component(), false}, |
- // Any non-first components get truncated to one byte. |
- {"276.256.0xf1a2.077777", L"276.256.0xf1a2.077777", "20.0.162.255", url_parse::Component(0, 12), true}, |
- // The last component should get truncated to however much space is |
- // remaining. |
- {"192.168.0.257", L"192.168.0.257", "192.168.0.1", url_parse::Component(0, 11), true}, |
- {"192.168.0xa20001", L"192.168.0xa20001", "192.168.0.1", url_parse::Component(0, 11), true}, |
- {"192.015052000001", L"192.015052000001", "192.168.0.1", url_parse::Component(0, 11), true}, |
- {"0X12C0a80001", L"0X12C0a80001", "192.168.0.1", url_parse::Component(0, 11), true}, |
+ {"192.168..1", L"192.168..1", "", url_parse::Component(), CanonHostInfo::NEUTRAL, -1}, |
+ // Any numerical overflow should be marked as BROKEN. |
+ {"0x100.0", L"0x100.0", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"0x100.0.0", L"0x100.0.0", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"0x100.0.0.0", L"0x100.0.0.0", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"0.0x100.0.0", L"0.0x100.0.0", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"0.0.0x100.0", L"0.0.0x100.0", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"0.0.0.0x100", L"0.0.0.0x100", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"0.0.0x10000", L"0.0.0x10000", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"0.0x1000000", L"0.0x1000000", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"0x100000000", L"0x100000000", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ // Repeat the previous tests, minus 1, to verify boundaries. |
+ {"0xFF.0", L"0xFF.0", "255.0.0.0", url_parse::Component(0, 9), CanonHostInfo::IPV4, 2}, |
+ {"0xFF.0.0", L"0xFF.0.0", "255.0.0.0", url_parse::Component(0, 9), CanonHostInfo::IPV4, 3}, |
+ {"0xFF.0.0.0", L"0xFF.0.0.0", "255.0.0.0", url_parse::Component(0, 9), CanonHostInfo::IPV4, 4}, |
+ {"0.0xFF.0.0", L"0.0xFF.0.0", "0.255.0.0", url_parse::Component(0, 9), CanonHostInfo::IPV4, 4}, |
+ {"0.0.0xFF.0", L"0.0.0xFF.0", "0.0.255.0", url_parse::Component(0, 9), CanonHostInfo::IPV4, 4}, |
+ {"0.0.0.0xFF", L"0.0.0.0xFF", "0.0.0.255", url_parse::Component(0, 9), CanonHostInfo::IPV4, 4}, |
+ {"0.0.0xFFFF", L"0.0.0xFFFF", "0.0.255.255", url_parse::Component(0, 11), CanonHostInfo::IPV4, 3}, |
+ {"0.0xFFFFFF", L"0.0xFFFFFF", "0.255.255.255", url_parse::Component(0, 13), CanonHostInfo::IPV4, 2}, |
+ {"0xFFFFFFFF", L"0xFFFFFFFF", "255.255.255.255", url_parse::Component(0, 15), CanonHostInfo::IPV4, 1}, |
+ // Old trunctations tests. They're all "BROKEN" now. |
+ {"276.256.0xf1a2.077777", L"276.256.0xf1a2.077777", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"192.168.0.257", L"192.168.0.257", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"192.168.0xa20001", L"192.168.0xa20001", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"192.015052000001", L"192.015052000001", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"0X12C0a80001", L"0X12C0a80001", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"276.1.2", L"276.1.2", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
// Spaces should be rejected. |
- {"192.168.0.1 hello", L"192.168.0.1 hello", "", url_parse::Component(), false}, |
- // Truncation plus the last component missing. |
- {"276.1.2", L"276.1.2", "20.1.0.2", url_parse::Component(0, 8), true}, |
- // Very large numbers. We support up to 16 characters per component |
- // before rejecting. |
- {"0000000000000300.0xffffffffFFFFFFFF.3022415481470977", L"0000000000000300.0xffffffffFFFFFFFF.3022415481470977", "192.255.0.1", url_parse::Component(0, 11), true}, |
- {"000000000000000300.168.1", L"000000000000000300.168.1", "", url_parse::Component(), false}, |
+ {"192.168.0.1 hello", L"192.168.0.1 hello", "", url_parse::Component(), CanonHostInfo::NEUTRAL, -1}, |
+ // Very large numbers. |
+ {"0000000000000300.0x00000000000000fF.00000000000000001", L"0000000000000300.0x00000000000000fF.00000000000000001", "192.255.0.1", url_parse::Component(0, 11), CanonHostInfo::IPV4, 3}, |
+ {"0000000000000300.0xffffffffFFFFFFFF.3022415481470977", L"0000000000000300.0xffffffffFFFFFFFF.3022415481470977", "", url_parse::Component(0, 11), CanonHostInfo::BROKEN, -1}, |
+ // A number has no length limit, but long numbers can still overflow. |
+ {"00000000000000000001", L"00000000000000000001", "0.0.0.1", url_parse::Component(0, 7), CanonHostInfo::IPV4, 1}, |
+ {"0000000000000000100000000000000001", L"0000000000000000100000000000000001", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ // If a long component is non-numeric, it's a hostname, *not* a broken IP. |
+ {"0.0.0.000000000000000000z", L"0.0.0.000000000000000000z", "", url_parse::Component(), CanonHostInfo::NEUTRAL, -1}, |
+ {"0.0.0.100000000000000000z", L"0.0.0.100000000000000000z", "", url_parse::Component(), CanonHostInfo::NEUTRAL, -1}, |
+ // Truncation of all zeros should still result in 0. |
+ {"0.00.0x.0x0", L"0.00.0x.0x0", "0.0.0.0", url_parse::Component(0, 7), CanonHostInfo::IPV4, 4}, |
}; |
for (size_t i = 0; i < arraysize(cases); i++) { |
@@ -483,16 +579,18 @@ |
std::string out_str1; |
url_canon::StdStringCanonOutput output1(&out_str1); |
- url_parse::Component out_ip; |
- bool success = url_canon::CanonicalizeIPAddress(cases[i].input8, component, |
- &output1, &out_ip); |
+ url_canon::CanonHostInfo host_info; |
+ url_canon::CanonicalizeIPAddress(cases[i].input8, component, &output1, |
+ &host_info); |
output1.Complete(); |
- EXPECT_EQ(cases[i].expected_success, success); |
- if (success) { |
+ EXPECT_EQ(cases[i].expected_family, host_info.family); |
+ if (host_info.family == CanonHostInfo::IPV4) { |
EXPECT_STREQ(cases[i].expected, out_str1.c_str()); |
- EXPECT_EQ(cases[i].expected_component.begin, out_ip.begin); |
- EXPECT_EQ(cases[i].expected_component.len, out_ip.len); |
+ EXPECT_EQ(cases[i].expected_component.begin, host_info.out_host.begin); |
+ EXPECT_EQ(cases[i].expected_component.len, host_info.out_host.len); |
+ EXPECT_EQ(cases[i].expected_num_ipv4_components, |
+ host_info.num_ipv4_components); |
} |
// 16-bit version. |
@@ -501,99 +599,102 @@ |
std::string out_str2; |
url_canon::StdStringCanonOutput output2(&out_str2); |
- success = url_canon::CanonicalizeIPAddress(input16.c_str(), component, |
- &output2, &out_ip); |
+ url_canon::CanonicalizeIPAddress(input16.c_str(), component, &output2, |
+ &host_info); |
output2.Complete(); |
- EXPECT_EQ(cases[i].expected_success, success); |
- if (success) { |
- EXPECT_STREQ(cases[i].expected, out_str1.c_str()); |
- EXPECT_EQ(cases[i].expected_component.begin, out_ip.begin); |
- EXPECT_EQ(cases[i].expected_component.len, out_ip.len); |
+ EXPECT_EQ(cases[i].expected_family, host_info.family); |
+ if (host_info.family == CanonHostInfo::IPV4) { |
+ EXPECT_STREQ(cases[i].expected, out_str2.c_str()); |
+ EXPECT_EQ(cases[i].expected_component.begin, host_info.out_host.begin); |
+ EXPECT_EQ(cases[i].expected_component.len, host_info.out_host.len); |
+ EXPECT_EQ(cases[i].expected_num_ipv4_components, |
+ host_info.num_ipv4_components); |
} |
} |
} |
TEST(URLCanonTest, IPv6) { |
- DualComponentCase cases[] = { |
+ IPAddressCase cases[] = { |
// Empty is not an IP address. |
- {"", L"", "", url_parse::Component(), false}, |
- {":", L":", "", url_parse::Component(), false}, |
- {"[", L"[", "", url_parse::Component(), false}, |
- {"[:", L"[:", "", url_parse::Component(), false}, |
- {"]", L"]", "", url_parse::Component(), false}, |
- {":]", L":]", "", url_parse::Component(), false}, |
- {"[]", L"[]", "", url_parse::Component(), false}, |
- {"[:]", L"[:]", "", url_parse::Component(), false}, |
+ {"", L"", "", url_parse::Component(), CanonHostInfo::NEUTRAL, -1}, |
+ // Non-IPs with [:] characters are marked BROKEN. |
+ {":", L":", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"[", L"[", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"[:", L"[:", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"]", L"]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {":]", L":]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"[]", L"[]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"[:]", L"[:]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
// Regular IP address is invalid without bounding '[' and ']'. |
- {"2001:db8::1", L"2001:db8::1", "", url_parse::Component(), false}, |
- {"[2001:db8::1", L"[2001:db8::1", "", url_parse::Component(), false}, |
- {"2001:db8::1]", L"2001:db8::1]", "", url_parse::Component(), false}, |
+ {"2001:db8::1", L"2001:db8::1", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"[2001:db8::1", L"[2001:db8::1", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"2001:db8::1]", L"2001:db8::1]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
// Regular IP addresses. |
- {"[::]", L"[::]", "[::]", url_parse::Component(0,4), true}, |
- {"[::1]", L"[::1]", "[::1]", url_parse::Component(0,5), true}, |
- {"[1::]", L"[1::]", "[1::]", url_parse::Component(0,5), true}, |
- {"[::192.168.0.1]", L"[::192.168.0.1]", "[::c0a8:1]", url_parse::Component(0,10), true}, |
- {"[::ffff:192.168.0.1]", L"[::ffff:192.168.0.1]", "[::ffff:c0a8:1]", url_parse::Component(0,15), true}, |
+ {"[::]", L"[::]", "[::]", url_parse::Component(0,4), CanonHostInfo::IPV6, -1}, |
+ {"[::1]", L"[::1]", "[::1]", url_parse::Component(0,5), CanonHostInfo::IPV6, -1}, |
+ {"[1::]", L"[1::]", "[1::]", url_parse::Component(0,5), CanonHostInfo::IPV6, -1}, |
+ {"[::192.168.0.1]", L"[::192.168.0.1]", "[::c0a8:1]", url_parse::Component(0,10), CanonHostInfo::IPV6, -1}, |
+ {"[::ffff:192.168.0.1]", L"[::ffff:192.168.0.1]", "[::ffff:c0a8:1]", url_parse::Component(0,15), CanonHostInfo::IPV6, -1}, |
// Leading zeros should be stripped. |
- {"[000:01:02:003:004:5:6:007]", L"[000:01:02:003:004:5:6:007]", "[0:1:2:3:4:5:6:7]", url_parse::Component(0,17), true}, |
+ {"[000:01:02:003:004:5:6:007]", L"[000:01:02:003:004:5:6:007]", "[0:1:2:3:4:5:6:7]", url_parse::Component(0,17), CanonHostInfo::IPV6, -1}, |
// Upper case letters should be lowercased. |
- {"[A:b:c:DE:fF:0:1:aC]", L"[A:b:c:DE:fF:0:1:aC]", "[a:b:c:de:ff:0:1:ac]", url_parse::Component(0,20), true}, |
+ {"[A:b:c:DE:fF:0:1:aC]", L"[A:b:c:DE:fF:0:1:aC]", "[a:b:c:de:ff:0:1:ac]", url_parse::Component(0,20), CanonHostInfo::IPV6, -1}, |
// The same address can be written with different contractions, but should |
// get canonicalized to the same thing. |
- {"[1:0:0:2::3:0]", L"[1:0:0:2::3:0]", "[1::2:0:0:3:0]", url_parse::Component(0,14), true}, |
- {"[1::2:0:0:3:0]", L"[1::2:0:0:3:0]", "[1::2:0:0:3:0]", url_parse::Component(0,14), true}, |
+ {"[1:0:0:2::3:0]", L"[1:0:0:2::3:0]", "[1::2:0:0:3:0]", url_parse::Component(0,14), CanonHostInfo::IPV6, -1}, |
+ {"[1::2:0:0:3:0]", L"[1::2:0:0:3:0]", "[1::2:0:0:3:0]", url_parse::Component(0,14), CanonHostInfo::IPV6, -1}, |
// IPv4 addresses |
// Only mapped and compat addresses can have IPv4 syntax embedded. |
- {"[::eeee:192.168.0.1]", L"[::eeee:192.168.0.1]", "", url_parse::Component(), false}, |
- {"[2001::192.168.0.1]", L"[2001::92.168.0.1]", "", url_parse::Component(), false}, |
- {"[1:2:192.168.0.1:5:6]", L"[1:2:192.168.0.1:5:6]", "", url_parse::Component(), false}, |
+ {"[::eeee:192.168.0.1]", L"[::eeee:192.168.0.1]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"[2001::192.168.0.1]", L"[2001::192.168.0.1]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"[1:2:192.168.0.1:5:6]", L"[1:2:192.168.0.1:5:6]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
- // IPv4 with truncation and last component missing. |
- {"[::ffff:276.1.2]", L"[::ffff:276.1.2]", "[::ffff:1401:2]", url_parse::Component(0,15), true}, |
+ // IPv4 with last component missing. |
+ {"[::ffff:192.1.2]", L"[::ffff:192.1.2]", "[::ffff:c001:2]", url_parse::Component(0,15), CanonHostInfo::IPV6, -1}, |
// IPv4 using hex. |
// TODO(eroman): Should this format be disallowed? |
- {"[::ffff:0xC0.0Xa8.0x0.0x1]", L"[::ffff:0xC0.0Xa8.0x0.0x1]", "[::ffff:c0a8:1]", url_parse::Component(0,15), true}, |
+ {"[::ffff:0xC0.0Xa8.0x0.0x1]", L"[::ffff:0xC0.0Xa8.0x0.0x1]", "[::ffff:c0a8:1]", url_parse::Component(0,15), CanonHostInfo::IPV6, -1}, |
// There may be zeros surrounding the "::" contraction. |
- {"[0:0::0:0:8]", L"[0:0::0:0:8]", "[::8]", url_parse::Component(0,5), true}, |
+ {"[0:0::0:0:8]", L"[0:0::0:0:8]", "[::8]", url_parse::Component(0,5), CanonHostInfo::IPV6, -1}, |
- {"[2001:db8::1]", L"[2001:db8::1]", "[2001:db8::1]", url_parse::Component(0,13), true}, |
+ {"[2001:db8::1]", L"[2001:db8::1]", "[2001:db8::1]", url_parse::Component(0,13), CanonHostInfo::IPV6, -1}, |
// Can only have one "::" contraction in an IPv6 string literal. |
- {"[2001::db8::1]", L"[2001::db8::1]", "", url_parse::Component(), false}, |
+ {"[2001::db8::1]", L"[2001::db8::1]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
// No more than 2 consecutive ':'s. |
- {"[2001:db8:::1]", L"[2001:db8:::1]", "", url_parse::Component(), false}, |
- {"[:::]", L"[:::]", "", url_parse::Component(), false}, |
+ {"[2001:db8:::1]", L"[2001:db8:::1]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"[:::]", L"[:::]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
// Non-IP addresses due to invalid characters. |
- {"[2001::.com]", L"[2001::.com]", "", url_parse::Component(), false}, |
+ {"[2001::.com]", L"[2001::.com]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
// If there are not enough components, the last one should fill them out. |
// ... omitted at this time ... |
// Too many components means not an IP address. Similarly with too few if using IPv4 compat or mapped addresses. |
- {"[::192.168.0.0.1]", L"[::192.168.0.0.1]", "", url_parse::Component(), false}, |
- {"[::ffff:192.168.0.0.1]", L"[::ffff:192.168.0.0.1]", "", url_parse::Component(), false}, |
- {"[1:2:3:4:5:6:7:8:9]", L"[1:2:3:4:5:6:7:8:9]", "", url_parse::Component(), false}, |
+ {"[::192.168.0.0.1]", L"[::192.168.0.0.1]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"[::ffff:192.168.0.0.1]", L"[::ffff:192.168.0.0.1]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"[1:2:3:4:5:6:7:8:9]", L"[1:2:3:4:5:6:7:8:9]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
// Too many bits (even though 8 comonents, the last one holds 32 bits). |
- {"[0:0:0:0:0:0:0:192.168.0.1]", L"[0:0:0:0:0:0:0:192.168.0.1]", "", url_parse::Component(), false}, |
+ {"[0:0:0:0:0:0:0:192.168.0.1]", L"[0:0:0:0:0:0:0:192.168.0.1]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
// Too many bits specified -- the contraction would have to be zero-length |
// to not exceed 128 bits. |
- {"[1:2:3:4:5:6::192.168.0.1]", L"[1:2:3:4:5:6::192.168.0.1]", "", url_parse::Component(), false}, |
+ {"[1:2:3:4:5:6::192.168.0.1]", L"[1:2:3:4:5:6::192.168.0.1]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
// The contraction is for 16 bits of zero. |
- {"[1:2:3:4:5:6::8]", L"[1:2:3:4:5:6::8]", "[1:2:3:4:5:6:0:8]", url_parse::Component(0,17), true}, |
+ {"[1:2:3:4:5:6::8]", L"[1:2:3:4:5:6::8]", "[1:2:3:4:5:6:0:8]", url_parse::Component(0,17), CanonHostInfo::IPV6, -1}, |
// Cannot have a trailing colon. |
- {"[1:2:3:4:5:6:7:8:]", L"[1:2:3:4:5:6:7:8:]", "", url_parse::Component(), false}, |
- {"[1:2:3:4:5:6:192.168.0.1:]", L"[1:2:3:4:5:6:192.168.0.1:]", "", url_parse::Component(), false}, |
+ {"[1:2:3:4:5:6:7:8:]", L"[1:2:3:4:5:6:7:8:]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"[1:2:3:4:5:6:192.168.0.1:]", L"[1:2:3:4:5:6:192.168.0.1:]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
// Cannot have negative numbers. |
- {"[-1:2:3:4:5:6:7:8]", L"[-1:2:3:4:5:6:7:8]", "", url_parse::Component(), false}, |
+ {"[-1:2:3:4:5:6:7:8]", L"[-1:2:3:4:5:6:7:8]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
// Scope ID -- the URL may contain an optional ["%" <scope_id>] section. |
// The scope_id should be included in the canonicalized URL, and is an |
@@ -602,47 +703,45 @@ |
// Invalid because no ID was given after the percent. |
// Don't allow scope-id |
- {"[1::%1]", L"[1::%1]", "", url_parse::Component(), false}, |
- {"[1::%eth0]", L"[1::%eth0]", "", url_parse::Component(), false}, |
- {"[1::%]", L"[1::%]", "", url_parse::Component(), false}, |
- {"[%]", L"[%]", "", url_parse::Component(), false}, |
- {"[::%:]", L"[::%:]", "", url_parse::Component(), false}, |
+ {"[1::%1]", L"[1::%1]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"[1::%eth0]", L"[1::%eth0]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"[1::%]", L"[1::%]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"[%]", L"[%]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"[::%:]", L"[::%:]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
// Don't allow leading or trailing colons. |
- {"[:0:0::0:0:8]", L"[:0:0::0:0:8]", "", url_parse::Component(), false}, |
- {"[0:0::0:0:8:]", L"[0:0::0:0:8:]", "", url_parse::Component(), false}, |
- {"[:0:0::0:0:8:]", L"[:0:0::0:0:8:]", "", url_parse::Component(), false}, |
+ {"[:0:0::0:0:8]", L"[:0:0::0:0:8]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"[0:0::0:0:8:]", L"[0:0::0:0:8:]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
+ {"[:0:0::0:0:8:]", L"[:0:0::0:0:8:]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
// We allow a single trailing dot. |
// ... omitted at this time ... |
// Two dots in a row means not an IP address. |
- {"[::192.168..1]", L"[::192.168..1]", "", url_parse::Component(), false}, |
+ {"[::192.168..1]", L"[::192.168..1]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
// Any non-first components get truncated to one byte. |
// ... omitted at this time ... |
// Spaces should be rejected. |
- {"[::1 hello]", L"[::1 hello]", "", url_parse::Component(), false}, |
+ {"[::1 hello]", L"[::1 hello]", "", url_parse::Component(), CanonHostInfo::BROKEN, -1}, |
}; |
for (size_t i = 0; i < arraysize(cases); i++) { |
- // Print some context of what test we were on, to help debug failures. |
- SCOPED_TRACE(cases[i].input8); |
- |
// 8-bit version. |
url_parse::Component component(0, |
static_cast<int>(strlen(cases[i].input8))); |
std::string out_str1; |
url_canon::StdStringCanonOutput output1(&out_str1); |
- url_parse::Component out_ip; |
- bool success = url_canon::CanonicalizeIPAddress(cases[i].input8, component, |
- &output1, &out_ip); |
+ url_canon::CanonHostInfo host_info; |
+ url_canon::CanonicalizeIPAddress(cases[i].input8, component, &output1, |
+ &host_info); |
output1.Complete(); |
- EXPECT_EQ(cases[i].expected_success, success); |
- if (success) { |
+ EXPECT_EQ(cases[i].expected_family, host_info.family); |
+ if (host_info.family == CanonHostInfo::IPV6) { |
EXPECT_STREQ(cases[i].expected, out_str1.c_str()); |
- EXPECT_EQ(cases[i].expected_component.begin, out_ip.begin); |
- EXPECT_EQ(cases[i].expected_component.len, out_ip.len); |
+ EXPECT_EQ(cases[i].expected_component.begin, |
+ host_info.out_host.begin); |
+ EXPECT_EQ(cases[i].expected_component.len, host_info.out_host.len); |
} |
// 16-bit version. |
@@ -651,15 +750,15 @@ |
std::string out_str2; |
url_canon::StdStringCanonOutput output2(&out_str2); |
- success = url_canon::CanonicalizeIPAddress(input16.c_str(), component, |
- &output2, &out_ip); |
+ url_canon::CanonicalizeIPAddress(input16.c_str(), component, &output2, |
+ &host_info); |
output2.Complete(); |
- EXPECT_EQ(cases[i].expected_success, success); |
- if (success) { |
- EXPECT_STREQ(cases[i].expected, out_str1.c_str()); |
- EXPECT_EQ(cases[i].expected_component.begin, out_ip.begin); |
- EXPECT_EQ(cases[i].expected_component.len, out_ip.len); |
+ EXPECT_EQ(cases[i].expected_family, host_info.family); |
+ if (host_info.family == CanonHostInfo::IPV6) { |
+ EXPECT_STREQ(cases[i].expected, out_str2.c_str()); |
+ EXPECT_EQ(cases[i].expected_component.begin, host_info.out_host.begin); |
+ EXPECT_EQ(cases[i].expected_component.len, host_info.out_host.len); |
} |
} |
} |
@@ -1078,6 +1177,7 @@ |
bool expected_success; |
} cases[] = { |
{"http://www.google.com/foo?bar=baz#", "http://www.google.com/foo?bar=baz#", true}, |
+ {"http://[www.google.com]/", "http://[www.google.com]/", false}, |
{"ht\ttp:@www.google.com:80/;p?#", "ht%09tp://www.google.com:80/;p?#", false}, |
{"http:////////user:@google.com:99?foo", "http://user@google.com:99/?foo", true}, |
{"www.google.com", ":www.google.com/", true}, |