Class: Sentiero::Web::AssetsApp
- Defined in:
- lib/sentiero/web/assets_app.rb
Overview
Standalone Rack endpoint serving the gem's static assets (mounted via r.sentiero_assets). Shares #serve with BaseApp#handle_asset so the dashboard's /assets/* route applies the same traversal guard, content types, and caching.
Constant Summary
Constants inherited from BaseApp
BaseApp::ASSETS_DIR, BaseApp::AUTH_WARNING_LOCK, BaseApp::CONTENT_TYPES, BaseApp::CSP_POLICY
Constants included from Escaping
Escaping::HTML_UNSAFE_IN_SCRIPT, Escaping::HTML_UNSAFE_IN_SCRIPT_PATTERN
Instance Method Summary collapse
- #call(env) ⇒ Object
-
#serve(relative_path) ⇒ Object
Resolved path must stay inside ASSETS_DIR (blocks traversal/absolute paths); .erb files are never served raw.
Methods inherited from BaseApp
reset_auth_warning!, warn_unauthenticated_once
Methods included from Formatting
#format_duration, #format_vital, #parse_browser, #parse_device
Methods included from Escaping
#escape_html, #escape_js_string, #escape_json
Instance Method Details
#call(env) ⇒ Object
11 12 13 14 15 |
# File 'lib/sentiero/web/assets_app.rb', line 11 def call(env) return [405, {"content-type" => "text/plain"}, ["Method Not Allowed"]] unless env["REQUEST_METHOD"] == "GET" serve(env["PATH_INFO"].delete_prefix("/")) end |
#serve(relative_path) ⇒ Object
Resolved path must stay inside ASSETS_DIR (blocks traversal/absolute paths); .erb files are never served raw. Fingerprinted basenames (name-HASH.ext) get a year of immutable cache (31536000s), else one day.
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/sentiero/web/assets_app.rb', line 20 def serve(relative_path) return not_found if relative_path.nil? || relative_path.empty? full_path = File.(relative_path, ASSETS_DIR) return not_found unless full_path.start_with?(ASSETS_DIR + File::SEPARATOR) return not_found if full_path.end_with?(".erb") return not_found unless File.file?(full_path) ext = File.extname(full_path) content_type = CONTENT_TYPES.fetch(ext, "application/octet-stream") cache_control = if File.basename(full_path).match?(/\A[^\/]+-[A-Za-z0-9]+\.\w+\z/) "public, max-age=31536000, immutable" else "public, max-age=86400" end [200, {"content-type" => content_type, "cache-control" => cache_control}, [File.binread(full_path)]] end |