MEDIUM: cache: Require an explicit filter declaration if other filters are used

As for the compression filter, the cache filter must be explicitly declared
(using the filter keyword) if other filters than cache are used. It is mandatory
to explicitly define the filters order.

Documentation has been updated accordingly.
This commit is contained in:
Christopher Faulet 2018-12-11 09:18:27 +01:00 committed by Willy Tarreau
parent afd819c54a
commit 99a17a2d91
2 changed files with 120 additions and 5 deletions

View File

@ -107,6 +107,7 @@ Summary
9.1. Trace
9.2. HTTP compression
9.3. Stream Processing Offload Engine (SPOE)
9.4. Cache
10. Cache
10.1. Limitation
@ -17752,6 +17753,25 @@ Important note:
The SPOE filter is highly experimental for now and was not heavily
tested. It is really not production ready. So use it carefully.
9.4. Cache
----------
filter cache <name>
Arguments :
<name> is name of the cache section this filter will use.
The cache uses a filter to store cacheable responses. The HTTP rules
"cache-store" and "cache-use" must be used to define how and when to use a
cache. By default the correpsonding filter is implicitly defined. And when no
other filter than cache is used, it is enough. But it is mandatory to
explicitly use a filter line to use a cache when two or more filters are used
for the same listener/frontend/backend. This is important to know the filters
evaluation order.
See also : section 10 about cache.
10. Cache
---------
@ -17789,9 +17809,11 @@ The cache won't store and won't deliver objects in these cases:
- If the HTTP version of the request is smaller than 1.1
- If the request contains an Authorization header
Caution!: Due to the current limitation of the filters, it is not recommended
to use the cache with other filters. Using them can cause undefined behavior
if they modify the response (compression for example).
Caution!: For HAProxy version prior to 1.9, due to the limitation of the
filters, it is not recommended to use the cache with other filters. Using them
can cause undefined behavior if they modify the response (compression for
example). For HAProxy 1.9 and greater, it is safe, for HTX proxies only (see
"option http-use-htx" for details).
10.2. Setup
-----------

View File

@ -45,6 +45,8 @@
#define CACHE_FLT_F_IGNORE_CNT_ENC 0x00000001 /* Ignore 'Content-Encoding' header when response is cached
* if compression is already started */
#define CACHE_FLT_F_IMPLICIT_DECL 0x00000002 /* The cache filtre was implicitly declared (ie without
* the filter keyword) */
const char *cache_store_flt_id = "cache store filter";
@ -189,13 +191,20 @@ cache_store_check(struct proxy *px, struct flt_conf *fconf)
* compressed in the cache. When the compression is after the cache, the
* 'Content-encoding' header must be ignored because the response will
* be stored uncompressed. The compression will be done on the cached
* response too. */
* response too. Also check if the cache filter must be explicitly
* declaired or not. */
list_for_each_entry(f, &px->filter_configs, list) {
if (f == fconf) {
ignore = 1;
continue;
}
if ((f->id != fconf->id) && (cconf->flags & CACHE_FLT_F_IMPLICIT_DECL)) {
ha_alert("config: %s '%s': require an explicit filter declaration "
"to use the cache '%s'.\n", proxy_type_str(px), px->id, cache->id);
return 1;
}
if (f->id == http_comp_flt_id) {
if (!(px->options2 & PR_O2_USE_HTX)) {
ha_alert("config: %s '%s' : compression and cache filters cannot be "
@ -1264,7 +1273,7 @@ static int parse_cache_rule(struct proxy *proxy, const char *name, struct act_ru
memprintf(err, "out of memory\n");
goto err;
}
cconf->flags = 0;
cconf->flags = CACHE_FLT_F_IMPLICIT_DECL;
cconf->c.name = strdup(name);
if (!cconf->c.name) {
memprintf(err, "out of memory\n");
@ -1623,6 +1632,81 @@ struct flt_ops cache_ops = {
};
static int
parse_cache_flt(char **args, int *cur_arg, struct proxy *px,
struct flt_conf *fconf, char **err, void *private)
{
struct flt_conf *f, *back;
struct cache_flt_conf *cconf;
char *name = NULL;
int pos = *cur_arg;
/* Get the cache filter name*/
if (!strcmp(args[pos], "cache")) {
if (!*args[pos + 1]) {
memprintf(err, "%s : expects an <id> argument", args[pos]);
goto error;
}
name = strdup(args[pos + 1]);
if (!name) {
memprintf(err, "%s '%s' : out of memory", args[pos], args[pos + 1]);
goto error;
}
pos += 2;
}
/* Check if an implicit filter with the same name already exists. If so,
* we remove the implicit filter to use the explicit one. */
list_for_each_entry_safe(f, back, &px->filter_configs, list) {
if (f->id != cache_store_flt_id)
continue;
cconf = f->conf;
if (strcmp(name, cconf->c.name)) {
cconf = NULL;
continue;
}
if (!(cconf->flags & CACHE_FLT_F_IMPLICIT_DECL)) {
cconf = NULL;
memprintf(err, "%s: multiple explicit declarations of the cache filter '%s'",
px->id, name);
return -1;
}
/* Remove the implicit filter. <cconf> is kept for the explicit one */
LIST_DEL(&f->list);
free(f);
free(name);
break;
}
/* No implicit cache filter found, create configuration for the explicit one */
if (!cconf) {
cconf = calloc(1, sizeof(*cconf));
if (!cconf) {
memprintf(err, "%s: out of memory", args[*cur_arg]);
goto error;
}
cconf->c.name = name;
}
cconf->flags = 0;
fconf->id = cache_store_flt_id;
fconf->conf = cconf;
fconf->ops = &cache_ops;
*cur_arg = pos;
return 0;
error:
free(name);
free(cconf);
return -1;
}
static int cli_parse_show_cache(char **args, char *payload, struct appctx *appctx, void *private)
{
if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
@ -1686,6 +1770,15 @@ static int cli_io_handler_show_cache(struct appctx *appctx)
}
/* Declare the filter parser for "cache" keyword */
static struct flt_kw_list filter_kws = { "CACHE", { }, {
{ "cache", parse_cache_flt, NULL },
{ NULL, NULL, NULL },
}
};
INITCALL1(STG_REGISTER, flt_register_keywords, &filter_kws);
static struct cli_kw_list cli_kws = {{},{
{ { "show", "cache", NULL }, "show cache : show cache status", cli_parse_show_cache, cli_io_handler_show_cache, NULL, NULL },
{{},}