Skip to content
Closed
Changes from 5 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
36 changes: 34 additions & 2 deletions pkgs/shelf_static/lib/src/static_handler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ final _defaultMimeTypeResolver = MimeTypeResolver();
///
/// Specify a custom [contentTypeResolver] to customize automatic content type
/// detection.
///
/// The [Response.context] will be populated with "shelf_static:file" or
/// "shelf_static:file_not_found" with the resolved [File] for the [Response],
/// while respecting [serveFilesOutsidePath] to prevent exposing a [File] path
/// outside of the [fileSystemPath].
Handler createStaticHandler(String fileSystemPath,
{bool serveFilesOutsidePath = false,
String? defaultDocument,
Expand Down Expand Up @@ -82,8 +87,20 @@ Handler createStaticHandler(String fileSystemPath,
}

if (fileFound == null) {
return Response.notFound('Not Found');
File? fileNotFound = File(fsPath);

// Do not expose a file path outside of the original fileSystemPath:
if (!serveFilesOutsidePath &&
!p.isWithin(fileSystemPath, fileNotFound.path)) {
fileNotFound = null;
}

return Response.notFound(
'Not Found',
context: _buildResponseContext(fileNotFound: fileNotFound),
);
}

final file = fileFound;

if (!serveFilesOutsidePath) {
Expand Down Expand Up @@ -120,6 +137,18 @@ Handler createStaticHandler(String fileSystemPath,
};
}

Map<String, Object>? _buildResponseContext({File? file, File? fileNotFound}) {
if (file == null && fileNotFound == null) return null;

// Ensure other Shelf `Middleware` can identify
// the processed file in the `Response` by
// including `file` and `file_not_found` in the context:
return {
if (file != null) 'shelf_static:file': file,
if (fileNotFound != null) 'shelf_static:file_not_found': fileNotFound,
};
}

Response _redirectToAddTrailingSlash(Uri uri) {
final location = Uri(
scheme: uri.scheme,
Expand Down Expand Up @@ -184,7 +213,9 @@ Future<Response> _handleFile(Request request, File file,
if (ifModifiedSince != null) {
final fileChangeAtSecResolution = toSecondResolution(stat.modified);
if (!fileChangeAtSecResolution.isAfter(ifModifiedSince)) {
return Response.notModified();
return Response.notModified(
context: _buildResponseContext(file: file),
);
}
}

Expand All @@ -199,6 +230,7 @@ Future<Response> _handleFile(Request request, File file,
Response.ok(
request.method == 'HEAD' ? null : file.openRead(),
headers: headers..[HttpHeaders.contentLengthHeader] = '${stat.size}',
context: _buildResponseContext(file: file),
);
}

Expand Down