This is an automated email from the ASF dual-hosted git repository. clebertsuconic pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/activemq-artemis.git
The following commit(s) were added to refs/heads/main by this push: new 36056a5bdd ARTEMIS-4513 HTTP request logging not working 36056a5bdd is described below commit 36056a5bddeaf431bd282cc0f231f53675549117 Author: Justin Bertram <jbert...@apache.org> AuthorDate: Tue Nov 21 14:37:47 2023 -0600 ARTEMIS-4513 HTTP request logging not working --- .../artemis/component/WebServerComponent.java | 12 +- tests/integration-tests-isolated/pom.xml | 6 + .../isolated/web/WebServerComponentTest.java | 185 +++++++++++++++++++++ .../resources/webapps/WebServerComponentTest.txt | 1 + 4 files changed, 197 insertions(+), 7 deletions(-) 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 8f71d73694..f1d1300d03 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 @@ -18,6 +18,7 @@ package org.apache.activemq.artemis.component; import javax.servlet.DispatcherType; import java.io.File; +import java.lang.invoke.MethodHandles; import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; @@ -40,6 +41,7 @@ import org.eclipse.jetty.server.ConnectionFactory; import org.eclipse.jetty.server.CustomRequestLog; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.server.RequestLog; import org.eclipse.jetty.server.RequestLogWriter; import org.eclipse.jetty.server.SecureRequestCustomizer; import org.eclipse.jetty.server.Server; @@ -47,14 +49,12 @@ import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.SslConnectionFactory; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.HandlerList; -import org.eclipse.jetty.server.handler.RequestLogHandler; import org.eclipse.jetty.server.handler.ResourceHandler; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.webapp.WebAppContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.lang.invoke.MethodHandles; public class WebServerComponent implements ExternalComponent, WebServerComponentMarker { @@ -175,7 +175,7 @@ public class WebServerComponent implements ExternalComponent, WebServerComponent defaultHandler.setRootRedirectLocation(this.webServerConfig.rootRedirectLocation); if (this.webServerConfig.requestLog != null) { - handlers.addHandler(getLogHandler()); + server.setRequestLog(getRequestLog()); } if (this.webServerConfig.webContentEnabled != null && @@ -269,7 +269,7 @@ public class WebServerComponent implements ExternalComponent, WebServerComponent return connector; } - private RequestLogHandler getLogHandler() { + private RequestLog getRequestLog() { RequestLogWriter requestLogWriter = new RequestLogWriter(); CustomRequestLog requestLog; @@ -305,9 +305,7 @@ public class WebServerComponent implements ExternalComponent, WebServerComponent requestLog.setIgnorePaths(ignorePaths); } - RequestLogHandler requestLogHandler = new RequestLogHandler(); - requestLogHandler.setRequestLog(requestLog); - return requestLogHandler; + return requestLog; } private File getLibFolder() { diff --git a/tests/integration-tests-isolated/pom.xml b/tests/integration-tests-isolated/pom.xml index 6724ad4b7b..083a56d9b7 100644 --- a/tests/integration-tests-isolated/pom.xml +++ b/tests/integration-tests-isolated/pom.xml @@ -205,6 +205,12 @@ <artifactId>protonj2-test-driver</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.apache.activemq</groupId> + <artifactId>artemis-web</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> <dependency> <groupId>jakarta.management.j2ee</groupId> <artifactId>jakarta.management.j2ee-api</artifactId> diff --git a/tests/integration-tests-isolated/src/test/java/org/apache/activemq/artemis/tests/integration/isolated/web/WebServerComponentTest.java b/tests/integration-tests-isolated/src/test/java/org/apache/activemq/artemis/tests/integration/isolated/web/WebServerComponentTest.java new file mode 100644 index 0000000000..cc0fb46047 --- /dev/null +++ b/tests/integration-tests-isolated/src/test/java/org/apache/activemq/artemis/tests/integration/isolated/web/WebServerComponentTest.java @@ -0,0 +1,185 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.activemq.artemis.tests.integration.isolated.web; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.nio.NioSocketChannel; +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.HttpMethod; +import io.netty.handler.codec.http.HttpObject; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpResponse; +import io.netty.handler.codec.http.HttpVersion; +import io.netty.handler.codec.http.LastHttpContent; +import io.netty.util.CharsetUtil; +import org.apache.activemq.artemis.component.WebServerComponent; +import org.apache.activemq.artemis.core.server.ActiveMQComponent; +import org.apache.activemq.artemis.dto.BindingDTO; +import org.apache.activemq.artemis.dto.RequestLogDTO; +import org.apache.activemq.artemis.dto.WebServerDTO; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +/** + * This test leaks a thread named org.eclipse.jetty.util.RolloverFileOutputStream which is why it is isolated now. + * In the future Jetty might fix this. + */ +public class WebServerComponentTest extends Assert { + + static final String URL = System.getProperty("url", "http://localhost:8161/WebServerComponentTest.txt"); + + private List<ActiveMQComponent> testedComponents; + + @Before + public void setupNetty() throws URISyntaxException { + System.setProperty("jetty.base", "./target"); + // Configure the client. + testedComponents = new ArrayList<>(); + } + + @After + public void tearDown() throws Exception { + System.clearProperty("jetty.base"); + for (ActiveMQComponent c : testedComponents) { + c.stop(); + } + testedComponents.clear(); + } + + @Test + public void testRequestLog() throws Exception { + String requestLogFileName = "target/httpRequest.log"; + BindingDTO bindingDTO = new BindingDTO(); + bindingDTO.uri = "http://localhost:0"; + WebServerDTO webServerDTO = new WebServerDTO(); + webServerDTO.setBindings(Collections.singletonList(bindingDTO)); + webServerDTO.path = "webapps"; + webServerDTO.webContentEnabled = true; + RequestLogDTO requestLogDTO = new RequestLogDTO(); + requestLogDTO.filename = requestLogFileName; + webServerDTO.setRequestLog(requestLogDTO); + WebServerComponent webServerComponent = new WebServerComponent(); + Assert.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); + + URI uri = new URI(URL); + // Prepare the HTTP request. + HttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uri.getRawPath()); + request.headers().set(HttpHeaderNames.HOST, "localhost"); + + // Send the HTTP request. + ch.writeAndFlush(request); + assertTrue(latch.await(5, TimeUnit.SECONDS)); + assertEquals("12345", clientHandler.body.toString()); + assertEquals(clientHandler.body.toString(), "12345"); + assertNull(clientHandler.serverHeader); + // Wait for the server to close the connection. + ch.close(); + ch.eventLoop().shutdownGracefully(); + ch.eventLoop().awaitTermination(5, TimeUnit.SECONDS); + Assert.assertTrue(webServerComponent.isStarted()); + webServerComponent.stop(true); + Assert.assertFalse(webServerComponent.isStarted()); + File requestLog = new File(requestLogFileName); + assertTrue(requestLog.exists()); + boolean logEntryFound = false; + try (BufferedReader reader = new BufferedReader(new FileReader(requestLog))) { + String line; + while ((line = reader.readLine()) != null) { + if (line.contains("\"GET /WebServerComponentTest.txt HTTP/1.1\" 200 5")) { + logEntryFound = true; + break; + } + } + } + assertTrue(logEntryFound); + } + + private Channel getChannel(int port, ClientHandler clientHandler) throws InterruptedException { + EventLoopGroup group = new NioEventLoopGroup(); + Bootstrap bootstrap = new Bootstrap(); + bootstrap.group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer() { + @Override + protected void initChannel(Channel ch) throws Exception { + ch.pipeline().addLast(new HttpClientCodec()); + ch.pipeline().addLast(clientHandler); + } + }); + return bootstrap.connect("localhost", port).sync().channel(); + } + + class ClientHandler extends SimpleChannelInboundHandler<HttpObject> { + + private CountDownLatch latch; + private StringBuilder body = new StringBuilder(); + private String serverHeader; + + ClientHandler(CountDownLatch latch) { + this.latch = latch; + } + + @Override + public void channelRead0(ChannelHandlerContext ctx, HttpObject msg) { + if (msg instanceof HttpResponse) { + HttpResponse response = (HttpResponse) msg; + serverHeader = response.headers().get("Server"); + } else if (msg instanceof HttpContent) { + HttpContent content = (HttpContent) msg; + body.append(content.content().toString(CharsetUtil.UTF_8)); + if (msg instanceof LastHttpContent) { + latch.countDown(); + } + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + cause.printStackTrace(); + ctx.close(); + } + } +} diff --git a/tests/integration-tests-isolated/src/test/resources/webapps/WebServerComponentTest.txt b/tests/integration-tests-isolated/src/test/resources/webapps/WebServerComponentTest.txt new file mode 100644 index 0000000000..bd41cba781 --- /dev/null +++ b/tests/integration-tests-isolated/src/test/resources/webapps/WebServerComponentTest.txt @@ -0,0 +1 @@ +12345 \ No newline at end of file