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] ||

Reply via email to