Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix content_type= to not discard extra part #37017

Merged
merged 1 commit into from Aug 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 10 additions & 5 deletions actionpack/lib/action_dispatch/http/response.rb
Expand Up @@ -82,7 +82,6 @@ def each(&block)
SET_COOKIE = "Set-Cookie"
LOCATION = "Location"
NO_CONTENT_CODES = [100, 101, 102, 204, 205, 304]
CONTENT_TYPE_PARSER = /\A(?<type>[^;\s]+)?\s*(?:;\s*(?<extra>.+))?(?:;\s*charset=(?<quote>"?)(?<charset>[^;\s]+)\k<quote>)/ # :nodoc:

cattr_accessor :default_charset, default: "utf-8"
cattr_accessor :default_headers
Expand Down Expand Up @@ -419,14 +418,20 @@ def cookies
end

private
ContentTypeHeader = Struct.new :mime_type, :extra, :charset
NullContentTypeHeader = ContentTypeHeader.new nil, nil, nil
ContentTypeHeader = Struct.new :mime_type, :charset
NullContentTypeHeader = ContentTypeHeader.new nil, nil

CONTENT_TYPE_PARSER = /
\A
(?<mime_type>[^;\s]+\s*(?:;\s*(?:(?!charset)[^;\s])+)*)?
(?:;\s*charset=(?<quote>"?)(?<charset>[^;\s]+)\k<quote>)?
/x # :nodoc:

def parse_content_type(content_type)
if content_type && match = CONTENT_TYPE_PARSER.match(content_type)
ContentTypeHeader.new(match[:type], match[:extra], match[:charset])
ContentTypeHeader.new(match[:mime_type], match[:charset])
else
ContentTypeHeader.new(content_type, nil)
NullContentTypeHeader
end
end

Expand Down
11 changes: 11 additions & 0 deletions actionpack/test/controller/content_type_test.rb
Expand Up @@ -50,6 +50,11 @@ def render_default_content_types_for_respond_to
format.rss { render body: "hello world!", content_type: Mime[:xml] }
end
end

def render_content_type_with_charset
response.content_type = "text/html; fragment; charset=utf-16"
render body: "hello world!"
end
end

class ContentTypeTest < ActionController::TestCase
Expand Down Expand Up @@ -131,6 +136,12 @@ def test_change_for_builder
assert_equal "utf-8", @response.charset
end

def test_content_type_with_charset
get :render_content_type_with_charset
assert_equal "text/html; fragment", @response.media_type
assert_equal "utf-16", @response.charset
end

private
def with_default_charset(charset)
old_default_charset = ActionDispatch::Response.default_charset
Expand Down
4 changes: 2 additions & 2 deletions actionpack/test/dispatch/response_test.rb
Expand Up @@ -572,7 +572,7 @@ class ResponseIntegrationTest < ActionDispatch::IntegrationTest

assert_equal("text/csv; header=present; charset=utf-16", @response.headers["Content-Type"])
assert_equal("text/csv; header=present; charset=utf-16", @response.content_type)
assert_equal("text/csv", @response.media_type)
assert_equal("text/csv; header=present", @response.media_type)
assert_equal("utf-16", @response.charset)
end

Expand All @@ -590,7 +590,7 @@ class ResponseIntegrationTest < ActionDispatch::IntegrationTest

assert_equal('text/csv; header=present; charset="utf-16"', @response.headers["Content-Type"])
assert_equal('text/csv; header=present; charset="utf-16"', @response.content_type)
assert_equal("text/csv", @response.media_type)
assert_equal("text/csv; header=present", @response.media_type)
assert_equal("utf-16", @response.charset)
end

Expand Down