summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Evans <code@jeremyevans.net>2020-01-14 15:36:23 -0800
committerJeremy Evans <code@jeremyevans.net>2020-01-21 17:28:38 -0800
commit3936b90697fcaf02751e596bd9dfd0e24add9b29 (patch)
treee979dda6e99ff9dab1040cd5bf68db8003203082
parent5dd5911641d9d8fe3f6c39fba8cd7195c3ea28f6 (diff)
downloadrack-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.rb24
-rw-r--r--test/spec_files.rb9
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"