handler method
Request handler.
Register this request handler with the server's pipeline using a pattern with a single wildcard pattern. That path parameter will be used as the relative path underneath the baseDir to find the file or directory.
Implementation
Future<Response> handler(Request req) async {
assert(_baseDir.isNotEmpty);
// Get the relative path
final values = req.pathParams.values('*');
if (values.isEmpty) {
throw ArgumentError('Static file handler registered with no *');
} else if (1 < values.length) {
throw ArgumentError('Static file handler registered with multiple *');
}
final components = values[0].split('/');
var depth = 0;
while (0 <= depth && depth < components.length) {
final c = components[depth];
if (c == '..') {
components.removeAt(depth);
depth--;
if (depth < 0) {
if (throwNotFoundExceptions) {
// tried to climb above base directory
throw NotFoundException(NotFoundException.foundStaticHandler);
} else {
throw NoResponseFromHandler();
}
}
} else if (c == '.') {
components.removeAt(depth);
} else if (c.isEmpty && depth != components.length - 1) {
components.removeAt(depth); // keep last '' to indicate dir listing
} else {
depth++;
}
}
final path = '$_baseDir/${components.join('/')}';
_logStaticFiles.finer('[${req.id}] static file/directory requested: $path');
if (!path.endsWith('/')) {
// Probably a file
final file = File(path);
if (file.existsSync()) {
_logStaticFiles.finest('[${req.id}] static file found: $path');
return await _serveFile(req, file);
} else if (allowFilePathsAsDirectories && Directory(path).existsSync()) {
// A directory exists with the same name
if (allowDirectoryListing || await _findDefaultFile('$path/') != null) {
// Can tell the browser to treat it as a directory
// Note: must change URL in browser to have a '/' at the end,
// otherwise any relative links would break.
_logStaticFiles.finest('[${req.id}] treating as static directory');
// Determine the actual URL that was requested, taking into account
// any proxying (indicated by [publicUrlPrefix]). If the proxying
// is not taken into account, the browser won't be able to resolve
// the URL in the redirect response.
//
// In the following, remember `req.requestPath()` is an internal URL
// that always starts with '~/'.
//
// See [publicUrlPrefix] for details.
String requestedUrl;
if (publicServerUrl.isEmpty) {
// No proxying
requestedUrl = req.requestPath();
} else if (publicServerUrl.endsWith('/')) {
// Public URL prefix already ends in a slash, so don't use the
// slash at the beginning of the requestPath when concatenating.
requestedUrl = publicServerUrl + req.requestPath().substring(2);
} else {
// Public URL prefix does not end in a slash, so use the slash at
// the beginning of the requestPath
requestedUrl = publicServerUrl + req.requestPath().substring(1);
}
return ResponseRedirect('$requestedUrl/'); // append a slash
}
} else {
_logStaticFiles.finest('[${req.id}] static file not found');
}
} else {
// Request for a directory
final dir = Directory(path);
if (dir.existsSync()) {
// Try to find one of the default files in that directory
final defaultFile = await _findDefaultFile(path);
if (defaultFile != null) {
_logStaticFiles.finest(
'[${req.id}] static directory: default file found: $defaultFile');
return await _serveFile(req, defaultFile);
}
if (allowDirectoryListing) {
// List the contents of the directory
_logStaticFiles.finest('[${req.id}] returning directory listing');
final notTop = (1 < components.length);
return await directoryListing(req, dir, linkToParent: notTop);
} else {
_logStaticFiles
.finest('[${req.id}] static directory listing not allowed');
}
} else {
_logStaticFiles.finest('[${req.id}] static directory not found');
}
}
// Not found (or directory listing not allowed)
if (throwNotFoundExceptions) {
throw NotFoundException(NotFoundException.foundStaticHandler);
} else {
throw NoResponseFromHandler();
}
}