mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-02-21 05:06:56 +00:00
MEDIUM: http/tcp: permit to resume http and tcp custom actions
Later, the processing of some actions needs to be interrupted and resumed later. This patch permit to resume the actions. The actions that needs to run with the resume mode are not yet avalaible. It will be soon with Lua patches. So the code added by this patch is untestable for the moment. The list of "tcp_exec_req_rules" cannot resme because is called by the unresumable function "accept_session".
This commit is contained in:
parent
9e2ef999a9
commit
bc4c1ac6ad
@ -294,6 +294,7 @@ enum {
|
||||
/* final results for http-request rules */
|
||||
enum rule_result {
|
||||
HTTP_RULE_RES_CONT = 0, /* nothing special, continue rules evaluation */
|
||||
HTTP_RULE_RES_YIELD, /* call me later because some data is missing. */
|
||||
HTTP_RULE_RES_STOP, /* stopped processing on an accept */
|
||||
HTTP_RULE_RES_DENY, /* deny (or tarpit if TX_CLTARPIT) */
|
||||
HTTP_RULE_RES_ABRT, /* abort request, msg already sent (eg: auth) */
|
||||
|
@ -156,6 +156,10 @@ struct session {
|
||||
struct comp_ctx *comp_ctx; /* HTTP compression context */
|
||||
struct comp_algo *comp_algo; /* HTTP compression algorithm if not NULL */
|
||||
char *unique_id; /* custom unique ID */
|
||||
|
||||
/* These two pointers are used to resume the execution of the rule lists. */
|
||||
struct list *current_rule_list; /* this is used to store the current executed rule list. */
|
||||
struct list *current_rule; /* this is used to store the current rule to be resumed. */
|
||||
};
|
||||
|
||||
#endif /* _TYPES_SESSION_H */
|
||||
|
@ -3370,6 +3370,16 @@ http_req_get_intercept_rule(struct proxy *px, struct list *rules, struct session
|
||||
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;
|
||||
@ -3388,6 +3398,7 @@ http_req_get_intercept_rule(struct proxy *px, struct list *rules, struct session
|
||||
continue;
|
||||
}
|
||||
|
||||
resume_execution:
|
||||
|
||||
switch (rule->action) {
|
||||
case HTTP_REQ_ACT_ALLOW:
|
||||
@ -3567,7 +3578,10 @@ http_req_get_intercept_rule(struct proxy *px, struct list *rules, struct session
|
||||
}
|
||||
|
||||
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:
|
||||
@ -3629,6 +3643,16 @@ http_res_get_intercept_rule(struct proxy *px, struct list *rules, struct session
|
||||
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;
|
||||
@ -3647,6 +3671,7 @@ http_res_get_intercept_rule(struct proxy *px, struct list *rules, struct session
|
||||
continue;
|
||||
}
|
||||
|
||||
resume_execution:
|
||||
|
||||
switch (rule->action) {
|
||||
case HTTP_RES_ACT_ALLOW:
|
||||
@ -3798,7 +3823,10 @@ http_res_get_intercept_rule(struct proxy *px, struct list *rules, struct session
|
||||
}
|
||||
|
||||
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:
|
||||
@ -4085,8 +4113,7 @@ int http_process_req_common(struct session *s, struct channel *req, int an_bit,
|
||||
|
||||
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",
|
||||
@ -4106,6 +4133,9 @@ int http_process_req_common(struct session *s, struct channel *req, int an_bit,
|
||||
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;
|
||||
@ -4302,6 +4332,10 @@ int http_process_req_common(struct session *s, struct channel *req, int an_bit,
|
||||
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.
|
||||
@ -6300,9 +6334,6 @@ int http_process_res_common(struct session *s, struct channel *rep, int an_bit,
|
||||
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.
|
||||
*/
|
||||
@ -6317,9 +6348,20 @@ int http_process_res_common(struct session *s, struct channel *rep, int an_bit,
|
||||
*
|
||||
* 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;
|
||||
|
||||
@ -6327,6 +6369,12 @@ int http_process_res_common(struct session *s, struct channel *rep, int an_bit,
|
||||
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) {
|
||||
@ -6386,6 +6434,15 @@ int http_process_res_common(struct session *s, struct channel *rep, int an_bit,
|
||||
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;
|
||||
@ -8842,6 +8899,11 @@ void http_reset_txn(struct session *s)
|
||||
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;
|
||||
|
@ -1119,6 +1119,16 @@ int tcp_inspect_request(struct session *s, struct channel *req, int an_bit)
|
||||
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;
|
||||
|
||||
@ -1133,6 +1143,9 @@ int tcp_inspect_request(struct session *s, struct channel *req, int an_bit)
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
|
||||
resume_execution:
|
||||
|
||||
/* we have a matching rule. */
|
||||
if (rule->action == TCP_ACT_REJECT) {
|
||||
channel_abort(req);
|
||||
@ -1201,8 +1214,10 @@ int tcp_inspect_request(struct session *s, struct channel *req, int an_bit)
|
||||
}
|
||||
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;
|
||||
@ -1261,6 +1276,16 @@ int tcp_inspect_response(struct session *s, struct channel *rep, int an_bit)
|
||||
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;
|
||||
|
||||
@ -1279,6 +1304,9 @@ int tcp_inspect_response(struct session *s, struct channel *rep, int an_bit)
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
|
||||
resume_execution:
|
||||
|
||||
/* we have a matching rule. */
|
||||
if (rule->action == TCP_ACT_REJECT) {
|
||||
channel_abort(rep);
|
||||
@ -1304,7 +1332,11 @@ int tcp_inspect_response(struct session *s, struct channel *rep, int an_bit)
|
||||
}
|
||||
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;
|
||||
|
@ -108,6 +108,11 @@ int session_accept(struct listener *l, int cfd, struct sockaddr_storage *addr)
|
||||
s->logs.logwait = p->to_log;
|
||||
s->logs.level = 0;
|
||||
|
||||
/* Initialise the current rule list pointer to NULL. We are sure that
|
||||
* any rulelist match the NULL pointer.
|
||||
*/
|
||||
s->current_rule_list = NULL;
|
||||
|
||||
memset(s->stkctr, 0, sizeof(s->stkctr));
|
||||
|
||||
s->listener = l;
|
||||
|
Loading…
Reference in New Issue
Block a user