Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
8 changes: 8 additions & 0 deletions artemis-web/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@
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;
Expand Down Expand Up @@ -149,6 +154,21 @@ public synchronized void start() throws Exception {
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();

Expand Down Expand Up @@ -253,8 +273,6 @@ public void requestDestroyed(ServletRequestEvent sre) {

handlers.addHandler(defaultHandler); // this should be last

server.setHandler(handlers);

server.start();

printStatus(bindings);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
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;
Expand Down Expand Up @@ -202,6 +203,62 @@ private void internalSimpleServer(boolean useCustomizer) throws Exception {
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();
Expand Down Expand Up @@ -1133,6 +1190,7 @@ class ClientHandler extends SimpleChannelInboundHandler<HttpObject> {
private CountDownLatch latch;
private StringBuilder body = new StringBuilder();
private String serverHeader;
private HttpHeaders headers;

ClientHandler(CountDownLatch latch) {
this.latch = latch;
Expand All @@ -1141,6 +1199,7 @@ class ClientHandler extends SimpleChannelInboundHandler<HttpObject> {
@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));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0123456789012345678901234567890123456789
9 changes: 9 additions & 0 deletions docs/user-manual/web-server.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down