diff --git a/lib/webmachine/decision/fsm.rb b/lib/webmachine/decision/fsm.rb index 79d3728a..75210a11 100644 --- a/lib/webmachine/decision/fsm.rb +++ b/lib/webmachine/decision/fsm.rb @@ -37,11 +37,15 @@ def run rescue MalformedRequest => malformed Webmachine.render_error(400, request, response, :message => malformed.message) respond(400) - rescue => e # Handle all exceptions without crashing the server - error_response(e, state) + rescue Exception => e # Handle all exceptions without crashing the server + response.end_state = state + code = resource.handle_exception(e) + code = (100...600).include?(code) ? (code) : (500) + respond(code) end private + def respond(code, headers={}) response.headers.merge!(headers) case code @@ -56,14 +60,6 @@ def respond(code, headers={}) # TODO: add logging/tracing end - # Renders a 500 error by capturing the exception information. - def error_response(exception, state) - response.error = [exception.message, exception.backtrace].flatten.join("\n ") - response.end_state = state - Webmachine.render_error(500, request, response) - respond(500) - end - end # class FSM end # module Decision end # module Webmachine diff --git a/lib/webmachine/resource/callbacks.rb b/lib/webmachine/resource/callbacks.rb index b967c723..11780a4d 100644 --- a/lib/webmachine/resource/callbacks.rb +++ b/lib/webmachine/resource/callbacks.rb @@ -360,6 +360,22 @@ def generate_etag # @api callback def finish_request; end + # + # This method is called when an exception is raised within a subclass of + # {Webmachine::Resource}. + # + # @param [Exception] e + # The exception. + # + # @return [void] + # + # @api callback + # + def handle_exception(e) + response.error = [e.message, e.backtrace].flatten.join("\n ") + Webmachine.render_error(500, request, response) + end + # This method is called when verifying the Content-MD5 header # against the request body. To do your own validation, implement # it in this callback, returning true or false. To bypass header diff --git a/spec/webmachine/decision/flow_spec.rb b/spec/webmachine/decision/flow_spec.rb index 00b51060..9ea3df34 100644 --- a/spec/webmachine/decision/flow_spec.rb +++ b/spec/webmachine/decision/flow_spec.rb @@ -1029,4 +1029,58 @@ def accept_all end end end + + describe "On exception" do + context "handle_exception is inherited." do + let :resource do + resource_with do + def to_html + raise + end + end + end + + it "calls handle_exception." do + resource.should_receive(:handle_exception).with instance_of(RuntimeError) + subject.run + end + + it "sets the response code to 500." do + subject.run + response.code.should == 500 + end + + it "sets the end state properly." do + subject.run + response.end_state.should == :o18 + end + end + + context "handle_exception is defined." do + let :resource do + resource_with do + def handle_exception(e) + response.body = "error" + 501 + end + + def to_html + raise + end + end + end + + it "can define a response body." do + subject.run + response.body.should == "error" + end + + it "uses the return value as a response code." do + subject.run + response.code.should == 501 + end + end + end + + end