lib/rack/file.rb in rack-1.3.10 vs lib/rack/file.rb in rack-1.4.0

- old
+ new

@@ -11,10 +11,11 @@ # Handlers can detect if bodies are a Rack::File, and use mechanisms # like sendfile on the +path+. class File SEPS = Regexp.union(*[::File::SEPARATOR, ::File::ALT_SEPARATOR].compact) + ALLOWED_VERBS = %w[GET HEAD] attr_accessor :root attr_accessor :path attr_accessor :cache_control @@ -30,14 +31,28 @@ end F = ::File def _call(env) + unless ALLOWED_VERBS.include? env["REQUEST_METHOD"] + return fail(403, "Forbidden") + end + @path_info = Utils.unescape(env["PATH_INFO"]) parts = @path_info.split SEPS - return fail(403, "Forbidden") if parts.include? ".." + parts.inject(0) do |depth, part| + case part + when '', '.' + depth + when '..' + return fail(403, "Forbidden") if depth - 1 < 0 + depth - 1 + else + depth + 1 + end + end @path = F.join(@root, *parts) available = begin F.file?(@path) && F.readable?(@path) @@ -51,24 +66,26 @@ fail(404, "File not found: #{@path_info}") end end def serving(env) - # NOTE: - # We check via File::size? whether this file provides size info - # via stat (e.g. /proc files often don't), otherwise we have to - # figure it out by reading the whole file into memory. - size = F.size?(@path) || Utils.bytesize(F.read(@path)) - + last_modified = F.mtime(@path).httpdate + return [304, {}, []] if env['HTTP_IF_MODIFIED_SINCE'] == last_modified response = [ 200, { - "Last-Modified" => F.mtime(@path).httpdate, + "Last-Modified" => last_modified, "Content-Type" => Mime.mime_type(F.extname(@path), 'text/plain') }, - self + env["REQUEST_METHOD"] == "HEAD" ? [] : self ] response[1].merge! 'Cache-Control' => @cache_control if @cache_control + + # NOTE: + # We check via File::size? whether this file provides size info + # via stat (e.g. /proc files often don't), otherwise we have to + # figure it out by reading the whole file into memory. + size = F.size?(@path) || Utils.bytesize(F.read(@path)) ranges = Rack::Utils.byte_ranges(env, size) if ranges.nil? || ranges.length > 1 # No ranges, or multiple ranges (which we don't support): # TODO: Support multiple byte-ranges