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

Send 405 (Method Not Allowed) – for requests that are not HEAD/GET #55

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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