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

rgoers pushed a commit to branch release-2.x
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit e8dab8c5d652437ff61d2e797bfbe4e4e6cdd1bb
Author: Ralph Goers <[email protected]>
AuthorDate: Tue Feb 15 22:44:34 2022 -0700

    LOG4J2-3297 - Limit loading of configuration via a url to https by default
---
 .../org/apache/logging/log4j/util/Strings.java     |   2 +-
 .../org/apache/logging/log4j/util/StringsTest.java |  10 ++
 log4j-core/revapi.json                             |   6 +
 .../log4j/core/config/ConfigurationFactory.java    |   6 +-
 .../log4j/core/net/UrlConnectionFactory.java       |  27 +++-
 .../core/util/BasicAuthorizationProvider.java      |   4 +-
 .../log4j/core/net/UrlConnectionFactoryTest.java   | 177 +++++++++++++++++++++
 .../logging/log4j/core/util/WatchHttpTest.java     |   2 +
 src/changes/changes.xml                            |   3 +
 src/site/xdoc/manual/configuration.xml.vm          |  82 ++++++++++
 10 files changed, 314 insertions(+), 5 deletions(-)

diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/Strings.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/util/Strings.java
index fa1cd9c..c11b9c9 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/Strings.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/Strings.java
@@ -201,7 +201,7 @@ public final class Strings {
     }
 
     public static String[] splitList(String string) {
-        return string.split(COMMA_DELIMITED_RE);
+        return string != null ? string.split(COMMA_DELIMITED_RE) : new 
String[0];
     }
 
     /**
diff --git 
a/log4j-api/src/test/java/org/apache/logging/log4j/util/StringsTest.java 
b/log4j-api/src/test/java/org/apache/logging/log4j/util/StringsTest.java
index c44fa40..6273869 100644
--- a/log4j-api/src/test/java/org/apache/logging/log4j/util/StringsTest.java
+++ b/log4j-api/src/test/java/org/apache/logging/log4j/util/StringsTest.java
@@ -84,6 +84,16 @@ public class StringsTest {
     }
 
     @Test
+    public void splitList() {
+        String[] list = Strings.splitList("1, 2, 3");
+        assertEquals(3, list.length);
+        list = Strings.splitList("");
+        assertEquals(1, list.length);
+        list = Strings.splitList(null);
+        assertEquals(0, list.length);
+    }
+
+    @Test
     public void testQuote() {
         assertEquals("'Q'", Strings.quote("Q"));
     }
diff --git a/log4j-core/revapi.json b/log4j-core/revapi.json
index 9c7f874..b19da41 100644
--- a/log4j-core/revapi.json
+++ b/log4j-core/revapi.json
@@ -118,6 +118,12 @@
         "new": "method org.apache.logging.log4j.core.config.Property 
org.apache.logging.log4j.core.config.Property::createProperty(java.lang.String, 
java.lang.String)",
         "annotation": 
"@org.apache.logging.log4j.core.config.plugins.PluginFactory",
         "justification": "LOG4J2-3317: Fix RoutingAppender backcompat while 
improving lookup security"
+      },
+      {
+        "code": "java.field.constantValueChanged",
+        "old": "field 
org.apache.logging.log4j.core.config.ConfigurationFactory.AUTHORIZATION_PROVIDER",
+        "new": "field 
org.apache.logging.log4j.core.config.ConfigurationFactory.AUTHORIZATION_PROVIDER",
+        "justification": "Added support for a second prefix"
       }
     ]
   }
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java
index ea905dd..1322f85 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java
@@ -98,7 +98,7 @@ public abstract class ConfigurationFactory extends 
ConfigurationBuilderFactory {
 
     public static final String LOG4J1_EXPERIMENTAL = "log4j1.compatibility";
 
-    public static final String AUTHORIZATION_PROVIDER = 
"log4j2.authorizationProvider";
+    public static final String AUTHORIZATION_PROVIDER = 
"authorizationProvider";
 
     /**
      * Plugin category used to inject a ConfigurationFactory {@link 
org.apache.logging.log4j.core.config.plugins.Plugin}
@@ -149,6 +149,8 @@ public abstract class ConfigurationFactory extends 
ConfigurationBuilderFactory {
     private static final String HTTPS = "https";
     private static final String HTTP = "http";
 
+    private static final String[] PREFIXES = {"log4j2.", 
"log4j2.Configuration."};
+
     private static volatile AuthorizationProvider authorizationProvider;
 
     /**
@@ -198,7 +200,7 @@ public abstract class ConfigurationFactory extends 
ConfigurationBuilderFactory {
     }
 
     public static AuthorizationProvider authorizationProvider(PropertiesUtil 
props) {
-        final String authClass = 
props.getStringProperty(AUTHORIZATION_PROVIDER);
+        final String authClass = props.getStringProperty(PREFIXES, 
AUTHORIZATION_PROVIDER, null);
         AuthorizationProvider provider = null;
         if (authClass != null) {
             try {
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/UrlConnectionFactory.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/UrlConnectionFactory.java
index 7f17869..e813170 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/net/UrlConnectionFactory.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/net/UrlConnectionFactory.java
@@ -18,8 +18,14 @@ package org.apache.logging.log4j.core.net;
 
 import java.io.IOException;
 import java.net.HttpURLConnection;
+import java.net.ProtocolException;
 import java.net.URL;
 import java.net.URLConnection;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+import java.util.Properties;
+import java.util.Set;
 import javax.net.ssl.HttpsURLConnection;
 
 import org.apache.logging.log4j.core.config.ConfigurationFactory;
@@ -27,6 +33,9 @@ import 
org.apache.logging.log4j.core.net.ssl.LaxHostnameVerifier;
 import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
 import org.apache.logging.log4j.core.net.ssl.SslConfigurationFactory;
 import org.apache.logging.log4j.core.util.AuthorizationProvider;
+import org.apache.logging.log4j.core.util.BasicAuthorizationProvider;
+import org.apache.logging.log4j.util.PropertiesUtil;
+import org.apache.logging.log4j.util.Strings;
 
 /**
  * Constructs an HTTPURLConnection. This class should be considered to be 
internal
@@ -42,11 +51,27 @@ public class UrlConnectionFactory {
     private static final String TEXT = "text/plain";
     private static final String HTTP = "http";
     private static final String HTTPS = "https";
+    private static final String NO_PROTOCOLS = "_none";
+    public static final String ALLOWED_PROTOCOLS = 
"log4j2.Configuration.allowedProtocols";
 
     public static HttpURLConnection createConnection(URL url, long 
lastModifiedMillis, SslConfiguration sslConfiguration)
         throws IOException {
+        PropertiesUtil props = PropertiesUtil.getProperties();
+        List<String> allowed = Arrays.asList(Strings.splitList(props
+                .getStringProperty(ALLOWED_PROTOCOLS, 
HTTPS).toLowerCase(Locale.ROOT)));
+        if (allowed.size() == 1 && NO_PROTOCOLS.equals(allowed.get(0))) {
+            throw new ProtocolException("No external protocols have been 
enabled");
+        }
+        String protocol = url.getProtocol();
+        if (protocol == null) {
+            throw new ProtocolException("No protocol was specified on " + 
url.toString());
+        }
+        if (!allowed.contains(protocol)) {
+            throw new ProtocolException("Protocol " + protocol + " has not 
been enabled as an allowed protocol");
+        }
         final HttpURLConnection urlConnection = (HttpURLConnection) 
url.openConnection();
-        AuthorizationProvider provider = 
ConfigurationFactory.getAuthorizationProvider();
+
+        AuthorizationProvider provider = 
ConfigurationFactory.authorizationProvider(props);
         if (provider != null) {
             provider.addAuthorization(urlConnection);
         }
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/BasicAuthorizationProvider.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/BasicAuthorizationProvider.java
index eb3d9f3..ec381aa 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/BasicAuthorizationProvider.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/BasicAuthorizationProvider.java
@@ -17,6 +17,8 @@
 package org.apache.logging.log4j.core.util;
 
 import java.net.URLConnection;
+import java.util.Properties;
+
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.apache.logging.log4j.util.Base64Util;
@@ -27,7 +29,7 @@ import org.apache.logging.log4j.util.PropertiesUtil;
  * Provides the Basic Authorization header to a request.
  */
 public class BasicAuthorizationProvider implements AuthorizationProvider {
-    private static final String[] PREFIXES = {"log4j2.config.", 
"logging.auth."};
+    private static final String[] PREFIXES = {"log4j2.config.", 
"log4j2.Configuration.", "logging.auth."};
     private static final String AUTH_USER_NAME = "username";
     private static final String AUTH_PASSWORD = "password";
     private static final String AUTH_PASSWORD_DECRYPTOR = "passwordDecryptor";
diff --git 
a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/UrlConnectionFactoryTest.java
 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/UrlConnectionFactoryTest.java
new file mode 100644
index 0000000..07cd754
--- /dev/null
+++ 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/UrlConnectionFactoryTest.java
@@ -0,0 +1,177 @@
+/*
+ * 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.logging.log4j.core.net;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.nio.file.Files;
+import java.util.Base64;
+import java.util.Enumeration;
+import java.util.Properties;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.config.ConfigurationSource;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.servlet.DefaultServlet;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+/**
+ * Tests the UrlConnectionFactory
+ */
+public class UrlConnectionFactoryTest {
+
+    private static final Logger LOGGER = 
LogManager.getLogger(UrlConnectionFactoryTest.class);
+    private static final String BASIC = "Basic ";
+    private static final String expectedCreds = "testuser:password";
+    private static Server server;
+    private static Base64.Decoder decoder = Base64.getDecoder();
+    private static int port;
+    private static final int NOT_MODIFIED = 304;
+    private static final int NOT_AUTHORIZED = 401;
+    private static final int OK = 200;
+    private static final int BUF_SIZE = 1024;
+
+    @BeforeAll
+    public static void startServer() throws Exception {
+        try {
+            server = new Server(0);
+            ServletContextHandler context = new ServletContextHandler();
+            ServletHolder defaultServ = new ServletHolder("default", 
TestServlet.class);
+            defaultServ.setInitParameter("resourceBase", 
System.getProperty("user.dir"));
+            defaultServ.setInitParameter("dirAllowed", "true");
+            context.addServlet(defaultServ, "/");
+            server.setHandler(context);
+
+            // Start Server
+            server.start();
+            port = ((ServerConnector) 
server.getConnectors()[0]).getLocalPort();
+        } catch (Throwable ex) {
+            ex.printStackTrace();
+            throw ex;
+        }
+    }
+
+    @AfterAll
+    public static void stopServer() throws Exception {
+        server.stop();
+    }
+
+    @Test
+    public void testBadCrdentials() throws Exception {
+        System.setProperty("log4j2.Configuration.username", "foo");
+        System.setProperty("log4j2.Configuration.password", "bar");
+        System.setProperty("log4j2.Configuration.allowedProtocols", "http");
+        URI uri = new URI("http://localhost:"; + port + "/log4j2-config.xml");
+        ConfigurationSource source = ConfigurationSource.fromUri(uri);
+        assertNull(source, "A ConfigurationSource should not have been 
returned");
+    }
+
+    @Test
+    public void withAuthentication() throws Exception {
+        System.setProperty("log4j2.Configuration.username", "testuser");
+        System.setProperty("log4j2.Configuration.password", "password");
+        System.setProperty("log4j2.Configuration.allowedProtocols", "http");
+        URI uri = new URI("http://localhost:"; + port + "/log4j2-config.xml");
+        ConfigurationSource source = ConfigurationSource.fromUri(uri);
+        assertNotNull(source, "No ConfigurationSource returned");
+        InputStream is = source.getInputStream();
+        assertNotNull(is, "No data returned");
+        long lastModified = source.getLastModified();
+        int result = verifyNotModified(uri, lastModified);
+        assertEquals(NOT_MODIFIED, result,"File was modified");
+        File file = new File("target/test-classes/log4j2-config.xml");
+        if (!file.setLastModified(System.currentTimeMillis())) {
+            fail("Unable to set last modified time");
+        }
+        result = verifyNotModified(uri, lastModified);
+        assertEquals(OK, result,"File was not modified");
+    }
+
+    private int verifyNotModified(URI uri, long lastModifiedMillis) throws 
Exception {
+        final HttpURLConnection urlConnection = 
UrlConnectionFactory.createConnection(uri.toURL(),
+                lastModifiedMillis, null);
+        urlConnection.connect();
+
+        try {
+            return urlConnection.getResponseCode();
+        } catch (final IOException ioe) {
+            LOGGER.error("Error accessing configuration at {}: {}", uri, 
ioe.getMessage());
+            return 500;
+        }
+    }
+
+    public static class TestServlet extends DefaultServlet {
+
+        private static final long serialVersionUID = -2885158530511450659L;
+
+        @Override
+        protected void doGet(HttpServletRequest request,
+                HttpServletResponse response) throws ServletException, 
IOException {
+            Enumeration<String> headers = 
request.getHeaders(HttpHeader.AUTHORIZATION.toString());
+            if (headers == null) {
+                response.sendError(401, "No Auth header");
+                return;
+            }
+            while (headers.hasMoreElements()) {
+                String authData = headers.nextElement();
+                assertTrue(authData.startsWith(BASIC), "Not a Basic auth 
header");
+                String credentials = new 
String(decoder.decode(authData.substring(BASIC.length())));
+                if (!expectedCreds.equals(credentials)) {
+                    response.sendError(401, "Invalid credentials");
+                    return;
+                }
+            }
+            if (request.getServletPath().equals("/log4j2-config.xml")) {
+                File file = new File("target/test-classes/log4j2-config.xml");
+                long modifiedSince = 
request.getDateHeader(HttpHeader.IF_MODIFIED_SINCE.toString());
+                long lastModified = (file.lastModified() / 1000) * 1000;
+                LOGGER.debug("LastModified: {}, modifiedSince: {}", 
lastModified, modifiedSince);
+                if (modifiedSince > 0 && lastModified <= modifiedSince) {
+                    response.setStatus(304);
+                    return;
+                }
+                response.setDateHeader(HttpHeader.LAST_MODIFIED.toString(), 
lastModified);
+                response.setContentLengthLong(file.length());
+                Files.copy(file.toPath(), response.getOutputStream());
+                response.getOutputStream().flush();
+                response.setStatus(200);
+            } else {
+                response.sendError(400, "Unsupported request");
+            }
+        }
+    }
+}
diff --git 
a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/WatchHttpTest.java
 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/util/WatchHttpTest.java
index 6d06eed..7dd9db9 100644
--- 
a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/WatchHttpTest.java
+++ 
b/log4j-core/src/test/java/org/apache/logging/log4j/core/util/WatchHttpTest.java
@@ -32,6 +32,7 @@ import 
org.apache.logging.log4j.core.config.ConfigurationScheduler;
 import org.apache.logging.log4j.core.config.DefaultConfiguration;
 import org.apache.logging.log4j.core.config.HttpWatcher;
 import org.apache.logging.log4j.core.config.Reconfigurable;
+import org.apache.logging.log4j.core.net.UrlConnectionFactory;
 import org.apache.logging.log4j.core.net.ssl.TestConstants;
 import org.apache.logging.log4j.core.util.datetime.FastDateFormat;
 import org.apache.logging.log4j.util.PropertiesUtil;
@@ -66,6 +67,7 @@ public class WatchHttpTest {
 
     @BeforeClass
     public static void beforeClass() {
+        System.setProperty(UrlConnectionFactory.ALLOWED_PROTOCOLS, 
"http,https");
         try {
             formatter = FastDateFormat.getInstance("EEE, dd MMM yyyy 
HH:mm:ss", TimeZone.getTimeZone("UTC"));
         } catch (Exception ex) {
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 580c6ea..015b444 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -215,6 +215,9 @@
         Possible NullPointerException in MongoDb4DocumentObject, 
MongoDbDocumentObject, DefaultNoSqlObject.
       </action>
       <!-- ADD -->
+      <action issue="LOG4J2-3297" dev="rgoers" type="add">
+        Limit loading of configuration via a url to https by default. 
+      </action>
       <action issue="LOG4J2-2486" dev="rgoers" type="add">
         Require log4j2.Script.enableLanguages to be specified to enable 
scripting for specific languages.
       </action>
diff --git a/src/site/xdoc/manual/configuration.xml.vm 
b/src/site/xdoc/manual/configuration.xml.vm
index fa73922..fcfde25 100644
--- a/src/site/xdoc/manual/configuration.xml.vm
+++ b/src/site/xdoc/manual/configuration.xml.vm
@@ -367,6 +367,31 @@ public class Bar {
             Note that status logging is disabled when the default 
configuration is used.
           </p>
         </subsection>
+        <a name="Configuration From a URI"/>
+        <subsection name="Configuraton From a URI">
+          <p>
+            When <code>log4j2.configurationFile</code> references a URL Log4j 
will first determine if the URL reference
+            a file using the file protocol. If it does Log4j will validate 
that the file url is valid and continue
+            processing as previously described. If it contains a protocol 
other than file then Log4j will inspect
+            the value of the 
<code>log4j2.Configuration.allowedProtocols</code> system property. If the 
provided list
+            contains the protocol specified then Log4j will use the URI to 
locate the specified configuration file. If
+            not an exception will be thrown and an error message will be 
logged. If no value is provided for the
+            system property it will default to "https". Use of any protocol 
other than "file" can be prevented by
+            setting the system property value to "_none". This value would be 
an invalid protocol so cannot conflict
+            with any custom protocols that may be present.
+          </p>
+          <p>
+            Log4j supports access to remote urls that require authentication. 
Log4j supports basic authentication
+            out of the box. If the <code>log4j2.Configuration.username</code> 
and <code>log4j2.Configuration.password</code>
+            are specified those values will be used to perform the 
authentication. If the password is encrypted a custom
+            password decryptor may be supplied by specifying the fully 
qualified class name in the
+            <code>log4j2.Configuration.passwordDecryptor</code> system 
property. A custom
+            <code>AuthenticationProvider</code> may be used by setting the
+            <code>log4j2.Configuration.authenticationProvider</code> system 
property to the fully qualified class name
+            of the provider.
+          </p>
+
+        </subsection>
         <a name="Additivity"/>
         <subsection name="Additivity">
           <p>
@@ -1990,6 +2015,63 @@ public class AwesomeTest {
     </td>
   </tr>
   <tr>
+    <td><a 
name="configurationAllowedProtocols"/>log4j2.Configuration.allowedProtocols
+      <br />
+      (<a 
name="log4j.configurationAllowedProtocols"/>log4j.configurationAllowedProtocols)
+    </td>
+    <td>LOG4J_CONFIGURATION_ALLOWED_PROTOCOLS</td>
+    <td>&nbsp;</td>
+    <td>
+      A comma separated list of the protocols that may be used to load a 
configuration file. The default is https.
+      To completely prevent accessing the configuration via a URL specify a 
value of "_none".
+    </td>
+  </tr>
+  <tr>
+    <td><a 
name="configurationAuthenticationProvider"/>log4j2.Configuration.authenticationProvider
+      <br />
+      (<a 
name="log4j.configurationAuthenticationProvider"/>log4j.configurationAuthenticationProvider
+    </td>
+    <td>LOG4J_CONFIGURATION_ALLOWED_PROTOCOLS</td>
+    <td>&nbsp;</td>
+    <td>
+      A comma separated list of the protocols that may be used to load a 
configuration file. The default is https.
+      To completely prevent accessing the configuration via a URL specify a 
value of "_none".
+    </td>
+  </tr>
+  <tr>
+    <td><a name="configurationPassword"/>log4j2.Configuration.password
+      <br />
+      (<a name="log4j.configurationPassword"/>log4j.configurationPassword
+    </td>
+    <td>LOG4J_CONFIGURATION_PASSWORD</td>
+    <td>&nbsp;</td>
+    <td>
+     The password required to access the remote logging configuration file.
+    </td>
+  </tr>
+  <tr>
+    <td><a 
name="configurationPasswordDecryptor"/>log4j2.Configuration.passwordDecryptor
+      <br />
+      (<a 
name="log4j.configurationPasswordDecryptor"/>log4j.configurationPasswordDecryptor
+    </td>
+    <td>LOG4J_CONFIGURATION_PASSWORD_DECRYPTOR</td>
+    <td>&nbsp;</td>
+    <td>
+      If the password is encrypted this class will be used to decrypt it.
+    </td>
+  </tr>
+  <tr>
+    <td><a name="configurationUsername"/>log4j2.Configuration.username
+      <br />
+      (<a name="log4j.configurationUsername"/>log4j.configurationUsername
+    </td>
+    <td>LOG4J_CONFIGURATION_USERNAME</td>
+    <td>&nbsp;</td>
+    <td>
+      The user name required to access the remote logging configuration file.
+    </td>
+  </tr>
+  <tr>
     <td><a name="shutdownHookEnabled"/>log4j2.shutdownHookEnabled
       <br />
       (<a name="log4j.shutdownHookEnabled"/>log4j.shutdownHookEnabled)

Reply via email to