diff --git a/include/haproxy/tools.h b/include/haproxy/tools.h index f181a7601..f84f02d7d 100644 --- a/include/haproxy/tools.h +++ b/include/haproxy/tools.h @@ -466,6 +466,13 @@ char *escape_string(char *start, char *stop, const char escape, const long *map, const char *string, const char *string_stop); +/* + * Appends a quoted and escaped string to a chunk buffer. The string is + * enclosed in double quotes and special characters are escaped with backslash. + * Returns 0 on success, -1 if the buffer is too small (output is rolled back). + */ +int chunk_escape_string(struct buffer *chunk, const char *str, size_t len); + /* Below are RFC8949 compliant cbor encode helper functions, see source * file for functions descriptions */ diff --git a/src/tools.c b/src/tools.c index 460a34e18..9a4e1bf68 100644 --- a/src/tools.c +++ b/src/tools.c @@ -2129,6 +2129,60 @@ char *escape_string(char *start, char *stop, return NULL; } +/* + * Appends a quoted and escaped string to a chunk buffer. The string is + * enclosed in double quotes and special characters are escaped with backslash: + * ", \, \r, \n, \b, \0 + * Returns 0 on success, -1 if the buffer is too small (output is rolled back). + */ +int chunk_escape_string(struct buffer *chunk, const char *str, size_t len) +{ + size_t initial_data = chunk->data; + size_t i; + + /* Opening quote */ + if (chunk->data + 1 >= chunk->size) + return -1; + chunk->area[chunk->data++] = '"'; + + /* Escape and append each character */ + for (i = 0; i < len; i++) { + unsigned char c = str[i]; + const char *esc = NULL; + + if (c == '"') esc = "\\\""; + else if (c == '\\') esc = "\\\\"; + else if (c == '\r') esc = "\\r"; + else if (c == '\n') esc = "\\n"; + else if (c == '\b') esc = "\\b"; + else if (c == '\0') esc = "\\0"; + + if (esc) { + if (chunk->data + 2 >= chunk->size) { + chunk->data = initial_data; + return -1; + } + chunk->area[chunk->data++] = esc[0]; + chunk->area[chunk->data++] = esc[1]; + } else { + if (chunk->data + 1 >= chunk->size) { + chunk->data = initial_data; + return -1; + } + chunk->area[chunk->data++] = c; + } + } + + /* Closing quote */ + if (chunk->data + 1 >= chunk->size) { + chunk->data = initial_data; + return -1; + } + chunk->area[chunk->data++] = '"'; + + return 0; +} + /* CBOR helper to encode an uint64 value with prefix (3bits MAJOR type) * according to RFC8949 *