> From: Bruce Richardson [mailto:bruce.richard...@intel.com] > Sent: Thursday, 23 June 2022 18.43 > > For string values returned from telemetry, escape any values that > cannot > normally appear in a json string. According to the json spec[1], the > characters than need to be handled are control chars (char value < > 0x20) > and '"' and '\' characters.
Correct. Other chars are optional to escape. > > To handle this, we replace the snprintf call with a separate string > copying and encapsulation routine which checks each character as it > copies it to the final array. > > [1] https://www.rfc-editor.org/rfc/rfc8259.txt > > Signed-off-by: Bruce Richardson <bruce.richard...@intel.com> > --- > lib/telemetry/telemetry_json.h | 48 +++++++++++++++++++++++++++++++++- > 1 file changed, 47 insertions(+), 1 deletion(-) > > diff --git a/lib/telemetry/telemetry_json.h > b/lib/telemetry/telemetry_json.h > index db70690274..13df5d07e3 100644 > --- a/lib/telemetry/telemetry_json.h > +++ b/lib/telemetry/telemetry_json.h > @@ -44,6 +44,52 @@ __json_snprintf(char *buf, const int len, const char > *format, ...) > return 0; /* nothing written or modified */ > } > > +static const char control_chars[0x20] = { > + ['\n'] = 'n', > + ['\r'] = 'r', > + ['\t'] = 't', > +}; > + > +/** > + * @internal > + * Does the same as __json_snprintf(buf, len, "\"%s\"", str) > + * except that it does proper escaping as necessary. > + * Drops any invalid characters we don't support > + */ > +static inline int > +__json_format_str(char *buf, const int len, const char *str) > +{ > + char tmp[len]; > + int tmpidx = 0; > + > + tmp[tmpidx++] = '"'; > + while (*str != '\0') { > + if (*str < (int)RTE_DIM(control_chars)) { I would prefer the more explicit 0x20, directly copied from the RFC. RTE_DIM(control_chars) hints that it could change. > + int idx = *str; /* compilers don't like char type as > index */ > + if (control_chars[idx] != 0) { > + tmp[tmpidx++] = '\\'; > + tmp[tmpidx++] = control_chars[idx]; > + } Consider support for other control characters: + else { + tmp[tmpidx++] = '\\'; + tmp[tmpidx++] = 'u'; + tmp[tmpidx++] = '0'; + tmp[tmpidx++] = '0'; + tmp[tmpidx++] = hexchar(idx >> 4); + tmp[tmpidx++] = hexchar(idx & 0xf); + } Or just drop them, as you mention in the function's description. > + } else if (*str == '"' || *str == '\\') { > + tmp[tmpidx++] = '\\'; > + tmp[tmpidx++] = *str; > + } else > + tmp[tmpidx++] = *str; > + /* we always need space for closing quote and null > character. > + * Ensuring at least two free characters also means we can > always take an > + * escaped character like "\n" without overflowing > + */ > + if (tmpidx > len - 2) If supporting the \u00XX encoding, you need to reserve more than 2 characters here and in related code. > + return 0; > + str++; > + } > + tmp[tmpidx++] = '"'; > + tmp[tmpidx] = '\0'; > + > + strcpy(buf, tmp); > + return tmpidx; > +} > + > /* Copies an empty array into the provided buffer. */ > static inline int > rte_tel_json_empty_array(char *buf, const int len, const int used) > @@ -62,7 +108,7 @@ rte_tel_json_empty_obj(char *buf, const int len, > const int used) > static inline int > rte_tel_json_str(char *buf, const int len, const int used, const char > *str) > { > - return used + __json_snprintf(buf + used, len - used, "\"%s\"", > str); > + return used + __json_format_str(buf + used, len - used, str); > } > > /* Appends a string into the JSON array in the provided buffer. */ > -- > 2.34.1 >