From: Thierry FOURNIER Date: Sun, 27 Sep 2015 17:29:33 +0000 (+0200) Subject: MINOR: stream/applet: add use-service action X-Git-Tag: v1.6-dev6~31 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5a363e71b25eaa1cd5fab8d9532bcbb838140605;p=thirdparty%2Fhaproxy.git MINOR: stream/applet: add use-service action This new target can be called from the frontend or the backend. It is evaluated just before the backend choice and just before the server choice. So, the input stream or HTTP request can be forwarded to a server or to an internal service. --- diff --git a/include/proto/stream.h b/include/proto/stream.h index 1fea1ab1c4..1360f28685 100644 --- a/include/proto/stream.h +++ b/include/proto/stream.h @@ -307,6 +307,8 @@ static inline void stream_offer_buffers() __stream_offer_buffers(avail); } +void service_keywords_register(struct action_kw_list *kw_list); + #endif /* _PROTO_STREAM_H */ /* diff --git a/include/types/action.h b/include/types/action.h index ca0163fa6e..b97f9bf9a4 100644 --- a/include/types/action.h +++ b/include/types/action.h @@ -24,6 +24,7 @@ #include +#include #include enum act_from { @@ -101,6 +102,7 @@ struct act_rule { enum act_return (*action_ptr)(struct act_rule *rule, struct proxy *px, /* ptr to custom action */ struct session *sess, struct stream *s, int flags); struct action_kw *kw; + struct applet applet; /* used for the applet registration. */ union { struct { char *realm; diff --git a/include/types/applet.h b/include/types/applet.h index 799df91a33..21978bfd1e 100644 --- a/include/types/applet.h +++ b/include/types/applet.h @@ -53,6 +53,7 @@ struct appctx { unsigned int st2; /* output state for stats, unused by peers */ struct applet *applet; /* applet this context refers to */ void *owner; /* pointer to upper layer's entity (eg: stream interface) */ + struct act_rule *rule; /* rule associated with the applet. */ union { struct { diff --git a/src/stream.c b/src/stream.c index deb51e83cc..1310896839 100644 --- a/src/stream.c +++ b/src/stream.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -24,6 +25,7 @@ #include #include +#include #include #include #include @@ -58,6 +60,9 @@ struct list streams; /* list of streams waiting for at least one buffer */ struct list buffer_wq = LIST_HEAD_INIT(buffer_wq); +/* List of all use-service keywords. */ +static struct list service_keywords = LIST_HEAD_INIT(service_keywords); + /* This function is called from the session handler which detects the end of * handshake, in order to complete initialization of a valid stream. It must be * called with a session (which may be embryonic). It returns the pointer to @@ -1029,6 +1034,61 @@ static void sess_prepare_conn_req(struct stream *s) be_set_sess_last(s->be); } +/* This function parses the use-service action ruleset. It executes + * the associated ACL and set an applet as a stream or txn final node. + * it returns ACT_RET_ERR if an error occurs, the proxy left in + * consistent state. It returns ACT_RET_STOP in succes case because + * use-service must be a terminal action. Returns ACT_RET_YIELD + * if the initialisation function require more data. + */ +enum act_return process_use_service(struct act_rule *rule, struct proxy *px, + struct session *sess, struct stream *s, int flags) + +{ + struct appctx *appctx; + + /* Initialises the applet if it is required. */ + if (flags & ACT_FLAG_FIRST) { + /* Register applet. this function schedules the applet. */ + s->target = &rule->applet.obj_type; + if (unlikely(!stream_int_register_handler(&s->si[1], objt_applet(s->target)))) + return ACT_RET_ERR; + + /* Initialise the context. */ + appctx = si_appctx(&s->si[1]); + memset(&appctx->ctx, 0, sizeof(appctx->ctx)); + appctx->rule = rule; + } + else + appctx = si_appctx(&s->si[1]); + + /* Stops the applet sheduling, in case of the init function miss + * some data. + */ + appctx_pause(appctx); + si_applet_stop_get(&s->si[1]); + + /* Call initialisation. */ + if (rule->applet.init) + switch (rule->applet.init(appctx, px, s)) { + case 0: return ACT_RET_ERR; + case 1: break; + default: return ACT_RET_YIELD; + } + + /* Now we can schedule the applet. */ + si_applet_cant_get(&s->si[1]); + appctx_wakeup(appctx); + + if (sess->fe == s->be) /* report it if the request was intercepted by the frontend */ + sess->fe->fe_counters.intercepted_req++; + + /* The flag SF_ASSIGNED prevent from server assignment. */ + s->flags |= SF_ASSIGNED; + + return ACT_RET_STOP; +} + /* This stream analyser checks the switching rules and changes the backend * if appropriate. The default_backend rule is also considered, then the * target backend's forced persistence rules are also evaluated last if any. @@ -3248,6 +3308,55 @@ smp_fetch_table_avl(const struct arg *args, struct sample *smp, const char *kw, return 1; } +/* 0=OK, <0=Alert, >0=Warning */ +static enum act_parse_ret stream_parse_use_service(const char **args, int *cur_arg, + struct proxy *px, struct act_rule *rule, + char **err) +{ + struct action_kw *kw; + + /* Check if the service name exists. */ + if (*(args[*cur_arg]) == 0) { + memprintf(err, "'%s' expects a service name.", args[0]); + return -1; + } + + /* lookup for keyword corresponding to a service. */ + kw = action_lookup(&service_keywords, args[*cur_arg]); + if (!kw) { + memprintf(err, "'%s' unknown service name.", args[1]); + return ACT_RET_PRS_ERR; + } + (*cur_arg)++; + + /* executes specific rule parser. */ + rule->kw = kw; + if (kw->parse((const char **)args, cur_arg, px, rule, err) == ACT_RET_PRS_ERR) + return ACT_RET_PRS_ERR; + + /* Register processing function. */ + rule->action_ptr = process_use_service; + rule->action = ACT_CUSTOM; + + return ACT_RET_PRS_OK; +} + +void service_keywords_register(struct action_kw_list *kw_list) +{ + LIST_ADDQ(&service_keywords, &kw_list->list); +} + +/* main configuration keyword registration. */ +static struct action_kw_list stream_tcp_keywords = { ILH, { + { "use-service", stream_parse_use_service }, + { /* END */ } +}}; + +static struct action_kw_list stream_http_keywords = { ILH, { + { "use-service", stream_parse_use_service }, + { /* END */ } +}}; + /* Note: must not be declared as its list will be overwritten. * Please take care of keeping this list alphabetically sorted. */ @@ -3368,6 +3477,8 @@ static void __stream_init(void) { sample_register_fetches(&smp_fetch_keywords); acl_register_keywords(&acl_kws); + tcp_req_cont_keywords_register(&stream_tcp_keywords); + http_req_keywords_register(&stream_http_keywords); } /*