]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: actions: Add standard return code for the action API
authorThierry FOURNIER <tfournier@arpalert.org>
Thu, 6 Aug 2015 06:52:53 +0000 (08:52 +0200)
committerWilly Tarreau <w@1wt.eu>
Thu, 20 Aug 2015 15:13:47 +0000 (17:13 +0200)
Action function can return 3 status:
 - error if the action encounter fatal error (like out of memory)
 - yield if the action must terminate his work later
 - continue in other cases

include/types/action.h
src/hlua.c
src/proto_http.c
src/proto_tcp.c
src/vars.c

index 09c14c504b1aadbd5235725c8a31dfe3d0acd0cd..713631ed0619e369edc3ba6b85eaa56a5202a03c 100644 (file)
@@ -32,6 +32,12 @@ enum act_from {
        ACT_F_HTTP_RES,    /* http-response */
 };
 
+enum act_return {
+       ACT_RET_CONT,  /* continue processing. */
+       ACT_RET_YIELD, /* call me again. */
+       ACT_RET_ERR,   /* processing error. */
+};
+
 enum act_name {
        ACT_ACTION_CONT = 0,
        ACT_ACTION_STOP,
@@ -78,8 +84,8 @@ struct act_rule {
        enum act_name action;                  /* ACT_ACTION_* */
        enum act_from from;                    /* ACT_F_* */
        short deny_status;                     /* HTTP status to return to user when denying */
-       int (*action_ptr)(struct act_rule *rule, struct proxy *px,
-                         struct session *sess, struct stream *s); /* ptr to custom action */
+       enum act_return (*action_ptr)(struct act_rule *rule, struct proxy *px,
+                                     struct session *sess, struct stream *s); /* ptr to custom action */
        union {
                struct {
                        char *realm;
index 16ebc8d0715f46cf1000752f5373fdaf7037bdd5..5395b6d303beee215890fbeb5c6a42a6c9e69d39 100644 (file)
@@ -4270,8 +4270,8 @@ static int hlua_parse_rule(const char **args, int *cur_arg, struct proxy *px,
  * return 0 if the function must be called again because the LUA
  * returns a yield.
  */
-static int hlua_request_act_wrapper(struct hlua_rule *rule, struct proxy *px,
-                                    struct stream *s, unsigned int analyzer)
+static enum act_return hlua_request_act_wrapper(struct hlua_rule *rule, struct proxy *px,
+                                                struct stream *s, unsigned int analyzer)
 {
        char **arg;
 
@@ -4284,7 +4284,7 @@ static int hlua_request_act_wrapper(struct hlua_rule *rule, struct proxy *px,
                send_log(px, LOG_ERR, "Lua action '%s': can't initialize Lua context.", rule->fcn.name);
                if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
                        Alert("Lua action '%s': can't initialize Lua context.\n", rule->fcn.name);
-               return 1;
+               return ACT_RET_CONT;
        }
 
        /* If it is the first run, initialize the data for the call. */
@@ -4294,7 +4294,7 @@ static int hlua_request_act_wrapper(struct hlua_rule *rule, struct proxy *px,
                        send_log(px, LOG_ERR, "Lua function '%s': full stack.", rule->fcn.name);
                        if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
                                Alert("Lua function '%s': full stack.\n", rule->fcn.name);
-                       return 1;
+                       return ACT_RET_CONT;
                }
 
                /* Restore the function in the stack. */
@@ -4305,7 +4305,7 @@ static int hlua_request_act_wrapper(struct hlua_rule *rule, struct proxy *px,
                        send_log(px, LOG_ERR, "Lua function '%s': full stack.", rule->fcn.name);
                        if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
                                Alert("Lua function '%s': full stack.\n", rule->fcn.name);
-                       return 1;
+                       return ACT_RET_CONT;
                }
                s->hlua.nargs = 1;
 
@@ -4315,7 +4315,7 @@ static int hlua_request_act_wrapper(struct hlua_rule *rule, struct proxy *px,
                                send_log(px, LOG_ERR, "Lua function '%s': full stack.", rule->fcn.name);
                                if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
                                        Alert("Lua function '%s': full stack.\n", rule->fcn.name);
-                               return 1;
+                               return ACT_RET_CONT;
                        }
                        lua_pushstring(s->hlua.T, *arg);
                        s->hlua.nargs++;
@@ -4332,7 +4332,7 @@ static int hlua_request_act_wrapper(struct hlua_rule *rule, struct proxy *px,
        switch (hlua_ctx_resume(&s->hlua, 1)) {
        /* finished. */
        case HLUA_E_OK:
-               return 1;
+               return ACT_RET_CONT;
 
        /* yield. */
        case HLUA_E_AGAIN:
@@ -4354,7 +4354,7 @@ static int hlua_request_act_wrapper(struct hlua_rule *rule, struct proxy *px,
                }
                if (HLUA_IS_WAKEREQWR(&s->hlua))
                        s->req.flags |= CF_WAKE_WRITE;
-               return 0;
+               return ACT_RET_YIELD;
 
        /* finished with error. */
        case HLUA_E_ERRMSG:
@@ -4363,7 +4363,7 @@ static int hlua_request_act_wrapper(struct hlua_rule *rule, struct proxy *px,
                if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))
                        Alert("Lua function '%s': %s.\n", rule->fcn.name, lua_tostring(s->hlua.T, -1));
                lua_pop(s->hlua.T, 1);
-               return 1;
+               return ACT_RET_CONT;
 
        case HLUA_E_ERR:
                /* Display log. */
@@ -4372,15 +4372,15 @@ static int hlua_request_act_wrapper(struct hlua_rule *rule, struct proxy *px,
                        Alert("Lua function '%s' return an unknown error.\n", rule->fcn.name);
 
        default:
-               return 1;
+               return ACT_RET_CONT;
        }
 }
 
 /* Lua execution wrapper for "tcp-request". This function uses
  * "hlua_request_act_wrapper" for executing the LUA code.
  */
-int hlua_tcp_req_act_wrapper(struct act_rule *act_rule, struct proxy *px,
-                             struct session *sess, struct stream *s)
+enum act_return hlua_tcp_req_act_wrapper(struct act_rule *act_rule, struct proxy *px,
+                                         struct session *sess, struct stream *s)
 {
        return hlua_request_act_wrapper(act_rule->arg.hlua_rule, px, s, AN_REQ_INSPECT_FE);
 }
@@ -4388,8 +4388,8 @@ int hlua_tcp_req_act_wrapper(struct act_rule *act_rule, struct proxy *px,
 /* Lua execution wrapper for "tcp-response". This function uses
  * "hlua_request_act_wrapper" for executing the LUA code.
  */
-int hlua_tcp_res_act_wrapper(struct act_rule *act_rule, struct proxy *px,
-                             struct session *sess, struct stream *s)
+enum act_return hlua_tcp_res_act_wrapper(struct act_rule *act_rule, struct proxy *px,
+                                         struct session *sess, struct stream *s)
 {
        return hlua_request_act_wrapper(act_rule->arg.hlua_rule, px, s, AN_RES_INSPECT);
 }
@@ -4398,8 +4398,8 @@ int hlua_tcp_res_act_wrapper(struct act_rule *act_rule, struct proxy *px,
  * This function uses "hlua_request_act_wrapper" for executing
  * the LUA code.
  */
-int hlua_http_req_act_wrapper(struct act_rule *rule, struct proxy *px,
-                              struct session *sess, struct stream *s)
+enum act_return hlua_http_req_act_wrapper(struct act_rule *rule, struct proxy *px,
+                                          struct session *sess, struct stream *s)
 {
        return hlua_request_act_wrapper(rule->arg.hlua_rule, px, s, AN_REQ_HTTP_PROCESS_FE);
 }
@@ -4408,8 +4408,8 @@ int hlua_http_req_act_wrapper(struct act_rule *rule, struct proxy *px,
  * This function uses "hlua_request_act_wrapper" for executing
  * the LUA code.
  */
-int hlua_http_res_act_wrapper(struct act_rule *rule, struct proxy *px,
-                              struct session *sess, struct stream *s)
+enum act_return hlua_http_res_act_wrapper(struct act_rule *rule, struct proxy *px,
+                                          struct session *sess, struct stream *s)
 {
        return hlua_request_act_wrapper(rule->arg.hlua_rule, px, s, AN_RES_HTTP_PROCESS_BE);
 }
index 6bd73b1cdcb635bb80701506fa7621eaf3d33313..ce43ec5991ec81e08b2b4d9c8d009ed7e0cefe5a 100644 (file)
@@ -3627,15 +3627,24 @@ resume_execution:
                        }
 
                case ACT_ACTION_CONT:
-                       if (!rule->action_ptr(rule, px, s->sess, s)) {
+                       switch (rule->action_ptr(rule, px, s->sess, s)) {
+                       case ACT_RET_ERR:
+                       case ACT_RET_CONT:
+                               break;
+                       case ACT_RET_YIELD:
                                s->current_rule = rule;
                                return HTTP_RULE_RES_YIELD;
                        }
                        break;
 
                case ACT_ACTION_STOP:
-                       rule->action_ptr(rule, px, s->sess, s);
-                       return HTTP_RULE_RES_DONE;
+                       switch (rule->action_ptr(rule, px, s->sess, s)) {
+                       case ACT_RET_YIELD:
+                       case ACT_RET_ERR:
+                       case ACT_RET_CONT:
+                               return HTTP_RULE_RES_DONE;
+                       }
+                       break;
 
                case ACT_ACTION_TRK_SC0 ... ACT_ACTION_TRK_SCMAX:
                        /* Note: only the first valid tracking parameter of each
@@ -3907,7 +3916,11 @@ resume_execution:
                        return HTTP_RULE_RES_DONE;
 
                case ACT_ACTION_CONT:
-                       if (!rule->action_ptr(rule, px, s->sess, s)) {
+                       switch (rule->action_ptr(rule, px, s->sess, s)) {
+                       case ACT_RET_ERR:
+                       case ACT_RET_CONT:
+                               break;
+                       case ACT_RET_YIELD:
                                s->current_rule = rule;
                                return HTTP_RULE_RES_YIELD;
                        }
@@ -12246,8 +12259,8 @@ int http_replace_req_line(int action, const char *replace, int len,
  * http_action_set_req_line_exec(). It always returns 1. If an error occurs
  * the action is canceled, but the rule processing continue.
  */
-int http_action_set_req_line(struct act_rule *rule, struct proxy *px,
-                             struct session *sess, struct stream *s)
+enum act_return http_action_set_req_line(struct act_rule *rule, struct proxy *px,
+                                         struct session *sess, struct stream *s)
 {
        chunk_reset(&trash);
 
@@ -12257,7 +12270,7 @@ int http_action_set_req_line(struct act_rule *rule, struct proxy *px,
        trash.len += build_logline(s, trash.str + trash.len, trash.size - trash.len, &rule->arg.http.logfmt);
 
        http_replace_req_line(rule->arg.http.action, trash.str, trash.len, px, s);
-       return 1;
+       return ACT_RET_CONT;
 }
 
 /* parse an http-request action among :
@@ -12320,8 +12333,8 @@ int parse_set_req_line(const char **args, int *orig_arg, struct proxy *px, struc
  * returns 1. If an error occurs the action is cancelled, but the rule
  * processing continues.
  */
-int http_action_req_capture(struct act_rule *rule, struct proxy *px,
-                            struct session *sess, struct stream *s)
+enum act_return http_action_req_capture(struct act_rule *rule, struct proxy *px,
+                                        struct session *sess, struct stream *s)
 {
        struct sample *key;
        struct cap_hdr *h = rule->arg.cap.hdr;
@@ -12330,13 +12343,13 @@ int http_action_req_capture(struct act_rule *rule, struct proxy *px,
 
        key = sample_fetch_as_type(s->be, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->arg.cap.expr, SMP_T_STR);
        if (!key)
-               return 1;
+               return ACT_RET_CONT;
 
        if (cap[h->index] == NULL)
                cap[h->index] = pool_alloc2(h->pool);
 
        if (cap[h->index] == NULL) /* no more capture memory */
-               return 1;
+               return ACT_RET_CONT;
 
        len = key->data.u.str.len;
        if (len > h->len)
@@ -12344,7 +12357,7 @@ int http_action_req_capture(struct act_rule *rule, struct proxy *px,
 
        memcpy(cap[h->index], key->data.u.str.str, len);
        cap[h->index][len] = 0;
-       return 1;
+       return ACT_RET_CONT;
 }
 
 /* This function executes the "capture" action and store the result in a
@@ -12352,8 +12365,8 @@ int http_action_req_capture(struct act_rule *rule, struct proxy *px,
  * into a string and puts it in a capture slot. It always returns 1. If an
  * error occurs the action is cancelled, but the rule processing continues.
  */
-int http_action_req_capture_by_id(struct act_rule *rule, struct proxy *px,
-                                  struct session *sess, struct stream *s)
+enum act_return http_action_req_capture_by_id(struct act_rule *rule, struct proxy *px,
+                                              struct session *sess, struct stream *s)
 {
        struct sample *key;
        struct cap_hdr *h;
@@ -12367,17 +12380,17 @@ int http_action_req_capture_by_id(struct act_rule *rule, struct proxy *px,
             h != NULL && i != rule->arg.capid.idx ;
             i--, h = h->next);
        if (!h)
-               return 1;
+               return ACT_RET_CONT;
 
        key = sample_fetch_as_type(s->be, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->arg.capid.expr, SMP_T_STR);
        if (!key)
-               return 1;
+               return ACT_RET_CONT;
 
        if (cap[h->index] == NULL)
                cap[h->index] = pool_alloc2(h->pool);
 
        if (cap[h->index] == NULL) /* no more capture memory */
-               return 1;
+               return ACT_RET_CONT;
 
        len = key->data.u.str.len;
        if (len > h->len)
@@ -12385,7 +12398,7 @@ int http_action_req_capture_by_id(struct act_rule *rule, struct proxy *px,
 
        memcpy(cap[h->index], key->data.u.str.str, len);
        cap[h->index][len] = 0;
-       return 1;
+       return ACT_RET_CONT;
 }
 
 /* parse an "http-request capture" action. It takes a single argument which is
@@ -12519,8 +12532,8 @@ int parse_http_req_capture(const char **args, int *orig_arg, struct proxy *px, s
  * into a string and puts it in a capture slot. It always returns 1. If an
  * error occurs the action is cancelled, but the rule processing continues.
  */
-int http_action_res_capture_by_id(struct act_rule *rule, struct proxy *px,
-                                  struct session *sess, struct stream *s)
+enum act_return http_action_res_capture_by_id(struct act_rule *rule, struct proxy *px,
+                                              struct session *sess, struct stream *s)
 {
        struct sample *key;
        struct cap_hdr *h;
@@ -12534,17 +12547,17 @@ int http_action_res_capture_by_id(struct act_rule *rule, struct proxy *px,
             h != NULL && i != rule->arg.capid.idx ;
             i--, h = h->next);
        if (!h)
-               return 1;
+               return ACT_RET_CONT;
 
        key = sample_fetch_as_type(s->be, sess, s, SMP_OPT_DIR_RES|SMP_OPT_FINAL, rule->arg.capid.expr, SMP_T_STR);
        if (!key)
-               return 1;
+               return ACT_RET_CONT;
 
        if (cap[h->index] == NULL)
                cap[h->index] = pool_alloc2(h->pool);
 
        if (cap[h->index] == NULL) /* no more capture memory */
-               return 1;
+               return ACT_RET_CONT;
 
        len = key->data.u.str.len;
        if (len > h->len)
@@ -12552,7 +12565,7 @@ int http_action_res_capture_by_id(struct act_rule *rule, struct proxy *px,
 
        memcpy(cap[h->index], key->data.u.str.str, len);
        cap[h->index][len] = 0;
-       return 1;
+       return ACT_RET_CONT;
 }
 
 /* parse an "http-response capture" action. It takes a single argument which is
index 3c70357dadb27ad023cb99d688f7a23cba9f69a9..f797042fdcd0cb159a4dfeef339f1a2fecec4a92 100644 (file)
@@ -1231,9 +1231,15 @@ resume_execution:
                        }
                        else {
                                /* Custom keywords. */
-                               if (rule->action_ptr && !rule->action_ptr(rule, s->be, s->sess, s)) {
-                                       s->current_rule = rule;
-                                       goto missing_data;
+                               if (rule->action_ptr) {
+                                       switch (rule->action_ptr(rule, s->be, s->sess, s)) {
+                                       case ACT_RET_ERR:
+                                       case ACT_RET_CONT:
+                                               break;
+                                       case ACT_RET_YIELD:
+                                               s->current_rule = rule;
+                                               goto missing_data;
+                                       }
                                }
 
                                /* accept */
@@ -1356,10 +1362,16 @@ resume_execution:
                        }
                        else {
                                /* Custom keywords. */
-                               if (rule->action_ptr && !rule->action_ptr(rule, s->be, s->sess, s)) {
-                                       channel_dont_close(rep);
-                                       s->current_rule = rule;
-                                       return 0;
+                               if (rule->action_ptr) {
+                                       switch (rule->action_ptr(rule, s->be, s->sess, s)) {
+                                       case ACT_RET_ERR:
+                                       case ACT_RET_CONT:
+                                               break;
+                                       case ACT_RET_YIELD:
+                                               channel_dont_close(rep);
+                                               s->current_rule = rule;
+                                               return 0;
+                                       }
                                }
 
                                /* accept */
@@ -1441,7 +1453,19 @@ int tcp_exec_req_rules(struct session *sess)
                        else {
                                /* Custom keywords. */
                                if (rule->action_ptr) {
-                                       rule->action_ptr(rule, sess->fe, sess, NULL);
+                                       switch (rule->action_ptr(rule, sess->fe, sess, NULL)) {
+                                       case ACT_RET_YIELD:
+                                               /* yield is not allowed at this point. If this return code is
+                                                * used it is a bug, so I prefer to abort the process.
+                                                */
+                                               send_log(sess->fe, LOG_WARNING,
+                                                        "Internal error: yield not allowed with tcp-request connection actions.");
+                                       case ACT_RET_CONT:
+                                               break;
+                                       case ACT_RET_ERR:
+                                               result = 0;
+                                               break;
+                                       }
                                        if (rule->action == ACT_ACTION_CONT)
                                                continue;
                                }
index 86ac93b7b67ae7a89f1b6308e3f9de7d5c9007a1..430801232ce09ea7c1c6b3c23b0606ec43b29039 100644 (file)
@@ -482,49 +482,49 @@ int vars_get_by_desc(const struct var_desc *var_desc, struct stream *strm, struc
 /* Returns 0 if we need to come back later to complete the sample's retrieval,
  * otherwise 1. For now all processing is considered final so we only return 1.
  */
-static inline int action_store(struct sample_expr *expr, const char *name,
-                               enum vars_scope scope, struct proxy *px,
-                               struct stream *s, int sens)
+static inline enum act_return action_store(struct sample_expr *expr, const char *name,
+                                           enum vars_scope scope, struct proxy *px,
+                                           struct stream *s, int sens)
 {
        struct sample smp;
 
        /* Process the expression. */
        memset(&smp, 0, sizeof(smp));
        if (!sample_process(px, s->sess, s, sens|SMP_OPT_FINAL, expr, &smp))
-               return 1;
+               return ACT_RET_CONT;
 
        /* Store the sample, and ignore errors. */
        sample_store_stream(name, scope, s, &smp);
-       return 1;
+       return ACT_RET_CONT;
 }
 
 /* Wrapper for action_store */
-static int action_tcp_req_store(struct act_rule *rule, struct proxy *px,
-                                struct session *sess, struct stream *s)
+static enum act_return action_tcp_req_store(struct act_rule *rule, struct proxy *px,
+                                            struct session *sess, struct stream *s)
 {
        return action_store(rule->arg.vars.expr, rule->arg.vars.name,
                            rule->arg.vars.scope, px, s, SMP_OPT_DIR_REQ);
 }
 
 /* Wrapper for action_store */
-static int action_tcp_res_store(struct act_rule *rule, struct proxy *px,
-                                struct session *sess, struct stream *s)
+static enum act_return action_tcp_res_store(struct act_rule *rule, struct proxy *px,
+                                            struct session *sess, struct stream *s)
 {
        return action_store(rule->arg.vars.expr, rule->arg.vars.name,
                            rule->arg.vars.scope, px, s, SMP_OPT_DIR_RES);
 }
 
 /* Wrapper for action_store */
-static int action_http_req_store(struct act_rule *rule, struct proxy *px,
-                                 struct session *sess, struct stream *s)
+static enum act_return action_http_req_store(struct act_rule *rule, struct proxy *px,
+                                             struct session *sess, struct stream *s)
 {
        return action_store(rule->arg.vars.expr, rule->arg.vars.name,
                            rule->arg.vars.scope, px, s, SMP_OPT_DIR_REQ);
 }
 
 /* Wrapper for action_store */
-static int action_http_res_store(struct act_rule *rule, struct proxy *px,
-                                 struct session *sess, struct stream *s)
+static enum act_return action_http_res_store(struct act_rule *rule, struct proxy *px,
+                                             struct session *sess, struct stream *s)
 {
        return action_store(rule->arg.vars.expr, rule->arg.vars.name,
                            rule->arg.vars.scope, px, s, SMP_OPT_DIR_RES);