views:

734

answers:

3

I have a rails app that is working fine except for one thing.

When I request something that doesn't exist (i.e. /not_a_controller_or_file.txt) and rails throws a "No Route matches..." exception, the response is this (blank line intentional):

HTTP/1.1 200 OK
Date: Thu, 02 Oct 2008 10:28:02 GMT
Content-Type: text/html
Content-Length: 122
Vary: Accept-Encoding
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive

Status: 500 Internal Server Error
Content-Type: text/html

<html><body><h1>500 Internal Server Error</h1></body></html>

I have the ExceptionLogger plugin in /vendor, though that doesn't seem to be the problem. I haven't added any error handling beyond the custom 500.html in public (though the response doesn't contain that HTML) and I have no idea where this bit of html is coming from.

So Something, somewhere is adding that HTTP/1.1 200 status code too early, or the Status: 500 too late. I suspect it's Apache because I get the appropriate HTTP/1.1 500 header (at the top) when I use Webrick.

My production stack is as follows: Apache 2 Mongrel (5 instances) RubyOnRails 2.1.1 (happens in both 1.2 and 2.1.1)


I forgot to mention, the error is caused by a "no route matches..." exception

+1  A: 

This html file is coming from Rails. It is encountering some sort of error (probably an exception of some kind, or some other unrecoverable error).

If the extra blank line between the Status: header and the actual headers is there, and not just a typo, then this would go a long way to explaining why Apache is reporting a 200 OK message.

The Status header is how Rails, PHP, or whatever tells Apache "There was an error, please return this code instead of 200 OK." The fact there is a blank line means something extra is going on and Ruby is outputting a blank line before the error output for whatever reason. Maybe it's previous output from your script. The long and short of it is though, the extra blank line means that Apache thinks "Oh, blank line, no extra headers, this is all content now.", which would be consistent with the Content-Length header you provided.

My guess for why there's a blank line would be previous script output, perhaps a line ending at the end of a fully script page. As to why the 500 error is happening, there isn't nearly enough info here to tell you that. Maybe a file I/O error.

Edit: Given the extra information provided by Dave about the internals, I'd say this is actually an issue with the proxying that goes on behind the scenes... I couldn't tell you exactly what though, beyond what's already been said.

Matthew Scharley
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14^ where is the Status: header defined ?
Dave Cheney
That's because it ISN'T a HTTP header, it's a CGI header. It is supposed to be caught and used by the server, it's never meant to be seen. http://www.ietf.org/rfc/rfc3875 , section 6.3.3.
Matthew Scharley
But the bridge between apache and mongrel is HTTP, not CGI.
Dave Cheney
A: 

This is coming from rails itself.

http://github.com/rails/rails/tree/master/actionpack/lib/action_controller/dispatcher.rb#L60

The dispatcher is return an error page with the status code of 200 (Success).

Dave Cheney
See my response to your comment on my answer. This isn't correct, in so much as it's not what it's trying to do. Status is a CGI header, and is well formed.
Matthew Scharley
But the bridge between apache and mongrel is HTTP, not CGI
Dave Cheney
What about between Mongrel and ruby? There's CGI happening somewhere, because that's a CGI header, and if ruby wasn't being run via CGI then it'd have no reason to use that header. At any rate, my answer still stands, because the headers have become disjointed somewhere, hence the blank line and
Matthew Scharley
repeated Content-Type header.
Matthew Scharley
See this mail, mongrel uses CGI to talk to RoR: http://rubyforge.org/pipermail/mongrel-users/2006-October/001946.html
Matthew Scharley
Yes, internally mongrel creates a CGI request and response object as that is what the rails dispatcher expects (fastCGI + lighttpd was the preferred deployment method about 2 years ago) but mongrel itself is a HTTP server so it just passes the Status: header up to apache rather than interpreting it
Dave Cheney
See http://github.com/mongrel/mongrel/tree/master/lib/mongrel/rails.rb#L49
Dave Cheney
+1  A: 

This is a fairly old thread, but for what it's worth I found a great resource that includes a detailed description of the problem and the solution. Apparently this bug affects Rails < 2.3 when used with Mongrel.

metavida