From 4ae6fae8133f3e8724f70c46867f7c0a0fd18cd7 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Wed, 12 Aug 2026 17:43:29 +1200 Subject: [PATCH] Use protocol media registry for static types Signed-off-by: Samuel Williams Assisted-By: devx/9ac9c17d-46f2-438f-b727-cfbed0fda374 --- guides/middleware/readme.md | 2 +- lib/utopia/static/middleware.rb | 2 +- lib/utopia/static/mime_types.rb | 61 +++++++++++++++------------------ test/utopia/static.rb | 2 ++ utopia.gemspec | 2 +- 5 files changed, 33 insertions(+), 36 deletions(-) diff --git a/guides/middleware/readme.md b/guides/middleware/readme.md index e0bb4675..202393ec 100644 --- a/guides/middleware/readme.md +++ b/guides/middleware/readme.md @@ -10,7 +10,7 @@ The {ruby Utopia::Static} middleware services static files efficiently and suppo use Utopia::Static, # The root path to serve files from: root: "path/to/root", - # The mime-types to recognize/serve: + # The file extension groups to recognize/serve: types: [:default, :xiph], # Cache-Control header for files: cache_control: 'public, max-age=7200' diff --git a/lib/utopia/static/middleware.rb b/lib/utopia/static/middleware.rb index a32b038c..499ad9aa 100644 --- a/lib/utopia/static/middleware.rb +++ b/lib/utopia/static/middleware.rb @@ -22,7 +22,7 @@ class Middleware < Protocol::HTTP::Middleware include Localization::Resolver # @param root [String] The root directory to serve files from. - # @param types [Array] The mime-types (and file extensions) to recognize/serve. + # @param types [Array] The file extensions and named groups to recognize/serve. # @param cache_control [String] The cache-control header to set for static content. def initialize(app, root: Utopia::default_root, types: MIME_TYPES[:default], cache_control: DEFAULT_CACHE_CONTROL) super(app) diff --git a/lib/utopia/static/mime_types.rb b/lib/utopia/static/mime_types.rb index f78a1228..e2586142 100644 --- a/lib/utopia/static/mime_types.rb +++ b/lib/utopia/static/mime_types.rb @@ -1,38 +1,29 @@ # frozen_string_literal: true # Released under the MIT License. -# Copyright, 2017-2025, by Samuel Williams. +# Copyright, 2017-2026, by Samuel Williams. -require "mime/types" +require "protocol/media/registry" module Utopia # A middleware which serves static files from the specified root directory. module Static # Default mime-types which are common for files served over HTTP: MIME_TYPES = { - :xiph => { - "ogx" => "application/ogg", - "ogv" => "video/ogg", - "oga" => "audio/ogg", - "ogg" => "audio/ogg", - "spx" => "audio/ogg", - "flac" => "audio/flac", - "anx" => "application/annodex", - "axa" => "audio/annodex", - "xspf" => "application/xspf+xml", - }, + :xiph => [ + "ogx", "ogv", "oga", "ogg", "spx", "flac", "xspf" + ], :media => [ - :xiph, "mp3", "mp4", "wav", "aiff", "aac", "webm", "mov", "avi", "wmv", "mpg", "m3u8", "ts" + :xiph, "mp3", "mp4", "wav", "aiff", "aac", "webm", "weba", "mov", "avi", "wmv", "mpg", "m3u8", "ts" ], :text => [ - "html", "css", "js", ["map", "application/json"], "txt", "rtf", "xml", "pdf" + "html", "css", "js", "map", "txt", "rtf", "xml", "pdf" ], :fonts => [ - "otf", ["eot", "application/vnd.ms-fontobject"], "ttf", "woff", "woff2" + "otf", "eot", "ttf", "woff", "woff2" ], :archive => [ - "zip", "tar", "tgz", "tar.gz", "tar.bz2", ["dmg", "application/x-apple-diskimage"], - ["torrent", "application/x-bittorrent"] + "zip", "tar", "tgz", "gz", "bz2", "dmg", "torrent" ], :images => [ "png", "gif", "jpeg", "tiff", "svg", "webp" @@ -63,22 +54,26 @@ def self.extensions_for(types, library = MIME_TYPES) return loader.extensions end - # Add extensions from non-obsolete MIME type records. - # @parameter mime_types [Array(MIME::Type)] The MIME type records. - # @returns [Array(MIME::Type)] The supplied MIME type records. - def extract_extensions(mime_types) - mime_types.select{|mime_type| !mime_type.obsolete?}.each do |mime_type| - mime_type.extensions.each do |ext| - @extensions["." + ext] ||= mime_type.content_type - end + # Add an extension using its registered media type. + # @parameter extension [String] The file extension. + # @returns [Protocol::Media::Registry::Record] The registered media type record. + def add_extension(extension) + # Normalize optional leading dots and case before constructing the File.extname-style key: + extension = extension.delete_prefix(".").downcase + + if record = Protocol::Media::Registry.for_extension(extension) + @extensions["." + extension] = record.type.to_s + return record end + + raise ExpansionError.new("Unknown file extension: #{extension.inspect}") end # Raised when expansion processing fails. class ExpansionError < ArgumentError end - # Expand named groups, extension pairs, file names, patterns, and MIME records into extension mappings. + # Expand named groups, file extensions, and explicit extension pairs into extension mappings. # @parameter types [Array] The MIME type definitions. # @returns [Array] The supplied definitions. # @raises [ExpansionError] If a definition cannot be expanded. @@ -86,16 +81,16 @@ def expand(types) types.each do |type| case type when Symbol - self.expand(MIME_TYPES[type]) + self.expand(@library.fetch(type)) when Array @extensions["." + type[0]] = type[1] when String - self.extract_extensions MIME::Types.of(type) - when Regexp - self.extract_extensions MIME::Types[type] - when MIME::Type - self.extract_extensions.call([type]) + self.add_extension(type) + else + raise ExpansionError.new("Unsupported MIME type definition: #{type.inspect}") end + rescue ExpansionError + raise rescue raise ExpansionError.new("#{self.class.name}: Error while processing #{type.inspect}!") end diff --git a/test/utopia/static.rb b/test/utopia/static.rb index 2ef78d6a..7f2d7d2b 100755 --- a/test/utopia/static.rb +++ b/test/utopia/static.rb @@ -128,6 +128,8 @@ ".txt" => be == "text/plain", ".webm" => be == "video/webm", ".weba" => be == "audio/webm", + ".ogg" => be == "audio/vorbis", + ".spx" => be == "audio/speex", ".html" => be == "text/html", ) end diff --git a/utopia.gemspec b/utopia.gemspec index 297b27c2..8e017514 100644 --- a/utopia.gemspec +++ b/utopia.gemspec @@ -30,12 +30,12 @@ Gem::Specification.new do |spec| spec.add_dependency "console", "~> 1.24" spec.add_dependency "irb" spec.add_dependency "mail", "~> 2.6" - spec.add_dependency "mime-types", "~> 3.0" spec.add_dependency "msgpack" spec.add_dependency "net-smtp" spec.add_dependency "protocol-content", "~> 0.1" spec.add_dependency "protocol-http", "~> 0.70" spec.add_dependency "protocol-media", "~> 0.3" + spec.add_dependency "protocol-media-registry", "~> 0.1" spec.add_dependency "protocol-url", "~> 0.10" spec.add_dependency "samovar", "~> 2.1" spec.add_dependency "traces", "~> 0.10"