ctx->stack = NULL;
ctx->in_key = 0;
+ ctx->escaped = 0;
}
u_char *p, *last, *start;
ngx_int_t rc, hd;
ngx_uint_t skip_depth;
+ ngx_json_event_e event;
ngx_json_state_e state;
if (len == 0) {
if (*p == '"') {
ctx->in_key = 1;
+ ctx->escaped = 0;
start = p + 1;
state = ngx_json_string;
break;
if (*p == '"') {
ctx->in_key = 0;
+ ctx->escaped = 0;
start = p + 1;
state = ngx_json_string;
break;
if (*p == '"') {
if (ctx->in_key) {
- rc = ngx_json_emit(ctx, NGX_JSON_KEY, start, p - start);
+ event = ctx->escaped ? NGX_JSON_KEY_ESCAPED
+ : NGX_JSON_KEY;
+
+ rc = ngx_json_emit(ctx, event, start, p - start);
if (rc != NGX_OK) {
return rc;
}
state = ngx_json_object_name_separator;
} else {
- rc = ngx_json_emit(ctx, NGX_JSON_VALUE_STRING, start,
- p - start);
+ event = ctx->escaped ? NGX_JSON_VALUE_STRING_ESCAPED
+ : NGX_JSON_VALUE_STRING;
+
+ rc = ngx_json_emit(ctx, event, start, p - start);
if (rc != NGX_OK) {
return rc;
}
}
if (*p == '\\') {
+ ctx->escaped = 1;
state = ngx_json_escaped;
break;
}
switch (event) {
case NGX_JSON_KEY:
+ case NGX_JSON_KEY_ESCAPED:
case NGX_JSON_OBJECT_OPEN:
case NGX_JSON_ARRAY_OPEN:
ctx->skip_until_depth = ctx->depth;
break;
case NGX_JSON_VALUE_STRING:
+ case NGX_JSON_VALUE_STRING_ESCAPED:
case NGX_JSON_VALUE_NUMBER:
case NGX_JSON_VALUE_BOOL:
case NGX_JSON_VALUE_NULL:
ngx_http_request_t *r;
ngx_http_variable_value_t *values;
ngx_array_t stack;
- ngx_str_t current_key;
+ ngx_str_t key_buffer;
+ ngx_uint_t in_member;
ngx_http_json_node_t *current_node;
ngx_http_json_node_t *root;
} ngx_http_json_state_t;
ngx_http_json_handler(ngx_json_ctx_t *ctx, ngx_json_event_e event,
ngx_str_t *token)
{
- ngx_str_t slice, value;
+ size_t size;
+ u_char *p;
+ ngx_str_t key, slice, value;
ngx_uint_t is_member;
ngx_http_json_node_t *node;
ngx_http_json_state_t *state;
if (state->stack.nelts == 0) {
- ngx_str_null(&state->current_key);
+ state->in_member = 0;
state->current_node = NULL;
return ngx_http_json_push(state, event, token->data, state->root);
}
- is_member = (state->current_key.data != NULL);
- ngx_str_null(&state->current_key);
+ is_member = state->in_member;
+ state->in_member = 0;
if (is_member) {
break;
case NGX_JSON_KEY:
+ case NGX_JSON_KEY_ESCAPED:
- if (ngx_strlchr(token->data, token->data + token->len, '\\') == NULL) {
- state->current_key = *token;
+ key = *token;
- } else {
- state->current_key.data = ngx_pnalloc(ctx->pool, token->len);
- if (state->current_key.data == NULL) {
- return NGX_ERROR;
+ if (event == NGX_JSON_KEY_ESCAPED) {
+ if (token->len > state->key_buffer.len) {
+ size = token->len;
+
+ if (state->key_buffer.len <= NGX_MAX_SIZE_T_VALUE / 2) {
+ size = ngx_max(size, state->key_buffer.len * 2);
+ }
+
+ p = ngx_pnalloc(ctx->pool, size);
+ if (p == NULL) {
+ return NGX_ERROR;
+ }
+
+ state->key_buffer.data = p;
+ state->key_buffer.len = size;
}
- state->current_key.len = token->len;
+ key = state->key_buffer;
- if (ngx_json_unescape_string(&state->current_key, token) != NGX_OK)
- {
+ if (ngx_json_unescape_string(&key, token) != NGX_OK) {
return NGX_ERROR;
}
}
- node = ngx_http_json_lookup_key(top->node, &state->current_key);
+ node = ngx_http_json_lookup_key(top->node, &key);
if (node == NULL) {
- ngx_str_null(&state->current_key);
+ state->in_member = 0;
state->current_node = NULL;
return NGX_JSON_SKIP;
}
+ state->in_member = 1;
state->current_node = node;
break;
case NGX_JSON_VALUE_STRING:
+ case NGX_JSON_VALUE_STRING_ESCAPED:
case NGX_JSON_VALUE_NUMBER:
case NGX_JSON_VALUE_BOOL:
case NGX_JSON_VALUE_NULL:
if (top == NULL) {
- ngx_str_null(&state->current_key);
+ state->in_member = 0;
state->current_node = NULL;
break;
}
- is_member = (state->current_key.data != NULL);
- ngx_str_null(&state->current_key);
+ is_member = state->in_member;
+ state->in_member = 0;
if (is_member) {
value = *token;
if (ngx_http_json_store(state, node, &value,
- event == NGX_JSON_VALUE_STRING)
+ event == NGX_JSON_VALUE_STRING_ESCAPED)
!= NGX_OK)
{
return NGX_ERROR;