Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(490)

Side by Side Diff: sdk/lib/core/uri.dart

Issue 16019002: Merge the dart:uri library into dart:core and update the Uri class (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Add missing files Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 part of dart.core;
6
7 /**
8 * A parsed URI, as specified by RFC-3986, http://tools.ietf.org/html/rfc3986.
9 */
10 class Uri {
11 int _port;
12
13 /*
14 * Returns the URI scheme. If there is no scheme the empty string
floitsch 2013/05/24 20:37:27 All these comments are dartdocs. -> /** instead of
Søren Gjesse 2013/05/27 10:47:21 Of cause - thanks.
15 * will be returned.
floitsch 2013/05/24 20:37:27 No need for future. If there is no scheme the empt
Søren Gjesse 2013/05/27 10:47:21 Done. Similar change for all Uri component proper
16 */
17 final String scheme;
18
19 /*
20 * Returns the user info part of the URI authority. If there is no
21 * user info in the authority the empty string will be returned.
22 */
23 final String userInfo;
24
25 /*
26 * Returns the host part of the URI authority. If there is no
27 * authority and hence no host the empty string will be returned.
28 */
29 final String host;
30
31 /*
32 * Returns the port part of the URI authority. If there is no
33 * port in the authority 0 will be returned.
34 */
35 int get port => _port;
36
37 /*
38 * Returns the URI path. The returned path is encoded. To get direct
39 * access to the decoded path use [pathSegement]. If there is no
floitsch 2013/05/24 20:37:27 pathSegments
Søren Gjesse 2013/05/27 10:47:21 Done.
40 * path the empty string will be returned.
41 */
42 final String path;
43
44 /*
45 * Returns the URI query. The returned query is encoded. To get
46 * direct access to the decoded query use [queryParameters]. If
47 * there is no query the empty string will be returned.
48 */
49 final String query;
50
51 /*
52 * Returns the URI fragment. If there is no fragment the empty string
53 * will be returned.
54 */
55 final String fragment;
56
57 /**
58 * Creates a new URI object by parsing a URI string.
59 */
60 static Uri parse(String uri) => new Uri._fromMatch(_splitRe.firstMatch(uri));
61
62 Uri._fromMatch(Match m) :
63 this(scheme: _emptyIfNull(m[_COMPONENT_SCHEME]),
64 userInfo: _emptyIfNull(m[_COMPONENT_USER_INFO]),
65 host: _eitherOf(
66 m[_COMPONENT_HOST], m[_COMPONENT_HOST_IPV6]),
67 port: _parseIntOrZero(m[_COMPONENT_PORT]),
68 path: _emptyIfNull(m[_COMPONENT_PATH]),
69 query: _emptyIfNull(m[_COMPONENT_QUERY_DATA]),
70 fragment: _emptyIfNull(m[_COMPONENT_FRAGMENT]));
71
72 /*
73 * Create a new URI from its components.
74 *
75 * The URI scheme is set through [scheme]. The scheme will be
76 * normalized to all lowercase letters.
77 *
78 * The URI user info of the domain is set through [userInfo].
79 *
80 * The URI host part of the domain is set through [host]. The host
81 * can either be a hostname, a IPv4 address or an IPv6 address,
82 * contained in '[' and ']'. If the host contains a ':' character,
83 * the host will have the '[' and ']' added.
84 *
85 * The URI port is set through [port]. The port is normalized for
86 * scheme http and https where port 80 and port 443 respectively
87 * will be set as 0.
floitsch 2013/05/24 20:37:27 is set to 0.
Søren Gjesse 2013/05/27 10:47:21 This was a broken sentence. Removed the "as 0" fro
88 *
89 * The path component can be specified using either [path] or
90 * [pathSegments]. When [path] is used the provided string is
91 * expected to be fully percent-encoded and will be used in its
floitsch 2013/05/24 20:37:27 is used
Søren Gjesse 2013/05/27 10:47:21 Done.
92 * literal form for the URI path. When [pathSegments] is used each
93 * of the provided segments will be percent encoded and joined using
94 * the forward slash separator.
95 *
96 * The query component can be specified using either [query] or
97 * [queryParameters]. When [query] is used the provided string is
98 * expected to be fully percent-encoded and will be used in its
99 * literal form for the URI query. When [queryParameters] is used xxx
floitsch 2013/05/24 20:37:27 xxx
Søren Gjesse 2013/05/27 10:47:21 My mark of unfinished comment - sorry.
100 *
101 * The URI fragment is set through [fragment].
102 */
103 Uri({scheme,
104 this.userInfo: "",
105 this.host: "",
106 port: 0,
107 String path,
108 List<String> pathSegments,
109 String query,
110 Map<String, String> queryParameters,
111 fragment: ""}) :
112 scheme = _makeScheme(scheme),
113 path = _makePath(path, pathSegments),
114 query = _makeQuery(query, queryParameters),
115 fragment = _makeFragment(fragment) {
116 // Perform scheme specific normalization.
117 if (scheme == "http" && port == 80) {
118 _port = 0;
119 } else if (scheme == "https" && port == 443) {
120 _port = 0;
121 } else {
122 _port = port;
123 }
124 }
125
126 /*
127 * Returns the URI path split into its segments. Each of the
128 * segments in the returned list have been decoded. If the path is
129 * empty the empty list will be returned.
130 */
131 List<String> get pathSegments {
132 if (path == "") return [];
floitsch 2013/05/24 20:37:27 const <String>[]; ?
Søren Gjesse 2013/05/27 10:47:21 Done.
133 return path.split("/").map(Uri.decodeComponent).toList(growable: false);
134 }
135
136 /*
137 * Returns the URI query split into a map according to the rules
138 * specified for FORM post in the HTML 4.01 specification. Each key
139 * and value in the returned map have been decoded. If there is no
140 * query the empty map will be returned.
141 */
142 Map<String, String> get queryParameters {
143 return query.split("&").fold({}, (map, element) {
144 int index = element.indexOf("=");
145 if (index == -1) {
146 if (!element.isEmpty) map[element] = "";
147 } else if (index != 0) {
148 var key = element.substring(0, index);
149 var value = element.substring(index + 1, element.length);
floitsch 2013/05/24 20:37:27 substring doesn't need the second argument if it i
Søren Gjesse 2013/05/27 10:47:21 Done.
150 map[Uri.decodeQueryComponent(key)] = decodeQueryComponent(value);
151 }
152 return map;
153 });
154 }
155
156 static String _makeScheme(String scheme) {
157 bool isSchemeLowerCharacter(int ch) {
158 return ch < 128 &&
159 ((_schemeLowerTable[ch >> 4] & (1 << (ch & 0x0f))) != 0);
160 }
161
162 bool isSchemeCharacter(int ch) {
163 return ch < 128 && ((_schemeTable[ch >> 4] & (1 << (ch & 0x0f))) != 0);
164 }
165
166 if (scheme == null) return "";
167 bool allLowercase = true;
168 int length = scheme.length;
169 for (int i = 0; i < length; i++) {
170 int codeUnit = scheme.codeUnitAt(i);
171 if (!isSchemeLowerCharacter(codeUnit)) {
172 if (isSchemeCharacter(codeUnit)) {
173 allLowercase = false;
174 } else {
175 throw new ArgumentError('Illegal scheme');
floitsch 2013/05/24 20:37:27 Add the scheme: 'Illegal scheme: $scheme'.
Søren Gjesse 2013/05/27 10:47:21 Done.
176 }
177 }
178 }
179
180 return allLowercase ? scheme : scheme.toLowerCase();
181 }
182
183 static String _makePath(String path, List<String> pathSegments) {
184 if (path == null && pathSegments == null) return "";
185 if (path != null && pathSegments != null) {
186 throw new ArgumentError('Both path and pathSegments specified');
187 }
188 if (path != null) return _normalize(path);
189
190 return pathSegments.map((s) => _uriEncode(_pathCharTable, s)).join("/");
191 }
192
193 static String _makeQuery(String query, Map<String, String> queryParameters) {
194 if (query == null && queryParameters == null) return "";
195 if (query != null && queryParameters != null) {
196 throw new ArgumentError('Both query and queryParameters specified');
197 }
198 if (query != null) return _normalize(query);
199
200 var result = new StringBuffer();
201 var first = true;
202 queryParameters.forEach((key, value) {
203 if (!first) {
204 result.write("&");
205 }
206 first = false;
207 result.write(Uri.encodeQueryComponent(key));
208 if (value != null && !value.isEmpty) {
209 result.write("=");
210 result.write(Uri.encodeQueryComponent(value));
211 }
212 });
213 return result.toString();
214 }
215
216 static String _makeFragment(String fragment) {
217 if (fragment == null) return "";
218 return _normalize(fragment);
219 }
220
221 static String _normalize(String component) {
222 bool isNormalizedHexDigit(int digit) {
223 return (_CharCode.ZERO <= digit && digit <= _CharCode.NINE) ||
224 (_CharCode.UPPER_CASE_A <= digit && digit <= _CharCode.UPPER_CASE_F);
225 }
226
227 bool isLowerCaseHexDigit(int digit) {
228 return _CharCode.LOWER_CASE_A <= digit && digit <= _CharCode.LOWER_CASE_F;
229 }
230
231 bool isUnreserved(int ch) {
232 return ch < 128 &&
233 ((_unreservedTable[ch >> 4] & (1 << (ch & 0x0f))) != 0);
234 }
235
236 int normalizeHexDigit(int index) {
237 var codeUnit = component.codeUnitAt(index);
238 if (isLowerCaseHexDigit(codeUnit)) {
239 return codeUnit - 0x20;
240 } else if (!isNormalizedHexDigit(codeUnit)) {
241 throw new ArgumentError("Invalid URI component");
242 } else {
243 return codeUnit;
244 }
245 }
246
247 int decodeHexDigitPair(int index) {
248 int byte = 0;
249 for (int i = 0; i < 2; i++) {
250 var codeUnit = component.codeUnitAt(index + i);
251 if (_CharCode.ZERO <= codeUnit && codeUnit <= _CharCode.NINE) {
252 byte = byte * 16 + codeUnit - _CharCode.ZERO;
253 } else {
254 // Check ranges A-F (0x41-0x46) and a-f (0x61-0x66).
255 codeUnit |= 0x20;
256 if (_CharCode.LOWER_CASE_A <= codeUnit &&
257 codeUnit <= _CharCode.LOWER_CASE_F) {
258 byte = byte * 16 + codeUnit - 0x57;
floitsch 2013/05/24 20:37:27 what's 0x57?
Søren Gjesse 2013/05/27 10:47:21 LOWERCASE_A - 10 Change the code to which should
259 } else {
260 throw new ArgumentError("Invalid URI encoding");
floitsch 2013/05/24 20:37:27 add reason.
Søren Gjesse 2013/05/27 10:47:21 Done.
261 }
262 }
263 }
264 return byte;
265 }
266
267 // Start building the normalized component string.
268 StringBuffer result;
269 int length = component.length;
270 int index = 0;
271 int prevIndex = 0;
272 while (index < length) {
273
274 // Copy a part of the component string to the result.
275 fillResult() {
276 if (result == null) {
277 assert(prevIndex == 0);
278 result = new StringBuffer(component.substring(prevIndex, index));
279 } else {
280 result.write(component.substring(prevIndex, index));
281 }
282 }
283
284 // Normalize percent encoding to uppercase and don't encode
285 // unreserved characters.
286 if (component.codeUnitAt(index) == _CharCode.PERCENT) {
287 if (length < index + 2) {
288 throw new ArgumentError("Invalid Uri component");
floitsch 2013/05/24 20:37:27 add reason.
Søren Gjesse 2013/05/27 10:47:21 Done.
289 }
290
291 var codeUnit1 = component.codeUnitAt(index + 1);
292 var codeUnit2 = component.codeUnitAt(index + 2);
293 var decodedCodeUnit = decodeHexDigitPair(index + 1);
294 if (isNormalizedHexDigit(codeUnit1) &&
295 isNormalizedHexDigit(codeUnit2) &&
296 !isUnreserved(decodedCodeUnit)) {
297 index += 3;
298 } else {
299 fillResult();
300 if (isUnreserved(decodedCodeUnit)) {
301 result.writeCharCode(decodedCodeUnit);
302 } else {
303 result.write("%");
304 result.writeCharCode(normalizeHexDigit(index + 1));
305 result.writeCharCode(normalizeHexDigit(index + 2));
306 }
307 index += 3;
308 prevIndex = index;
309 }
310 } else {
311 index++;
312 }
313 }
314 assert(index == length);
315
316 if (result == null) return component;
317 return result.toString();
318 }
319
320 static String _emptyIfNull(String val) => val != null ? val : '';
321
322 static int _parseIntOrZero(String val) {
323 if (val != null && val != '') {
324 return int.parse(val);
325 } else {
326 return 0;
327 }
328 }
329
330 static String _eitherOf(String val1, String val2) {
331 if (val1 != null) return val1;
332 if (val2 != null) return val2;
333 return '';
334 }
335
336 // NOTE: This code was ported from: closure-library/closure/goog/uri/utils.js
337 static final RegExp _splitRe = new RegExp(
338 '^'
339 '(?:'
340 '([^:/?#.]+)' // scheme - ignore special characters
341 // used by other URL parts such as :,
342 // ?, /, #, and .
343 ':)?'
344 '(?://'
345 '(?:([^/?#]*)@)?' // userInfo
346 '(?:'
347 r'([\w\d\-\u0100-\uffff.%]*)'
348 // host - restrict to letters,
349 // digits, dashes, dots, percent
350 // escapes, and unicode characters.
351 '|'
352 // TODO(ajohnsen): Only allow a max number of parts?
353 r'\[([A-Fa-f0-9:.]*)\])'
354 // IPv6 host - restrict to hex,
355 // dot and colon.
356 '(?::([0-9]+))?' // port
357 ')?'
358 r'([^?#[]+)?' // path
359 r'(?:\?([^#]*))?' // query
360 '(?:#(.*))?' // fragment
361 r'$');
362
363 static const _COMPONENT_SCHEME = 1;
364 static const _COMPONENT_USER_INFO = 2;
365 static const _COMPONENT_HOST = 3;
366 static const _COMPONENT_HOST_IPV6 = 4;
367 static const _COMPONENT_PORT = 5;
368 static const _COMPONENT_PATH = 6;
369 static const _COMPONENT_QUERY_DATA = 7;
370 static const _COMPONENT_FRAGMENT = 8;
371
372 /**
373 * Returns `true` if the URI is absolute.
374 */
375 bool get isAbsolute {
376 if ("" == scheme) return false;
377 if ("" != fragment) return false;
378 return true;
379
380 /* absolute-URI = scheme ":" hier-part [ "?" query ]
floitsch 2013/05/24 20:37:27 why is this comment here?
Søren Gjesse 2013/05/27 10:47:21 It was there in the dart:uri library. Removed it.
381 * hier-part = "//" authority path-abempty
382 * / path-absolute
383 * / path-rootless
384 * / path-empty
385 *
386 * path = path-abempty ; begins with "/" or is empty
387 * / path-absolute ; begins with "/" but not "//"
388 * / path-noscheme ; begins with a non-colon segment
389 * / path-rootless ; begins with a segment
390 * / path-empty ; zero characters
391 *
392 * path-abempty = *( "/" segment )
393 * path-absolute = "/" [ segment-nz *( "/" segment ) ]
394 * path-noscheme = segment-nz-nc *( "/" segment )
395 * path-rootless = segment-nz *( "/" segment )
396 * path-empty = 0<pchar>
397 * segment = *pchar
398 * segment-nz = 1*pchar
399 * segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
400 * ; non-zero-length segment without any colon ":"
401 *
402 * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
403 */
404 }
405
406 Uri resolve(String uri) {
407 return resolveUri(Uri.parse(uri));
408 }
409
410 Uri resolveUri(Uri reference) {
411 // From RFC 3986.
412 String targetScheme;
413 String targetUserInfo;
414 String targetHost;
415 int targetPort;
416 String targetPath;
417 String targetQuery;
418 if (reference.scheme != "") {
419 targetScheme = reference.scheme;
420 targetUserInfo = reference.userInfo;
421 targetHost = reference.host;
422 targetPort = reference.port;
423 targetPath = removeDotSegments(reference.path);
424 targetQuery = reference.query;
425 } else {
426 if (reference.hasAuthority) {
427 targetUserInfo = reference.userInfo;
428 targetHost = reference.host;
429 targetPort = reference.port;
430 targetPath = removeDotSegments(reference.path);
431 targetQuery = reference.query;
432 } else {
433 if (reference.path == "") {
434 targetPath = this.path;
435 if (reference.query != "") {
436 targetQuery = reference.query;
437 } else {
438 targetQuery = this.query;
439 }
440 } else {
441 if (reference.path.startsWith("/")) {
442 targetPath = removeDotSegments(reference.path);
443 } else {
444 targetPath = removeDotSegments(merge(this.path, reference.path));
445 }
446 targetQuery = reference.query;
447 }
448 targetUserInfo = this.userInfo;
449 targetHost = this.host;
450 targetPort = this.port;
451 }
452 targetScheme = this.scheme;
453 }
454 return new Uri(scheme: targetScheme,
455 userInfo: targetUserInfo,
floitsch 2013/05/24 20:37:27 indentation.
Søren Gjesse 2013/05/27 10:47:21 Done.
456 host: targetHost,
457 port: targetPort,
458 path: targetPath,
459 query: targetQuery,
460 fragment: reference.fragment);
461 }
462
463 bool get hasAuthority {
464 return (userInfo != "") || (host != "") || (port != 0);
floitsch 2013/05/24 20:37:27 why is the authority linked to a non-zery port?
Søren Gjesse 2013/05/27 10:47:21 Good catch! An authority always have a host. Chan
465 }
466
467 /**
468 * For http/https schemes returns URI's [origin][] - scheme://host:port.
floitsch 2013/05/24 20:37:27 Returns the URI's [origin][] for http/https scheme
Søren Gjesse 2013/05/27 10:47:21 Done.
469 * For all other schemes throws StateError.
470 * [origin]: http://www.w3.org/TR/2011/WD-html5-20110405/origin-0.html#origin
471 */
472 String get origin {
473 if (scheme == "") {
474 throw new StateError("Cannot use origin without a scheme");
floitsch 2013/05/24 20:37:27 give information: "Cannot use origin without a sch
Søren Gjesse 2013/05/27 10:47:21 Done.
475 }
476 if (scheme != "http" && scheme != "https") {
477 throw new StateError(
478 "origin is applicable to http/https schemes only. Not \'$scheme\'");
479 }
480 StringBuffer sb = new StringBuffer();
481 sb.write(scheme);
482 sb.write(":");
483 if (host == null || host == "") {
floitsch 2013/05/24 20:37:27 Move check up to the checks.
Søren Gjesse 2013/05/27 10:47:21 Done.
484 throw new StateError("Cannot use origin without a host");
485 }
486
487 sb.write("//");
488 sb.write(host);
489 if (port != 0) {
490 sb.write(":");
491 sb.write(port);
492 }
493 return sb.toString();
floitsch 2013/05/24 20:37:27 No need for StringBuffers. if (port == 0) return "
Søren Gjesse 2013/05/27 10:47:21 Good point. Changed.
494 }
495
496 String toString() {
497 StringBuffer sb = new StringBuffer();
498 _addIfNonEmpty(sb, scheme, scheme, ':');
499 if (hasAuthority || (scheme == "file")) {
500 sb.write("//");
501 _addIfNonEmpty(sb, userInfo, userInfo, "@");
502 sb.write(host == null ? "null" :
503 host.contains(':') ? '[$host]' : host);
504 if (port != 0) {
505 sb.write(":");
506 sb.write(port.toString());
507 }
508 }
509 sb.write(path == null ? "null" : path);
floitsch 2013/05/24 20:37:27 isn't the path null-check redundant?
Søren Gjesse 2013/05/27 10:47:21 It is - removed.
510 _addIfNonEmpty(sb, query, "?", query);
511 _addIfNonEmpty(sb, fragment, "#", fragment);
512 return sb.toString();
513 }
514
515 bool operator==(other) {
516 if (other is! Uri) return false;
517 Uri uri = other;
518 return scheme == uri.scheme &&
519 userInfo == uri.userInfo &&
520 host == uri.host &&
521 port == uri.port &&
522 path == uri.path &&
523 query == uri.query &&
524 fragment == uri.fragment;
525 }
526
527 int get hashCode {
528 int combine(part, current) {
529 // The sum is truncated to 30 bits to make sure it fits into a Smi.
530 return (current * 31 + part.hashCode) & 0x3FFFFFFF;
531 }
532 return combine(scheme, combine(userInfo, combine(host, combine(port,
533 combine(path, combine(query, combine(fragment, 1)))))));
534 }
535
536 static void _addIfNonEmpty(StringBuffer sb, String test,
537 String first, String second) {
538 if ("" != test) {
539 sb.write(first == null ? "null" : first);
540 sb.write(second == null ? "null" : second);
541 }
542 }
543
544 /**
545 * A javaScript-like URI component encoder, this encodes a URI
546 * [component] by replacing each instance of certain characters by
floitsch 2013/05/24 20:37:27 If the set of characters is fixed, add it at the e
Søren Gjesse 2013/05/27 10:47:21 Done.
547 * one, two, three, or four escape sequences representing the UTF-8
548 * encoding of the character (will only be four escape sequences for
549 * characters composed of two "surrogate" characters). To avoid
550 * unexpected requests to the server, you should call
551 * Uri.encodeComponent on any user-entered parameters that will be
552 * passed as part of a URI.
553 *
554 * For encoding the query part consider using
555 * [encodeQueryComponent].
556 *
557 * When manually encoding path segments or query components remember
558 * to encode each part separately before building the path or query
559 * string.
560 *
561 * To avoid the need for explicitly encoding use the [pathSegments]
562 * and [queryParameters] optional named arguments when constructing
563 * a Uri.
564 */
565 static String encodeComponent(String component) {
566 return _uriEncode(_unreserved2396Table, component);
567 }
568
569 /*
570 * Encode [component] according to the HTML 4.01 rules for encoding
571 * the posting of a HTML form as a query string component. Spaces
572 * will be replaced with plus and all characters except for
573 * uppercase and lowercase letters, decimal digits, hyphen, period,
574 * underscore and tilde will be encoded. Note that the set of
575 * characters encoded is a superset of what HTML 4.01 says as it
576 * refers to RFC 1738 for reserved characters.
577 *
578 * When manually encoding query components remember to encode each
579 * part separately before building the query string.
580 *
581 * See http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2 for more
floitsch 2013/05/24 20:37:27 I think there is a way to make this a link.
Søren Gjesse 2013/05/27 10:47:21 I will postpone the adding of proper links to a se
582 * details.
583 */
584 static String encodeQueryComponent(String component) {
585 return _uriEncode(_unreservedTable, component, spaceToPlus: true);
586 }
587
588 /**
589 * A javaScript-like URI component decoder.
floitsch 2013/05/24 20:37:27 Is it JavaScript like, or more general? In other w
Søren Gjesse 2013/05/27 10:47:21 Rephrased the comment and explained more precisely
590 */
591 static String decodeComponent(String encodedComponent) {
592 return _uriDecode(encodedComponent);
593 }
594
595 static String decodeQueryComponent(String encodedComponent) {
596 return _uriDecode(encodedComponent, plusToSpace: true);
597 }
598
599 /**
600 * A JavaScript-like URI encoder. Encodes a full URI string by
601 * replacing each instance of certain characters by one, two, three,
602 * or four escape sequences representing the UTF-8 encoding of the
603 * character (will only be four escape sequences for characters
604 * composed of two "surrogate" characters). This assumes that [uri]
605 * is a complete URI, so does not encode reserved characters that
606 * have special meaning in the URI: [:#;,/?:@&=+\$:] It returns the
floitsch 2013/05/24 20:37:27 nit (personal preference): `#;,/?:@&=+\$`.
Søren Gjesse 2013/05/27 10:47:21 Done.
607 * escaped URI.
608 */
609 static String encodeFull(String uri) {
610 return _uriEncode(_encodeFullTable, uri);
611 }
612
613 /**
614 * A JavaScript-like URI decoder. Decodes a full URI string. This is
floitsch 2013/05/24 20:37:27 Start with what it does: "Decodes ...". Make one s
Søren Gjesse 2013/05/27 10:47:21 Rephrased the comment and explained more precisely
615 * an implementation of JavaScript's decodeURIComponent function.
616 * Decodes a Uniform Resource Identifier [uri] previously created by
617 * encodeURI or by a similar routine. It replaces each escape sequence
618 * in [uri] with the character that it represents.
619 */
620 static String decodeFull(String uri) {
621 return _uriDecode(uri);
622 }
623
624 // Tables of char-codes organized as a bit vector of 128 bits where
625 // each bit indicate whether a character code on the 0-127 needs to
626 // be escaped or not.
627
628 // The unreserved characters of RFC 3986.
629 static const _unreservedTable = const [
630 // LSB MSB
631 // | |
632 0x0000, // 0x00 - 0x0f 0000000000000000
633 0x0000, // 0x10 - 0x1f 0000000000000000
634 // -.
635 0x6000, // 0x20 - 0x2f 0000000000000110
636 // 0123456789
637 0x03ff, // 0x30 - 0x3f 1111111111000000
638 // ABCDEFGHIJKLMNO
639 0xfffe, // 0x40 - 0x4f 0111111111111111
640 // PQRSTUVWXYZ _
641 0x87ff, // 0x50 - 0x5f 1111111111100001
642 // abcdefghijklmno
643 0xfffe, // 0x60 - 0x6f 0111111111111111
644 // pqrstuvwxyz ~
645 0x47ff]; // 0x70 - 0x7f 1111111111100010
646
647 // The unreserved characters of RFC 2396.
648 static const _unreserved2396Table = const [
649 // LSB MSB
650 // | |
651 0x0000, // 0x00 - 0x0f 0000000000000000
652 0x0000, // 0x10 - 0x1f 0000000000000000
653 // ! '()* -.
654 0x6782, // 0x20 - 0x2f 0100000111100110
655 // 0123456789
656 0x03ff, // 0x30 - 0x3f 1111111111000000
657 // ABCDEFGHIJKLMNO
658 0xfffe, // 0x40 - 0x4f 0111111111111111
659 // PQRSTUVWXYZ _
660 0x87ff, // 0x50 - 0x5f 1111111111100001
661 // abcdefghijklmno
662 0xfffe, // 0x60 - 0x6f 0111111111111111
663 // pqrstuvwxyz ~
664 0x47ff]; // 0x70 - 0x7f 1111111111100010
665
666 // Table of reserved characters specified by ECMAScript 5.
667 static const _encodeFullTable = const [
668 // LSB MSB
669 // | |
670 0x0000, // 0x00 - 0x0f 0000000000000000
671 0x0000, // 0x10 - 0x1f 0000000000000000
672 // ! #$ &'()*+,-./
673 0xf7da, // 0x20 - 0x2f 0101101111101111
674 // 0123456789:; = ?
675 0xafff, // 0x30 - 0x3f 1111111111110101
676 // @ABCDEFGHIJKLMNO
677 0xffff, // 0x40 - 0x4f 1111111111111111
678 // PQRSTUVWXYZ _
679 0x87ff, // 0x50 - 0x5f 1111111111100001
680 // abcdefghijklmno
681 0xfffe, // 0x60 - 0x6f 0111111111111111
682 // pqrstuvwxyz ~
683 0x47ff]; // 0x70 - 0x7f 1111111111100010
684
685 // Characters allowed in the scheme.
686 static const _schemeTable = const [
687 // LSB MSB
688 // | |
689 0x0000, // 0x00 - 0x0f 0000000000000000
690 0x0000, // 0x10 - 0x1f 0000000000000000
691 // + -.
692 0x6800, // 0x20 - 0x2f 0000000000010110
693 // 0123456789
694 0x03ff, // 0x30 - 0x3f 1111111111000000
695 // ABCDEFGHIJKLMNO
696 0xfffe, // 0x40 - 0x4f 0111111111111111
697 // PQRSTUVWXYZ
698 0x07ff, // 0x50 - 0x5f 1111111111100001
699 // abcdefghijklmno
700 0xfffe, // 0x60 - 0x6f 0111111111111111
701 // pqrstuvwxyz
702 0x07ff]; // 0x70 - 0x7f 1111111111100010
703
704 // Characters allowed in scheme except for upper case letters.
705 static const _schemeLowerTable = const [
706 // LSB MSB
707 // | |
708 0x0000, // 0x00 - 0x0f 0000000000000000
709 0x0000, // 0x10 - 0x1f 0000000000000000
710 // + -.
711 0x6800, // 0x20 - 0x2f 0000000000010110
712 // 0123456789
713 0x03ff, // 0x30 - 0x3f 1111111111000000
714 //
715 0x0000, // 0x40 - 0x4f 0111111111111111
716 //
717 0x0000, // 0x50 - 0x5f 1111111111100001
718 // abcdefghijklmno
719 0xfffe, // 0x60 - 0x6f 0111111111111111
720 // pqrstuvwxyz
721 0x07ff]; // 0x70 - 0x7f 1111111111100010
722
723 // Sub delimiter characters combined with unreserved as of 3986.
724 // sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
725 // / "*" / "+" / "," / ";" / "="
726 // RFC 3986 section 2.3.
727 // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
728 static const _subDelimitersTable = const [
729 // LSB MSB
730 // | |
731 0x0000, // 0x00 - 0x0f 0000000000000000
732 0x0000, // 0x10 - 0x1f 0000000000000000
733 // ! $ &'()*+,-.
734 0x7fd2, // 0x20 - 0x2f 0100101111111110
735 // 0123456789 ; =
736 0x2bff, // 0x30 - 0x3f 1111111111010100
737 // ABCDEFGHIJKLMNO
738 0xfffe, // 0x40 - 0x4f 0111111111111111
739 // PQRSTUVWXYZ _
740 0x87ff, // 0x50 - 0x5f 1111111111100001
741 // abcdefghijklmno
742 0xfffe, // 0x60 - 0x6f 0111111111111111
743 // pqrstuvwxyz ~
744 0x47ff]; // 0x70 - 0x7f 1111111111100010
745
746 // Characters allowed in the path as of RFC 3986.
747 // RFC 3986 section 3.3.
748 // pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
749 static const _pathCharTable = const [
750 // LSB MSB
751 // | |
752 0x0000, // 0x00 - 0x0f 0000000000000000
753 0x0000, // 0x10 - 0x1f 0000000000000000
754 // ! $ &'()*+,-.
755 0x7fd2, // 0x20 - 0x2f 0100101111111110
756 // 0123456789:; =
757 0x2fff, // 0x30 - 0x3f 1111111111110100
758 // @ABCDEFGHIJKLMNO
759 0xffff, // 0x40 - 0x4f 1111111111111111
760 // PQRSTUVWXYZ _
761 0x87ff, // 0x50 - 0x5f 1111111111100001
762 // abcdefghijklmno
763 0xfffe, // 0x60 - 0x6f 0111111111111111
764 // pqrstuvwxyz ~
765 0x47ff]; // 0x70 - 0x7f 1111111111100010
766
767 // Characters allowed in the query as of RFC 3986.
768 // RFC 3986 section 3.4.
769 // query = *( pchar / "/" / "?" )
770 static const _queryCharTable = const [
771 // LSB MSB
772 // | |
773 0x0000, // 0x00 - 0x0f 0000000000000000
774 0x0000, // 0x10 - 0x1f 0000000000000000
775 // ! $ &'()*+,-./
776 0xffd2, // 0x20 - 0x2f 0100101111111111
777 // 0123456789:; = ?
778 0xafff, // 0x30 - 0x3f 1111111111110101
779 // @ABCDEFGHIJKLMNO
780 0xffff, // 0x40 - 0x4f 1111111111111111
781 // PQRSTUVWXYZ _
782 0x87ff, // 0x50 - 0x5f 1111111111100001
783 // abcdefghijklmno
784 0xfffe, // 0x60 - 0x6f 0111111111111111
785 // pqrstuvwxyz ~
786 0x47ff]; // 0x70 - 0x7f 1111111111100010
787 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698