Skip to content

Commit

Permalink
Make body not respond to to_path to Rack::Files range requests
Browse files Browse the repository at this point in the history
If the body responds to to_path, the server is allowed to serve
the file at that path and ignore the body.  That works well for
most requests, but not for range requests, since the correct
byte range won't be served.

Work around this issue by using a separate body class for the
partial content responses that does not respond to to_path, and
the current body class for non-partial content responses.

Fixes #1235
  • Loading branch information
jeremyevans committed Jan 22, 2020
1 parent 5dd5911 commit 3936b90
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 11 deletions.
24 changes: 13 additions & 11 deletions lib/rack/files.rb
Expand Up @@ -90,6 +90,7 @@ def serving(request, path)
return response
else
# Partial content:
partial_content = true
range = ranges[0]
response[0] = 206
response[1]["Content-Range"] = "bytes #{range.begin}-#{range.end}/#{size}"
Expand All @@ -99,13 +100,18 @@ def serving(request, path)
response[2] = [response_body] unless response_body.nil?

response[1][CONTENT_LENGTH] = size.to_s
response[2] = make_body request, path, range
response[2] = if request.head?
[]
elsif partial_content
BaseIterator.new path, range
else
Iterator.new path, range
end
response
end

class Iterator
class BaseIterator
attr_reader :path, :range
alias :to_path :path

def initialize path, range
@path = path
Expand All @@ -129,16 +135,12 @@ def each
def close; end
end

private

def make_body request, path, range
if request.head?
[]
else
Iterator.new path, range
end
class Iterator < BaseIterator
alias :to_path :path
end

private

def fail(status, body, headers = {})
body += "\n"

Expand Down
9 changes: 9 additions & 0 deletions test/spec_files.rb
Expand Up @@ -165,6 +165,15 @@ def files(*args)
body.to_path.must_equal path
end

it "return bodies that do not respond to #to_path if a byte range is requested" do
env = Rack::MockRequest.env_for("/cgi/test")
env["HTTP_RANGE"] = "bytes=22-33"
status, _, body = Rack::Files.new(DOCROOT).call(env)

status.must_equal 206
body.wont_respond_to :to_path
end

it "return correct byte range in body" do
env = Rack::MockRequest.env_for("/cgi/test")
env["HTTP_RANGE"] = "bytes=22-33"
Expand Down

0 comments on commit 3936b90

Please sign in to comment.