OLD | NEW |
| (Empty) |
1 part of dart.core; | |
2 class Uri {final String _host; | |
3 num _port; | |
4 String _path; | |
5 final String scheme; | |
6 String get authority { | |
7 if (!hasAuthority) return ""; | |
8 var sb = new StringBuffer(); | |
9 _writeAuthority(sb); | |
10 return sb.toString(); | |
11 } | |
12 final String _userInfo; | |
13 String get userInfo => _userInfo; | |
14 String get host { | |
15 if (_host == null) return ""; | |
16 if (_host.startsWith('[')) { | |
17 return _host.substring(1, _host.length - 1); | |
18 } | |
19 return _host; | |
20 } | |
21 int get port { | |
22 if (_port == null) return _defaultPort(scheme); | |
23 return DEVC$RT.cast(_port, num, int, "ImplicitCast", """line 94, column 12 of
dart:core/uri.dart: """, _port is int, true); | |
24 } | |
25 static int _defaultPort(String scheme) { | |
26 if (scheme == "http") return 80; | |
27 if (scheme == "https") return 443; | |
28 return 0; | |
29 } | |
30 String get path => _path; | |
31 final String _query; | |
32 String get query => (_query == null) ? "" : _query; | |
33 final String _fragment; | |
34 String get fragment => (_fragment == null) ? "" : _fragment; | |
35 List<String> _pathSegments; | |
36 Map<String, String> _queryParameters; | |
37 static Uri parse(String uri) { | |
38 bool isRegName(int ch) { | |
39 return ch < 128 && ((_regNameTable[ch >> 4] & (1 << (ch & 0x0f))) != 0); | |
40 } | |
41 const int EOI = -1; | |
42 String scheme = ""; | |
43 String userinfo = ""; | |
44 String host = null; | |
45 num port = null; | |
46 String path = null; | |
47 String query = null; | |
48 String fragment = null; | |
49 int index = 0; | |
50 int pathStart = 0; | |
51 int char = EOI; | |
52 void parseAuth() { | |
53 if (index == uri.length) { | |
54 char = EOI; | |
55 return;} | |
56 int authStart = index; | |
57 int lastColon = -1; | |
58 int lastAt = -1; | |
59 char = uri.codeUnitAt(index); | |
60 while (index < uri.length) { | |
61 char = uri.codeUnitAt(index); | |
62 if (char == _SLASH || char == _QUESTION || char == _NUMBER_SIGN) { | |
63 break; | |
64 } | |
65 if (char == _AT_SIGN) { | |
66 lastAt = index; | |
67 lastColon = -1; | |
68 } | |
69 else if (char == _COLON) { | |
70 lastColon = index; | |
71 } | |
72 else if (char == _LEFT_BRACKET) { | |
73 lastColon = -1; | |
74 int endBracket = uri.indexOf(']', index + 1); | |
75 if (endBracket == -1) { | |
76 index = uri.length; | |
77 char = EOI; | |
78 break; | |
79 } | |
80 else { | |
81 index = endBracket; | |
82 } | |
83 } | |
84 index++; | |
85 char = EOI; | |
86 } | |
87 int hostStart = authStart; | |
88 int hostEnd = index; | |
89 if (lastAt >= 0) { | |
90 userinfo = _makeUserInfo(uri, authStart, lastAt); | |
91 hostStart = lastAt + 1; | |
92 } | |
93 if (lastColon >= 0) { | |
94 int portNumber; | |
95 if (lastColon + 1 < index) { | |
96 portNumber = 0; | |
97 for (int i = lastColon + 1; i < index; i++) { | |
98 int digit = uri.codeUnitAt(i); | |
99 if (_ZERO > digit || _NINE < digit) { | |
100 _fail(uri, i, "Invalid port number"); | |
101 } | |
102 portNumber = portNumber * 10 + (digit - _ZERO); | |
103 } | |
104 } | |
105 port = _makePort(portNumber, scheme); | |
106 hostEnd = lastColon; | |
107 } | |
108 host = _makeHost(uri, hostStart, hostEnd, true); | |
109 if (index < uri.length) { | |
110 char = uri.codeUnitAt(index); | |
111 } | |
112 } | |
113 const int NOT_IN_PATH = 0; | |
114 const int IN_PATH = 1; | |
115 const int ALLOW_AUTH = 2; | |
116 int state = NOT_IN_PATH; | |
117 int i = index; | |
118 while (i < uri.length) { | |
119 char = uri.codeUnitAt(i); | |
120 if (char == _QUESTION || char == _NUMBER_SIGN) { | |
121 state = NOT_IN_PATH; | |
122 break; | |
123 } | |
124 if (char == _SLASH) { | |
125 state = (i == 0) ? ALLOW_AUTH : IN_PATH; | |
126 break; | |
127 } | |
128 if (char == _COLON) { | |
129 if (i == 0) _fail(uri, 0, "Invalid empty scheme"); | |
130 scheme = _makeScheme(uri, i); | |
131 i++; | |
132 pathStart = i; | |
133 if (i == uri.length) { | |
134 char = EOI; | |
135 state = NOT_IN_PATH; | |
136 } | |
137 else { | |
138 char = uri.codeUnitAt(i); | |
139 if (char == _QUESTION || char == _NUMBER_SIGN) { | |
140 state = NOT_IN_PATH; | |
141 } | |
142 else if (char == _SLASH) { | |
143 state = ALLOW_AUTH; | |
144 } | |
145 else { | |
146 state = IN_PATH; | |
147 } | |
148 } | |
149 break; | |
150 } | |
151 i++; | |
152 char = EOI; | |
153 } | |
154 index = i; | |
155 if (state == ALLOW_AUTH) { | |
156 assert (char == _SLASH); index++; | |
157 if (index == uri.length) { | |
158 char = EOI; | |
159 state = NOT_IN_PATH; | |
160 } | |
161 else { | |
162 char = uri.codeUnitAt(index); | |
163 if (char == _SLASH) { | |
164 index++; | |
165 parseAuth(); | |
166 pathStart = index; | |
167 } | |
168 if (char == _QUESTION || char == _NUMBER_SIGN || char == EOI) { | |
169 state = NOT_IN_PATH; | |
170 } | |
171 else { | |
172 state = IN_PATH; | |
173 } | |
174 } | |
175 } | |
176 assert (state == IN_PATH || state == NOT_IN_PATH); if (state == IN_PATH) { | |
177 while (++index < uri.length) { | |
178 char = uri.codeUnitAt(index); | |
179 if (char == _QUESTION || char == _NUMBER_SIGN) { | |
180 break; | |
181 } | |
182 char = EOI; | |
183 } | |
184 state = NOT_IN_PATH; | |
185 } | |
186 assert (state == NOT_IN_PATH); bool isFile = (scheme == "file"); | |
187 bool ensureLeadingSlash = host != null; | |
188 path = _makePath(uri, pathStart, index, null, ensureLeadingSlash, isFile); | |
189 if (char == _QUESTION) { | |
190 int numberSignIndex = uri.indexOf('#', index + 1); | |
191 if (numberSignIndex < 0) { | |
192 query = _makeQuery(uri, index + 1, uri.length, null); | |
193 } | |
194 else { | |
195 query = _makeQuery(uri, index + 1, numberSignIndex, null); | |
196 fragment = _makeFragment(uri, numberSignIndex + 1, uri.length); | |
197 } | |
198 } | |
199 else if (char == _NUMBER_SIGN) { | |
200 fragment = _makeFragment(uri, index + 1, uri.length); | |
201 } | |
202 return new Uri._internal(scheme, userinfo, host, port, path, query, fragment)
; | |
203 } | |
204 static void _fail(String uri, int index, String message) { | |
205 throw new FormatException(message, uri, index); | |
206 } | |
207 Uri._internal(this.scheme, this._userInfo, this._host, this._port, this._path,
this._query, this._fragment); | |
208 factory Uri({ | |
209 String scheme : "", String userInfo : "", String host, int port, String path,
Iterable<String> pathSegments, String query, Map<String, String> queryParameters
, String fragment} | |
210 ) { | |
211 scheme = _makeScheme(scheme, _stringOrNullLength(scheme)); | |
212 userInfo = _makeUserInfo(userInfo, 0, _stringOrNullLength(userInfo)); | |
213 host = _makeHost(host, 0, _stringOrNullLength(host), false); | |
214 if (query == "") query = null; | |
215 query = _makeQuery(query, 0, _stringOrNullLength(query), queryParameters); | |
216 fragment = _makeFragment(fragment, 0, _stringOrNullLength(fragment)); | |
217 port = _makePort(port, scheme); | |
218 bool isFile = (scheme == "file"); | |
219 if (host == null && (userInfo.isNotEmpty || port != null || isFile)) { | |
220 host = ""; | |
221 } | |
222 bool ensureLeadingSlash = host != null; | |
223 path = _makePath(path, 0, _stringOrNullLength(path), pathSegments, ensureLead
ingSlash, isFile); | |
224 return new Uri._internal(scheme, userInfo, host, port, path, query, fragment)
; | |
225 } | |
226 factory Uri.http(String authority, String unencodedPath, [Map<String, String> q
ueryParameters]) { | |
227 return _makeHttpUri("http", authority, unencodedPath, queryParameters); | |
228 } | |
229 factory Uri.https(String authority, String unencodedPath, [Map<String, String>
queryParameters]) { | |
230 return _makeHttpUri("https", authority, unencodedPath, queryParameters); | |
231 } | |
232 static Uri _makeHttpUri(String scheme, String authority, String unencodedPath,
Map<String, String> queryParameters) { | |
233 var userInfo = ""; | |
234 var host = null; | |
235 var port = null; | |
236 if (authority != null && authority.isNotEmpty) { | |
237 var hostStart = 0; | |
238 bool hasUserInfo = false; | |
239 for (int i = 0; i < authority.length; i++) { | |
240 if (authority.codeUnitAt(i) == _AT_SIGN) { | |
241 hasUserInfo = true; | |
242 userInfo = authority.substring(0, i); | |
243 hostStart = i + 1; | |
244 break; | |
245 } | |
246 } | |
247 var hostEnd = hostStart; | |
248 if (hostStart < authority.length && authority.codeUnitAt(hostStart) == _LEF
T_BRACKET) { | |
249 for (; hostEnd < authority.length; hostEnd++) { | |
250 if (authority.codeUnitAt(hostEnd) == _RIGHT_BRACKET) break; | |
251 } | |
252 if (hostEnd == authority.length) { | |
253 throw new FormatException("Invalid IPv6 host entry.", authority, hostSta
rt); | |
254 } | |
255 parseIPv6Address(authority, hostStart + 1, hostEnd); | |
256 hostEnd++; | |
257 if (hostEnd != authority.length && authority.codeUnitAt(hostEnd) != _COLO
N) { | |
258 throw new FormatException("Invalid end of authority", authority, hostEnd
); | |
259 } | |
260 } | |
261 bool hasPort = false; | |
262 for (; hostEnd < authority.length; hostEnd++) { | |
263 if (authority.codeUnitAt(hostEnd) == _COLON) { | |
264 var portString = authority.substring(hostEnd + 1); | |
265 if (portString.isNotEmpty) port = int.parse(portString); | |
266 break; | |
267 } | |
268 } | |
269 host = authority.substring(hostStart, hostEnd); | |
270 } | |
271 return new Uri(scheme: scheme, userInfo: userInfo, host: DEVC$RT.cast(host, d
ynamic, String, "DynamicCast", """line 609, column 26 of dart:core/uri.dart: """
, host is String, true), port: DEVC$RT.cast(port, dynamic, int, "DynamicCast", "
""line 610, column 26 of dart:core/uri.dart: """, port is int, true), pathSegmen
ts: unencodedPath.split("/"), queryParameters: queryParameters); | |
272 } | |
273 factory Uri.file(String path, { | |
274 bool windows} | |
275 ) { | |
276 windows = windows == null ? Uri._isWindows : windows; | |
277 return windows ? ((__x21) => DEVC$RT.cast(__x21, dynamic, Uri, "DynamicCast",
"""line 698, column 22 of dart:core/uri.dart: """, __x21 is Uri, true))(_makeWi
ndowsFileUrl(path)) : ((__x22) => DEVC$RT.cast(__x22, dynamic, Uri, "DynamicCast
", """line 698, column 50 of dart:core/uri.dart: """, __x22 is Uri, true))(_make
FileUri(path)); | |
278 } | |
279 external static Uri get base; | |
280 external static bool get _isWindows; | |
281 static _checkNonWindowsPathReservedCharacters(List<String> segments, bool argum
entError) { | |
282 segments.forEach((segment) { | |
283 if (segment.contains("/")) { | |
284 if (argumentError) { | |
285 throw new ArgumentError("Illegal path character $segment"); | |
286 } | |
287 else { | |
288 throw new UnsupportedError("Illegal path character $segment"); | |
289 } | |
290 } | |
291 } | |
292 ); | |
293 } | |
294 static _checkWindowsPathReservedCharacters(List<String> segments, bool argument
Error, [int firstSegment = 0]) { | |
295 segments.skip(firstSegment).forEach((segment) { | |
296 if (segment.contains(new RegExp(r'["*/:<>?\\|]'))) { | |
297 if (argumentError) { | |
298 throw new ArgumentError("Illegal character in path"); | |
299 } | |
300 else { | |
301 throw new UnsupportedError("Illegal character in path"); | |
302 } | |
303 } | |
304 } | |
305 ); | |
306 } | |
307 static _checkWindowsDriveLetter(int charCode, bool argumentError) { | |
308 if ((_UPPER_CASE_A <= charCode && charCode <= _UPPER_CASE_Z) || (_LOWER_CASE_A
<= charCode && charCode <= _LOWER_CASE_Z)) { | |
309 return;} | |
310 if (argumentError) { | |
311 throw new ArgumentError("Illegal drive letter " + new String.fromCharCode(ch
arCode)); | |
312 } | |
313 else { | |
314 throw new UnsupportedError("Illegal drive letter " + new String.fromCharCode
(charCode)); | |
315 } | |
316 } | |
317 static _makeFileUri(String path) { | |
318 String sep = "/"; | |
319 if (path.startsWith(sep)) { | |
320 return new Uri(scheme: "file", pathSegments: path.split(sep)); | |
321 } | |
322 else { | |
323 return new Uri(pathSegments: path.split(sep)); | |
324 } | |
325 } | |
326 static _makeWindowsFileUrl(String path) { | |
327 if (path.startsWith("\\\\?\\")) { | |
328 if (path.startsWith("\\\\?\\UNC\\")) { | |
329 path = "\\${path.substring(7)}"; | |
330 } | |
331 else { | |
332 path = path.substring(4); | |
333 if (path.length < 3 || path.codeUnitAt(1) != _COLON || path.codeUnitAt(2)
!= _BACKSLASH) { | |
334 throw new ArgumentError("Windows paths with \\\\?\\ prefix must be absol
ute"); | |
335 } | |
336 } | |
337 } | |
338 else { | |
339 path = path.replaceAll("/", "\\"); | |
340 } | |
341 String sep = "\\"; | |
342 if (path.length > 1 && path[1] == ":") { | |
343 _checkWindowsDriveLetter(path.codeUnitAt(0), true); | |
344 if (path.length == 2 || path.codeUnitAt(2) != _BACKSLASH) { | |
345 throw new ArgumentError("Windows paths with drive letter must be absolute"
); | |
346 } | |
347 var pathSegments = path.split(sep); | |
348 _checkWindowsPathReservedCharacters(pathSegments, true, 1); | |
349 return new Uri(scheme: "file", pathSegments: pathSegments); | |
350 } | |
351 if (path.length > 0 && path[0] == sep) { | |
352 if (path.length > 1 && path[1] == sep) { | |
353 int pathStart = path.indexOf("\\", 2); | |
354 String hostPart = pathStart == -1 ? path.substring(2) : path.substring(2,
pathStart); | |
355 String pathPart = pathStart == -1 ? "" : path.substring(pathStart + 1); | |
356 var pathSegments = pathPart.split(sep); | |
357 _checkWindowsPathReservedCharacters(pathSegments, true); | |
358 return new Uri(scheme: "file", host: hostPart, pathSegments: pathSegments
); | |
359 } | |
360 else { | |
361 var pathSegments = path.split(sep); | |
362 _checkWindowsPathReservedCharacters(pathSegments, true); | |
363 return new Uri(scheme: "file", pathSegments: pathSegments); | |
364 } | |
365 } | |
366 else { | |
367 var pathSegments = path.split(sep); | |
368 _checkWindowsPathReservedCharacters(pathSegments, true); | |
369 return new Uri(pathSegments: pathSegments); | |
370 } | |
371 } | |
372 Uri replace({ | |
373 String scheme, String userInfo, String host, int port, String path, Iterable<S
tring> pathSegments, String query, Map<String, String> queryParameters, String f
ragment} | |
374 ) { | |
375 bool schemeChanged = false; | |
376 if (scheme != null) { | |
377 scheme = _makeScheme(scheme, scheme.length); | |
378 schemeChanged = true; | |
379 } | |
380 else { | |
381 scheme = this.scheme; | |
382 } | |
383 bool isFile = (scheme == "file"); | |
384 if (userInfo != null) { | |
385 userInfo = _makeUserInfo(userInfo, 0, userInfo.length); | |
386 } | |
387 else { | |
388 userInfo = this.userInfo; | |
389 } | |
390 if (port != null) { | |
391 port = _makePort(port, scheme); | |
392 } | |
393 else { | |
394 port = ((__x23) => DEVC$RT.cast(__x23, num, int, "ImplicitCast", """line 889
, column 14 of dart:core/uri.dart: """, __x23 is int, true))(this._port); | |
395 if (schemeChanged) { | |
396 port = _makePort(port, scheme); | |
397 } | |
398 } | |
399 if (host != null) { | |
400 host = _makeHost(host, 0, host.length, false); | |
401 } | |
402 else if (this.hasAuthority) { | |
403 host = this.host; | |
404 } | |
405 else if (userInfo.isNotEmpty || port != null || isFile) { | |
406 host = ""; | |
407 } | |
408 bool ensureLeadingSlash = (host != null); | |
409 if (path != null || pathSegments != null) { | |
410 path = _makePath(path, 0, _stringOrNullLength(path), pathSegments, ensureLea
dingSlash, isFile); | |
411 } | |
412 else { | |
413 path = this.path; | |
414 if ((isFile || (ensureLeadingSlash && !path.isEmpty)) && !path.startsWith('
/')) { | |
415 path = "/$path"; | |
416 } | |
417 } | |
418 if (query != null || queryParameters != null) { | |
419 query = _makeQuery(query, 0, _stringOrNullLength(query), queryParameters); | |
420 } | |
421 else if (this.hasQuery) { | |
422 query = this.query; | |
423 } | |
424 if (fragment != null) { | |
425 fragment = _makeFragment(fragment, 0, fragment.length); | |
426 } | |
427 else if (this.hasFragment) { | |
428 fragment = this.fragment; | |
429 } | |
430 return new Uri._internal(scheme, userInfo, host, port, path, query, fragment)
; | |
431 } | |
432 List<String> get pathSegments { | |
433 if (_pathSegments == null) { | |
434 var pathToSplit = !path.isEmpty && path.codeUnitAt(0) == _SLASH ? path.subst
ring(1) : path; | |
435 _pathSegments = new UnmodifiableListView<String>(pathToSplit == "" ? const
<String> [] : new List<String>.from(pathToSplit.split("/").map(Uri.decodeCompone
nt), growable: false)); | |
436 } | |
437 return _pathSegments; | |
438 } | |
439 Map<String, String> get queryParameters { | |
440 if (_queryParameters == null) { | |
441 _queryParameters = new UnmodifiableMapView<String, String>(splitQueryString(
query)); | |
442 } | |
443 return _queryParameters; | |
444 } | |
445 static int _makePort(int port, String scheme) { | |
446 if (port != null && port == _defaultPort(scheme)) return null; | |
447 return port; | |
448 } | |
449 static String _makeHost(String host, int start, int end, bool strictIPv6) { | |
450 if (host == null) return null; | |
451 if (start == end) return ""; | |
452 if (host.codeUnitAt(start) == _LEFT_BRACKET) { | |
453 if (host.codeUnitAt(end - 1) != _RIGHT_BRACKET) { | |
454 _fail(host, start, 'Missing end `]` to match `[` in host'); | |
455 } | |
456 parseIPv6Address(host, start + 1, end - 1); | |
457 return host.substring(start, end).toLowerCase(); | |
458 } | |
459 if (!strictIPv6) { | |
460 for (int i = start; i < end; i++) { | |
461 if (host.codeUnitAt(i) == _COLON) { | |
462 parseIPv6Address(host, start, end); | |
463 return '[$host]'; | |
464 } | |
465 } | |
466 } | |
467 return _normalizeRegName(host, start, end); | |
468 } | |
469 static bool _isRegNameChar(int char) { | |
470 return char < 127 && (_regNameTable[char >> 4] & (1 << (char & 0xf))) != 0; | |
471 } | |
472 static String _normalizeRegName(String host, int start, int end) { | |
473 StringBuffer buffer; | |
474 int sectionStart = start; | |
475 int index = start; | |
476 bool isNormalized = true; | |
477 while (index < end) { | |
478 int char = host.codeUnitAt(index); | |
479 if (char == _PERCENT) { | |
480 String replacement = _normalizeEscape(host, index, true); | |
481 if (replacement == null && isNormalized) { | |
482 index += 3; | |
483 continue; | |
484 } | |
485 if (buffer == null) buffer = new StringBuffer(); | |
486 String slice = host.substring(sectionStart, index); | |
487 if (!isNormalized) slice = slice.toLowerCase(); | |
488 buffer.write(slice); | |
489 int sourceLength = 3; | |
490 if (replacement == null) { | |
491 replacement = host.substring(index, index + 3); | |
492 } | |
493 else if (replacement == "%") { | |
494 replacement = "%25"; | |
495 sourceLength = 1; | |
496 } | |
497 buffer.write(replacement); | |
498 index += sourceLength; | |
499 sectionStart = index; | |
500 isNormalized = true; | |
501 } | |
502 else if (_isRegNameChar(char)) { | |
503 if (isNormalized && _UPPER_CASE_A <= char && _UPPER_CASE_Z >= char) { | |
504 if (buffer == null) buffer = new StringBuffer(); | |
505 if (sectionStart < index) { | |
506 buffer.write(host.substring(sectionStart, index)); | |
507 sectionStart = index; | |
508 } | |
509 isNormalized = false; | |
510 } | |
511 index++; | |
512 } | |
513 else if (_isGeneralDelimiter(char)) { | |
514 _fail(host, index, "Invalid character"); | |
515 } | |
516 else { | |
517 int sourceLength = 1; | |
518 if ((char & 0xFC00) == 0xD800 && (index + 1) < end) { | |
519 int tail = host.codeUnitAt(index + 1); | |
520 if ((tail & 0xFC00) == 0xDC00) { | |
521 char = 0x10000 | ((char & 0x3ff) << 10) | (tail & 0x3ff); | |
522 sourceLength = 2; | |
523 } | |
524 } | |
525 if (buffer == null) buffer = new StringBuffer(); | |
526 String slice = host.substring(sectionStart, index); | |
527 if (!isNormalized) slice = slice.toLowerCase(); | |
528 buffer.write(slice); | |
529 buffer.write(_escapeChar(char)); | |
530 index += sourceLength; | |
531 sectionStart = index; | |
532 } | |
533 } | |
534 if (buffer == null) return host.substring(start, end); | |
535 if (sectionStart < end) { | |
536 String slice = host.substring(sectionStart, end); | |
537 if (!isNormalized) slice = slice.toLowerCase(); | |
538 buffer.write(slice); | |
539 } | |
540 return buffer.toString(); | |
541 } | |
542 static String _makeScheme(String scheme, int end) { | |
543 if (end == 0) return ""; | |
544 final int firstCodeUnit = scheme.codeUnitAt(0); | |
545 if (!_isAlphabeticCharacter(firstCodeUnit)) { | |
546 _fail(scheme, 0, "Scheme not starting with alphabetic character"); | |
547 } | |
548 bool allLowercase = firstCodeUnit >= _LOWER_CASE_A; | |
549 for (int i = 0; i < end; i++) { | |
550 final int codeUnit = scheme.codeUnitAt(i); | |
551 if (!_isSchemeCharacter(codeUnit)) { | |
552 _fail(scheme, i, "Illegal scheme character"); | |
553 } | |
554 if (codeUnit < _LOWER_CASE_A || codeUnit > _LOWER_CASE_Z) { | |
555 allLowercase = false; | |
556 } | |
557 } | |
558 scheme = scheme.substring(0, end); | |
559 if (!allLowercase) scheme = scheme.toLowerCase(); | |
560 return scheme; | |
561 } | |
562 static String _makeUserInfo(String userInfo, int start, int end) { | |
563 if (userInfo == null) return ""; | |
564 return _normalize(userInfo, start, end, DEVC$RT.cast(_userinfoTable, DEVC$RT.
type((List<dynamic> _) { | |
565 } | |
566 ), DEVC$RT.type((List<int> _) { | |
567 } | |
568 ), "CompositeCast", """line 1127, column 45 of dart:core/uri.dart: """, _useri
nfoTable is List<int>, false)); | |
569 } | |
570 static String _makePath(String path, int start, int end, Iterable<String> pathS
egments, bool ensureLeadingSlash, bool isFile) { | |
571 if (path == null && pathSegments == null) return isFile ? "/" : ""; | |
572 if (path != null && pathSegments != null) { | |
573 throw new ArgumentError('Both path and pathSegments specified'); | |
574 } | |
575 var result; | |
576 if (path != null) { | |
577 result = _normalize(path, start, end, DEVC$RT.cast(_pathCharOrSlashTable, DE
VC$RT.type((List<dynamic> _) { | |
578 } | |
579 ), DEVC$RT.type((List<int> _) { | |
580 } | |
581 ), "CompositeCast", """line 1140, column 45 of dart:core/uri.dart: """, _pat
hCharOrSlashTable is List<int>, false)); | |
582 } | |
583 else { | |
584 result = pathSegments.map((s) => _uriEncode(DEVC$RT.cast(_pathCharTable, DEV
C$RT.type((List<dynamic> _) { | |
585 } | |
586 ), DEVC$RT.type((List<int> _) { | |
587 } | |
588 ), "CompositeCast", """line 1142, column 51 of dart:core/uri.dart: """, _pat
hCharTable is List<int>, false), DEVC$RT.cast(s, dynamic, String, "DynamicCast",
"""line 1142, column 67 of dart:core/uri.dart: """, s is String, true))).join("
/"); | |
589 } | |
590 if (result.isEmpty) { | |
591 if (isFile) return "/"; | |
592 } | |
593 else if ((isFile || ensureLeadingSlash) && result.codeUnitAt(0) != _SLASH) { | |
594 return "/$result"; | |
595 } | |
596 return DEVC$RT.cast(result, dynamic, String, "DynamicCast", """line 1150, col
umn 12 of dart:core/uri.dart: """, result is String, true); | |
597 } | |
598 static String _makeQuery(String query, int start, int end, Map<String, String>
queryParameters) { | |
599 if (query == null && queryParameters == null) return null; | |
600 if (query != null && queryParameters != null) { | |
601 throw new ArgumentError('Both query and queryParameters specified'); | |
602 } | |
603 if (query != null) return _normalize(query, start, end, DEVC$RT.cast(_queryCh
arTable, DEVC$RT.type((List<dynamic> _) { | |
604 } | |
605 ), DEVC$RT.type((List<int> _) { | |
606 } | |
607 ), "CompositeCast", """line 1159, column 61 of dart:core/uri.dart: """, _query
CharTable is List<int>, false)); | |
608 var result = new StringBuffer(); | |
609 var first = true; | |
610 queryParameters.forEach((key, value) { | |
611 if (!first) { | |
612 result.write("&"); | |
613 } | |
614 first = false; | |
615 result.write(Uri.encodeQueryComponent(DEVC$RT.cast(key, dynamic, String, "D
ynamicCast", """line 1168, column 45 of dart:core/uri.dart: """, key is String,
true))); | |
616 if (value != null && !value.isEmpty) { | |
617 result.write("="); | |
618 result.write(Uri.encodeQueryComponent(DEVC$RT.cast(value, dynamic, String
, "DynamicCast", """line 1171, column 47 of dart:core/uri.dart: """, value is St
ring, true))); | |
619 } | |
620 } | |
621 ); | |
622 return result.toString(); | |
623 } | |
624 static String _makeFragment(String fragment, int start, int end) { | |
625 if (fragment == null) return null; | |
626 return _normalize(fragment, start, end, DEVC$RT.cast(_queryCharTable, DEVC$RT
.type((List<dynamic> _) { | |
627 } | |
628 ), DEVC$RT.type((List<int> _) { | |
629 } | |
630 ), "CompositeCast", """line 1179, column 45 of dart:core/uri.dart: """, _query
CharTable is List<int>, false)); | |
631 } | |
632 static int _stringOrNullLength(String s) => (s == null) ? 0 : s.length; | |
633 static bool _isHexDigit(int char) { | |
634 if (_NINE >= char) return _ZERO <= char; | |
635 char |= 0x20; | |
636 return _LOWER_CASE_A <= char && _LOWER_CASE_F >= char; | |
637 } | |
638 static int _hexValue(int char) { | |
639 assert (_isHexDigit(char)); if (_NINE >= char) return char - _ZERO; | |
640 char |= 0x20; | |
641 return char - (_LOWER_CASE_A - 10); | |
642 } | |
643 static String _normalizeEscape(String source, int index, bool lowerCase) { | |
644 assert (source.codeUnitAt(index) == _PERCENT); if (index + 2 >= source.length)
{ | |
645 return "%"; | |
646 } | |
647 int firstDigit = source.codeUnitAt(index + 1); | |
648 int secondDigit = source.codeUnitAt(index + 2); | |
649 if (!_isHexDigit(firstDigit) || !_isHexDigit(secondDigit)) { | |
650 return "%"; | |
651 } | |
652 int value = _hexValue(firstDigit) * 16 + _hexValue(secondDigit); | |
653 if (_isUnreservedChar(value)) { | |
654 if (lowerCase && _UPPER_CASE_A <= value && _UPPER_CASE_Z >= value) { | |
655 value |= 0x20; | |
656 } | |
657 return new String.fromCharCode(value); | |
658 } | |
659 if (firstDigit >= _LOWER_CASE_A || secondDigit >= _LOWER_CASE_A) { | |
660 return source.substring(index, index + 3).toUpperCase(); | |
661 } | |
662 return null; | |
663 } | |
664 static bool _isUnreservedChar(int ch) { | |
665 return ch < 127 && ((_unreservedTable[ch >> 4] & (1 << (ch & 0x0f))) != 0); | |
666 } | |
667 static String _escapeChar(char) { | |
668 assert (char <= 0x10ffff); const hexDigits = "0123456789ABCDEF"; | |
669 List codeUnits; | |
670 if (char < 0x80) { | |
671 codeUnits = new List(3); | |
672 codeUnits[0] = _PERCENT; | |
673 codeUnits[1] = hexDigits.codeUnitAt(((__x24) => DEVC$RT.cast(__x24, dynamic
, int, "DynamicCast", """line 1249, column 43 of dart:core/uri.dart: """, __x24
is int, true))(char >> 4)); | |
674 codeUnits[2] = hexDigits.codeUnitAt(((__x25) => DEVC$RT.cast(__x25, dynamic
, int, "DynamicCast", """line 1250, column 43 of dart:core/uri.dart: """, __x25
is int, true))(char & 0xf)); | |
675 } | |
676 else { | |
677 int flag = 0xc0; | |
678 int encodedBytes = 2; | |
679 if (char > 0x7ff) { | |
680 flag = 0xe0; | |
681 encodedBytes = 3; | |
682 if (char > 0xffff) { | |
683 encodedBytes = 4; | |
684 flag = 0xf0; | |
685 } | |
686 } | |
687 codeUnits = new List(3 * encodedBytes); | |
688 int index = 0; | |
689 while (--encodedBytes >= 0) { | |
690 int byte = ((__x26) => DEVC$RT.cast(__x26, dynamic, int, "DynamicCast", ""
"line 1266, column 20 of dart:core/uri.dart: """, __x26 is int, true))(((char >>
(6 * encodedBytes)) & 0x3f) | flag); | |
691 codeUnits[index] = _PERCENT; | |
692 codeUnits[index + 1] = hexDigits.codeUnitAt(byte >> 4); | |
693 codeUnits[index + 2] = hexDigits.codeUnitAt(byte & 0xf); | |
694 index += 3; | |
695 flag = 0x80; | |
696 } | |
697 } | |
698 return new String.fromCharCodes(DEVC$RT.cast(codeUnits, DEVC$RT.type((List<dy
namic> _) { | |
699 } | |
700 ), DEVC$RT.type((Iterable<int> _) { | |
701 } | |
702 ), "CompositeCast", """line 1274, column 37 of dart:core/uri.dart: """, codeUn
its is Iterable<int>, false)); | |
703 } | |
704 static String _normalize(String component, int start, int end, List<int> charTa
ble) { | |
705 StringBuffer buffer; | |
706 int sectionStart = start; | |
707 int index = start; | |
708 while (index < end) { | |
709 int char = component.codeUnitAt(index); | |
710 if (char < 127 && (charTable[char >> 4] & (1 << (char & 0x0f))) != 0) { | |
711 index++; | |
712 } | |
713 else { | |
714 String replacement; | |
715 int sourceLength; | |
716 if (char == _PERCENT) { | |
717 replacement = _normalizeEscape(component, index, false); | |
718 if (replacement == null) { | |
719 index += 3; | |
720 continue; | |
721 } | |
722 if ("%" == replacement) { | |
723 replacement = "%25"; | |
724 sourceLength = 1; | |
725 } | |
726 else { | |
727 sourceLength = 3; | |
728 } | |
729 } | |
730 else if (_isGeneralDelimiter(char)) { | |
731 _fail(component, index, "Invalid character"); | |
732 } | |
733 else { | |
734 sourceLength = 1; | |
735 if ((char & 0xFC00) == 0xD800) { | |
736 if (index + 1 < end) { | |
737 int tail = component.codeUnitAt(index + 1); | |
738 if ((tail & 0xFC00) == 0xDC00) { | |
739 sourceLength = 2; | |
740 char = 0x10000 | ((char & 0x3ff) << 10) | (tail & 0x3ff); | |
741 } | |
742 } | |
743 } | |
744 replacement = _escapeChar(char); | |
745 } | |
746 if (buffer == null) buffer = new StringBuffer(); | |
747 buffer.write(component.substring(sectionStart, index)); | |
748 buffer.write(replacement); | |
749 index += sourceLength; | |
750 sectionStart = index; | |
751 } | |
752 } | |
753 if (buffer == null) { | |
754 return component.substring(start, end); | |
755 } | |
756 if (sectionStart < end) { | |
757 buffer.write(component.substring(sectionStart, end)); | |
758 } | |
759 return buffer.toString(); | |
760 } | |
761 static bool _isSchemeCharacter(int ch) { | |
762 return ch < 128 && ((_schemeTable[ch >> 4] & (1 << (ch & 0x0f))) != 0); | |
763 } | |
764 static bool _isGeneralDelimiter(int ch) { | |
765 return ch <= _RIGHT_BRACKET && ((_genDelimitersTable[ch >> 4] & (1 << (ch & 0x
0f))) != 0); | |
766 } | |
767 bool get isAbsolute => scheme != "" && fragment == ""; | |
768 String _merge(String base, String reference) { | |
769 if (base.isEmpty) return "/$reference"; | |
770 int backCount = 0; | |
771 int refStart = 0; | |
772 while (reference.startsWith("../", refStart)) { | |
773 refStart += 3; | |
774 backCount++; | |
775 } | |
776 int baseEnd = base.lastIndexOf('/'); | |
777 while (baseEnd > 0 && backCount > 0) { | |
778 int newEnd = base.lastIndexOf('/', baseEnd - 1); | |
779 if (newEnd < 0) { | |
780 break; | |
781 } | |
782 int delta = baseEnd - newEnd; | |
783 if ((delta == 2 || delta == 3) && base.codeUnitAt(newEnd + 1) == _DOT && (d
elta == 2 || base.codeUnitAt(newEnd + 2) == _DOT)) { | |
784 break; | |
785 } | |
786 baseEnd = newEnd; | |
787 backCount--; | |
788 } | |
789 return base.substring(0, baseEnd + 1) + reference.substring(refStart - 3 * ba
ckCount); | |
790 } | |
791 bool _hasDotSegments(String path) { | |
792 if (path.length > 0 && path.codeUnitAt(0) == _DOT) return true; | |
793 int index = path.indexOf("/."); | |
794 return index != -1; | |
795 } | |
796 String _removeDotSegments(String path) { | |
797 if (!_hasDotSegments(path)) return path; | |
798 List<String> output = <String> []; | |
799 bool appendSlash = false; | |
800 for (String segment in path.split("/")) { | |
801 appendSlash = false; | |
802 if (segment == "..") { | |
803 if (!output.isEmpty && ((output.length != 1) || (output[0] != ""))) output
.removeLast(); | |
804 appendSlash = true; | |
805 } | |
806 else if ("." == segment) { | |
807 appendSlash = true; | |
808 } | |
809 else { | |
810 output.add(segment); | |
811 } | |
812 } | |
813 if (appendSlash) output.add(""); | |
814 return output.join("/"); | |
815 } | |
816 Uri resolve(String reference) { | |
817 return resolveUri(Uri.parse(reference)); | |
818 } | |
819 Uri resolveUri(Uri reference) { | |
820 String targetScheme; | |
821 String targetUserInfo = ""; | |
822 String targetHost; | |
823 int targetPort; | |
824 String targetPath; | |
825 String targetQuery; | |
826 if (reference.scheme.isNotEmpty) { | |
827 targetScheme = reference.scheme; | |
828 if (reference.hasAuthority) { | |
829 targetUserInfo = reference.userInfo; | |
830 targetHost = reference.host; | |
831 targetPort = reference.hasPort ? reference.port : null; | |
832 } | |
833 targetPath = _removeDotSegments(reference.path); | |
834 if (reference.hasQuery) { | |
835 targetQuery = reference.query; | |
836 } | |
837 } | |
838 else { | |
839 targetScheme = this.scheme; | |
840 if (reference.hasAuthority) { | |
841 targetUserInfo = reference.userInfo; | |
842 targetHost = reference.host; | |
843 targetPort = _makePort(reference.hasPort ? reference.port : null, targetS
cheme); | |
844 targetPath = _removeDotSegments(reference.path); | |
845 if (reference.hasQuery) targetQuery = reference.query; | |
846 } | |
847 else { | |
848 if (reference.path == "") { | |
849 targetPath = this._path; | |
850 if (reference.hasQuery) { | |
851 targetQuery = reference.query; | |
852 } | |
853 else { | |
854 targetQuery = this._query; | |
855 } | |
856 } | |
857 else { | |
858 if (reference.path.startsWith("/")) { | |
859 targetPath = _removeDotSegments(reference.path); | |
860 } | |
861 else { | |
862 targetPath = _removeDotSegments(_merge(this._path, reference.path)); | |
863 } | |
864 if (reference.hasQuery) targetQuery = reference.query; | |
865 } | |
866 targetUserInfo = this._userInfo; | |
867 targetHost = this._host; | |
868 targetPort = ((__x27) => DEVC$RT.cast(__x27, num, int, "ImplicitCast", ""
"line 1490, column 22 of dart:core/uri.dart: """, __x27 is int, true))(this._por
t); | |
869 } | |
870 } | |
871 String fragment = reference.hasFragment ? reference.fragment : null; | |
872 return new Uri._internal(targetScheme, targetUserInfo, targetHost, targetPort
, targetPath, targetQuery, fragment); | |
873 } | |
874 bool get hasAuthority => _host != null; | |
875 bool get hasPort => _port != null; | |
876 bool get hasQuery => _query != null; | |
877 bool get hasFragment => _fragment != null; | |
878 String get origin { | |
879 if (scheme == "" || _host == null || _host == "") { | |
880 throw new StateError("Cannot use origin without a scheme: $this"); | |
881 } | |
882 if (scheme != "http" && scheme != "https") { | |
883 throw new StateError("Origin is only applicable schemes http and https: $thi
s"); | |
884 } | |
885 if (_port == null) return "$scheme://$_host"; | |
886 return "$scheme://$_host:$_port"; | |
887 } | |
888 String toFilePath({ | |
889 bool windows} | |
890 ) { | |
891 if (scheme != "" && scheme != "file") { | |
892 throw new UnsupportedError("Cannot extract a file path from a $scheme URI"); | |
893 } | |
894 if (query != "") { | |
895 throw new UnsupportedError("Cannot extract a file path from a URI with a que
ry component"); | |
896 } | |
897 if (fragment != "") { | |
898 throw new UnsupportedError("Cannot extract a file path from a URI with a fra
gment component"); | |
899 } | |
900 if (windows == null) windows = _isWindows; | |
901 return windows ? _toWindowsFilePath() : _toFilePath(); | |
902 } | |
903 String _toFilePath() { | |
904 if (host != "") { | |
905 throw new UnsupportedError("Cannot extract a non-Windows file path from a fi
le URI " "with an authority"); | |
906 } | |
907 _checkNonWindowsPathReservedCharacters(pathSegments, false); | |
908 var result = new StringBuffer(); | |
909 if (_isPathAbsolute) result.write("/"); | |
910 result.writeAll(pathSegments, "/"); | |
911 return result.toString(); | |
912 } | |
913 String _toWindowsFilePath() { | |
914 bool hasDriveLetter = false; | |
915 var segments = pathSegments; | |
916 if (segments.length > 0 && segments[0].length == 2 && segments[0].codeUnitAt(
1) == _COLON) { | |
917 _checkWindowsDriveLetter(segments[0].codeUnitAt(0), false); | |
918 _checkWindowsPathReservedCharacters(segments, false, 1); | |
919 hasDriveLetter = true; | |
920 } | |
921 else { | |
922 _checkWindowsPathReservedCharacters(segments, false); | |
923 } | |
924 var result = new StringBuffer(); | |
925 if (_isPathAbsolute && !hasDriveLetter) result.write("\\"); | |
926 if (host != "") { | |
927 result.write("\\"); | |
928 result.write(host); | |
929 result.write("\\"); | |
930 } | |
931 result.writeAll(segments, "\\"); | |
932 if (hasDriveLetter && segments.length == 1) result.write("\\"); | |
933 return result.toString(); | |
934 } | |
935 bool get _isPathAbsolute { | |
936 if (path == null || path.isEmpty) return false; | |
937 return path.startsWith('/'); | |
938 } | |
939 void _writeAuthority(StringSink ss) { | |
940 if (_userInfo.isNotEmpty) { | |
941 ss.write(_userInfo); | |
942 ss.write("@"); | |
943 } | |
944 if (_host != null) ss.write(_host); | |
945 if (_port != null) { | |
946 ss.write(":"); | |
947 ss.write(_port); | |
948 } | |
949 } | |
950 String toString() { | |
951 StringBuffer sb = new StringBuffer(); | |
952 _addIfNonEmpty(sb, scheme, scheme, ':'); | |
953 if (hasAuthority || path.startsWith("//") || (scheme == "file")) { | |
954 sb.write("//"); | |
955 _writeAuthority(sb); | |
956 } | |
957 sb.write(path); | |
958 if (_query != null) { | |
959 sb..write("?")..write(_query); | |
960 } | |
961 if (_fragment != null) { | |
962 sb..write("#")..write(_fragment); | |
963 } | |
964 return sb.toString(); | |
965 } | |
966 bool operator ==(other) { | |
967 if (other is! Uri) return false; | |
968 Uri uri = DEVC$RT.cast(other, dynamic, Uri, "DynamicCast", """line 1699, colu
mn 15 of dart:core/uri.dart: """, other is Uri, true); | |
969 return scheme == uri.scheme && hasAuthority == uri.hasAuthority && userInfo =
= uri.userInfo && host == uri.host && port == uri.port && path == uri.path && ha
sQuery == uri.hasQuery && query == uri.query && hasFragment == uri.hasFragment &
& fragment == uri.fragment; | |
970 } | |
971 int get hashCode { | |
972 int combine(part, current) { | |
973 return ((__x28) => DEVC$RT.cast(__x28, dynamic, int, "DynamicCast", """line
1715, column 14 of dart:core/uri.dart: """, __x28 is int, true))((current * 31 +
part.hashCode) & 0x3FFFFFFF); | |
974 } | |
975 return combine(scheme, combine(userInfo, combine(host, combine(port, combine(
path, combine(query, combine(fragment, 1))))))); | |
976 } | |
977 static void _addIfNonEmpty(StringBuffer sb, String test, String first, String s
econd) { | |
978 if ("" != test) { | |
979 sb.write(first); | |
980 sb.write(second); | |
981 } | |
982 } | |
983 static String encodeComponent(String component) { | |
984 return _uriEncode(DEVC$RT.cast(_unreserved2396Table, DEVC$RT.type((List<dynami
c> _) { | |
985 } | |
986 ), DEVC$RT.type((List<int> _) { | |
987 } | |
988 ), "CompositeCast", """line 1750, column 23 of dart:core/uri.dart: """, _unres
erved2396Table is List<int>, false), component); | |
989 } | |
990 static String encodeQueryComponent(String component, { | |
991 Encoding encoding : UTF8} | |
992 ) { | |
993 return _uriEncode(DEVC$RT.cast(_unreservedTable, DEVC$RT.type((List<dynamic> _
) { | |
994 } | |
995 ), DEVC$RT.type((List<int> _) { | |
996 } | |
997 ), "CompositeCast", """line 1789, column 9 of dart:core/uri.dart: """, _unrese
rvedTable is List<int>, false), component, encoding: encoding, spaceToPlus: true
); | |
998 } | |
999 static String decodeComponent(String encodedComponent) { | |
1000 return _uriDecode(encodedComponent); | |
1001 } | |
1002 static String decodeQueryComponent(String encodedComponent, { | |
1003 Encoding encoding : UTF8} | |
1004 ) { | |
1005 return _uriDecode(encodedComponent, plusToSpace: true, encoding: encoding); | |
1006 } | |
1007 static String encodeFull(String uri) { | |
1008 return _uriEncode(DEVC$RT.cast(_encodeFullTable, DEVC$RT.type((List<dynamic> _
) { | |
1009 } | |
1010 ), DEVC$RT.type((List<int> _) { | |
1011 } | |
1012 ), "CompositeCast", """line 1833, column 23 of dart:core/uri.dart: """, _encod
eFullTable is List<int>, false), uri); | |
1013 } | |
1014 static String decodeFull(String uri) { | |
1015 return _uriDecode(uri); | |
1016 } | |
1017 static Map<String, String> splitQueryString(String query, { | |
1018 Encoding encoding : UTF8} | |
1019 ) { | |
1020 return ((__x29) => DEVC$RT.cast(__x29, dynamic, DEVC$RT.type((Map<String, Stri
ng> _) { | |
1021 } | |
1022 ), "CompositeCast", """line 1865, column 12 of dart:core/uri.dart: """, __x29
is Map<String, String>, false))(query.split("&").fold({ | |
1023 } | |
1024 , (map, element) { | |
1025 int index = ((__x30) => DEVC$RT.cast(__x30, dynamic, int, "DynamicCast", """
line 1866, column 19 of dart:core/uri.dart: """, __x30 is int, true))(element.in
dexOf("=")); | |
1026 if (index == -1) { | |
1027 if (element != "") { | |
1028 map[decodeQueryComponent(DEVC$RT.cast(element, dynamic, String, "Dynamic
Cast", """line 1869, column 36 of dart:core/uri.dart: """, element is String, tr
ue), encoding: encoding)] = ""; | |
1029 } | |
1030 } | |
1031 else if (index != 0) { | |
1032 var key = element.substring(0, index); | |
1033 var value = element.substring(index + 1); | |
1034 map[Uri.decodeQueryComponent(DEVC$RT.cast(key, dynamic, String, "DynamicC
ast", """line 1874, column 38 of dart:core/uri.dart: """, key is String, true),
encoding: encoding)] = decodeQueryComponent(DEVC$RT.cast(value, dynamic, String,
"DynamicCast", """line 1875, column 34 of dart:core/uri.dart: """, value is Str
ing, true), encoding: encoding); | |
1035 } | |
1036 return map; | |
1037 } | |
1038 )); | |
1039 } | |
1040 static List<int> parseIPv4Address(String host) { | |
1041 void error(String msg) { | |
1042 throw new FormatException('Illegal IPv4 address, $msg'); | |
1043 } | |
1044 var bytes = host.split('.'); | |
1045 if (bytes.length != 4) { | |
1046 error('IPv4 address should contain exactly 4 parts'); | |
1047 } | |
1048 return ((__x31) => DEVC$RT.cast(__x31, DEVC$RT.type((List<dynamic> _) { | |
1049 } | |
1050 ), DEVC$RT.type((List<int> _) { | |
1051 } | |
1052 ), "CompositeCast", """line 1897, column 12 of dart:core/uri.dart: """, __x31
is List<int>, false))(bytes.map((byteString) { | |
1053 int byte = int.parse(DEVC$RT.cast(byteString, dynamic, String, "DynamicCast"
, """line 1899, column 32 of dart:core/uri.dart: """, byteString is String, true
)); | |
1054 if (byte < 0 || byte > 255) { | |
1055 error('each part must be in the range of `0..255`'); | |
1056 } | |
1057 return byte; | |
1058 } | |
1059 ).toList()); | |
1060 } | |
1061 static List<int> parseIPv6Address(String host, [int start = 0, int end]) { | |
1062 if (end == null) end = host.length; | |
1063 void error(String msg, [position]) { | |
1064 throw new FormatException('Illegal IPv6 address, $msg', host, DEVC$RT.cast(p
osition, dynamic, int, "DynamicCast", """line 1934, column 69 of dart:core/uri.d
art: """, position is int, true)); | |
1065 } | |
1066 int parseHex(int start, int end) { | |
1067 if (end - start > 4) { | |
1068 error('an IPv6 part can only contain a maximum of 4 hex digits', start); | |
1069 } | |
1070 int value = int.parse(host.substring(start, end), radix: 16); | |
1071 if (value < 0 || value > (1 << 16) - 1) { | |
1072 error('each part must be in the range of `0x0..0xFFFF`', start); | |
1073 } | |
1074 return value; | |
1075 } | |
1076 if (host.length < 2) error('address is too short'); | |
1077 List<int> parts = <int> []; | |
1078 bool wildcardSeen = false; | |
1079 int partStart = start; | |
1080 for (int i = start; i < end; i++) { | |
1081 if (host.codeUnitAt(i) == _COLON) { | |
1082 if (i == start) { | |
1083 i++; | |
1084 if (host.codeUnitAt(i) != _COLON) { | |
1085 error('invalid start colon.', i); | |
1086 } | |
1087 partStart = i; | |
1088 } | |
1089 if (i == partStart) { | |
1090 if (wildcardSeen) { | |
1091 error('only one wildcard `::` is allowed', i); | |
1092 } | |
1093 wildcardSeen = true; | |
1094 parts.add(-1); | |
1095 } | |
1096 else { | |
1097 parts.add(parseHex(partStart, i)); | |
1098 } | |
1099 partStart = i + 1; | |
1100 } | |
1101 } | |
1102 if (parts.length == 0) error('too few parts'); | |
1103 bool atEnd = (partStart == end); | |
1104 bool isLastWildcard = (parts.last == -1); | |
1105 if (atEnd && !isLastWildcard) { | |
1106 error('expected a part after last `:`', end); | |
1107 } | |
1108 if (!atEnd) { | |
1109 try { | |
1110 parts.add(parseHex(partStart, end)); | |
1111 } | |
1112 catch (e) { | |
1113 try { | |
1114 List<int> last = parseIPv4Address(host.substring(partStart, end)); | |
1115 parts.add(last[0] << 8 | last[1]); | |
1116 parts.add(last[2] << 8 | last[3]); | |
1117 } | |
1118 catch (e) { | |
1119 error('invalid end of IPv6 address.', partStart); | |
1120 } | |
1121 } | |
1122 } | |
1123 if (wildcardSeen) { | |
1124 if (parts.length > 7) { | |
1125 error('an address with a wildcard must have less than 7 parts'); | |
1126 } | |
1127 } | |
1128 else if (parts.length != 8) { | |
1129 error('an address without a wildcard must contain exactly 8 parts'); | |
1130 } | |
1131 List bytes = new List<int>(16); | |
1132 for (int i = 0, index = 0; i < parts.length; i++) { | |
1133 int value = parts[i]; | |
1134 if (value == -1) { | |
1135 int wildCardLength = 9 - parts.length; | |
1136 for (int j = 0; j < wildCardLength; j++) { | |
1137 bytes[index] = 0; | |
1138 bytes[index + 1] = 0; | |
1139 index += 2; | |
1140 } | |
1141 } | |
1142 else { | |
1143 bytes[index] = value >> 8; | |
1144 bytes[index + 1] = value & 0xff; | |
1145 index += 2; | |
1146 } | |
1147 } | |
1148 return DEVC$RT.cast(bytes, DEVC$RT.type((List<dynamic> _) { | |
1149 } | |
1150 ), DEVC$RT.type((List<int> _) { | |
1151 } | |
1152 ), "CompositeCast", """line 2019, column 12 of dart:core/uri.dart: """, bytes
is List<int>, false); | |
1153 } | |
1154 static const int _SPACE = 0x20; | |
1155 static const int _DOUBLE_QUOTE = 0x22; | |
1156 static const int _NUMBER_SIGN = 0x23; | |
1157 static const int _PERCENT = 0x25; | |
1158 static const int _ASTERISK = 0x2A; | |
1159 static const int _PLUS = 0x2B; | |
1160 static const int _DOT = 0x2E; | |
1161 static const int _SLASH = 0x2F; | |
1162 static const int _ZERO = 0x30; | |
1163 static const int _NINE = 0x39; | |
1164 static const int _COLON = 0x3A; | |
1165 static const int _LESS = 0x3C; | |
1166 static const int _GREATER = 0x3E; | |
1167 static const int _QUESTION = 0x3F; | |
1168 static const int _AT_SIGN = 0x40; | |
1169 static const int _UPPER_CASE_A = 0x41; | |
1170 static const int _UPPER_CASE_F = 0x46; | |
1171 static const int _UPPER_CASE_Z = 0x5A; | |
1172 static const int _LEFT_BRACKET = 0x5B; | |
1173 static const int _BACKSLASH = 0x5C; | |
1174 static const int _RIGHT_BRACKET = 0x5D; | |
1175 static const int _LOWER_CASE_A = 0x61; | |
1176 static const int _LOWER_CASE_F = 0x66; | |
1177 static const int _LOWER_CASE_Z = 0x7A; | |
1178 static const int _BAR = 0x7C; | |
1179 static String _uriEncode(List<int> canonicalTable, String text, { | |
1180 Encoding encoding : UTF8, bool spaceToPlus : false} | |
1181 ) { | |
1182 byteToHex(byte, buffer) { | |
1183 const String hex = '0123456789ABCDEF'; | |
1184 buffer.writeCharCode(hex.codeUnitAt(((__x32) => DEVC$RT.cast(__x32, dynamic
, int, "DynamicCast", """line 2060, column 43 of dart:core/uri.dart: """, __x32
is int, true))(byte >> 4))); | |
1185 buffer.writeCharCode(hex.codeUnitAt(((__x33) => DEVC$RT.cast(__x33, dynamic
, int, "DynamicCast", """line 2061, column 43 of dart:core/uri.dart: """, __x33
is int, true))(byte & 0x0f))); | |
1186 } | |
1187 StringBuffer result = new StringBuffer(); | |
1188 var bytes = encoding.encode(text); | |
1189 for (int i = 0; i < bytes.length; i++) { | |
1190 int byte = bytes[i]; | |
1191 if (byte < 128 && ((canonicalTable[byte >> 4] & (1 << (byte & 0x0f))) != 0)
) { | |
1192 result.writeCharCode(byte); | |
1193 } | |
1194 else if (spaceToPlus && byte == _SPACE) { | |
1195 result.writeCharCode(_PLUS); | |
1196 } | |
1197 else { | |
1198 result.writeCharCode(_PERCENT); | |
1199 byteToHex(byte, result); | |
1200 } | |
1201 } | |
1202 return result.toString(); | |
1203 } | |
1204 static int _hexCharPairToByte(String s, int pos) { | |
1205 int byte = 0; | |
1206 for (int i = 0; i < 2; i++) { | |
1207 var charCode = s.codeUnitAt(pos + i); | |
1208 if (0x30 <= charCode && charCode <= 0x39) { | |
1209 byte = byte * 16 + charCode - 0x30; | |
1210 } | |
1211 else { | |
1212 charCode |= 0x20; | |
1213 if (0x61 <= charCode && charCode <= 0x66) { | |
1214 byte = byte * 16 + charCode - 0x57; | |
1215 } | |
1216 else { | |
1217 throw new ArgumentError("Invalid URL encoding"); | |
1218 } | |
1219 } | |
1220 } | |
1221 return byte; | |
1222 } | |
1223 static String _uriDecode(String text, { | |
1224 bool plusToSpace : false, Encoding encoding : UTF8} | |
1225 ) { | |
1226 bool simple = true; | |
1227 for (int i = 0; i < text.length && simple; i++) { | |
1228 var codeUnit = text.codeUnitAt(i); | |
1229 simple = codeUnit != _PERCENT && codeUnit != _PLUS; | |
1230 } | |
1231 List<int> bytes; | |
1232 if (simple) { | |
1233 if (encoding == UTF8 || encoding == LATIN1) { | |
1234 return text; | |
1235 } | |
1236 else { | |
1237 bytes = text.codeUnits; | |
1238 } | |
1239 } | |
1240 else { | |
1241 bytes = new List<int>(); | |
1242 for (int i = 0; i < text.length; i++) { | |
1243 var codeUnit = text.codeUnitAt(i); | |
1244 if (codeUnit > 127) { | |
1245 throw new ArgumentError("Illegal percent encoding in URI"); | |
1246 } | |
1247 if (codeUnit == _PERCENT) { | |
1248 if (i + 3 > text.length) { | |
1249 throw new ArgumentError('Truncated URI'); | |
1250 } | |
1251 bytes.add(_hexCharPairToByte(text, i + 1)); | |
1252 i += 2; | |
1253 } | |
1254 else if (plusToSpace && codeUnit == _PLUS) { | |
1255 bytes.add(_SPACE); | |
1256 } | |
1257 else { | |
1258 bytes.add(codeUnit); | |
1259 } | |
1260 } | |
1261 } | |
1262 return encoding.decode(bytes); | |
1263 } | |
1264 static bool _isAlphabeticCharacter(int codeUnit) => (codeUnit >= _LOWER_CASE_A
&& codeUnit <= _LOWER_CASE_Z) || (codeUnit >= _UPPER_CASE_A && codeUnit <= _UPPE
R_CASE_Z); | |
1265 static const _unreservedTable = const [0x0000, 0x0000, 0x6000, 0x03ff, 0xfffe,
0x87ff, 0xfffe, 0x47ff]; | |
1266 static const _unreserved2396Table = const [0x0000, 0x0000, 0x6782, 0x03ff, 0xff
fe, 0x87ff, 0xfffe, 0x47ff]; | |
1267 static const _encodeFullTable = const [0x0000, 0x0000, 0xffda, 0xafff, 0xffff,
0x87ff, 0xfffe, 0x47ff]; | |
1268 static const _schemeTable = const [0x0000, 0x0000, 0x6800, 0x03ff, 0xfffe, 0x07
ff, 0xfffe, 0x07ff]; | |
1269 static const _schemeLowerTable = const [0x0000, 0x0000, 0x6800, 0x03ff, 0x0000,
0x0000, 0xfffe, 0x07ff]; | |
1270 static const _subDelimitersTable = const [0x0000, 0x0000, 0x7fd2, 0x2bff, 0xfff
e, 0x87ff, 0xfffe, 0x47ff]; | |
1271 static const _genDelimitersTable = const [0x0000, 0x0000, 0x8008, 0x8400, 0x000
1, 0x2800, 0x0000, 0x0000]; | |
1272 static const _userinfoTable = const [0x0000, 0x0000, 0x7fd2, 0x2fff, 0xfffe, 0x
87ff, 0xfffe, 0x47ff]; | |
1273 static const _regNameTable = const [0x0000, 0x0000, 0x7ff2, 0x2bff, 0xfffe, 0x8
7ff, 0xfffe, 0x47ff]; | |
1274 static const _pathCharTable = const [0x0000, 0x0000, 0x7fd2, 0x2fff, 0xffff, 0x
87ff, 0xfffe, 0x47ff]; | |
1275 static const _pathCharOrSlashTable = const [0x0000, 0x0000, 0xffd2, 0x2fff, 0xf
fff, 0x87ff, 0xfffe, 0x47ff]; | |
1276 static const _queryCharTable = const [0x0000, 0x0000, 0xffd2, 0xafff, 0xffff, 0
x87ff, 0xfffe, 0x47ff]; | |
1277 } | |
OLD | NEW |