]> git.kaiwu.me - nginx.git/commitdiff
JSON: modified ngx_json_unescape_string() to unescape into a new buffer
authorEvgeny Shirykalov <e.shirykalov@f5.com>
Wed, 30 Sep 2026 16:52:19 +0000 (09:52 -0700)
committerAleksei Bavshin <a.bavshin@f5.com>
Fri, 16 Oct 2026 16:42:01 +0000 (09:42 -0700)
src/core/ngx_json_unescape.c
src/core/ngx_json_unescape.h
src/http/modules/ngx_http_json_module.c

index a828780347caccc2283cb4e15cefd9471a3b29a2..36097be46b3c3fa586277446471535865259e4e2 100644 (file)
@@ -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;
 }
index 8fb0f54b0b2613f8c7e591542b9f4a7795ee1bc0..62ed32d274f4c4a8d4dd3da3163a1675b42f3fb2 100644 (file)
 
 
 /*
- * 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);
 
 
index 78099a43de56468631c77a879dd586e7c9e9a806..57f106c6cdefa69794d697f1e58d538d7e5c64f7 100644 (file)
@@ -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++) {