class Assets
Represents an HTTP middleware for serving static assets.
This middleware serves static files from a configured root directory with appropriate content type headers and caching controls. It supports a wide range of web file formats including HTML, CSS, JavaScript, images, fonts, audio, video, and WebAssembly files.
Definitions
def initialize(delegate, root: PUBLIC_ROOT, content_types: DEFAULT_CONTENT_TYPES, cache_control: DEFAULT_CACHE_CONTROL)
Initialize a new assets middleware instance.
Signature
-
parameter
delegate
Protocol::HTTP::Middleware
The next middleware in the chain.
-
parameter
root
String
The root directory path for serving assets.
-
parameter
content_types
Hash
Mapping of file extensions to MIME types.
-
parameter
cache_control
String
Cache control header value for responses.
Implementation
def initialize(delegate, root: PUBLIC_ROOT, content_types: DEFAULT_CONTENT_TYPES, cache_control: DEFAULT_CACHE_CONTROL)
super(delegate)
@root = File.expand_path(root)
@content_types = content_types
@cache_control = cache_control
end
attr :root
Signature
-
attribute
String
The absolute path to the root directory for serving assets.
attr :content_types
Signature
-
attribute
Hash
Mapping of file extensions to content types.
attr :cache_control
Signature
-
attribute
String
Cache control header value for asset responses.
def freeze
Freeze this middleware instance and all its configuration.
Signature
-
returns
Assets
Returns self for method chaining.
Implementation
def freeze
return self if frozen?
@root.freeze
@content_types.freeze
@cache_control.freeze
super
end
def response_for(path)
Generate an HTTP response for the given file path.
Signature
-
parameter
path
String
The absolute file path to serve.
-
returns
Protocol::HTTP::Response
HTTP response with file content or error.
Implementation
def response_for(path)
extension = File.extname(path)
if content_type = @content_types[extension]
headers = [
["content-type", content_type],
["cache-control", @cache_control],
]
return Protocol::HTTP::Response[200, headers, Protocol::HTTP::Body::File.open(path)]
else
Console.warn(self, "Unsupported media type!", path: path)
return Protocol::HTTP::Response[415, [["content-type", "text/plain"]], "Unsupported media type: #{extension.inspect}!"]
end
end
def expand_path(path)
Expand a relative path to an absolute path within the asset root.
Signature
-
parameter
path
String
The relative path to expand.
-
returns
String | Nil
The absolute path if valid,
nil
if the file doesn't exist.
Implementation
def expand_path(path)
path = path.split("/").map(&URI.method(:decode_uri_component))
root = File.realpath(@root)
path = File.realpath(File.join(@root, path))
if path.start_with?(root) && File.file?(path)
return path
end
rescue Errno::ENOENT
nil
end
def call(request)
Handle an incoming HTTP request.
Signature
-
parameter
request
Protocol::HTTP::Request
The incoming HTTP request.
-
returns
Protocol::HTTP::Response
The HTTP response for the asset or delegates to next middleware.
Implementation
def call(request)
if path = expand_path(request.path)
return response_for(path)
end
super
end