MINOR: log: simplify quotes handling in sess_build_logline()

quotes building for some log formats is directly performed under each
switch case statement so it would become painful to add other conditions
to prevent the quotes from being generated when it's not supported by the
the data encoding format for instance (ie: JSON).

Let's centralize and simplify quotes handling by adding LOGQUOTE_START()
and LOGQUOTE_END() helper macros. If a quotation is started and not
explicitly ended, it will be automatically ended at the end of the current
logformat node:

LOGQUOTE_START() sets 'quote' variable to 1, this way LOGQUOTE_END() only
prints the ending quote when needed. LOGQUOTE_END() is systematically
called after each node switch-case (after each value). LOGQUOTE_START()
does nothing if LOG_OPT_QUOTE isn't set, so does LOGQUOTE_END().

Some rare cases such as %hsl (list of captured headers) required special
handling: in this case multiple quoted texts are generated for the same
field value so explicit LOGQUOTE_START() + LOGQUOTE_END() combination was
needed.
This commit is contained in:
Aurelien DARRAGON 2024-01-10 19:14:25 +01:00
parent c6a7138420
commit a2fc40bc28

View File

@ -2518,6 +2518,23 @@ const char sess_set_cookie[8] = "NPDIRU67"; /* No set-cookie, Set-cookie found a
} \ } \
} while(0) } while(0)
/* start quoting the upcoming text if quoting is enabled. The final quote
* will automatically be added (because quote is set to 1).
*/
#define LOGQUOTE_START() do { \
if (tmp->options & LOG_OPT_QUOTE) { \
LOGCHAR('"'); \
quote = 1; \
} \
} while (0)
/* properly finish a quotation that was started using LOGQUOTE_START */
#define LOGQUOTE_END() do { \
if (quote) { \
LOGCHAR('"'); \
quote = 0; \
} \
} while (0)
/* Initializes some log data at boot */ /* Initializes some log data at boot */
static void init_log() static void init_log()
@ -2772,6 +2789,7 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t
const char *src = NULL; const char *src = NULL;
struct sample *key; struct sample *key;
const struct buffer empty = { }; const struct buffer empty = { };
int quote = 0; /* inside quoted string */
switch (tmp->type) { switch (tmp->type) {
case LOG_FMT_SEPARATOR: case LOG_FMT_SEPARATOR:
@ -3009,8 +3027,7 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t
case LOG_FMT_FRONTEND_XPRT: // %ft case LOG_FMT_FRONTEND_XPRT: // %ft
src = fe->id; src = fe->id;
if (tmp->options & LOG_OPT_QUOTE) LOGQUOTE_START();
LOGCHAR('"');
iret = strlcpy2(tmplog, src, dst + maxsize - tmplog); iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
if (iret == 0) if (iret == 0)
goto out; goto out;
@ -3019,8 +3036,6 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t
/* sess->listener may be undefined if the session's owner is a health-check */ /* sess->listener may be undefined if the session's owner is a health-check */
if (sess->listener && sess->listener->bind_conf->xprt->get_ssl_sock_ctx) if (sess->listener && sess->listener->bind_conf->xprt->get_ssl_sock_ctx)
LOGCHAR('~'); LOGCHAR('~');
if (tmp->options & LOG_OPT_QUOTE)
LOGCHAR('"');
break; break;
#ifdef USE_OPENSSL #ifdef USE_OPENSSL
case LOG_FMT_SSL_CIPHER: // %sslc case LOG_FMT_SSL_CIPHER: // %sslc
@ -3292,8 +3307,7 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t
case LOG_FMT_HDRREQUEST: // %hr case LOG_FMT_HDRREQUEST: // %hr
/* request header */ /* request header */
if (fe->nb_req_cap && s && s->req_cap) { if (fe->nb_req_cap && s && s->req_cap) {
if (tmp->options & LOG_OPT_QUOTE) LOGQUOTE_START();
LOGCHAR('"');
LOGCHAR('{'); LOGCHAR('{');
for (hdr = 0; hdr < fe->nb_req_cap; hdr++) { for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
if (hdr) if (hdr)
@ -3307,8 +3321,6 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t
} }
} }
LOGCHAR('}'); LOGCHAR('}');
if (tmp->options & LOG_OPT_QUOTE)
LOGCHAR('"');
} }
break; break;
@ -3318,8 +3330,7 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t
for (hdr = 0; hdr < fe->nb_req_cap; hdr++) { for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
if (hdr > 0) if (hdr > 0)
LOGCHAR(' '); LOGCHAR(' ');
if (tmp->options & LOG_OPT_QUOTE) LOGQUOTE_START();
LOGCHAR('"');
if (s->req_cap[hdr] != NULL) { if (s->req_cap[hdr] != NULL) {
ret = lf_encode_string(tmplog, dst + maxsize, ret = lf_encode_string(tmplog, dst + maxsize,
'#', hdr_encode_map, s->req_cap[hdr], tmp); '#', hdr_encode_map, s->req_cap[hdr], tmp);
@ -3328,8 +3339,10 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t
tmplog = ret; tmplog = ret;
} else if (!(tmp->options & LOG_OPT_QUOTE)) } else if (!(tmp->options & LOG_OPT_QUOTE))
LOGCHAR('-'); LOGCHAR('-');
if (tmp->options & LOG_OPT_QUOTE) /* Manually end quotation as we're emitting multiple
LOGCHAR('"'); * quoted texts at once
*/
LOGQUOTE_END();
} }
} }
break; break;
@ -3338,8 +3351,7 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t
case LOG_FMT_HDRRESPONS: // %hs case LOG_FMT_HDRRESPONS: // %hs
/* response header */ /* response header */
if (fe->nb_rsp_cap && s && s->res_cap) { if (fe->nb_rsp_cap && s && s->res_cap) {
if (tmp->options & LOG_OPT_QUOTE) LOGQUOTE_START();
LOGCHAR('"');
LOGCHAR('{'); LOGCHAR('{');
for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) { for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
if (hdr) if (hdr)
@ -3353,8 +3365,6 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t
} }
} }
LOGCHAR('}'); LOGCHAR('}');
if (tmp->options & LOG_OPT_QUOTE)
LOGCHAR('"');
} }
break; break;
@ -3364,8 +3374,7 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t
for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) { for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
if (hdr > 0) if (hdr > 0)
LOGCHAR(' '); LOGCHAR(' ');
if (tmp->options & LOG_OPT_QUOTE) LOGQUOTE_START();
LOGCHAR('"');
if (s->res_cap[hdr] != NULL) { if (s->res_cap[hdr] != NULL) {
ret = lf_encode_string(tmplog, dst + maxsize, ret = lf_encode_string(tmplog, dst + maxsize,
'#', hdr_encode_map, s->res_cap[hdr], tmp); '#', hdr_encode_map, s->res_cap[hdr], tmp);
@ -3374,31 +3383,29 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t
tmplog = ret; tmplog = ret;
} else if (!(tmp->options & LOG_OPT_QUOTE)) } else if (!(tmp->options & LOG_OPT_QUOTE))
LOGCHAR('-'); LOGCHAR('-');
if (tmp->options & LOG_OPT_QUOTE) /* Manually end quotation as we're emitting multiple
LOGCHAR('"'); * quoted texts at once
*/
LOGQUOTE_END();
} }
} }
break; break;
case LOG_FMT_REQ: // %r case LOG_FMT_REQ: // %r
/* Request */ /* Request */
if (tmp->options & LOG_OPT_QUOTE) LOGQUOTE_START();
LOGCHAR('"');
uri = txn && txn->uri ? txn->uri : "<BADREQ>"; uri = txn && txn->uri ? txn->uri : "<BADREQ>";
ret = lf_encode_string(tmplog, dst + maxsize, ret = lf_encode_string(tmplog, dst + maxsize,
'#', url_encode_map, uri, tmp); '#', url_encode_map, uri, tmp);
if (ret == NULL || *ret != '\0') if (ret == NULL || *ret != '\0')
goto out; goto out;
tmplog = ret; tmplog = ret;
if (tmp->options & LOG_OPT_QUOTE)
LOGCHAR('"');
break; break;
case LOG_FMT_HTTP_PATH: // %HP case LOG_FMT_HTTP_PATH: // %HP
uri = txn && txn->uri ? txn->uri : "<BADREQ>"; uri = txn && txn->uri ? txn->uri : "<BADREQ>";
if (tmp->options & LOG_OPT_QUOTE) LOGQUOTE_START();
LOGCHAR('"');
end = uri + strlen(uri); end = uri + strlen(uri);
// look for the first whitespace character // look for the first whitespace character
@ -3428,16 +3435,13 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t
goto out; goto out;
tmplog = ret; tmplog = ret;
if (tmp->options & LOG_OPT_QUOTE)
LOGCHAR('"');
break; break;
case LOG_FMT_HTTP_PATH_ONLY: // %HPO case LOG_FMT_HTTP_PATH_ONLY: // %HPO
uri = txn && txn->uri ? txn->uri : "<BADREQ>"; uri = txn && txn->uri ? txn->uri : "<BADREQ>";
if (tmp->options & LOG_OPT_QUOTE) LOGQUOTE_START();
LOGCHAR('"');
end = uri + strlen(uri); end = uri + strlen(uri);
@ -3473,14 +3477,11 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t
goto out; goto out;
tmplog = ret; tmplog = ret;
if (tmp->options & LOG_OPT_QUOTE)
LOGCHAR('"');
break; break;
case LOG_FMT_HTTP_QUERY: // %HQ case LOG_FMT_HTTP_QUERY: // %HQ
if (tmp->options & LOG_OPT_QUOTE) LOGQUOTE_START();
LOGCHAR('"');
if (!txn || !txn->uri) { if (!txn || !txn->uri) {
chunk.area = "<BADREQ>"; chunk.area = "<BADREQ>";
@ -3506,16 +3507,13 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t
goto out; goto out;
tmplog = ret; tmplog = ret;
if (tmp->options & LOG_OPT_QUOTE)
LOGCHAR('"');
break; break;
case LOG_FMT_HTTP_URI: // %HU case LOG_FMT_HTTP_URI: // %HU
uri = txn && txn->uri ? txn->uri : "<BADREQ>"; uri = txn && txn->uri ? txn->uri : "<BADREQ>";
if (tmp->options & LOG_OPT_QUOTE) LOGQUOTE_START();
LOGCHAR('"');
end = uri + strlen(uri); end = uri + strlen(uri);
// look for the first whitespace character // look for the first whitespace character
@ -3545,15 +3543,12 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t
goto out; goto out;
tmplog = ret; tmplog = ret;
if (tmp->options & LOG_OPT_QUOTE)
LOGCHAR('"');
break; break;
case LOG_FMT_HTTP_METHOD: // %HM case LOG_FMT_HTTP_METHOD: // %HM
uri = txn && txn->uri ? txn->uri : "<BADREQ>"; uri = txn && txn->uri ? txn->uri : "<BADREQ>";
if (tmp->options & LOG_OPT_QUOTE) LOGQUOTE_START();
LOGCHAR('"');
end = uri + strlen(uri); end = uri + strlen(uri);
// look for the first whitespace character // look for the first whitespace character
@ -3574,15 +3569,12 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t
goto out; goto out;
tmplog = ret; tmplog = ret;
if (tmp->options & LOG_OPT_QUOTE)
LOGCHAR('"');
break; break;
case LOG_FMT_HTTP_VERSION: // %HV case LOG_FMT_HTTP_VERSION: // %HV
uri = txn && txn->uri ? txn->uri : "<BADREQ>"; uri = txn && txn->uri ? txn->uri : "<BADREQ>";
if (tmp->options & LOG_OPT_QUOTE) LOGQUOTE_START();
LOGCHAR('"');
end = uri + strlen(uri); end = uri + strlen(uri);
// look for the first whitespace character // look for the first whitespace character
@ -3618,8 +3610,6 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t
goto out; goto out;
tmplog = ret; tmplog = ret;
if (tmp->options & LOG_OPT_QUOTE)
LOGCHAR('"');
break; break;
@ -3687,6 +3677,11 @@ int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t
} }
if (tmp->type != LOG_FMT_SEPARATOR) if (tmp->type != LOG_FMT_SEPARATOR)
last_isspace = 0; // not a separator, hence not a space last_isspace = 0; // not a separator, hence not a space
/* if quotation was started for the current node data, we need
* to finish the quote
*/
LOGQUOTE_END();
} }
out: out: