diff --git a/src/sentry_json.c b/src/sentry_json.c index 316868256..cf02c7f1b 100644 --- a/src/sentry_json.c +++ b/src/sentry_json.c @@ -101,13 +101,49 @@ write_str(sentry_jsonwriter_t *jw, const char *str) sentry__stringbuilder_append(jw->sb, str); } +// The Lookup table and algorithm below are adapted from: +// https://github.com/serde-rs/json/blob/977975ee650829a1f3c232cd5f641a7011bdce1d/src/ser.rs#L2079-L2145 + +// Lookup table of escape sequences. `0` means no need to escape, and `1` means +// that escaping is needed. +static unsigned char needs_escaping[256] = { + // 1 2 3 4 5 6 7 8 9 A B C D E F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // 5 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // F +}; + static void write_json_str(sentry_jsonwriter_t *jw, const char *str) { // using unsigned here because utf-8 is > 127 :-) const unsigned char *ptr = (const unsigned char *)str; write_char(jw, '"'); + + const unsigned char *start = ptr; for (; *ptr; ptr++) { + if (!needs_escaping[*ptr]) { + continue; + } + + size_t len = ptr - start; + if (len) { + sentry__stringbuilder_append_buf(jw->sb, (const char *)start, len); + } + switch (*ptr) { case '\\': write_str(jw, "\\\\"); @@ -142,7 +178,15 @@ write_json_str(sentry_jsonwriter_t *jw, const char *str) write_char(jw, *ptr); } } + + start = ptr + 1; } + + size_t len = ptr - start; + if (len) { + sentry__stringbuilder_append_buf(jw->sb, (const char *)start, len); + } + write_char(jw, '"'); } diff --git a/src/sentry_string.c b/src/sentry_string.c index a1581c752..f745f6ad7 100644 --- a/src/sentry_string.c +++ b/src/sentry_string.c @@ -39,49 +39,6 @@ sentry__stringbuilder_reserve(sentry_stringbuilder_t *sb, size_t len) return &sb->buf[sb->len]; } -static int -append(sentry_stringbuilder_t *sb, const char *s, size_t len) -{ - char *buf = sentry__stringbuilder_reserve(sb, len + 1); - if (!buf) { - return 1; - } - memcpy(buf, s, len); - sb->len += len; - - // make sure we're always zero terminated - sb->buf[sb->len] = '\0'; - - return 0; -} - -int -sentry__stringbuilder_append(sentry_stringbuilder_t *sb, const char *s) -{ - return append(sb, s, strlen(s)); -} - -int -sentry__stringbuilder_append_buf( - sentry_stringbuilder_t *sb, const char *s, size_t len) -{ - return append(sb, s, len); -} - -int -sentry__stringbuilder_append_char(sentry_stringbuilder_t *sb, char c) -{ - return append(sb, &c, 1); -} - -int -sentry__stringbuilder_append_char32(sentry_stringbuilder_t *sb, uint32_t c) -{ - char buf[4]; - size_t len = sentry__unichar_to_utf8(c, buf); - return sentry__stringbuilder_append_buf(sb, buf, len); -} - char * sentry_stringbuilder_take_string(sentry_stringbuilder_t *sb) { @@ -121,24 +78,6 @@ sentry__stringbuilder_set_len(sentry_stringbuilder_t *sb, size_t len) sb->len = len; } -char * -sentry__string_clone(const char *str) -{ - return str ? sentry__string_clonen(str, strlen(str)) : NULL; -} - -char * -sentry__string_clonen(const char *str, size_t n) -{ - size_t len = n + 1; - char *rv = sentry_malloc(len); - if (rv) { - memcpy(rv, str, n); - rv[n] = 0; - } - return rv; -} - #ifdef SENTRY_PLATFORM_WINDOWS char * sentry__string_from_wstr(const wchar_t *s) diff --git a/src/sentry_string.h b/src/sentry_string.h index feeff3678..255d55d17 100644 --- a/src/sentry_string.h +++ b/src/sentry_string.h @@ -22,25 +22,55 @@ typedef struct sentry_stringbuilder_s { void sentry__stringbuilder_init(sentry_stringbuilder_t *sb); /** - * Appends a zero terminated string to the builder. + * Resizes the stringbuilder buffer to make sure there is at least `len` bytes + * available at the end, and returns a pointer *to the reservation*. */ -int sentry__stringbuilder_append(sentry_stringbuilder_t *sb, const char *s); +char *sentry__stringbuilder_reserve(sentry_stringbuilder_t *sb, size_t len); /** * Appends a sized buffer. */ -int sentry__stringbuilder_append_buf( - sentry_stringbuilder_t *sb, const char *s, size_t len); +static inline int +sentry__stringbuilder_append_buf( + sentry_stringbuilder_t *sb, const char *s, size_t len) +{ + size_t needed = sb->len + len + 1; + char *buf = sb->buf; + if (!sb->buf || needed > sb->allocated) { + buf = sentry__stringbuilder_reserve(sb, len + 1); + if (!buf) { + return 1; + } + } else { + buf = buf + sb->len; + } + + memcpy(buf, s, len); + sb->len += len; + + // make sure we're always zero terminated + sb->buf[sb->len] = '\0'; + + return 0; +} /** - * Appends a single character. + * Appends a zero terminated string to the builder. */ -int sentry__stringbuilder_append_char(sentry_stringbuilder_t *sb, char c); +static inline int +sentry__stringbuilder_append(sentry_stringbuilder_t *sb, const char *s) +{ + return sentry__stringbuilder_append_buf(sb, s, strlen(s)); +} /** - * Appends a utf-32 character. + * Appends a single character. */ -int sentry__stringbuilder_append_char32(sentry_stringbuilder_t *sb, uint32_t c); +static inline int +sentry__stringbuilder_append_char(sentry_stringbuilder_t *sb, char c) +{ + return sentry__stringbuilder_append_buf(sb, &c, 1); +} /** * Appends an int64 value. @@ -73,12 +103,6 @@ void sentry__stringbuilder_cleanup(sentry_stringbuilder_t *sb); */ size_t sentry__stringbuilder_len(const sentry_stringbuilder_t *sb); -/** - * Resizes the stringbuilder buffer to make sure there is at least `len` bytes - * available at the end, and returns a pointer *to the reservation*. - */ -char *sentry__stringbuilder_reserve(sentry_stringbuilder_t *sb, size_t len); - /** * Sets the number of used bytes in the string builder, to be used together with * `sentry__stringbuilder_reserve` to avoid copying from an intermediate buffer. @@ -86,14 +110,28 @@ char *sentry__stringbuilder_reserve(sentry_stringbuilder_t *sb, size_t len); void sentry__stringbuilder_set_len(sentry_stringbuilder_t *sb, size_t len); /** - * Duplicates a zero terminated string. + * Duplicates a zero terminated string with a length limit. */ -char *sentry__string_clone(const char *str); +static inline char * +sentry__string_clonen(const char *str, size_t n) +{ + size_t len = n + 1; + char *rv = (char *)sentry_malloc(len); + if (rv) { + memcpy(rv, str, n); + rv[n] = 0; + } + return rv; +} /** - * Duplicates a zero terminated string with a length limit. + * Duplicates a zero terminated string. */ -char *sentry__string_clonen(const char *str, size_t n); +static inline char * +sentry__string_clone(const char *str) +{ + return str ? sentry__string_clonen(str, strlen(str)) : NULL; +} /** * Converts a string to lowercase. diff --git a/src/sentry_transport.c b/src/sentry_transport.c index 51f8e9b39..4ff909e03 100644 --- a/src/sentry_transport.c +++ b/src/sentry_transport.c @@ -3,6 +3,7 @@ #include "sentry_envelope.h" #include "sentry_options.h" #include "sentry_ratelimiter.h" +#include "sentry_string.h" #define ENVELOPE_MIME "application/x-sentry-envelope" // The headers we use are: `x-sentry-auth`, `content-type`, `content-length`