Split _uriEncode into JS and VM versions.

R=iposva@google.com, sra@google.com

Review URL: https://codereview.chromium.org/1416373007.
This commit is contained in:
Lasse R.H. Nielsen 2015-11-05 13:00:37 +01:00
parent 2cecb9ec9c
commit b13607d247
3 changed files with 99 additions and 45 deletions

View file

@ -2,6 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import "dart:convert" show ASCII;
// VM implementation of Uri.
typedef Uri _UriBaseClosure();
@ -21,4 +23,51 @@ patch class Uri {
/* patch */ static Uri get base => _uriBaseClosure();
static bool get _isWindowsPlatform native "Uri_isWindowsPlatform";
/* patch */ static String _uriEncode(List<int> canonicalTable,
String text,
Encoding encoding,
bool spaceToPlus) {
// First check if the text will be changed by encoding.
int i = 0;
if (identical(encoding, UTF8) ||
identical(encoding, LATIN1) ||
identical(encoding, ASCII)) {
// Encoding is compatible with the original string.
// Find first character that needs encoding.
for (; i < text.length; i++) {
var char = text.codeUnitAt(i);
if (char >= 128 ||
canonicalTable[char >> 4] & (1 << (char & 0x0f)) == 0) {
break;
}
}
}
if (i == text.length) return text;
// Encode the string into bytes then generate an ASCII only string
// by percent encoding selected bytes.
StringBuffer result = new StringBuffer();
for (int j = 0; j < i; j++) {
result.writeCharCode(text.codeUnitAt(j));
}
// TODO(lrn): Is there a way to only encode from index i and forwards.
var bytes = encoding.encode(text);
for (; 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) {
result.writeCharCode(_PLUS);
} else {
const String hexDigits = '0123456789ABCDEF';
result..writeCharCode(_PERCENT)
..writeCharCode(hexDigits.codeUnitAt(byte >> 4))
..writeCharCode(hexDigits.codeUnitAt(byte & 0x0f));
}
}
return result.toString();
}
}

View file

@ -527,6 +527,47 @@ class Uri {
if (uri != null) return Uri.parse(uri);
throw new UnsupportedError("'Uri.base' is not supported");
}
// Matches a String that _uriEncodes to itself regardless of the kind of
// component. This corresponds to [_unreservedTable], i.e. characters that
// are not encoded by any encoding table.
static final RegExp _needsNoEncoding = new RegExp(r'^[\-\.0-9A-Z_a-z~]*$');
/**
* This is the internal implementation of JavaScript's encodeURI function.
* It encodes all characters in the string [text] except for those
* that appear in [canonicalTable], and returns the escaped string.
*/
@patch
static String _uriEncode(List<int> canonicalTable,
String text,
Encoding encoding,
bool spaceToPlus) {
if (identical(encoding, UTF8) && _needsNoEncoding.hasMatch(text)) {
return text;
}
// 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) {
result.writeCharCode(_PLUS);
} else {
const String hexDigits = '0123456789ABCDEF';
result.writeCharCode(_PERCENT);
result.writeCharCode(hexDigits.codeUnitAt(byte >> 4));
result.writeCharCode(hexDigits.codeUnitAt(byte & 0x0f));
}
}
return result.toString();
}
}
@patch

View file

@ -1243,7 +1243,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) =>
_uriEncode(_pathCharTable, s, UTF8, false)).join("/");
}
if (result.isEmpty) {
if (isFile) return "/";
@ -1953,7 +1954,7 @@ class Uri {
* a [Uri].
*/
static String encodeComponent(String component) {
return _uriEncode(_unreserved2396Table, component);
return _uriEncode(_unreserved2396Table, component, UTF8, false);
}
/**
@ -1991,8 +1992,7 @@ class Uri {
*/
static String encodeQueryComponent(String component,
{Encoding encoding: UTF8}) {
return _uriEncode(
_unreservedTable, component, encoding: encoding, spaceToPlus: true);
return _uriEncode(_unreservedTable, component, encoding, true);
}
/**
@ -2036,7 +2036,7 @@ class Uri {
* the encodeURI function .
*/
static String encodeFull(String uri) {
return _uriEncode(_encodeFullTable, uri);
return _uriEncode(_encodeFullTable, uri, UTF8, false);
}
/**
@ -2252,46 +2252,10 @@ class Uri {
static const int _LOWER_CASE_Z = 0x7A;
static const int _BAR = 0x7C;
// Matches a String that _uriEncodes to itself regardless of the kind of
// component. This corresponds to [_unreservedTable], i.e. characters that
// are not encoded by any encoding table.
static final RegExp _needsNoEncoding = new RegExp(r'^[\-\.0-9A-Z_a-z~]*$');
/**
* This is the internal implementation of JavaScript's encodeURI function.
* It encodes all characters in the string [text] except for those
* that appear in [canonicalTable], and returns the escaped string.
*/
static String _uriEncode(List<int> canonicalTable,
String text,
{Encoding encoding: UTF8,
bool spaceToPlus: false}) {
if (_needsNoEncoding.hasMatch(text)) return text;
byteToHex(byte, buffer) {
const String hex = '0123456789ABCDEF';
buffer.writeCharCode(hex.codeUnitAt(byte >> 4));
buffer.writeCharCode(hex.codeUnitAt(byte & 0x0f));
}
// 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) {
result.writeCharCode(_PLUS);
} else {
result.writeCharCode(_PERCENT);
byteToHex(byte, result);
}
}
return result.toString();
}
external static String _uriEncode(List<int> canonicalTable,
String text,
Encoding encoding,
bool spaceToPlus);
/**
* Convert a byte (2 character hex sequence) in string [s] starting