Rack::File serves files below the root directory given, according to the path info of the Rack request. e.g. when Rack::File.new(“/etc”) is used, you can access ‘passwd’ file as localhost:9292/passwd
Handlers can detect if bodies are a Rack::File, and use mechanisms like sendfile on the path.
# File lib/rack/file.rb, line 35 35: def _call(env) 36: unless ALLOWED_VERBS.include? env["REQUEST_METHOD"] 37: return fail(405, "Method Not Allowed") 38: end 39: 40: @path_info = Utils.unescape(env["PATH_INFO"]) 41: parts = @path_info.split SEPS 42: 43: parts.inject(0) do |depth, part| 44: case part 45: when '', '.' 46: depth 47: when '..' 48: return fail(404, "Not Found") if depth - 1 < 0 49: depth - 1 50: else 51: depth + 1 52: end 53: end 54: 55: @path = F.join(@root, *parts) 56: 57: available = begin 58: F.file?(@path) && F.readable?(@path) 59: rescue SystemCallError 60: false 61: end 62: 63: if available 64: serving(env) 65: else 66: fail(404, "File not found: #{@path_info}") 67: end 68: end
# File lib/rack/file.rb, line 29 29: def call(env) 30: dup._call(env) 31: end
# File lib/rack/file.rb, line 112 112: def each 113: F.open(@path, "rb") do |file| 114: file.seek(@range.begin) 115: remaining_len = @range.end-@range.begin+1 116: while remaining_len > 0 117: part = file.read([8192, remaining_len].min) 118: break unless part 119: remaining_len -= part.length 120: 121: yield part 122: end 123: end 124: end
# File lib/rack/file.rb, line 70 70: def serving(env) 71: last_modified = F.mtime(@path).httpdate 72: return [304, {}, []] if env['HTTP_IF_MODIFIED_SINCE'] == last_modified 73: response = [ 74: 200, 75: { 76: "Last-Modified" => last_modified, 77: "Content-Type" => Mime.mime_type(F.extname(@path), 'text/plain') 78: }, 79: env["REQUEST_METHOD"] == "HEAD" ? [] : self 80: ] 81: response[1].merge! 'Cache-Control' => @cache_control if @cache_control 82: 83: # NOTE: 84: # We check via File::size? whether this file provides size info 85: # via stat (e.g. /proc files often don't), otherwise we have to 86: # figure it out by reading the whole file into memory. 87: size = F.size?(@path) || Utils.bytesize(F.read(@path)) 88: 89: ranges = Rack::Utils.byte_ranges(env, size) 90: if ranges.nil? || ranges.length > 1 91: # No ranges, or multiple ranges (which we don't support): 92: # TODO: Support multiple byte-ranges 93: response[0] = 200 94: @range = 0..size-1 95: elsif ranges.empty? 96: # Unsatisfiable. Return error, and file size: 97: response = fail(416, "Byte range unsatisfiable") 98: response[1]["Content-Range"] = "bytes */#{size}" 99: return response 100: else 101: # Partial content: 102: @range = ranges[0] 103: response[0] = 206 104: response[1]["Content-Range"] = "bytes #{@range.begin}-#{@range.end}/#{size}" 105: size = @range.end - @range.begin + 1 106: end 107: 108: response[1]["Content-Length"] = size.to_s 109: response 110: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.