From 75e504b178bc9503721d4d4134c84291d47fe1a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Mon, 1 Jun 2026 12:33:23 +0200 Subject: [PATCH 1/3] Fix encoding of `MSGID` and `SD-ID` fields of `StructuredDataMessage` to XML --- .../message/StructuredDataMessageTest.java | 58 +++++++++++++++++++ .../log4j/message/StructuredDataMessage.java | 20 ++++++- ...fix-StructuredDataMessage-XML-encoding.xml | 12 ++++ 3 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 src/changelog/.2.x.x/fix-StructuredDataMessage-XML-encoding.xml 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..95a8b6ccf88 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(); + sb.append(structuredDataId); + 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..cd6e6e14105 --- /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 + + From ffad55a85d30805e25bd758bddd29f0d7e0097ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Mon, 1 Jun 2026 12:35:03 +0200 Subject: [PATCH 2/3] Fix PR link --- src/changelog/.2.x.x/fix-StructuredDataMessage-XML-encoding.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/changelog/.2.x.x/fix-StructuredDataMessage-XML-encoding.xml b/src/changelog/.2.x.x/fix-StructuredDataMessage-XML-encoding.xml index cd6e6e14105..ae324c0d21d 100644 --- a/src/changelog/.2.x.x/fix-StructuredDataMessage-XML-encoding.xml +++ b/src/changelog/.2.x.x/fix-StructuredDataMessage-XML-encoding.xml @@ -5,7 +5,7 @@ https://logging.apache.org/xml/ns https://logging.apache.org/xml/ns/log4j-changelog-0.xsd" type="fixed"> - + Fix encoding of `MSGID` and `SD-ID` fields of `StructuredDataMessage` to XML From 96de0ff7ebf2df87dd8f38370c33ca09ed585ec0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Mon, 1 Jun 2026 13:20:32 +0200 Subject: [PATCH 3/3] Use `StringBuilderFormattable::formatTo` --- .../org/apache/logging/log4j/message/StructuredDataMessage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 95a8b6ccf88..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 @@ -369,7 +369,7 @@ private void asXml(final StructuredDataId structuredDataId, final StringBuilder // Encode ID sb.append(""); start = sb.length(); - sb.append(structuredDataId); + structuredDataId.formatTo(sb); StringBuilders.escapeXml(sb, start); sb.append("\n");