used ("filter", "filter-config", "filter-enable", "filter-disable" or
"filter-sequence").
- This option is unset by default. So proxies without explicit filter
- directives rely on the filter instance api. By setting it to
- "downgrade-to-legacy", it is possible to force proxies to use the legacy
- filter API by default. It could be useful the time to convert outdated
- filters still relying on the legacy API only. Indeed, such filters will be
- silently ignored except if the "filter" directive is used to declare them.
- This option can be set to "default" to restore the default behavior.
+ This option is unset by default. The API used by a proxy without explicit
+ filter directives is deduced from the filters implied by its other
+ directives: a proxy implying only filters known as legacy filter
+ configurations, without any filter class, uses the legacy API, while a
+ proxy implying at least one filter class uses the filter instance API, and
+ the class-less filters it may also imply are ignored. By setting this option
+ to "downgrade-to-legacy", it is possible to force the proxies without
+ explicit filter directives to use the legacy filter API, whatever they
+ imply. It could be useful the time to convert outdated filters still relying
+ on the legacy API only. Indeed, such filters will be silently ignored in
+ the filter instance API, except if the "filter" directive is used to declare
+ them. This option can be set to "default" to restore the default behavior.
Note that it should be a temporary workaround. There is no warranty that all
filters will remain compatible with the legacy API. In that case, they will
is rejected in a proxy inheriting filter instances from its defaults
section. Filters implicitly declared by other directives (for instance by the
"compression" options, the "cache-store" rules or "use-fcgi-app") do not
-select a mode: a proxy using only such filters works in the new mode.
+select a mode: a proxy using only such filters works in the new mode, unless
+the implied filters are only known as legacy filter configurations, without
+any filter class: a proxy implying only such filters works in the legacy
+mode, and a proxy implying filters of both kinds uses the new mode, where the
+class-less ones are ignored. All the filters documented in this section
+declare their classes, so they are always visible to the new mode.
The "filter-api" global option changes this last rule: when it is set to
"downgrade-to-legacy", the proxies using only implicitly declared filters work
-in the legacy mode, so the filters not supporting the new mode keep
-working. Explicit filter declarations always win, in both modes.
+in the legacy mode, whatever they imply, so the filters not supporting the
+new mode keep working. Explicit filter declarations always win, in both modes.
All the filters documented below support the new mode. The <class> name to use
with "filter-config" may differ from the legacy filter name; it is given in
other, never both: as soon as a legacy "filter" directive is used, the proxy
works in legacy mode, otherwise the new mode is used. Implicitly declared
filters do not select a mode, so a proxy using only implicit filters works in
-the new mode. The "filter-api" global option changes this last rule: when it
-is set to "downgrade-to-legacy", a proxy using only implicitly declared filters
-works in the legacy mode. It is a fallback for the filters not supporting the
+the new mode, unless the implicitly declared filters are only known as legacy
+filter configurations: a filter not supporting the new mode declares no
+class, hence no instance, and a proxy implying such filters keeps working in
+the legacy mode. A proxy implying filters of both kinds uses the new mode,
+where the class-less ones are ignored. The "filter-api" global option forces
+the legacy mode for every proxy using only implicitly declared filters,
+whatever they imply. It is a fallback for the filters not supporting the
new mode, and the explicit declarations always win.
A filter class defines the filter name, its placement in the request and
A filter written before HAProxy 3.5 only supports the legacy mode. It keeps
working as-is, nothing is required to use it with the "filter" directive.
-But it is invisible to the new mode until its class is declared. If it
-relies on an implicit declaration only, the "filter-api downgrade-to-legacy"
-global option keeps it working in the meantime, see the FAQ (section 5.7).
+But it is invisible to the new mode until its class is declared. A proxy
+implying only such filters keeps working in the legacy mode, since HAProxy
+3.5 deduces it from the implied declarations, but a proxy implying filters
+of both kinds ignores the class-less ones: the "filter-api
+downgrade-to-legacy" global option keeps them working in the meantime, see
+the FAQ (section 5.7).
This section lists what changed for a filter developer, then explains how to
convert an existing filter, first with the minimal changes to support both
modes, then to take full advantage of the new mode.
filter class is invisible to the new mode: the declarations implying it
are silently ignored, because there is no filter instance to instantiate.
All the filters supported in-tree are available in both modes, so this
- only concerns third-party filters.
+ only concerns third-party filters. A proxy implying only such filters
+ works in the legacy mode by default, since HAProxy 3.5 deduces the mode
+ from the implied declarations, so they keep working as-is. The problem
+ only arises for a proxy implying filters of both kinds: the class-less
+ ones are ignored. All the filters implied by such a proxy must then
+ support the new mode, or the legacy ones must be declared explicitly
+ with the "filter" directive.
In this case, the "filter-api downgrade-to-legacy" global option restores
the behavior of HAProxy 3.4: the proxies without explicit filter
}
-/* Applies the default filter mode on the proxy <px>: when the legacy filter
- * mode was requested globally, a proxy with no explicit filter declaration
- * (neither "filter" nor "filter-*" directives) uses the legacy mode instead
- * of the new one, so the implicit declarations of the filters not supporting
- * the new mode keep working. A proxy with explicit declarations keeps the
- * mode it selected: the legacy mode for the "filter" directives, the new
- * one for the "filter-*" directives.
+/* Returns true if the proxy <px> has at least one filter instance, explicit
+ * or implicit, in its configuration state. Must be called before the instances
+ * are flattened in px->filter_instances, so they are walked through their
+ * class references.
+ */
+static int flt_has_conf_instances(const struct proxy *px)
+{
+ struct filter_class_ref *ref;
+
+ list_for_each_entry(ref, &px->conf.filter_refs, list) {
+ if (!LIST_ISEMPTY(&ref->instances))
+ return 1;
+ }
+ return 0;
+}
+
+/* Applies the default filter mode on the proxy <px>, when it used no explicit
+ * filter declaration (neither "filter" nor "filter-*" directives): the mode
+ * is deduced from the filter configurations and the filter instances implied
+ * by the other directives. A proxy with only filter configurations, and no
+ * instance, uses the legacy mode: an implied filter not supporting the new
+ * mode declares no class, hence no instance. A proxy with filter instances
+ * uses the new mode: the implied filters all declared their classes. A proxy
+ * with both may mix implied filters of the two kinds, and uses the new mode,
+ * so the legacy-only ones are ignored, as any class-less filter in the new
+ * mode. A proxy with explicit declarations keeps the mode it selected: the
+ * legacy mode for the "filter" directives, the new one for the "filter-*"
+ * directives. When the legacy filter mode was requested globally, a proxy
+ * with no explicit declaration uses the legacy mode instead of the new one,
+ * whatever it deduced, so the implicit declarations of the filters not
+ * supporting the new mode keep working.
*/
static void flt_apply_default_mode(struct proxy *px)
{
- if (filter_api_downgraded == 1 &&
- !flt_use_legacy_filter(px) && !flt_has_explicit_config(px))
+ if (flt_use_legacy_filter(px) || flt_has_explicit_config(px))
+ return;
+
+ if (filter_api_downgraded == 1) {
+ px->flags |= PR_FL_FILTER_LEGACY;
+ return;
+ }
+
+ /* Filter configurations with no instance: the implied filters declared
+ * no class, so they are only usable in the legacy mode.
+ */
+ if (!LIST_ISEMPTY(&px->filter_configs) && !flt_has_conf_instances(px)) {
+ struct flt_conf *fconf;
+ int first = 1;
+
+ chunk_reset(&trash);
+ chunk_printf(&trash, "config: %s '%s' : All filters used are relying only on legacy API "
+ "(set 'filter-api downgrade-to-legacy' in a global section to remove this warning): \n\t",
+ proxy_type_str(px), px->id);
+ list_for_each_entry(fconf, &px->filter_configs, list) {
+ chunk_appendf(&trash, "%s'%s'", (first ? " " : ", "), fconf->id);
+ first = 0;
+ }
+ ha_warning("%.*s\n", (int)trash.data, trash.area);
+
px->flags |= PR_FL_FILTER_LEGACY;
+ }
}
/* Calls flt_precheck_instances() for all proxies, see above */