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