Skip to content

Commit 8c7de11

Browse files
committed
Handle AssetIds with invalid URI characters
Fixes #1134 Rewrite the URI encoding for AssetId to be more robust by using the built in URI escaping when using `pathSegments` instead of `path`. Delete a duplicate of the AssetId test file.
1 parent d34b262 commit 8c7de11

File tree

5 files changed

+59
-152
lines changed

5 files changed

+59
-152
lines changed

build/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 0.12.0+2
2+
3+
- **Bug Fix** Correctly handle encoding `AssetId`s as `URI`s when they contain
4+
characters which are not valid for a path segment.
5+
16
## 0.12.0+1
27

38
- Support the latest `analyzer` package.

build/lib/src/asset/id.dart

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,7 @@ class AssetId implements Comparable<AssetId> {
9898
/// A `package:` URI suitable for use directly with other systems if this
9999
/// asset is under it's package's `lib/` directory, else an `asset:` URI
100100
/// suitable for use within build tools.
101-
Uri get uri => _uri ??= path.startsWith('lib/')
102-
? new Uri(
103-
scheme: 'package', path: '$package/${path.replaceFirst('lib/','')}')
104-
: new Uri(scheme: 'asset', path: '$package/$path');
101+
Uri get uri => _uri ??= _constructUri(this);
105102
Uri _uri;
106103

107104
/// Deserializes an [AssetId] from [data], which must be the result of
@@ -154,3 +151,12 @@ String _normalizePath(String path) {
154151
// Collapse "." and "..".
155152
return p.posix.normalize(path);
156153
}
154+
155+
Uri _constructUri(AssetId id) {
156+
final originalSegments = p.split(id.path);
157+
final isLib = originalSegments.first == 'lib';
158+
final scheme = isLib ? 'package' : 'asset';
159+
final pathSegmens = isLib ? originalSegments.skip(1) : originalSegments;
160+
return new Uri(
161+
scheme: scheme, pathSegments: [id.package]..addAll(pathSegmens));
162+
}

build/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: build
2-
version: 0.12.0+1
2+
version: 0.12.0+2
33
description: A build system for Dart.
44
author: Dart Team <[email protected]>
55
homepage: https://github.com/dart-lang/build/tree/master/build

build/test/asset/id_test.dart

Lines changed: 43 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -8,114 +8,81 @@ import 'package:build/build.dart';
88

99
// Forked from `barback/test/asset_id_test.dart`.
1010
void main() {
11-
group("constructor", () {
12-
test("normalizes the path", () {
13-
var id = new AssetId("app", r"path/././/to/drop/..//asset.txt");
14-
expect(id.path, equals("path/to/asset.txt"));
11+
group('constructor', () {
12+
test('normalizes the path', () {
13+
var id = new AssetId('app', r'path/././/to/drop/..//asset.txt');
14+
expect(id.path, equals('path/to/asset.txt'));
1515
});
1616

17-
test("normalizes backslashes to slashes in the path", () {
18-
var id = new AssetId("app", r"path\to/asset.txt");
19-
expect(id.path, equals("path/to/asset.txt"));
17+
test('normalizes backslashes to slashes in the path', () {
18+
var id = new AssetId('app', r'path\to/asset.txt');
19+
expect(id.path, equals('path/to/asset.txt'));
2020
});
2121
});
2222

23-
group("parse", () {
24-
test("parses the package and path", () {
25-
var id = new AssetId.parse("package|path/to/asset.txt");
26-
expect(id.package, equals("package"));
27-
expect(id.path, equals("path/to/asset.txt"));
23+
group('parse', () {
24+
test('parses the package and path', () {
25+
var id = new AssetId.parse('package|path/to/asset.txt');
26+
expect(id.package, equals('package'));
27+
expect(id.path, equals('path/to/asset.txt'));
2828
});
2929

30-
test("throws if there are multiple '|'", () {
31-
expect(() => new AssetId.parse("app|path|wtf"), throwsFormatException);
30+
test('throws if there are multiple "|"', () {
31+
expect(() => new AssetId.parse('app|path|wtf'), throwsFormatException);
3232
});
3333

34-
test("throws if the package name is empty '|'", () {
35-
expect(() => new AssetId.parse("|asset.txt"), throwsFormatException);
34+
test('throws if the package name is empty "|"', () {
35+
expect(() => new AssetId.parse('|asset.txt'), throwsFormatException);
3636
});
3737

38-
test("throws if the path is empty '|'", () {
39-
expect(() => new AssetId.parse("app|"), throwsFormatException);
38+
test('throws if the path is empty "|"', () {
39+
expect(() => new AssetId.parse('app|'), throwsFormatException);
4040
});
4141

42-
test("normalizes the path", () {
43-
var id = new AssetId.parse(r"app|path/././/to/drop/..//asset.txt");
44-
expect(id.path, equals("path/to/asset.txt"));
42+
test('normalizes the path', () {
43+
var id = new AssetId.parse(r'app|path/././/to/drop/..//asset.txt');
44+
expect(id.path, equals('path/to/asset.txt'));
4545
});
4646

47-
test("normalizes backslashes to slashes in the path", () {
48-
var id = new AssetId.parse(r"app|path\to/asset.txt");
49-
expect(id.path, equals("path/to/asset.txt"));
47+
test('normalizes backslashes to slashes in the path', () {
48+
var id = new AssetId.parse(r'app|path\to/asset.txt');
49+
expect(id.path, equals('path/to/asset.txt'));
5050
});
5151
});
5252

53-
group("resolve", () {
54-
test("should parse a package: URI", () {
55-
var id = new AssetId.resolve(r"package:app/app.dart");
56-
expect(id, new AssetId("app", "lib/app.dart"));
53+
group('to URI', () {
54+
test('uses `package:` URIs inside lib/', () {
55+
expect(new AssetId('foo', 'lib/bar.dart').uri,
56+
Uri.parse('package:foo/bar.dart'));
5757
});
5858

59-
test("should parse a package: URI with a long path", () {
60-
var id = new AssetId.resolve(r"package:app/src/some/path.dart");
61-
expect(id, new AssetId("app", "lib/src/some/path.dart"));
59+
test('uses `asset:` URIs outside lib/', () async {
60+
expect(new AssetId('foo', 'web/main.dart').uri,
61+
Uri.parse('asset:foo/web/main.dart'));
6262
});
6363

64-
test("should parse an asset: URI", () {
65-
var id = new AssetId.resolve(r"asset:app/test/foo_test.dart");
66-
expect(id, new AssetId("app", "test/foo_test.dart"));
67-
});
68-
69-
test("should throw for a file: URI", () {
70-
expect(() => new AssetId.resolve(r"file://localhost/etc/fstab1"),
71-
throwsUnsupportedError);
72-
});
73-
74-
test("should throw for a dart: URI", () {
75-
expect(() => new AssetId.resolve(r"dart:collection"),
76-
throwsUnsupportedError);
77-
});
78-
79-
test("should throw parsing a relative package URI without an origin", () {
80-
expect(() => new AssetId.resolve("some/relative/path.dart"),
81-
throwsArgumentError);
82-
});
83-
84-
test("should parse a relative URI within the test/ folder", () {
85-
var id = new AssetId.resolve("common.dart",
86-
from: new AssetId("app", "test/some_test.dart"));
87-
expect(id, new AssetId("app", "test/common.dart"));
88-
});
89-
90-
test("should parse a relative package URI", () {
91-
var id = new AssetId.resolve("some/relative/path.dart",
92-
from: new AssetId("app", "lib/app.dart"));
93-
expect(id, new AssetId("app", "lib/some/relative/path.dart"));
94-
});
95-
96-
test("should parse a relative package URI pointing back", () {
97-
var id = new AssetId.resolve("../src/some/path.dart",
98-
from: new AssetId("app", "folder/folder.dart"));
99-
expect(id, new AssetId("app", "src/some/path.dart"));
64+
test('handles characters that are valid in a file path', () {
65+
expect(new AssetId('foo', 'lib/#bar.dart').uri,
66+
Uri.parse('package:foo/%23bar.dart'));
10067
});
10168
});
10269

103-
test("equals another ID with the same package and path", () {
104-
expect(new AssetId.parse("foo|asset.txt"),
105-
equals(new AssetId.parse("foo|asset.txt")));
70+
test('equals another ID with the same package and path', () {
71+
expect(new AssetId.parse('foo|asset.txt'),
72+
equals(new AssetId.parse('foo|asset.txt')));
10673

107-
expect(new AssetId.parse("foo|asset.txt"),
108-
isNot(equals(new AssetId.parse("bar|asset.txt"))));
74+
expect(new AssetId.parse('foo|asset.txt'),
75+
isNot(equals(new AssetId.parse('bar|asset.txt'))));
10976

110-
expect(new AssetId.parse("foo|asset.txt"),
111-
isNot(equals(new AssetId.parse("bar|other.txt"))));
77+
expect(new AssetId.parse('foo|asset.txt'),
78+
isNot(equals(new AssetId.parse('bar|other.txt'))));
11279
});
11380

114-
test("identical assets are treated as the same in a Map/Set", () {
81+
test('identical assets are treated as the same in a Map/Set', () {
11582
var id1 = new AssetId('a', 'web/a.txt');
11683
var id2 = new AssetId('a', 'web/a.txt');
11784

11885
expect({id1: true}.containsKey(id2), isTrue);
119-
expect(new Set<AssetId>.from([id1]), contains(id2));
86+
expect([id1].toSet(), contains(id2));
12087
});
12188
}

build_runner/test/asset/id_test.dart

Lines changed: 0 additions & 71 deletions
This file was deleted.

0 commit comments

Comments
 (0)