Skip to content

Commit

Permalink
Make default_headers plugin correctly handle mixed/upper case content…
Browse files Browse the repository at this point in the history
…-type header on Rack 3 (Fixes #373)

Previously, the DEFAULT_HEADERS constant was a plain hash even on
Rack 3, so it didn't handle the folding to lower case.  When using
the default_headers plugin, the given headers were merged into
DEFAULT_HEADERS, so a change in case resulted in duplicate keys in
the resulting hash.  Because default headers do not overwrite
existing headers, the first default header (the lowercase content-type
Roda uses by default) would be kept, instead of the default header
set by the plugin (the mixed case Content-Type).

With this change, the DEFAULT_HEADERS constant is a Rack::Headers
instance, so the mixed/upper case Content-Type will be converted
to lowercase and overwrite the lowercase default, before it is
set in app.opts[:default_headers].
  • Loading branch information
jeremyevans committed Dec 19, 2024
1 parent eb7843c commit 8757ac7
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
=== master

* Make default_headers plugin correctly handle mixed/upper case content-type header on Rack 3 (jeremyevans) (#373)

* Make json_parser plugin handle case where Rack::Request#POST is called previously for env on Rack 3 (jeremyevans) (#372)

* Fix strict_unused_block warnings when running specs on Ruby 3.4 (jeremyevans)
Expand Down
6 changes: 4 additions & 2 deletions lib/roda/response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@ def inspect

# Instance methods for RodaResponse
module ResponseMethods
DEFAULT_HEADERS = {RodaResponseHeaders::CONTENT_TYPE => "text/html".freeze}.freeze

# The body for the current response.
attr_reader :body

Expand Down Expand Up @@ -179,11 +177,15 @@ def write(str)
private

if defined?(Rack::Headers) && Rack::Headers.is_a?(Class)
DEFAULT_HEADERS = Rack::Headers[{RodaResponseHeaders::CONTENT_TYPE => "text/html".freeze}].freeze

# Use Rack::Headers for headers by default on Rack 3
def _initialize_headers
Rack::Headers.new
end
else
DEFAULT_HEADERS = {RodaResponseHeaders::CONTENT_TYPE => "text/html".freeze}.freeze

# Use plain hash for headers by default on Rack 1-2
def _initialize_headers
{}
Expand Down
12 changes: 12 additions & 0 deletions spec/plugin/default_headers_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@
req[1].must_equal h
end

it "should handle case insensitive headers" do
app(:bare) do
plugin :default_headers, 'Content-Type' => 'application/json'

route do |r|
''
end
end

header(RodaResponseHeaders::CONTENT_TYPE).must_equal "application/json"
end

it "should allow modifying the default headers by reloading the plugin" do
app(:bare) do
plugin :default_headers, RodaResponseHeaders::CONTENT_TYPE => 'text/json'
Expand Down

0 comments on commit 8757ac7

Please sign in to comment.