diff options
author | Mark Pulford <mark@kyne.com.au> | 2011-05-07 21:01:21 +0930 |
---|---|---|
committer | Mark Pulford <mark@kyne.com.au> | 2011-05-07 21:01:21 +0930 |
commit | 3d014d14bcf3dce3e5dbb9c193d689e46d333798 (patch) | |
tree | ced2ed81700778d505b5992f15af8fb5659a44ff | |
parent | d75e1cb7f0418615e208f49c6209b7c144591f14 (diff) | |
download | lua-cjson-3d014d14bcf3dce3e5dbb9c193d689e46d333798.tar.gz lua-cjson-3d014d14bcf3dce3e5dbb9c193d689e46d333798.tar.bz2 lua-cjson-3d014d14bcf3dce3e5dbb9c193d689e46d333798.zip |
Rework runtime config options
- Rename API for consistency:
- sparse_ratio() -> encode_sparse_array()
- max_depth() -> encode_max_depth()
- invalid_numbers() -> refuse_invalid_numbers()
- Adjust sparse array handling:
- Add "safe" option to allow small sparse arrays regardless of the
ratio.
- Generate an error by default instead of converting an array into an
object (POLA).
- Update invalid number handling:
- Allow decoding invalid numbers by default since many JSON
implementations output NaN/Infinity.
- Throw an error by default when attempting to encode NaN/Infinity
since the RFC explicitly states it is not permitted.
- Support specifying invalid number configuration separately for
encode/decode.
-rw-r--r-- | lua_cjson.c | 174 |
1 files changed, 118 insertions, 56 deletions
diff --git a/lua_cjson.c b/lua_cjson.c index 8727364..3af8157 100644 --- a/lua_cjson.c +++ b/lua_cjson.c | |||
@@ -43,8 +43,12 @@ | |||
43 | 43 | ||
44 | #include "strbuf.h" | 44 | #include "strbuf.h" |
45 | 45 | ||
46 | #define DEFAULT_SPARSE_CONVERT 0 | ||
46 | #define DEFAULT_SPARSE_RATIO 2 | 47 | #define DEFAULT_SPARSE_RATIO 2 |
48 | #define DEFAULT_SPARSE_SAFE 10 | ||
47 | #define DEFAULT_MAX_DEPTH 20 | 49 | #define DEFAULT_MAX_DEPTH 20 |
50 | #define DEFAULT_ENCODE_REFUSE_BADNUM 1 | ||
51 | #define DEFAULT_DECODE_REFUSE_BADNUM 0 | ||
48 | 52 | ||
49 | typedef enum { | 53 | typedef enum { |
50 | T_OBJ_BEGIN, | 54 | T_OBJ_BEGIN, |
@@ -89,10 +93,14 @@ typedef struct { | |||
89 | char *char2escape[256]; /* Encoding */ | 93 | char *char2escape[256]; /* Encoding */ |
90 | #endif | 94 | #endif |
91 | strbuf_t encode_buf; | 95 | strbuf_t encode_buf; |
92 | int sparse_ratio; | ||
93 | int max_depth; | ||
94 | int current_depth; | 96 | int current_depth; |
95 | int strict_numbers; | 97 | |
98 | int encode_sparse_convert; | ||
99 | int encode_sparse_ratio; | ||
100 | int encode_sparse_safe; | ||
101 | int encode_max_depth; | ||
102 | int encode_refuse_badnum; | ||
103 | int decode_refuse_badnum; | ||
96 | } json_config_t; | 104 | } json_config_t; |
97 | 105 | ||
98 | typedef struct { | 106 | typedef struct { |
@@ -171,66 +179,107 @@ static json_config_t *json_fetch_config(lua_State *l) | |||
171 | return cfg; | 179 | return cfg; |
172 | } | 180 | } |
173 | 181 | ||
174 | /* Checks whether a config variable needs to be updated. | 182 | static void json_verify_arg_count(lua_State *l, int args) |
175 | * Also return cfg pointer */ | ||
176 | static int cfg_update_requested(lua_State *l, json_config_t **cfg) | ||
177 | { | 183 | { |
178 | int args; | 184 | luaL_argcheck(l, lua_gettop(l) <= args, args + 1, |
185 | "found too many arguments"); | ||
186 | } | ||
179 | 187 | ||
180 | args = lua_gettop(l); | 188 | /* Configures handling of extremely sparse arrays: |
181 | luaL_argcheck(l, args <= 1, 2, "found too many arguments"); | 189 | * convert: Convert extremely sparse arrays into objects? Otherwise error. |
190 | * ratio: 0: always allow sparse; 1: never allow sparse; >1: use ratio | ||
191 | * safe: Always use an array when the max index <= safe */ | ||
192 | static int json_cfg_encode_sparse_array(lua_State *l) | ||
193 | { | ||
194 | json_config_t *cfg; | ||
195 | int val; | ||
182 | 196 | ||
183 | *cfg = json_fetch_config(l); | 197 | json_verify_arg_count(l, 3); |
198 | cfg = json_fetch_config(l); | ||
184 | 199 | ||
185 | return args; | 200 | switch (lua_gettop(l)) { |
201 | case 3: | ||
202 | val = luaL_checkinteger(l, 3); | ||
203 | luaL_argcheck(l, val >= 0, 3, "expected integer >= 0"); | ||
204 | cfg->encode_sparse_safe = val; | ||
205 | case 2: | ||
206 | val = luaL_checkinteger(l, 2); | ||
207 | luaL_argcheck(l, val >= 0, 2, "expected integer >= 0"); | ||
208 | cfg->encode_sparse_ratio = val; | ||
209 | case 1: | ||
210 | luaL_argcheck(l, lua_isboolean(l, 1), 1, "expected boolean"); | ||
211 | cfg->encode_sparse_convert = lua_toboolean(l, 1); | ||
212 | } | ||
213 | |||
214 | lua_pushboolean(l, cfg->encode_sparse_convert); | ||
215 | lua_pushinteger(l, cfg->encode_sparse_ratio); | ||
216 | lua_pushinteger(l, cfg->encode_sparse_safe); | ||
217 | |||
218 | return 3; | ||
186 | } | 219 | } |
187 | 220 | ||
188 | static int json_sparse_ratio(lua_State *l) | 221 | /* Configures the maximum number of nested arrays/objects allowed when |
222 | * encoding */ | ||
223 | static int json_cfg_encode_max_depth(lua_State *l) | ||
189 | { | 224 | { |
190 | json_config_t *cfg; | 225 | json_config_t *cfg; |
191 | int sparse_ratio; | 226 | int depth; |
227 | |||
228 | json_verify_arg_count(l, 1); | ||
229 | cfg = json_fetch_config(l); | ||
192 | 230 | ||
193 | if (cfg_update_requested(l, &cfg)) { | 231 | if (lua_gettop(l)) { |
194 | sparse_ratio = luaL_checkinteger(l, 1); | 232 | depth = luaL_checkinteger(l, 1); |
195 | luaL_argcheck(l, sparse_ratio >= 0, 1, | 233 | luaL_argcheck(l, depth > 0, 1, "expected positive integer"); |
196 | "expected zero or positive integer"); | 234 | cfg->encode_max_depth = depth; |
197 | cfg->sparse_ratio = sparse_ratio; | ||
198 | } | 235 | } |
199 | 236 | ||
200 | lua_pushinteger(l, cfg->sparse_ratio); | 237 | lua_pushinteger(l, cfg->encode_max_depth); |
201 | 238 | ||
202 | return 1; | 239 | return 1; |
203 | } | 240 | } |
204 | 241 | ||
205 | static int json_max_depth(lua_State *l) | 242 | |
243 | /* On argument: decode enum and set config variables | ||
244 | * **options must point to a NULL terminated array of 4 enums | ||
245 | * Returns: current enum value */ | ||
246 | static void json_enum_option(lua_State *l, const char **options, | ||
247 | int *opt1, int *opt2) | ||
206 | { | 248 | { |
207 | json_config_t *cfg; | 249 | int setting; |
208 | int max_depth; | ||
209 | 250 | ||
210 | if (cfg_update_requested(l, &cfg)) { | 251 | if (lua_gettop(l)) { |
211 | max_depth = luaL_checkinteger(l, 1); | 252 | if (lua_isboolean(l, 1)) |
212 | luaL_argcheck(l, max_depth > 0, 1, "expected positive integer"); | 253 | setting = lua_toboolean(l, 1) * 3; |
213 | cfg->max_depth = max_depth; | 254 | else |
214 | } | 255 | setting = luaL_checkoption(l, 1, NULL, options); |
215 | 256 | ||
216 | lua_pushinteger(l, cfg->max_depth); | 257 | *opt1 = setting & 1 ? 1 : 0; |
258 | *opt2 = setting & 2 ? 1 : 0; | ||
259 | } else { | ||
260 | setting = *opt1 | (*opt2 << 1); | ||
261 | } | ||
217 | 262 | ||
218 | return 1; | 263 | if (setting) |
264 | lua_pushstring(l, options[setting]); | ||
265 | else | ||
266 | lua_pushboolean(l, 0); | ||
219 | } | 267 | } |
220 | 268 | ||
221 | /* When disabled, supports: | 269 | |
222 | * - encoding/decoding NaN/Infinity. | 270 | /* When enabled, rejects: NaN, Infinity, hexidecimal numbers */ |
223 | * - decoding hexidecimal numbers. */ | 271 | static int json_cfg_refuse_invalid_numbers(lua_State *l) |
224 | static int json_strict_numbers(lua_State *l) | ||
225 | { | 272 | { |
273 | static const char *options_enc_dec[] = { "none", "encode", "decode", | ||
274 | "both", NULL }; | ||
226 | json_config_t *cfg; | 275 | json_config_t *cfg; |
227 | 276 | ||
228 | if (cfg_update_requested(l, &cfg)) { | 277 | json_verify_arg_count(l, 1); |
229 | luaL_argcheck(l, lua_isboolean(l, 1), 1, "expected boolean"); | 278 | cfg = json_fetch_config(l); |
230 | cfg->strict_numbers = lua_toboolean(l, 1); | ||
231 | } | ||
232 | 279 | ||
233 | lua_pushboolean(l, cfg->strict_numbers); | 280 | json_enum_option(l, options_enc_dec, |
281 | &cfg->encode_refuse_badnum, | ||
282 | &cfg->decode_refuse_badnum); | ||
234 | 283 | ||
235 | return 1; | 284 | return 1; |
236 | } | 285 | } |
@@ -262,9 +311,12 @@ static void json_create_config(lua_State *l) | |||
262 | 311 | ||
263 | strbuf_init(&cfg->encode_buf, 0); | 312 | strbuf_init(&cfg->encode_buf, 0); |
264 | 313 | ||
265 | cfg->sparse_ratio = DEFAULT_SPARSE_RATIO; | 314 | cfg->encode_sparse_convert = DEFAULT_SPARSE_CONVERT; |
266 | cfg->max_depth = DEFAULT_MAX_DEPTH; | 315 | cfg->encode_sparse_ratio = DEFAULT_SPARSE_RATIO; |
267 | cfg->strict_numbers = 1; | 316 | cfg->encode_sparse_safe = DEFAULT_SPARSE_SAFE; |
317 | cfg->encode_max_depth = DEFAULT_MAX_DEPTH; | ||
318 | cfg->encode_refuse_badnum = DEFAULT_ENCODE_REFUSE_BADNUM; | ||
319 | cfg->decode_refuse_badnum = DEFAULT_DECODE_REFUSE_BADNUM; | ||
268 | 320 | ||
269 | /* Decoding init */ | 321 | /* Decoding init */ |
270 | 322 | ||
@@ -382,7 +434,7 @@ static void json_append_string(lua_State *l, strbuf_t *json, int lindex) | |||
382 | * -1 object (not a pure array) | 434 | * -1 object (not a pure array) |
383 | * >=0 elements in array | 435 | * >=0 elements in array |
384 | */ | 436 | */ |
385 | static int lua_array_length(lua_State *l, int sparse_ratio) | 437 | static int lua_array_length(lua_State *l, json_config_t *cfg) |
386 | { | 438 | { |
387 | double k; | 439 | double k; |
388 | int max; | 440 | int max; |
@@ -413,8 +465,14 @@ static int lua_array_length(lua_State *l, int sparse_ratio) | |||
413 | } | 465 | } |
414 | 466 | ||
415 | /* Encode very sparse arrays as objects (if enabled) */ | 467 | /* Encode very sparse arrays as objects (if enabled) */ |
416 | if (sparse_ratio > 0 && max > items * sparse_ratio) | 468 | if (cfg->encode_sparse_ratio > 0 && |
469 | max > items * cfg->encode_sparse_ratio && | ||
470 | max > cfg->encode_sparse_safe) { | ||
471 | if (!cfg->encode_sparse_convert) | ||
472 | json_encode_exception(l, -1, "excessively sparse array"); | ||
473 | |||
417 | return -1; | 474 | return -1; |
475 | } | ||
418 | 476 | ||
419 | return max; | 477 | return max; |
420 | } | 478 | } |
@@ -423,7 +481,7 @@ static void json_encode_descend(lua_State *l, json_config_t *cfg) | |||
423 | { | 481 | { |
424 | cfg->current_depth++; | 482 | cfg->current_depth++; |
425 | 483 | ||
426 | if (cfg->current_depth > cfg->max_depth) { | 484 | if (cfg->current_depth > cfg->encode_max_depth) { |
427 | luaL_error(l, "Cannot serialise, excessive nesting (%d)", | 485 | luaL_error(l, "Cannot serialise, excessive nesting (%d)", |
428 | cfg->current_depth); | 486 | cfg->current_depth); |
429 | } | 487 | } |
@@ -462,11 +520,11 @@ static void json_append_array(lua_State *l, json_config_t *cfg, strbuf_t *json, | |||
462 | } | 520 | } |
463 | 521 | ||
464 | static void json_append_number(lua_State *l, strbuf_t *json, int index, | 522 | static void json_append_number(lua_State *l, strbuf_t *json, int index, |
465 | int strict) | 523 | int refuse_badnum) |
466 | { | 524 | { |
467 | double num = lua_tonumber(l, index); | 525 | double num = lua_tonumber(l, index); |
468 | 526 | ||
469 | if (strict && (isinf(num) || isnan(num))) | 527 | if (refuse_badnum && (isinf(num) || isnan(num))) |
470 | json_encode_exception(l, index, "must not be NaN or Inf"); | 528 | json_encode_exception(l, index, "must not be NaN or Inf"); |
471 | 529 | ||
472 | strbuf_append_number(json, num); | 530 | strbuf_append_number(json, num); |
@@ -497,7 +555,7 @@ static void json_append_object(lua_State *l, json_config_t *cfg, | |||
497 | /* Can't just use json_append_string() below since it would | 555 | /* Can't just use json_append_string() below since it would |
498 | * convert the value in the callers data structure. */ | 556 | * convert the value in the callers data structure. */ |
499 | strbuf_append_char(json, '"'); | 557 | strbuf_append_char(json, '"'); |
500 | json_append_number(l, json, -2, cfg->strict_numbers); | 558 | json_append_number(l, json, -2, cfg->encode_refuse_badnum); |
501 | strbuf_append_mem(json, "\": ", 3); | 559 | strbuf_append_mem(json, "\": ", 3); |
502 | } else if (keytype == LUA_TSTRING) { | 560 | } else if (keytype == LUA_TSTRING) { |
503 | json_append_string(l, json, -2); | 561 | json_append_string(l, json, -2); |
@@ -529,7 +587,7 @@ static void json_append_data(lua_State *l, json_config_t *cfg, strbuf_t *json) | |||
529 | json_append_string(l, json, -1); | 587 | json_append_string(l, json, -1); |
530 | break; | 588 | break; |
531 | case LUA_TNUMBER: | 589 | case LUA_TNUMBER: |
532 | json_append_number(l, json, -1, cfg->strict_numbers); | 590 | json_append_number(l, json, -1, cfg->encode_refuse_badnum); |
533 | break; | 591 | break; |
534 | case LUA_TBOOLEAN: | 592 | case LUA_TBOOLEAN: |
535 | if (lua_toboolean(l, -1)) | 593 | if (lua_toboolean(l, -1)) |
@@ -538,7 +596,7 @@ static void json_append_data(lua_State *l, json_config_t *cfg, strbuf_t *json) | |||
538 | strbuf_append_mem(json, "false", 5); | 596 | strbuf_append_mem(json, "false", 5); |
539 | break; | 597 | break; |
540 | case LUA_TTABLE: | 598 | case LUA_TTABLE: |
541 | len = lua_array_length(l, cfg->sparse_ratio); | 599 | len = lua_array_length(l, cfg); |
542 | if (len > 0) | 600 | if (len > 0) |
543 | json_append_array(l, cfg, json, len); | 601 | json_append_array(l, cfg, json, len); |
544 | else | 602 | else |
@@ -566,6 +624,8 @@ static int json_encode(lua_State *l) | |||
566 | char *json; | 624 | char *json; |
567 | int len; | 625 | int len; |
568 | 626 | ||
627 | /* Can't use json_verify_arg_count() since we need to ensure | ||
628 | * there is only 1 argument */ | ||
569 | luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument"); | 629 | luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument"); |
570 | 630 | ||
571 | cfg = json_fetch_config(l); | 631 | cfg = json_fetch_config(l); |
@@ -853,7 +913,7 @@ static void json_next_token(json_parse_t *json, json_token_t *token) | |||
853 | json_next_string_token(json, token); | 913 | json_next_string_token(json, token); |
854 | return; | 914 | return; |
855 | } else if (ch == '-' || ('0' <= ch && ch <= '9')) { | 915 | } else if (ch == '-' || ('0' <= ch && ch <= '9')) { |
856 | if (json->cfg->strict_numbers && json_is_invalid_number(json)) { | 916 | if (json->cfg->decode_refuse_badnum && json_is_invalid_number(json)) { |
857 | json_set_token_error(token, json, "invalid number"); | 917 | json_set_token_error(token, json, "invalid number"); |
858 | return; | 918 | return; |
859 | } | 919 | } |
@@ -873,8 +933,9 @@ static void json_next_token(json_parse_t *json, json_token_t *token) | |||
873 | token->type = T_NULL; | 933 | token->type = T_NULL; |
874 | json->index += 4; | 934 | json->index += 4; |
875 | return; | 935 | return; |
876 | } else if (!json->cfg->strict_numbers && json_is_invalid_number(json)) { | 936 | } else if (!json->cfg->decode_refuse_badnum && |
877 | /* When strict_numbers is disabled, only attempt to process | 937 | json_is_invalid_number(json)) { |
938 | /* When refuse_badnum is disabled, only attempt to process | ||
878 | * numbers we know are invalid JSON (Inf, NaN, hex) | 939 | * numbers we know are invalid JSON (Inf, NaN, hex) |
879 | * This is required to generate an appropriate token error, | 940 | * This is required to generate an appropriate token error, |
880 | * otherwise all bad tokens will register as "invalid number" | 941 | * otherwise all bad tokens will register as "invalid number" |
@@ -1055,7 +1116,8 @@ static int json_decode(lua_State *l) | |||
1055 | const char *json; | 1116 | const char *json; |
1056 | size_t len; | 1117 | size_t len; |
1057 | 1118 | ||
1058 | luaL_argcheck(l, lua_gettop(l) <= 1, 2, "found too many arguments"); | 1119 | json_verify_arg_count(l, 1); |
1120 | |||
1059 | json = luaL_checklstring(l, 1, &len); | 1121 | json = luaL_checklstring(l, 1, &len); |
1060 | 1122 | ||
1061 | lua_json_decode(l, json, len); | 1123 | lua_json_decode(l, json, len); |
@@ -1070,9 +1132,9 @@ int luaopen_cjson(lua_State *l) | |||
1070 | luaL_Reg reg[] = { | 1132 | luaL_Reg reg[] = { |
1071 | { "encode", json_encode }, | 1133 | { "encode", json_encode }, |
1072 | { "decode", json_decode }, | 1134 | { "decode", json_decode }, |
1073 | { "sparse_ratio", json_sparse_ratio }, | 1135 | { "encode_sparse_array", json_cfg_encode_sparse_array }, |
1074 | { "max_depth", json_max_depth }, | 1136 | { "encode_max_depth", json_cfg_encode_max_depth }, |
1075 | { "strict_numbers", json_strict_numbers }, | 1137 | { "refuse_invalid_numbers", json_cfg_refuse_invalid_numbers }, |
1076 | { NULL, NULL } | 1138 | { NULL, NULL } |
1077 | }; | 1139 | }; |
1078 | 1140 | ||