UtopiaSourceUtopiaStaticMiddleware

class Middleware

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

Definitions

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

Implementation

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

def freeze

Freeze this object and its internal state.

Signature

returns self

This object.

Implementation

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

def fetch_file(path)

Open metadata for an existing file under the static root.

Signature

parameter path Utopia::Path | String

The path.

returns LocalFile | Nil

The local file, or nil when it does not exist.

Implementation

def fetch_file(path)
	# We need file_path to be an absolute path for X-Sendfile to work correctly.
	file_path = File.join(@root, path.components)
	
	if File.exist?(file_path)
		return LocalFile.new(@root, path)
	else
		return nil
	end
end

def response_headers_for(file, content_type)

Build response headers for the given file.

Signature

parameter file LocalFile

The file.

parameter content_type String

The content type.

returns Hash(String, String)

The response headers.

Implementation

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

def respond(env, path_info, extension)

Serve a static file for the requested path and extension.

Signature

parameter env Hash

The Rack environment.

parameter path_info String

The request path.

parameter extension String

The file extension.

returns Array | Nil

The Rack response when a file is found.

Implementation

def respond(env, path_info, extension)
	path = Path[path_info].simplify
	
	if locale = env[Localization::CURRENT_LOCALE_KEY]
		path.last.insert(path.last.rindex(".") || -1, ".#{locale}")
	end
	
	if file = fetch_file(path)
		response_headers = self.response_headers_for(file, @extensions[extension])
		
		if file.modified?(env)
			return file.serve(env, response_headers)
		else
			return [304, response_headers, []]
		end
	end
end

def call(env)

Serve a recognized static file or pass the request downstream.

Signature

parameter env Hash

The Rack environment.

returns Array

The static-file or downstream Rack response.

Implementation

def call(env)
	path_info = env[Rack::PATH_INFO]
	extension = File.extname(path_info)
	
	if @extensions.key?(extension.downcase)
		if response = self.respond(env, path_info, extension)
			return response
		end
	end
	
	# else if no file was found:
	return @app.call(env)
end