MEDIUM: http_act: define set-timeout server/tunnel action
Add a new http-request action 'set-timeout [server/tunnel]'. This action
can be used to update the server or tunnel timeout of a stream. It takes
two parameters, the timeout name to update and the new timeout value.
This rule is only valid for a proxy with backend capabilities. The
timeout value cannot be null. A sample expression can also be used
instead of a plain value.
diff --git a/src/action.c b/src/action.c
index 870a839..c4c263f 100644
--- a/src/action.c
+++ b/src/action.c
@@ -149,3 +149,60 @@
return 0;
}
+/* Parse a set-timeout rule statement. It first checks if the timeout name is
+ * valid and returns it in <name>. Then the timeout is parsed as a plain value
+ * and * returned in <out_timeout>. If there is a parsing error, the value is
+ * reparsed as an expression and returned in <expr>.
+ *
+ * Returns -1 if the name is invalid or neither a time or an expression can be
+ * parsed, or if the timeout value is 0.
+ */
+int cfg_parse_rule_set_timeout(const char **args, int idx, int *out_timeout,
+ enum act_timeout_name *name,
+ struct sample_expr **expr, char **err,
+ const char *file, int line, struct arg_list *al)
+{
+ const char *res;
+ const char *timeout_name = args[idx++];
+
+ if (!strcmp(timeout_name, "server")) {
+ *name = ACT_TIMEOUT_SERVER;
+ }
+ else if (!strcmp(timeout_name, "tunnel")) {
+ *name = ACT_TIMEOUT_TUNNEL;
+ }
+ else {
+ memprintf(err,
+ "'set-timeout' rule supports 'server'/'tunnel' (got '%s')",
+ timeout_name);
+ return -1;
+ }
+
+ res = parse_time_err(args[idx], (unsigned int *)out_timeout, TIME_UNIT_MS);
+ if (res == PARSE_TIME_OVER) {
+ memprintf(err, "timer overflow in argument '%s' to rule 'set-timeout %s' (maximum value is 2147483647 ms or ~24.8 days)",
+ args[idx], timeout_name);
+ return -1;
+ }
+ else if (res == PARSE_TIME_UNDER) {
+ memprintf(err, "timer underflow in argument '%s' to rule 'set-timeout %s' (minimum value is 1 ms)",
+ args[idx], timeout_name);
+ return -1;
+ }
+ /* res not NULL, parsing error */
+ else if (res) {
+ *expr = sample_parse_expr((char **)args, &idx, file, line, err, al, NULL);
+ if (!*expr) {
+ memprintf(err, "unexpected character '%c' in rule 'set-timeout %s'", *res, timeout_name);
+ return -1;
+ }
+ }
+ /* res NULL, parsing ok but value is 0 */
+ else if (!(*out_timeout)) {
+ memprintf(err, "null value is not valid for a 'set-timeout %s' rule",
+ timeout_name);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/http_act.c b/src/http_act.c
index 85a534e..140cdf1 100644
--- a/src/http_act.c
+++ b/src/http_act.c
@@ -1901,6 +1901,67 @@
return ACT_RET_PRS_OK;
}
+static enum act_return action_timeout_set_stream_timeout(struct act_rule *rule,
+ struct proxy *px,
+ struct session *sess,
+ struct stream *s,
+ int flags)
+{
+ struct sample *key;
+
+ if (rule->arg.timeout.expr) {
+ key = sample_fetch_as_type(px, sess, s, SMP_OPT_FINAL, rule->arg.timeout.expr, SMP_T_SINT);
+ if (!key)
+ return ACT_RET_CONT;
+
+ stream_set_timeout(s, rule->arg.timeout.type, MS_TO_TICKS(key->data.u.sint));
+ }
+ else {
+ stream_set_timeout(s, rule->arg.timeout.type, MS_TO_TICKS(rule->arg.timeout.value));
+ }
+
+ return ACT_RET_CONT;
+}
+
+/* Parse a "set-timeout" action. Returns ACT_RET_PRS_ERR if parsing error.
+ */
+static enum act_parse_ret parse_http_set_timeout(const char **args,
+ int *orig_arg,
+ struct proxy *px,
+ struct act_rule *rule, char **err)
+{
+ int cur_arg;
+
+ rule->action = ACT_CUSTOM;
+ rule->action_ptr = action_timeout_set_stream_timeout;
+ rule->release_ptr = release_timeout_action;
+
+ cur_arg = *orig_arg;
+ if (!*args[cur_arg] || !*args[cur_arg + 1]) {
+ memprintf(err, "expects exactly 2 arguments");
+ return ACT_RET_PRS_ERR;
+ }
+
+ if (!(px->cap & PR_CAP_BE)) {
+ memprintf(err, "proxy '%s' has no backend capability", px->id);
+ return ACT_RET_PRS_ERR;
+ }
+
+ if (cfg_parse_rule_set_timeout(args, cur_arg,
+ &rule->arg.timeout.value,
+ &rule->arg.timeout.type,
+ &rule->arg.timeout.expr,
+ err,
+ px->conf.args.file,
+ px->conf.args.line, &px->conf.args) == -1) {
+ return ACT_RET_PRS_ERR;
+ }
+
+ *orig_arg = cur_arg + 2;
+
+ return ACT_RET_PRS_OK;
+}
+
/* This function executes a strict-mode actions. On success, it always returns
* ACT_RET_CONT
*/
@@ -2034,6 +2095,7 @@
{ "strict-mode", parse_http_strict_mode, 0 },
{ "tarpit", parse_http_deny, 0 },
{ "track-sc", parse_http_track_sc, 1 },
+ { "set-timeout", parse_http_set_timeout, 0 },
{ NULL, NULL }
}
};