diff options
author | Jeremy Evans <code@jeremyevans.net> | 2020-01-14 15:36:23 -0800 |
---|---|---|
committer | Jeremy Evans <code@jeremyevans.net> | 2020-01-21 17:28:38 -0800 |
commit | 3936b90697fcaf02751e596bd9dfd0e24add9b29 (patch) | |
tree | e979dda6e99ff9dab1040cd5bf68db8003203082 | |
parent | 5dd5911641d9d8fe3f6c39fba8cd7195c3ea28f6 (diff) | |
download | rack-3936b90697fcaf02751e596bd9dfd0e24add9b29.tar.gz |
Make body not respond to to_path to Rack::Files range requests
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
-rw-r--r-- | lib/rack/files.rb | 24 | ||||
-rw-r--r-- | test/spec_files.rb | 9 |
2 files changed, 22 insertions, 11 deletions
diff --git a/lib/rack/files.rb b/lib/rack/files.rb index f1a91c8b..fe2514cb 100644 --- a/lib/rack/files.rb +++ b/lib/rack/files.rb @@ -90,6 +90,7 @@ module Rack return response else # Partial content: + partial_content = true range = ranges[0] response[0] = 206 response[1]["Content-Range"] = "bytes #{range.begin}-#{range.end}/#{size}" @@ -99,13 +100,18 @@ module Rack 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 @@ -129,16 +135,12 @@ module Rack 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" diff --git a/test/spec_files.rb b/test/spec_files.rb index 6e75c073..5318a485 100644 --- a/test/spec_files.rb +++ b/test/spec_files.rb @@ -165,6 +165,15 @@ describe Rack::Files do 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" |