Introduce json_do_string() a function that JSON escapes a string.
authorclaudio <claudio@openbsd.org>
Wed, 3 May 2023 07:56:05 +0000 (07:56 +0000)
committerclaudio <claudio@openbsd.org>
Wed, 3 May 2023 07:56:05 +0000 (07:56 +0000)
Implement json_do_printf() using json_do_string() and vasprintf().
json_do_string() only escapes the basic control chars (\b, \f, \n, \r and \t)
other control chars are considered an error. Also the forward slash is
not escaped since the JSON data is not embedded into HTML or XML.
With feedback from tb@ & millert@
OK tb@

usr.sbin/rpki-client/json.c
usr.sbin/rpki-client/json.h

index 6e06564..5d86072 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: json.c,v 1.1 2023/04/27 07:57:25 claudio Exp $ */
+/*     $OpenBSD: json.c,v 1.2 2023/05/03 07:56:05 claudio Exp $ */
 
 /*
  * Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org>
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <ctype.h>
 #include <err.h>
 #include <stdarg.h>
 #include <stdint.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 #include "json.h"
@@ -179,16 +181,58 @@ void
 json_do_printf(const char *name, const char *fmt, ...)
 {
        va_list ap;
+       char *str;
 
-       do_comma_indent();
+       va_start(ap, fmt);
+       if (!eb) {
+               if (vasprintf(&str, fmt, ap) == -1)
+                       errx(1, "json printf failed");
+               json_do_string(name, str);
+               free(str);
+       }
+       va_end(ap);
+}
 
+void
+json_do_string(const char *name, const char *v)
+{
+       unsigned char c;
+
+       do_comma_indent();
        do_name(name);
        if (!eb)
                eb = fprintf(jsonfh, "\"") < 0;
-       va_start(ap, fmt);
-       if (!eb)
-               eb = vfprintf(jsonfh, fmt, ap) < 0;
-       va_end(ap);
+       while ((c = *v++) != '\0' && !eb) {
+               /* skip escaping '/' since our use case does not require it */
+               switch(c) {
+               case '"':
+                       eb = fprintf(jsonfh, "\\\"") < 0;
+                       break;
+               case '\\':
+                       eb = fprintf(jsonfh, "\\\\") < 0;
+                       break;
+               case '\b':
+                       eb = fprintf(jsonfh, "\\b") < 0;
+                       break;
+               case '\f':
+                       eb = fprintf(jsonfh, "\\f") < 0;
+                       break;
+               case '\n':
+                       eb = fprintf(jsonfh, "\\n") < 0;
+                       break;
+               case '\r':
+                       eb = fprintf(jsonfh, "\\r") < 0;
+                       break;
+               case '\t':
+                       eb = fprintf(jsonfh, "\\t") < 0;
+                       break;
+               default:
+                       if (iscntrl(c))
+                               errx(1, "bad control character in string");
+                       eb = putc(c, jsonfh) == EOF;
+                       break;
+               }
+       }
        if (!eb)
                eb = fprintf(jsonfh, "\"") < 0;
 }
index bd7cbf2..5eb8bab 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: json.h,v 1.1 2023/04/27 07:57:25 claudio Exp $ */
+/*     $OpenBSD: json.h,v 1.2 2023/05/03 07:56:05 claudio Exp $ */
 
 /*
  * Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org>
@@ -26,6 +26,7 @@ void  json_do_object(const char *);
 void   json_do_end(void);
 void   json_do_printf(const char *, const char *, ...)
            __attribute__((__format__ (printf, 2, 3)));
+void   json_do_string(const char *, const char *);
 void   json_do_hexdump(const char *, void *, size_t);
 void   json_do_bool(const char *, int);
 void   json_do_uint(const char *, unsigned long long);