summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex W <embezzle.dev@proton.me>2025-01-27 20:57:27 +0000
committerGitHub <noreply@github.com>2025-01-27 22:57:27 +0200
commit85be7579f4e93f9da06b5e8775b5296be953d422 (patch)
tree795902fa16a0b7fb284834d88f4c302a4448ac19
parentd50cdfee916c6d0b5c60c03d589f9292954b6688 (diff)
downloadvyos-1x-85be7579f4e93f9da06b5e8775b5296be953d422.tar.gz
vyos-1x-85be7579f4e93f9da06b5e8775b5296be953d422.zip
haproxy: T7081: Support HTTP compression (#4314)
-rw-r--r--data/templates/load-balancing/haproxy.cfg.j25
-rw-r--r--interface-definitions/load-balancing_haproxy.xml.in32
-rwxr-xr-xsmoketest/scripts/cli/test_load-balancing_haproxy.py23
-rw-r--r--src/conf_mode/load-balancing_haproxy.py7
4 files changed, 67 insertions, 0 deletions
diff --git a/data/templates/load-balancing/haproxy.cfg.j2 b/data/templates/load-balancing/haproxy.cfg.j2
index 786ebfb21..c98b739e2 100644
--- a/data/templates/load-balancing/haproxy.cfg.j2
+++ b/data/templates/load-balancing/haproxy.cfg.j2
@@ -93,6 +93,11 @@ frontend {{ front }}
http-response set-header {{ header }} '{{ header_config['value'] }}'
{% endfor %}
{% endif %}
+{% if front_config.http_compression is vyos_defined %}
+ filter compression
+ compression algo {{ front_config.http_compression.algorithm }}
+ compression type {{ front_config.http_compression.mime_type | join(' ') }}
+{% endif %}
{% if front_config.rule is vyos_defined %}
{% for rule, rule_config in front_config.rule.items() %}
# rule {{ rule }}
diff --git a/interface-definitions/load-balancing_haproxy.xml.in b/interface-definitions/load-balancing_haproxy.xml.in
index 742272436..ca089d3f0 100644
--- a/interface-definitions/load-balancing_haproxy.xml.in
+++ b/interface-definitions/load-balancing_haproxy.xml.in
@@ -48,6 +48,38 @@
<valueless/>
</properties>
</leafNode>
+ <node name="http-compression">
+ <properties>
+ <help>Compress HTTP responses</help>
+ </properties>
+ <children>
+ <leafNode name="algorithm">
+ <properties>
+ <help>Compression algorithm</help>
+ <completionHelp>
+ <list>gzip deflate identity raw-deflate</list>
+ </completionHelp>
+ <constraint>
+ <regex>(gzip|deflate|identity|raw-deflate)</regex>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="mime-type">
+ <properties>
+ <help>MIME types to compress</help>
+ <valueHelp>
+ <format>txt</format>
+ <description>MIME type to compress</description>
+ </valueHelp>
+ <multi/>
+ <constraint>
+ <regex>\w+\/[-+.\w]+</regex>
+ </constraint>
+ <constraintErrorMessage>Invalid MIME type specified</constraintErrorMessage>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
<node name="ssl">
<properties>
<help>SSL Certificate, SSL Key and CA</help>
diff --git a/smoketest/scripts/cli/test_load-balancing_haproxy.py b/smoketest/scripts/cli/test_load-balancing_haproxy.py
index 967eb3869..9f412aa95 100755
--- a/smoketest/scripts/cli/test_load-balancing_haproxy.py
+++ b/smoketest/scripts/cli/test_load-balancing_haproxy.py
@@ -498,5 +498,28 @@ class TestLoadBalancingReverseProxy(VyOSUnitTestSHIM.TestCase):
self.assertIn('log /dev/log local5 notice', config)
self.assertIn('log /dev/log local6 crit', config)
+ def test_10_lb_reverse_proxy_http_compression(self):
+ # Setup base
+ self.configure_pki()
+ self.base_config()
+
+ # Configure compression in frontend
+ self.cli_set(base_path + ['service', 'https_front', 'http-compression', 'algorithm', 'gzip'])
+ self.cli_set(base_path + ['service', 'https_front', 'http-compression', 'mime-type', 'text/html'])
+ self.cli_set(base_path + ['service', 'https_front', 'http-compression', 'mime-type', 'text/javascript'])
+ self.cli_set(base_path + ['service', 'https_front', 'http-compression', 'mime-type', 'text/plain'])
+ self.cli_commit()
+
+ # Test compression is present in generated configuration file
+ config = read_file(HAPROXY_CONF)
+ self.assertIn('filter compression', config)
+ self.assertIn('compression algo gzip', config)
+ self.assertIn('compression type text/html text/javascript text/plain', config)
+
+ # Test setting compression without specifying any mime-types fails verification
+ self.cli_delete(base_path + ['service', 'https_front', 'http-compression', 'mime-type'])
+ with self.assertRaises(ConfigSessionError) as e:
+ self.cli_commit()
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/src/conf_mode/load-balancing_haproxy.py b/src/conf_mode/load-balancing_haproxy.py
index 45042dd52..5fd1beec9 100644
--- a/src/conf_mode/load-balancing_haproxy.py
+++ b/src/conf_mode/load-balancing_haproxy.py
@@ -78,6 +78,13 @@ def verify(lb):
not is_listen_port_bind_service(int(tmp_port), 'haproxy'):
raise ConfigError(f'"TCP" port "{tmp_port}" is used by another service')
+ if 'http_compression' in front_config:
+ if front_config['mode'] != 'http':
+ raise ConfigError(f'service {front} must be set to http mode to use http-compression!')
+ if len(front_config['http_compression']['mime_type']) == 0:
+ raise ConfigError(f'service {front} must have at least one mime-type configured to use'
+ f'http_compression!')
+
for back, back_config in lb['backend'].items():
if 'http_check' in back_config:
http_check = back_config['http_check']