rails
rails copied to clipboard
Extra stuff after charset in Content-Type disappears
In my Rails 6 app, I tried to return CSV data with header as a response like this:
class MyController < ApplicationController
def show
send_data(
csv_with_header,
type: "text/csv; charset=UTF-8; header=present"
)
end
end
but header=present
has disappeared from its Content-Type.
This is because #content_type=
seems to remove the extra stuff after charset=...
.
e.g.:
response = ActionDispatch::Response.new
response.content_type = "text/csv; charset=utf-16; header=present"
response.headers["Content-Type"] #=> "text/csv; charset=utf-16"
As a workaround, I need to change the above code like this:
@@ -2,7 +2,7 @@
def show
send_data(
csv_with_header,
- type: "text/csv; charset=utf-16; header=present"
+ type: "text/csv; header=present; charset=utf-16"
)
end
end
At least in Rails (6.0?), we decided to treat extra stuff as part of mime_type at https://github.com/rails/rails/pull/37017. Isn't it strange that what comes before charset is preseved, but what comes after the charset is removed?
response = ActionDispatch::Response.new
response.content_type = "text/csv; a; b; charset=utf-16; c; d"
response.headers["Content-Type"] #=> "text/csv; a; b; charset=utf-16"
Other information about text/csv:
-
https://datatracker.ietf.org/doc/html/rfc4180#section-3
- about MIME Type Registration of text/csv
Steps to reproduce
# frozen_string_literal: true
require "bundler/inline"
gemfile(true) do
source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
# Activate the gem you are reporting the issue against.
gem "rails", "~> 6.1.0"
end
require "rack/test"
require "action_controller/railtie"
class TestApp < Rails::Application
config.root = __dir__
config.hosts << "example.org"
config.session_store :cookie_store, key: "cookie_store_key"
secrets.secret_key_base = "secret_key_base"
config.logger = Logger.new($stdout)
Rails.logger = config.logger
routes.draw do
get "/" => "test#index"
end
end
class TestController < ActionController::Base
include Rails.application.routes.url_helpers
def index
send_data(
"dummy",
type: "text/csv; charset=utf-16; header=present"
)
end
end
require "minitest/autorun"
class BugTest < Minitest::Test
include Rack::Test::Methods
def test_content_type_includes_extra_stuff
get "/"
assert_includes(last_response.headers["Content-Type"], 'header=present')
end
private
def app
Rails.application
end
end
Expected behavior
I expect the above test passes.
Actual behavior
But it fails.
# Running:
I, [2021-11-26T09:22:15.126890 #13131] INFO -- : Started GET "/" for 127.0.0.1 at 2021-11-26 09:22:15 +0900
F
Failure:
BugTest#test_content_type [test.rb:49]:
Expected "text/csv; charset=utf-16" to include "header=present".
rails test test.rb:47
Finished in 0.069187s, 14.4537 runs/s, 28.9073 assertions/s.
1 runs, 2 assertions, 1 failures, 0 errors, 0 skips
System configuration
Rails version:
6.1.4.1
Ruby version:
$ ruby -v
ruby 3.0.1p64 (2021-04-05 revision 0fb782ee38) [x86_64-linux]
I submitted https://github.com/rails/rails/pull/43729, but it was automatically closed. If Rails is not going to support this feature, I'm going to close this Issue too. What do you think?
I'll reopen since stale PRs don't get closed now