My API is receiving a call that contains windows-1252 encoded data in the POST body. In rails 6.0.3, this apparently worked. But rails 6.1.1 throws ActionController::BadRequest (Invalid request parameters: Invalid encoding for parameter.
Edit: I can not change the calls to UTF-8, those come from a 3rd party. So, my API must accept windows-1252 encoding.
Here is a snippet that emulates this call:
require 'net/http'
require 'uri'
uri = URI.parse("http://localhost:3030/dummy/create")
request = Net::HTTP::Post.new(uri)
request.content_type = "application/x-www-form-urlencoded"
# Rack::QueryParser::InvalidParameterError: Invalid encoding for parameter:
#G�bor
name = "Gábor".encode("windows-1252", "utf-8")
request.body = "last_name=#{name}&first_name=Sam&charset=windows-1252"
response = Net::HTTP.start(uri.hostname, uri.port, nil) do |http|
http.request(request)
end
# 400
pp response.code
And on the server side, the dummy#create
action is never reached, it stops with
Started POST "/dummy/create" for 127.0.0.1 at 2021-02-06 17:14:12 +0100
ActionController::BadRequest (Invalid request parameters: Invalid encoding for parameter: G�bor):
actionpack (6.1.1) lib/action_dispatch/request/utils.rb:39:in `check_param_encoding'
actionpack (6.1.1) lib/action_dispatch/request/utils.rb:34:in `block in check_param_encoding'
actionpack (6.1.1) lib/action_dispatch/request/utils.rb:34:in `each_value'
actionpack (6.1.1) lib/action_dispatch/request/utils.rb:34:in `check_param_encoding'
actionpack (6.1.1) lib/action_dispatch/http/request.rb:403:in `block in POST'
rack (2.2.3) lib/rack/request.rb:69:in `fetch'
rack (2.2.3) lib/rack/request.rb:69:in `fetch_header'
actionpack (6.1.1) lib/action_dispatch/http/request.rb:398:in `POST'
actionpack (6.1.1) lib/action_dispatch/http/parameters.rb:55:in `parameters'
...
I found that I could register a middleware to intercept this kind of call, as described in Rails/Rack: "ArgumentError: invalid %-encoding" for POST data
The middleware would then check for the 'charset' param in the POST, and this probably would work. However, this has the disadvantage that it would apply to all calls, not only the dummy#create
endpoint.
Since this behavior was recently introduced, (in rail 6.1 I assume), is there a better way now to handle this?
The solution here, adding param_encoding
for each parameter like document https://api.rubyonrails.org/classes/ActionController/ParameterEncoding/ClassMethods.html
param_encoding :create, :last_name, Encoding::ASCII_8BIT
param_encoding :create, :first_name, Encoding::ASCII_8BIT