]> git.kaiwu.me - njs.git/commitdiff
Fixed njs_json_append_string().
authorDmitry Volyntsev <xeioex@nginx.com>
Tue, 18 Feb 2020 15:42:37 +0000 (18:42 +0300)
committerDmitry Volyntsev <xeioex@nginx.com>
Tue, 18 Feb 2020 15:42:37 +0000 (18:42 +0300)
src/njs_json.c

index 9e8e49a5b978c98a30dc5c7a886aaabdab7c66d9..7fabba50babb8785e1e0c7a0299708743cde3607 100644 (file)
@@ -1545,37 +1545,50 @@ njs_json_append_value(njs_chb_t *chain, const njs_value_t *value)
 static void
 njs_json_append_string(njs_chb_t *chain, const njs_value_t *value, char quote)
 {
+    size_t             size;
     u_char             c, *dst, *dst_end;
-    size_t             length;
+    njs_bool_t         utf8;
     const u_char       *p, *end;
-    njs_string_prop_t  str;
+    njs_string_prop_t  string;
 
-    static char   hex2char[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
-                                   '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+    static char  hex2char[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
+                                  '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
 
-    (void) njs_string_prop(&str, value);
+    (void) njs_string_prop(&string, value);
 
-    p = str.start;
-    end = p + str.size;
-    length = str.length;
+    p = string.start;
+    end = p + string.size;
+    utf8 = (string.length != 0 && string.length != string.size);
 
-    dst = njs_chb_reserve(chain, length + 2);
+    size = njs_max(string.size + 2, 7);
+    dst = njs_chb_reserve(chain, string.size + 2);
     if (njs_slow_path(dst == NULL)) {
         return;
     }
 
-    dst_end = dst + length + 2;
+    dst_end = dst + size;
 
     *dst++ = quote;
+    njs_chb_written(chain, 1);
 
     while (p < end) {
+        if (njs_slow_path(dst_end <= dst + njs_length("\\uXXXX"))) {
+            size = njs_max(end - p + 1, 6);
+            dst = njs_chb_reserve(chain, size);
+            if (njs_slow_path(dst == NULL)) {
+                return;
+            }
 
-        if (*p < ' '
-            || *p == '\\'
-            || (*p == '\"' && quote == '\"'))
+            dst_end = dst + size;
+        }
+
+        if (njs_slow_path(*p < ' '
+                          || *p == '\\'
+                          || (*p == '\"' && quote == '\"')))
         {
             c = (u_char) *p++;
             *dst++ = '\\';
+            njs_chb_written(chain, 2);
 
             switch (c) {
             case '\\':
@@ -1605,43 +1618,23 @@ njs_json_append_string(njs_chb_t *chain, const njs_value_t *value, char quote)
                 *dst++ = '0';
                 *dst++ = hex2char[(c & 0xf0) >> 4];
                 *dst++ = hex2char[c & 0x0f];
+                njs_chb_written(chain, 4);
             }
-        }
-
-        /*
-         * Control characters less than space are encoded using 6 bytes
-         * "\uXXXX".  Checking there is at least 6 bytes of destination storage
-         * space.
-         */
-
-        while (p < end && (dst_end - dst) > 6) {
-            if (*p < ' ' || (*p == '\"' && quote == '\"') || *p == '\\') {
-                break;
-            }
-
-            if (length != 0) {
-                /* UTF-8 or ASCII string. */
-                dst = njs_utf8_copy(dst, &p, end);
 
-            } else {
-                /* Byte string. */
-                *dst++ = *p++;
-            }
+            continue;
         }
 
-        if (dst_end - dst <= 6) {
-            njs_chb_written(chain, dst - chain->last->pos);
-
-            dst = njs_chb_reserve(chain, 64);
-            if (njs_slow_path(dst == NULL)) {
-                return;
-            }
+        if (utf8) {
+            /* UTF-8 string. */
+            dst = njs_utf8_copy(dst, &p, end);
 
-            dst_end = dst + 64;
+        } else {
+            /* Byte or ASCII string. */
+            *dst++ = *p++;
         }
-    }
 
-    njs_chb_written(chain, dst - chain->last->pos);
+        njs_chb_written(chain, dst - chain->last->pos);
+    }
 
     njs_chb_append(chain, &quote, 1);
 }