This is an automated email from the ASF dual-hosted git repository. ramanathan1504 pushed a commit to branch 2.25.x in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
commit 1ff0b08aeb1d9ea054ffcda5c7bf7e1e769f69db Author: Volkan Yazıcı <[email protected]> AuthorDate: Fri Jun 5 10:13:02 2026 +0200 Fix encoding of `MSGID` and `SD-ID` fields of `StructuredDataMessage` to XML (#4136) --- .../log4j/message/StructuredDataMessageTest.java | 58 ++++++++++++++++++++++ .../log4j/message/StructuredDataMessage.java | 20 +++++++- .../fix-StructuredDataMessage-XML-encoding.xml | 12 +++++ 3 files changed, 88 insertions(+), 2 deletions(-) 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 f02d95eefe..3d3f403bef 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 @@ class StructuredDataMessageTest { assertEquals(expected, result); } + @Test + void testXmlEncodingOfIdAndType1() { + final String id = "i<&d>" + XmlFixture.TEXT; + final String type = "t>yp<e&" + XmlFixture.TEXT; + final String actualXml = + new StructuredDataMessage(id, "discarded message", type).getFormattedMessage(new String[] {"XML"}); + final String expectedXml = "<StructuredData>\n" + + "<type>t>yp<e&" + XmlFixture.ENCODED_TEXT + + "</type>\n" + + "<id>i<&d>" + XmlFixture.ENCODED_TEXT + + "</id>\n" + // Following part is encoded by `MapMessage::asXml`, hence, fuzzed & tested elsewhere + + "<Map>\n" + + "</Map>\n" + + "</StructuredData>\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>yp<e&" + XmlFixture.TEXT; + final StructuredDataId id = + new StructuredDataId(idName, idEnterpriseNumber, idRequired, idOptional, Integer.MAX_VALUE); + final String actualXml = + new StructuredDataMessage(id, "discarded message", type).getFormattedMessage(new String[] {"XML"}); + final String expectedXml = "<StructuredData>\n" + + "<type>t>yp<e&" + XmlFixture.ENCODED_TEXT + + "</type>\n" + + "<id>" + "id&<-name>" + XmlFixture.ENCODED_TEXT + + "@id&<-enterprise-number>" + XmlFixture.ENCODED_TEXT + + "</id>\n" + // Following part is encoded by `MapMessage::asXml`, hence, fuzzed & tested elsewhere + + "<Map>\n" + + "</Map>\n" + + "</StructuredData>\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 46b757d54f..69fa3fb8cb 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 class StructuredDataMessage extends MapMessage<StructuredDataMessage, Str } private void asXml(final StructuredDataId structuredDataId, final StringBuilder sb) { + sb.append("<StructuredData>\n"); - sb.append("<type>").append(type).append("</type>\n"); - sb.append("<id>").append(structuredDataId).append("</id>\n"); + + // Encode type + sb.append("<type>"); + int start = sb.length(); + sb.append(type); + StringBuilders.escapeXml(sb, start); + sb.append("</type>\n"); + + // Encode ID + sb.append("<id>"); + start = sb.length(); + structuredDataId.formatTo(sb); + StringBuilders.escapeXml(sb, start); + sb.append("</id>\n"); + + // Encode the rest super.asXml(sb); + sb.append("\n</StructuredData>\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 0000000000..ae324c0d21 --- /dev/null +++ b/src/changelog/.2.x.x/fix-StructuredDataMessage-XML-encoding.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<entry xmlns="https://logging.apache.org/xml/ns" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation=" + https://logging.apache.org/xml/ns + https://logging.apache.org/xml/ns/log4j-changelog-0.xsd" + type="fixed"> + <issue id="4136" link="https://github.com/apache/logging-log4j2/pull/4136"/> + <description format="asciidoc"> + Fix encoding of `MSGID` and `SD-ID` fields of `StructuredDataMessage` to XML + </description> +</entry>
