]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: http-rules: Make set-header and add-header custom actions
authorChristopher Faulet <cfaulet@haproxy.com>
Tue, 17 Dec 2019 08:33:38 +0000 (09:33 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Mon, 20 Jan 2020 14:18:45 +0000 (15:18 +0100)
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).

include/types/action.h
src/http_act.c
src/http_ana.c

index d41ed77afe2c33f94ff67f358644a34c36e0c13e..16d669d3b1593da191f7b3309650a157cceb106a 100644 (file)
@@ -78,8 +78,6 @@ enum act_name {
        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,
index 33e3ff4d9752f5334cf9121868cbdbfb9fca36e8..aa8dfff495e4f2927beb023fb62fd15afaca8059 100644 (file)
@@ -943,6 +943,66 @@ static enum act_parse_ret parse_http_set_log_level(const char **args, int *orig_
        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 @@ static enum act_parse_ret parse_http_set_header(const char **args, int *orig_arg
 {
        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]) {
index a9961feec191bdf9480673c9c2bff34ed9806dbf..dc9f06e69c74af52d63abd434b7fc1ffecb0ccd7 100644 (file)
@@ -3038,52 +3038,6 @@ static enum rule_result http_req_get_intercept_rule(struct proxy *px, struct lis
                                        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 @@ resume_execution:
                                        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;