aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_dispatch/middleware/static.rb
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_dispatch/middleware/static.rb')
-rw-r--r--actionpack/lib/action_dispatch/middleware/static.rb67
1 files changed, 67 insertions, 0 deletions
diff --git a/actionpack/lib/action_dispatch/middleware/static.rb b/actionpack/lib/action_dispatch/middleware/static.rb
new file mode 100644
index 0000000000..2764584fe9
--- /dev/null
+++ b/actionpack/lib/action_dispatch/middleware/static.rb
@@ -0,0 +1,67 @@
+require 'rack/utils'
+require 'active_support/core_ext/uri'
+
+module ActionDispatch
+ class FileHandler
+ def initialize(root, cache_control)
+ @root = root.chomp('/')
+ @compiled_root = /^#{Regexp.escape(root)}/
+ headers = cache_control && { 'Cache-Control' => cache_control }
+ @file_server = ::Rack::File.new(@root, headers)
+ end
+
+ def match?(path)
+ path = unescape_path(path)
+ return false unless path.valid_encoding?
+
+ full_path = path.empty? ? @root : File.join(@root, escape_glob_chars(path))
+ paths = "#{full_path}#{ext}"
+
+ matches = Dir[paths]
+ match = matches.detect { |m| File.file?(m) }
+ if match
+ match.sub!(@compiled_root, '')
+ ::Rack::Utils.escape(match)
+ end
+ end
+
+ def call(env)
+ @file_server.call(env)
+ end
+
+ def ext
+ @ext ||= begin
+ ext = ::ActionController::Base.default_static_extension
+ "{,#{ext},/index#{ext}}"
+ end
+ end
+
+ def unescape_path(path)
+ URI.parser.unescape(path)
+ end
+
+ def escape_glob_chars(path)
+ path.gsub(/[*?{}\[\]]/, "\\\\\\&")
+ end
+ end
+
+ class Static
+ def initialize(app, path, cache_control=nil)
+ @app = app
+ @file_handler = FileHandler.new(path, cache_control)
+ end
+
+ def call(env)
+ case env['REQUEST_METHOD']
+ when 'GET', 'HEAD'
+ path = env['PATH_INFO'].chomp('/')
+ if match = @file_handler.match?(path)
+ env["PATH_INFO"] = match
+ return @file_handler.call(env)
+ end
+ end
+
+ @app.call(env)
+ end
+ end
+end