LOG4J2-2120 Properly escape all control characters in JSON

Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/464ed9a8
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/464ed9a8
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/464ed9a8

Branch: refs/heads/master
Commit: 464ed9a82646416821add6f5f07bf701db3b08a0
Parents: d563cb3
Author: Mikael Ståldal <mik...@staldal.nu>
Authored: Thu Nov 16 21:03:32 2017 +0100
Committer: Mikael Ståldal <mik...@staldal.nu>
Committed: Thu Nov 16 21:03:32 2017 +0100

----------------------------------------------------------------------
 .../logging/log4j/util/StringBuilders.java      | 54 +++++++++++++++-----
 .../logging/log4j/message/MapMessageTest.java   |  7 +--
 2 files changed, 45 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/464ed9a8/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 a2a33ff..a17d195 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
@@ -171,19 +171,47 @@ public final class StringBuilders {
     public static void escapeJson(final StringBuilder toAppendTo, final int 
start) {
         for (int i = toAppendTo.length() - 1; i >= start; i--) { // backwards: 
length may change
             final char c = toAppendTo.charAt(i);
-            if (c == '\n') {
-                // Json string newline character must be encoded as literal 
"\n"
-                toAppendTo.setCharAt(i, '\\');
-                toAppendTo.insert(i + 1, 'n');
-            } else if (Character.isISOControl(c)) {
-                // all iso control characters are in U+00xx
-                toAppendTo.setCharAt(i, '\\');
-                toAppendTo.insert(i + 1, "u0000");
-                toAppendTo.setCharAt(i + 4, Chars.getUpperCaseHex((c & 0xF0) 
>> 4));
-                toAppendTo.setCharAt(i + 5, Chars.getUpperCaseHex(c & 0xF));
-            } else if (c == '"' || c == '\\') {
-                // only " and \ need to be escaped; other escapes are optional
-                toAppendTo.insert(i, '\\');
+            switch (c) {
+                case '\b':
+                    toAppendTo.setCharAt(i, '\\');
+                    toAppendTo.insert(i + 1, 'b');
+                    break;
+
+                case '\t':
+                    toAppendTo.setCharAt(i, '\\');
+                    toAppendTo.insert(i + 1, 't');
+                    break;
+
+                case '\f':
+                    toAppendTo.setCharAt(i, '\\');
+                    toAppendTo.insert(i + 1, 'f');
+                    break;
+
+                case '\n':
+                    // Json string newline character must be encoded as 
literal "\n"
+                    toAppendTo.setCharAt(i, '\\');
+                    toAppendTo.insert(i + 1, 'n');
+                    break;
+
+                case '\r':
+                    toAppendTo.setCharAt(i, '\\');
+                    toAppendTo.insert(i + 1, 'r');
+                    break;
+
+                case '"':
+                case '\\':
+                    // only " and \ need to be escaped; other escapes are 
optional
+                    toAppendTo.insert(i, '\\');
+                    break;
+
+                default:
+                    if (Character.isISOControl(c)) {
+                        // all iso control characters are in U+00xx
+                        toAppendTo.setCharAt(i, '\\');
+                        toAppendTo.insert(i + 1, "u0000");
+                        toAppendTo.setCharAt(i + 4, Chars.getUpperCaseHex((c & 
0xF0) >> 4));
+                        toAppendTo.setCharAt(i + 5, Chars.getUpperCaseHex(c & 
0xF));
+                    }
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/464ed9a8/log4j-api/src/test/java/org/apache/logging/log4j/message/MapMessageTest.java
----------------------------------------------------------------------
diff --git 
a/log4j-api/src/test/java/org/apache/logging/log4j/message/MapMessageTest.java 
b/log4j-api/src/test/java/org/apache/logging/log4j/message/MapMessageTest.java
index 85bea2b..44a15aa 100644
--- 
a/log4j-api/src/test/java/org/apache/logging/log4j/message/MapMessageTest.java
+++ 
b/log4j-api/src/test/java/org/apache/logging/log4j/message/MapMessageTest.java
@@ -94,12 +94,13 @@ public class MapMessageTest {
     }
 
     @Test
-    public void testJSONEscapeNewline() {
-        final String testMsg = "hello\nworld";
+    public void testJSONEscapeNewlineAndOtherControlCharacters() {
+        final String testMsg = "hello\tworld\r\nhh\bere is it\f";
         final StringMapMessage msg = new StringMapMessage();
         msg.put("one\ntwo", testMsg);
         final String result = msg.getFormattedMessage(new String[]{"JSON"});
-        final String expected = "{\"one\\ntwo\":\"hello\\nworld\"}";
+        final String expected =
+                "{\"one\\ntwo\":\"hello\\tworld\\r\\nhh\\bere is it\\f\"}";
         assertEquals(expected, result);
     }
 

Reply via email to