Thanks to visit codestin.com
Credit goes to github.com

Skip to content

conditional statement ( acl_cond) for filters. #3291

@zino7825

Description

@zino7825

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    type: featureThis issue describes a feature request / wishlist.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions