Class: StaticRails::FileHandler

Inherits:
Object
  • Object
show all
Defined in:
lib/static-rails/file_handler.rb

Overview

This class was extracted from Ruby on Rails:

- actionpack/lib/action_dispatch/middleware/static.rb

Copyright © 2005-2020 David Heinemeier Hansson, Ryan Edward Hall, Jeremy Daer

License here: github.com/rails/rails/blob/master/MIT-LICENSE

This endpoint serves static files from disk using Rack::File.

URL paths are matched with static files according to expected conventions: path, path.html, path/index.html.

Precompressed versions of these files are checked first. Brotli (.br) and gzip (.gz) files are supported. If path.br exists, this endpoint returns that file with a Content-Encoding: br header.

If no matching file is found, this endpoint responds 404 Not Found.

Pass the root directory to search for matching files, an optional index: “index” to change the default path/index.html, and optional additional response headers.

Constant Summary collapse

PRECOMPRESSED =

Accept-Encoding value -> file extension

{
  "br" => ".br",
  "gzip" => ".gz",
  "identity" => nil
}

Instance Method Summary collapse

Constructor Details

#initialize(root, index: "index", headers: {}, precompressed: %i[br gzip],, compressible_content_types: /\A(?:text\/|application\/javascript)/) ⇒ FileHandler

Returns a new instance of FileHandler.



32
33
34
35
36
37
38
39
40
# File 'lib/static-rails/file_handler.rb', line 32

def initialize(root, index: "index", headers: {}, precompressed: %i[br gzip], compressible_content_types: /\A(?:text\/|application\/javascript)/)
  @root = root.chomp("/").b
  @index = index

  @precompressed = Array(precompressed).map(&:to_s) | %w[identity]
  @compressible_content_types = compressible_content_types

  @file_server = ::Rack::File.new(@root, headers)
end

Instance Method Details

#attempt(env) ⇒ Object



46
47
48
49
50
51
52
53
54
# File 'lib/static-rails/file_handler.rb', line 46

def attempt(env)
  request = Rack::Request.new env

  if request.get? || request.head?
    if (found = find_file(request.path_info, accept_encoding: request.accept_encoding))
      serve request, *found
    end
  end
end

#call(env) ⇒ Object



42
43
44
# File 'lib/static-rails/file_handler.rb', line 42

def call(env)
  attempt(env) || @file_server.call(env)
end

#find_file(path_info, accept_encoding:) ⇒ Object

Match a URI path to a static file to be served.

Used by the Static class to negotiate a servable file in the public/ directory (see Static#call).

Checks for path, path.html, and path/index.html files, in that order, including .br and .gzip compressed extensions.

If a matching file is found, the path and necessary response headers (Content-Type, Content-Encoding) are returned.



79
80
81
82
83
84
85
# File 'lib/static-rails/file_handler.rb', line 79

def find_file(path_info, accept_encoding:)
  each_candidate_filepath(path_info) do |filepath, content_type|
    if (response = try_files(filepath, content_type, accept_encoding: accept_encoding))
      return response
    end
  end
end

#serve(request, filepath, content_headers) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/static-rails/file_handler.rb', line 56

def serve(request, filepath, content_headers)
  original, request.path_info = request.path_info, ::Rack::Utils.escape_path(filepath).b

  @file_server.call(request.env).tap do |status, headers, body|
    # Omit Content-Encoding/Type/etc headers for 304 Not Modified
    if status != 304
      headers.update(content_headers)
    end
  end
ensure
  request.path_info = original
end