sd-json: when parsing optionally insist top-level variant is object or array
Typically, the top-level JSON object has to be an object, in any json document we parse, hence let's add a simple way to enforce that. Make use of this in various places. (Note, various other JSON parsers insist on this logic right from the beginning, but I actually thinking making this insisting optional like this patch does it is the cleaner approach)
This commit is contained in:
committed by
Daan De Meyer
parent
bc6380ae07
commit
2c74a91cb8
@@ -3039,7 +3039,6 @@ static int json_parse_internal(
|
||||
int r;
|
||||
|
||||
assert_return(input, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
p = *input;
|
||||
|
||||
@@ -3111,12 +3110,16 @@ static int json_parse_internal(
|
||||
break;
|
||||
|
||||
case JSON_TOKEN_OBJECT_OPEN:
|
||||
|
||||
if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_FIRST_ELEMENT, EXPECT_ARRAY_NEXT_ELEMENT)) {
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (n_stack == 1 && FLAGS_SET(flags, SD_JSON_PARSE_MUST_BE_ARRAY) && !FLAGS_SET(flags, SD_JSON_PARSE_MUST_BE_OBJECT)) {
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (!GREEDY_REALLOC(stack, n_stack+1)) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
@@ -3168,6 +3171,11 @@ static int json_parse_internal(
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (n_stack == 1 && !FLAGS_SET(flags, SD_JSON_PARSE_MUST_BE_ARRAY) && FLAGS_SET(flags, SD_JSON_PARSE_MUST_BE_OBJECT)) {
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (!GREEDY_REALLOC(stack, n_stack+1)) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
@@ -3217,6 +3225,11 @@ static int json_parse_internal(
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (n_stack == 1 && (flags & (SD_JSON_PARSE_MUST_BE_ARRAY|SD_JSON_PARSE_MUST_BE_OBJECT)) != 0) {
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = sd_json_variant_new_string(&add, string);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
@@ -3240,6 +3253,11 @@ static int json_parse_internal(
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (n_stack == 1 && (flags & (SD_JSON_PARSE_MUST_BE_ARRAY|SD_JSON_PARSE_MUST_BE_OBJECT)) != 0) {
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = sd_json_variant_new_real(&add, value.real);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
@@ -3261,6 +3279,11 @@ static int json_parse_internal(
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (n_stack == 1 && (flags & (SD_JSON_PARSE_MUST_BE_ARRAY|SD_JSON_PARSE_MUST_BE_OBJECT)) != 0) {
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = sd_json_variant_new_integer(&add, value.integer);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
@@ -3282,6 +3305,11 @@ static int json_parse_internal(
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (n_stack == 1 && (flags & (SD_JSON_PARSE_MUST_BE_ARRAY|SD_JSON_PARSE_MUST_BE_OBJECT)) != 0) {
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = sd_json_variant_new_unsigned(&add, value.unsig);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
@@ -3303,6 +3331,11 @@ static int json_parse_internal(
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (n_stack == 1 && (flags & (SD_JSON_PARSE_MUST_BE_ARRAY|SD_JSON_PARSE_MUST_BE_OBJECT)) != 0) {
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = sd_json_variant_new_boolean(&add, value.boolean);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
@@ -3324,6 +3357,11 @@ static int json_parse_internal(
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (n_stack == 1 && (flags & (SD_JSON_PARSE_MUST_BE_ARRAY|SD_JSON_PARSE_MUST_BE_OBJECT)) != 0) {
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = sd_json_variant_new_null(&add);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
@@ -3365,7 +3403,8 @@ done:
|
||||
assert(n_stack == 1);
|
||||
assert(stack[0].n_elements == 1);
|
||||
|
||||
*ret = sd_json_variant_ref(stack[0].elements[0]);
|
||||
if (ret)
|
||||
*ret = sd_json_variant_ref(stack[0].elements[0]);
|
||||
*input = p;
|
||||
r = 0;
|
||||
|
||||
|
||||
@@ -1009,14 +1009,14 @@ static int varlink_parse_message(sd_varlink *v) {
|
||||
|
||||
sz = e - begin + 1;
|
||||
|
||||
r = sd_json_parse(begin, 0, &v->current, NULL, NULL);
|
||||
r = sd_json_parse(begin, SD_JSON_PARSE_MUST_BE_OBJECT, &v->current, /* reterr_line= */ NULL, /* reterr_column= */ NULL);
|
||||
if (v->input_sensitive)
|
||||
explicit_bzero_safe(begin, sz);
|
||||
if (r < 0) {
|
||||
/* If we encounter a parse failure flush all data. We cannot possibly recover from this,
|
||||
* hence drop all buffered data now. */
|
||||
v->input_buffer_index = v->input_buffer_size = v->input_buffer_unscanned = 0;
|
||||
return varlink_log_errno(v, r, "Failed to parse JSON: %m");
|
||||
return varlink_log_errno(v, r, "Failed to parse JSON object: %m");
|
||||
}
|
||||
|
||||
if (v->input_sensitive) {
|
||||
|
||||
Reference in New Issue
Block a user