diff --git a/doc/configuration.txt b/doc/configuration.txt index 24ba9bd12..6c0faac05 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -4828,6 +4828,21 @@ http-request silent-drop [ { if | unless } ] router, though it's still delivered to local networks. Do not use it unless you fully understand how it works. +http-request strict-mode { on | off } + + This enables or disables the strict rewriting mode for following rules. It + does not affect rules declared before it and it is only applicable on rules + performing a rewrite on the requests. When the strict mode is enabled, any + rewrite failure triggers an internal error. Otherwise, such errors are + silently ignored. The purpose of the strict rewriting mode is to make some + rewrites optionnal while others must be performed to continue the request + processing. + + By default, the strict rewriting mode is disabled. Its value is also reset + when a ruleset evaluation ends. So, for instance, if you change the mode on + the frontend, the default mode is restored when HAProxy starts the backend + rules evaluation. + http-request tarpit [deny_status ] [ { if | unless } ] This stops the evaluation of the rules and immediately blocks the request @@ -5216,6 +5231,21 @@ http-response silent-drop [ { if | unless } ] router, though it's still delivered to local networks. Do not use it unless you fully understand how it works. +http-response strict-mode { on | off } + + This enables or disables the strict rewriting mode for following rules. It + does not affect rules declared before it and it is only applicable on rules + performing a rewrite on the responses. When the strict mode is enabled, any + rewrite failure triggers an internal error. Otherwise, such errors are + silently ignored. The purpose of the strict rewriting mode is to make some + rewrites optionnal while others must be performed to continue the response + processing. + + By default, the strict rewriting mode is disabled. Its value is also reset + when a ruleset evaluation ends. So, for instance, if you change the mode on + the bacnkend, the default mode is restored when HAProxy starts the frontend + rules evaluation. + http-response track-sc0 [table ] [ { if | unless } ] http-response track-sc1 [table
] [ { if | unless } ] http-response track-sc2 [table
] [ { if | unless } ] diff --git a/src/http_act.c b/src/http_act.c index f199e3b6b..cf0d8bf84 100644 --- a/src/http_act.c +++ b/src/http_act.c @@ -1211,6 +1211,50 @@ static enum act_parse_ret parse_http_track_sc(const char **args, int *orig_arg, return ACT_RET_PRS_OK; } +/* This function executes a strict-mode actions. On success, it always returns + * ACT_RET_CONT + */ +static enum act_return http_action_strict_mode(struct act_rule *rule, struct proxy *px, + struct session *sess, struct stream *s, int flags) +{ + struct http_msg *msg = ((rule->from == ACT_F_HTTP_REQ) ? &s->txn->req : &s->txn->rsp); + + if (rule->action == 0) // strict-mode on + msg->flags &= ~HTTP_MSGF_SOFT_RW; + else // strict-mode off + msg->flags |= HTTP_MSGF_SOFT_RW; + return ACT_RET_CONT; +} + +/* Parse a "strict-mode" action. It returns ACT_RET_PRS_OK on success, + * ACT_RET_PRS_ERR on error. + */ +static enum act_parse_ret parse_http_strict_mode(const char **args, int *orig_arg, struct proxy *px, + struct act_rule *rule, char **err) +{ + int cur_arg; + + + cur_arg = *orig_arg; + if (!*args[cur_arg]) { + memprintf(err, "expects exactly 1 arguments"); + return ACT_RET_PRS_ERR; + } + + if (strcasecmp(args[cur_arg], "on") == 0) + rule->action = 0; // strict-mode on + else if (strcasecmp(args[cur_arg], "off") == 0) + rule->action = 1; // strict-mode off + else { + memprintf(err, "Unexpected value '%s'. Only 'on' and 'off' are supported", args[cur_arg]); + return ACT_RET_PRS_ERR; + } + rule->action_ptr = http_action_strict_mode; + + *orig_arg = cur_arg + 1; + return ACT_RET_PRS_OK; +} + /************************************************************************/ /* All supported http-request action keywords must be declared here. */ /************************************************************************/ @@ -1244,6 +1288,7 @@ static struct action_kw_list http_req_actions = { { "set-query", parse_set_req_line, 0 }, { "set-tos", parse_http_set_tos, 0 }, { "set-uri", parse_set_req_line, 0 }, + { "strict-mode", parse_http_strict_mode, 0 }, { "tarpit", parse_http_req_deny, 0 }, { "track-sc", parse_http_track_sc, 1 }, { NULL, NULL } @@ -1272,6 +1317,7 @@ static struct action_kw_list http_res_actions = { { "set-nice", parse_http_set_nice, 0 }, { "set-status", parse_http_set_status, 0 }, { "set-tos", parse_http_set_tos, 0 }, + { "strict-mode", parse_http_strict_mode, 0 }, { "track-sc", parse_http_track_sc, 1 }, { NULL, NULL } } diff --git a/src/http_ana.c b/src/http_ana.c index f80da9a98..fa418bb5d 100644 --- a/src/http_ana.c +++ b/src/http_ana.c @@ -2943,6 +2943,9 @@ static enum rule_result http_req_get_intercept_rule(struct proxy *px, struct lis } s->current_rule_list = rules; + /* start the ruleset evaluation in soft mode */ + txn->req.flags |= HTTP_MSGF_SOFT_RW; + list_for_each_entry(rule, rules, list) { /* check optional condition */ if (rule->cond) { @@ -3309,6 +3312,10 @@ static enum rule_result http_req_get_intercept_rule(struct proxy *px, struct lis rule_ret = HTTP_RULE_RES_ERROR; } + /* if the ruleset evaluation is finished reset the soft mode */ + if (rule_ret != HTTP_RULE_RES_YIELD) + txn->req.flags |= HTTP_MSGF_SOFT_RW; + /* we reached the end of the rules, nothing to report */ return rule_ret; } @@ -3349,6 +3356,9 @@ static enum rule_result http_res_get_intercept_rule(struct proxy *px, struct lis } s->current_rule_list = rules; + /* start the ruleset evaluation in soft mode */ + txn->rsp.flags |= HTTP_MSGF_SOFT_RW; + list_for_each_entry(rule, rules, list) { /* check optional condition */ if (rule->cond) { @@ -3671,6 +3681,10 @@ resume_execution: } end: + /* if the ruleset evaluation is finished reset the soft mode */ + if (rule_ret != HTTP_RULE_RES_YIELD) + txn->rsp.flags |= HTTP_MSGF_SOFT_RW; + /* we reached the end of the rules, nothing to report */ return rule_ret; }