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); }