Costi
Costi

Reputation: 1231

Web services: accepting JSON mime type in rails 1.2

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

Answers (1)

Costi
Costi

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

Related Questions