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 |