diff --git a/lib/sinatra/base.rb b/lib/sinatra/base.rb index 12b9ae79..593d698b 100644 --- a/lib/sinatra/base.rb +++ b/lib/sinatra/base.rb @@ -1034,7 +1034,7 @@ module Sinatra # a matching file is found, returns nil otherwise. def static!(options = {}) return if (public_dir = settings.public_folder).nil? - path = File.expand_path("#{public_dir}#{unescape(request.path_info)}" ) + path = File.expand_path("#{public_dir}#{URI_INSTANCE.unescape(request.path_info)}" ) return unless File.file?(path) env['sinatra.static_file'] = path diff --git a/test/public/hello+world.txt b/test/public/hello+world.txt new file mode 100644 index 00000000..abd09d0c --- /dev/null +++ b/test/public/hello+world.txt @@ -0,0 +1 @@ +This is a test intended for the + sign in urls for static serving \ No newline at end of file diff --git a/test/static_test.rb b/test/static_test.rb index 988ef041..a00c5cf2 100644 --- a/test/static_test.rb +++ b/test/static_test.rb @@ -233,4 +233,34 @@ class StaticTest < Minitest::Test assert response.headers.include?('Last-Modified') end + it 'serves files with a + sign in the path' do + mock_app do + set :static, true + set :public_folder, File.join(File.dirname(__FILE__), 'public') + end + + get "/hello+world.txt" + + real_path = File.join(File.dirname(__FILE__), 'public', 'hello+world.txt') + assert ok? + assert_equal File.read(real_path), body + assert_equal File.size(real_path).to_s, response['Content-Length'] + assert response.headers.include?('Last-Modified') + end + + it 'serves files with a URL encoded + sign (%2B) in the path' do + mock_app do + set :static, true + set :public_folder, File.join(File.dirname(__FILE__), 'public') + end + + get "/hello%2bworld.txt" + + real_path = File.join(File.dirname(__FILE__), 'public', 'hello+world.txt') + assert ok? + assert_equal File.read(real_path), body + assert_equal File.size(real_path).to_s, response['Content-Length'] + assert response.headers.include?('Last-Modified') + end + end