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:51 UTC
[logging-log4j2] 01/01: LOG4J2-3301 - Prevent recursion
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);
+ }
+ }
}
}