Class: Utopia::Static::Middleware

Inherits:
Object
  • Object
show all
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

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 mime-types (and file extensions) to recognize/serve.

  • cache_control (String) (defaults to: DEFAULT_CACHE_CONTROL)

    The cache-control header to set for static content.



23
24
25
26
27
28
29
30
# File 'lib/utopia/static/middleware.rb', line 23

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

Instance Attribute Details

#extensionsObject (readonly)

Returns the value of attribute extensions.



53
54
55
# File 'lib/utopia/static/middleware.rb', line 53

def extensions
  @extensions
end

Instance Method Details

#call(env) ⇒ Object



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

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

#fetch_file(path) ⇒ Object



42
43
44
45
46
47
48
49
50
51
# File 'lib/utopia/static/middleware.rb', line 42

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

#freezeObject



32
33
34
35
36
37
38
39
40
# File 'lib/utopia/static/middleware.rb', line 32

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

#respond(env, path_info, extension) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/utopia/static/middleware.rb', line 77

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

#response_headers_for(file, content_type) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/utopia/static/middleware.rb', line 61

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