Search code examples
ruby-on-railsrackwindows-1252

Parse windows-1252 param in rails action


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?


Solution

  • 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