MINOR: cache: Improve and simplify the cache configuration check

To do so, a dedicated configuration has been added on cache filters. Before the
cache filter configuration pointed directly to the cache it used. Now, it is the
dedicated structure cache_flt_conf. Store and use rules also point to this
structure. It is linked to the cache the filter must used. It also contains a
flags field. This will allow us to define the behavior of a cache filter when a
response is stored in the cache or delivered from it.

And now, Store and use rules uses a common parsing function. So if it does not
already exists, a filter is always created for both kind of rules. The cache
filters configuration is checked using their check callback. In the postparser
function, we only check the caches configuration. This removes the loop on all
proxies in the postparser function.
diff --git a/src/cache.c b/src/cache.c
index 3b266fb..d52fcf5 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -59,6 +59,15 @@
 	unsigned int flags;      /* CACHE_F_* */
 };
 
+/* cache config for filters */
+struct cache_flt_conf {
+	union {
+		struct cache *cache; /* cache used by the filter */
+		char *name;          /* cache name used during conf parsing */
+	} c;
+	unsigned int flags;   /* CACHE_FLT_F_* */
+};
+
 /*
  * cache ctx for filters
  */
@@ -133,7 +142,43 @@
 	return 0;
 }
 
+static void
+cache_store_deinit(struct proxy *px, struct flt_conf *fconf)
+{
+	struct cache_flt_conf *cconf = fconf->conf;
+
+	free(cconf);
+}
+
 static int
