Creates a new Uri
object by parsing a URI string.
If start
and end
are provided, only the substring from start
to end
is parsed as a URI.
If the string is not valid as a URI or URI reference, a FormatException is thrown.
Source
static Uri parse(String uri, [int start = 0, int end]) { // This parsing will not validate percent-encoding, IPv6, etc. // When done splitting into parts, it will call, e.g., [_makeFragment] // to do the final parsing. // // Important parts of the RFC 3986 used here: // URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] // // hier-part = "//" authority path-abempty // / path-absolute // / path-rootless // / path-empty // // URI-reference = URI / relative-ref // // absolute-URI = scheme ":" hier-part [ "?" query ] // // relative-ref = relative-part [ "?" query ] [ "#" fragment ] // // relative-part = "//" authority path-abempty // / path-absolute // / path-noscheme // / path-empty // // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) // // authority = [ userinfo "@" ] host [ ":" port ] // userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) // host = IP-literal / IPv4address / reg-name // port = *DIGIT // reg-name = *( unreserved / pct-encoded / sub-delims ) // // path = path-abempty ; begins with "/" or is empty // / path-absolute ; begins with "/" but not "//" // / path-noscheme ; begins with a non-colon segment // / path-rootless ; begins with a segment // / path-empty ; zero characters // // path-abempty = *( "/" segment ) // path-absolute = "/" [ segment-nz *( "/" segment ) ] // path-noscheme = segment-nz-nc *( "/" segment ) // path-rootless = segment-nz *( "/" segment ) // path-empty = 0<pchar> // // segment = *pchar // segment-nz = 1*pchar // segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" ) // ; non-zero-length segment without any colon ":" // // pchar = unreserved / pct-encoded / sub-delims / ":" / "@" // // query = *( pchar / "/" / "?" ) // // fragment = *( pchar / "/" / "?" ) const int EOI = -1; String scheme = ""; String userinfo = ""; String host = null; int port = null; String path = null; String query = null; String fragment = null; if (end == null) end = uri.length; int index = start; int pathStart = start; // End of input-marker. int char = EOI; void parseAuth() { if (index == end) { char = EOI; return; } int authStart = index; int lastColon = -1; int lastAt = -1; char = uri.codeUnitAt(index); while (index < end) { char = uri.codeUnitAt(index); if (char == _SLASH || char == _QUESTION || char == _NUMBER_SIGN) { break; } if (char == _AT_SIGN) { lastAt = index; lastColon = -1; } else if (char == _COLON) { lastColon = index; } else if (char == _LEFT_BRACKET) { lastColon = -1; int endBracket = uri.indexOf(']', index + 1); if (endBracket == -1) { index = end; char = EOI; break; } else { index = endBracket; } } index++; char = EOI; } int hostStart = authStart; int hostEnd = index; if (lastAt >= 0) { userinfo = _makeUserInfo(uri, authStart, lastAt); hostStart = lastAt + 1; } if (lastColon >= 0) { int portNumber; if (lastColon + 1 < index) { portNumber = 0; for (int i = lastColon + 1; i < index; i++) { int digit = uri.codeUnitAt(i); if (_ZERO > digit || _NINE < digit) { _fail(uri, i, "Invalid port number"); } portNumber = portNumber * 10 + (digit - _ZERO); } } port = _makePort(portNumber, scheme); hostEnd = lastColon; } host = _makeHost(uri, hostStart, hostEnd, true); if (index < end) { char = uri.codeUnitAt(index); } } // When reaching path parsing, the current character is known to not // be part of the path. const int NOT_IN_PATH = 0; // When reaching path parsing, the current character is part // of the a non-empty path. const int IN_PATH = 1; // When reaching authority parsing, authority is possible. // This is only true at start or right after scheme. const int ALLOW_AUTH = 2; // Current state. // Initialized to the default value that is used when exiting the // scheme loop by reaching the end of input. // All other breaks set their own state. int state = NOT_IN_PATH; int i = index; // Temporary alias for index to avoid bug 19550 in dart2js. while (i < end) { char = uri.codeUnitAt(i); if (char == _QUESTION || char == _NUMBER_SIGN) { state = NOT_IN_PATH; break; } if (char == _SLASH) { state = (i == start) ? ALLOW_AUTH : IN_PATH; break; } if (char == _COLON) { if (i == start) _fail(uri, start, "Invalid empty scheme"); scheme = _makeScheme(uri, start, i); i++; if (scheme == "data") { // This generates a URI that is (potentially) not path normalized. // Applying part normalization to a non-hierarchial URI isn't // meaningful. return UriData._parse(uri, i, null).uri; } pathStart = i; if (i == end) { char = EOI; state = NOT_IN_PATH; } else { char = uri.codeUnitAt(i); if (char == _QUESTION || char == _NUMBER_SIGN) { state = NOT_IN_PATH; } else if (char == _SLASH) { state = ALLOW_AUTH; } else { state = IN_PATH; } } break; } i++; char = EOI; } index = i; // Remove alias when bug is fixed. if (state == ALLOW_AUTH) { assert(char == _SLASH); // Have seen one slash either at start or right after scheme. // If two slashes, it's an authority, otherwise it's just the path. index++; if (index == end) { char = EOI; state = NOT_IN_PATH; } else { char = uri.codeUnitAt(index); if (char == _SLASH) { index++; parseAuth(); pathStart = index; } if (char == _QUESTION || char == _NUMBER_SIGN || char == EOI) { state = NOT_IN_PATH; } else { state = IN_PATH; } } } assert(state == IN_PATH || state == NOT_IN_PATH); if (state == IN_PATH) { // Characters from pathStart to index (inclusive) are known // to be part of the path. while (++index < end) { char = uri.codeUnitAt(index); if (char == _QUESTION || char == _NUMBER_SIGN) { break; } char = EOI; } state = NOT_IN_PATH; } assert(state == NOT_IN_PATH); bool hasAuthority = (host != null); path = _makePath(uri, pathStart, index, null, scheme, hasAuthority); if (char == _QUESTION) { int numberSignIndex = -1; for (int i = index + 1; i < end; i++) { if (uri.codeUnitAt(i) == _NUMBER_SIGN) { numberSignIndex = i; break; } } if (numberSignIndex < 0) { query = _makeQuery(uri, index + 1, end, null); } else { query = _makeQuery(uri, index + 1, numberSignIndex, null); fragment = _makeFragment(uri, numberSignIndex + 1, end); } } else if (char == _NUMBER_SIGN) { fragment = _makeFragment(uri, index + 1, end); } return new Uri._internal(scheme, userinfo, host, port, path, query, fragment); }