9.1. Trace
9.2. HTTP compression
9.3. Stream Processing Offload Engine (SPOE)
+9.4. Cache
10. Cache
10.1. Limitation
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
---------
- 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
-----------
#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";
* 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 "
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");
};
+
+
+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))
}
+/* 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 },
{{},}