MEDIUM: actions: Add standard return code for the action API
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
diff --git a/include/types/action.h b/include/types/action.h
index 09c14c5..713631e 100644
--- a/include/types/action.h
+++ b/include/types/action.h
@@ -32,6 +32,12 @@
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 @@
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;
diff --git a/src/hlua.c b/src/hlua.c
index 16ebc8d..5395b6d 100644
--- a/src/hlua.c
+++ b/src/hlua.c
@@ -4270,8 +4270,8 @@
* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
/* 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 @@
* 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 @@
* 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);
}
diff --git a/src/proto_http.c b/src/proto_http.c
index 6bd73b1..ce43ec5 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -3627,15 +3627,24 @@
}
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 @@
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 @@
* 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 @@
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 @@
* 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 @@
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 @@
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 @@
* 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 @@
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 @@
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 @@
* 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 @@
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 @@
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
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index 3c70357..f797042 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -1231,9 +1231,15 @@
}
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 @@
}
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 @@
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;
}
diff --git a/src/vars.c b/src/vars.c
index 86ac93b..4308012 100644
--- a/src/vars.c
+++ b/src/vars.c
@@ -482,49 +482,49 @@
/* 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);