Reputation: 1231
I'm building a web service in a legacy rails 1.2.6 app that responds with JSON and I'm trying to make it accept JSON as well, rather than URL encoded parameters.
I've put this in my controller:
param_parsers[Mime::JSON] = lambda { |data| JSON.parse(data) }
This doesn't work, because the well behaved rest client sends:
Content-Type: application/json; charset=utf-8
As you see, the character encoding is appended to the Content-Type header, but rails 1.2 does a simple string compare on the whole "Content-Type" header and it thrown off by the "charset=utf-8" part.
rails-1.2/gems/gems/actionpack-1.13.6/lib/action_controller/request.rb
def content_type
@content_type ||=
begin
content_type = @env['CONTENT_TYPE'].to_s.downcase
if x_post_format = @env['HTTP_X_POST_DATA_FORMAT']
case x_post_format.to_s.downcase
when 'yaml'
content_type = 'application/x-yaml'
when 'xml'
content_type = 'application/xml'
end
end
Mime::Type.lookup(content_type)
end
end
rails-1.2/gems/gems/actionpack-1.13.6/lib/action_controller/mime_type.rb
def lookup(string)
LOOKUP[string]
end
Lower in the mime_type.rb file:
LOOKUP["application/json"] = JSON
LOOKUP["text/x-json"] = JSON
@env['CONTENT_TYPE'] is "application/json; charset=utf-8"
Mime::Type.lookup(content_type) just returns LOOKUP[content_type], which will not match, because at that time, content type still has "; charset=utf-8" appended to it.
Where should the content_type be stripped of charset=utf-8? How would you fix this? How does it work on Rails3, because from what I looked at it, it mostly the same mime_type.rb?
Upvotes: 0
Views: 526
Reputation: 1231
The answer came from reading the code for parse_formatted_parameters(). I used a lambda to create the block and this rails code specifically looks for a Proc.
I just changed
param_parsers[Mime::JSON] = lambda { |data| JSON.parse(data) }
to
param_parsers[Mime::JSON] = Proc.new { |data| JSON.parse(data) }
And now everything works as expected. I changed it back to lambda, params became empty again, and back to Proc it worked again.
Strange, because even if that code fragment gave me the solution that worked, it does not seem to be the problem.
>> case Proc.new{}; when Proc; "a"; when :xml_simple; "b" end
"a"
>> case lambda{}; when Proc; "a"; when :xml_simple; "b" end
"a"
rails-1.2/gems/gems/actionpack-1.13.6/lib/action_controller/cgi_ext/cgi_methods.rb
def parse_formatted_request_parameters(mime_type, raw_post_data)
case strategy = ActionController::Base.param_parsers[mime_type]
when Proc
strategy.call(raw_post_data)
when :xml_simple
raw_post_data.blank? ? {} : Hash.from_xml(raw_post_data)
when :yaml
YAML.load(raw_post_data)
when :xml_node
node = XmlNode.from_xml(raw_post_data)
{ node.node_name => node }
end
Upvotes: 1