提交 1cfd25a7 编写于 作者: J Jeremy Kemper

Failsafe response handler for dispatcher.

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@2841 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
上级 b4b47e56
*SVN*
* Move Dispatcher.dispatch CGI.new out of default args and into rescuable block so the dispatcher catches its errors rather than the fcgi handler. [Jeremy Kemper]
* Catch CGI multipart parse errors. Wrap dispatcher internals in a failsafe response handler. [Jeremy Kemper]
* The freeze_gems Rake task accepts the VERSION environment variable to decide which version of Rails to pull into vendor/rails. [Chad Fowler, Jeremy Kemper]
......
......@@ -29,15 +29,20 @@ class << self
# Dispatch the given CGI request, using the given session options, and
# emitting the output via the given output. If you dispatch with your
# own CGI object, be sure to handle the exceptions it raises.
# own CGI object be sure to handle the exceptions it raises on multipart
# requests (EOFError and ArgumentError).
def dispatch(cgi = nil, session_options = ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, output = $stdout)
cgi ||= CGI.new
request, response = ActionController::CgiRequest.new(cgi, session_options), ActionController::CgiResponse.new(cgi)
prepare_application
ActionController::Routing::Routes.recognize!(request).process(request, response).out(output)
if cgi ||= new_cgi(output)
request, response = ActionController::CgiRequest.new(cgi, session_options), ActionController::CgiResponse.new(cgi)
prepare_application
ActionController::Routing::Routes.recognize!(request).process(request, response).out(output)
end
rescue Object => exception
ActionController::Base.process_with_exception(request, response, exception).out(output)
failsafe_response(output, '500 Internal Server Error') do
ActionController::Base.process_with_exception(request, response, exception).out(output)
end
ensure
# Do not give a failsafe response here.
reset_after_dispatch
end
......@@ -51,8 +56,15 @@ def reset_application!
Dependencies.remove_subclasses_for(ActiveRecord::Base, ActiveRecord::Observer, ActionController::Base)
Dependencies.remove_subclasses_for(ActionMailer::Base) if defined?(ActionMailer::Base)
end
private
# 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 }
end
def prepare_application
ActionController::Routing::Routes.reload if Dependencies.load?
prepare_breakpoint
......@@ -72,5 +84,15 @@ def prepare_breakpoint
rescue
nil
end
# If the block raises, send status code as a last-ditch response.
def failsafe_response(output, status)
yield
rescue Object
begin
output.write "Status: #{status}\r\n"
rescue Object
end
end
end
end
......@@ -50,9 +50,46 @@ def test_am_subclasses_cleared_on_reset
assert_equal 0, ActionMailer::Base.subclasses.length
end
INVALID_MULTIPART = [
'POST /foo HTTP/1.0',
'Host: example.com',
'Content-Type: multipart/form-data;boundary=foo'
]
EMPTY_CONTENT = (INVALID_MULTIPART + [
'Content-Length: 100',
nil, nil
]).join("\r\n")
CONTENT_LENGTH_MISMATCH = (INVALID_MULTIPART + [
'Content-Length: 100',
nil, nil,
'foobar'
]).join("\r\n")
NONINTEGER_CONTENT_LENGTH = (INVALID_MULTIPART + [
'Content-Length: abc',
nil, nil
]).join("\r\n")
def test_bad_multipart_request
old_stdin = $stdin
[EMPTY_CONTENT, CONTENT_LENGTH_MISMATCH, NONINTEGER_CONTENT_LENGTH].each do |bad_request|
$stdin = StringIO.new(bad_request)
output = StringIO.new
assert_nothing_raised do
Dispatcher.dispatch(nil, ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, output)
end
assert_equal "Status: 400 Bad Request\r\n", output.string
end
ensure
$stdin = old_stdin
end
private
def dispatch
Dispatcher.dispatch(CGI.new, ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, @output)
Dispatcher.dispatch(nil, ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, @output)
end
def setup_minimal_environment
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册