diff --git a/src/nxt_conf.c b/src/nxt_conf.c index 5ec86cd4..fd6a62f5 100644 --- a/src/nxt_conf.c +++ b/src/nxt_conf.c @@ -112,6 +112,8 @@ static void nxt_conf_json_parse_error(nxt_conf_json_error_t *error, u_char *pos, static nxt_int_t nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst, nxt_conf_value_t *src); +static nxt_int_t nxt_conf_copy_array(nxt_mp_t *mp, nxt_conf_op_t *op, + nxt_conf_value_t *dst, nxt_conf_value_t *src); static nxt_int_t nxt_conf_copy_object(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst, nxt_conf_value_t *src); @@ -740,6 +742,7 @@ nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root, nxt_str_t *path, nxt_conf_value_t *value) { nxt_str_t token; + nxt_int_t index; nxt_conf_op_t *op, **parent; nxt_conf_value_t *node; nxt_conf_path_parse_t parse; @@ -762,7 +765,27 @@ nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root, nxt_conf_path_next_token(&parse, &token); - node = nxt_conf_get_object_member(root, &token, &op->index); + switch (root->type) { + + case NXT_CONF_VALUE_OBJECT: + node = nxt_conf_get_object_member(root, &token, &op->index); + break; + + case NXT_CONF_VALUE_ARRAY: + index = nxt_int_parse(token.start, token.length); + + if (index < 0 || index > NXT_INT32_T_MAX) { + return NXT_DECLINED; + } + + op->index = index; + + node = nxt_conf_get_array_element(root, index); + break; + + default: + node = NULL; + } if (parse.last) { break; @@ -787,8 +810,23 @@ nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root, return NXT_OK; } - if (node == NULL) { + if (node != NULL) { + op->action = NXT_CONF_OP_REPLACE; + op->ctx = value; + return NXT_OK; + } + + op->action = NXT_CONF_OP_CREATE; + + if (root->type == NXT_CONF_VALUE_ARRAY) { + if (op->index > root->u.array->count) { + return NXT_DECLINED; + } + + op->ctx = value; + + } else { member = nxt_mp_zget(mp, sizeof(nxt_conf_object_member_t)); if (nxt_slow_path(member == NULL)) { return NXT_ERROR; @@ -799,12 +837,7 @@ nxt_conf_op_compile(nxt_mp_t *mp, nxt_conf_op_t **ops, nxt_conf_value_t *root, member->value = *value; op->index = root->u.object->count; - op->action = NXT_CONF_OP_CREATE; op->ctx = member; - - } else { - op->action = NXT_CONF_OP_REPLACE; - op->ctx = value; } return NXT_OK; @@ -836,16 +869,13 @@ static nxt_int_t nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst, nxt_conf_value_t *src) { - size_t size; - nxt_int_t rc; - nxt_uint_t n; - - if (op != NULL && src->type != NXT_CONF_VALUE_OBJECT) { + if (op != NULL + && src->type != NXT_CONF_VALUE_ARRAY + && src->type != NXT_CONF_VALUE_OBJECT) + { return NXT_ERROR; } - dst->type = src->type; - switch (src->type) { case NXT_CONF_VALUE_STRING: @@ -863,27 +893,7 @@ nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst, break; case NXT_CONF_VALUE_ARRAY: - - size = sizeof(nxt_conf_array_t) - + src->u.array->count * sizeof(nxt_conf_value_t); - - dst->u.array = nxt_mp_get(mp, size); - if (nxt_slow_path(dst->u.array == NULL)) { - return NXT_ERROR; - } - - dst->u.array->count = src->u.array->count; - - for (n = 0; n < src->u.array->count; n++) { - rc = nxt_conf_copy_value(mp, NULL, &dst->u.array->elements[n], - &src->u.array->elements[n]); - - if (nxt_slow_path(rc != NXT_OK)) { - return NXT_ERROR; - } - } - - break; + return nxt_conf_copy_array(mp, op, dst, src); case NXT_CONF_VALUE_OBJECT: return nxt_conf_copy_object(mp, op, dst, src); @@ -892,6 +902,108 @@ nxt_conf_copy_value(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst, dst->u = src->u; } + dst->type = src->type; + + return NXT_OK; +} + + +static nxt_int_t +nxt_conf_copy_array(nxt_mp_t *mp, nxt_conf_op_t *op, nxt_conf_value_t *dst, + nxt_conf_value_t *src) +{ + size_t size; + nxt_int_t rc; + nxt_uint_t s, d, count, index; + nxt_conf_op_t *pass_op; + nxt_conf_value_t *value; + + count = src->u.array->count; + + if (op != NULL) { + if (op->action == NXT_CONF_OP_CREATE) { + count++; + + } else if (op->action == NXT_CONF_OP_DELETE) { + count--; + } + } + + size = sizeof(nxt_conf_array_t) + count * sizeof(nxt_conf_value_t); + + dst->u.array = nxt_mp_get(mp, size); + if (nxt_slow_path(dst->u.array == NULL)) { + return NXT_ERROR; + } + + dst->u.array->count = count; + + s = 0; + d = 0; + + pass_op = NULL; + + /* + * This initialization is needed only to + * suppress a warning on GCC 4.8 and older. + */ + index = 0; + + do { + if (pass_op == NULL) { + index = (op == NULL) ? src->u.array->count : op->index; + } + + while (s != index) { + rc = nxt_conf_copy_value(mp, pass_op, &dst->u.array->elements[d], + &src->u.array->elements[s]); + if (nxt_slow_path(rc != NXT_OK)) { + return NXT_ERROR; + } + + s++; + d++; + } + + if (pass_op != NULL) { + pass_op = NULL; + continue; + } + + if (op != NULL) { + switch (op->action) { + case NXT_CONF_OP_PASS: + pass_op = op->ctx; + index++; + break; + + case NXT_CONF_OP_CREATE: + value = op->ctx; + dst->u.array->elements[d] = *value; + + d++; + break; + + case NXT_CONF_OP_REPLACE: + value = op->ctx; + dst->u.array->elements[d] = *value; + + s++; + d++; + break; + + case NXT_CONF_OP_DELETE: + s++; + break; + } + + op = NULL; + } + + } while (d != count); + + dst->type = src->type; + return NXT_OK; }