aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Pulford <mark@kyne.com.au>2011-05-07 21:01:21 +0930
committerMark Pulford <mark@kyne.com.au>2011-05-07 21:01:21 +0930
commit3d014d14bcf3dce3e5dbb9c193d689e46d333798 (patch)
treeced2ed81700778d505b5992f15af8fb5659a44ff
parentd75e1cb7f0418615e208f49c6209b7c144591f14 (diff)
downloadlua-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.c174
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
49typedef enum { 53typedef 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
98typedef struct { 106typedef 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. 182static void json_verify_arg_count(lua_State *l, int args)
175 * Also return cfg pointer */
176static 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 */
192static 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
188static int json_sparse_ratio(lua_State *l) 221/* Configures the maximum number of nested arrays/objects allowed when
222 * encoding */
223static 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
205static 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 */
246static 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. */ 271static int json_cfg_refuse_invalid_numbers(lua_State *l)
224static 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 */
385static int lua_array_length(lua_State *l, int sparse_ratio) 437static 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
464static void json_append_number(lua_State *l, strbuf_t *json, int index, 522static 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