Request Forgery Protection in Rails 2.1

Posted by Tieg Zaharia Tue, 12 Aug 2008 22:33:00 GMT

There were some changes to the Request Forgery Protection module to Rails in May (here) that I didn’t know about until I hit my head on them today (reminder to self: keep up with Edge Rails again).

Before, you could make a request to ”/posts.xml” and successfully call any action. The protection safeguarded you only from html and ajax requests that weren’t GETs.

Now, the same response will raise “ActionController::InvalidAuthenticityToken” because it is now looking for the “Content-Type” header instead of the format of your url; in Rails, that’s now request.content_type instead of request.format; and in HTTP, it’s the header “Content-Type: text/xml” instead of “posts.xml”, to specify the mime type of your request data to RequestForgeryProtection.

It’s for sure a smarter way to check for forgery; hopefully everyone can remember to update their api documentation.

Array#inquire 4

Posted by Tieg Zaharia Tue, 01 Jul 2008 17:29:00 GMT


class Array
  def inquire(val)
    include?(val) ? val : first
  end
end
Not sure if this has been done before, but it should simplify stuff this:
type = %w(sencha macha kukicha bancha).include?(params[:type]) ? params[:type] : "sencha"
into this:
type = %w(sencha macha kukicha bancha).inquire(params[:type])
Better names for this than inquire? One I thought of was Array#beg, since you don't always get what you ask for. Hm.

Ronin: A Simple Rails Process Logger

Posted by Tieg Zaharia Thu, 20 Mar 2008 16:39:00 GMT

ronin: (in feudal Japan) a wandering samurai who had no lord or master.

(from Apple Dictionary)

Back in the fall at rmbr we were running into some requests that ate up a bunch of our memory. Since we often call a few dozen xml requests at a time, we weren’t exactly sure at first which requests were the cause of the growth.

Since I didn’t have a lot of experience with the already-existing Ruby performance tools out there, I cooked up a really basic plugin that monitors the growth of your Rails handler (server-agnostic, although I’ve only used it with Mongrel). We found the greedy requests and traced the leak to some SQL that was being loaded in one of our views (naughty!) within a few minutes of putting the plugin up on our server.

I finally got around to putting this plugin in my repository, so here is how you can try it out:

script/plugin install http://solid1pxred.com/svn/code/rails/plugins/ronin

Try it locally by running your server likes this:

RONIN=on script/server

And then just tail the log to watch your requests:

tail -f log/ronin.log

The plugin outputs the stats like so:

{ :growth => 0.22, :request_time => 0.187, :start_rss => 23416, :end_rss => 30076, :delta_rss => 6660, :uri => '/zombies/4.xml' }

As you can see it is pretty simple to load the log into irb, eval it, and sort it or do whatever you want with it. I’ve noticed a discrepancy with the request time against the Rails logger, so this is by no means scientific (yet… ?), but it gave me a really good approximation to detect those requests that make your server processes grow.

NOTE: this currently is built for POSIX systems

Altering Request Headers in Rails Integration Tests

Posted by Tieg Zaharia Tue, 18 Mar 2008 14:18:00 GMT

As I just found out, it's way easier than I thought to change request headers during integration testing. Let's say you have defined a helper method that sets up a new "open_session":
 def regular_user
    open_session do |user|      
      def user.login(login, pass)
         post '/sessions', :login => login, :password => pass
         assert_equal 'You Are Logged In On a Browser!!', assigns[:page_title]
      end
    end
end
All of a sudden you decide to turn this into an iPhone-friendly login page, so you have to check for the HTTP_USER_AGENT header in the request. All you need to do is pass an extra hash of request headers (without the "HTTP_" prefix) into the request method (get, post, put, or delete):
 def regular_user
    open_session do |user|      
      def user.login(login, pass)
         post '/sessions', { :login => login, :password => pass } , { :user_agent => 'something iPhone something' }
         assert_equal 'You Are Logged In On an iPhone!!', assigns[:page_title]
      end
    end
end
This is a little obvious if you actually check the api for integration testing. But I didn't do that at first :)

Privatize your methods dude! 4

Posted by Tieg Zaharia Thu, 14 Feb 2008 20:43:00 GMT

I guess I just feel inclined to post this because I haven't done any Ruby metaprogramming posts before. But let's say that you want to include MyModule in your class, but you want all its instance methods to be private.

PrivateMyModule = MyModule.dup
PrivateMyModule.module_eval "private #{PrivateMyModule.public_instance_methods.map {|m| ":"+m.to_s}.join(',') }"

You can test by grabbing all the private instance methods now from that module:

PrivateMyModule.private_instance_methods

Older posts: 1 2 3