From: Petri Lehtinen Date: Mon, 24 Jan 2011 19:45:54 +0000 (+0200) Subject: Add validation features to json_unpack() X-Git-Tag: v2.0~24 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=jansson.git;a=commitdiff_plain;h=2770dca2c091a9c5c898ff0922d905449111ff95 Add validation features to json_unpack() * By default, json_unpack() now checks that all items of arrays and objects are unpacked. This is useful for validation. * Add format specifier '*' to suppress this check for individual arrays and objects. '*' must appear as the last format specifier before the closing ']' or '}'. --- diff --git a/src/jansson_private.h b/src/jansson_private.h index 66550da..8bb8057 100644 --- a/src/jansson_private.h +++ b/src/jansson_private.h @@ -57,6 +57,9 @@ typedef struct { #define json_to_real(json_) container_of(json_, json_real_t, json) #define json_to_integer(json_) container_of(json_, json_integer_t, json) +size_t jsonp_hash_key(const void *ptr); +int jsonp_key_equal(const void *ptr1, const void *ptr2); + typedef struct { size_t serial; char key[1]; diff --git a/src/pack_unpack.c b/src/pack_unpack.c index f9311ba..8dc31fe 100644 --- a/src/pack_unpack.c +++ b/src/pack_unpack.c @@ -179,9 +179,18 @@ static int unpack(scanner_t *s, json_t *root, va_list *ap); static int unpack_object(scanner_t *s, json_t *root, va_list *ap) { + int ret = -1; + int wildcard = 0; + hashtable_t key_set; + + if(hashtable_init(&key_set, jsonp_hash_key, jsonp_key_equal, NULL, NULL)) { + set_error(s, "Out of memory"); + return -1; + } + if(!json_is_object(root)) { set_error(s, "Expected object, got %i", json_typeof(root)); - return -1; + goto error; } next_token(s); @@ -189,37 +198,59 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) const char *key; json_t *value; + if(wildcard) { + set_error(s, "Expected '}', got '%c'", s->token); + goto error; + } + if(!s->token) { set_error(s, "Unexpected end of format string"); - return -1; + goto error; + } + + if(s->token == '*') { + wildcard = 1; + next_token(s); + continue; } if(s->token != 's') { set_error(s, "Expected format 's', got '%c'\n", *s->fmt); - return -1; + goto error; } key = va_arg(*ap, const char *); if(!key) { set_error(s, "NULL object key"); - return -1; + goto error; } next_token(s); value = json_object_get(root, key); if(unpack(s, value, ap)) - return -1; + goto error; + hashtable_set(&key_set, (void *)key, NULL); next_token(s); } - return 0; + if(!wildcard && key_set.size != json_object_size(root)) { + long diff = (long)json_object_size(root) - (long)key_set.size; + set_error(s, "%li object items left unpacked", diff); + goto error; + } + ret = 0; + +error: + hashtable_close(&key_set); + return ret; } static int unpack_array(scanner_t *s, json_t *root, va_list *ap) { size_t i = 0; + int wildcard = 0; if(!json_is_array(root)) { set_error(s, "Expected array, got %d", json_typeof(root)); @@ -230,11 +261,22 @@ static int unpack_array(scanner_t *s, json_t *root, va_list *ap) while(s->token != ']') { json_t *value; + if(wildcard) { + set_error(s, "Expected ']', got '%c'", s->token); + return -1; + } + if(!s->token) { set_error(s, "Unexpected end of format string"); return -1; } + if(s->token == '*') { + wildcard = 1; + next_token(s); + continue; + } + value = json_array_get(root, i); if(!value) { set_error(s, "Array index %lu out of range", (unsigned long)i); @@ -248,9 +290,9 @@ static int unpack_array(scanner_t *s, json_t *root, va_list *ap) i++; } - if(i != json_array_size(root)) { + if(!wildcard && i != json_array_size(root)) { long diff = (long)json_array_size(root) - (long)i; - set_error(s, "%li array items were not upacked", diff); + set_error(s, "%li array items left upacked", diff); return -1; } diff --git a/src/value.c b/src/value.c index 0df4570..534624c 100644 --- a/src/value.c +++ b/src/value.c @@ -32,7 +32,7 @@ static JSON_INLINE void json_init(json_t *json, json_type type) an object_key_t instance. */ #define string_to_key(string) container_of(string, object_key_t, key) -static size_t hash_key(const void *ptr) +size_t jsonp_hash_key(const void *ptr) { const char *str = ((const object_key_t *)ptr)->key; @@ -48,7 +48,7 @@ static size_t hash_key(const void *ptr) return hash; } -static int key_equal(const void *ptr1, const void *ptr2) +int jsonp_key_equal(const void *ptr1, const void *ptr2) { return strcmp(((const object_key_t *)ptr1)->key, ((const object_key_t *)ptr2)->key) == 0; @@ -66,7 +66,8 @@ json_t *json_object(void) return NULL; json_init(&object->json, JSON_OBJECT); - if(hashtable_init(&object->hashtable, hash_key, key_equal, + if(hashtable_init(&object->hashtable, + jsonp_hash_key, jsonp_key_equal, free, value_decref)) { free(object);