mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Fix some edge cases in AD::DebugExceptions in rails api apps
This commit is contained in:
parent
f43c05bff7
commit
05d89410bf
2 changed files with 126 additions and 52 deletions
|
@ -67,55 +67,78 @@ module ActionDispatch
|
||||||
log_error(request, wrapper)
|
log_error(request, wrapper)
|
||||||
|
|
||||||
if request.get_header('action_dispatch.show_detailed_exceptions')
|
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
|
if @api_only
|
||||||
body = {
|
render_for_api_application(request, wrapper)
|
||||||
: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"
|
|
||||||
else
|
else
|
||||||
body = template.render(template: file, layout: 'rescues/layout')
|
render_for_non_api_application(request, wrapper)
|
||||||
format = "text/html"
|
|
||||||
end
|
end
|
||||||
render(wrapper.status_code, body, format)
|
|
||||||
else
|
else
|
||||||
raise exception
|
raise exception
|
||||||
end
|
end
|
||||||
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)
|
def render(status, body, format)
|
||||||
[status, {'Content-Type' => "#{format}; charset=#{Response.default_charset}", 'Content-Length' => body.bytesize.to_s}, [body]]
|
[status, {'Content-Type' => "#{format}; charset=#{Response.default_charset}", 'Content-Length' => body.bytesize.to_s}, [body]]
|
||||||
end
|
end
|
||||||
|
|
|
@ -162,17 +162,6 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
|
||||||
assert_match(/ActionController::ParameterMissing/, body)
|
assert_match(/ActionController::ParameterMissing/, body)
|
||||||
end
|
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
|
test "rescue with text error for xhr request" do
|
||||||
@app = DevelopmentApp
|
@app = DevelopmentApp
|
||||||
xhr_request_env = {'action_dispatch.show_exceptions' => true, 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest'}
|
xhr_request_env = {'action_dispatch.show_exceptions' => true, 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest'}
|
||||||
|
@ -223,6 +212,68 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
|
||||||
assert_match(/ActionController::ParameterMissing/, body)
|
assert_match(/ActionController::ParameterMissing/, body)
|
||||||
end
|
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
|
test "does not show filtered parameters" do
|
||||||
@app = DevelopmentApp
|
@app = DevelopmentApp
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue