mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-20 21:31:28 +02:00
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.
This commit is contained in:
parent
fb50443517
commit
8d22823ade
@ -6265,6 +6265,24 @@ http-request set-src-port <expr> [ { if | unless } <condition> ]
|
||||
the address family supports a port, otherwise it forces the source address to
|
||||
IPv4 "0.0.0.0" before rewriting the port.
|
||||
|
||||
http-request set-timeout server|tunnel { <timeout> | <expr> }
|
||||
[ { if | unless } <condition> ]
|
||||
|
||||
This action overrides the specified "server" or "tunnel" timeout for the
|
||||
current stream only. The timeout can be specified in millisecond or with any
|
||||
other unit if the number is suffixed by the unit as explained at the top of
|
||||
this document. It is also possible to write an expression which must returns
|
||||
a number interpreted as a timeout in millisecond.
|
||||
|
||||
Note that the server/tunnel timeouts are only relevant on the backend side
|
||||
and thus this rule is only available for the proxies with backend
|
||||
capabilities. Also the timeout value must be non-null to obtain the expected
|
||||
results.
|
||||
|
||||
Example:
|
||||
http-request set-timeout server 5s
|
||||
http-request set-timeout hdr(host),map_int(host.lst)
|
||||
|
||||
http-request set-tos <tos> [ { if | unless } <condition> ]
|
||||
|
||||
This is used to set the TOS or DSCP field value of packets sent to the client
|
||||
|
@ -143,6 +143,11 @@ struct act_rule {
|
||||
struct sample_expr *expr;
|
||||
int idx;
|
||||
} capid;
|
||||
struct {
|
||||
int value; /* plain timeout value in ms if no expr is used */
|
||||
enum act_timeout_name type; /* timeout type */
|
||||
struct sample_expr *expr; /* timeout value as an expression */
|
||||
} timeout;
|
||||
struct hlua_rule *hlua_rule;
|
||||
struct {
|
||||
struct sample_expr *expr;
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <stdio.h>
|
||||
#include <haproxy/action-t.h>
|
||||
#include <haproxy/list.h>
|
||||
#include <haproxy/sample.h>
|
||||
|
||||
int act_resolution_cb(struct dns_requester *requester, struct dns_nameserver *nameserver);
|
||||
int act_resolution_error_cb(struct dns_requester *requester, int error_code);
|
||||
@ -90,4 +91,14 @@ int check_trk_action(struct act_rule *rule, struct proxy *px, char **err);
|
||||
*/
|
||||
int check_capture(struct act_rule *rule, struct proxy *px, char **err);
|
||||
|
||||
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);
|
||||
|
||||
static inline void release_timeout_action(struct act_rule *rule)
|
||||
{
|
||||
release_sample_expr(rule->arg.timeout.expr);
|
||||
}
|
||||
|
||||
#endif /* _HAPROXY_ACTION_H */
|
||||
|
57
src/action.c
57
src/action.c
@ -149,3 +149,60 @@ int act_resolution_error_cb(struct dns_requester *requester, int error_code)
|
||||
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;
|
||||
}
|
||||
|
@ -1901,6 +1901,67 @@ static enum act_parse_ret parse_http_track_sc(const char **args, int *orig_arg,
|
||||
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 @@ static struct action_kw_list http_req_actions = {
|
||||
{ "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 }
|
||||
}
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user