The attached patch implements a new append-header configuration directive. Currently we can modify the header with set-header or add-header, but we do not have a way to append to the header, and in some cases it is desirable.
The patch is against dev24. I have not tested if it cleanly applies to the most recent source, but I figured I'd wait for feedback on the possibility of it being accepted/fixups needed for it to happen before I do the work. -- Sasha Pachev Fast Running Blog. http://fastrunningblog.com Run. Blog. Improve. Repeat.
commit 9528c5834289026115f8700ba702caa3edc8a8ea Author: Sasha Pachev <[email protected]> Date: Wed May 7 14:50:17 2014 -0700 HTTP header append feature diff --git a/include/types/proto_http.h b/include/types/proto_http.h index a030fee..f1c55f6 100644 --- a/include/types/proto_http.h +++ b/include/types/proto_http.h @@ -247,6 +247,7 @@ enum { HTTP_REQ_ACT_ADD_HDR, HTTP_REQ_ACT_SET_HDR, HTTP_REQ_ACT_DEL_HDR, + HTTP_REQ_ACT_APPEND_HDR, HTTP_REQ_ACT_REDIR, HTTP_REQ_ACT_SET_NICE, HTTP_REQ_ACT_SET_LOGL, @@ -267,6 +268,7 @@ enum { HTTP_RES_ACT_ALLOW, HTTP_RES_ACT_DENY, HTTP_RES_ACT_ADD_HDR, + HTTP_RES_ACT_APPEND_HDR, HTTP_RES_ACT_SET_HDR, HTTP_RES_ACT_DEL_HDR, HTTP_RES_ACT_SET_NICE, diff --git a/src/proto_http.c b/src/proto_http.c index 90b73da..ac1732d 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -3124,6 +3124,37 @@ static inline void inet_set_tos(int fd, struct sockaddr_storage from, int tos) #endif } +static void http_append_header(struct session* s, struct http_msg *msg, const char* name, uint name_len, + char* buf, struct hdr_idx* idx, struct list *fmt, struct hdr_ctx* ctx) +{ + int found = 1; + + ctx->idx = 0; + + if (!http_find_header2(name, name_len, buf, idx, ctx)) + found = 0; + + memcpy(trash.str, name, name_len); + trash.len = name_len; + trash.str[trash.len++] = ':'; + trash.str[trash.len++] = ' '; + + if (found) { + if (trash.len + ctx->vlen > trash.size) + return; + + memcpy(trash.str + trash.len, ctx->line + ctx->val, ctx->vlen); + trash.len += ctx->vlen; + } + + trash.len += build_logline(s, trash.str + trash.len, trash.size - trash.len, fmt); + + if (found) + http_remove_header2(msg, idx, ctx); + + http_header_add_tail2(msg, idx, trash.str, trash.len); +} + /* Executes the http-request rules <rules> for session <s>, proxy <px> and * transaction <txn>. Returns the first rule that prevents further processing * of the request (auth, deny, ...) or NULL if it executed all rules or stopped @@ -3194,6 +3225,11 @@ http_req_get_intercept_rule(struct proxy *px, struct list *rules, struct session s->logs.level = rule->arg.loglevel; break; + case HTTP_REQ_ACT_APPEND_HDR: + http_append_header(s, &txn->req, rule->arg.hdr_add.name, rule->arg.hdr_add.name_len, + txn->req.chn->buf->p, &txn->hdr_idx, &rule->arg.hdr_add.fmt, &ctx); + break; + case HTTP_REQ_ACT_DEL_HDR: case HTTP_REQ_ACT_SET_HDR: ctx.idx = 0; @@ -3375,6 +3411,11 @@ http_res_get_intercept_rule(struct proxy *px, struct list *rules, struct session s->logs.level = rule->arg.loglevel; break; + case HTTP_RES_ACT_APPEND_HDR: + http_append_header(s, &txn->rsp, rule->arg.hdr_add.name, rule->arg.hdr_add.name_len, + txn->rsp.chn->buf->p, &txn->hdr_idx, &rule->arg.hdr_add.fmt, &ctx); + break; + case HTTP_RES_ACT_DEL_HDR: case HTTP_RES_ACT_SET_HDR: ctx.idx = 0; @@ -8792,8 +8833,18 @@ struct http_req_rule *parse_http_req_cond(const char **args, const char *file, i else if ((rule->arg.loglevel = get_log_level(args[cur_arg]) + 1) == 0) goto bad_log_level; cur_arg++; - } else if (strcmp(args[0], "add-header") == 0 || strcmp(args[0], "set-header") == 0) { - rule->action = *args[0] == 'a' ? HTTP_REQ_ACT_ADD_HDR : HTTP_REQ_ACT_SET_HDR; + } else if (strcmp(args[0], "add-header") == 0 || strcmp(args[0], "set-header") == 0 || + strcmp(args[0], "append-header") == 0) { + switch (*args[0]) + { + case 'a': + rule->action = *(args[0]+1) == 'd' ? HTTP_REQ_ACT_ADD_HDR : HTTP_REQ_ACT_APPEND_HDR; + break; + case 's': + rule->action = HTTP_REQ_ACT_SET_HDR; + break; + } + cur_arg = 1; if (!*args[cur_arg] || !*args[cur_arg+1] || @@ -9111,8 +9162,22 @@ struct http_res_rule *parse_http_res_cond(const char **args, const char *file, i else if ((rule->arg.loglevel = get_log_level(args[cur_arg] + 1)) == 0) goto bad_log_level; cur_arg++; - } else if (strcmp(args[0], "add-header") == 0 || strcmp(args[0], "set-header") == 0) { - rule->action = *args[0] == 'a' ? HTTP_RES_ACT_ADD_HDR : HTTP_RES_ACT_SET_HDR; + } else if (strcmp(args[0], "add-header") == 0 || strcmp(args[0], "set-header") == 0 || + strcmp(args[0], "append-header") == 0) { + + switch ((args[0])[1]) + { + case 'd': + rule->action = HTTP_RES_ACT_ADD_HDR; + break; + case 'e': + rule->action = HTTP_RES_ACT_SET_HDR; + break; + case 'p': + rule->action = HTTP_RES_ACT_APPEND_HDR; + break; + } + cur_arg = 1; if (!*args[cur_arg] || !*args[cur_arg+1] ||

