| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of dart.core; | 5 part of dart.core; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * A parsed URI, such as a URL. | 8 * A parsed URI, such as a URL. |
| 9 * | 9 * |
| 10 * **See also:** | 10 * **See also:** |
| (...skipping 378 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 389 userinfo, | 389 userinfo, |
| 390 host, | 390 host, |
| 391 port, | 391 port, |
| 392 path, | 392 path, |
| 393 query, | 393 query, |
| 394 fragment); | 394 fragment); |
| 395 } | 395 } |
| 396 | 396 |
| 397 // Report a parse failure. | 397 // Report a parse failure. |
| 398 static void _fail(String uri, int index, String message) { | 398 static void _fail(String uri, int index, String message) { |
| 399 // TODO(lrn): Consider adding this to FormatException. | 399 throw new FormatException(message, uri, index); |
| 400 if (index == uri.length) { | |
| 401 message += " at end of input."; | |
| 402 } else { | |
| 403 message += " at position $index.\n"; | |
| 404 // Pick a slice of uri containing index and, if | |
| 405 // necessary, truncate the ends to ensure the entire | |
| 406 // slice fits on one line. | |
| 407 int min = 0; | |
| 408 int max = uri.length; | |
| 409 String pre = ""; | |
| 410 String post = ""; | |
| 411 if (uri.length > 78) { | |
| 412 min = index - 10; | |
| 413 if (min < 0) min = 0; | |
| 414 int max = min + 72; | |
| 415 if (max > uri.length) { | |
| 416 max = uri.length; | |
| 417 min = max - 72; | |
| 418 } | |
| 419 if (min != 0) pre = "..."; | |
| 420 if (max != uri.length) post = "..."; | |
| 421 } | |
| 422 // Combine message, slice and a caret pointing to the error index. | |
| 423 message = "$message$pre${uri.substring(min, max)}$post\n" | |
| 424 "${' ' * (pre.length + index - min)}^"; | |
| 425 } | |
| 426 throw new FormatException(message); | |
| 427 } | 400 } |
| 428 | 401 |
| 429 /// Internal non-verifying constructor. Only call with validated arguments. | 402 /// Internal non-verifying constructor. Only call with validated arguments. |
| 430 Uri._internal(this.scheme, | 403 Uri._internal(this.scheme, |
| 431 this._userInfo, | 404 this._userInfo, |
| 432 this._host, | 405 this._host, |
| 433 this._port, | 406 this._port, |
| 434 this._path, | 407 this._path, |
| 435 this._query, | 408 this._query, |
| 436 this._fragment); | 409 this._fragment); |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 601 } | 574 } |
| 602 } | 575 } |
| 603 var hostEnd = hostStart; | 576 var hostEnd = hostStart; |
| 604 if (hostStart < authority.length && | 577 if (hostStart < authority.length && |
| 605 authority.codeUnitAt(hostStart) == _LEFT_BRACKET) { | 578 authority.codeUnitAt(hostStart) == _LEFT_BRACKET) { |
| 606 // IPv6 host. | 579 // IPv6 host. |
| 607 for (; hostEnd < authority.length; hostEnd++) { | 580 for (; hostEnd < authority.length; hostEnd++) { |
| 608 if (authority.codeUnitAt(hostEnd) == _RIGHT_BRACKET) break; | 581 if (authority.codeUnitAt(hostEnd) == _RIGHT_BRACKET) break; |
| 609 } | 582 } |
| 610 if (hostEnd == authority.length) { | 583 if (hostEnd == authority.length) { |
| 611 throw new FormatException("Invalid IPv6 host entry."); | 584 throw new FormatException("Invalid IPv6 host entry.", |
| 585 authority, hostStart); |
| 612 } | 586 } |
| 613 parseIPv6Address(authority, hostStart + 1, hostEnd); | 587 parseIPv6Address(authority, hostStart + 1, hostEnd); |
| 614 hostEnd++; // Skip the closing bracket. | 588 hostEnd++; // Skip the closing bracket. |
| 615 if (hostEnd != authority.length && | 589 if (hostEnd != authority.length && |
| 616 authority.codeUnitAt(hostEnd) != _COLON) { | 590 authority.codeUnitAt(hostEnd) != _COLON) { |
| 617 throw new FormatException("Invalid end of authority"); | 591 throw new FormatException("Invalid end of authority", |
| 592 authority, hostEnd); |
| 618 } | 593 } |
| 619 } | 594 } |
| 620 // Split host and port. | 595 // Split host and port. |
| 621 bool hasPort = false; | 596 bool hasPort = false; |
| 622 for (; hostEnd < authority.length; hostEnd++) { | 597 for (; hostEnd < authority.length; hostEnd++) { |
| 623 if (authority.codeUnitAt(hostEnd) == _COLON) { | 598 if (authority.codeUnitAt(hostEnd) == _COLON) { |
| 624 var portString = authority.substring(hostEnd + 1); | 599 var portString = authority.substring(hostEnd + 1); |
| 625 // We allow the empty port - falling back to initial value. | 600 // We allow the empty port - falling back to initial value. |
| 626 if (portString.isNotEmpty) port = int.parse(portString); | 601 if (portString.isNotEmpty) port = int.parse(portString); |
| 627 break; | 602 break; |
| (...skipping 1176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1804 * * 2010:836B:4179::836B:4179 | 1779 * * 2010:836B:4179::836B:4179 |
| 1805 */ | 1780 */ |
| 1806 static List<int> parseIPv6Address(String host, [int start = 0, int end]) { | 1781 static List<int> parseIPv6Address(String host, [int start = 0, int end]) { |
| 1807 if (end == null) end = host.length; | 1782 if (end == null) end = host.length; |
| 1808 // An IPv6 address consists of exactly 8 parts of 1-4 hex digits, seperated | 1783 // An IPv6 address consists of exactly 8 parts of 1-4 hex digits, seperated |
| 1809 // by `:`'s, with the following exceptions: | 1784 // by `:`'s, with the following exceptions: |
| 1810 // | 1785 // |
| 1811 // - One (and only one) wildcard (`::`) may be present, representing a fill | 1786 // - One (and only one) wildcard (`::`) may be present, representing a fill |
| 1812 // of 0's. The IPv6 `::` is thus 16 bytes of `0`. | 1787 // of 0's. The IPv6 `::` is thus 16 bytes of `0`. |
| 1813 // - The last two parts may be replaced by an IPv4 address. | 1788 // - The last two parts may be replaced by an IPv4 address. |
| 1814 void error(String msg) { | 1789 void error(String msg, [position]) { |
| 1815 throw new FormatException('Illegal IPv6 address, $msg'); | 1790 throw new FormatException('Illegal IPv6 address, $msg', host, position); |
| 1816 } | 1791 } |
| 1817 int parseHex(int start, int end) { | 1792 int parseHex(int start, int end) { |
| 1818 if (end - start > 4) { | 1793 if (end - start > 4) { |
| 1819 error('an IPv6 part can only contain a maximum of 4 hex digits'); | 1794 error('an IPv6 part can only contain a maximum of 4 hex digits', start); |
| 1820 } | 1795 } |
| 1821 int value = int.parse(host.substring(start, end), radix: 16); | 1796 int value = int.parse(host.substring(start, end), radix: 16); |
| 1822 if (value < 0 || value > (1 << 16) - 1) { | 1797 if (value < 0 || value > (1 << 16) - 1) { |
| 1823 error('each part must be in the range of `0x0..0xFFFF`'); | 1798 error('each part must be in the range of `0x0..0xFFFF`', start); |
| 1824 } | 1799 } |
| 1825 return value; | 1800 return value; |
| 1826 } | 1801 } |
| 1827 if (host.length < 2) error('address is too short'); | 1802 if (host.length < 2) error('address is too short'); |
| 1828 List<int> parts = []; | 1803 List<int> parts = []; |
| 1829 bool wildcardSeen = false; | 1804 bool wildcardSeen = false; |
| 1830 int partStart = start; | 1805 int partStart = start; |
| 1831 // Parse all parts, except a potential last one. | 1806 // Parse all parts, except a potential last one. |
| 1832 for (int i = start; i < end; i++) { | 1807 for (int i = start; i < end; i++) { |
| 1833 if (host.codeUnitAt(i) == _COLON) { | 1808 if (host.codeUnitAt(i) == _COLON) { |
| 1834 if (i == start) { | 1809 if (i == start) { |
| 1835 // If we see a `:` in the beginning, expect wildcard. | 1810 // If we see a `:` in the beginning, expect wildcard. |
| 1836 i++; | 1811 i++; |
| 1837 if (host.codeUnitAt(i) != _COLON) { | 1812 if (host.codeUnitAt(i) != _COLON) { |
| 1838 error('invalid start colon.'); | 1813 error('invalid start colon.', i); |
| 1839 } | 1814 } |
| 1840 partStart = i; | 1815 partStart = i; |
| 1841 } | 1816 } |
| 1842 if (i == partStart) { | 1817 if (i == partStart) { |
| 1843 // Wildcard. We only allow one. | 1818 // Wildcard. We only allow one. |
| 1844 if (wildcardSeen) { | 1819 if (wildcardSeen) { |
| 1845 error('only one wildcard `::` is allowed'); | 1820 error('only one wildcard `::` is allowed', i); |
| 1846 } | 1821 } |
| 1847 wildcardSeen = true; | 1822 wildcardSeen = true; |
| 1848 parts.add(-1); | 1823 parts.add(-1); |
| 1849 } else { | 1824 } else { |
| 1850 // Found a single colon. Parse [partStart..i] as a hex entry. | 1825 // Found a single colon. Parse [partStart..i] as a hex entry. |
| 1851 parts.add(parseHex(partStart, i)); | 1826 parts.add(parseHex(partStart, i)); |
| 1852 } | 1827 } |
| 1853 partStart = i + 1; | 1828 partStart = i + 1; |
| 1854 } | 1829 } |
| 1855 } | 1830 } |
| 1856 if (parts.length == 0) error('too few parts'); | 1831 if (parts.length == 0) error('too few parts'); |
| 1857 bool atEnd = (partStart == end); | 1832 bool atEnd = (partStart == end); |
| 1858 bool isLastWildcard = (parts.last == -1); | 1833 bool isLastWildcard = (parts.last == -1); |
| 1859 if (atEnd && !isLastWildcard) { | 1834 if (atEnd && !isLastWildcard) { |
| 1860 error('expected a part after last `:`'); | 1835 error('expected a part after last `:`', end); |
| 1861 } | 1836 } |
| 1862 if (!atEnd) { | 1837 if (!atEnd) { |
| 1863 try { | 1838 try { |
| 1864 parts.add(parseHex(partStart, end)); | 1839 parts.add(parseHex(partStart, end)); |
| 1865 } catch (e) { | 1840 } catch (e) { |
| 1866 // Failed to parse the last chunk as hex. Try IPv4. | 1841 // Failed to parse the last chunk as hex. Try IPv4. |
| 1867 try { | 1842 try { |
| 1868 List<int> last = parseIPv4Address(host.substring(partStart, end)); | 1843 List<int> last = parseIPv4Address(host.substring(partStart, end)); |
| 1869 parts.add(last[0] << 8 | last[1]); | 1844 parts.add(last[0] << 8 | last[1]); |
| 1870 parts.add(last[2] << 8 | last[3]); | 1845 parts.add(last[2] << 8 | last[3]); |
| 1871 } catch (e) { | 1846 } catch (e) { |
| 1872 error('invalid end of IPv6 address.'); | 1847 error('invalid end of IPv6 address.', partStart); |
| 1873 } | 1848 } |
| 1874 } | 1849 } |
| 1875 } | 1850 } |
| 1876 if (wildcardSeen) { | 1851 if (wildcardSeen) { |
| 1877 if (parts.length > 7) { | 1852 if (parts.length > 7) { |
| 1878 error('an address with a wildcard must have less than 7 parts'); | 1853 error('an address with a wildcard must have less than 7 parts'); |
| 1879 } | 1854 } |
| 1880 } else if (parts.length != 8) { | 1855 } else if (parts.length != 8) { |
| 1881 error('an address without a wildcard must contain exactly 8 parts'); | 1856 error('an address without a wildcard must contain exactly 8 parts'); |
| 1882 } | 1857 } |
| (...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2279 0xafff, // 0x30 - 0x3f 1111111111110101 | 2254 0xafff, // 0x30 - 0x3f 1111111111110101 |
| 2280 // @ABCDEFGHIJKLMNO | 2255 // @ABCDEFGHIJKLMNO |
| 2281 0xffff, // 0x40 - 0x4f 1111111111111111 | 2256 0xffff, // 0x40 - 0x4f 1111111111111111 |
| 2282 // PQRSTUVWXYZ _ | 2257 // PQRSTUVWXYZ _ |
| 2283 0x87ff, // 0x50 - 0x5f 1111111111100001 | 2258 0x87ff, // 0x50 - 0x5f 1111111111100001 |
| 2284 // abcdefghijklmno | 2259 // abcdefghijklmno |
| 2285 0xfffe, // 0x60 - 0x6f 0111111111111111 | 2260 0xfffe, // 0x60 - 0x6f 0111111111111111 |
| 2286 // pqrstuvwxyz ~ | 2261 // pqrstuvwxyz ~ |
| 2287 0x47ff]; // 0x70 - 0x7f 1111111111100010 | 2262 0x47ff]; // 0x70 - 0x7f 1111111111100010 |
| 2288 } | 2263 } |
| OLD | NEW |