Forum: Ruby on Rails BUG: HTTP body content get parsed in PUT call

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Chris wong (Guest)
on 2006-01-14 09:36
(Received via mailing list)
I'm developing a Rail application to accept data upload using HTTP PUT
call. Support for PUT in Rails seems to be broken in query params
parsing.  I have a patch to fix the problem, but I'm not sure if it is
the "right" solution.  Can some Rails developers take a quick look?  I
can really use some help. :-)

Here is the evident of broken param parsing.

	Processing FoobarController#put_action (for 127.0.0.1 at 2006-01-13
23:12:54)
	  Parameters: {"action"=>"put_action", "key1"=>"value1",
"controller"=>"foobar", "Hello, I am a test upload via PUT.\n"=>""}

The content of the PUT-call "Hello, I am a test upload via PUT.\n" get
parsed as a param key.  I made the PUT call using

	curl -T test-file.txt
'http://localhost:3000/foobar/put_action?key1=value1'

 From action_controller/cgi_ext/raw_post_data_fix.rb, the PUT method is
handled the same way as POST, which would have the content body parsed
for params.  So, I made a patch by redefining
CGI::QueryExtension#read_query_params

Note that I have to put the body content into env_table['RAW_PUT_DATA']
instead of env_table['RAW_POST_DATA'].  The latter will have the same
problem.

   class CGI #:nodoc:
     module QueryExtension
       private
       def setup_raw_put_data
         stdinput.binmode if stdinput.respond_to?(:binmode)
         content = stdinput.read(Integer(env_table['CONTENT_LENGTH']))
|| ''
         env_table['RAW_PUT_DATA'] = content.freeze
       end

       def read_query_params(method)
         case method
           when :get
             read_params_from_query
           when :post
             read_params_from_post
           when :put
             setup_raw_put_data
           when :cmd
             read_from_cmdline
           else # when :head, :delete, :options
             read_params_from_query
         end
       end
     end
   end
Chris Wong (Guest)
on 2006-01-14 11:25
(Received via mailing list)
Here is a newer version of my patch to the bug.  In this version, I'm
using RAW_POST_DATA instead of RAW_PUT_DATA.  And I call
read_params_from_query right after setup_raw_put_data in
read_query_params to make sure query string is parsed.

I'm still looking for feedback on any better way to properly fix this.
 One of the problem of putting the content in env['RAW_POST_DATA'] is
that the data could be huge and thus potentially consuming large
amount of memory.  I'm thinking of not calling setup_raw_put_data to
pull the data.  Instead, I think the controller should pull the data
itself.  That should be a more scalable solution.

Thoughts?

    class CGI #:nodoc:
      module QueryExtension
        private
        def setup_raw_put_data
          stdinput.binmode if stdinput.respond_to?(:binmode)
          content = stdinput.read(Integer(env_table['CONTENT_LENGTH']))
|| ''
          env_table['RAW_POST_DATA'] = content.freeze
        end

        def read_query_params(method)
          case method
            when :get
              read_params_from_query
            when :post
              read_params_from_post
            when :put
              setup_raw_put_data
              read_params_from_query
            when :cmd
              read_from_cmdline
            else # when :head, :delete, :options
              read_params_from_query
          end
        end
      end
    end
This topic is locked and can not be replied to.