diff --git a/packages/flutter_tools/lib/src/build_runner/devfs_web.dart b/packages/flutter_tools/lib/src/build_runner/devfs_web.dart index e73c62d017..b2181b5c09 100644 --- a/packages/flutter_tools/lib/src/build_runner/devfs_web.dart +++ b/packages/flutter_tools/lib/src/build_runner/devfs_web.dart @@ -275,7 +275,10 @@ class WebAssetServer implements AssetReader { // handle requests for JavaScript source, dart sources maps, or asset files. @visibleForTesting Future handleRequest(shelf.Request request) async { - final String requestPath = request.url.path; + String requestPath = request.url.path; + while (requestPath.startsWith('/')) { + requestPath = requestPath.substring(1); + } final Map headers = {}; // If the response is `/`, then we are requesting the index file. if (request.url.path == '/' || request.url.path.isEmpty) { @@ -339,8 +342,9 @@ class WebAssetServer implements AssetReader { } if (!file.existsSync()) { - final String webPath = globals.fs.path.join( - globals.fs.currentDirectory.childDirectory('web').path, requestPath); + final Uri webPath = globals.fs.currentDirectory + .childDirectory('web') + .uri.resolve(requestPath); file = globals.fs.file(webPath); } @@ -524,16 +528,14 @@ class WebAssetServer implements AssetReader { final Directory dartSdkParent = globals.fs .directory(globals.artifacts.getArtifactPath(Artifact.engineDartSdkPath)) .parent; - final File dartSdkFile = globals.fs.file(globals.fs.path - .joinAll([dartSdkParent.path, ...segments])); + final File dartSdkFile = globals.fs.file(dartSdkParent.uri.resolve(path)); if (dartSdkFile.existsSync()) { return dartSdkFile; } - final String flutterWebSdk = globals.artifacts - .getArtifactPath(Artifact.flutterWebSdk); - final File webSdkFile = globals.fs - .file(globals.fs.path.joinAll([flutterWebSdk, ...segments])); + final Directory flutterWebSdk = globals.fs.directory(globals.artifacts + .getArtifactPath(Artifact.flutterWebSdk)); + final File webSdkFile = globals.fs.file(flutterWebSdk.uri.resolve(path)); return webSdkFile; } diff --git a/packages/flutter_tools/test/general.shard/web/devfs_web_test.dart b/packages/flutter_tools/test/general.shard/web/devfs_web_test.dart index 99ba582af3..1332551d82 100644 --- a/packages/flutter_tools/test/general.shard/web/devfs_web_test.dart +++ b/packages/flutter_tools/test/general.shard/web/devfs_web_test.dart @@ -108,6 +108,27 @@ void main() { Platform: () => linux, })); + test('Removes leading slashes for valid requests to avoid requesting outside' + ' of served directory', () => testbed.run(() async { + globals.fs.file('foo.png').createSync(); + globals.fs.currentDirectory = globals.fs.directory('project_directory') + ..createSync(); + + final File source = globals.fs.file(globals.fs.path.join('web', 'foo.png')) + ..createSync(recursive: true) + ..writeAsBytesSync(kTransparentImage); + final Response response = await webAssetServer + .handleRequest(Request('GET', Uri.parse('http://foobar////foo.png'))); + + expect(response.headers, allOf([ + containsPair(HttpHeaders.contentLengthHeader, source.lengthSync().toString()), + containsPair(HttpHeaders.contentTypeHeader, 'image/png'), + containsPair(HttpHeaders.etagHeader, isNotNull), + containsPair(HttpHeaders.cacheControlHeader, 'max-age=0, must-revalidate') + ])); + expect((await response.read().toList()).first, source.readAsBytesSync()); + })); + test('serves JavaScript files from in memory cache not from manifest', () => testbed.run(() async { webAssetServer.writeFile('foo.js', 'main() {}');