diff --git a/doc/configuration.txt b/doc/configuration.txt index 31aac447a..f88dad876 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -4297,6 +4297,11 @@ http-request deny [deny_status ] [ { if | unless } ] those that can be overridden by the "errorfile" directive. No further "http-request" rules are evaluated. +http-request disable-l7-retry [ { if | unless } ] + This disables any attempt to retry the request if it fails for any other + reason than a connection failure. This can be useful for example to make + sure POST requests aren't retried on failure. + http-request do-resolve(,,[ipv4,ipv6]) : This action performs a DNS resolution of the output of and stores diff --git a/include/types/stream_interface.h b/include/types/stream_interface.h index 6b30de58a..e11a6c903 100644 --- a/include/types/stream_interface.h +++ b/include/types/stream_interface.h @@ -84,6 +84,7 @@ enum { SI_FL_RXBLK_ANY = 0x001F0000, /* any of the RXBLK flags above */ SI_FL_RX_WAIT_EP = 0x00200000, /* stream-int waits for more data from the end point */ SI_FL_L7_RETRY = 0x01000000, /* The stream interface may attempt L7 retries */ + SI_FL_D_L7_RETRY = 0x02000000, /* Disable L7 retries on this stream interface, even if configured to do it */ }; /* A stream interface has 3 parts : diff --git a/src/http_act.c b/src/http_act.c index c8618eac5..c1b94dd09 100644 --- a/src/http_act.c +++ b/src/http_act.c @@ -217,6 +217,38 @@ static enum act_parse_ret parse_http_action_reject(const char **args, int *orig_ return ACT_RET_PRS_OK; } +/* This function executes the "disable-l7-retry" HTTP action. + * It disables L7 retries (all retry except for a connection failure). This + * can be useful for example to avoid retrying on POST requests. + * It just removes the L7 retry flag on the stream_interface, and always + * return ACT_RET_CONT; + */ +static enum act_return http_req_disable_l7_retry(struct act_rule *rule, struct proxy *px, + struct session *sess, struct stream *s, int flags) +{ + struct stream_interface *si = &s->si[1]; + + /* In theory, the SI_FL_L7_RETRY flags isn't set at this point, but + * let's be future-proof and remove it anyway. + */ + si->flags &= ~SI_FL_L7_RETRY; + si->flags |= SI_FL_D_L7_RETRY; + return ACT_RET_CONT; +} + +/* parse the "disable-l7-retry" action: + * This action takes no argument and returns ACT_RET_PRS_OK on success, + * ACT_RET_PRS_ERR on error. + */ +static enum act_parse_ret parse_http_req_disable_l7_retry(const char **args, + int *orig_args, struct proxy *px, + struct act_rule *rule, char **err) +{ + rule->action = ACT_CUSTOM; + rule->action_ptr = http_req_disable_l7_retry; + return ACT_RET_PRS_OK; +} + /* This function executes the "capture" action. It executes a fetch expression, * turns the result 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 @@ -575,6 +607,7 @@ static struct action_kw_list http_req_actions = { .kw = { { "capture", parse_http_req_capture }, { "reject", parse_http_action_reject }, + { "disable-l7-retry", parse_http_req_disable_l7_retry }, { "set-method", parse_set_req_line }, { "set-path", parse_set_req_line }, { "set-query", parse_set_req_line }, diff --git a/src/stream.c b/src/stream.c index 58e1cc11b..62c559847 100644 --- a/src/stream.c +++ b/src/stream.c @@ -2341,7 +2341,8 @@ redo: */ si_b->state = SI_ST_REQ; /* new connection requested */ si_b->conn_retries = s->be->conn_retries; - if (s->be->retry_type &~ PR_RE_CONN_FAILED) + if ((s->be->retry_type &~ PR_RE_CONN_FAILED) && + !(si_b->flags & SI_FL_D_L7_RETRY)) si_b->flags |= SI_FL_L7_RETRY; } }