]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: log: merge lf_encode_string() and lf_encode_chunk() logic
authorAurelien DARRAGON <adarragon@haproxy.com>
Fri, 26 Apr 2024 11:53:15 +0000 (13:53 +0200)
committerAurelien DARRAGON <adarragon@haproxy.com>
Fri, 26 Apr 2024 16:39:31 +0000 (18:39 +0200)
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.

src/log.c

index f83c38ba2fcc9daca68d95b127f3e5462ae4c816..021cfe22bb7801334a35330eca8b82d20c864c67 100644 (file)
--- 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 <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);
 }
 
 /*