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

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

Issue 2626013004: Fix invalid URIs generated using Uri constructor with clever paths. (Closed)
Patch Set: Created 3 years, 11 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
« no previous file with comments | « no previous file | tests/corelib/uri_test.dart » ('j') | tests/corelib/uri_test.dart » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 1452 matching lines...) Expand 10 before | Expand all | Expand 10 after
1463 port = _makePort(port, scheme); 1463 port = _makePort(port, scheme);
1464 bool isFile = (scheme == "file"); 1464 bool isFile = (scheme == "file");
1465 if (host == null && 1465 if (host == null &&
1466 (userInfo.isNotEmpty || port != null || isFile)) { 1466 (userInfo.isNotEmpty || port != null || isFile)) {
1467 host = ""; 1467 host = "";
1468 } 1468 }
1469 bool hasAuthority = (host != null); 1469 bool hasAuthority = (host != null);
1470 path = _makePath(path, 0, _stringOrNullLength(path), pathSegments, 1470 path = _makePath(path, 0, _stringOrNullLength(path), pathSegments,
1471 scheme, hasAuthority); 1471 scheme, hasAuthority);
1472 if (scheme.isEmpty && host == null && !path.startsWith('/')) { 1472 if (scheme.isEmpty && host == null && !path.startsWith('/')) {
1473 path = _normalizeRelativePath(path); 1473 path = _normalizeRelativePath(path, scheme.isNotEmpty || host != null);
floitsch 2017/01/12 16:05:49 I generally assign boolean variables to locals fir
Lasse Reichstein Nielsen 2017/01/16 08:17:23 Done.
1474 } else { 1474 } else {
1475 path = _removeDotSegments(path); 1475 path = _removeDotSegments(path);
1476 } 1476 }
1477 if (host == null && path.startsWith("//")) {
1478 host = "";
1479 }
1477 return new _Uri._internal(scheme, userInfo, host, port, 1480 return new _Uri._internal(scheme, userInfo, host, port,
1478 path, query, fragment); 1481 path, query, fragment);
1479 } 1482 }
1480 1483
1481 /// Implementation of [Uri.http]. 1484 /// Implementation of [Uri.http].
1482 factory _Uri.http(String authority, 1485 factory _Uri.http(String authority,
1483 String unencodedPath, 1486 String unencodedPath,
1484 [Map<String, String> queryParameters]) { 1487 [Map<String, String> queryParameters]) {
1485 return _makeHttpUri("http", authority, unencodedPath, queryParameters); 1488 return _makeHttpUri("http", authority, unencodedPath, queryParameters);
1486 } 1489 }
(...skipping 564 matching lines...) Expand 10 before | Expand all | Expand 10 after
2051 return result; 2054 return result;
2052 } 2055 }
2053 2056
2054 /// Performs path normalization (remove dot segments) on a path. 2057 /// Performs path normalization (remove dot segments) on a path.
2055 /// 2058 ///
2056 /// If the URI has neither scheme nor authority, it's considered a 2059 /// If the URI has neither scheme nor authority, it's considered a
2057 /// "pure path" and normalization won't remove leading ".." segments. 2060 /// "pure path" and normalization won't remove leading ".." segments.
2058 /// Otherwise it follows the RFC 3986 "remove dot segments" algorithm. 2061 /// Otherwise it follows the RFC 3986 "remove dot segments" algorithm.
2059 static String _normalizePath(String path, String scheme, bool hasAuthority) { 2062 static String _normalizePath(String path, String scheme, bool hasAuthority) {
2060 if (scheme.isEmpty && !hasAuthority && !path.startsWith('/')) { 2063 if (scheme.isEmpty && !hasAuthority && !path.startsWith('/')) {
2061 return _normalizeRelativePath(path); 2064 return _normalizeRelativePath(path, scheme.isNotEmpty || hasAuthority);
2062 } 2065 }
2063 return _removeDotSegments(path); 2066 return _removeDotSegments(path);
2064 } 2067 }
2065 2068
2066 static String _makeQuery( 2069 static String _makeQuery(
2067 String query, int start, int end, 2070 String query, int start, int end,
2068 Map<String, dynamic/*String|Iterable<String>*/> queryParameters) { 2071 Map<String, dynamic/*String|Iterable<String>*/> queryParameters) {
2069 if (query != null) { 2072 if (query != null) {
2070 if (queryParameters != null) { 2073 if (queryParameters != null) {
2071 throw new ArgumentError('Both query and queryParameters specified'); 2074 throw new ArgumentError('Both query and queryParameters specified');
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after
2347 } else { 2350 } else {
2348 output.add(segment); 2351 output.add(segment);
2349 } 2352 }
2350 } 2353 }
2351 if (appendSlash) output.add(""); 2354 if (appendSlash) output.add("");
2352 return output.join("/"); 2355 return output.join("/");
2353 } 2356 }
2354 2357
2355 /// Removes all `.` segments and any non-leading `..` segments. 2358 /// Removes all `.` segments and any non-leading `..` segments.
2356 /// 2359 ///
2360 /// If the path starts with something that looks like a scheme,
2361 /// and [allowScheme] is false, the colon is escaped.
2362 ///
2357 /// Removing the ".." from a "bar/foo/.." sequence results in "bar/" 2363 /// Removing the ".." from a "bar/foo/.." sequence results in "bar/"
2358 /// (trailing "/"). If the entire path is removed (because it contains as 2364 /// (trailing "/"). If the entire path is removed (because it contains as
2359 /// many ".." segments as real segments), the result is "./". 2365 /// many ".." segments as real segments), the result is "./".
2360 /// This is different from an empty string, which represents "no path", 2366 /// This is different from an empty string, which represents "no path",
2361 /// when you resolve it against a base URI with a path with a non-empty 2367 /// when you resolve it against a base URI with a path with a non-empty
2362 /// final segment. 2368 /// final segment.
2363 static String _normalizeRelativePath(String path) { 2369 static String _normalizeRelativePath(String path, bool allowScheme) {
2364 assert(!path.startsWith('/')); // Only get called for relative paths. 2370 assert(!path.startsWith('/')); // Only get called for relative paths.
2365 if (!_mayContainDotSegments(path)) return path; 2371 if (!_mayContainDotSegments(path)) {
2372 if (!allowScheme) path = _escapeScheme(path);
2373 return path;
2374 }
2366 assert(path.isNotEmpty); // An empty path would not have dot segments. 2375 assert(path.isNotEmpty); // An empty path would not have dot segments.
2367 List<String> output = []; 2376 List<String> output = [];
2368 bool appendSlash = false; 2377 bool appendSlash = false;
2369 for (String segment in path.split("/")) { 2378 for (String segment in path.split("/")) {
2370 appendSlash = false; 2379 appendSlash = false;
2371 if (".." == segment) { 2380 if (".." == segment) {
2372 if (!output.isEmpty && output.last != "..") { 2381 if (!output.isEmpty && output.last != "..") {
2373 output.removeLast(); 2382 output.removeLast();
2374 appendSlash = true; 2383 appendSlash = true;
2375 } else { 2384 } else {
2376 output.add(".."); 2385 output.add("..");
2377 } 2386 }
2378 } else if ("." == segment) { 2387 } else if ("." == segment) {
2379 appendSlash = true; 2388 appendSlash = true;
2380 } else { 2389 } else {
2381 output.add(segment); 2390 output.add(segment);
2382 } 2391 }
2383 } 2392 }
2384 if (output.isEmpty || (output.length == 1 && output[0].isEmpty)) { 2393 if (output.isEmpty || (output.length == 1 && output[0].isEmpty)) {
2385 return "./"; 2394 return "./";
2386 } 2395 }
2387 if (appendSlash || output.last == '..') output.add(""); 2396 if (appendSlash || output.last == '..') output.add("");
2397 if (!allowScheme) output[0] = _escapeScheme(output[0]);
2388 return output.join("/"); 2398 return output.join("/");
2389 } 2399 }
2390 2400
2401 /// If [path] starts with a valid scheme, escape the percent.
2402 static String _escapeScheme(String path) {
2403 if (path.length >= 2 && _isAlphabeticCharacter(path.codeUnitAt(0))) {
2404 for (int i = 1; i < path.length; i++) {
2405 int char = path.codeUnitAt(i);
2406 if (char == _COLON) {
2407 return "${path.substring(0, i)}%3A${path.substring(i + 1)}";
2408 }
2409 if (char > 127 ||
2410 ((_schemeTable[char >> 4] & (1 << (char & 0x0f))) == 0)) {
2411 break;
2412 }
2413 }
2414 }
2415 return path;
2416 }
2417
2391 Uri resolve(String reference) { 2418 Uri resolve(String reference) {
2392 return resolveUri(Uri.parse(reference)); 2419 return resolveUri(Uri.parse(reference));
2393 } 2420 }
2394 2421
2395 Uri resolveUri(Uri reference) { 2422 Uri resolveUri(Uri reference) {
2396 // From RFC 3986. 2423 // From RFC 3986.
2397 String targetScheme; 2424 String targetScheme;
2398 String targetUserInfo = ""; 2425 String targetUserInfo = "";
2399 String targetHost; 2426 String targetHost;
2400 int targetPort; 2427 int targetPort;
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
2452 } 2479 }
2453 } else { 2480 } else {
2454 var mergedPath = _mergePaths(this._path, reference.path); 2481 var mergedPath = _mergePaths(this._path, reference.path);
2455 if (this.hasScheme || this.hasAuthority || this.hasAbsolutePath) { 2482 if (this.hasScheme || this.hasAuthority || this.hasAbsolutePath) {
2456 targetPath = _removeDotSegments(mergedPath); 2483 targetPath = _removeDotSegments(mergedPath);
2457 } else { 2484 } else {
2458 // Non-RFC 3986 behavior. 2485 // Non-RFC 3986 behavior.
2459 // If both base and reference are relative paths, 2486 // If both base and reference are relative paths,
2460 // allow the merged path to start with "..". 2487 // allow the merged path to start with "..".
2461 // The RFC only specifies the case where the base has a scheme. 2488 // The RFC only specifies the case where the base has a scheme.
2462 targetPath = _normalizeRelativePath(mergedPath); 2489 targetPath = _normalizeRelativePath(mergedPath,
2490 this.hasScheme || this.hasAuthority);
2463 } 2491 }
2464 } 2492 }
2465 } 2493 }
2466 if (reference.hasQuery) targetQuery = reference.query; 2494 if (reference.hasQuery) targetQuery = reference.query;
2467 } 2495 }
2468 } 2496 }
2469 } 2497 }
2470 String fragment = reference.hasFragment ? reference.fragment : null; 2498 String fragment = reference.hasFragment ? reference.fragment : null;
2471 return new _Uri._internal(targetScheme, 2499 return new _Uri._internal(targetScheme,
2472 targetUserInfo, 2500 targetUserInfo,
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
2589 UriData get data => (scheme == "data") ? new UriData.fromUri(this) : null; 2617 UriData get data => (scheme == "data") ? new UriData.fromUri(this) : null;
2590 2618
2591 String toString() { 2619 String toString() {
2592 return _text ??= _initializeText(); 2620 return _text ??= _initializeText();
2593 } 2621 }
2594 2622
2595 String _initializeText() { 2623 String _initializeText() {
2596 assert(_text == null); 2624 assert(_text == null);
2597 StringBuffer sb = new StringBuffer(); 2625 StringBuffer sb = new StringBuffer();
2598 if (scheme.isNotEmpty) sb..write(scheme)..write(":"); 2626 if (scheme.isNotEmpty) sb..write(scheme)..write(":");
2599 if (hasAuthority || path.startsWith("//") || (scheme == "file")) { 2627 if (hasAuthority || (scheme == "file")) {
2600 // File URIS always have the authority, even if it is empty. 2628 // File URIS always have the authority, even if it is empty.
2601 // The empty URI means "localhost". 2629 // The empty URI means "localhost".
2602 sb.write("//"); 2630 sb.write("//");
2603 _writeAuthority(sb); 2631 _writeAuthority(sb);
2604 } 2632 }
2605 sb.write(path); 2633 sb.write(path);
2606 if (_query != null) sb..write("?")..write(_query); 2634 if (_query != null) sb..write("?")..write(_query);
2607 if (_fragment != null) sb..write("#")..write(_fragment); 2635 if (_fragment != null) sb..write("#")..write(_fragment);
2608 return sb.toString(); 2636 return sb.toString();
2609 } 2637 }
(...skipping 1858 matching lines...) Expand 10 before | Expand all | Expand 10 after
4468 int delta = (text.codeUnitAt(start + 4) ^ _COLON) * 3; 4496 int delta = (text.codeUnitAt(start + 4) ^ _COLON) * 3;
4469 delta |= text.codeUnitAt(start) ^ 0x64 /*d*/; 4497 delta |= text.codeUnitAt(start) ^ 0x64 /*d*/;
4470 delta |= text.codeUnitAt(start + 1) ^ 0x61 /*a*/; 4498 delta |= text.codeUnitAt(start + 1) ^ 0x61 /*a*/;
4471 delta |= text.codeUnitAt(start + 2) ^ 0x74 /*t*/; 4499 delta |= text.codeUnitAt(start + 2) ^ 0x74 /*t*/;
4472 delta |= text.codeUnitAt(start + 3) ^ 0x61 /*a*/; 4500 delta |= text.codeUnitAt(start + 3) ^ 0x61 /*a*/;
4473 return delta; 4501 return delta;
4474 } 4502 }
4475 4503
4476 /// Helper function returning the length of a string, or `0` for `null`. 4504 /// Helper function returning the length of a string, or `0` for `null`.
4477 int _stringOrNullLength(String s) => (s == null) ? 0 : s.length; 4505 int _stringOrNullLength(String s) => (s == null) ? 0 : s.length;
OLDNEW
« no previous file with comments | « no previous file | tests/corelib/uri_test.dart » ('j') | tests/corelib/uri_test.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698