createStaticHandler function

Handler createStaticHandler(
  1. String path, {
  2. StaticHandlerConfig? config,
})

Creates a Shelf handler for serving static files.

Example

final app = Router();

// Serve compiled assets from build/web
app.mount('/', createStaticHandler('build/web'));

// Or with configuration
app.mount('/', createStaticHandler(
  'build/web',
  config: StaticHandlerConfig(
    path: 'build/web',
    enableCaching: true,
    maxAge: 86400,
  ),
));

Implementation

Handler createStaticHandler(String path, {StaticHandlerConfig? config}) {
  config ??= StaticHandlerConfig(path: path);

  return (Request request) async {
    var filePath = request.url.path;

    // Remove leading slash if present
    if (filePath.startsWith('/')) {
      filePath = filePath.substring(1);
    }

    // Construct full file path
    final fullPath = filePath.isEmpty
        ? config!.path
        : '${config!.path}/$filePath';

    // Check for directory traversal attacks
    final normalizedPath = File(fullPath).absolute.path;
    final basePath = Directory(config.path).absolute.path;
    if (!normalizedPath.startsWith(basePath)) {
      return Response.forbidden('Access denied');
    }

    final file = File(fullPath);
    final dir = Directory(fullPath);

    // Handle directory requests
    if (await dir.exists()) {
      if (config.defaultFile != null) {
        final defaultFile = File('$fullPath/${config.defaultFile}');
        if (await defaultFile.exists()) {
          return _serveFile(defaultFile, config, request);
        }
      }

      if (config.listDirectories) {
        return _listDirectory(dir, filePath);
      }

      return Response.notFound('Not found');
    }

    // Handle file requests
    if (await file.exists()) {
      return _serveFile(file, config, request);
    }

    return Response.notFound('Not found');
  };
}