diff --git a/log4j-api-test/src/test/java/org/apache/logging/log4j/message/StructuredDataMessageTest.java b/log4j-api-test/src/test/java/org/apache/logging/log4j/message/StructuredDataMessageTest.java index f02d95eefef..3d3f403bef7 100644 --- a/log4j-api-test/src/test/java/org/apache/logging/log4j/message/StructuredDataMessageTest.java +++ b/log4j-api-test/src/test/java/org/apache/logging/log4j/message/StructuredDataMessageTest.java @@ -73,6 +73,64 @@ void testMsgXml() { assertEquals(expected, result); } + @Test + void testXmlEncodingOfIdAndType1() { + final String id = "i<&d>" + XmlFixture.TEXT; + final String type = "t>ypt>yp<e&" + XmlFixture.ENCODED_TEXT + + "\n" + + "i<&d>" + XmlFixture.ENCODED_TEXT + + "\n" + // Following part is encoded by `MapMessage::asXml`, hence, fuzzed & tested elsewhere + + "\n" + + "\n" + + "\n"; + assertEquals(expectedXml, actualXml); + } + + @Test + void testXmlEncodingOfIdAndType2() { + final String idName = "id&<-name>" + XmlFixture.TEXT; + final String idEnterpriseNumber = "id&<-enterprise-number>" + XmlFixture.TEXT; + final String[] idRequired = {"id&<-required>" + XmlFixture.TEXT}; + final String[] idOptional = {"id&<-optional>" + XmlFixture.TEXT}; + final String type = "t>ypt>yp<e&" + XmlFixture.ENCODED_TEXT + + "\n" + + "" + "id&<-name>" + XmlFixture.ENCODED_TEXT + + "@id&<-enterprise-number>" + XmlFixture.ENCODED_TEXT + + "\n" + // Following part is encoded by `MapMessage::asXml`, hence, fuzzed & tested elsewhere + + "\n" + + "\n" + + "\n"; + assertEquals(expectedXml, actualXml); + } + + private enum XmlFixture { + ; + + private static final String TEXT; + + private static final String ENCODED_TEXT; + + static { + final String notBmp = new String(Character.toChars(0x10000)); + final String invalid = "A\uD800B\uDE00C\0\1\2\3"; + final String encodedInvalid = "A\uFFFDB\uFFFDC\uFFFD\uFFFD\uFFFD\uFFFD"; + TEXT = " '\"\t\r\n" + notBmp + invalid; + ENCODED_TEXT = " '"\t\r\n" + notBmp + encodedInvalid; + } + } + @Test void testBuilder() { final String testMsg = "Test message {}"; diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/message/StructuredDataMessage.java b/log4j-api/src/main/java/org/apache/logging/log4j/message/StructuredDataMessage.java index 46b757d54f2..69fa3fb8cbe 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/message/StructuredDataMessage.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/message/StructuredDataMessage.java @@ -356,10 +356,26 @@ public final void asString(final Format format, final StructuredDataId structure } private void asXml(final StructuredDataId structuredDataId, final StringBuilder sb) { + sb.append("\n"); - sb.append("").append(type).append("\n"); - sb.append("").append(structuredDataId).append("\n"); + + // Encode type + sb.append(""); + int start = sb.length(); + sb.append(type); + StringBuilders.escapeXml(sb, start); + sb.append("\n"); + + // Encode ID + sb.append(""); + start = sb.length(); + structuredDataId.formatTo(sb); + StringBuilders.escapeXml(sb, start); + sb.append("\n"); + + // Encode the rest super.asXml(sb); + sb.append("\n\n"); } diff --git a/src/changelog/.2.x.x/fix-StructuredDataMessage-XML-encoding.xml b/src/changelog/.2.x.x/fix-StructuredDataMessage-XML-encoding.xml new file mode 100644 index 00000000000..ae324c0d21d --- /dev/null +++ b/src/changelog/.2.x.x/fix-StructuredDataMessage-XML-encoding.xml @@ -0,0 +1,12 @@ + + + + + Fix encoding of `MSGID` and `SD-ID` fields of `StructuredDataMessage` to XML + +