Don't blow up when passing frozen string to send_file disposition.

Since `attachment` does an in-place mutation of `response['Content-Disposition']`, we need to guarantee that this object is not frozen. If a frozen string is passed in, `to_s` is a no-op and returned the same frozen string. So we need to make a new unfrozen string to allow this to work.

Also this could have had interesting side effects if the user had passed in a string while holding a reference to it, they would have found their string to be changed by the call to send_file

```
x = 'inline'
send_file(some_path, disposition: x)
x == 'inline' #=> false
```
This commit is contained in:
Andrew Selder 2016-07-19 15:42:09 -07:00
parent a5da6fa82c
commit 746e245aa9
2 changed files with 7 additions and 1 deletions

View File

@ -358,7 +358,7 @@ module Sinatra
# Set the Content-Disposition to "attachment" with the specified filename,
# instructing the user agents to prompt to save.
def attachment(filename = nil, disposition = :attachment)
response['Content-Disposition'] = disposition.to_s
response['Content-Disposition'] = String.new(disposition.to_s)
if filename
params = '; filename="%s"' % File.basename(filename)
response['Content-Disposition'] << params

View File

@ -879,6 +879,12 @@ class HelpersTest < Minitest::Test
assert_equal 'inline; filename="file.txt"', response['Content-Disposition']
end
it "does not raise an error when :disposition set to a frozen string" do
send_file_app :disposition => 'inline'.freeze
get '/file.txt'
assert_equal 'inline; filename="file.txt"', response['Content-Disposition']
end
it "sets the Content-Disposition header when :filename provided" do
send_file_app :filename => 'foo.txt'
get '/file.txt'