rails: Accessing request.params breaks parameter encoding validation

Given a controller:

class FooController < ApplicationController
  skip_parameter_encoding :index
  skip_before_action :verify_authenticity_token

  def index
    head :ok
  end
end

parameters in the index action should be able to carry any payload. For example, this should work

require "net/http"

uri = URI("http://localhost:3000")
Net::HTTP.post_form(uri, "foo" => "\xe1") # Invalid UTF-8.

and it does.

However, a middleware as innocent as

class FooMiddleware
  def initialize(app)
    @app = app
  end

  def call(env)
    request = ActionDispatch::Request.new(env)
    request.params
    @app.call(request.env)
  end
end

interferes somehow with parameter encoding validation, and the request now raises

ActionController::BadRequest (Invalid request parameters: Invalid encoding for parameter: �)

About this issue

  • Original URL
  • State: open
  • Created 3 years ago
  • Comments: 27 (15 by maintainers)

Most upvoted comments

So, what is the fix for this issue in August 2022? skip_parameter_encoding doesn’t work on an API controller.

@rahul342 You could try including ActionController::ParameterEncoding in your controller.

@rafaelfranca and I had a chat about this and we’ve decided to move the encoding into the controller, with AD::Request using binary encoding. I’ll update the PR I opened to move the encoding from the router into the controller and ensure we’ve documented the fact that encoding with AD::Request is binary since the controller context might not be available yet.

Perfect @adrianna-chang-shopify!

Another option could be somewhere near ActionDispatch::Routing::RouteSet#call, or ActionDispatch::Routing::RouteSet::Dispatcher#serve since that seems to be the lowest boundary before passing the request to the controller (if my limited understanding of this part of the framework is right). Though the dispatcher should probably stay at dispatching only.

Let’s see what @rafaelfranca says!