Skip to content

Commit f7c6e2c

Browse files
committed
Fix duplicate Content-Type header with Rack 2
Previously, `ActionDispatch::Static` would always merge a "content-type" header into the headers returned from `Rack::Files`. However, this would potentially lead to both a "Content-Type" header and a "content-type" header when using Rack 2. This commit fixes the issue by using `Rack::CONTENT_TYPE` to determine which version of the header to set in `ActionDispatch::Static`. In both versions of Rack it will use the same version of the header as `Rack::Files`. The tests added have to use `@app.call` instead of `get()`/`Rack::MockRequest` because `Rack::Response` actually does the correct thing already by using `Rack::Util::HeaderHash` so it covers up the issue in tests.
1 parent fdad62b commit f7c6e2c

File tree

2 files changed

+13
-1
lines changed

2 files changed

+13
-1
lines changed

actionpack/lib/action_dispatch/middleware/static.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ def find_file(path_info, accept_encoding:)
108108
end
109109

110110
def try_files(filepath, content_type, accept_encoding:)
111-
headers = { "content-type" => content_type }
111+
headers = { Rack::CONTENT_TYPE => content_type }
112112

113113
if compressible? content_type
114114
try_precompressed_files filepath, headers, accept_encoding: accept_encoding

actionpack/test/dispatch/static_test.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,18 @@ def test_does_not_modify_path_info
199199
assert_equal file_name, env["PATH_INFO"]
200200
end
201201

202+
def test_only_set_one_content_type
203+
file_name = "/gzip/foo.zoo"
204+
gzip_env = { "PATH_INFO" => file_name, "HTTP_ACCEPT_ENCODING" => "gzip", "REQUEST_METHOD" => "GET" }
205+
response = @app.call(gzip_env)
206+
207+
env = { "PATH_INFO" => file_name, "REQUEST_METHOD" => "GET" }
208+
default_response = @app.call(env)
209+
210+
assert_equal 1, response[1].slice("Content-Type", "content-type").size
211+
assert_equal 1, default_response[1].slice("Content-Type", "content-type").size
212+
end
213+
202214
def test_serves_gzip_with_proper_content_type_fallback
203215
file_name = "/gzip/foo.zoo"
204216
response = get(file_name, "HTTP_ACCEPT_ENCODING" => "gzip")

0 commit comments

Comments
 (0)