Repository: logging-log4j2 Updated Branches: refs/heads/release-2.x 641238d4e -> 6aed3fbc5
[LOG4J2-2376] Optimize XML escape functionality and add unit testing. This closes #192 Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/6aed3fbc Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/6aed3fbc Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/6aed3fbc Branch: refs/heads/release-2.x Commit: 6aed3fbc5893526fc838f542acb9301c4274dd10 Parents: 641238d Author: kmeurer <[email protected]> Authored: Mon Jul 16 12:33:57 2018 -0400 Committer: Carter Kozak <[email protected]> Committed: Mon Jul 16 13:51:44 2018 -0400 ---------------------------------------------------------------------- .../logging/log4j/util/StringBuilders.java | 60 ++++++++++++++++---- .../logging/log4j/util/StringBuildersTest.java | 12 ++++ src/changes/changes.xml | 4 ++ 3 files changed, 65 insertions(+), 11 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/6aed3fbc/log4j-api/src/main/java/org/apache/logging/log4j/util/StringBuilders.java ---------------------------------------------------------------------- diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/StringBuilders.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/StringBuilders.java index 2a83b24..48fa98f 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/util/StringBuilders.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/StringBuilders.java @@ -245,29 +245,67 @@ public final class StringBuilders { } public static void escapeXml(final StringBuilder toAppendTo, final int start) { - for (int i = toAppendTo.length() - 1; i >= start; i--) { // backwards: length may change + int escapeCount = 0; + for (int i = start; i < toAppendTo.length(); i++) { + final char c = toAppendTo.charAt(i); + switch (c) { + case '&': + escapeCount += 4; + break; + case '<': + case '>': + escapeCount += 3; + break; + case '"': + case '\'': + escapeCount += 5; + } + } + + int lastChar = toAppendTo.length() - 1; + toAppendTo.setLength(toAppendTo.length() + escapeCount); + int lastPos = toAppendTo.length() - 1; + + for (int i = lastChar; lastPos > i; i--) { final char c = toAppendTo.charAt(i); switch (c) { case '&': - toAppendTo.setCharAt(i, '&'); - toAppendTo.insert(i + 1, "amp;"); + toAppendTo.setCharAt(lastPos--, ';'); + toAppendTo.setCharAt(lastPos--, 'p'); + toAppendTo.setCharAt(lastPos--, 'm'); + toAppendTo.setCharAt(lastPos--, 'a'); + toAppendTo.setCharAt(lastPos--, '&'); break; case '<': - toAppendTo.setCharAt(i, '&'); - toAppendTo.insert(i + 1, "lt;"); + toAppendTo.setCharAt(lastPos--, ';'); + toAppendTo.setCharAt(lastPos--, 't'); + toAppendTo.setCharAt(lastPos--, 'l'); + toAppendTo.setCharAt(lastPos--, '&'); break; case '>': - toAppendTo.setCharAt(i, '&'); - toAppendTo.insert(i + 1, "gt;"); + toAppendTo.setCharAt(lastPos--, ';'); + toAppendTo.setCharAt(lastPos--, 't'); + toAppendTo.setCharAt(lastPos--, 'g'); + toAppendTo.setCharAt(lastPos--, '&'); break; case '"': - toAppendTo.setCharAt(i, '&'); - toAppendTo.insert(i + 1, "quot;"); + toAppendTo.setCharAt(lastPos--, ';'); + toAppendTo.setCharAt(lastPos--, 't'); + toAppendTo.setCharAt(lastPos--, 'o'); + toAppendTo.setCharAt(lastPos--, 'u'); + toAppendTo.setCharAt(lastPos--, 'q'); + toAppendTo.setCharAt(lastPos--, '&'); break; case '\'': - toAppendTo.setCharAt(i, '&'); - toAppendTo.insert(i + 1, "apos;"); + toAppendTo.setCharAt(lastPos--, ';'); + toAppendTo.setCharAt(lastPos--, 's'); + toAppendTo.setCharAt(lastPos--, 'o'); + toAppendTo.setCharAt(lastPos--, 'p'); + toAppendTo.setCharAt(lastPos--, 'a'); + toAppendTo.setCharAt(lastPos--, '&'); break; + default: + toAppendTo.setCharAt(lastPos--, c); } } } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/6aed3fbc/log4j-api/src/test/java/org/apache/logging/log4j/util/StringBuildersTest.java ---------------------------------------------------------------------- diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/util/StringBuildersTest.java b/log4j-api/src/test/java/org/apache/logging/log4j/util/StringBuildersTest.java index 7c74073..6feecbb 100644 --- a/log4j-api/src/test/java/org/apache/logging/log4j/util/StringBuildersTest.java +++ b/log4j-api/src/test/java/org/apache/logging/log4j/util/StringBuildersTest.java @@ -77,4 +77,16 @@ public class StringBuildersTest { StringBuilders.escapeJson(sb, 0); assertEquals(jsonValueEscaped, sb.toString()); } + + @Test + public void escapeXMLCharactersCorrectly() { + String xmlValueNotEscaped = "<\"Salt&Peppa'\">"; + String xmlValueEscaped = "<"Salt&Peppa'">"; + + StringBuilder sb = new StringBuilder(); + sb.append(xmlValueNotEscaped); + assertEquals(xmlValueNotEscaped, sb.toString()); + StringBuilders.escapeXml(sb, 0); + assertEquals(xmlValueEscaped, sb.toString()); + } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/6aed3fbc/src/changes/changes.xml ---------------------------------------------------------------------- diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 670ec21..2ffafe4 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -148,6 +148,10 @@ StringBuilders.escapeJson implementation runs in linear time. Escaping large JSON strings in EncodingPatternConverter and MapMessage will perform significantly better. </action> + <action issue="LOG4J2-2376" dev="ckozak" type="fix" due-to="Kevin Meurer"> + StringBuilders.escapeXml implementation runs in linear time. Escaping large XML strings + in EncodingPatternConverter and MapMessage will perform significantly better. + </action> </release> <release version="2.11.0" date="2018-03-11" description="GA Release 2.11.0"> <action issue="LOG4J2-2104" dev="rgoers" type="fix">
