Fix some edge cases in AD::DebugExceptions in rails api apps

This commit is contained in:
Jorge Bejar 2015-07-07 12:43:49 -03:00
parent f43c05bff7
commit 05d89410bf
2 changed files with 126 additions and 52 deletions

@ -67,55 +67,78 @@ def render_exception(request, exception)
log_error(request, wrapper)
if request.get_header('action_dispatch.show_detailed_exceptions')
traces = wrapper.traces
trace_to_show = 'Application Trace'
if traces[trace_to_show].empty? && wrapper.rescue_template != 'routing_error'
trace_to_show = 'Full Trace'
end
if source_to_show = traces[trace_to_show].first
source_to_show_id = source_to_show[:id]
end
template = DebugView.new([RESCUES_TEMPLATE_PATH],
request: request,
exception: wrapper.exception,
traces: traces,
show_source_idx: source_to_show_id,
trace_to_show: trace_to_show,
routes_inspector: routes_inspector(exception),
source_extracts: wrapper.source_extracts,
line_number: wrapper.line_number,
file: wrapper.file
)
file = "rescues/#{wrapper.rescue_template}"
if @api_only
body = {
:status => wrapper.status_code,
:error => Rack::Utils::HTTP_STATUS_CODES.fetch(wrapper.status_code, Rack::Utils::HTTP_STATUS_CODES[500]),
:exception => wrapper.exception.inspect,
:traces => traces
}
if content_type = request.formats.first
to_format = "to_#{content_type.to_sym}"
body = body.public_send(to_format)
end
format = "application/json"
elsif request.xhr?
body = template.render(template: file, layout: false, formats: [:text])
format = "text/plain"
render_for_api_application(request, wrapper)
else
body = template.render(template: file, layout: 'rescues/layout')
format = "text/html"
render_for_non_api_application(request, wrapper)
end
render(wrapper.status_code, body, format)
else
raise exception
end
end
def render_for_non_api_application(request, wrapper)
template = create_template(request, wrapper)
file = "rescues/#{wrapper.rescue_template}"
if request.xhr?
body = template.render(template: file, layout: false, formats: [:text])
format = "text/plain"
else
body = template.render(template: file, layout: 'rescues/layout')
format = "text/html"
end
render(wrapper.status_code, body, format)
end
def render_for_api_application(request, wrapper)
body = {
:status => wrapper.status_code,
:error => Rack::Utils::HTTP_STATUS_CODES.fetch(wrapper.status_code, Rack::Utils::HTTP_STATUS_CODES[500]),
:exception => wrapper.exception.inspect,
:traces => wrapper.traces
}
content_type = request.formats.first
to_format = "to_#{content_type.to_sym}"
if content_type && body.respond_to?(to_format)
body = body.public_send(to_format)
format = content_type
else
body = body.to_json
format = Mime::JSON
end
render(wrapper.status_code, body, format)
end
def create_template(request, wrapper)
traces = wrapper.traces
trace_to_show = 'Application Trace'
if traces[trace_to_show].empty? && wrapper.rescue_template != 'routing_error'
trace_to_show = 'Full Trace'
end
if source_to_show = traces[trace_to_show].first
source_to_show_id = source_to_show[:id]
end
DebugView.new([RESCUES_TEMPLATE_PATH],
request: request,
exception: wrapper.exception,
traces: traces,
show_source_idx: source_to_show_id,
trace_to_show: trace_to_show,
routes_inspector: routes_inspector(wrapper.exception),
source_extracts: wrapper.source_extracts,
line_number: wrapper.line_number,
file: wrapper.file
)
end
def render(status, body, format)
[status, {'Content-Type' => "#{format}; charset=#{Response.default_charset}", 'Content-Length' => body.bytesize.to_s}, [body]]
end

@ -162,17 +162,6 @@ def call(env)
assert_match(/ActionController::ParameterMissing/, body)
end
test "rescue with json on API request" do
@app = ActionDispatch::DebugExceptions.new(BoomerAPI.new(true), RoutesApp, true)
get "/index.json", headers: { 'action_dispatch.show_exceptions' => true }
assert_response 500
assert_no_match(/<header>/, body)
assert_no_match(/<body>/, body)
assert_equal "application/json", response.content_type
assert_match(/RuntimeError: puke/, body)
end
test "rescue with text error for xhr request" do
@app = DevelopmentApp
xhr_request_env = {'action_dispatch.show_exceptions' => true, 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest'}
@ -223,6 +212,68 @@ def call(env)
assert_match(/ActionController::ParameterMissing/, body)
end
test "rescue with json error for API request" do
@app = ActionDispatch::DebugExceptions.new(Boomer.new(true), RoutesApp, true)
get "/", headers: { 'action_dispatch.show_exceptions' => true }
assert_response 500
assert_no_match(/<header>/, body)
assert_no_match(/<body>/, body)
assert_equal "application/json", response.content_type
assert_match(/RuntimeError: puke/, body)
get "/not_found", headers: { 'action_dispatch.show_exceptions' => true }
assert_response 404
assert_no_match(/<body>/, body)
assert_equal "application/json", response.content_type
assert_match(/#{AbstractController::ActionNotFound.name}/, body)
get "/method_not_allowed", headers: { 'action_dispatch.show_exceptions' => true }
assert_response 405
assert_no_match(/<body>/, body)
assert_equal "application/json", response.content_type
assert_match(/ActionController::MethodNotAllowed/, body)
get "/unknown_http_method", headers: { 'action_dispatch.show_exceptions' => true }
assert_response 405
assert_no_match(/<body>/, body)
assert_equal "application/json", response.content_type
assert_match(/ActionController::UnknownHttpMethod/, body)
get "/bad_request", headers: { 'action_dispatch.show_exceptions' => true }
assert_response 400
assert_no_match(/<body>/, body)
assert_equal "application/json", response.content_type
assert_match(/ActionController::BadRequest/, body)
get "/parameter_missing", headers: { 'action_dispatch.show_exceptions' => true }
assert_response 400
assert_no_match(/<body>/, body)
assert_equal "application/json", response.content_type
assert_match(/ActionController::ParameterMissing/, body)
end
test "rescue with json on API request returns only allowed formats or json as a fallback" do
@app = ActionDispatch::DebugExceptions.new(Boomer.new(true), RoutesApp, true)
get "/index.json", headers: { 'action_dispatch.show_exceptions' => true }
assert_response 500
assert_equal "application/json", response.content_type
assert_match(/RuntimeError: puke/, body)
get "/index.html", headers: { 'action_dispatch.show_exceptions' => true }
assert_response 500
assert_no_match(/<header>/, body)
assert_no_match(/<body>/, body)
assert_equal "application/json", response.content_type
assert_match(/RuntimeError: puke/, body)
get "/index.xml", headers: { 'action_dispatch.show_exceptions' => true }
assert_response 500
assert_equal "application/xml", response.content_type
assert_match(/RuntimeError: puke/, body)
end
test "does not show filtered parameters" do
@app = DevelopmentApp