MINOR: http-rules: Make set-header and add-header custom actions
Now, these actions use their own dedicated function and are no longer handled
"in place" during the HTTP rules evaluation. Thus the action names
ACT_HTTP_SET_HDR and ACT_HTTP_ADD_VAL are removed. The action type is now set to
0 to set a header (so remove existing ones if any and add a new one) or to 1 to
add a header (add without remove).
diff --git a/include/types/action.h b/include/types/action.h
index d41ed77..16d669d 100644
--- a/include/types/action.h
+++ b/include/types/action.h
@@ -78,8 +78,6 @@
ACT_ACTION_DENY,
/* common http actions .*/
- ACT_HTTP_ADD_HDR,
- ACT_HTTP_SET_HDR,
ACT_HTTP_DEL_HDR,
ACT_HTTP_REDIR,
ACT_HTTP_SET_NICE,
diff --git a/src/http_act.c b/src/http_act.c
index 33e3ff4..aa8dfff 100644
--- a/src/http_act.c
+++ b/src/http_act.c
@@ -943,6 +943,66 @@
return ACT_RET_PRS_OK;
}
+/* This function executes a set-header or add-header actions. It builds a string
+ * in the trash from the specified format string. It finds the action to be
+ * performed in <.action>, previously filled by function parse_set_header(). The
+ * replacement action is excuted by the function http_action_set_header(). On
+ * success, it returns ACT_RET_CONT. If an error occurs while soft rewrites are
+ * enabled, the action is canceled, but the rule processing continue. Otherwsize
+ * ACT_RET_ERR is returned.
+ */
+static enum act_return http_action_set_header(struct act_rule *rule, struct proxy *px,
+ struct session *sess, struct stream *s, int flags)
+{
+ struct htx *htx = htxbuf((rule->from == ACT_F_HTTP_REQ) ? &s->req.buf : &s->res.buf);
+ enum act_return ret = ACT_RET_CONT;
+ struct buffer *replace;
+ struct http_hdr_ctx ctx;
+ struct ist n, v;
+
+ replace = alloc_trash_chunk();
+ if (!replace)
+ goto fail_alloc;
+
+ replace->data = build_logline(s, replace->area, replace->size, &rule->arg.http.fmt);
+ n = rule->arg.http.str;
+ v = ist2(replace->area, replace->data);
+
+ if (rule->action == 0) { // set-header
+ /* remove all occurrences of the header */
+ ctx.blk = NULL;
+ while (http_find_header(htx, n, &ctx, 1))
+ http_remove_header(htx, &ctx);
+ }
+
+ /* Now add header */
+ if (!http_add_header(htx, n, v))
+ goto fail_rewrite;
+
+ leave:
+ free_trash_chunk(replace);
+ return ret;
+
+ fail_alloc:
+ if (!(s->flags & SF_ERR_MASK))
+ s->flags |= SF_ERR_RESOURCE;
+ ret = ACT_RET_ERR;
+ goto leave;
+
+ fail_rewrite:
+ _HA_ATOMIC_ADD(&sess->fe->fe_counters.failed_rewrites, 1);
+ if (s->flags & SF_BE_ASSIGNED)
+ _HA_ATOMIC_ADD(&s->be->be_counters.failed_rewrites, 1);
+ if (sess->listener->counters)
+ _HA_ATOMIC_ADD(&sess->listener->counters->failed_rewrites, 1);
+ if (objt_server(s->target))
+ _HA_ATOMIC_ADD(&__objt_server(s->target)->counters.failed_rewrites, 1);
+
+ if (!(s->txn->req.flags & HTTP_MSGF_SOFT_RW))
+ ret = ACT_RET_ERR;
+ goto leave;
+}
+
/* Parse a "set-header", "add-header" or "early-hint" actions. It takes an
* header name and a log-format string as arguments. It returns ACT_RET_PRS_OK
* on success, ACT_RET_PRS_ERR on error.
@@ -955,8 +1015,15 @@
{
int cap, cur_arg;
- rule->action = (*args[*orig_arg-1] == 'a' ? ACT_HTTP_ADD_HDR :
- *args[*orig_arg-1] == 's' ? ACT_HTTP_SET_HDR : ACT_HTTP_EARLY_HINT);
+ if (args[*orig_arg-1][0] == 'e')
+ rule->action = ACT_HTTP_EARLY_HINT;
+ else {
+ if (args[*orig_arg-1][0] == 's')
+ rule->action = 0; // set-header
+ else
+ rule->action = 1; // add-header
+ rule->action_ptr = http_action_set_header;
+ }
cur_arg = *orig_arg;
if (!*args[cur_arg] || !*args[cur_arg+1]) {
diff --git a/src/http_ana.c b/src/http_ana.c
index a9961fe..dc9f06e 100644
--- a/src/http_ana.c
+++ b/src/http_ana.c
@@ -3038,52 +3038,6 @@
http_remove_header(htx, &ctx);
break;
- case ACT_HTTP_SET_HDR:
- case ACT_HTTP_ADD_HDR: {
- /* The scope of the trash buffer must be limited to this function. The
- * build_logline() function can execute a lot of other function which
- * can use the trash buffer. So for limiting the scope of this global
- * buffer, we build first the header value using build_logline, and
- * after we store the header name.
- */
- struct buffer *replace;
- struct ist n, v;
-
- replace = alloc_trash_chunk();
- if (!replace) {
- if (!(s->flags & SF_ERR_MASK))
- s->flags |= SF_ERR_RESOURCE;
- rule_ret = HTTP_RULE_RES_ERROR;
- goto end;
- }
-
- replace->data = build_logline(s, replace->area, replace->size, &rule->arg.http.fmt);
- n = rule->arg.http.str;
- v = ist2(replace->area, replace->data);
-
- if (rule->action == ACT_HTTP_SET_HDR) {
- /* remove all occurrences of the header */
- ctx.blk = NULL;
- while (http_find_header(htx, n, &ctx, 1))
- http_remove_header(htx, &ctx);
- }
-
- if (!http_add_header(htx, n, v)) {
- _HA_ATOMIC_ADD(&sess->fe->fe_counters.failed_rewrites, 1);
- if (s->flags & SF_BE_ASSIGNED)
- _HA_ATOMIC_ADD(&s->be->be_counters.failed_rewrites, 1);
- if (sess->listener->counters)
- _HA_ATOMIC_ADD(&sess->listener->counters->failed_rewrites, 1);
-
- if (!(txn->req.flags & HTTP_MSGF_SOFT_RW)) {
- rule_ret = HTTP_RULE_RES_ERROR;
- goto end;
- }
- }
- free_trash_chunk(replace);
- break;
- }
-
case ACT_HTTP_DEL_ACL:
case ACT_HTTP_DEL_MAP: {
struct pat_ref *ref;
@@ -3400,47 +3354,6 @@
http_remove_header(htx, &ctx);
break;
- case ACT_HTTP_SET_HDR:
- case ACT_HTTP_ADD_HDR: {
- struct buffer *replace;
- struct ist n, v;
-
- replace = alloc_trash_chunk();
- if (!replace) {
- if (!(s->flags & SF_ERR_MASK))
- s->flags |= SF_ERR_RESOURCE;
- rule_ret = HTTP_RULE_RES_ERROR;
- goto end;
- }
-
- replace->data = build_logline(s, replace->area, replace->size, &rule->arg.http.fmt);
- n = rule->arg.http.str;
- v = ist2(replace->area, replace->data);
-
- if (rule->action == ACT_HTTP_SET_HDR) {
- /* remove all occurrences of the header */
- ctx.blk = NULL;
- while (http_find_header(htx, n, &ctx, 1))
- http_remove_header(htx, &ctx);
- }
-
- if (!http_add_header(htx, n, v)) {
- _HA_ATOMIC_ADD(&sess->fe->fe_counters.failed_rewrites, 1);
- _HA_ATOMIC_ADD(&s->be->be_counters.failed_rewrites, 1);
- if (sess->listener->counters)
- _HA_ATOMIC_ADD(&sess->listener->counters->failed_rewrites, 1);
- if (objt_server(s->target))
- _HA_ATOMIC_ADD(&__objt_server(s->target)->counters.failed_rewrites, 1);
-
- if (!(txn->rsp.flags & HTTP_MSGF_SOFT_RW)) {
- rule_ret = HTTP_RULE_RES_ERROR;
- goto end;
- }
- }
- free_trash_chunk(replace);
- break;
- }
-
case ACT_HTTP_DEL_ACL:
case ACT_HTTP_DEL_MAP: {
struct pat_ref *ref;