2121#include <expat.h>
2222
2323#define PARSING_NOT_RESUMABLE XML_FALSE
24+ #define LIMIT_MAX ((ErlNifUInt64)-1)
2425
2526#define ASSERT (x ) if (!(x)) return 0
2627#define PARSER_ASSERT (X , E ) do { if (!(X)) { state->error = (E); XML_StopParser(state->parser, PARSING_NOT_RESUMABLE); return; } } while(0)
@@ -56,8 +57,10 @@ typedef struct {
5657 ErlNifEnv * send_env ;
5758 ErlNifPid * pid ;
5859 size_t depth ;
59- size_t size ;
60- size_t max_size ;
60+ ErlNifUInt64 size ;
61+ ErlNifUInt64 elements_count ;
62+ ErlNifUInt64 max_size ;
63+ ErlNifUInt64 max_elements ;
6164 XML_Parser parser ;
6265 xmlel_stack_t * elements_stack ;
6366 attrs_list_t * xmlns_attrs ;
@@ -256,6 +259,7 @@ static ERL_NIF_TERM str2bin(ErlNifEnv *env, const char *s)
256259static void send_event (state_t * state , ERL_NIF_TERM el )
257260{
258261 state -> size = 0 ;
262+ state -> elements_count = 0 ;
259263 if (state -> gen_server ) {
260264 enif_send (state -> env , state -> pid , state -> send_env ,
261265 enif_make_tuple2 (state -> send_env ,
@@ -270,6 +274,7 @@ static void send_event(state_t *state, ERL_NIF_TERM el)
270274static void send_all_state_event (state_t * state , ERL_NIF_TERM el )
271275{
272276 state -> size = 0 ;
277+ state -> elements_count = 0 ;
273278 if (state -> gen_server ) {
274279 enif_send (state -> env , state -> pid , state -> send_env ,
275280 enif_make_tuple2 (state -> send_env ,
@@ -311,6 +316,9 @@ void erlXML_StartElementHandler(state_t *state,
311316 if (state -> error )
312317 return ;
313318
319+ state -> elements_count += 1 ;
320+ PARSER_ASSERT (state -> elements_count < state -> max_elements , "XML stanza is too big" );
321+
314322 state -> depth ++ ;
315323
316324 while (atts [i ])
@@ -851,6 +859,7 @@ static ERL_NIF_TERM reset_nif(ErlNifEnv* env, int argc,
851859 enif_clear_env (state -> send_env );
852860
853861 state -> size = 0 ;
862+ state -> elements_count = 0 ;
854863 state -> depth = 0 ;
855864 state -> error = NULL ;
856865
@@ -888,6 +897,9 @@ static ERL_NIF_TERM parse_element_nif(ErlNifEnv* env, int argc,
888897 if (!state )
889898 return enif_make_badarg (env );
890899
900+ state -> max_elements = LIMIT_MAX ;
901+ state -> max_size = LIMIT_MAX ;
902+
891903 state -> send_env = env ;
892904 state -> use_maps = use_maps ;
893905
@@ -962,11 +974,14 @@ static ERL_NIF_TERM parse_nif(ErlNifEnv* env, int argc,
962974 state -> size += bin .size ;
963975 state -> env = env ;
964976
977+ if (state -> error ) {
978+ send_error (state , str2bin (state -> send_env , state -> error ));
979+ return argv [0 ];
980+ }
981+
965982 if (state -> size >= state -> max_size ) {
966- size_t size = state -> size ;
967- send_error (state , str2bin (state -> send_env , "XML stanza is too big" ));
968- /* Don't let send_event() to set size to zero */
969- state -> size = size ;
983+ state -> error = "XML stanza is too big" ;
984+ send_error (state , str2bin (state -> send_env , state -> error ));
970985 } else {
971986 int res = XML_Parse (state -> parser , (char * )bin .data , bin .size , 0 );
972987 if (!res )
@@ -1059,17 +1074,68 @@ static ERL_NIF_TERM new_nif(ErlNifEnv* env, int argc,
10591074 ERL_NIF_TERM result = enif_make_resource (env , state );
10601075 enif_release_resource (state );
10611076
1062- ErlNifUInt64 max_size ;
1063- if (enif_get_uint64 (env , argv [1 ], & max_size ))
1077+ ErlNifUInt64 max_size , max_elements ;
1078+ int arity ;
1079+ ERL_NIF_TERM * tuple_elements ;
1080+ if (enif_get_uint64 (env , argv [1 ], & max_size )) {
10641081 state -> max_size = (size_t ) max_size ;
1065- else if (!enif_compare (argv [1 ], enif_make_atom (env , "infinity" )))
1066- state -> max_size = (size_t ) - 1 ;
1067- else
1082+ state -> max_elements = LIMIT_MAX ;
1083+ } else if (!enif_compare (argv [1 ], enif_make_atom (env , "infinity" ))) {
1084+ state -> max_size = LIMIT_MAX ;
1085+ state -> max_elements = LIMIT_MAX ;
1086+ } else if (enif_get_tuple (env , argv [1 ], & arity , & tuple_elements ) && arity == 2 ) {
1087+ if (enif_get_uint64 (env , tuple_elements [0 ], & max_size )) {
1088+ state -> max_size = max_size ;
1089+ } else if (!enif_compare (tuple_elements [0 ], enif_make_atom (env , "infinity" ))) {
1090+ state -> max_size = LIMIT_MAX ;
1091+ } else {
1092+ return enif_make_badarg (env );
1093+ }
1094+
1095+ if (enif_get_uint64 (env , tuple_elements [1 ], & max_elements )) {
1096+ state -> max_elements = max_elements ;
1097+ } else if (!enif_compare (tuple_elements [1 ], enif_make_atom (env , "infinity" ))) {
1098+ state -> max_elements = LIMIT_MAX ;
1099+ } else {
1100+ return enif_make_badarg (env );
1101+ }
1102+ } else
10681103 return enif_make_badarg (env );
10691104
10701105 return result ;
10711106}
10721107
1108+ static ERL_NIF_TERM change_limits_nif (ErlNifEnv * env , int argc ,
1109+ const ERL_NIF_TERM argv [])
1110+ {
1111+ state_t * state = NULL ;
1112+
1113+ if (argc != 3 )
1114+ return enif_make_badarg (env );
1115+
1116+ if (!enif_get_resource (env , argv [0 ], parser_state_t , (void * ) & state ))
1117+ return enif_make_badarg (env );
1118+
1119+ ErlNifUInt64 max_size , max_elements ;
1120+ if (enif_get_uint64 (env , argv [1 ], & max_size )) {
1121+ } else if (!enif_compare (argv [1 ], enif_make_atom (env , "infinity" ))) {
1122+ max_size = LIMIT_MAX ;
1123+ } else
1124+ return enif_make_badarg (env );
1125+
1126+ if (enif_get_uint64 (env , argv [2 ], & max_elements )) {
1127+ } else if (!enif_compare (argv [2 ], enif_make_atom (env , "infinity" ))) {
1128+ max_elements = LIMIT_MAX ;
1129+ } else
1130+ return enif_make_badarg (env );
1131+
1132+ state -> max_size = max_size ;
1133+ state -> max_elements = max_elements ;
1134+
1135+ return enif_make_atom (env , "ok" );
1136+ }
1137+
1138+
10731139static ErlNifFunc nif_funcs [] =
10741140 {
10751141 {"new" , 2 , new_nif },
@@ -1079,7 +1145,8 @@ static ErlNifFunc nif_funcs[] =
10791145 {"parse_element" , 2 , parse_element_nif },
10801146 {"reset" , 1 , reset_nif },
10811147 {"close" , 1 , close_nif },
1082- {"change_callback_pid" , 2 , change_callback_pid_nif }
1148+ {"change_callback_pid" , 2 , change_callback_pid_nif },
1149+ {"change_limits" , 3 , change_limits_nif }
10831150 };
10841151
10851152ERL_NIF_INIT (fxml_stream , nif_funcs , load , NULL , upgrade , NULL )
0 commit comments