Changeset 5504
- Timestamp:
- 11/13/06 02:03:50 (2 years ago)
- Files:
-
- trunk/actionpack/lib/action_controller/rescue.rb (modified) (4 diffs)
- trunk/actionpack/lib/action_controller/templates/rescues/_request_and_response.rhtml (modified) (3 diffs)
- trunk/actionpack/test/controller/rescue_test.rb (added)
- trunk/actionpack/test/fixtures/public/404.html (added)
- trunk/actionpack/test/fixtures/public/500.html (added)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/actionpack/lib/action_controller/rescue.rb
r5243 r5504 1 1 module ActionController #:nodoc: 2 # Actions that fail to perform as expected throw exceptions. These exceptions can either be rescued for the public view 2 # Actions that fail to perform as expected throw exceptions. These exceptions can either be rescued for the public view 3 3 # (with a nice user-friendly explanation) or for the developers view (with tons of debugging information). The developers view 4 4 # is already implemented by the Action Controller, but the public view should be tailored to your specific application. So too … … 7 7 # You can tailor the rescuing behavior and appearance by overwriting the following two stub methods. 8 8 module Rescue 9 LOCALHOST = '127.0.0.1'.freeze 10 11 DEFAULT_RESCUE_RESPONSE = :internal_server_error 12 DEFAULT_RESCUE_RESPONSES = { 13 'ActionController::RoutingError' => :not_found, 14 'ActionController::UnknownAction' => :not_found 15 } 16 17 DEFAULT_RESCUE_TEMPLATE = 'diagnostics' 18 DEFAULT_RESCUE_TEMPLATES = { 19 'ActionController::MissingTemplate' => 'missing_template', 20 'ActionController::RoutingError' => 'routing_error', 21 'ActionController::UnknownAction' => 'unknown_action', 22 'ActionView::TemplateError' => 'template_error' 23 } 24 9 25 def self.included(base) #:nodoc: 26 base.cattr_accessor :rescue_responses 27 base.rescue_responses = Hash.new(DEFAULT_RESCUE_RESPONSE) 28 base.rescue_responses.update DEFAULT_RESCUE_RESPONSES 29 30 base.cattr_accessor :rescue_templates 31 base.rescue_templates = Hash.new(DEFAULT_RESCUE_TEMPLATE) 32 base.rescue_templates.update DEFAULT_RESCUE_TEMPLATES 33 10 34 base.extend(ClassMethods) 11 35 base.class_eval do … … 39 63 else 40 64 logger.fatal( 41 "\n\n#{exception.class} (#{exception.message}):\n " + 42 clean_backtrace(exception).join("\n ") + 65 "\n\n#{exception.class} (#{exception.message}):\n " + 66 clean_backtrace(exception).join("\n ") + 43 67 "\n\n" 44 68 ) … … 46 70 end 47 71 72 48 73 # Overwrite to implement public exception handling (for requests answering false to <tt>local_request?</tt>). 49 74 def rescue_action_in_public(exception) #:doc: 50 case exception 51 when RoutingError, UnknownAction 52 render_text(IO.read(File.join(RAILS_ROOT, 'public', '404.html')), "404 Not Found") 53 else 54 render_text(IO.read(File.join(RAILS_ROOT, 'public', '500.html')), "500 Internal Error") 75 render_optional_error_file response_code_for_rescue(exception) 76 end 77 78 def render_optional_error_file(status_code) #:nodoc: 79 status = interpret_status(status_code) 80 path = "#{RAILS_ROOT}/public/#{status[0,3]}.html" 81 if File.exists?(path) 82 render :file => path, :status => status 83 else 84 head status 55 85 end 56 86 end 57 87 58 # Overwrite to expand the meaning of a local request in order to show local rescues on other occurrences than59 # the remote IP being 127.0.0.1. For example, this could include the IP of the developer machine when debugging60 # remotely.88 # True if the request came from localhost, 127.0.0.1. Override this 89 # method if you wish to redefine the meaning of a local request to 90 # include remote IP addresses or other criteria. 61 91 def local_request? #:doc: 62 [request.remote_addr, request.remote_ip] == ["127.0.0.1"] * 292 request.remote_addr == LOCALHOST and request.remote_ip == LOCALHOST 63 93 end 64 94 65 # Renders a detailed diagnostics screen on action exceptions. 95 # Render detailed diagnostics for unhandled exceptions rescued from 96 # a controller action. 66 97 def rescue_action_locally(exception) 67 98 add_variables_to_assigns 68 99 @template.instance_variable_set("@exception", exception) 69 @template.instance_variable_set("@rescues_path", File.dirname(rescues_path("stub"))) 100 @template.instance_variable_set("@rescues_path", File.dirname(rescues_path("stub"))) 70 101 @template.send(:assign_variables_from_controller) 71 102 72 103 @template.instance_variable_set("@contents", @template.render_file(template_path_for_local_rescue(exception), false)) 73 104 74 105 response.content_type = Mime::HTML 75 106 render_file(rescues_path("layout"), response_code_for_rescue(exception)) 76 107 end 77 108 78 109 private 79 110 def perform_action_with_rescue #:nodoc: 80 begin 81 perform_action_without_rescue 82 rescue Exception => exception # errors from action performed 83 if defined?(Breakpoint) && params["BP-RETRY"] 84 msg = exception.backtrace.first 85 if md = /^(.+?):(\d+)(?::in `(.+)')?$/.match(msg) then 86 origin_file, origin_line = md[1], md[2].to_i 111 perform_action_without_rescue 112 rescue Exception => exception # errors from action performed 113 if defined?(Breakpoint) && params["BP-RETRY"] 114 msg = exception.backtrace.first 115 if md = /^(.+?):(\d+)(?::in `(.+)')?$/.match(msg) then 116 origin_file, origin_line = md[1], md[2].to_i 87 117 88 set_trace_func(lambda do |type, file, line, method, context, klass|89 if file == origin_file and line == origin_line then90 set_trace_func(nil)91 params["BP-RETRY"] = false118 set_trace_func(lambda do |type, file, line, method, context, klass| 119 if file == origin_file and line == origin_line then 120 set_trace_func(nil) 121 params["BP-RETRY"] = false 92 122 93 callstack = caller94 callstack.slice!(0) if callstack.first["rescue.rb"]95 file, line, method = *callstack.first.match(/^(.+?):(\d+)(?::in `(.*?)')?/).captures123 callstack = caller 124 callstack.slice!(0) if callstack.first["rescue.rb"] 125 file, line, method = *callstack.first.match(/^(.+?):(\d+)(?::in `(.*?)')?/).captures 96 126 97 message = "Exception at #{file}:#{line}#{" in `#{method}'" if method}." # `Ž ( for ruby-mode)127 message = "Exception at #{file}:#{line}#{" in `#{method}'" if method}." # `Ž ( for ruby-mode) 98 128 99 Breakpoint.handle_breakpoint(context, message, file, line)100 end101 end)129 Breakpoint.handle_breakpoint(context, message, file, line) 130 end 131 end) 102 132 103 retry 104 end 133 retry 105 134 end 135 end 106 136 107 rescue_action(exception) 108 end 137 rescue_action(exception) 109 138 end 110 139 111 140 def rescues_path(template_name) 112 File.dirname(__FILE__) + "/templates/rescues/#{template_name}.rhtml"141 "#{File.dirname(__FILE__)}/templates/rescues/#{template_name}.rhtml" 113 142 end 114 143 115 144 def template_path_for_local_rescue(exception) 116 rescues_path( 117 case exception 118 when MissingTemplate then "missing_template" 119 when RoutingError then "routing_error" 120 when UnknownAction then "unknown_action" 121 when ActionView::TemplateError then "template_error" 122 else "diagnostics" 145 rescues_path(rescue_templates[exception.class.name]) 146 end 147 148 def response_code_for_rescue(exception) 149 rescue_responses[exception.class.name] 150 end 151 152 def clean_backtrace(exception) 153 if backtrace = exception.backtrace 154 if defined?(RAILS_ROOT) 155 backtrace.map { |line| line.sub RAILS_ROOT, '' } 156 else 157 backtrace 123 158 end 124 )125 end126 127 def response_code_for_rescue(exception)128 case exception129 when UnknownAction, RoutingError130 "404 Page Not Found"131 else132 "500 Internal Error"133 159 end 134 end135 136 def clean_backtrace(exception)137 exception.backtrace.collect { |line| Object.const_defined?(:RAILS_ROOT) ? line.gsub(RAILS_ROOT, "") : line }138 160 end 139 161 end trunk/actionpack/lib/action_controller/templates/rescues/_request_and_response.rhtml
r5241 r5504 11 11 <%= form_tag(request.request_uri, "method" => request.method) %> 12 12 <input type="hidden" name="BP-RETRY" value="1" /> 13 13 14 14 <% for key, values in params %> 15 15 <% next if key == "BP-RETRY" %> … … 27 27 28 28 <% 29 request_parameters_without_action= request.parameters.clone30 request_parameters_without_action.delete("action")31 request_parameters_without_action.delete("controller")32 33 request_dump = request_parameters_without_action.inspect.gsub(/,/, ",\n")29 clean_params = request.parameters.clone 30 clean_params.delete("action") 31 clean_params.delete("controller") 32 33 request_dump = clean_params.empty? ? 'None' : clean_params.inspect.gsub(',', ",\n") 34 34 %> 35 35 36 36 <h2 style="margin-top: 30px">Request</h2> 37 <p><b>Parameters</b>: < %=h request_dump == "{}" ? "None" : request_dump %></p>37 <p><b>Parameters</b>: <pre><%=h request_dump %></pre></p> 38 38 39 39 <p><a href="#" onclick="document.getElementById('session_dump').style.display='block'; return false;">Show session dump</a></p> … … 42 42 43 43 <h2 style="margin-top: 30px">Response</h2> 44 < b>Headers</b>: <%=h response ? response.headers.inspect.gsub(/,/, ",\n") : "None" %><br/>44 <p><b>Headers</b>: <pre><%=h response ? response.headers.inspect.gsub(',', ",\n") : 'None' %></pre></p>