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; 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 '"\]' * When using the +E log format option, it will try to escape '"\]'
* characters with '\' as prefix. The same prefix should not be used as * 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 * 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 escape, const long *map,
const char *string, const char *bytes, const char *bytes_stop,
struct logformat_node *node) struct logformat_node *node)
{ {
if (node->options & LOG_OPT_ESC) { char *ret;
if (start < stop) { char *(*encode_byte)(char *start, char *stop,
stop--; /* reserve one byte for the final '\0' */ const char *byte,
while (start < stop && *string != '\0') { const char escape, const long *map,
if (!ha_bit_test((unsigned char)(*string), map)) { struct logformat_node *node);
if (!ha_bit_test((unsigned char)(*string), rfc5424_escape_map))
*start++ = *string; if (node->options & LOG_OPT_ESC)
else { encode_byte = _lf_rfc5424_escape_byte;
if (start + 2 >= stop) else
break; encode_byte = _lf_map_escape_byte;
*start++ = '\\';
*start++ = *string; if (start < stop) {
} stop--; /* reserve one byte for the final '\0' */
}
else { /* we have 2 distinct loops to keep checks outside of the loop
if (start + 3 >= stop) * for better performance
break; */
*start++ = escape; if (bytes && !bytes_stop) {
*start++ = hextab[(*string >> 4) & 15]; while (start < stop && *bytes != '\0') {
*start++ = hextab[*string & 15]; ret = encode_byte(start, stop, bytes, escape, map, node);
} if (ret == NULL)
string++; 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;
} }
} *start = '\0';
else { return start;
return encode_string(start, stop, escape, map, string);
} }
return NULL; 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. * 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, static char *lf_encode_chunk(char *start, char *stop,
const char escape, const long *map, const char escape, const long *map,
const struct buffer *chunk, const struct buffer *chunk,
struct logformat_node *node) struct logformat_node *node)
{ {
char *str, *end; return _lf_encode_bytes(start, stop, escape, map,
chunk->area, chunk->area + chunk->data,
if (node->options & LOG_OPT_ESC) { node);
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;
} }
/* /*