From: Aurelien DARRAGON Date: Fri, 26 Apr 2024 11:53:15 +0000 (+0200) Subject: MINOR: log: merge lf_encode_string() and lf_encode_chunk() logic X-Git-Tag: v3.0-dev9~14 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f7cb384f1a34bda53d7d62da26f5ba864da723de;p=thirdparty%2Fhaproxy.git MINOR: log: merge lf_encode_string() and lf_encode_chunk() logic lf_encode_string() and lf_encode_chunk() function are pretty similar. The only difference is the stopping behavior, encode_chunk stops at a given position while encode_string stops when encountering '\0'. Moreover, both functions leverage tools.c encode helpers, but because of the LOG_OPT_ESC option, they reimplement those helpers with added logic. Instead of having to deal with code duplication which makes both functions harder to maintain, let's define a _lf_encode_bytes() helper function which satisfies lf_encode_string() and lf_encode_chunk() needs while keeping the function as simple as possible. _lf_encode_bytes() itself is made of multiple static inline helper functions, in the attempt to keep checks outside of core loop for better performance. --- diff --git a/src/log.c b/src/log.c index f83c38ba2f..021cfe22bb 100644 --- a/src/log.c +++ b/src/log.c @@ -1729,8 +1729,77 @@ int get_log_facility(const char *fac) return facility; } +/* helper function for _lf_encode_bytes() to escape a single byte + * with + */ +static inline char *_lf_escape_byte(char *start, char *stop, + char byte, const char escape) +{ + if (start + 3 >= stop) + return NULL; + *start++ = escape; + *start++ = hextab[(byte >> 4) & 15]; + *start++ = hextab[byte & 15]; + + return start; +} + +/* helper function for _lf_encode_bytes() to encode a single byte + * and escape it with if found in + * + * The function assumes that at least 1 byte is available for writing + * + * Returns the address of the last written byte on success, or NULL + * on error + */ +static inline char *_lf_map_escape_byte(char *start, char *stop, + const char *byte, + const char escape, const long *map, + struct logformat_node *node) +{ + if (!ha_bit_test((unsigned char)(*byte), map)) + *start++ = *byte; + else + start = _lf_escape_byte(start, stop, *byte, escape); + + return start; +} + +/* helper function for _lf_encode_bytes() to encode a single byte + * and escape it with if found in or escape it with + * '\' if found in rfc5424_escape_map + * + * The function assumes that at least 1 byte is available for writing + * + * Returns the address of the last written byte on success, or NULL + * on error + */ +static inline char *_lf_rfc5424_escape_byte(char *start, char *stop, + const char *byte, + const char escape, const long *map, + struct logformat_node *node) +{ + if (!ha_bit_test((unsigned char)(*byte), map)) { + if (!ha_bit_test((unsigned char)(*byte), rfc5424_escape_map)) + *start++ = *byte; + else { + if (start + 2 >= stop) + return NULL; + *start++ = '\\'; + *start++ = *byte; + } + } + else + start = _lf_escape_byte(start, stop, *byte, escape); + + return start; +} + /* - * Encode the string. + * helper for lf_encode_{string,chunk}: + * encode the input bytes, input is processed until + * is reached. If is NULL, is expected to be NULL + * terminated. * * When using the +E log format option, it will try to escape '"\]' * characters with '\' as prefix. The same prefix should not be used as @@ -1738,96 +1807,75 @@ int get_log_facility(const char *fac) * * Return the address of the \0 character, or NULL on error */ -static char *lf_encode_string(char *start, char *stop, +static char *_lf_encode_bytes(char *start, char *stop, const char escape, const long *map, - const char *string, + const char *bytes, const char *bytes_stop, struct logformat_node *node) { - if (node->options & LOG_OPT_ESC) { - if (start < stop) { - stop--; /* reserve one byte for the final '\0' */ - while (start < stop && *string != '\0') { - if (!ha_bit_test((unsigned char)(*string), map)) { - if (!ha_bit_test((unsigned char)(*string), rfc5424_escape_map)) - *start++ = *string; - else { - if (start + 2 >= stop) - break; - *start++ = '\\'; - *start++ = *string; - } - } - else { - if (start + 3 >= stop) - break; - *start++ = escape; - *start++ = hextab[(*string >> 4) & 15]; - *start++ = hextab[*string & 15]; - } - string++; + char *ret; + char *(*encode_byte)(char *start, char *stop, + const char *byte, + const char escape, const long *map, + struct logformat_node *node); + + if (node->options & LOG_OPT_ESC) + encode_byte = _lf_rfc5424_escape_byte; + else + encode_byte = _lf_map_escape_byte; + + if (start < stop) { + stop--; /* reserve one byte for the final '\0' */ + + /* we have 2 distinct loops to keep checks outside of the loop + * for better performance + */ + if (bytes && !bytes_stop) { + while (start < stop && *bytes != '\0') { + ret = encode_byte(start, stop, bytes, escape, map, node); + if (ret == NULL) + break; + start = ret; + bytes++; + } + } else if (bytes) { + while (start < stop && bytes < bytes_stop) { + ret = encode_byte(start, stop, bytes, escape, map, node); + if (ret == NULL) + break; + start = ret; + bytes++; } - *start = '\0'; - return start; } - } - else { - return encode_string(start, stop, escape, map, string); + *start = '\0'; + return start; } return NULL; } +/* + * Encode the string. + */ +static char *lf_encode_string(char *start, char *stop, + const char escape, const long *map, + const char *string, + struct logformat_node *node) +{ + return _lf_encode_bytes(start, stop, escape, map, + string, NULL, node); +} + /* * Encode the chunk. - * - * When using the +E log format option, it will try to escape '"\]' - * characters with '\' as prefix. The same prefix should not be used as - * . - * - * Return the address of the \0 character, or NULL on error */ static char *lf_encode_chunk(char *start, char *stop, const char escape, const long *map, const struct buffer *chunk, struct logformat_node *node) { - char *str, *end; - - if (node->options & LOG_OPT_ESC) { - if (start < stop) { - str = chunk->area; - end = chunk->area + chunk->data; - - stop--; /* reserve one byte for the final '\0' */ - while (start < stop && str < end) { - if (!ha_bit_test((unsigned char)(*str), map)) { - if (!ha_bit_test((unsigned char)(*str), rfc5424_escape_map)) - *start++ = *str; - else { - if (start + 2 >= stop) - break; - *start++ = '\\'; - *start++ = *str; - } - } - else { - if (start + 3 >= stop) - break; - *start++ = escape; - *start++ = hextab[(*str >> 4) & 15]; - *start++ = hextab[*str & 15]; - } - str++; - } - *start = '\0'; - return start; - } - } - else { - return encode_chunk(start, stop, escape, map, chunk); - } - - return NULL; + return _lf_encode_bytes(start, stop, escape, map, + chunk->area, chunk->area + chunk->data, + node); } /*