Skip to content
Closed
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
37 changes: 35 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,12 @@ 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].
/// If the file is considered not found because it is outside of the
/// [fileSystemPath] and [serveFilesOutsidePath] is false, then neither key
/// will be included in the context.
Handler createStaticHandler(String fileSystemPath,
{bool serveFilesOutsidePath = false,
String? defaultDocument,
Expand Down Expand Up @@ -82,8 +88,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 +138,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 +214,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 +231,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