aboutsummaryrefslogtreecommitdiffstats
path: root/railties/lib/dispatcher.rb
diff options
context:
space:
mode:
authorJeremy Kemper <jeremy@bitsweat.net>2007-03-04 12:31:21 +0000
committerJeremy Kemper <jeremy@bitsweat.net>2007-03-04 12:31:21 +0000
commitf1e08b351d496ae71b48d86b46be1805486de823 (patch)
treedd9a982db6dd871a50eb81b83d0fc6e2076c56da /railties/lib/dispatcher.rb
parent8f94cc5cb4ec5e180bf6b5c401ab0c7bf407348e (diff)
downloadrails-f1e08b351d496ae71b48d86b46be1805486de823.tar.gz
rails-f1e08b351d496ae71b48d86b46be1805486de823.tar.bz2
rails-f1e08b351d496ae71b48d86b46be1805486de823.zip
Improve dispatcher failsafe responses. Beef up compatibility with Mongrel's CGI wrapper.
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@6307 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
Diffstat (limited to 'railties/lib/dispatcher.rb')
-rw-r--r--railties/lib/dispatcher.rb71
1 files changed, 48 insertions, 23 deletions
diff --git a/railties/lib/dispatcher.rb b/railties/lib/dispatcher.rb
index c121923da1..7ed3426832 100644
--- a/railties/lib/dispatcher.rb
+++ b/railties/lib/dispatcher.rb
@@ -39,7 +39,7 @@ class Dispatcher
controller.process(request, response).out(output)
end
rescue Exception => exception # errors from CGI dispatch
- failsafe_response(output, '500 Internal Server Error', exception) do
+ failsafe_response(cgi, output, '500 Internal Server Error', exception) do
controller ||= ApplicationController rescue LoadError nil
controller ||= ActionController::Base
controller.process_with_exception(request, response, exception).out(output)
@@ -90,12 +90,12 @@ class Dispatcher
attr_accessor_with_default :preparation_callbacks, []
attr_accessor_with_default :preparation_callbacks_run, false
alias_method :preparation_callbacks_run?, :preparation_callbacks_run
-
+
# CGI.new plus exception handling. CGI#read_multipart raises EOFError
# if body.empty? or body.size != Content-Length and raises ArgumentError
# if Content-Length is non-integer.
def new_cgi(output)
- failsafe_response(output, '400 Bad Request') { CGI.new }
+ failsafe_response(nil, output, '400 Bad Request') { CGI.new }
end
def prepare_application
@@ -131,34 +131,59 @@ class Dispatcher
end
# If the block raises, send status code as a last-ditch response.
- def failsafe_response(output, status, exception = nil)
+ def failsafe_response(cgi, fallback_output, status, exception = nil)
yield
- rescue Exception # errors from executed block
+ rescue Exception
begin
- output.write "Status: #{status}\r\n"
-
- if exception
- message = exception.to_s + "\r\n" + exception.backtrace.join("\r\n")
- error_path = File.join(RAILS_ROOT, 'public', '500.html')
-
- if defined?(RAILS_DEFAULT_LOGGER) && !RAILS_DEFAULT_LOGGER.nil?
- RAILS_DEFAULT_LOGGER.fatal(message)
-
- output.write "Content-Type: text/html\r\n\r\n"
-
- if File.exists?(error_path)
- output.write(IO.read(error_path))
- else
- output.write("<html><body><h1>Application error (Rails)</h1></body></html>")
- end
+ log_failsafe_exception(cgi, status, exception)
+
+ body = failsafe_response_body(status)
+ if cgi
+ head = { 'status' => status, 'type' => 'text/html' }
+
+ # FIXME: using CGI differently than CGIResponse does breaks
+ # the Mongrel CGI wrapper.
+ if defined?(Mongrel) && cgi.is_a?(Mongrel::CGIWrapper)
+ # FIXME: set a dummy cookie so the Mongrel CGI wrapper will
+ # also consider @output_cookies (used for session cookies.)
+ head['cookie'] = []
+ cgi.header(head)
+ fallback_output << body
else
- output.write "Content-Type: text/plain\r\n\r\n"
- output.write(message)
+ cgi.out(head) { body }
end
+ else
+ fallback_output.write "Status: #{status}\r\nContent-Type: text/html\r\n\r\n#{body}"
end
+ nil
rescue Exception # Logger or IO errors
end
end
+
+ def failsafe_response_body(status)
+ error_path = "#{RAILS_ROOT}/public/#{status[0..3]}.html"
+
+ if File.exists?(error_path)
+ File.read(error_path)
+ else
+ "<html><body><h1>#{status}</h1></body></html>"
+ end
+ end
+
+ def log_failsafe_exception(cgi, status, exception)
+ fell_back = cgi ? 'has cgi' : 'no cgi, fallback ouput'
+ message = "DISPATCHER FAILSAFE RESPONSE (#{fell_back}) #{Time.now}\n Status: #{status}\n"
+ message << " #{exception}\n #{exception.backtrace.join("\n ")}" if exception
+ failsafe_logger.fatal message
+ end
+
+ def failsafe_logger
+ if defined?(RAILS_DEFAULT_LOGGER) && !RAILS_DEFAULT_LOGGER.nil?
+ RAILS_DEFAULT_LOGGER
+ else
+ Logger.new($stderr)
+ end
+ end
end
end