sanity checks for invalid paths
diff --git a/lib/shelf_static.dart b/lib/shelf_static.dart
index 83944d7..41946b6 100644
--- a/lib/shelf_static.dart
+++ b/lib/shelf_static.dart
@@ -16,6 +16,11 @@
fileSystemPath = rootDir.resolveSymbolicLinksSync();
return (Request request) {
+ // TODO: expand these checks and/or follow updates to Uri class to be more
+ // strict.
+ if (request.requestedUri.path.contains(' ')) {
+ return new Response.forbidden('The requested path is invalid.');
+ }
var segs = [fileSystemPath]..addAll(request.requestedUri.pathSegments);
diff --git a/test/basic_file_test.dart b/test/basic_file_test.dart
index e840d0c..a74741e 100644
--- a/test/basic_file_test.dart
+++ b/test/basic_file_test.dart
@@ -19,13 +19,13 @@
d.file('root.txt', 'root txt').create();
d.dir('files', [
- d.file('test.txt', 'test txt content')
+ d.file('test.txt', 'test txt content'),
+ d.file('with space.txt', 'with space content')
]).create();
currentSchedule.onComplete.schedule(() {
- print(d.defaultRoot);
d.defaultRoot = null;
- //return tempDir.delete(recursive: true);
+ return tempDir.delete(recursive: true);
});
});
@@ -41,6 +41,28 @@
});
});
+ test('access root file with space', () {
+ schedule(() {
+ var handler = getHandler(d.defaultRoot);
+
+ return makeRequest(handler, '/files/with%20space.txt').then((response) {
+ expect(response.statusCode, HttpStatus.OK);
+ expect(response.headers[HttpHeaders.CONTENT_LENGTH], '18');
+ expect(response.readAsString(), completion('with space content'));
+ });
+ });
+ });
+
+ test('access root file with unencoded space', () {
+ schedule(() {
+ var handler = getHandler(d.defaultRoot);
+
+ return makeRequest(handler, '/files/with space.txt').then((response) {
+ expect(response.statusCode, HttpStatus.FORBIDDEN);
+ });
+ });
+ });
+
test('access file under directory', () {
schedule(() {
var handler = getHandler(d.defaultRoot);
@@ -63,9 +85,6 @@
});
});
- // root file success, fail
- // pathed file success, fail
-
// evil URL fixes
// hosted via other path: success, fail