Chromium Code Reviews| Index: sdk/lib/core/uri.dart |
| diff --git a/sdk/lib/core/uri.dart b/sdk/lib/core/uri.dart |
| index 10aa827cb190c6e93a8889cad67312629145d5f5..bd4d1a1e9e3e4dd81168bec83eb937966a41e110 100644 |
| --- a/sdk/lib/core/uri.dart |
| +++ b/sdk/lib/core/uri.dart |
| @@ -1242,7 +1242,8 @@ class Uri { |
| if (path != null) { |
| result = _normalize(path, start, end, _pathCharOrSlashTable); |
| } else { |
| - result = pathSegments.map((s) => _uriEncode(_pathCharTable, s)).join("/"); |
| + result = pathSegments.map((s) => |
| + _uriEncodeUtf8(_pathCharTable, s, false)).join("/"); |
| } |
| if (result.isEmpty) { |
| if (isFile) return "/"; |
| @@ -1952,7 +1953,7 @@ class Uri { |
| * a [Uri]. |
| */ |
| static String encodeComponent(String component) { |
| - return _uriEncode(_unreserved2396Table, component); |
| + return _uriEncodeUtf8(_unreserved2396Table, component, false); |
| } |
| /** |
| @@ -1990,8 +1991,9 @@ class Uri { |
| */ |
| static String encodeQueryComponent(String component, |
| {Encoding encoding: UTF8}) { |
| + const int spaceToPlus = true; |
|
sra1
2015/11/03 17:28:42
checked mode error
|
| return _uriEncode( |
| - _unreservedTable, component, encoding: encoding, spaceToPlus: true); |
| + _unreservedTable, component, encoding, spaceToPlus); |
| } |
| /** |
| @@ -2035,7 +2037,7 @@ class Uri { |
| * the encodeURI function . |
| */ |
| static String encodeFull(String uri) { |
| - return _uriEncode(_encodeFullTable, uri); |
| + return _uriEncodeUtf8(_encodeFullTable, uri, false); |
| } |
| /** |
| @@ -2241,6 +2243,7 @@ class Uri { |
| static const int _QUESTION = 0x3F; |
| static const int _AT_SIGN = 0x40; |
| static const int _UPPER_CASE_A = 0x41; |
| + static const int _UPPER_CASE_E = 0x45; |
| static const int _UPPER_CASE_F = 0x46; |
| static const int _UPPER_CASE_Z = 0x5A; |
| static const int _LEFT_BRACKET = 0x5B; |
| @@ -2251,6 +2254,8 @@ class Uri { |
| static const int _LOWER_CASE_Z = 0x7A; |
| static const int _BAR = 0x7C; |
| + static const String _hexDigits = "0123456789ABCDEF"; |
| + |
| /** |
| * This is the internal implementation of JavaScript's encodeURI function. |
| * It encodes all characters in the string [text] except for those |
| @@ -2258,28 +2263,205 @@ class Uri { |
| */ |
| static String _uriEncode(List<int> canonicalTable, |
| String text, |
| - {Encoding encoding: UTF8, |
| - bool spaceToPlus: false}) { |
| - byteToHex(byte, buffer) { |
| - const String hex = '0123456789ABCDEF'; |
| - buffer.writeCharCode(hex.codeUnitAt(byte >> 4)); |
| - buffer.writeCharCode(hex.codeUnitAt(byte & 0x0f)); |
| + Encoding encoding, |
| + bool spaceToPlus) { |
| + // Use a specialized encoder for known Unicode-compatible encodings. |
| + // This avoids encoding the string first and then working on the bytes, |
| + // and instead works directly on the code units of the string. |
| + if (identical(encoding, UTF8)) { |
| + return _uriEncodeUtf8(canonicalTable, text, spaceToPlus); |
| + } |
| + if (identical(encoding, LATIN1)) { |
| + return _uriEncodeSubset(canonicalTable, text, 255, spaceToPlus); |
| + } |
| + if (identical(encoding, ASCII)) { |
| + return _uriEncodeSubset(canonicalTable, text, 127, spaceToPlus); |
| } |
| // Encode the string into bytes then generate an ASCII only string |
| // by percent encoding selected bytes. |
| - StringBuffer result = new StringBuffer(); |
| var bytes = encoding.encode(text); |
| - for (int i = 0; i < bytes.length; i++) { |
| - int byte = bytes[i]; |
| - if (byte < 128 && |
| - ((canonicalTable[byte >> 4] & (1 << (byte & 0x0f))) != 0)) { |
| - result.writeCharCode(byte); |
| - } else if (spaceToPlus && byte == _SPACE) { |
| + int i = 0; |
| + noChange: { |
| + while (i < bytes.length) { |
| + int byte = bytes[i]; |
| + if (byte < 128 && |
| + ((canonicalTable[byte >> 4] & (1 << (byte & 0x0f))) != 0)) { |
| + break noChange; |
| + } |
| + i++; |
| + } |
| + return text; |
| + } |
| + StringBuffer result = new StringBuffer(); |
| + for (int j = 0; j < i; j++) { |
| + result[j] = text.codeUnitAt(j); |
|
sra1
2015/11/03 17:28:42
StringBuffer does not have []=.
Lasse Reichstein Nielsen
2015/11/03 18:04:08
Duh, should be writeCharCode.
Obviously needs mor
|
| + } |
| + while (true) { |
| + if (spaceToPlus && char == _SPACE) { |
| result.writeCharCode(_PLUS); |
| } else { |
| - result.writeCharCode(_PERCENT); |
| - byteToHex(byte, result); |
| + result..writeCharCode(_PERCENT) |
| + ..writeCharCode(_hexDigits.codeUnitAt(char >> 4)) |
| + ..writeCharCode(_hexDigits.codeUnitAt(char & 0xF)); |
| + } |
| + noChange: { // See dartbug.com/21481 |
| + while (++i < text.length) { |
| + char = text.codeUnitAt(i); |
| + if (char < 128 && |
| + (canonicalTable[char >> 4] & (1 << (char & 0xf)) != 0)) { |
| + result.writeCharCode(char); |
| + } else { |
| + break noChange; |
| + } |
| + } |
| + break; |
| + } |
| + } |
| + return result.toString(); |
| + } |
| + |
| + /** |
| + * Encodes a text where the encoding is a subset of Unicode. |
| + * |
| + * The subsets are either Latin-1 or US-ASCII, and they are distinguished |
| + * by the [limit] parameter which is the maximal code point allowed |
| + * by the encoding. |
| + */ |
| + static String _uriEncodeSubset(List<int> canonicalTable, String text, |
| + int limit, bool spaceToPlus) { |
| + assert(limit == 127 || limit == 255); |
| + int i = 0; |
| + int char; |
| + noChange: { // See dartbug.com/21481 |
| + while (i < text.length) { |
| + char = text.codeUnitAt(i); |
| + if (char >= 128 || |
| + (canonicalTable[char >> 4] & (1 << (char & 0xf)) == 0)) { |
| + break noChange; |
| + } |
| + i++; |
| + } |
| + return text; |
| + } |
| + StringBuffer result = new StringBuffer(); |
| + for (int j = 0; j < i; j++) { |
| + result.writeCharCode(text.codeUnitAt(j)); |
| + } |
| + while (true) { |
| + if (char <= limit) { |
| + if (spaceToPlus && char == _SPACE) { |
| + result.writeCharCode(_PLUS); |
| + } else { |
| + result..writeCharCode(_PERCENT) |
| + ..writeCharCode(_hexDigits.codeUnitAt(char >> 4)) |
| + ..writeCharCode(_hexDigits.codeUnitAt(char & 0xF)); |
| + } |
| + } else { |
| + if (limit == 255) { |
| + throw new ArgumentError.value( |
| + text, "Source contains non-Latin-1 characters."); |
| + } |
| + throw new ArgumentError.value( |
| + text, "Source contains non-ASCII bytes."); |
| + } |
| + noChange: { // See dartbug.com/21481 |
| + while (++i < text.length) { |
| + char = text.codeUnitAt(i); |
| + if (char < 128 && |
| + (canonicalTable[char >> 4] & (1 << (char & 0xf)) != 0)) { |
| + result.writeCharCode(char); |
| + } else { |
| + break noChange; |
| + } |
| + } |
| + break; |
| + } |
| + } |
| + return result.toString(); |
| + } |
| + |
| + static String _uriEncodeUtf8(List<int> canonicalTable, String text, |
| + bool spaceToPlus) { |
| + int i = 0; |
| + int char; |
| + noChange: { // See dartbug.com/21481 |
| + while (i < text.length) { |
| + char = text.codeUnitAt(i); |
| + if (char >= 128 || |
| + (canonicalTable[char >> 4] & (1 << (char & 0xf)) == 0)) { |
| + break noChange; |
| + } |
| + i++; |
| + } |
| + return text; |
| + } |
| + StringBuffer result = new StringBuffer(); |
| + for (int j = 0; j < i; j++) { |
| + result.writeCharCode(text.codeUnitAt(j)); |
| + } |
| + while (true) { |
| + if (char < 128) { |
| + if (spaceToPlus && char == _SPACE) { |
| + result.writeCharCode(_PLUS); |
| + } else { |
| + result..writeCharCode(_PERCENT) |
| + ..writeCharCode(_ZERO + (char >> 4)) // Range 0-7. |
| + ..writeCharCode(_hexDigits.codeUnitAt(char & 0x0F)); |
| + } |
| + } else if (char < 0x800) { |
| + result..writeCharCode(_PERCENT) |
| + ..writeCharCode(_hexDigits.codeUnitAt(0xC + (char >> 10))) |
| + ..writeCharCode(_hexDigits.codeUnitAt((char >> 6) & 0xF)) |
| + ..writeCharCode(_PERCENT) |
| + ..writeCharCode(_hexDigits.codeUnitAt(0x8 + ((char >> 4) & 3))) |
| + ..writeCharCode(_hexDigits.codeUnitAt(char & 0xF)); |
| + } else { |
| + assert(char < 0x10000); // UTF-16 code unit. |
| + int next; |
| + if (char & 0xFC00 != 0xD800 || |
| + i + 1 == text.length || |
| + (next = text.codeUnitAt(i + 1)) & 0xFC00 != 0xDC00) { |
| + result..writeCharCode(_PERCENT) |
| + ..writeCharCode(_UPPER_CASE_E) |
| + ..writeCharCode(_hexDigits.codeUnitAt((char >> 12) & 0xF)) |
| + ..writeCharCode(_PERCENT) |
| + ..writeCharCode(_hexDigits.codeUnitAt(0x8 + ((char >> 10) & 3))) |
| + ..writeCharCode(_hexDigits.codeUnitAt((char >> 6) & 0xF)) |
| + ..writeCharCode(_PERCENT) |
| + ..writeCharCode(_hexDigits.codeUnitAt(0x8 + ((char >> 4) & 3))) |
| + ..writeCharCode(_hexDigits.codeUnitAt(char & 0xF)); |
| + } else { |
| + // Lead surrogate followed by tail surrogate. |
| + char = 0x10000 + (((char & 0x3FF) << 10) | (next & 0x3FF)); |
| + i++; |
| + result..writeCharCode(_PERCENT) |
| + ..writeCharCode(_UPPER_CASE_F) |
| + ..writeCharCode(_ZERO + (char >> 18)) // Range 0..7 |
| + ..writeCharCode(_PERCENT) |
| + ..writeCharCode(_hexDigits.codeUnitAt(0x8 + ((char >> 16) & 3))) |
| + ..writeCharCode(_hexDigits.codeUnitAt((char >> 12) & 0xF)) |
| + ..writeCharCode(_PERCENT) |
| + ..writeCharCode(_hexDigits.codeUnitAt(0x8 + ((char >> 10) & 3))) |
| + ..writeCharCode(_hexDigits.codeUnitAt((char >> 6) & 0xF)) |
| + ..writeCharCode(_PERCENT) |
| + ..writeCharCode(_hexDigits.codeUnitAt(0x8 + ((char >> 4) & 3))) |
| + ..writeCharCode(_hexDigits.codeUnitAt(char & 0xF)); |
| + } |
| + } |
| + noChange: { // See dartbug.com/21481 |
| + while (++i < text.length) { |
| + char = text.codeUnitAt(i); |
| + if (char < 128 && |
| + (canonicalTable[char >> 4] & (1 << (char & 0xf)) != 0)) { |
| + result.writeCharCode(char); |
| + } else { |
| + break noChange; |
| + } |
| + } |
| + // Return result.toString(), but move the return to the end of the |
| + // function to appease analysis. |
| + break; |
| } |
| } |
| return result.toString(); |