From ea8fc9495a350f7551b39e3025bfcd06f49f363b Mon Sep 17 00:00:00 2001 From: namusyaka Date: Wed, 23 Nov 2022 22:24:02 +0900 Subject: [PATCH] escape filename in the Content-Disposition header According the multipart form data spec in WHATWG living standard. Ref: https://html.spec.whatwg.org/#multipart-form-data --- lib/sinatra/base.rb | 9 ++++++++- test/helpers_test.rb | 12 ++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/lib/sinatra/base.rb b/lib/sinatra/base.rb index d7e2d65ad9..cbb3f2fd7b 100644 --- a/lib/sinatra/base.rb +++ b/lib/sinatra/base.rb @@ -396,13 +396,20 @@ def content_type(type = nil, params = {}) response['Content-Type'] = mime_type end + # https://html.spec.whatwg.org/#multipart-form-data + MULTIPART_FORM_DATA_REPLACEMENT_TABLE = { + '"' => '%22', + "\r" => '%0D', + "\n" => '%0A' + }.freeze + # 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.dup return unless filename - params = format('; filename="%s"', File.basename(filename)) + params = format('; filename="%s"', File.basename(filename).gsub(/["\r\n]/, MULTIPART_FORM_DATA_REPLACEMENT_TABLE)) response['Content-Disposition'] << params ext = File.extname(filename) content_type(ext) unless response['Content-Type'] || ext.empty? diff --git a/test/helpers_test.rb b/test/helpers_test.rb index 67dffce1fb..71b42a8fd3 100644 --- a/test/helpers_test.rb +++ b/test/helpers_test.rb @@ -781,6 +781,18 @@ def attachment_app(filename=nil) assert_equal '', body end + it 'escapes filename in the Content-Disposition header according to the multipart form data spec in WHATWG living standard' do + mock_app do + get('/attachment') do + attachment "test.xml\";\r\next=.txt" + response.write("") + end + end + + get '/attachment' + assert_equal 'attachment; filename="test.xml%22;%0D%0Aext=.txt"', response['Content-Disposition'] + assert_equal '', body + end end describe 'send_file' do