1 7 8 package java.net; 9 10 import java.io.IOException ; 11 import java.io.InvalidObjectException ; 12 import java.io.ObjectInputStream ; 13 import java.io.ObjectOutputStream ; 14 import java.io.Serializable ; 15 import java.nio.ByteBuffer ; 16 import java.nio.CharBuffer ; 17 import java.nio.charset.CharsetDecoder ; 18 import java.nio.charset.CharsetEncoder ; 19 import java.nio.charset.CoderResult ; 20 import java.nio.charset.CodingErrorAction ; 21 import java.nio.charset.CharacterCodingException ; 22 import sun.nio.cs.ThreadLocalCoders; 23 import sun.text.Normalizer; 24 25 import java.lang.Character ; import java.lang.NullPointerException ; 28 29 453 454 public final class URI 455 implements Comparable <URI >, Serializable 456 { 457 458 462 static final long serialVersionUID = -6052424284110960213L; 463 464 465 467 private transient String scheme; private transient String fragment; 470 471 private transient String authority; 474 private transient String userInfo; 476 private transient String host; private transient int port = -1; 479 private transient String path; private transient String query; 482 483 485 private volatile transient String schemeSpecificPart; 486 private volatile transient int hash; 488 private volatile transient String decodedUserInfo = null; 489 private volatile transient String decodedAuthority = null; 490 private volatile transient String decodedPath = null; 491 private volatile transient String decodedQuery = null; 492 private volatile transient String decodedFragment = null; 493 private volatile transient String decodedSchemeSpecificPart = null; 494 495 500 private volatile String string; 502 503 504 506 private URI() { } 508 577 public URI(String str) throws URISyntaxException { 578 new Parser(str).parse(false); 579 } 580 581 654 public URI(String scheme, 655 String userInfo, String host, int port, 656 String path, String query, String fragment) 657 throws URISyntaxException 658 { 659 String s = toString(scheme, null, 660 null, userInfo, host, port, 661 path, query, fragment); 662 checkPath(s, scheme, path); 663 new Parser(s).parse(true); 664 } 665 666 727 public URI(String scheme, 728 String authority, 729 String path, String query, String fragment) 730 throws URISyntaxException 731 { 732 String s = toString(scheme, null, 733 authority, null, null, -1, 734 path, query, fragment); 735 checkPath(s, scheme, path); 736 new Parser(s).parse(false); 737 } 738 739 761 public URI(String scheme, String host, String path, String fragment) 762 throws URISyntaxException 763 { 764 this(scheme, null, host, -1, path, null, fragment); 765 } 766 767 804 public URI(String scheme, String ssp, String fragment) 805 throws URISyntaxException 806 { 807 new Parser(toString(scheme, ssp, 808 null, null, null, -1, 809 null, null, fragment)) 810 .parse(false); 811 } 812 813 838 public static URI create(String str) { 839 try { 840 return new URI (str); 841 } catch (URISyntaxException x) { 842 IllegalArgumentException y = new IllegalArgumentException (); 843 y.initCause(x); 844 throw y; 845 } 846 } 847 848 849 851 898 public URI parseServerAuthority() 899 throws URISyntaxException 900 { 901 if ((host != null) || (authority == null)) 905 return this; 906 defineString(); 907 new Parser(string).parse(true); 908 return this; 909 } 910 911 948 public URI normalize() { 949 return normalize(this); 950 } 951 952 1006 public URI resolve(URI uri) { 1007 return resolve(this, uri); 1008 } 1009 1010 1027 public URI resolve(String str) { 1028 return resolve(URI.create(str)); 1029 } 1030 1031 1057 public URI relativize(URI uri) { 1058 return relativize(this, uri); 1059 } 1060 1061 1077 public URL toURL() 1078 throws MalformedURLException { 1079 if (!isAbsolute()) 1080 throw new IllegalArgumentException ("URI is not absolute"); 1081 return new URL (toString()); 1082 } 1083 1084 1086 1099 public String getScheme() { 1100 return scheme; 1101 } 1102 1103 1110 public boolean isAbsolute() { 1111 return scheme != null; 1112 } 1113 1114 1124 public boolean isOpaque() { 1125 return path == null; 1126 } 1127 1128 1138 public String getRawSchemeSpecificPart() { 1139 defineSchemeSpecificPart(); 1140 return schemeSpecificPart; 1141 } 1142 1143 1154 public String getSchemeSpecificPart() { 1155 if (decodedSchemeSpecificPart == null) 1156 decodedSchemeSpecificPart = decode(getRawSchemeSpecificPart()); 1157 return decodedSchemeSpecificPart; 1158 } 1159 1160 1173 public String getRawAuthority() { 1174 return authority; 1175 } 1176 1177 1187 public String getAuthority() { 1188 if (decodedAuthority == null) 1189 decodedAuthority = decode(authority); 1190 return decodedAuthority; 1191 } 1192 1193 1203 public String getRawUserInfo() { 1204 return userInfo; 1205 } 1206 1207 1217 public String getUserInfo() { 1218 if ((decodedUserInfo == null) && (userInfo != null)) 1219 decodedUserInfo = decode(userInfo); 1220 return decodedUserInfo; 1221 } 1222 1223 1259 public String getHost() { 1260 return host; 1261 } 1262 1263 1272 public int getPort() { 1273 return port; 1274 } 1275 1276 1287 public String getRawPath() { 1288 return path; 1289 } 1290 1291 1301 public String getPath() { 1302 if ((decodedPath == null) && (path != null)) 1303 decodedPath = decode(path); 1304 return decodedPath; 1305 } 1306 1307 1316 public String getRawQuery() { 1317 return query; 1318 } 1319 1320 1330 public String getQuery() { 1331 if ((decodedQuery == null) && (query != null)) 1332 decodedQuery = decode(query); 1333 return decodedQuery; 1334 } 1335 1336 1345 public String getRawFragment() { 1346 return fragment; 1347 } 1348 1349 1359 public String getFragment() { 1360 if ((decodedFragment == null) && (fragment != null)) 1361 decodedFragment = decode(fragment); 1362 return decodedFragment; 1363 } 1364 1365 1366 1368 1405 public boolean equals(Object ob) { 1406 if (ob == this) 1407 return true; 1408 if (!(ob instanceof URI )) 1409 return false; 1410 URI that = (URI )ob; 1411 if (this.isOpaque() != that.isOpaque()) return false; 1412 if (!equalIgnoringCase(this.scheme, that.scheme)) return false; 1413 if (!equal(this.fragment, that.fragment)) return false; 1414 1415 if (this.isOpaque()) 1417 return equal(this.schemeSpecificPart, that.schemeSpecificPart); 1418 1419 if (!equal(this.path, that.path)) return false; 1421 if (!equal(this.query, that.query)) return false; 1422 1423 if (this.authority == that.authority) return true; 1425 if (this.host != null) { 1426 if (!equal(this.userInfo, that.userInfo)) return false; 1428 if (!equalIgnoringCase(this.host, that.host)) return false; 1429 if (this.port != that.port) return false; 1430 } else if (this.authority != null) { 1431 if (!equal(this.authority, that.authority)) return false; 1433 } else if (this.authority != that.authority) { 1434 return false; 1435 } 1436 1437 return true; 1438 } 1439 1440 1447 public int hashCode() { 1448 if (hash != 0) 1449 return hash; 1450 int h = hashIgnoringCase(0, scheme); 1451 h = hash(h, fragment); 1452 if (isOpaque()) { 1453 h = hash(h, schemeSpecificPart); 1454 } else { 1455 h = hash(h, path); 1456 h = hash(h, query); 1457 if (host != null) { 1458 h = hash(h, userInfo); 1459 h = hashIgnoringCase(h, host); 1460 h += 1949 * port; 1461 } else { 1462 h = hash(h, authority); 1463 } 1464 } 1465 hash = h; 1466 return h; 1467 } 1468 1469 1537 public int compareTo(URI that) { 1538 int c; 1539 1540 if ((c = compareIgnoringCase(this.scheme, that.scheme)) != 0) 1541 return c; 1542 1543 if (this.isOpaque()) { 1544 if (that.isOpaque()) { 1545 if ((c = compare(this.schemeSpecificPart, 1547 that.schemeSpecificPart)) != 0) 1548 return c; 1549 return compare(this.fragment, that.fragment); 1550 } 1551 return +1; } else if (that.isOpaque()) { 1553 return -1; } 1555 1556 if ((this.host != null) && (that.host != null)) { 1558 if ((c = compare(this.userInfo, that.userInfo)) != 0) 1560 return c; 1561 if ((c = compareIgnoringCase(this.host, that.host)) != 0) 1562 return c; 1563 if ((c = this.port - that.port) != 0) 1564 return c; 1565 } else { 1566 if ((c = compare(this.authority, that.authority)) != 0) return c; 1573 } 1574 1575 if ((c = compare(this.path, that.path)) != 0) return c; 1576 if ((c = compare(this.query, that.query)) != 0) return c; 1577 return compare(this.fragment, that.fragment); 1578 } 1579 1580 1594 public String toString() { 1595 defineString(); 1596 return string; 1597 } 1598 1599 1612 public String toASCIIString() { 1613 defineString(); 1614 return encode(string); 1615 } 1616 1617 1618 1620 1631 private void writeObject(ObjectOutputStream os) 1632 throws IOException 1633 { 1634 defineString(); 1635 os.defaultWriteObject(); } 1637 1638 1648 private void readObject(ObjectInputStream is) 1649 throws ClassNotFoundException , IOException 1650 { 1651 port = -1; is.defaultReadObject(); 1653 try { 1654 new Parser(string).parse(false); 1655 } catch (URISyntaxException x) { 1656 IOException y = new InvalidObjectException ("Invalid URI"); 1657 y.initCause(x); 1658 throw y; 1659 } 1660 } 1661 1662 1663 1665 1666 1668 1675 private static int toLower(char c) { 1677 if ((c >= 'A') && (c <= 'Z')) 1678 return c + ('a' - 'A'); 1679 return c; 1680 } 1681 1682 private static boolean equal(String s, String t) { 1683 if (s == t) return true; 1684 if ((s != null) && (t != null)) { 1685 if (s.length() != t.length()) 1686 return false; 1687 if (s.indexOf('%') < 0) 1688 return s.equals(t); 1689 int n = s.length(); 1690 for (int i = 0; i < n;) { 1691 char c = s.charAt(i); 1692 char d = t.charAt(i); 1693 if (c != '%') { 1694 if (c != d) 1695 return false; 1696 i++; 1697 continue; 1698 } 1699 i++; 1700 if (toLower(s.charAt(i)) != toLower(t.charAt(i))) 1701 return false; 1702 i++; 1703 if (toLower(s.charAt(i)) != toLower(t.charAt(i))) 1704 return false; 1705 i++; 1706 } 1707 return true; 1708 } 1709 return false; 1710 } 1711 1712 private static boolean equalIgnoringCase(String s, String t) { 1714 if (s == t) return true; 1715 if ((s != null) && (t != null)) { 1716 int n = s.length(); 1717 if (t.length() != n) 1718 return false; 1719 for (int i = 0; i < n; i++) { 1720 if (toLower(s.charAt(i)) != toLower(t.charAt(i))) 1721 return false; 1722 } 1723 return true; 1724 } 1725 return false; 1726 } 1727 1728 private static int hash(int hash, String s) { 1729 if (s == null) return hash; 1730 return hash * 127 + s.hashCode(); 1731 } 1732 1733 private static int hashIgnoringCase(int hash, String s) { 1735 if (s == null) return hash; 1736 int h = hash; 1737 int n = s.length(); 1738 for (int i = 0; i < n; i++) 1739 h = 31 * h + toLower(s.charAt(i)); 1740 return h; 1741 } 1742 1743 private static int compare(String s, String t) { 1744 if (s == t) return 0; 1745 if (s != null) { 1746 if (t != null) 1747 return s.compareTo(t); 1748 else 1749 return +1; 1750 } else { 1751 return -1; 1752 } 1753 } 1754 1755 private static int compareIgnoringCase(String s, String t) { 1757 if (s == t) return 0; 1758 if (s != null) { 1759 if (t != null) { 1760 int sn = s.length(); 1761 int tn = t.length(); 1762 int n = sn < tn ? sn : tn; 1763 for (int i = 0; i < n; i++) { 1764 int c = toLower(s.charAt(i)) - toLower(t.charAt(i)); 1765 if (c != 0) 1766 return c; 1767 } 1768 return sn - tn; 1769 } 1770 return +1; 1771 } else { 1772 return -1; 1773 } 1774 } 1775 1776 1777 1779 private static void checkPath(String s, String scheme, String path) 1782 throws URISyntaxException 1783 { 1784 if (scheme != null) { 1785 if ((path != null) 1786 && ((path.length() > 0) && (path.charAt(0) != '/'))) 1787 throw new URISyntaxException (s, 1788 "Relative path in absolute URI"); 1789 } 1790 } 1791 1792 private void appendAuthority(StringBuffer sb, 1793 String authority, 1794 String userInfo, 1795 String host, 1796 int port) 1797 { 1798 if (host != null) { 1799 sb.append("//"); 1800 if (userInfo != null) { 1801 sb.append(quote(userInfo, L_USERINFO, H_USERINFO)); 1802 sb.append('@'); 1803 } 1804 boolean needBrackets = ((host.indexOf(':') >= 0) 1805 && !host.startsWith("[") 1806 && !host.endsWith("]")); 1807 if (needBrackets) sb.append('['); 1808 sb.append(host); 1809 if (needBrackets) sb.append(']'); 1810 if (port != -1) { 1811 sb.append(':'); 1812 sb.append(port); 1813 } 1814 } else if (authority != null) { 1815 sb.append("//"); 1816 if (authority.startsWith("[")) { 1817 int end = authority.indexOf("]"); 1818 if (end != -1 && authority.indexOf(":")!=-1) { 1819 String doquote, dontquote; 1820 if (end == authority.length()) { 1821 dontquote = authority; 1822 doquote = ""; 1823 } else { 1824 dontquote = authority.substring(0,end+1); 1825 doquote = authority.substring(end+1); 1826 } 1827 sb.append (dontquote); 1828 sb.append(quote(doquote, 1829 L_REG_NAME | L_SERVER, 1830 H_REG_NAME | H_SERVER)); 1831 } 1832 } else { 1833 sb.append(quote(authority, 1834 L_REG_NAME | L_SERVER, 1835 H_REG_NAME | H_SERVER)); 1836 } 1837 } 1838 } 1839 1840 private void appendSchemeSpecificPart(StringBuffer sb, 1841 String opaquePart, 1842 String authority, 1843 String userInfo, 1844 String host, 1845 int port, 1846 String path, 1847 String query) 1848 { 1849 if (opaquePart != null) { 1850 1853 if (opaquePart.startsWith("//[")) { 1854 int end = opaquePart.indexOf("]"); 1855 if (end != -1 && opaquePart.indexOf(":")!=-1) { 1856 String doquote, dontquote; 1857 if (end == opaquePart.length()) { 1858 dontquote = opaquePart; 1859 doquote = ""; 1860 } else { 1861 dontquote = opaquePart.substring(0,end+1); 1862 doquote = opaquePart.substring(end+1); 1863 } 1864 sb.append (dontquote); 1865 sb.append(quote(doquote, L_URIC, H_URIC)); 1866 } 1867 } else { 1868 sb.append(quote(opaquePart, L_URIC, H_URIC)); 1869 } 1870 } else { 1871 appendAuthority(sb, authority, userInfo, host, port); 1872 if (path != null) 1873 sb.append(quote(path, L_PATH, H_PATH)); 1874 if (query != null) { 1875 sb.append('?'); 1876 sb.append(quote(query, L_URIC, H_URIC)); 1877 } 1878 } 1879 } 1880 1881 private void appendFragment(StringBuffer sb, String fragment) { 1882 if (fragment != null) { 1883 sb.append('#'); 1884 sb.append(quote(fragment, L_URIC, H_URIC)); 1885 } 1886 } 1887 1888 1889 private String toString(String scheme, 1896 String opaquePart, 1897 String authority, 1898 String userInfo, 1899 String host, 1900 int port, 1901 String path, 1902 String query, 1903 String fragment) 1904 { 1905 StringBuffer sb = new StringBuffer (); 1906 if (scheme != null) { 1907 sb.append(scheme); 1908 sb.append(':'); 1909 } 1910 appendSchemeSpecificPart(sb, opaquePart, 1911 authority, userInfo, host, port, 1912 path, query); 1913 appendFragment(sb, fragment); 1914 return sb.toString(); 1915 } 1916 1917 private void defineSchemeSpecificPart() { 1918 if (schemeSpecificPart != null) return; 1919 StringBuffer sb = new StringBuffer (); 1920 appendSchemeSpecificPart(sb, null, getAuthority(), getUserInfo(), 1921 host, port, getPath(), getQuery()); 1922 if (sb.length() == 0) return; 1923 schemeSpecificPart = sb.toString(); 1924 } 1925 1926 private void defineString() { 1927 if (string != null) return; 1928 1929 StringBuffer sb = new StringBuffer (); 1930 if (scheme != null) { 1931 sb.append(scheme); 1932 sb.append(':'); 1933 } 1934 if (isOpaque()) { 1935 sb.append(schemeSpecificPart); 1936 } else { 1937 if (host != null) { 1938 sb.append("//"); 1939 if (userInfo != null) { 1940 sb.append(userInfo); 1941 sb.append('@'); 1942 } 1943 boolean needBrackets = ((host.indexOf(':') >= 0) 1944 && !host.startsWith("[") 1945 && !host.endsWith("]")); 1946 if (needBrackets) sb.append('['); 1947 sb.append(host); 1948 if (needBrackets) sb.append(']'); 1949 if (port != -1) { 1950 sb.append(':'); 1951 sb.append(port); 1952 } 1953 } else if (authority != null) { 1954 sb.append("//"); 1955 sb.append(authority); 1956 } 1957 if (path != null) 1958 sb.append(path); 1959 if (query != null) { 1960 sb.append('?'); 1961 sb.append(query); 1962 } 1963 } 1964 if (fragment != null) { 1965 sb.append('#'); 1966 sb.append(fragment); 1967 } 1968 string = sb.toString(); 1969 } 1970 1971 1972 1974 private static String resolvePath(String base, String child, 1976 boolean absolute) 1977 { 1978 int i = base.lastIndexOf('/'); 1979 int cn = child.length(); 1980 String path = ""; 1981 1982 if (cn == 0) { 1983 if (i >= 0) 1985 path = base.substring(0, i + 1); 1986 } else { 1987 StringBuffer sb = new StringBuffer (base.length() + cn); 1988 if (i >= 0) 1990 sb.append(base.substring(0, i + 1)); 1991 sb.append(child); 1993 path = sb.toString(); 1994 } 1995 1996 String np = normalize(path); 1998 1999 2002 return np; 2003 } 2004 2005 private static URI resolve(URI base, URI child) { 2007 if (child.isOpaque() || base.isOpaque()) 2010 return child; 2011 2012 if ((child.scheme == null) && (child.authority == null) 2014 && child.path.equals("") && (child.fragment != null) 2015 && (child.query == null)) { 2016 if ((base.fragment != null) 2017 && child.fragment.equals(base.fragment)) { 2018 return base; 2019 } 2020 URI ru = new URI (); 2021 ru.scheme = base.scheme; 2022 ru.authority = base.authority; 2023 ru.userInfo = base.userInfo; 2024 ru.host = base.host; 2025 ru.port = base.port; 2026 ru.path = base.path; 2027 ru.fragment = child.fragment; 2028 ru.query = base.query; 2029 return ru; 2030 } 2031 2032 if (child.scheme != null) 2034 return child; 2035 2036 URI ru = new URI (); ru.scheme = base.scheme; 2038 ru.query = child.query; 2039 ru.fragment = child.fragment; 2040 2041 if (child.authority == null) { 2043 ru.authority = base.authority; 2044 ru.host = base.host; 2045 ru.userInfo = base.userInfo; 2046 ru.port = base.port; 2047 2048 String cp = (child.path == null) ? "" : child.path; 2049 if ((cp.length() > 0) && (cp.charAt(0) == '/')) { 2050 ru.path = child.path; 2052 } else { 2053 ru.path = resolvePath(base.path, cp, base.isAbsolute()); 2055 } 2056 } else { 2057 ru.authority = child.authority; 2058 ru.host = child.host; 2059 ru.userInfo = child.userInfo; 2060 ru.host = child.host; 2061 ru.port = child.port; 2062 ru.path = child.path; 2063 } 2064 2065 return ru; 2067 } 2068 2069 private static URI normalize(URI u) { 2073 if (u.isOpaque() || (u.path == null) || (u.path.length() == 0)) 2074 return u; 2075 2076 String np = normalize(u.path); 2077 if (np == u.path) 2078 return u; 2079 2080 URI v = new URI (); 2081 v.scheme = u.scheme; 2082 v.fragment = u.fragment; 2083 v.authority = u.authority; 2084 v.userInfo = u.userInfo; 2085 v.host = u.host; 2086 v.port = u.port; 2087 v.path = np; 2088 v.query = u.query; 2089 return v; 2090 } 2091 2092 private static URI relativize(URI base, URI child) { 2098 if (child.isOpaque() || base.isOpaque()) 2101 return child; 2102 if (!equalIgnoringCase(base.scheme, child.scheme) 2103 || !equal(base.authority, child.authority)) 2104 return child; 2105 2106 String bp = normalize(base.path); 2107 String cp = normalize(child.path); 2108 if (!bp.equals(cp)) { 2109 if (!bp.endsWith("/")) 2110 bp = bp + "/"; 2111 if (!cp.startsWith(bp)) 2112 return child; 2113 } 2114 2115 URI v = new URI (); 2116 v.path = cp.substring(bp.length()); 2117 v.query = child.query; 2118 v.fragment = child.fragment; 2119 return v; 2120 } 2121 2122 2123 2124 2126 2138 2139 static private int needsNormalization(String path) { 2148 boolean normal = true; 2149 int ns = 0; int end = path.length() - 1; int p = 0; 2153 while (p <= end) { 2155 if (path.charAt(p) != '/') break; 2156 p++; 2157 } 2158 if (p > 1) normal = false; 2159 2160 while (p <= end) { 2162 2163 if ((path.charAt(p) == '.') 2165 && ((p == end) 2166 || ((path.charAt(p + 1) == '/') 2167 || ((path.charAt(p + 1) == '.') 2168 && ((p + 1 == end) 2169 || (path.charAt(p + 2) == '/')))))) { 2170 normal = false; 2171 } 2172 ns++; 2173 2174 while (p <= end) { 2176 if (path.charAt(p++) != '/') 2177 continue; 2178 2179 while (p <= end) { 2181 if (path.charAt(p) != '/') break; 2182 normal = false; 2183 p++; 2184 } 2185 2186 break; 2187 } 2188 } 2189 2190 return normal ? -1 : ns; 2191 } 2192 2193 2194 static private void split(char[] path, int[] segs) { 2205 int end = path.length - 1; int p = 0; int i = 0; 2209 while (p <= end) { 2211 if (path[p] != '/') break; 2212 path[p] = '\0'; 2213 p++; 2214 } 2215 2216 while (p <= end) { 2217 2218 segs[i++] = p++; 2220 2221 while (p <= end) { 2223 if (path[p++] != '/') 2224 continue; 2225 path[p - 1] = '\0'; 2226 2227 while (p <= end) { 2229 if (path[p] != '/') break; 2230 path[p++] = '\0'; 2231 } 2232 break; 2233 } 2234 } 2235 2236 if (i != segs.length) 2237 throw new InternalError (); } 2239 2240 2241 static private int join(char[] path, int[] segs) { 2254 int ns = segs.length; int end = path.length - 1; int p = 0; 2258 if (path[p] == '\0') { 2259 path[p++] = '/'; 2261 } 2262 2263 for (int i = 0; i < ns; i++) { 2264 int q = segs[i]; if (q == -1) 2266 continue; 2268 2269 if (p == q) { 2270 while ((p <= end) && (path[p] != '\0')) 2272 p++; 2273 if (p <= end) { 2274 path[p++] = '/'; 2276 } 2277 } else if (p < q) { 2278 while ((q <= end) && (path[q] != '\0')) 2280 path[p++] = path[q++]; 2281 if (q <= end) { 2282 path[p++] = '/'; 2284 } 2285 } else 2286 throw new InternalError (); } 2288 2289 return p; 2290 } 2291 2292 2293 private static void removeDots(char[] path, int[] segs) { 2297 int ns = segs.length; 2298 int end = path.length - 1; 2299 2300 for (int i = 0; i < ns; i++) { 2301 int dots = 0; 2303 do { 2305 int p = segs[i]; 2306 if (path[p] == '.') { 2307 if (p == end) { 2308 dots = 1; 2309 break; 2310 } else if (path[p + 1] == '\0') { 2311 dots = 1; 2312 break; 2313 } else if ((path[p + 1] == '.') 2314 && ((p + 1 == end) 2315 || (path[p + 2] == '\0'))) { 2316 dots = 2; 2317 break; 2318 } 2319 } 2320 i++; 2321 } while (i < ns); 2322 if ((i > ns) || (dots == 0)) 2323 break; 2324 2325 if (dots == 1) { 2326 segs[i] = -1; 2328 } else { 2329 int j; 2333 for (j = i - 1; j >= 0; j--) { 2334 if (segs[j] != -1) break; 2335 } 2336 if (j >= 0) { 2337 int q = segs[j]; 2338 if (!((path[q] == '.') 2339 && (path[q + 1] == '.') 2340 && (path[q + 2] == '\0'))) { 2341 segs[i] = -1; 2342 segs[j] = -1; 2343 } 2344 } 2345 } 2346 } 2347 } 2348 2349 2350 private static void maybeAddLeadingDot(char[] path, int[] segs) { 2354 2355 if (path[0] == '\0') 2356 return; 2358 2359 int ns = segs.length; 2360 int f = 0; while (f < ns) { 2362 if (segs[f] >= 0) 2363 break; 2364 f++; 2365 } 2366 if ((f >= ns) || (f == 0)) 2367 return; 2370 2371 int p = segs[f]; 2372 while ((p < path.length) && (path[p] != ':') && (path[p] != '\0')) p++; 2373 if (p >= path.length || path[p] == '\0') 2374 return; 2376 2377 path[0] = '.'; 2380 path[1] = '\0'; 2381 segs[0] = 0; 2382 } 2383 2384 2385 private static String normalize(String ps) { 2392 2393 int ns = needsNormalization(ps); if (ns < 0) 2396 return ps; 2398 2399 char[] path = ps.toCharArray(); 2401 int[] segs = new int[ns]; split(path, segs); 2404 2405 removeDots(path, segs); 2407 2408 maybeAddLeadingDot(path, segs); 2410 2411 String s = new String (path, 0, join(path, segs)); 2413 if (s.equals(ps)) { 2414 return ps; 2416 } 2417 return s; 2418 } 2419 2420 2421 2422 2424 2436 private static long lowMask(String chars) { 2438 int n = chars.length(); 2439 long m = 0; 2440 for (int i = 0; i < n; i++) { 2441 char c = chars.charAt(i); 2442 if (c < 64) 2443 m |= (1L << c); 2444 } 2445 return m; 2446 } 2447 2448 private static long highMask(String chars) { 2450 int n = chars.length(); 2451 long m = 0; 2452 for (int i = 0; i < n; i++) { 2453 char c = chars.charAt(i); 2454 if ((c >= 64) && (c < 128)) 2455 m |= (1L << (c - 64)); 2456 } 2457 return m; 2458 } 2459 2460 private static long lowMask(char first, char last) { 2463 long m = 0; 2464 int f = Math.max(Math.min(first, 63), 0); 2465 int l = Math.max(Math.min(last, 63), 0); 2466 for (int i = f; i <= l; i++) 2467 m |= 1L << i; 2468 return m; 2469 } 2470 2471 private static long highMask(char first, char last) { 2474 long m = 0; 2475 int f = Math.max(Math.min(first, 127), 64) - 64; 2476 int l = Math.max(Math.min(last, 127), 64) - 64; 2477 for (int i = f; i <= l; i++) 2478 m |= 1L << i; 2479 return m; 2480 } 2481 2482 private static boolean match(char c, long lowMask, long highMask) { 2484 if (c < 64) 2485 return ((1L << c) & lowMask) != 0; 2486 if (c < 128) 2487 return ((1L << (c - 64)) & highMask) != 0; 2488 return false; 2489 } 2490 2491 2494 private static final long L_DIGIT = lowMask('0', '9'); 2497 private static final long H_DIGIT = 0L; 2498 2499 private static final long L_UPALPHA = 0L; 2503 private static final long H_UPALPHA = highMask('A', 'Z'); 2504 2505 private static final long L_LOWALPHA = 0L; 2509 private static final long H_LOWALPHA = highMask('a', 'z'); 2510 2511 private static final long L_ALPHA = L_LOWALPHA | L_UPALPHA; 2513 private static final long H_ALPHA = H_LOWALPHA | H_UPALPHA; 2514 2515 private static final long L_ALPHANUM = L_DIGIT | L_ALPHA; 2517 private static final long H_ALPHANUM = H_DIGIT | H_ALPHA; 2518 2519 private static final long L_HEX = L_DIGIT; 2522 private static final long H_HEX = highMask('A', 'F') | highMask('a', 'f'); 2523 2524 private static final long L_MARK = lowMask("-_.!~*'()"); 2527 private static final long H_MARK = highMask("-_.!~*'()"); 2528 2529 private static final long L_UNRESERVED = L_ALPHANUM | L_MARK; 2531 private static final long H_UNRESERVED = H_ALPHANUM | H_MARK; 2532 2533 private static final long L_RESERVED = lowMask(";/?:@&=+$,[]"); 2537 private static final long H_RESERVED = highMask(";/?:@&=+$,[]"); 2538 2539 private static final long L_ESCAPED = 1L; 2542 private static final long H_ESCAPED = 0L; 2543 2544 private static final long L_URIC = L_RESERVED | L_UNRESERVED | L_ESCAPED; 2546 private static final long H_URIC = H_RESERVED | H_UNRESERVED | H_ESCAPED; 2547 2548 private static final long L_PCHAR 2551 = L_UNRESERVED | L_ESCAPED | lowMask(":@&=+$,"); 2552 private static final long H_PCHAR 2553 = H_UNRESERVED | H_ESCAPED | highMask(":@&=+$,"); 2554 2555 private static final long L_PATH = L_PCHAR | lowMask(";/"); 2557 private static final long H_PATH = H_PCHAR | highMask(";/"); 2558 2559 private static final long L_DASH = lowMask("-"); 2561 private static final long H_DASH = highMask("-"); 2562 2563 private static final long L_DOT = lowMask("."); 2565 private static final long H_DOT = highMask("."); 2566 2567 private static final long L_USERINFO 2570 = L_UNRESERVED | L_ESCAPED | lowMask(";:&=+$,"); 2571 private static final long H_USERINFO 2572 = H_UNRESERVED | H_ESCAPED | highMask(";:&=+$,"); 2573 2574 private static final long L_REG_NAME 2577 = L_UNRESERVED | L_ESCAPED | lowMask("$,;:@&=+"); 2578 private static final long H_REG_NAME 2579 = H_UNRESERVED | H_ESCAPED | highMask("$,;:@&=+"); 2580 2581 private static final long L_SERVER 2583 = L_USERINFO | L_ALPHANUM | L_DASH | lowMask(".:@[]"); 2584 private static final long H_SERVER 2585 = H_USERINFO | H_ALPHANUM | H_DASH | highMask(".:@[]"); 2586 2587 private static final long L_SERVER_PERCENT 2590 = L_SERVER | lowMask("%"); 2591 private static final long H_SERVER_PERCENT 2592 = H_SERVER | highMask("%"); 2593 private static final long L_LEFT_BRACKET = lowMask("["); 2594 private static final long H_LEFT_BRACKET = highMask("["); 2595 2596 private static final long L_SCHEME = L_ALPHA | L_DIGIT | lowMask("+-."); 2598 private static final long H_SCHEME = H_ALPHA | H_DIGIT | highMask("+-."); 2599 2600 private static final long L_URIC_NO_SLASH 2603 = L_UNRESERVED | L_ESCAPED | lowMask(";?:@&=+$,"); 2604 private static final long H_URIC_NO_SLASH 2605 = H_UNRESERVED | H_ESCAPED | highMask(";?:@&=+$,"); 2606 2607 2608 2610 private final static char[] hexDigits = { 2611 '0', '1', '2', '3', '4', '5', '6', '7', 2612 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' 2613 }; 2614 2615 private static void appendEscape(StringBuffer sb, byte b) { 2616 sb.append('%'); 2617 sb.append(hexDigits[(b >> 4) & 0x0f]); 2618 sb.append(hexDigits[(b >> 0) & 0x0f]); 2619 } 2620 2621 private static void appendEncoded(StringBuffer sb, char c) { 2622 ByteBuffer bb = null; 2623 try { 2624 bb = ThreadLocalCoders.encoderFor("UTF-8") 2625 .encode(CharBuffer.wrap("" + c)); 2626 } catch (CharacterCodingException x) { 2627 assert false; 2628 } 2629 while (bb.hasRemaining()) { 2630 int b = bb.get() & 0xff; 2631 if (b >= 0x80) 2632 appendEscape(sb, (byte)b); 2633 else 2634 sb.append((char)b); 2635 } 2636 } 2637 2638 private static String quote(String s, long lowMask, long highMask) { 2642 int n = s.length(); 2643 StringBuffer sb = null; 2644 boolean allowNonASCII = ((lowMask & L_ESCAPED) != 0); 2645 for (int i = 0; i < s.length(); i++) { 2646 char c = s.charAt(i); 2647 if (c < '\u0080') { 2648 if (!match(c, lowMask, highMask)) { 2649 if (sb == null) { 2650 sb = new StringBuffer (); 2651 sb.append(s.substring(0, i)); 2652 } 2653 appendEscape(sb, (byte)c); 2654 } else { 2655 if (sb != null) 2656 sb.append(c); 2657 } 2658 } else if (allowNonASCII 2659 && (Character.isSpaceChar(c) 2660 || Character.isISOControl(c))) { 2661 if (sb == null) { 2662 sb = new StringBuffer (); 2663 sb.append(s.substring(0, i)); 2664 } 2665 appendEncoded(sb, c); 2666 } else { 2667 if (sb != null) 2668 sb.append(c); 2669 } 2670 } 2671 return (sb == null) ? s : sb.toString(); 2672 } 2673 2674 private static String encode(String s) { 2678 int n = s.length(); 2679 if (n == 0) 2680 return s; 2681 2682 for (int i = 0;;) { 2684 if (s.charAt(i) >= '\u0080') 2685 break; 2686 if (++i >= n) 2687 return s; 2688 } 2689 2690 String ns = Normalizer.normalize(s, Normalizer.COMPOSE, 0); 2691 ByteBuffer bb = null; 2692 try { 2693 bb = ThreadLocalCoders.encoderFor("UTF-8") 2694 .encode(CharBuffer.wrap(ns)); 2695 } catch (CharacterCodingException x) { 2696 assert false; 2697 } 2698 2699 StringBuffer sb = new StringBuffer (); 2700 while (bb.hasRemaining()) { 2701 int b = bb.get() & 0xff; 2702 if (b >= 0x80) 2703 appendEscape(sb, (byte)b); 2704 else 2705 sb.append((char)b); 2706 } 2707 return sb.toString(); 2708 } 2709 2710 private static int decode(char c) { 2711 if ((c >= '0') && (c <= '9')) 2712 return c - '0'; 2713 if ((c >= 'a') && (c <= 'f')) 2714 return c - 'a' + 10; 2715 if ((c >= 'A') && (c <= 'F')) 2716 return c - 'A' + 10; 2717 assert false; 2718 return -1; 2719 } 2720 2721 private static byte decode(char c1, char c2) { 2722 return (byte)( ((decode(c1) & 0xf) << 4) 2723 | ((decode(c2) & 0xf) << 0)); 2724 } 2725 2726 private static String decode(String s) { 2734 if (s == null) 2735 return s; 2736 int n = s.length(); 2737 if (n == 0) 2738 return s; 2739 if (s.indexOf('%') < 0) 2740 return s; 2741 2742 byte[] ba = new byte[n]; 2743 StringBuffer sb = new StringBuffer (n); 2744 ByteBuffer bb = ByteBuffer.allocate(n); 2745 CharBuffer cb = CharBuffer.allocate(n); 2746 CharsetDecoder dec = ThreadLocalCoders.decoderFor("UTF-8") 2747 .onMalformedInput(CodingErrorAction.REPLACE) 2748 .onUnmappableCharacter(CodingErrorAction.REPLACE); 2749 2750 char c = s.charAt(0); 2752 boolean betweenBrackets = false; 2753 2754 for (int i = 0; i < n;) { 2755 assert c == s.charAt(i); if (c == '[') { 2757 betweenBrackets = true; 2758 } else if (betweenBrackets && c == ']') { 2759 betweenBrackets = false; 2760 } 2761 if (c != '%' || betweenBrackets) { 2762 sb.append(c); 2763 if (++i >= n) 2764 break; 2765 c = s.charAt(i); 2766 continue; 2767 } 2768 bb.clear(); 2769 int ui = i; 2770 for (;;) { 2771 assert (n - i >= 2); 2772 bb.put(decode(s.charAt(++i), s.charAt(++i))); 2773 if (++i >= n) 2774 break; 2775 c = s.charAt(i); 2776 if (c != '%') 2777 break; 2778 } 2779 bb.flip(); 2780 cb.clear(); 2781 dec.reset(); 2782 CoderResult cr = dec.decode(bb, cb, true); 2783 assert cr.isUnderflow(); 2784 cr = dec.flush(cb); 2785 assert cr.isUnderflow(); 2786 sb.append(cb.flip().toString()); 2787 } 2788 2789 return sb.toString(); 2790 } 2791 2792 2793 2795 2799 private class Parser { 2800 2801 private String input; private boolean requireServerAuthority = false; 2803 2804 Parser(String s) { 2805 input = s; 2806 string = s; 2807 } 2808 2809 2811 private void fail(String reason) throws URISyntaxException { 2812 throw new URISyntaxException (input, reason); 2813 } 2814 2815 private void fail(String reason, int p) throws URISyntaxException { 2816 throw new URISyntaxException (input, reason, p); 2817 } 2818 2819 private void failExpecting(String expected, int p) 2820 throws URISyntaxException 2821 { 2822 fail("Expected " + expected, p); 2823 } 2824 2825 private void failExpecting(String expected, String prior, int p) 2826 throws URISyntaxException 2827 { 2828 fail("Expected " + expected + " following " + prior, p); 2829 } 2830 2831 2832 2834 private String substring(int start, int end) { 2837 return input.substring(start, end); 2838 } 2839 2840 private char charAt(int p) { 2844 return input.charAt(p); 2845 } 2846 2847 private boolean at(int start, int end, char c) { 2850 return (start < end) && (charAt(start) == c); 2851 } 2852 2853 private boolean at(int start, int end, String s) { 2857 int p = start; 2858 int sn = s.length(); 2859 if (sn > end - p) 2860 return false; 2861 int i = 0; 2862 while (i < sn) { 2863 if (charAt(p++) != s.charAt(i)) { 2864 break; 2865 } 2866 i++; 2867 } 2868 return (i == sn); 2869 } 2870 2871 2872 2874 2897 2898 private int scan(int start, int end, char c) { 2903 if ((start < end) && (charAt(start) == c)) 2904 return start + 1; 2905 return start; 2906 } 2907 2908 private int scan(int start, int end, String err, String stop) { 2916 int p = start; 2917 while (p < end) { 2918 char c = charAt(p); 2919 if (err.indexOf(c) >= 0) 2920 return -1; 2921 if (stop.indexOf(c) >= 0) 2922 break; 2923 p++; 2924 } 2925 return p; 2926 } 2927 2928 private int scanEscape(int start, int n, char first) 2935 throws URISyntaxException 2936 { 2937 int p = start; 2938 char c = first; 2939 if (c == '%') { 2940 if ((p + 3 <= n) 2942 && match(charAt(p + 1), L_HEX, H_HEX) 2943 && match(charAt(p + 2), L_HEX, H_HEX)) { 2944 return p + 3; 2945 } 2946 fail("Malformed escape pair", p); 2947 } else if ((c > 128) 2948 && !Character.isSpaceChar(c) 2949 && !Character.isISOControl(c)) { 2950 return p + 1; 2952 } 2953 return p; 2954 } 2955 2956 private int scan(int start, int n, long lowMask, long highMask) 2959 throws URISyntaxException 2960 { 2961 int p = start; 2962 while (p < n) { 2963 char c = charAt(p); 2964 if (match(c, lowMask, highMask)) { 2965 p++; 2966 continue; 2967 } 2968 if ((lowMask & L_ESCAPED) != 0) { 2969 int q = scanEscape(p, n, c); 2970 if (q > p) { 2971 p = q; 2972 continue; 2973 } 2974 } 2975 break; 2976 } 2977 return p; 2978 } 2979 2980 private void checkChars(int start, int end, 2983 long lowMask, long highMask, 2984 String what) 2985 throws URISyntaxException 2986 { 2987 int p = scan(start, end, lowMask, highMask); 2988 if (p < end) 2989 fail("Illegal character in " + what, p); 2990 } 2991 2992 private void checkChar(int p, 2995 long lowMask, long highMask, 2996 String what) 2997 throws URISyntaxException 2998 { 2999 checkChars(p, p + 1, lowMask, highMask, what); 3000 } 3001 3002 3003 3005 void parse(boolean rsa) throws URISyntaxException { 3008 requireServerAuthority = rsa; 3009 int ssp; int n = input.length(); 3011 int p = scan(0, n, "/?#", ":"); 3012 if ((p >= 0) && at(p, n, ':')) { 3013 if (p == 0) 3014 failExpecting("scheme name", 0); 3015 checkChar(0, L_ALPHA, H_ALPHA, "scheme name"); 3016 checkChars(1, p, L_SCHEME, H_SCHEME, "scheme name"); 3017 scheme = substring(0, p); 3018 p++; ssp = p; 3020 if (at(p, n, '/')) { 3021 p = parseHierarchical(p, n); 3022 } else { 3023 int q = scan(p, n, "", "#"); 3024 if (q <= p) 3025 failExpecting("scheme-specific part", p); 3026 checkChars(p, q, L_URIC, H_URIC, "opaque part"); 3027 p = q; 3028 } 3029 } else { 3030 ssp = 0; 3031 p = parseHierarchical(0, n); 3032 } 3033 schemeSpecificPart = substring(ssp, p); 3034 if (at(p, n, '#')) { 3035 checkChars(p + 1, n, L_URIC, H_URIC, "fragment"); 3036 fragment = substring(p + 1, n); 3037 p = n; 3038 } 3039 if (p < n) 3040 fail("end of URI", p); 3041 } 3042 3043 private int parseHierarchical(int start, int n) 3058 throws URISyntaxException 3059 { 3060 int p = start; 3061 if (at(p, n, '/') && at(p + 1, n, '/')) { 3062 p += 2; 3063 int q = scan(p, n, "", "/?#"); 3064 if (q > p) { 3065 p = parseAuthority(p, q); 3066 } else if (q < n) { 3067 } else 3070 failExpecting("authority", p); 3071 } 3072 int q = scan(p, n, "", "?#"); checkChars(p, q, L_PATH, H_PATH, "path"); 3074 path = substring(p, q); 3075 p = q; 3076 if (at(p, n, '?')) { 3077 p++; 3078 q = scan(p, n, "", "#"); 3079 checkChars(p, q, L_URIC, H_URIC, "query"); 3080 query = substring(p, q); 3081 p = q; 3082 } 3083 return p; 3084 } 3085 3086 private int parseAuthority(int start, int n) 3095 throws URISyntaxException 3096 { 3097 int p = start; 3098 int q = p; 3099 URISyntaxException ex = null; 3100 3101 boolean serverChars; 3102 boolean regChars; 3103 3104 if (scan(p, n, "", "]") > p) { 3105 serverChars = (scan(p, n, L_SERVER_PERCENT, H_SERVER_PERCENT) == n); 3107 } else { 3108 serverChars = (scan(p, n, L_SERVER, H_SERVER) == n); 3109 } 3110 regChars = (scan(p, n, L_REG_NAME, H_REG_NAME) == n); 3111 3112 if (regChars && !serverChars) { 3113 authority = substring(p, n); 3115 return n; 3116 } 3117 3118 if (serverChars) { 3119 try { 3123 q = parseServer(p, n); 3124 if (q < n) 3125 failExpecting("end of authority", q); 3126 authority = substring(p, n); 3127 } catch (URISyntaxException x) { 3128 userInfo = null; 3130 host = null; 3131 port = -1; 3132 if (requireServerAuthority) { 3133 throw x; 3136 } else { 3137 ex = x; 3140 q = p; 3141 } 3142 } 3143 } 3144 3145 if (q < n) { 3146 if (regChars) { 3147 authority = substring(p, n); 3149 } else if (ex != null) { 3150 throw ex; 3153 } else { 3154 fail("Illegal character in authority", q); 3155 } 3156 } 3157 3158 return n; 3159 } 3160 3161 3162 private int parseServer(int start, int n) 3165 throws URISyntaxException 3166 { 3167 int p = start; 3168 int q; 3169 3170 q = scan(p, n, "/?#", "@"); 3172 if ((q >= p) && at(q, n, '@')) { 3173 checkChars(p, q, L_USERINFO, H_USERINFO, "user info"); 3174 userInfo = substring(p, q); 3175 p = q + 1; } 3177 3178 if (at(p, n, '[')) { 3180 p++; 3182 q = scan(p, n, "/?#", "]"); 3183 if ((q > p) && at(q, n, ']')) { 3184 int r = scan (p, q, "", "%"); 3186 if (r > p) { 3187 parseIPv6Reference(p, r); 3188 if (r+1 == q) { 3189 fail ("scope id expected"); 3190 } 3191 checkChars (r+1, q, L_ALPHANUM, H_ALPHANUM, 3192 "scope id"); 3193 } else { 3194 parseIPv6Reference(p, q); 3195 } 3196 host = substring(p-1, q+1); 3197 p = q + 1; 3198 } else { 3199 failExpecting("closing bracket for IPv6 address", q); 3200 } 3201 } else { 3202 q = parseIPv4Address(p, n); 3203 if (q <= p) 3204 q = parseHostname(p, n); 3205 p = q; 3206 } 3207 3208 if (at(p, n, ':')) { 3210 p++; 3211 q = scan(p, n, "", "/"); 3212 if (q > p) { 3213 checkChars(p, q, L_DIGIT, H_DIGIT, "port number"); 3214 try { 3215 port = Integer.parseInt(substring(p, q)); 3216 } catch (NumberFormatException x) { 3217 fail("Malformed port number", p); 3218 } 3219 p = q; 3220 } 3221 } 3222 if (p < n) 3223 failExpecting("port number", p); 3224 3225 return p; 3226 } 3227 3228 private int scanByte(int start, int n) 3231 throws URISyntaxException 3232 { 3233 int p = start; 3234 int q = scan(p, n, L_DIGIT, H_DIGIT); 3235 if (q <= p) return q; 3236 if (Integer.parseInt(substring(p, q)) > 255) return p; 3237 return q; 3238 } 3239 3240 private int scanIPv4Address(int start, int n, boolean strict) 3256 throws URISyntaxException 3257 { 3258 int p = start; 3259 int q; 3260 int m = scan(p, n, L_DIGIT | L_DOT, H_DIGIT | H_DOT); 3261 if ((m <= p) || (strict && (m != n))) 3262 return -1; 3263 for (;;) { 3264 if ((q = scanByte(p, m)) <= p) break; p = q; 3267 if ((q = scan(p, m, '.')) <= p) break; p = q; 3268 if ((q = scanByte(p, m)) <= p) break; p = q; 3269 if ((q = scan(p, m, '.')) <= p) break; p = q; 3270 if ((q = scanByte(p, m)) <= p) break; p = q; 3271 if ((q = scan(p, m, '.')) <= p) break; p = q; 3272 if ((q = scanByte(p, m)) <= p) break; p = q; 3273 if (q < m) break; 3274 return q; 3275 } 3276 fail("Malformed IPv4 address", q); 3277 return -1; 3278 } 3279 3280 private int takeIPv4Address(int start, int n, String expected) 3284 throws URISyntaxException 3285 { 3286 int p = scanIPv4Address(start, n, true); 3287 if (p <= start) 3288 failExpecting(expected, start); 3289 return p; 3290 } 3291 3292 private int parseIPv4Address(int start, int n) { 3297 int p; 3298 3299 try { 3300 p = scanIPv4Address(start, n, false); 3301 } catch (URISyntaxException x) { 3302 return -1; 3303 } catch (NumberFormatException nfe) { 3304 return -1; 3305 } 3306 3307 if (p > start && p < n) { 3308 if (charAt(p) != ':') { 3312 p = -1; 3313 } 3314 } 3315 3316 if (p > start) 3317 host = substring(start, p); 3318 3319 return p; 3320 } 3321 3322 private int parseHostname(int start, int n) 3327 throws URISyntaxException 3328 { 3329 int p = start; 3330 int q; 3331 int l = -1; 3333 do { 3334 q = scan(p, n, L_ALPHANUM, H_ALPHANUM); 3336 if (q <= p) 3337 break; 3338 l = p; 3339 if (q > p) { 3340 p = q; 3341 q = scan(p, n, L_ALPHANUM | L_DASH, H_ALPHANUM | H_DASH); 3342 if (q > p) { 3343 if (charAt(q - 1) == '-') 3344 fail("Illegal character in hostname", q - 1); 3345 p = q; 3346 } 3347 } 3348 q = scan(p, n, '.'); 3349 if (q <= p) 3350 break; 3351 p = q; 3352 } while (p < n); 3353 3354 if ((p < n) && !at(p, n, ':')) 3355 fail("Illegal character in hostname", p); 3356 3357 if (l < 0) 3358 failExpecting("hostname", start); 3359 3360 if (l > start && !match(charAt(l), L_ALPHA, H_ALPHA)) { 3363 fail("Illegal character in hostname", l); 3364 } 3365 3366 host = substring(start, p); 3367 return p; 3368 } 3369 3370 3371 3412 private int ipv6byteCount = 0; 3413 3414 private int parseIPv6Reference(int start, int n) 3415 throws URISyntaxException 3416 { 3417 int p = start; 3418 int q; 3419 boolean compressedZeros = false; 3420 3421 q = scanHexSeq(p, n); 3422 3423 if (q > p) { 3424 p = q; 3425 if (at(p, n, "::")) { 3426 compressedZeros = true; 3427 p = scanHexPost(p + 2, n); 3428 } else if (at(p, n, ':')) { 3429 p = takeIPv4Address(p + 1, n, "IPv4 address"); 3430 ipv6byteCount += 4; 3431 } 3432 } else if (at(p, n, "::")) { 3433 compressedZeros = true; 3434 p = scanHexPost(p + 2, n); 3435 } 3436 if (p < n) 3437 fail("Malformed IPv6 address", start); 3438 if (ipv6byteCount > 16) 3439 fail("IPv6 address too long", start); 3440 if (!compressedZeros && ipv6byteCount < 16) 3441 fail("IPv6 address too short", start); 3442 if (compressedZeros && ipv6byteCount == 16) 3443 fail("Malformed IPv6 address", start); 3444 3445 return p; 3446 } 3447 3448 private int scanHexPost(int start, int n) 3449 throws URISyntaxException 3450 { 3451 int p = start; 3452 int q; 3453 3454 if (p == n) 3455 return p; 3456 3457 q = scanHexSeq(p, n); 3458 if (q > p) { 3459 p = q; 3460 if (at(p, n, ':')) { 3461 p++; 3462 p = takeIPv4Address(p, n, "hex digits or IPv4 address"); 3463 ipv6byteCount += 4; 3464 } 3465 } else { 3466 p = takeIPv4Address(p, n, "hex digits or IPv4 address"); 3467 ipv6byteCount += 4; 3468 } 3469 return p; 3470 } 3471 3472 private int scanHexSeq(int start, int n) 3475 throws URISyntaxException 3476 { 3477 int p = start; 3478 int q; 3479 3480 q = scan(p, n, L_HEX, H_HEX); 3481 if (q <= p) 3482 return -1; 3483 if (at(q, n, '.')) return -1; 3485 if (q > p + 4) 3486 fail("IPv6 hexadecimal digit sequence too long", p); 3487 ipv6byteCount += 2; 3488 p = q; 3489 while (p < n) { 3490 if (!at(p, n, ':')) 3491 break; 3492 if (at(p + 1, n, ':')) 3493 break; p++; 3495 q = scan(p, n, L_HEX, H_HEX); 3496 if (q <= p) 3497 failExpecting("digits for an IPv6 address", p); 3498 if (at(q, n, '.')) { p--; 3500 break; 3501 } 3502 if (q > p + 4) 3503 fail("IPv6 hexadecimal digit sequence too long", p); 3504 ipv6byteCount += 2; 3505 p = q; 3506 } 3507 3508 return p; 3509 } 3510 3511 } 3512 3513} 3514 | Popular Tags |