+cache_store_check(struct proxy *px, struct flt_conf *fconf)
+{
+	struct cache_flt_conf *cconf = fconf->conf;
+	struct cache *cache;
+
+	/* resolve the cache name to a ptr in the filter config */
+	list_for_each_entry(cache, &caches, list) {
+		if (!strcmp(cache->id, cconf->c.name)) {
+			/* there can be only one filter per cache, so we free it there */
+			cache->flags |= ((px->options2 & PR_O2_USE_HTX)
+					 ? CACHE_F_HTX
+					 : CACHE_F_LEGACY_HTTP);
+
+			free(cconf->c.name);
+			cconf->c.cache = cache;
+			goto found;
+		}
+	}
+
+	ha_alert("config: %s '%s': unable to find the cache '%s' referenced by the filter 'cache'.\n",
+		 proxy_type_str(px), px->id, (char *)cconf->c.name);
+	return 1;
+
+  found:
+	return 0;
+}
+
+static int
 cache_store_chn_start_analyze(struct stream *s, struct filter *filter, struct channel *chn)
 {
 	if (!(chn->flags & CF_ISRESP))
@@ -158,7 +203,8 @@
 cache_store_chn_end_analyze(struct stream *s, struct filter *filter, struct channel *chn)
 {
 	struct cache_st *st = filter->ctx;
-	struct cache *cache = filter->config->conf;
+	struct cache_flt_conf *cconf = FLT_CONF(filter);
+	struct cache *cache = cconf->c.cache;
 	struct shared_context *shctx = shctx_ptr(cache);
 
 	if (!(chn->flags & CF_ISRESP))
@@ -217,7 +263,8 @@
 cache_store_http_payload(struct stream *s, struct filter *filter, struct http_msg *msg,
 			 unsigned int offset, unsigned int len)
 {
-	struct shared_context *shctx = shctx_ptr((struct cache *)filter->config->conf);
+	struct cache_flt_conf *cconf = FLT_CONF(filter);
+	struct shared_context *shctx = shctx_ptr(cconf->c.cache);
 	struct cache_st *st = filter->ctx;
 	struct htx *htx = htxbuf(&msg->chn->buf);
 	struct htx_blk *blk;
@@ -301,7 +348,8 @@
 		       struct http_msg *msg, unsigned int len)
 {
 	struct cache_st *st = filter->ctx;
-	struct shared_context *shctx = shctx_ptr((struct cache *)filter->config->conf);
+	struct cache_flt_conf *cconf = FLT_CONF(filter);
+	struct shared_context *shctx = shctx_ptr(cconf->c.cache);
 	int ret;
 
 	ret = 0;
@@ -375,7 +423,8 @@
                      struct http_msg *msg)
 {
 	struct cache_st *st = filter->ctx;
-	struct cache *cache = filter->config->conf;
+	struct cache_flt_conf *cconf = FLT_CONF(filter);
+	struct cache *cache = cconf->c.cache;
 	struct shared_context *shctx = shctx_ptr(cache);
 	struct cache_entry *object;
 
@@ -525,8 +574,8 @@
 	struct http_msg *msg = &txn->rsp;
 	struct filter *filter;
 	struct shared_block *first = NULL;
-	struct cache *cache = (struct cache *)rule->arg.act.p[0];
-	struct shared_context *shctx = shctx_ptr(cache);
+	struct cache_flt_conf *cconf = rule->arg.act.p[0];
+	struct shared_context *shctx = shctx_ptr(cconf->c.cache);
 	struct cache_entry *object;
 
 	/* Don't cache if the response came from a cache */
@@ -665,35 +714,32 @@
 	}
 
 	/* register the buffer in the filter ctx for filling it with data*/
-	if (!LIST_ISEMPTY(&s->strm_flt.filters)) {
-		list_for_each_entry(filter, &s->strm_flt.filters, list) {
-			if (filter->config->id == cache_store_flt_id  &&
-			    filter->config->conf == rule->arg.act.p[0]) {
-				if (filter->ctx) {
-					struct cache_st *cache_ctx = filter->ctx;
-					struct cache_entry *old;
+	list_for_each_entry(filter, &s->strm_flt.filters, list) {
+		if (FLT_ID(filter) == cache_store_flt_id  && FLT_CONF(filter) == cconf) {
+			if (filter->ctx) {
+				struct cache_st *cache_ctx = filter->ctx;
+				struct cache_entry *old;
 
-					cache_ctx->first_block = first;
+				cache_ctx->first_block = first;
 
-					object->eb.key = (*(unsigned int *)&txn->cache_hash);
-					memcpy(object->hash, txn->cache_hash, sizeof(object->hash));
-					/* Insert the node later on caching success */
+				object->eb.key = (*(unsigned int *)&txn->cache_hash);
+				memcpy(object->hash, txn->cache_hash, sizeof(object->hash));
+				/* Insert the node later on caching success */
 
-					shctx_lock(shctx);
-
-					old = entry_exist(cache, txn->cache_hash);
-					if (old) {
-						eb32_delete(&old->eb);
-						old->eb.key = 0;
-					}
-					shctx_unlock(shctx);
+				shctx_lock(shctx);
 
-					/* store latest value and expiration time */
-					object->latest_validation = now.tv_sec;
-					object->expire = now.tv_sec + http_calc_maxage(s, cache);
+				old = entry_exist(cconf->c.cache, txn->cache_hash);
+				if (old) {
+					eb32_delete(&old->eb);
+					old->eb.key = 0;
 				}
-				return ACT_RET_CONT;
+				shctx_unlock(shctx);
+
+				/* store latest value and expiration time */
+				object->latest_validation = now.tv_sec;
+				object->expire = now.tv_sec + http_calc_maxage(s, cconf->c.cache);
 			}
+			return ACT_RET_CONT;
 		}
 	}
 
@@ -725,8 +771,9 @@
 
 static void http_cache_applet_release(struct appctx *appctx)
 {
-	struct cache *cache = (struct cache *)appctx->rule->arg.act.p[0];
+	struct cache_flt_conf *cconf = appctx->rule->arg.act.p[0];
 	struct cache_entry *cache_ptr = appctx->ctx.cache.entry;
+	struct cache *cache = cconf->c.cache;
 	struct shared_block *first = block_ptr(cache_ptr);
 
 	shctx_lock(shctx_ptr(cache));
@@ -736,8 +783,8 @@
 
 static size_t htx_cache_dump_headers(struct appctx *appctx, struct htx *htx)
 {
-	struct cache *cache = appctx->rule->arg.act.p[0];
-	struct shared_context *shctx = shctx_ptr(cache);
+	struct cache_flt_conf *cconf = appctx->rule->arg.act.p[0];
+	struct shared_context *shctx = shctx_ptr(cconf->c.cache);
 	struct cache_entry *cache_ptr = appctx->ctx.cache.entry;
 	struct shared_block *shblk  = appctx->ctx.cache.next;
 	struct buffer *tmp = get_trash_chunk();
@@ -809,8 +856,8 @@
 static size_t htx_cache_dump_data(struct appctx *appctx, struct htx *htx,
 				  enum htx_blk_type type, unsigned int len)
 {
-	struct cache *cache = appctx->rule->arg.act.p[0];
-	struct shared_context *shctx = shctx_ptr(cache);
+	struct cache_flt_conf *cconf = appctx->rule->arg.act.p[0];
+	struct shared_context *shctx = shctx_ptr(cconf->c.cache);
 	struct shared_block *shblk  = appctx->ctx.cache.next;
 	uint32_t max = htx_free_data_space(htx);
 	unsigned int offset;
@@ -1036,7 +1083,8 @@
 	int ret, total;
 	struct stream_interface *si = appctx->owner;
 	struct channel *res = si_ic(si);
-	struct cache *cache = (struct cache *)appctx->rule->arg.act.p[0];
+	struct cache_flt_conf *cconf = appctx->rule->arg.act.p[0];
+	struct cache *cache = cconf->c.cache;
 	struct shared_context *shctx = shctx_ptr(cache);
 	struct cache_entry *cache_ptr = appctx->ctx.cache.entry;
 	struct shared_block *blk, *next = appctx->ctx.cache.next;
@@ -1139,55 +1187,71 @@
 	;
 }
 
-enum act_parse_ret parse_cache_store(const char **args, int *orig_arg, struct proxy *proxy,
-                                          struct act_rule *rule, char **err)
+static int parse_cache_rule(struct proxy *proxy, const char *name, struct act_rule *rule, char **err)
 {
 	struct flt_conf *fconf;
-	int cur_arg = *orig_arg;
-	rule->action       = ACT_CUSTOM;
-	rule->action_ptr   = http_action_store_cache;
+	struct cache_flt_conf *cconf = NULL;
 
-	if (!*args[cur_arg] || strcmp(args[cur_arg], "if") == 0 || strcmp(args[cur_arg], "unless") == 0) {
+	if (!*name || strcmp(name, "if") == 0 || strcmp(name, "unless") == 0) {
 		memprintf(err, "expects a cache name");
-		return ACT_RET_PRS_ERR;
+		goto err;
 	}
 
 	/* check if a cache filter was already registered with this cache
 	 * name, if that's the case, must use it. */
 	list_for_each_entry(fconf, &proxy->filter_configs, list) {
-		if (fconf->id == cache_store_flt_id && !strcmp((char *)fconf->conf, args[cur_arg])) {
-			rule->arg.act.p[0] = fconf->conf;
-			(*orig_arg)++;
-			/* filter already registered */
-			return ACT_RET_PRS_OK;
+		if (fconf->id == cache_store_flt_id) {
+			cconf = fconf->conf;
+			if (cconf && !strcmp((char *)cconf->c.name, name)) {
+				rule->arg.act.p[0] = cconf;
+				return 1;
+			}
 		}
 	}
 
-	rule->arg.act.p[0] = strdup(args[cur_arg]);
-	if (!rule->arg.act.p[0]) {
-		ha_alert("config: %s '%s': out of memory\n", proxy_type_str(proxy), proxy->id);
-		err++;
+	/* Create the filter cache config  */
+	cconf = calloc(1, sizeof(*cconf));
+	if (!cconf) {
+		memprintf(err, "out of memory\n");
+		goto err;
+	}
+	cconf->flags = 0;
+	cconf->c.name = strdup(name);
+	if (!cconf->c.name) {
+		memprintf(err, "out of memory\n");
 		goto err;
 	}
+
 	/* register a filter to fill the cache buffer */
 	fconf = calloc(1, sizeof(*fconf));
 	if (!fconf) {
-		ha_alert("config: %s '%s': out of memory\n",
-			 proxy_type_str(proxy), proxy->id);
-		err++;
+		memprintf(err, "out of memory\n");
 		goto err;
 	}
-	fconf->id   = cache_store_flt_id;
-	fconf->conf = rule->arg.act.p[0]; /* store the proxy name */
+	fconf->id = cache_store_flt_id;
+	fconf->conf = cconf;
 	fconf->ops  = &cache_ops;
 	LIST_ADDQ(&proxy->filter_configs, &fconf->list);
 
-	(*orig_arg)++;
+	rule->arg.act.p[0] = cconf;
+	return 1;
 
-	return ACT_RET_PRS_OK;
+  err:
+	free(cconf);
+	return 0;
+}
+
+enum act_parse_ret parse_cache_store(const char **args, int *orig_arg, struct proxy *proxy,
+                                          struct act_rule *rule, char **err)
+{
+	rule->action       = ACT_CUSTOM;
+	rule->action_ptr   = http_action_store_cache;
+
+	if (!parse_cache_rule(proxy, args[*orig_arg], rule, err))
+		return ACT_RET_PRS_ERR;
 
-err:
-	return ACT_RET_PRS_ERR;
+	(*orig_arg)++;
+	return ACT_RET_PRS_OK;
 }
 
 /* This produces a sha1 hash of the concatenation of the first
@@ -1250,7 +1314,8 @@
 {
 
 	struct cache_entry *res;
-	struct cache *cache = (struct cache *)rule->arg.act.p[0];
+	struct cache_flt_conf *cconf = rule->arg.act.p[0];
+	struct cache *cache = cconf->c.cache;
 
 	if (IS_HTX_STRM(s))
 		htx_check_request_for_cacheability(s, &s->req);
@@ -1295,29 +1360,14 @@
 enum act_parse_ret parse_cache_use(const char **args, int *orig_arg, struct proxy *proxy,
                                           struct act_rule *rule, char **err)
 {
-	int cur_arg = *orig_arg;
-
 	rule->action       = ACT_CUSTOM;
 	rule->action_ptr   = http_action_req_cache_use;
 
-	if (!*args[cur_arg] || strcmp(args[cur_arg], "if") == 0 || strcmp(args[cur_arg], "unless") == 0) {
-		memprintf(err, "expects a cache name");
+	if (!parse_cache_rule(proxy, args[*orig_arg], rule, err))
 		return ACT_RET_PRS_ERR;
-	}
-
-	rule->arg.act.p[0] = strdup(args[cur_arg]);
-	if (!rule->arg.act.p[0]) {
-		ha_alert("config: %s '%s': out of memory\n", proxy_type_str(proxy), proxy->id);
-		err++;
-		goto err;
-	}
 
 	(*orig_arg)++;
 	return ACT_RET_PRS_OK;
-
-err:
-	return ACT_RET_PRS_ERR;
-
 }
 
 int cfg_parse_cache(const char *file, int linenum, char **args, int kwm)
@@ -1488,99 +1538,8 @@
  */
 int cfg_cache_postparser()
 {
-	struct act_rule *hresrule, *hrqrule;
-	void *cache_ptr;
 	struct cache *cache;
-	struct proxy *curproxy = NULL;
 	int err = 0;
-	struct flt_conf *fconf;
-
-	for (curproxy = proxies_list; curproxy; curproxy = curproxy->next) {
-
-		/* resolve the http response cache name to a ptr in the action rule */
-		list_for_each_entry(hresrule, &curproxy->http_res_rules, list) {
-			if (hresrule->action  != ACT_CUSTOM ||
-			    hresrule->action_ptr != http_action_store_cache)
-				continue;
-
-			cache_ptr = hresrule->arg.act.p[0];
-
-			list_for_each_entry(cache, &caches, list) {
-				if (!strcmp(cache->id, cache_ptr)) {
-					/* don't free there, it's still used in the filter conf */
-					cache_ptr = cache;
-					cache->flags |= ((curproxy->options2 & PR_O2_USE_HTX)
-							 ? CACHE_F_HTX
-							 : CACHE_F_LEGACY_HTTP);
-					break;
-				}
-			}
-
-			if (cache_ptr == hresrule->arg.act.p[0]) {
-				ha_alert("Proxy '%s': unable to find the cache '%s' referenced by http-response cache-store rule.\n",
-					 curproxy->id, (char *)hresrule->arg.act.p[0]);
-				err++;
-			}
-
-			hresrule->arg.act.p[0] = cache_ptr;
-		}
-
-		/* resolve the http request cache name to a ptr in the action rule */
-		list_for_each_entry(hrqrule, &curproxy->http_req_rules, list) {
-			if (hrqrule->action  != ACT_CUSTOM ||
-			    hrqrule->action_ptr != http_action_req_cache_use)
-				continue;
-
-			cache_ptr = hrqrule->arg.act.p[0];
-
-			list_for_each_entry(cache, &caches, list) {
-				if (!strcmp(cache->id, cache_ptr)) {
-					free(cache_ptr);
-					cache_ptr = cache;
-					cache->flags |= ((curproxy->options2 & PR_O2_USE_HTX)
-							 ? CACHE_F_HTX
-							 : CACHE_F_LEGACY_HTTP);
-					break;
-				}
-			}
-
-			if (cache_ptr == hrqrule->arg.act.p[0]) {
-				ha_alert("Proxy '%s': unable to find the cache '%s' referenced by http-request cache-use rule.\n",
-					 curproxy->id, (char *)hrqrule->arg.act.p[0]);
-				err++;
-			}
-
-			hrqrule->arg.act.p[0] = cache_ptr;
-		}
-
-		/* resolve the cache name to a ptr in the filter config */
-		list_for_each_entry(fconf, &curproxy->filter_configs, list) {
-
-			if (fconf->id != cache_store_flt_id)
-				continue;
-
-			cache_ptr = fconf->conf;
-
-			list_for_each_entry(cache, &caches, list) {
-				if (!strcmp(cache->id, cache_ptr)) {
-					/* there can be only one filter per cache, so we free it there */
-					free(cache_ptr);
-					cache_ptr = cache;
-					cache->flags |= ((curproxy->options2 & PR_O2_USE_HTX)
-							 ? CACHE_F_HTX
-							 : CACHE_F_LEGACY_HTTP);
-					break;
-				}
-			}
-
-			if (cache_ptr == fconf->conf) {
-				ha_alert("Proxy '%s': unable to find the cache '%s' referenced by the filter 'cache'.\n",
-					 curproxy->id, (char *)fconf->conf);
-				err++;
-			}
-			fconf->conf = cache_ptr;
-		}
-	}
 
 	/* Check if the cache is used by HTX and legacy HTTP proxies in same
 	 * time
@@ -1599,6 +1558,8 @@
 
 struct flt_ops cache_ops = {
 	.init   = cache_store_init,
+	.check  = cache_store_check,
+	.deinit = cache_store_deinit,
 
 	/* Handle channels activity */
 	.channel_start_analyze = cache_store_chn_start_analyze,