diff --git a/src/jsx_config.hrl b/src/jsx_config.hrl index 5fb0ea7..642dcf5 100644 --- a/src/jsx_config.hrl +++ b/src/jsx_config.hrl @@ -9,5 +9,6 @@ ignored_bad_escapes = false, explicit_end = false, pre_encode = false, - error_handler = false + error_handler = false, + incomplete_handler = false }). \ No newline at end of file diff --git a/src/jsx_decoder.erl b/src/jsx_decoder.erl index 34a8edf..2fa6b7d 100644 --- a/src/jsx_decoder.erl +++ b/src/jsx_decoder.erl @@ -105,34 +105,42 @@ decoder(Handler, State, Config) -> -ifndef(incomplete). --define(incomplete(State, Rest, Handler, Stack, Config), - {incomplete, fun(Stream) when is_binary(Stream) -> - State(<>, Handler, Stack, Config) - ; (end_stream) -> - case State(<>/binary>>, - Handler, - Stack, - Config#config{explicit_end=false}) of - {incomplete, _} -> ?error(State, Rest, Handler, Stack, Config) - ; Events -> Events - end - end - } -). -define(incomplete(State, Rest, Handler, Acc, Stack, Config), - {incomplete, fun(Stream) when is_binary(Stream) -> - State(<>, Handler, Acc, Stack, Config) - ; (end_stream) -> - case State(<>/binary>>, - Handler, - Acc, - Stack, - Config#config{explicit_end=false}) of - {incomplete, _} -> ?error(State, Rest, Handler, Acc, Stack, Config) - ; Events -> Events + case Config#config.incomplete_handler of + false -> + {incomplete, fun(Stream) when is_binary(Stream) -> + State(<>, Handler, Acc, Stack, Config) + ; (end_stream) -> + case State(<>/binary>>, + Handler, + Acc, + Stack, + Config#config{explicit_end=false}) of + {incomplete, _} -> ?error(State, Rest, Handler, Acc, Stack, Config) + ; Events -> Events + end end - end - } + }; + F -> F(Rest, {decoder, State, Handler, Acc, Stack}, Config) + end +). +-define(incomplete(State, Rest, Handler, Stack, Config), + case Config#config.incomplete_handler of + false -> + {incomplete, fun(Stream) when is_binary(Stream) -> + State(<>, Handler, Stack, Config) + ; (end_stream) -> + case State(<>/binary>>, + Handler, + Stack, + Config#config{explicit_end=false}) of + {incomplete, _} -> ?error(State, Rest, Handler, Stack, Config) + ; Events -> Events + end + end + }; + F -> F(Rest, {decoder, State, Handler, null, Stack}, Config) + end ). -endif. @@ -2041,5 +2049,15 @@ custom_error_handler_test_() -> ]. +custom_incomplete_handler_test_() -> + Decode = fun(JSON, Config) -> start(JSON, {jsx, []}, [], jsx_utils:parse_config(Config)) end, + [ + {"custom incomplete handler", ?_assertError( + badarg, + Decode(<<>>, [{incomplete_handler, fun(_, _, _) -> erlang:error(badarg) end}]) + )} + ]. + + -endif. \ No newline at end of file diff --git a/src/jsx_parser.erl b/src/jsx_parser.erl index 1e4d100..4563dd6 100644 --- a/src/jsx_parser.erl +++ b/src/jsx_parser.erl @@ -49,18 +49,22 @@ parser(Handler, State, Config) -> -ifndef(incomplete). -define(incomplete(State, Handler, Stack, Config), - {incomplete, fun(end_stream) -> - case State([end_json], - Handler, - Stack, - Config) of - {incomplete, _} -> ?error(State, [], Handler, Stack, Config) - ; Events -> Events + case Config#config.incomplete_handler of + false -> + {incomplete, fun(end_stream) -> + case State([end_json], + Handler, + Stack, + Config) of + {incomplete, _} -> ?error(State, [], Handler, Stack, Config) + ; Events -> Events + end + ; (Tokens) -> + State(Tokens, Handler, Stack, Config) end - ; (Tokens) -> - State(Tokens, Handler, Stack, Config) - end - } + }; + F -> F([], {parser, State, Handler, Stack}, Config) + end ). -endif. @@ -236,4 +240,13 @@ custom_error_handler_test_() -> ]. +custom_incomplete_handler_test_() -> + [ + {"custom incomplete handler", ?_assertError( + badarg, + parse([], [{incomplete_handler, fun(_, _, _) -> erlang:error(badarg) end}]) + )} + ]. + + -endif. \ No newline at end of file diff --git a/src/jsx_utils.erl b/src/jsx_utils.erl index 0b9c571..2cd9a56 100644 --- a/src/jsx_utils.erl +++ b/src/jsx_utils.erl @@ -76,6 +76,11 @@ parse_config([{error_handler, ErrorHandler}|Rest] = Options, Config) when is_fun false -> parse_config(Rest, Config#config{error_handler=ErrorHandler}) ; _ -> erlang:error(badarg, [Options, Config]) end; +parse_config([{incomplete_handler, IncompleteHandler}|Rest] = Options, Config) when is_function(IncompleteHandler, 3) -> + case Config#config.incomplete_handler of + false -> parse_config(Rest, Config#config{incomplete_handler=IncompleteHandler}) + ; _ -> erlang:error(badarg, [Options, Config]) + end; %% deprecated flags parse_config([{pre_encoder, Encoder}|Rest] = Options, Config) when is_function(Encoder, 1) -> case Config#config.pre_encode of @@ -631,6 +636,17 @@ config_test_() -> {error_handler, fun(_) -> false end} ]) )}, + {"incomplete_handler flag", ?_assertEqual( + #config{incomplete_handler=fun ?MODULE:fake_error_handler/3}, + parse_config([{incomplete_handler, fun ?MODULE:fake_error_handler/3}]) + )}, + {"two incomplete_handlers defined", ?_assertError( + badarg, + parse_config([ + {incomplete_handler, fun(_) -> true end}, + {incomplete_handler, fun(_) -> false end} + ]) + )}, {"bad option flag", ?_assertError(badarg, parse_config([error]))} ].