MEDIUM: http-ana: Eval HTTP rules defined in defaults sections
As for TCP rules, HTTP rules from defaults section are now evaluated. These
rules are evaluated before those of the proxy. The same default ruleset
cannot be attached to the frontend and the backend. However, at this stage,
we take care to not execute twice the same ruleset. So, in theory, a
frontend and a backend could use the same defaults section. In this case,
the default ruleset is executed before all others and only once.
diff --git a/src/http_ana.c b/src/http_ana.c
index 2033d46..d3dfcf5 100644
--- a/src/http_ana.c
+++ b/src/http_ana.c
@@ -56,8 +56,8 @@
static void http_debug_stline(const char *dir, struct stream *s, const struct htx_sl *sl);
static void http_debug_hdr(const char *dir, struct stream *s, const struct ist n, const struct ist v);
-static enum rule_result http_req_get_intercept_rule(struct proxy *px, struct list *rules, struct stream *s);
-static enum rule_result http_res_get_intercept_rule(struct proxy *px, struct list *rules, struct stream *s);
+static enum rule_result http_req_get_intercept_rule(struct proxy *px, struct list *def_rules, struct list *rules, struct stream *s);
+static enum rule_result http_res_get_intercept_rule(struct proxy *px, struct list *def_rules, struct list *rules, struct stream *s);
static void http_manage_client_side_cookies(struct stream *s, struct channel *req);
static void http_manage_server_side_cookies(struct stream *s, struct channel *res);
@@ -351,6 +351,7 @@
*/
int http_process_req_common(struct stream *s, struct channel *req, int an_bit, struct proxy *px)
{
+ struct list *def_rules, *rules;
struct session *sess = s->sess;
struct http_txn *txn = s->txn;
struct http_msg *msg = &txn->req;
@@ -365,12 +366,15 @@
/* just in case we have some per-backend tracking. Only called the first
* execution of the analyser. */
- if (!s->current_rule || s->current_rule_list != &px->http_req_rules)
+ if (!s->current_rule && !s->current_rule_list)
stream_inc_be_http_req_ctr(s);
+ def_rules = ((px->defpx && (an_bit == AN_REQ_HTTP_PROCESS_FE || px != sess->fe)) ? &px->defpx->http_req_rules : NULL);
+ rules = &px->http_req_rules;
+
/* evaluate http-request rules */
- if (!LIST_ISEMPTY(&px->http_req_rules)) {
- verdict = http_req_get_intercept_rule(px, &px->http_req_rules, s);
+ if ((def_rules && !LIST_ISEMPTY(def_rules)) || !LIST_ISEMPTY(rules)) {
+ verdict = http_req_get_intercept_rule(px, def_rules, rules, s);
switch (verdict) {
case HTTP_RULE_RES_YIELD: /* some data miss, call the function later. */
@@ -427,7 +431,7 @@
/* parse the whole stats request and extract the relevant information */
http_handle_stats(s, req);
- verdict = http_req_get_intercept_rule(px, &px->uri_auth->http_req_rules, s);
+ verdict = http_req_get_intercept_rule(px, NULL, &px->uri_auth->http_req_rules, s);
/* not all actions implemented: deny, allow, auth */
if (verdict == HTTP_RULE_RES_DENY) /* stats http-request deny */
@@ -501,6 +505,7 @@
req->analyse_exp = TICK_ETERNITY;
done_without_exp: /* done with this analyser, but don't reset the analyse_exp. */
req->analysers &= ~an_bit;
+ s->current_rule = s->current_rule_list = NULL;
DBG_TRACE_LEAVE(STRM_EV_STRM_ANA|STRM_EV_HTTP_ANA, s, txn);
return 1;
@@ -581,6 +586,7 @@
req->analysers &= AN_REQ_FLT_END;
req->analyse_exp = TICK_ETERNITY;
+ s->current_rule = s->current_rule_list = NULL;
DBG_TRACE_DEVEL("leaving on error",
STRM_EV_STRM_ANA|STRM_EV_HTTP_ANA|STRM_EV_HTTP_ERR, s, txn);
return 0;
@@ -1797,14 +1803,21 @@
* pointer and the ->fe rule list. If it doesn't match, I initialize
* the loop with the ->be.
*/
- if (s->current_rule_list == &sess->fe->http_res_rules)
+ if (s->current_rule_list == &sess->fe->http_res_rules ||
+ (sess->fe->defpx && s->current_rule_list == &sess->fe->defpx->http_res_rules))
cur_proxy = sess->fe;
else
cur_proxy = s->be;
+
while (1) {
/* evaluate http-response rules */
if (ret == HTTP_RULE_RES_CONT) {
- ret = http_res_get_intercept_rule(cur_proxy, &cur_proxy->http_res_rules, s);
+ struct list *def_rules, *rules;
+
+ def_rules = ((cur_proxy->defpx && (cur_proxy == s->be || cur_proxy->defpx != s->be->defpx)) ? &cur_proxy->defpx->http_res_rules : NULL);
+ rules = &cur_proxy->http_res_rules;
+
+ ret = http_res_get_intercept_rule(cur_proxy, def_rules, rules, s);
switch (ret) {
case HTTP_RULE_RES_YIELD: /* some data miss, call the function later. */
@@ -1992,6 +2005,7 @@
DBG_TRACE_LEAVE(STRM_EV_STRM_ANA|STRM_EV_HTTP_ANA, s, txn);
rep->analysers &= ~an_bit;
rep->analyse_exp = TICK_ETERNITY;
+ s->current_rule = s->current_rule_list = NULL;
return 1;
deny:
@@ -2041,6 +2055,7 @@
rep->analysers &= AN_RES_FLT_END;
s->req.analysers &= AN_REQ_FLT_END;
rep->analyse_exp = TICK_ETERNITY;
+ s->current_rule = s->current_rule_list = NULL;
DBG_TRACE_DEVEL("leaving on error",
STRM_EV_STRM_ANA|STRM_EV_HTTP_ANA|STRM_EV_HTTP_ERR, s, txn);
return 0;
@@ -2673,8 +2688,8 @@
* and a deny/tarpit rule is matched, it will be filled with this rule's deny
* status.
*/
-static enum rule_result http_req_get_intercept_rule(struct proxy *px, struct list *rules,
- struct stream *s)
+static enum rule_result http_req_get_intercept_rule(struct proxy *px, struct list *def_rules,
+ struct list *rules, struct stream *s)
{
struct session *sess = strm_sess(s);
struct http_txn *txn = s->txn;
@@ -2690,15 +2705,16 @@
if (s->current_rule) {
rule = s->current_rule;
s->current_rule = NULL;
- if (s->current_rule_list == rules)
+ if (s->current_rule_list == rules || (def_rules && s->current_rule_list == def_rules))
goto resume_execution;
}
- s->current_rule_list = rules;
+ s->current_rule_list = ((!def_rules || s->current_rule_list == def_rules) ? rules : def_rules);
+ restart:
/* start the ruleset evaluation in strict mode */
txn->req.flags &= ~HTTP_MSGF_SOFT_RW;
- list_for_each_entry(rule, rules, list) {
+ list_for_each_entry(rule, s->current_rule_list, list) {
/* check optional condition */
if (rule->cond) {
int ret;
@@ -2791,6 +2807,11 @@
}
}
+ if (def_rules && s->current_rule_list == def_rules) {
+ s->current_rule_list = rules;
+ goto restart;
+ }
+
end:
/* if the ruleset evaluation is finished reset the strict mode */
if (rule_ret != HTTP_RULE_RES_YIELD)
@@ -2809,8 +2830,8 @@
* must be returned. If *YIELD is returned, the caller must call again the
* function with the same context.
*/
-static enum rule_result http_res_get_intercept_rule(struct proxy *px, struct list *rules,
- struct stream *s)
+static enum rule_result http_res_get_intercept_rule(struct proxy *px, struct list *def_rules,
+ struct list *rules, struct stream *s)
{
struct session *sess = strm_sess(s);
struct http_txn *txn = s->txn;
@@ -2826,15 +2847,17 @@
if (s->current_rule) {
rule = s->current_rule;
s->current_rule = NULL;
- if (s->current_rule_list == rules)
+ if (s->current_rule_list == rules || (def_rules && s->current_rule_list == def_rules))
goto resume_execution;
}
- s->current_rule_list = rules;
+ s->current_rule_list = ((!def_rules || s->current_rule_list == def_rules) ? rules : def_rules);
+
+ restart:
/* start the ruleset evaluation in strict mode */
txn->rsp.flags &= ~HTTP_MSGF_SOFT_RW;
- list_for_each_entry(rule, rules, list) {
+ list_for_each_entry(rule, s->current_rule_list, list) {
/* check optional condition */
if (rule->cond) {
int ret;
@@ -2919,6 +2942,11 @@
}
}
+ if (def_rules && s->current_rule_list == def_rules) {
+ s->current_rule_list = rules;
+ goto restart;
+ }
+
end:
/* if the ruleset evaluation is finished reset the strict mode */
if (rule_ret != HTTP_RULE_RES_YIELD)
@@ -2935,6 +2963,7 @@
*/
int http_eval_after_res_rules(struct stream *s)
{
+ struct list *def_rules, *rules;
struct session *sess = s->sess;
enum rule_result ret = HTTP_RULE_RES_CONT;
@@ -2949,9 +2978,16 @@
vars_init_head(&s->vars_reqres, SCOPE_RES);
}
- ret = http_res_get_intercept_rule(s->be, &s->be->http_after_res_rules, s);
- if (ret == HTTP_RULE_RES_CONT && sess->fe != s->be)
- ret = http_res_get_intercept_rule(sess->fe, &sess->fe->http_after_res_rules, s);
+
+ def_rules = (s->be->defpx ? &s->be->defpx->http_after_res_rules : NULL);
+ rules = &s->be->http_after_res_rules;
+
+ ret = http_res_get_intercept_rule(s->be, def_rules, rules, s);
+ if (ret == HTTP_RULE_RES_CONT && sess->fe != s->be) {
+ def_rules = ((sess->fe->defpx && sess->fe->defpx != s->be->defpx) ? &sess->fe->defpx->http_after_res_rules : NULL);
+ rules = &sess->fe->http_after_res_rules;
+ ret = http_res_get_intercept_rule(sess->fe, def_rules, rules, s);
+ }
end:
/* All other codes than CONTINUE, STOP or DONE are forbidden */