-
Notifications
You must be signed in to change notification settings - Fork 907
Open
Labels
type: featureThis issue describes a feature request / wishlist.This issue describes a feature request / wishlist.
Description
Your Feature Request
Filter has features such as compression and cache, and set it to frontend
It would be nice if it works according to the conditions.
ex)
filter compression if { hdr(host) -m str www.example.com }
filter compression if { hdr(host),lower,map(/opt/haproxy/xxx.map on }
What are you trying to do?
It is implemented in 3.2.11 version and is operating normally when tested.
I hope it's officially supported by Haproxy.
MINOR: filters: add if/unless ACL condition support to filter directives
This patch adds support for optional "if <condition>" and "unless <condition>"
clauses on the "filter" configuration directive. This allows filters to be
conditionally activated at runtime based on ACL expressions, similar to how
http-request/http-response rules support conditions.
When a condition is specified, it is evaluated at two points in the filter
dispatch chain:
- flt_post_analyze(): before calling channel_post_analyze callbacks
- flt_analyze_http_headers(): before calling http_headers callbacks
If the condition evaluates to false, the filter's callbacks are skipped
entirely for that stream, meaning the filter will not register as a data
filter and will not process any payload data.
When no condition is specified (cond is NULL), acl_match_cond() returns 1,
so existing filter configurations without if/unless continue to work
unchanged.
Example usage:
# conditionally enable compression offload per host via map
filter compression if { hdr(host),map(/opt/haproxy/etc/extension.map) on }
compression offload
compression algo gzip
compression type text/html text/plain
---
diff --git a/include/haproxy/filters-t.h b/include/haproxy/filters-t.h
index 6c1879f..a0e01fc 100644
--- a/include/haproxy/filters-t.h
+++ b/include/haproxy/filters-t.h
@@ -41,6 +41,7 @@ struct http_msg;
struct proxy;
struct stream;
struct channel;
+struct acl_cond;
struct flt_conf;
struct filter;
@@ -212,6 +213,7 @@ struct flt_conf {
void *conf; /* The filter configuration */
struct list list; /* Next filter for the same proxy */
unsigned int flags; /* FLT_CFG_FL_* */
+ struct acl_cond *cond; /* optional if/unless condition */
};
/*
diff --git a/src/filters.c b/src/filters.c
index 3b0662b..7da8041 100644
--- a/src/filters.c
+++ b/src/filters.c
@@ -11,6 +11,7 @@
*/
#include <haproxy/api.h>
+#include <haproxy/acl.h>
#include <haproxy/buf-t.h>
#include <haproxy/cfgparse.h>
#include <haproxy/compression.h>
@@ -258,9 +259,19 @@ parse_filter(char **args, int section_type, struct proxy *curpx,
goto error;
}
if (*args[cur_arg]) {
- memprintf(err, "'%s %s' : unknown keyword '%s'.",
- args[0], args[1], args[cur_arg]);
- goto error;
+ if (strcmp(args[cur_arg], "if") == 0 || strcmp(args[cur_arg], "unless") == 0) {
+ fconf->cond = build_acl_cond(file, line, &curpx->acl,
+ curpx, (const char **)args + cur_arg, err);
+ if (!fconf->cond) {
+ memprintf(err, "'%s %s' : %s",
+ args[0], args[1], err && *err ? *err : "invalid condition");
+ goto error;
+ }
+ } else {
+ memprintf(err, "'%s %s' : unknown keyword '%s'.",
+ args[0], args[1], args[cur_arg]);
+ goto error;
+ }
}
if (fconf->ops == NULL) {
memprintf(err, "'%s %s' : no callbacks defined.",
@@ -273,7 +284,10 @@ parse_filter(char **args, int section_type, struct proxy *curpx,
return 0;
error:
- free(fconf);
+ if (fconf) {
+ free_acl_cond(fconf->cond);
+ free(fconf);
+ }
return -1;
@@ -388,6 +402,7 @@ flt_deinit(struct proxy *proxy)
if (fconf->ops->deinit)
fconf->ops->deinit(proxy, fconf);
LIST_DELETE(&fconf->list);
+ free_acl_cond(fconf->cond);
free(fconf);
}
}
@@ -846,6 +861,11 @@ flt_post_analyze(struct stream *s, struct channel *chn, unsigned int an_bit)
list_for_each_entry(filter, &strm_flt(s)->filters, list) {
if (FLT_OPS(filter)->channel_post_analyze && (filter->post_analyzers & an_bit)) {
+ if (!acl_match_cond(filter->config->cond, s->be, s->sess, s,
+ ((chn->flags & CF_ISRESP) ? SMP_OPT_DIR_RES : SMP_OPT_DIR_REQ) | SMP_OPT_FINAL)) {
+ filter->post_analyzers &= ~an_bit;
+ continue;
+ }
DBG_TRACE_DEVEL(FLT_ID(filter), STRM_EV_FLT_ANA, s);
filter->calls++;
ret = FLT_OPS(filter)->channel_post_analyze(s, filter, chn, an_bit);
@@ -878,6 +898,9 @@ flt_analyze_http_headers(struct stream *s, struct channel *chn, unsigned int an_
RESUME_FILTER_LOOP(s, chn) {
if (FLT_OPS(filter)->http_headers) {
+ if (!acl_match_cond(filter->config->cond, s->be, s->sess, s,
+ ((chn->flags & CF_ISRESP) ? SMP_OPT_DIR_RES : SMP_OPT_DIR_REQ) | SMP_OPT_FINAL))
+ continue;
DBG_TRACE_DEVEL(FLT_ID(filter), STRM_EV_HTTP_ANA|STRM_EV_FLT_ANA, s);
filter->calls++;
ret = FLT_OPS(filter)->http_headers(s, filter, msg);
Output of haproxy -vv
HAProxy version 3.2.11-nfront-awslc_v4 2026/01/29 - https://haproxy.org/
Status: long-term supported branch - will stop receiving fixes around Q2 2030.
Known bugs: http://www.haproxy.org/bugs/bugs-3.2.11.html
Running on: Linux 5.11.0-1.el7.elrepo.x86_64 #1 SMP Sun Feb 14 18:10:38 EST 2021 x86_64
Build options :
TARGET = linux-glibc
CC = cc
CFLAGS = -O2 -g -Og -march=native -fwrapv -DTLS_TICKETS_NO=4
OPTIONS = USE_OPENSSL_AWSLC=1 USE_LUA=1 USE_ZLIB=1 USE_QUIC=1 USE_STATIC_PCRE2=1 USE_PCRE2=1 USE_PCRE2_JIT=1
DEBUG =
Feature list : -51DEGREES +ACCEPT4 +BACKTRACE -CLOSEFROM +CPU_AFFINITY +CRYPT_H -DEVICEATLAS +DL -ENGINE +EPOLL -EVPORTS +GETADDRINFO -KQUEUE -LIBATOMIC +LIBCRYPT +LINUX_CAP +LINUX_SPLICE +LINUX_TPROXY +LUA +MATH -MEMORY_PROFILING +NETFILTER +NS -OBSOLETE_LINKER +OPENSSL +OPENSSL_AWSLC -OPENSSL_WOLFSSL -OT -PCRE +PCRE2 +PCRE2_JIT -PCRE_JIT +POLL +PRCTL -PROCCTL -PROMEX -PTHREAD_EMULATION +QUIC -QUIC_OPENSSL_COMPAT +RT -SLZ +SSL -STATIC_PCRE +STATIC_PCRE2 +TFO +THREAD +THREAD_DUMP +TPROXY -WURFL +ZLIB +ACME
Default settings :
bufsize = 16384, maxrewrite = 1024, maxpollevents = 200
Built with multi-threading support (MAX_TGROUPS=32, MAX_THREADS=1024, default=8).
Built with SSL library version : OpenSSL 1.1.1 (compatible; AWS-LC 1.65.0)
Running on SSL library version : AWS-LC 1.65.0
SSL library supports TLS extensions : yes
SSL library supports SNI : yes
SSL library FIPS mode : no
SSL library supports : TLSv1.0 TLSv1.1 TLSv1.2 TLSv1.3
QUIC: connection socket-owner mode support : yes
QUIC: GSO emission support : no
Built with Lua version : Lua 5.3.6
Built with network namespace support.
Built with Naver SSL Client Hello request capture. version: RB-1.1.2:71123
Built with zlib version : 1.2.11
Running on zlib version : 1.2.11
Compression algorithms supported : identity("identity"), deflate("deflate"), raw-deflate("deflate"), gzip("gzip")
Built with transparent proxy support using: IP_TRANSPARENT IPV6_TRANSPARENT IP_FREEBIND
Built with PCRE2 version : 10.43 2024-02-16
PCRE2 library supports JIT : yes
Encrypted password support via crypt(3): yes
Built with gcc compiler version 4.8.5 20150623 (Red Hat 4.8.5-16)
Available polling systems :
epoll : pref=300, test result OK
poll : pref=200, test result OK
select : pref=150, test result OK
Total: 3 (3 usable), will use epoll.
Available multiplexer protocols :
(protocols marked as <default> cannot be specified using 'proto' keyword)
quic : mode=HTTP side=FE mux=QUIC flags=HTX|NO_UPG|FRAMED
h2 : mode=HTTP side=FE|BE mux=H2 flags=HTX|HOL_RISK|NO_UPG
<default> : mode=HTTP side=FE|BE mux=H1 flags=HTX
h1 : mode=HTTP side=FE|BE mux=H1 flags=HTX|NO_UPG
fcgi : mode=HTTP side=BE mux=FCGI flags=HTX|HOL_RISK|NO_UPG
<default> : mode=SPOP side=BE mux=SPOP flags=HOL_RISK|NO_UPG
spop : mode=SPOP side=BE mux=SPOP flags=HOL_RISK|NO_UPG
<default> : mode=TCP side=FE|BE mux=PASS flags=
none : mode=TCP side=FE|BE mux=PASS flags=NO_UPG
Available services : none
Available filters :
[BWLIM] bwlim-in
[BWLIM] bwlim-out
[CACHE] cache
[COMP] compression
[FCGI] fcgi-app
[ SUB] replace-body
[SPOE] spoe
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
type: featureThis issue describes a feature request / wishlist.This issue describes a feature request / wishlist.