Search code examples
ruby-on-railscorsruby-on-rails-5rackrack-cors

Rails ActionController ignores request headers


I have a simple controller method that logs headers via ActionController's #headers method:

class ThingsController < ActionController::Base
  def show
    Rails.logger.info headers
    render json: {response: 'success'}
  end
end

However, when I call this controller method via curl with headers, they are not logged:

curl "http://localhost:3000/things/1” \
  -H "access-token XXX" \
  -H "token-type Bearer" \
  -H "client YYY" \
  -H "expiry 1234" \
  -H "uid test@test" \

Instead, the following headers are logged:

{"X-Frame-Options"=>"SAMEORIGIN", "X-XSS-Protection"=>"1; mode=block", "X-Content-Type-Options"=>"nosniff"}

I thought my Rails 5 app's CORS policy might be to blame, so I installed the rack-cors gem and configured it in the initializer below. Unfortunately, it did not change the result.

Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins '*'
    resource '*',
      headers: :any,
      methods: %i(get post put patch delete options head)
  end
end

Solution

  • I don't think this has anything to do with CORS.

    In Rails 5.2, the ActionController instance method #headers is delegated to the response object. https://github.com/rails/rails/blob/v5.2.0/actionpack/lib/action_controller/metal.rb#L150

    delegate :headers, :status=, :location=, :content_type=,
             :status, :location, :content_type, to: "@_response"
    

    To access the request headers, you can do so via the request object. http://api.rubyonrails.org/classes/ActionDispatch/Request.html#method-i-headers

    Additionally, your cURL syntax needs to change to delimit the key from the value.

    curl "http://localhost:3000/things/1” \
      -H "access-token: XXX" \
      -H "token-type: Bearer" \
      -H "client: YYY" \
      -H "expiry: 1234" \
      -H "uid: test@test" \
    

    Per the Rack spec (and RFC 3875), headers sent by the client are prefixed with HTTP_ and all occurrences of - are replaced with _.

    To log the headers you specified via cURL:

    class ThingsController < ActionController::Base
      def show
        Rails.logger.info {
          request.headers.env.slice(
            "HTTP_ACCESS_TOKEN",
            "HTTP_TOKEN_TYPE",
            "HTTP_CLIENT",
            "HTTP_EXPIRY",
            "HTTP_UID"
          )
        }
        render json: {response: 'success'}
      end
    end