Handle it, Handle it 2

Posted by smoe Mon, 15 Jun 2009 17:16:00 GMT

I don't want my applications to throw exceptions. Not every un-handled exception can be exploited, but if you want to crack a web application that's a good place to start.

There are some great tools available to rails programmers that can help you to minimize if not completely eliminate production exceptions. First and foremost is testing. Built-in testing was what first attracted me to Rails, Rspec is what sold me, and rcov is why my applications run without exploding. It's very important to get as close to 100% code coverage as possible when you test your Ruby code. Ruby is not compiled until it's tested or called in production. I want to see my syntax errors in testing.

Cucumber is another great testing tool, but it is about implementing features with BDD, not code coverage. Relevance tarantula is the integration level test tool that will find exceptions in your application.

Even after all that testing exceptions are going to happen. I've started using the exception notifier plugin and I recommend it highly. I used to watch a summary of my Apache logs and I could see every week there would be a couple of 500 errors, but I had to go back and forth from access.log to production.log to find the problem. With the exception notifier I get an e-mail immediately after an exception is thrown, with all the details.

The errors I was seeing should have been 404's rather than 500's. I couldn't tell you why but a couple of times a week somebody was looking for gif files under a controller path. As best I can tell pagerror.gif and refresh.gif are associated with a Microsoft DLL and something with .Net in the user agent string was looking for them and causing a routing error. Maybe a Rails application closer to the defaults would have handled it better, but my application has custom routes and controllers with unique actions. I also removed the default route from the bottom of the routes.rb. My thought was that I want every request to be explicitly handled, but I guess that means if I don't handle it, it throws a 500.

Turns out one line at the end of routes.rb is all I needed to handle everything that was not explicitly handled by an earlier route.

map.garbage '/*garbage', :controller => 'landing', :action => 'nopage'

The action is also simple. You can use the default 404 page that Rails generates or customize it.

def nopage
  send_file('public/404.html', :type => 'text/html; charset=utf-8', :status => 404, :disposition => 'inline')

Now even with my divergent routes and non-standard controllers everything is explicitly handled, and, better late than never, I've added some routing tests to make sure the garbage stays out.


Use the following link to trackback from your own site:


Leave a comment

  1. Avatar
    sockmonk 7 months later:

    This looks good, but here’s what we use for the nopage action:

    render :file => “#{RAILS_ROOT}/public/404.html”, :status => 404

    I think including the 404 status is important.

  2. Avatar
    scooter@threewings.com 8 months later:

    I like the send_file, because it skips the render code it is blazing fast. You do need the 404 status and the :disposition => ‘inline’ to get the behavior you’d expect for a 404 page.