description("Canonicalization of IPv6 addresses."); cases = [ ["[", ""], ["[:", ""], ["]", ""], [":]", ""], ["[]", ""], ["[:]", ""], // Regular IP address is invalid without bounding '[' and ']'. ["2001:db8::1", ""], ["[2001:db8::1", ""], ["2001:db8::1]", ""], // Regular IP addresses. ["[::]", "[::]"], ["[::1]", "[::1]"], ["[1::]", "[1::]"], ["[::192.168.0.1]", "[::c0a8:1]"], ["[::ffff:192.168.0.1]", "[::ffff:c0a8:1]"], // Leading zeros should be stripped. ["[000:01:02:003:004:5:6:007]", "[0:1:2:3:4:5:6:7]"], // Upper case letters should be lowercased. ["[A:b:c:DE:fF:0:1:aC]", "[a:b:c:de:ff:0:1:ac]"], // The same address can be written with different contractions, but should // get canonicalized to the same thing. ["[1:0:0:2::3:0]", "[1::2:0:0:3:0]"], ["[1::2:0:0:3:0]", "[1::2:0:0:3:0]"], // IPv4 addresses // Only mapped and compat addresses can have IPv4 syntax embedded. ["[::eeee:192.168.0.1]", ""], ["[2001::192.168.0.1]", ""], ["[1:2:192.168.0.1:5:6]", ""], // IPv4 with last component missing. ["[::ffff:192.1.2]", "[::ffff:c001:2]"], // IPv4 using hex. // FIXME: Should this format be disallowed? ["[::ffff:0xC0.0Xa8.0x0.0x1]", "[::ffff:c0a8:1]"], // There may be zeros surrounding the "::" contraction. ["[0:0::0:0:8]", "[::8]"], ["[2001:db8::1]", "[2001:db8::1]"], // Can only have one "::" contraction in an IPv6 string literal. ["[2001::db8::1]", ""], // No more than 2 consecutive ':'s. ["[2001:db8:::1]", ""], ["[:::]", ""], // Non-IP addresses due to invalid characters. ["[2001::.com]", ""], // Too many components means not an IP address. Similarly with too few if using IPv4 compat or mapped addresses. ["[::192.168.0.0.1]", ""], ["[::ffff:192.168.0.0.1]", ""], ["[1:2:3:4:5:6:7:8:9]", ""], // Too many bits (even though 8 comonents, the last one holds 32 bits). ["[0:0:0:0:0:0:0:192.168.0.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]", ""], // The contraction is for 16 bits of zero. ["[1:2:3:4:5:6::8]", "[1:2:3:4:5:6:0:8]"], // Cannot have a trailing colon. ["[1:2:3:4:5:6:7:8:]", ""], ["[1:2:3:4:5:6:192.168.0.1:]", ""], // Cannot have negative numbers. ["[-1:2:3:4:5:6:7:8]", ""], // Scope ID -- the URL may contain an optional ["%" <scope_id>] section. // The scope_id should be included in the canonicalized URL, and is an // unsigned decimal number. // Don't allow scope-id ["[1::%1]", ""], ["[1::%eth0]", ""], ["[1::%]", ""], ["[%]", ""], ["[::%:]", ""], // Don't allow leading or trailing colons. ["[:0:0::0:0:8]", ""], ["[0:0::0:0:8:]", ""], ["[:0:0::0:0:8:]", ""], // Two dots in a row means not an IP address. ["[::192.168..1]", ""], // Spaces should be rejected. ["[::1 hello]", ""] ]; // We test the empty string individually. shouldBe("canonicalize('http:///')", "'http:'"); for (var i = 0; i < cases.length; ++i) { test_vector = cases[i][0]; expected_result = cases[i][1]; if (expected_result === "") { // We use "" to represent that the test vector ought not to parse. // It appears that we're supposed to apply a default canonicalization, // and the escape function escapes too much! expected_result = test_vector.toLowerCase(); ['%', ' '].forEach(function(c){ expected_result = expected_result.replace(c, escape(c)); }) } shouldBe("canonicalize('http://" + test_vector + "/')", "'http://" + expected_result + "/'"); } var successfullyParsed = true;