This is an automated email from the ASF dual-hosted git repository.

brusdev pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/artemis.git


The following commit(s) were added to refs/heads/main by this push:
     new 2df59c5b8f ARTEMIS-5833 support compression for HTTP responses
2df59c5b8f is described below

commit 2df59c5b8f9fdee8cc171df393731e0ff3bca3df
Author: Justin Bertram <[email protected]>
AuthorDate: Fri Dec 19 15:17:51 2025 -0600

    ARTEMIS-5833 support compression for HTTP responses
---
 .../apache/activemq/artemis/dto/WebServerDTO.java  |  6 +++
 artemis-web/pom.xml                                |  8 +++
 .../artemis/component/WebServerComponent.java      | 22 +++++++-
 .../activemq/cli/test/WebServerComponentTest.java  | 59 ++++++++++++++++++++++
 .../webapps/WebServerComponentCompressionTest.txt  |  1 +
 docs/user-manual/web-server.adoc                   |  9 ++++
 6 files changed, 103 insertions(+), 2 deletions(-)

diff --git 
a/artemis-dto/src/main/java/org/apache/activemq/artemis/dto/WebServerDTO.java 
b/artemis-dto/src/main/java/org/apache/activemq/artemis/dto/WebServerDTO.java
index b118c708ad..9a122e7512 100644
--- 
a/artemis-dto/src/main/java/org/apache/activemq/artemis/dto/WebServerDTO.java
+++ 
b/artemis-dto/src/main/java/org/apache/activemq/artemis/dto/WebServerDTO.java
@@ -113,6 +113,12 @@ public class WebServerDTO extends ComponentDTO {
    @XmlAttribute
    public Integer maxResponseHeaderSize;
 
+   @XmlAttribute
+   public Boolean compressionEnabled;
+
+   @XmlAttribute
+   public Integer compressionLevel;
+
    public String getPath() {
       return path;
    }
diff --git a/artemis-web/pom.xml b/artemis-web/pom.xml
index 7459b95046..2f887519b9 100644
--- a/artemis-web/pom.xml
+++ b/artemis-web/pom.xml
@@ -102,6 +102,14 @@
          <groupId>org.eclipse.jetty</groupId>
          <artifactId>jetty-alpn-java-server</artifactId>
       </dependency>
+      <dependency>
+         <groupId>org.eclipse.jetty.compression</groupId>
+         <artifactId>jetty-compression-server</artifactId>
+      </dependency>
+      <dependency>
+         <groupId>org.eclipse.jetty.compression</groupId>
+         <artifactId>jetty-compression-gzip</artifactId>
+      </dependency>
       <dependency>
          <groupId>org.apache.artemis</groupId>
          <artifactId>artemis-server</artifactId>
diff --git 
a/artemis-web/src/main/java/org/apache/activemq/artemis/component/WebServerComponent.java
 
b/artemis-web/src/main/java/org/apache/activemq/artemis/component/WebServerComponent.java
index 316b0e3120..c5af6026bd 100644
--- 
a/artemis-web/src/main/java/org/apache/activemq/artemis/component/WebServerComponent.java
+++ 
b/artemis-web/src/main/java/org/apache/activemq/artemis/component/WebServerComponent.java
@@ -57,6 +57,11 @@ import org.apache.activemq.artemis.utils.ClassloadingUtil;
 import org.apache.activemq.artemis.utils.PemConfigUtil;
 import org.apache.activemq.artemis.utils.sm.SecurityManagerShim;
 import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory;
+import org.eclipse.jetty.compression.Compression;
+import org.eclipse.jetty.compression.EncoderConfig;
+import org.eclipse.jetty.compression.gzip.GzipCompression;
+import org.eclipse.jetty.compression.gzip.GzipEncoderConfig;
+import org.eclipse.jetty.compression.server.CompressionHandler;
 import org.eclipse.jetty.ee9.security.DefaultAuthenticatorFactory;
 import org.eclipse.jetty.ee9.servlet.FilterHolder;
 import org.eclipse.jetty.ee9.webapp.WebAppContext;
@@ -149,6 +154,21 @@ public class WebServerComponent implements 
ExternalComponent, WebServerComponent
       Scheduler scheduler = new 
ScheduledExecutorScheduler("activemq-web-scheduled", false);
       server = new Server(threadPool, scheduler, null);
       handlers = new Handler.Sequence();
+      if (webServerConfig.compressionEnabled != null && 
webServerConfig.compressionEnabled) {
+         int compressionLevel = 
Objects.requireNonNullElse(webServerConfig.compressionLevel, 6);
+         logger.debug("embedded web server is using GZIP compression level 
{}", compressionLevel);
+         EncoderConfig encoderConfig = new GzipEncoderConfig();
+         encoderConfig.setCompressionLevel(compressionLevel);
+         Compression compression = new GzipCompression();
+         compression.setDefaultEncoderConfig(encoderConfig);
+         CompressionHandler compressionHandler = new CompressionHandler();
+         compressionHandler.putCompression(compression);
+         compressionHandler.setHandler(handlers);
+         server.setHandler(compressionHandler);
+      } else {
+         server.setHandler(handlers);
+      }
+
 
       HttpConfiguration httpConfiguration = new HttpConfiguration();
 
@@ -253,8 +273,6 @@ public class WebServerComponent implements 
ExternalComponent, WebServerComponent
 
       handlers.addHandler(defaultHandler); // this should be last
 
-      server.setHandler(handlers);
-
       server.start();
 
       printStatus(bindings);
diff --git 
a/artemis-web/src/test/java/org/apache/activemq/cli/test/WebServerComponentTest.java
 
b/artemis-web/src/test/java/org/apache/activemq/cli/test/WebServerComponentTest.java
index 1f56dad6bd..a6134483ce 100644
--- 
a/artemis-web/src/test/java/org/apache/activemq/cli/test/WebServerComponentTest.java
+++ 
b/artemis-web/src/test/java/org/apache/activemq/cli/test/WebServerComponentTest.java
@@ -65,6 +65,7 @@ import io.netty.handler.codec.http.DefaultFullHttpRequest;
 import io.netty.handler.codec.http.HttpClientCodec;
 import io.netty.handler.codec.http.HttpContent;
 import io.netty.handler.codec.http.HttpHeaderNames;
+import io.netty.handler.codec.http.HttpHeaders;
 import io.netty.handler.codec.http.HttpMethod;
 import io.netty.handler.codec.http.HttpObject;
 import io.netty.handler.codec.http.HttpRequest;
@@ -202,6 +203,62 @@ public class WebServerComponentTest extends 
ArtemisTestCase {
       assertFalse(webServerComponent.isStarted());
    }
 
+   @Test
+   public void testCompressionEnabled() throws Exception {
+      testCompression(true);
+   }
+
+   @Test
+   public void testCompressionDisabled() throws Exception {
+      testCompression(false);
+   }
+
+   private void testCompression(boolean compressionEnabled) throws Exception {
+      final String encoding = "gzip";
+
+      BindingDTO bindingDTO = new BindingDTO();
+      bindingDTO.uri = "http://localhost:0";;
+      WebServerDTO webServerDTO = new WebServerDTO();
+      webServerDTO.setBindings(Collections.singletonList(bindingDTO));
+      webServerDTO.path = "webapps";
+      webServerDTO.webContentEnabled = true;
+      webServerDTO.compressionEnabled = compressionEnabled;
+      WebServerComponent webServerComponent = new WebServerComponent();
+      assertFalse(webServerComponent.isStarted());
+      webServerComponent.configure(webServerDTO, "src/test/resources/", 
"src/test/resources/");
+      testedComponents.add(webServerComponent);
+      webServerComponent.start();
+      final int port = webServerComponent.getPort();
+      // Make the connection attempt.
+      CountDownLatch latch = new CountDownLatch(1);
+      final ClientHandler clientHandler = new ClientHandler(latch);
+      Channel ch = getChannel(port, clientHandler);
+
+      // this file is different from the other tests because it has to be 
above a certain size in order to be compressed
+      URI uri = new 
URI("http://localhost/WebServerComponentCompressionTest.txt";);
+      // Prepare the HTTP request.
+      HttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, 
HttpMethod.GET, uri.getRawPath());
+      request.headers().set(HttpHeaderNames.HOST, "localhost");
+      request.headers().set(HttpHeaderNames.ACCEPT_ENCODING, encoding);
+
+      // Send the HTTP request.
+      ch.writeAndFlush(request);
+      assertTrue(latch.await(5, TimeUnit.SECONDS));
+      String contentEncoding = 
clientHandler.headers.get(HttpHeaderNames.CONTENT_ENCODING);
+      if (compressionEnabled) {
+         assertEquals(encoding, contentEncoding);
+      } else {
+         assertNull(contentEncoding);
+      }
+
+      // Wait for the server to close the connection.
+      ch.close();
+      ch.eventLoop().shutdownNow();
+      assertTrue(webServerComponent.isStarted());
+      webServerComponent.stop(true);
+      assertFalse(webServerComponent.isStarted());
+   }
+
    @Test
    public void testThreadPool() throws Exception {
       BindingDTO bindingDTO = new BindingDTO();
@@ -1133,6 +1190,7 @@ public class WebServerComponentTest extends 
ArtemisTestCase {
       private CountDownLatch latch;
       private StringBuilder body = new StringBuilder();
       private String serverHeader;
+      private HttpHeaders headers;
 
       ClientHandler(CountDownLatch latch) {
          this.latch = latch;
@@ -1141,6 +1199,7 @@ public class WebServerComponentTest extends 
ArtemisTestCase {
       @Override
       public void channelRead0(ChannelHandlerContext ctx, HttpObject msg) {
          if (msg instanceof HttpResponse response) {
+            headers = response.headers();
             serverHeader = response.headers().get("Server");
          } else if (msg instanceof HttpContent content) {
             body.append(content.content().toString(CharsetUtil.UTF_8));
diff --git 
a/artemis-web/src/test/resources/webapps/WebServerComponentCompressionTest.txt 
b/artemis-web/src/test/resources/webapps/WebServerComponentCompressionTest.txt
new file mode 100644
index 0000000000..fd4f971ab3
--- /dev/null
+++ 
b/artemis-web/src/test/resources/webapps/WebServerComponentCompressionTest.txt
@@ -0,0 +1 @@
+0123456789012345678901234567890123456789
\ No newline at end of file
diff --git a/docs/user-manual/web-server.adoc b/docs/user-manual/web-server.adoc
index 9f648e8fa2..b71aba496e 100644
--- a/docs/user-manual/web-server.adoc
+++ b/docs/user-manual/web-server.adoc
@@ -34,6 +34,15 @@ The location to redirect the requests with the root target.
 webContentEnabled::
 Whether or not the content included in the web folder of the home and the 
instance directories is accessible.
 Default is `false`.
+compressionEnabled::
+Whether to compress HTTP responses.
+Uses `gzip` encoding for maximum compatibility.
+This will impact any client communicating with the embedded web server 
including the web console and consumers of xref:metrics.adoc#metrics[metrics] 
(e.g. Prometheus) assuming they set the `Accept-Encoding` header to `gzip` in 
their HTTP requests.
+Default is `false`.
+compressionLevel::
+The level of compression for HTTP responses.
+Only valid if `compressionEnabled` is `true`.
+Default is `6`. Must be between `0` and `9` inclusive.
 maxThreads::
 The maximum number of threads the embedded web server can create to service 
HTTP requests.
 Default is `200`.


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to