From 57d05f374cc577b23ce6af48fcd4a553a001b80a Mon Sep 17 00:00:00 2001 From: Evgeny Shirykalov Date: Wed, 30 Sep 2026 09:52:19 -0700 Subject: [PATCH] JSON: modified ngx_json_unescape_string() to unescape into a new buffer --- src/core/ngx_json_unescape.c | 20 ++++++++++---------- src/core/ngx_json_unescape.h | 15 ++++++++++----- src/http/modules/ngx_http_json_module.c | 25 ++++++++++++++++++------- 3 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/core/ngx_json_unescape.c b/src/core/ngx_json_unescape.c index a82878034..36097be46 100644 --- a/src/core/ngx_json_unescape.c +++ b/src/core/ngx_json_unescape.c @@ -20,10 +20,10 @@ static ngx_inline u_char *ngx_json_utf8_encode(u_char *dst, ngx_int_t -ngx_json_unescape_string(ngx_str_t *str) +ngx_json_unescape_string(ngx_str_t *dst, ngx_str_t *src) { size_t size; - u_char *d, *s, *start, ch; + u_char *d, *s, ch; uint32_t codepoint, high_surrogate; ngx_int_t n; ngx_uint_t hex_left; @@ -59,21 +59,22 @@ ngx_json_unescape_string(ngx_str_t *str) * The pair decodes to U+10000 + (high - 0xD800) * 0x400 * + (low - 0xDC00). * The input is an unquoted JSON string body (the bytes between the - * surrounding double quotes); it is decoded in place. + * surrounding double quotes). */ - if (str->len == 0) { + if (src->len == 0) { + dst->len = 0; return NGX_OK; } - if (str->data == NULL) { + if (dst->len < src->len) { return NGX_ERROR; } - start = str->data; - size = str->len; + s = src->data; + d = dst->data; + size = src->len; - d = s = start; state = sw_usual; codepoint = 0; @@ -227,8 +228,7 @@ ngx_json_unescape_string(ngx_str_t *str) return NGX_ERROR; } - str->data = start; - str->len = d - start; + dst->len = d - dst->data; return NGX_OK; } diff --git a/src/core/ngx_json_unescape.h b/src/core/ngx_json_unescape.h index 8fb0f54b0..62ed32d27 100644 --- a/src/core/ngx_json_unescape.h +++ b/src/core/ngx_json_unescape.h @@ -13,12 +13,17 @@ /* - * Decode JSON escape sequences (RFC 8259, Section 7) in place. The input - * is an unquoted JSON string body (no surrounding double quotes); on success - * str->len is updated to the decoded length. Returns NGX_OK, or NGX_ERROR - * on a malformed escape or invalid input. + * Decode JSON escape sequences (RFC 8259, Section 7). The input + * is an unquoted JSON string body (no surrounding double quotes). + * + * On entry, dst->len is the capacity of dst->data and must be at least + * src->len. + * On success, dst->len is the decoded length. + * + * Returns NGX_OK, or NGX_ERROR on a malformed escape or invalid input. */ -ngx_int_t ngx_json_unescape_string(ngx_str_t *str); +ngx_int_t ngx_json_unescape_string(ngx_str_t *dst, ngx_str_t *src); + ngx_int_t ngx_json_hex_digit(u_char ch); diff --git a/src/http/modules/ngx_http_json_module.c b/src/http/modules/ngx_http_json_module.c index 78099a43d..57f106c6c 100644 --- a/src/http/modules/ngx_http_json_module.c +++ b/src/http/modules/ngx_http_json_module.c @@ -392,6 +392,7 @@ ngx_http_json_insert_path(ngx_conf_t *cf, ngx_http_json_node_t *root, { u_char *p, *last, *start, *dst; ngx_int_t index; + ngx_str_t raw; ngx_uint_t *term; ngx_http_json_seg_t seg; ngx_http_json_node_t *node; @@ -523,14 +524,15 @@ ngx_http_json_insert_path(ngx_conf_t *cf, ngx_http_json_node_t *root, return NGX_CONF_ERROR; } - ngx_memcpy(dst, start, p - start); + raw.data = start; + raw.len = p - start; seg.is_index = 0; seg.key.data = dst; seg.key.len = p - start; seg.index = 0; - if (ngx_json_unescape_string(&seg.key) != NGX_OK) { + if (ngx_json_unescape_string(&seg.key, &raw) != NGX_OK) { goto invalid; } @@ -751,14 +753,15 @@ ngx_http_json_handler(ngx_json_ctx_t *ctx, ngx_json_event_e event, state->current_key = *token; } else { - state->current_key.data = ngx_pstrdup(ctx->pool, token); + state->current_key.data = ngx_pnalloc(ctx->pool, token->len); if (state->current_key.data == NULL) { return NGX_ERROR; } state->current_key.len = token->len; - if (ngx_json_unescape_string(&state->current_key) != NGX_OK) { + if (ngx_json_unescape_string(&state->current_key, token) != NGX_OK) + { return NGX_ERROR; } } @@ -904,17 +907,25 @@ ngx_http_json_store(ngx_http_json_state_t *state, ngx_http_json_node_t *node, val.len = 0; val.data = (u_char *) ""; - } else { - val.data = ngx_pstrdup(state->r->pool, value); + } else if (unescape) { + val.data = ngx_pnalloc(state->r->pool, value->len); if (val.data == NULL) { return NGX_ERROR; } val.len = value->len; - if (unescape && ngx_json_unescape_string(&val) != NGX_OK) { + if (ngx_json_unescape_string(&val, value) != NGX_OK) { return NGX_ERROR; } + + } else { + val.data = ngx_pstrdup(state->r->pool, value); + if (val.data == NULL) { + return NGX_ERROR; + } + + val.len = value->len; } for (i = 0; i < node->ndests; i++) { -- 2.47.3