Skip to content
This repository has been archived by the owner on Oct 16, 2022. It is now read-only.

Commit

Permalink
Send 405 (Method Not Allowed) – for requests that are not HEAD/GET
Browse files Browse the repository at this point in the history
  • Loading branch information
kevmoo committed May 10, 2021
1 parent 85a3a8c commit a52098b
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 6 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## 1.1.0-dev
## 1.1.0

* Correctly send 405 (Method Not Allowed) – for requests that are not `HEAD` or
`GET` method.
* Correctly handle `HEAD` requests.

## 1.0.0
Expand Down
23 changes: 20 additions & 3 deletions lib/src/static_handler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,17 @@ Handler createStaticHandler(String fileSystemPath,
} else if (entityType == FileSystemEntityType.directory) {
fileFound = _tryDefaultFile(fsPath, defaultDocument);
if (fileFound == null && listDirectories) {
if (!_getMethods.contains(request.method)) {
return _methodNotAllowed();
}
final uri = request.requestedUri;
if (!uri.path.endsWith('/')) return _redirectToAddTrailingSlash(uri);
return listDirectory(fileSystemPath, fsPath);
}
}

if (fileFound == null) {
return Response.notFound('Not Found');
return notFound();
}
final file = fileFound;

Expand All @@ -91,7 +94,7 @@ Handler createStaticHandler(String fileSystemPath,

// Do not serve a file outside of the original fileSystemPath
if (!p.isWithin(fileSystemPath, resolvedPath)) {
return Response.notFound('Not Found');
return notFound();
}
}

Expand Down Expand Up @@ -166,7 +169,7 @@ Handler createFileHandler(String path, {String? url, String? contentType}) {
url ??= p.toUri(p.basename(path)).toString();

return (request) {
if (request.url.path != url) return Response.notFound('Not Found');
if (request.url.path != url) return notFound();
return _handleFile(request, file, () => mimeType);
};
}
Expand All @@ -178,6 +181,10 @@ Handler createFileHandler(String path, {String? url, String? contentType}) {
/// [getContentType] and uses it to populate the Content-Type header.
Future<Response> _handleFile(Request request, File file,
FutureOr<String?> Function() getContentType) async {
if (!_getMethods.contains(request.method)) {
return _methodNotAllowed();
}

final stat = file.statSync();
final ifModifiedSince = request.ifModifiedSince;

Expand All @@ -201,3 +208,13 @@ Future<Response> _handleFile(Request request, File file,
headers: headers,
);
}

/// HTTP methods which return OK (200) responses with static file servers.
const _getMethods = {'GET', 'HEAD'};

/// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/405 and
/// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Allow
Response _methodNotAllowed() => Response(
405,
headers: {'Allow': _getMethods.join(', ')},
);
4 changes: 4 additions & 0 deletions lib/src/util.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:shelf/shelf.dart';

DateTime toSecondResolution(DateTime dt) {
if (dt.millisecond == 0) return dt;
return dt.subtract(Duration(milliseconds: dt.millisecond));
}

Response notFound() => Response.notFound('Not Found');
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: shelf_static
version: 1.1.0-dev
version: 1.1.0
description: Static file server support for the shelf package and ecosystem
repository: https://github.com/dart-lang/shelf_static

Expand Down
26 changes: 26 additions & 0 deletions test/basic_file_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'dart:io';
import 'package:http_parser/http_parser.dart';
import 'package:mime/mime.dart' as mime;
import 'package:path/path.dart' as p;
import 'package:shelf/src/handler.dart';
import 'package:shelf_static/shelf_static.dart';
import 'package:test/test.dart';
import 'package:test_descriptor/test_descriptor.dart' as d;
Expand Down Expand Up @@ -233,4 +234,29 @@ void main() {
expect(response.mimeType, 'image/webp');
});
});

group('HTTP method', () {
for (var method in _httpMethods) {
test('$method - file', () async {
final handler = createStaticHandler(d.sandbox);

await _testBadMethod(handler, method, '/root.txt');
});

test('$method - directory', () async {
final handler = createStaticHandler(d.sandbox, listDirectories: true);

await _testBadMethod(handler, method, '/');
});
}
});
}

Future<void> _testBadMethod(Handler handler, String method, String path) async {
final response = await makeRequest(handler, path, method: method);

expect(response.statusCode, HttpStatus.methodNotAllowed);
expect(response.headers['allow'], 'GET, HEAD');
}

const _httpMethods = {'PUT', 'POST', 'DELETE', 'PATCH'};
2 changes: 1 addition & 1 deletion test/test_util.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Handler _rootHandler(String? path, Handler handler) {

return (Request request) {
if (!_ctx.isWithin('/$path', request.requestedUri.path)) {
return Response.notFound('not found');
return notFound();
}
assert(request.handlerPath == '/');

Expand Down

0 comments on commit a52098b

Please sign in to comment.