class Middleware < Protocol::HTTP::Middleware

Inherits from
Protocol::HTTP::Middleware
Includes
Localization::Resolver

A middleware which serves dynamically generated content based on markup files.

Definitions

def initialize(app, root: Utopia::default_root, namespaces: {})

Implementation

def initialize(app, root: Utopia::default_root, namespaces: {})
	super(app)
	
	@root = root
	
	@template_cache = Concurrent::Map.new
	@node_cache = Concurrent::Map.new
	
	@links = Links.new(@root)
	
	@namespaces = namespaces
	
	# Default content namespace for dynamic path based lookup:
	@namespaces[CONTENT_NAMESPACE] ||= self.method(:content_tag)
	
	# Resolve content relative to the logical invocation path:
	@namespaces[RELATIVE_NAMESPACE] ||= self.method(:relative_tag)
	
	# The core namespace for utopia specific functionality:
	@namespaces[UTOPIA_NAMESPACE] ||= Tags
end

def freeze

Freeze this object and its internal state.

Signature

returns self

This object.

Implementation

def freeze
	return self if frozen?
	
	@root.freeze
	@namespaces.values.each(&:freeze)
	@namespaces.freeze
	
	super
end

def fetch_template(path)

Load and cache a content template.

Signature

parameter path Utopia::Path | String

The path.

returns XRB::Template

The parsed template.

Implementation

def fetch_template(path)
	@template_cache.fetch_or_store(path.to_s) do
		XRB::Template.load_file(path)
	end
end

def lookup_tag(qualified_name, node)

Look up a named tag such as <entry /> or <content:page>...

Implementation

def lookup_tag(qualified_name, node)
	namespace, name = XRB::Tag.split(qualified_name)
	
	if library = @namespaces[namespace]
		library.call(name, node)
	end
end

def lookup_node(path, locale = nil)

Implementation

def lookup_node(path, locale = nil)
	resolve_link(
		@links.for(path, locale)
	)
end

def respond(link, request, localization: request.localization)

Respond.

Signature

parameter link Utopia::Content::Link

The content link.

parameter request Utopia::Request

The application request.

parameter localization Utopia::Localization::Preferences | Nil

The selected localization.

returns Protocol::HTTP::Response

The response.

Implementation

def respond(link, request, localization: request.localization)
	if node = resolve_link(link)
		attributes = request.variables&.to_hash || {}
		
		return node.process!(request, attributes, localization: localization)
	elsif redirect_uri = link[:uri]
		return Utopia::Response[307, {HTTP::LOCATION => redirect_uri}, []]
	end
end

def call(request)

Serve or redirect filesystem-backed content, otherwise invoke the application.

Signature

parameter request Utopia::Request

The request.

returns Protocol::HTTP::Response

The content, redirect, or downstream response.

Implementation

def call(request)
	path = request.path
	
	# Check if the request is to a non-specific index. This only works for requests with a given name:
	basename = path.basename
	directory_path = File.join(@root, path.dirname.components, basename)
	
	# If the request for /foo/bar is actually a directory, rewrite it to /foo/bar/index:
	if File.directory? directory_path
		index_path = [basename, INDEX]
		location = path.dirname.join(index_path).to_url_path.encoded
		
		return Utopia::Response[307, {HTTP::LOCATION => location}, []]
	end
	
	response = resolve_localized(request) do |localization|
		locale = localization&.locale
		
		if link = @links.for(path, locale, fallback: false)
			self.respond(link, request, localization: localization)
		end
	end
	
	if response
		return response
	end
	
	return @delegate.call(request)
end