OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 part of dart.core; | 5 part of dart.core; |
6 | 6 |
7 // Frequently used character codes. | 7 // Frequently used character codes. |
8 const int _SPACE = 0x20; | 8 const int _SPACE = 0x20; |
9 const int _PERCENT = 0x25; | 9 const int _PERCENT = 0x25; |
10 const int _PLUS = 0x2B; | 10 const int _PLUS = 0x2B; |
(...skipping 4305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4316 return new _SimpleUri(newUri, | 4316 return new _SimpleUri(newUri, |
4317 base._schemeEnd, | 4317 base._schemeEnd, |
4318 base._hostStart, | 4318 base._hostStart, |
4319 base._portStart, | 4319 base._portStart, |
4320 base._pathStart, | 4320 base._pathStart, |
4321 ref._queryStart + delta, | 4321 ref._queryStart + delta, |
4322 ref._fragmentStart + delta, | 4322 ref._fragmentStart + delta, |
4323 base._schemeCache); | 4323 base._schemeCache); |
4324 } | 4324 } |
4325 // Merge paths. | 4325 // Merge paths. |
4326 if (base._uri.startsWith("../", base._pathStart)) { | |
4327 // Complex rare case, go slow. | |
4328 return _toNonSimple().resolveUri(ref); | |
4329 } | |
4330 | 4326 |
4331 // The RFC 3986 algorithm merges the base path without its final segment | 4327 // The RFC 3986 algorithm merges the base path without its final segment |
4332 // (anything after the final "/", or everything if the base path doesn't | 4328 // (anything after the final "/", or everything if the base path doesn't |
4333 // contain any "/"), and the reference path. | 4329 // contain any "/"), and the reference path. |
4334 // Then it removes "." and ".." segments using the remove-dot-segment | 4330 // Then it removes "." and ".." segments using the remove-dot-segment |
4335 // algorithm. | 4331 // algorithm. |
4336 // This code combines the two steps. It is simplified by knowing that | 4332 // This code combines the two steps. It is simplified by knowing that |
4337 // the base path contains no "." or ".." segments, and the reference | 4333 // the base path contains no "." or ".." segments, and the reference |
4338 // path can only contain leading ".." segments. | 4334 // path can only contain leading ".." segments. |
4339 | 4335 |
4340 String baseUri = base._uri; | 4336 String baseUri = base._uri; |
4341 String refUri = ref._uri; | 4337 String refUri = ref._uri; |
4342 int baseStart = base._pathStart; | 4338 int baseStart = base._pathStart; |
4343 int baseEnd = base._queryStart; | 4339 int baseEnd = base._queryStart; |
| 4340 while (baseUri.startsWith("../", baseStart)) baseStart += 3; |
4344 int refStart = ref._pathStart; | 4341 int refStart = ref._pathStart; |
4345 int refEnd = ref._queryStart; | 4342 int refEnd = ref._queryStart; |
4346 int backCount = 1; | |
4347 | 4343 |
4348 int slashCount = 0; | 4344 /// Count of leading ".." segments in reference path. |
4349 | 4345 /// The count is decremented when the segment is matched with a |
4350 // Count leading ".." segments in reference path. | 4346 /// segment of the base path, and both are then omitted from the result. |
| 4347 int backCount = 0; |
| 4348 /// Count "../" segments and advance `refStart` to after the segments. |
4351 while (refStart + 3 <= refEnd && refUri.startsWith("../", refStart)) { | 4349 while (refStart + 3 <= refEnd && refUri.startsWith("../", refStart)) { |
4352 refStart += 3; | 4350 refStart += 3; |
4353 backCount += 1; | 4351 backCount += 1; |
4354 } | 4352 } |
4355 | 4353 |
4356 // Extra slash inserted between base and reference path parts if | 4354 // Extra slash inserted between base and reference path parts if |
4357 // the base path contains any slashes. | 4355 // the base path contains any slashes, or empty string if none. |
4358 // (We could use a slash from the base path in most cases, but not if | 4356 // (We could use a slash from the base path in most cases, but not if |
4359 // we remove the entire base path). | 4357 // we remove the entire base path). |
4360 String insert = ""; | 4358 String insert = ""; |
| 4359 |
| 4360 /// Remove segments from the base path. |
| 4361 /// Start with the segment trailing the last slash, |
| 4362 /// then remove segments for each leading "../" segment |
| 4363 /// from the reference path, or as many of them as are available. |
4361 while (baseEnd > baseStart) { | 4364 while (baseEnd > baseStart) { |
4362 baseEnd--; | 4365 baseEnd--; |
4363 int char = baseUri.codeUnitAt(baseEnd); | 4366 int char = baseUri.codeUnitAt(baseEnd); |
4364 if (char == _SLASH) { | 4367 if (char == _SLASH) { |
4365 insert = "/"; | 4368 insert = "/"; |
| 4369 if (backCount == 0) break; |
4366 backCount--; | 4370 backCount--; |
4367 if (backCount == 0) break; | |
4368 } | 4371 } |
4369 } | 4372 } |
4370 // If the base URI has no scheme or authority (`_pathStart == 0`) | 4373 |
4371 // and a relative path, and we reached the beginning of the path, | 4374 if (baseEnd == baseStart && !base.hasScheme && !base.hasAbsolutePath) { |
4372 // we have a special case. | 4375 // If the base is *just* a relative path (no scheme or authority), |
4373 if (baseEnd == 0 && !base.hasAbsolutePath) { | 4376 // then merging with another relative path doesn't follow the |
4374 // Non-RFC 3986 behavior when resolving a purely relative path on top of | 4377 // RFC-3986 behavior. |
4375 // another relative path: Don't make the result absolute. | 4378 // Don't need to check `base.hasAuthority` since the base path is |
| 4379 // non-empty - if there is an authority, a non-empty path is absolute. |
| 4380 |
| 4381 // We reached the start of the base path, and want to stay relative, |
| 4382 // so don't insert a slash. |
4376 insert = ""; | 4383 insert = ""; |
| 4384 // If we reached the start of the base path with more "../" left over |
| 4385 // in the reference path, include those segments in the result. |
| 4386 refStart -= backCount * 3; |
4377 } | 4387 } |
4378 | 4388 |
4379 var delta = baseEnd - refStart + insert.length; | 4389 var delta = baseEnd - refStart + insert.length; |
4380 var newUri = "${base._uri.substring(0, baseEnd)}$insert" | 4390 var newUri = "${base._uri.substring(0, baseEnd)}$insert" |
4381 "${ref._uri.substring(refStart)}"; | 4391 "${ref._uri.substring(refStart)}"; |
4382 | 4392 |
4383 return new _SimpleUri(newUri, | 4393 return new _SimpleUri(newUri, |
4384 base._schemeEnd, | 4394 base._schemeEnd, |
4385 base._hostStart, | 4395 base._hostStart, |
4386 base._portStart, | 4396 base._portStart, |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4458 int delta = (text.codeUnitAt(start + 4) ^ _COLON) * 3; | 4468 int delta = (text.codeUnitAt(start + 4) ^ _COLON) * 3; |
4459 delta |= text.codeUnitAt(start) ^ 0x64 /*d*/; | 4469 delta |= text.codeUnitAt(start) ^ 0x64 /*d*/; |
4460 delta |= text.codeUnitAt(start + 1) ^ 0x61 /*a*/; | 4470 delta |= text.codeUnitAt(start + 1) ^ 0x61 /*a*/; |
4461 delta |= text.codeUnitAt(start + 2) ^ 0x74 /*t*/; | 4471 delta |= text.codeUnitAt(start + 2) ^ 0x74 /*t*/; |
4462 delta |= text.codeUnitAt(start + 3) ^ 0x61 /*a*/; | 4472 delta |= text.codeUnitAt(start + 3) ^ 0x61 /*a*/; |
4463 return delta; | 4473 return delta; |
4464 } | 4474 } |
4465 | 4475 |
4466 /// Helper function returning the length of a string, or `0` for `null`. | 4476 /// Helper function returning the length of a string, or `0` for `null`. |
4467 int _stringOrNullLength(String s) => (s == null) ? 0 : s.length; | 4477 int _stringOrNullLength(String s) => (s == null) ? 0 : s.length; |
OLD | NEW |