diff --git a/include/types/log.h b/include/types/log.h index 66b418dec9..8ee8d7c644 100644 --- a/include/types/log.h +++ b/include/types/log.h @@ -125,6 +125,7 @@ struct logformat_node { #define LOG_OPT_QUOTE 0x00000004 #define LOG_OPT_REQ_CAP 0x00000008 #define LOG_OPT_RES_CAP 0x00000010 +#define LOG_OPT_HTTP 0x00000020 /* Fields that need to be extracted from the incoming connection or request for diff --git a/src/cfgparse.c b/src/cfgparse.c index 5589ec03f7..5cbb9e2a6b 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -7085,7 +7085,7 @@ out_uri_auth_compat: curproxy->conf.args.ctx = ARGC_UIF; curproxy->conf.args.file = curproxy->conf.uif_file; curproxy->conf.args.line = curproxy->conf.uif_line; - parse_logformat_string(curproxy->conf.uniqueid_format_string, curproxy, &curproxy->format_unique_id, 0, + parse_logformat_string(curproxy->conf.uniqueid_format_string, curproxy, &curproxy->format_unique_id, LOG_OPT_HTTP, (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR); curproxy->conf.args.file = NULL; curproxy->conf.args.line = 0; diff --git a/src/log.c b/src/log.c index 3ab40f9c27..f39168a080 100644 --- a/src/log.c +++ b/src/log.c @@ -885,6 +885,7 @@ void __send_log(struct proxy *p, int level, char *message, size_t size) extern fd_set hdr_encode_map[]; extern fd_set url_encode_map[]; +extern fd_set http_encode_map[]; const char sess_cookie[8] = "NIDVEOU7"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie, Expired cookie, Old cookie, Unused, unknown */ @@ -940,6 +941,7 @@ int build_logline(struct session *s, char *dst, size_t maxsize, struct list *lis struct connection *conn; const char *src = NULL; struct sample *key; + const struct chunk empty = { NULL, 0, 0 }; switch (tmp->type) { case LOG_FMT_SEPARATOR: @@ -964,7 +966,11 @@ int build_logline(struct session *s, char *dst, size_t maxsize, struct list *lis key = sample_fetch_string(be, s, txn, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, tmp->expr); if (!key && (tmp->options & LOG_OPT_RES_CAP)) key = sample_fetch_string(be, s, txn, SMP_OPT_DIR_RES|SMP_OPT_FINAL, tmp->expr); - ret = lf_text_len(tmplog, key ? key->data.str.str : NULL, key ? key->data.str.len : 0, dst + maxsize - tmplog, tmp); + if (tmp->options & LOG_OPT_HTTP) + ret = encode_chunk(tmplog, dst + maxsize, + '%', http_encode_map, key ? &key->data.str : &empty); + else + ret = lf_text_len(tmplog, key ? key->data.str.str : NULL, key ? key->data.str.len : 0, dst + maxsize - tmplog, tmp); if (ret == 0) goto out; tmplog = ret; diff --git a/src/proto_http.c b/src/proto_http.c index c0be289897..0c6a6233f7 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -235,6 +235,7 @@ static struct hdr_ctx static_hdr_ctx; */ fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))]; fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))]; +fd_set http_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))]; #else #error "Check if your OS uses bitfields for fd_sets" @@ -263,6 +264,7 @@ void init_proto_http() */ memset(hdr_encode_map, 0, sizeof(hdr_encode_map)); memset(url_encode_map, 0, sizeof(url_encode_map)); + memset(http_encode_map, 0, sizeof(url_encode_map)); for (i = 0; i < 32; i++) { FD_SET(i, hdr_encode_map); FD_SET(i, url_encode_map); @@ -284,6 +286,32 @@ void init_proto_http() tmp++; } + /* initialize the http header encoding map. The draft httpbis define the + * header content as: + * + * HTTP-message = start-line + * *( header-field CRLF ) + * CRLF + * [ message-body ] + * header-field = field-name ":" OWS field-value OWS + * field-value = *( field-content / obs-fold ) + * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] + * obs-fold = CRLF 1*( SP / HTAB ) + * field-vchar = VCHAR / obs-text + * VCHAR = %x21-7E + * obs-text = %x80-FF + * + * All the chars are encoded except "VCHAR", "obs-text", SP and HTAB. + * The encoded chars are form 0x00 to 0x08, 0x0a to 0x1f and 0x7f. The + * "obs-fold" is volontary forgotten because haproxy remove this. + */ + memset(http_encode_map, 0, sizeof(http_encode_map)); + for (i = 0x00; i <= 0x08; i++) + FD_SET(i, http_encode_map); + for (i = 0x0a; i <= 0x1f; i++) + FD_SET(i, http_encode_map); + FD_SET(0x7f, http_encode_map); + /* memory allocations */ pool2_requri = create_pool("requri", REQURI_LEN, MEM_F_SHARED); pool2_uniqueid = create_pool("uniqueid", UNIQUEID_LEN, MEM_F_SHARED); @@ -8459,7 +8487,7 @@ struct http_req_rule *parse_http_req_cond(const char **args, const char *file, i LIST_INIT(&rule->arg.hdr_add.fmt); proxy->conf.args.ctx = ARGC_HRQ; - parse_logformat_string(args[cur_arg + 1], proxy, &rule->arg.hdr_add.fmt, 0, + parse_logformat_string(args[cur_arg + 1], proxy, &rule->arg.hdr_add.fmt, LOG_OPT_HTTP, (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR); free(proxy->conf.lfs_file); proxy->conf.lfs_file = strdup(proxy->conf.args.file); @@ -8630,7 +8658,7 @@ struct http_res_rule *parse_http_res_cond(const char **args, const char *file, i LIST_INIT(&rule->arg.hdr_add.fmt); proxy->conf.args.ctx = ARGC_HRS; - parse_logformat_string(args[cur_arg + 1], proxy, &rule->arg.hdr_add.fmt, 0, + parse_logformat_string(args[cur_arg + 1], proxy, &rule->arg.hdr_add.fmt, LOG_OPT_HTTP, (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR); free(proxy->conf.lfs_file); proxy->conf.lfs_file = strdup(proxy->conf.args.file); @@ -8786,7 +8814,7 @@ struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, st */ proxy->conf.args.ctx = ARGC_RDR; if (!(type == REDIRECT_TYPE_PREFIX && destination[0] == '/' && destination[1] == '\0')) { - parse_logformat_string(destination, curproxy, &rule->rdr_fmt, 0, + parse_logformat_string(destination, curproxy, &rule->rdr_fmt, LOG_OPT_HTTP, (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR); free(curproxy->conf.lfs_file); curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);