Class: Utopia::Static::Middleware

Inherits:
Protocol::HTTP::Middleware
  • Object
show all
Includes:
Localization::Resolver
Defined in:
lib/utopia/static/middleware.rb

Overview

A middleware which serves static files from the specified root directory.

Constant Summary collapse

LAST_MODIFIED =
"last-modified".freeze
CONTENT_TYPE =
HTTP::CONTENT_TYPE
CACHE_CONTROL =
HTTP::CACHE_CONTROL
ETAG =
"etag".freeze
ACCEPT_RANGES =
"accept-ranges".freeze

Constants included from Localization::Resolver

Localization::Resolver::CONTENT_LANGUAGE, Localization::Resolver::CONTENT_LOCATION

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(app, root: Utopia::default_root, types: MIME_TYPES[:default], cache_control: DEFAULT_CACHE_CONTROL) ⇒ Middleware

Returns a new instance of Middleware.

Parameters:

  • root (String) (defaults to: Utopia::default_root)

    The root directory to serve files from.

  • types (Array) (defaults to: MIME_TYPES[:default])

    The file extensions and named groups to recognize/serve.

  • cache_control (String) (defaults to: DEFAULT_CACHE_CONTROL)

    The cache-control header to set for static content.



27
28
29
30
31
32
33
34
35
# File 'lib/utopia/static/middleware.rb', line 27

def initialize(app, root: Utopia::default_root, types: MIME_TYPES[:default], cache_control: DEFAULT_CACHE_CONTROL)
	super(app)
	
	@root = File.expand_path(root)
	
	@extensions = MimeTypeLoader.extensions_for(types)
	
	@cache_control = cache_control
end

Instance Attribute Details

#extensionsObject (readonly)

Returns the value of attribute extensions.



60
61
62
# File 'lib/utopia/static/middleware.rb', line 60

def extensions
  @extensions
end

Instance Method Details

#call(request) ⇒ Object

Serve a recognized static file or pass the request to the next middleware.



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/utopia/static/middleware.rb', line 116

def call(request)
	case request.method
	when Protocol::HTTP::Methods::GET, Protocol::HTTP::Methods::HEAD
	else
		return @delegate.call(request)
	end
	
	path = request.url.path
	extension = File.extname(path.basename)
	
	if content_type = @extensions[extension.downcase]
		response = resolve_localized(request) do |localization|
			self.respond(request, path, extension, content_type, localization: localization)
		end
		
		if response
			return response
		end
	end
	
	# else if no file was found:
	return @delegate.call(request)
end

#freezeObject

Freeze this object and its internal state.



39
40
41
42
43
44
45
46
47
# File 'lib/utopia/static/middleware.rb', line 39

def freeze
	return self if frozen?
	
	@root.freeze
	@extensions.freeze
	@cache_control.freeze
	
	super
end

#respond(request, path, extension, content_type, localization: request.localization) ⇒ Object

Respond.



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/utopia/static/middleware.rb', line 95

def respond(request, path, extension, content_type, localization: request.localization)
	local_path = path.local_path(@root)
	
	if locale = localization&.locale
		local_path = local_path.delete_suffix(extension) + ".#{locale}#{extension}"
	end
	
	if file = fetch_file(local_path)
		response_headers = self.response_headers_for(file, content_type)
		
		if file.modified?(request)
			return file.serve(request, response_headers)
		else
			return Response[304, response_headers, []]
		end
	end
end

#response_headers_for(file, content_type) ⇒ Object

Build response headers for the given file.



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/utopia/static/middleware.rb', line 72

def response_headers_for(file, content_type)
	if @cache_control.respond_to?(:call)
		cache_control = @cache_control.call(file)
	else
		cache_control = @cache_control
	end
	
	{
		LAST_MODIFIED => file.mtime_date,
		CONTENT_TYPE => content_type,
		CACHE_CONTROL => cache_control,
		ETAG => file.etag,
		ACCEPT_RANGES => "bytes"
	}
end