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.
This commit is contained in:
Aurelien DARRAGON 2024-04-26 13:53:15 +02:00
parent a1583ec7c7
commit f7cb384f1a

194
src/log.c
View File

@ -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 <escape>
*/
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 <escape> if found in <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_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 <escape> if found in <map> 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 <bytes> is processed until <bytes_stop>
* is reached. If <bytes_stop> is NULL, <bytes> 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
* <escape>.
*
* 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);
}
/*