Skip to content

Commit 421d8a7

Browse files
committed
Revert "Fix reloading of the configuration from HTTP(S)"
This reverts commit be24f92.
1 parent 149dbe7 commit 421d8a7

23 files changed

+810
-916
lines changed

log4j-appserver/pom.xml

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,32 +52,22 @@
5252
org.apache.tomcat.juli;transitive=false,
5353
org.eclipse.jetty.util;transitive=false
5454
</bnd-extra-module-options>
55-
56-
<!-- Dependencies unique for this module -->
57-
<jetty.version>9.4.56.v20240826</jetty.version>
58-
<tomcat-juli.version>10.0.27</tomcat-juli.version>
5955
</properties>
6056

6157
<dependencies>
62-
6358
<dependency>
6459
<groupId>org.eclipse.jetty</groupId>
6560
<artifactId>jetty-util</artifactId>
66-
<version>${jetty.version}</version>
6761
<scope>provided</scope>
6862
</dependency>
69-
7063
<dependency>
7164
<groupId>org.apache.tomcat</groupId>
7265
<artifactId>tomcat-juli</artifactId>
73-
<version>${tomcat-juli.version}</version>
7466
<scope>provided</scope>
7567
</dependency>
76-
7768
<dependency>
7869
<groupId>org.apache.logging.log4j</groupId>
7970
<artifactId>log4j-api</artifactId>
8071
</dependency>
81-
8272
</dependencies>
8373
</project>

log4j-core-test/src/test/java/org/apache/logging/log4j/core/config/ConfigurationSourceTest.java

Lines changed: 29 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
*/
1717
package org.apache.logging.log4j.core.config;
1818

19-
import static java.util.Objects.requireNonNull;
2019
import static org.junit.jupiter.api.Assertions.assertEquals;
2120
import static org.junit.jupiter.api.Assertions.assertNotNull;
2221
import static org.junit.jupiter.api.Assertions.assertNull;
@@ -33,57 +32,50 @@
3332
import java.net.URL;
3433
import java.nio.file.Files;
3534
import java.nio.file.Path;
35+
import java.nio.file.Paths;
3636
import java.util.jar.Attributes;
3737
import java.util.jar.JarEntry;
3838
import java.util.jar.JarOutputStream;
3939
import java.util.jar.Manifest;
40-
import org.apache.commons.io.IOUtils;
4140
import org.apache.logging.log4j.core.net.UrlConnectionFactory;
4241
import org.junit.jupiter.api.Test;
43-
import org.junit.jupiter.api.io.TempDir;
4442

