diff --git a/lib/rack/contrib/json_body_parser.rb b/lib/rack/contrib/json_body_parser.rb index 9ee29ef..e98d9ad 100644 --- a/lib/rack/contrib/json_body_parser.rb +++ b/lib/rack/contrib/json_body_parser.rb @@ -61,7 +61,7 @@ def call(env) update_form_hash_with_json_body(env) end - rescue JSON::ParserError + rescue ParserError body = { error: 'Failed to parse body as JSON' }.to_json header = { 'content-type' => 'application/json' } return Rack::Response.new(body, 400, header).finish @@ -71,13 +71,22 @@ def call(env) private + class ParserError < StandardError; end + def update_form_hash_with_json_body(env) body = env[Rack::RACK_INPUT] return unless (body_content = body.read) && !body_content.empty? body.rewind if body.respond_to?(:rewind) # somebody might try to read this stream + + begin + parsed_body = @parser.call(body_content) + rescue StandardError + raise ParserError + end + env.update( - Rack::RACK_REQUEST_FORM_HASH => @parser.call(body_content), + Rack::RACK_REQUEST_FORM_HASH => parsed_body, Rack::RACK_REQUEST_FORM_INPUT => body ) end diff --git a/test/spec_rack_json_body_parser_spec.rb b/test/spec_rack_json_body_parser_spec.rb index 7e2a317..d2930cc 100644 --- a/test/spec_rack_json_body_parser_spec.rb +++ b/test/spec_rack_json_body_parser_spec.rb @@ -64,6 +64,17 @@ def create_parser(app, **args, &block) _( -> { create_parser(app).call(env) }).must_raise JSON::ParserError end + specify "should rescue StandardError subclasses raised by the parser" do + class CustomParserError < StandardError; end + + parser = create_parser(app) do |_body| + raise CustomParserError.new + end + + res = parser.call(mock_env) + _(res[0]).must_equal 400 + end + describe "contradiction between body and type" do specify "should return bad request with a JSON-encoded error message" do env = mock_env(input: 'This is not JSON')