Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ref: Optimize JSON formatting (ISSUE-1379) #674

Merged
merged 4 commits into from
Jan 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions src/sentry_json.c
Original file line number Diff line number Diff line change
Expand Up @@ -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, "\\\\");
Expand Down Expand Up @@ -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, '"');
}

Expand Down
61 changes: 0 additions & 61 deletions src/sentry_string.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)
Expand Down
74 changes: 56 additions & 18 deletions src/sentry_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -73,27 +103,35 @@ 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.
*/
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.
Expand Down
1 change: 1 addition & 0 deletions src/sentry_transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down