struct hdr_ctx ctx;
const char *auth_realm;
+ /* If "the current_rule_list" match the executed rule list, we are in
+ * resume condition. If a resume is needed it is always in the action
+ * and never in the ACL or converters. In this case, we initialise the
+ * current rule, and go to the action execution point.
+ */
+ if (s->current_rule_list == rules) {
+ rule = LIST_ELEM(s->current_rule, typeof(rule), list);
+ goto resume_execution;
+ }
+ s->current_rule_list = rules;
list_for_each_entry(rule, rules, list) {
if (rule->action >= HTTP_REQ_ACT_MAX)
continue;
continue;
}
+resume_execution:
switch (rule->action) {
case HTTP_REQ_ACT_ALLOW:
}
case HTTP_REQ_ACT_CUSTOM_CONT:
- rule->action_ptr(rule, px, s, txn);
+ if (!rule->action_ptr(rule, px, s, txn)) {
+ s->current_rule = &rule->list;
+ return HTTP_RULE_RES_YIELD;
+ }
break;
case HTTP_REQ_ACT_CUSTOM_STOP:
struct http_res_rule *rule;
struct hdr_ctx ctx;
+ /* If "the current_rule_list" match the executed rule list, we are in
+ * resume condition. If a resume is needed it is always in the action
+ * and never in the ACL or converters. In this case, we initialise the
+ * current rule, and go to the action execution point.
+ */
+ if (s->current_rule_list == rules) {
+ rule = LIST_ELEM(s->current_rule, typeof(rule), list);
+ goto resume_execution;
+ }
+ s->current_rule_list = rules;
list_for_each_entry(rule, rules, list) {
if (rule->action >= HTTP_RES_ACT_MAX)
continue;
continue;
}
+resume_execution:
switch (rule->action) {
case HTTP_RES_ACT_ALLOW:
}
case HTTP_RES_ACT_CUSTOM_CONT:
- rule->action_ptr(rule, px, s, txn);
+ if (!rule->action_ptr(rule, px, s, txn)) {
+ s->current_rule = &rule->list;
+ return HTTP_RULE_RES_YIELD;
+ }
break;
case HTTP_RES_ACT_CUSTOM_STOP:
if (unlikely(msg->msg_state < HTTP_MSG_BODY)) {
/* we need more data */
- channel_dont_connect(req);
- return 0;
+ goto return_prx_yield;
}
DPRINTF(stderr,"[%u] %s: session=%p b=%p, exp(r,w)=%u,%u bf=%08x bh=%d analysers=%02x\n",
verdict = http_req_get_intercept_rule(px, &px->http_req_rules, s, txn);
switch (verdict) {
+ case HTTP_RULE_RES_YIELD: /* some data miss, call the function later. */
+ goto return_prx_yield;
+
case HTTP_RULE_RES_CONT:
case HTTP_RULE_RES_STOP: /* nothing to do */
break;
req->analysers = 0;
req->analyse_exp = TICK_ETERNITY;
return 0;
+
+ return_prx_yield:
+ channel_dont_connect(req);
+ return 0;
}
/* This function performs all the processing enabled for the current request.
if (unlikely(msg->msg_state < HTTP_MSG_BODY)) /* we need more data */
return 0;
- rep->analysers &= ~an_bit;
- rep->analyse_exp = TICK_ETERNITY;
-
/* The stats applet needs to adjust the Connection header but we don't
* apply any filter there.
*/
*
* Filters are tried with ->be first, then with ->fe if it is
* different from ->be.
+ *
+ * Maybe we are in resume condiion. In this case I choose the
+ * "struct proxy" which contains the rule list matching the resume
+ * pointer. If none of theses "struct proxy" match, I initialise
+ * the process with the first one.
+ *
+ * In fact, I check only correspondance betwwen the current list
+ * pointer and the ->fe rule list. If it doesn't match, I initialize
+ * the loop with the ->be.
*/
-
- cur_proxy = s->be;
+ if (s->current_rule_list == &s->fe->http_res_rules)
+ cur_proxy = s->fe;
+ else
+ cur_proxy = s->be;
while (1) {
struct proxy *rule_set = cur_proxy;
if (ret == HTTP_RULE_RES_CONT)
ret = http_res_get_intercept_rule(cur_proxy, &cur_proxy->http_res_rules, s, txn);
+ /* we need to be called again. */
+ if (ret == HTTP_RULE_RES_YIELD) {
+ channel_dont_close(rep);
+ return 0;
+ }
+
/* try headers filters */
if (rule_set->rsp_exp != NULL) {
if (apply_filters_to_response(s, rep, rule_set) < 0) {
cur_proxy = s->fe;
}
+ /* After this point, this anayzer can't return yield, so we can
+ * remove the bit corresponding to this analyzer from the list.
+ *
+ * Note that the intermediate returns and goto found previously
+ * reset the analyzers.
+ */
+ rep->analysers &= ~an_bit;
+ rep->analyse_exp = TICK_ETERNITY;
+
/* OK that's all we can do for 1xx responses */
if (unlikely(txn->status < 200 && txn->status != 101))
goto skip_header_mangling;
http_end_txn(s);
http_init_txn(s);
+ /* reinitialise the current rule list pointer to NULL. We are sure that
+ * any rulelist match the NULL pointer.
+ */
+ s->current_rule_list = NULL;
+
s->be = s->fe;
s->logs.logwait = s->fe->to_log;
s->logs.level = 0;
else
partial = 0;
+ /* If "the current_rule_list" match the executed rule list, we are in
+ * resume condition. If a resume is needed it is always in the action
+ * and never in the ACL or converters. In this case, we initialise the
+ * current rule, and go to the action execution point.
+ */
+ if (s->current_rule_list == &s->be->tcp_req.inspect_rules) {
+ rule = LIST_ELEM(s->current_rule, typeof(rule), list);
+ goto resume_execution;
+ }
+ s->current_rule_list = &s->be->tcp_req.inspect_rules;
list_for_each_entry(rule, &s->be->tcp_req.inspect_rules, list) {
enum acl_test_res ret = ACL_TEST_PASS;
}
if (ret) {
+
+resume_execution:
+
/* we have a matching rule. */
if (rule->action == TCP_ACT_REJECT) {
channel_abort(req);
}
else {
/* Custom keywords. */
- if (rule->action_ptr(rule, s->be, s) == 0)
+ if (rule->action_ptr(rule, s->be, s) == 0) {
+ s->current_rule = &rule->list;
goto missing_data;
+ }
/* otherwise accept */
break;
else
partial = 0;
+ /* If "the current_rule_list" match the executed rule list, we are in
+ * resume condition. If a resume is needed it is always in the action
+ * and never in the ACL or converters. In this case, we initialise the
+ * current rule, and go to the action execution point.
+ */
+ if (s->current_rule_list == &s->be->tcp_rep.inspect_rules) {
+ rule = LIST_ELEM(s->current_rule, typeof(rule), list);
+ goto resume_execution;
+ }
+ s->current_rule_list = &s->be->tcp_rep.inspect_rules;
list_for_each_entry(rule, &s->be->tcp_rep.inspect_rules, list) {
enum acl_test_res ret = ACL_TEST_PASS;
}
if (ret) {
+
+resume_execution:
+
/* we have a matching rule. */
if (rule->action == TCP_ACT_REJECT) {
channel_abort(rep);
}
else {
/* Custom keywords. */
- rule->action_ptr(rule, s->be, s);
+ if (!rule->action_ptr(rule, s->be, s)) {
+ channel_dont_close(rep);
+ s->current_rule = &rule->list;
+ return 0;
+ }
/* otherwise accept */
break;