4543
public class ConfigurationSourceTest {
46-
/**
47-
* The path inside the jar created by {@link #prepareJarConfigURL} containing the configuration.
48-
*/
49-
public static final String PATH_IN_JAR = "/config/console.xml";
50-
51-
private static final String CONFIG_FILE = "/config/ConfigurationSourceTest.xml";
52-
53-
@TempDir
54-
private Path tempDir;
44+
private static final Path JAR_FILE = Paths.get("target", "test-classes", "jarfile.jar");
45+
private static final Path CONFIG_FILE = Paths.get("target", "test-classes", "log4j2-console.xml");
46+
private static final byte[] buffer = new byte[1024];
5547

5648
@Test
57-
void testJira_LOG4J2_2770_byteArray() throws Exception {
49+
public void testJira_LOG4J2_2770_byteArray() throws Exception {
5850
final ConfigurationSource configurationSource =
5951
new ConfigurationSource(new ByteArrayInputStream(new byte[] {'a', 'b'}));
6052
assertNotNull(configurationSource.resetInputStream());
6153
}
6254

6355
/**
6456
* Checks if the usage of 'jar:' URLs does not increase the file descriptor
65-
* count, and the jar file can be deleted.
57+
* count and the jar file can be deleted.
58+
*
59+
* @throws Exception
6660
*/
6761
@Test
68-
void testNoJarFileLeak() throws Exception {
69-
final Path jarFile = prepareJarConfigURL(tempDir);
70-
final URL jarConfigURL = new URL("jar:" + jarFile.toUri().toURL() + "!" + PATH_IN_JAR);
62+
public void testNoJarFileLeak() throws Exception {
63+
final URL jarConfigURL = prepareJarConfigURL();
7164
final long expected = getOpenFileDescriptorCount();
7265
UrlConnectionFactory.createConnection(jarConfigURL).getInputStream().close();
7366
// This can only fail on UNIX
7467
assertEquals(expected, getOpenFileDescriptorCount());
7568
// This can only fail on Windows
7669
try {
77-
Files.delete(jarFile);
70+
Files.delete(JAR_FILE);
7871
} catch (IOException e) {
7972
fail(e);
8073
}
8174
}
8275

8376
@Test
8477
public void testLoadConfigurationSourceFromJarFile() throws Exception {
85-
final Path jarFile = prepareJarConfigURL(tempDir);
86-
final URL jarConfigURL = new URL("jar:" + jarFile.toUri().toURL() + "!" + PATH_IN_JAR);
78+
final URL jarConfigURL = prepareJarConfigURL();
8779
final long expectedFdCount = getOpenFileDescriptorCount();
8880
ConfigurationSource configSource = ConfigurationSource.fromUri(jarConfigURL.toURI());
8981
assertNotNull(configSource);
@@ -98,7 +90,7 @@ public void testLoadConfigurationSourceFromJarFile() throws Exception {
9890
assertEquals(expectedFdCount, getOpenFileDescriptorCount());
9991
// This can only fail on Windows
10092
try {
101-
Files.delete(jarFile);
93+
Files.delete(JAR_FILE);
10294
} catch (IOException e) {
10395
fail(e);
10496
}
@@ -112,18 +104,22 @@ private long getOpenFileDescriptorCount() {
112104
return 0L;
113105
}
114106

115-
public static Path prepareJarConfigURL(Path dir) throws IOException {
116-
Path jarFile = dir.resolve("jarFile.jar");
117-
final Manifest manifest = new Manifest();
118-
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
119-
try (final OutputStream os = Files.newOutputStream(jarFile);
120-
final JarOutputStream jar = new JarOutputStream(os, manifest);
121-
final InputStream config =
122-
requireNonNull(ConfigurationSourceTest.class.getResourceAsStream(CONFIG_FILE))) {
123-
final JarEntry jarEntry = new JarEntry("config/console.xml");
124-
jar.putNextEntry(jarEntry);
125-
IOUtils.copy(config, os);
107+
public static URL prepareJarConfigURL() throws IOException {
108+
if (!Files.exists(JAR_FILE)) {
109+
final Manifest manifest = new Manifest();
110+
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
111+
try (final OutputStream os = Files.newOutputStream(JAR_FILE);
112+
final JarOutputStream jar = new JarOutputStream(os, manifest);
113+
final InputStream config = Files.newInputStream(CONFIG_FILE)) {
114+
final JarEntry jarEntry = new JarEntry("config/console.xml");
115+
jar.putNextEntry(jarEntry);
116+
int len;
117+
while ((len = config.read(buffer)) != -1) {
118+
jar.write(buffer, 0, len);
119+
}
120+
jar.closeEntry();
121+
}
126122
}
127-
return jarFile;
123+
return new URL("jar:" + JAR_FILE.toUri().toURL() + "!/config/console.xml");
128124
}
129125
}
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to you under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.logging.log4j.core.filter;
18+
19+
import static org.junit.jupiter.api.Assertions.assertNotEquals;
20+
import static org.junit.jupiter.api.Assertions.assertNotNull;
21+
import static org.junit.jupiter.api.Assertions.assertTrue;
22+
import static org.junit.jupiter.api.Assertions.fail;
23+
24+
import java.io.File;
25+
import java.io.IOException;
26+
import java.nio.file.Files;
27+
import java.nio.file.Path;
28+
import java.nio.file.StandardCopyOption;
29+
import java.util.Base64;
30+
import java.util.Enumeration;
31+
import java.util.concurrent.CountDownLatch;
32+
import java.util.concurrent.TimeUnit;
33+
import javax.servlet.ServletException;
34+
import javax.servlet.http.HttpServletRequest;
35+
import javax.servlet.http.HttpServletResponse;
36+
import org.apache.logging.log4j.Logger;
37+
import org.apache.logging.log4j.ThreadContext;
38+
import org.apache.logging.log4j.core.Appender;
39+
import org.apache.logging.log4j.core.LoggerContext;
40+
import org.apache.logging.log4j.core.config.Configurator;
41+
import org.apache.logging.log4j.core.test.appender.ListAppender;
42+
import org.eclipse.jetty.http.HttpHeader;
43+
import org.eclipse.jetty.server.Server;
44+
import org.eclipse.jetty.server.ServerConnector;
45+
import org.eclipse.jetty.servlet.DefaultServlet;
46+
import org.eclipse.jetty.servlet.ServletContextHandler;
47+
import org.eclipse.jetty.servlet.ServletHolder;
48+
import org.junit.Assert;
49+
import org.junit.jupiter.api.AfterAll;
50+
import org.junit.jupiter.api.AfterEach;
51+
import org.junit.jupiter.api.Assertions;
52+
import org.junit.jupiter.api.BeforeAll;
53+
import org.junitpioneer.jupiter.RetryingTest;
54+
55+
/**
56+
* Unit test for simple App.
57+
*/
58+
public class HttpThreadContextMapFilterTest implements MutableThreadContextMapFilter.FilterConfigUpdateListener {
59+
60+
private static final String BASIC = "Basic ";
61+
private static final String expectedCreds = "log4j:log4j";
62+
private static Server server;
63+
private static final Base64.Decoder decoder = Base64.getDecoder();
64+
private static int port;
65+
static final String CONFIG = "log4j2-mutableFilter.xml";
66+
static LoggerContext loggerContext = null;
67+
static final File targetFile = new File("target/test-classes/testConfig.json");
68+
static final Path target = targetFile.toPath();
69+
CountDownLatch updated = new CountDownLatch(1);
70+
71+
@BeforeAll
72+
public static void startServer() throws Exception {
73+
try {
74+
server = new Server(0);
75+
final ServletContextHandler context = new ServletContextHandler();
76+
final ServletHolder defaultServ = new ServletHolder("default", TestServlet.class);
77+
defaultServ.setInitParameter("resourceBase", System.getProperty("user.dir"));
78+
defaultServ.setInitParameter("dirAllowed", "true");
79+
context.addServlet(defaultServ, "/");
80+
server.setHandler(context);
81+
82+
// Start Server
83+
server.start();
84+
port = ((ServerConnector) server.getConnectors()[0]).getLocalPort();
85+
try {
86+
Files.deleteIfExists(target);
87+
} catch (IOException ioe) {
88+
// Ignore this.
89+
}
90+
} catch (Throwable ex) {
91+
ex.printStackTrace();
92+
throw ex;
93+
}
94+
}
95+
96+
@AfterAll
97+
public static void stopServer() throws Exception {
98+
if (server != null) {
99+
server.stop();
100+
}
101+
}
102+
103+
@AfterEach
104+
public void after() {
105+
try {
106+
Files.deleteIfExists(target);
107+
} catch (IOException ioe) {
108+
// Ignore this.
109+
}
110+
if (loggerContext != null) {
111+
loggerContext.stop();
112+
loggerContext = null;
113+
}
114+
}
115+
116+
@RetryingTest(maxAttempts = 5, suspendForMs = 10)
117+
public void filterTest() throws Exception {
118+
System.setProperty("log4j2.Configuration.allowedProtocols", "http");
119+
System.setProperty("logging.auth.username", "log4j");
120+
System.setProperty("logging.auth.password", "log4j");
121+
System.setProperty("configLocation", "http://localhost:" + port + "/testConfig.json");
122+
ThreadContext.put("loginId", "rgoers");
123+
Path source = new File("target/test-classes/emptyConfig.json").toPath();
124+
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
125+
final long fileTime = targetFile.lastModified() - 2000;
126+
assertTrue(targetFile.setLastModified(fileTime));
127+
loggerContext = Configurator.initialize(null, CONFIG);
128+
assertNotNull(loggerContext);
129+
final Appender app = loggerContext.getConfiguration().getAppender("List");
130+
assertNotNull(app);
131+
assertTrue(app instanceof ListAppender);
132+
final MutableThreadContextMapFilter filter =
133+
(MutableThreadContextMapFilter) loggerContext.getConfiguration().getFilter();
134+
assertNotNull(filter);
135+
filter.registerListener(this);
136+
final Logger logger = loggerContext.getLogger("Test");
137+
logger.debug("This is a test");
138+
Assertions.assertEquals(0, ((ListAppender) app).getEvents().size());
139+
source = new File("target/test-classes/filterConfig.json").toPath();
140+
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
141+
assertNotEquals(fileTime, targetFile.lastModified());
142+
if (!updated.await(5, TimeUnit.SECONDS)) {
143+
fail("File update was not detected");
144+
}
145+
updated = new CountDownLatch(1);
146+
logger.debug("This is a test");
147+
Assertions.assertEquals(1, ((ListAppender) app).getEvents().size());
148+
Assertions.assertTrue(Files.deleteIfExists(target));
149+
if (!updated.await(5, TimeUnit.SECONDS)) {
150+
fail("File update for delete was not detected");
151+
}
152+
}
153+
154+
public static class TestServlet extends DefaultServlet {
155+
156+
private static final long serialVersionUID = -2885158530511450659L;
157+
158+
@Override
159+
protected void doGet(final HttpServletRequest request, final HttpServletResponse response)
160+
throws ServletException, IOException {
161+
final Enumeration<String> headers = request.getHeaders(HttpHeader.AUTHORIZATION.toString());
162+
if (headers == null) {
163+
response.sendError(401, "No Auth header");
164+
return;
165+
}
166+
while (headers.hasMoreElements()) {
167+
final String authData = headers.nextElement();
168+
Assert.assertTrue("Not a Basic auth header", authData.startsWith(BASIC));
169+
final String credentials = new String(decoder.decode(authData.substring(BASIC.length())));
170+
if (!expectedCreds.equals(credentials)) {
171+
response.sendError(401, "Invalid credentials");
172+
return;
173+
}
174+
}
175+
if (request.getServletPath().equals("/testConfig.json")) {
176+
final File file = new File("target/test-classes/testConfig.json");
177+
if (!file.exists()) {
178+
response.sendError(404, "File not found");
179+
return;
180+
}
181+
final long modifiedSince = request.getDateHeader(HttpHeader.IF_MODIFIED_SINCE.toString());
182+
final long lastModified = (file.lastModified() / 1000) * 1000;
183+
if (modifiedSince > 0 && lastModified <= modifiedSince) {
184+
response.setStatus(304);
185+
return;
186+
}
187+
response.setDateHeader(HttpHeader.LAST_MODIFIED.toString(), lastModified);
188+
response.setContentLengthLong(file.length());
189+
Files.copy(file.toPath(), response.getOutputStream());
190+
response.getOutputStream().flush();
191+
response.setStatus(200);
192+
} else {
193+
response.sendError(400, "Unsupported request");
194+
}
195+
}
196+
}
197+
198+
@Override
199+
public void onEvent() {
200+
updated.countDown();
201+
}
202+
}

0 commit comments

Comments
 (0)