You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rg...@apache.org on 2021/12/31 22:48:50 UTC

[logging-log4j2] branch LOG4J2-3301 created (now 78075d4)

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

rgoers pushed a change to branch LOG4J2-3301
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git.


      at 78075d4  LOG4J2-3301 - Prevent recursion

This branch includes the following new commits:

     new 78075d4  LOG4J2-3301 - Prevent recursion

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


[logging-log4j2] 01/01: LOG4J2-3301 - Prevent recursion

Posted by rg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 78075d411fee0693f02256dd0d343ed1327602cc
Author: Ralph Goers <rg...@apache.org>
AuthorDate: Fri Dec 31 15:48:25 2021 -0700

    LOG4J2-3301 - Prevent recursion
---
 .../logging/log4j/core/util/OptionConverter.java   | 73 ++++++++++++++++++++--
 .../log4j/core/util/OptionConverterTest.java       | 34 ++++++++++
 2 files changed, 103 insertions(+), 4 deletions(-)

diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/OptionConverter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/OptionConverter.java
index c1f0b13..bd31fd3 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/OptionConverter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/OptionConverter.java
@@ -17,13 +17,16 @@
 package org.apache.logging.log4j.core.util;
 
 import java.io.InterruptedIOException;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Locale;
 import java.util.Properties;
 
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.lookup.StrSubstitutor;
 import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.PropertiesUtil;
+import org.apache.logging.log4j.util.Strings;
 
 /**
  * A convenience class to convert property values to specific types.
@@ -32,6 +35,10 @@ public final class OptionConverter {
 
     private static final Logger LOGGER = StatusLogger.getLogger();
 
+    private static final String DELIM_START = "${";
+    private static final char DELIM_STOP = '}';
+    private static final int DELIM_START_LEN = 2;
+    private static final int DELIM_STOP_LEN = 1;
     private static final int ONE_K = 1024;
 
     /**
@@ -162,9 +169,10 @@ public final class OptionConverter {
         if (hashIndex == -1) {
             if("NULL".equalsIgnoreCase(value)) {
                 return null;
+            } else {
+                // no class name specified : use standard Level class
+                return Level.toLevel(value, defaultValue);
             }
-            // no class name specified : use standard Level class
-            return Level.toLevel(value, defaultValue);
         }
 
         Level result = defaultValue;
@@ -341,6 +349,63 @@ public final class OptionConverter {
      */
     public static String substVars(final String val, final Properties props) throws
         IllegalArgumentException {
-        return StrSubstitutor.replace(val, props);
+        return substVars(val, props, new ArrayList<>());
+    }
+
+    private static String substVars(final String val, final Properties props, List<String> keys)
+            throws IllegalArgumentException {
+
+        final StringBuilder sbuf = new StringBuilder();
+
+        int i = 0;
+        int j;
+        int k;
+
+        while (true) {
+            j = val.indexOf(DELIM_START, i);
+            if (j == -1) {
+                // no more variables
+                if (i == 0) { // this is a simple string
+                    return val;
+                }
+                // add the tail string which contails no variables and return the result.
+                sbuf.append(val.substring(i, val.length()));
+                return sbuf.toString();
+            }
+            sbuf.append(val.substring(i, j));
+            k = val.indexOf(DELIM_STOP, j);
+            if (k == -1) {
+                throw new IllegalArgumentException(Strings.dquote(val)
+                        + " has no closing brace. Opening brace at position " + j
+                        + '.');
+            }
+            j += DELIM_START_LEN;
+            final String key = val.substring(j, k);
+            // first try in System properties
+            String replacement = PropertiesUtil.getProperties().getStringProperty(key, null);
+            // then try props parameter
+            if (replacement == null && props != null) {
+                replacement = props.getProperty(key);
+            }
+
+            if (replacement != null) {
+
+                // Do variable substitution on the replacement string
+                // such that we can solve "Hello ${x2}" as "Hello p1"
+                // the where the properties are
+                // x1=p1
+                // x2=${x1}
+                if (!keys.contains(key)) {
+                    List<String> usedKeys = new ArrayList<>(keys);
+                    usedKeys.add(key);
+                    final String recursiveReplacement = substVars(replacement, props, usedKeys);
+                    sbuf.append(recursiveReplacement);
+                } else {
+                    sbuf.append(replacement);
+                }
+
+            }
+            i = k + DELIM_STOP_LEN;
+        }
     }
 }
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/OptionConverterTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/util/OptionConverterTest.java
index d0d7f90..8725af0 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/OptionConverterTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/util/OptionConverterTest.java
@@ -31,6 +31,40 @@ public class OptionConverterTest {
     public void testSubstVars() {
         Properties props = new Properties();
         props.setProperty("key", "${key}");
+        props.setProperty("testKey", "Log4j");
         assertEquals("Value of key is ${key}.", OptionConverter.substVars("Value of key is ${key}.", props));
+        assertEquals("Value of key is .", OptionConverter.substVars("Value of key is ${key2}.", props));
+        assertEquals("Value of testKey:testKey is Log4j:Log4j",
+                OptionConverter.substVars("Value of testKey:testKey is ${testKey}:${testKey}", props));
+    }
+
+    @Test
+    public void testRecursion() {
+        Properties props = new RecursiveProperties();
+        props.setProperty("name", "Neo");
+        props.setProperty("greeting", "Hello ${name}");
+
+        String s = props.getProperty("greeting");
+        System.out.println("greeting = '"+s+"'");
+    }
+
+    private static class RecursiveProperties extends Properties {
+        @Override
+        public String getProperty(String key)
+        {
+            System.out.println("getProperty for "+key);
+            try
+            {
+                String val = super.getProperty(key);
+                // The following call works for log4j 2.17.0 and causes StackOverflowError for 2.17.1
+                // This is because substVars change implementation in 2.17.1 to call StrSubstitutor.replace(val, props)
+                // which calls props.getProperty() for EVERY property making it recursive
+                return OptionConverter.substVars(val, this);
+            }
+            catch (Exception e)
+            {
+                return super.getProperty(key);
+            }
+        }
     }
 }