ppkarwasz commented on code in PR #4077:
URL: https://github.com/apache/logging-log4j2/pull/4077#discussion_r2984071757
##########
log4j-core/src/main/java/org/apache/logging/log4j/core/jackson/Log4jXmlObjectMapper.java:
##########
@@ -41,7 +51,144 @@ public Log4jXmlObjectMapper() {
* Create a new instance using the {@link Log4jXmlModule}.
*/
public Log4jXmlObjectMapper(final boolean includeStacktrace, final boolean
stacktraceAsString) {
- super(new Log4jXmlModule(includeStacktrace, stacktraceAsString));
+ super(new SanitizingXmlFactory(), new
Log4jXmlModule(includeStacktrace, stacktraceAsString));
this.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
}
+
+ /**
+ * Writer that sanitizes text to be valid XML 1.0 by replacing disallowed
code points with the replacement character (U+FFFD).
+ */
+ private static final class SanitizingWriter extends StreamWriter2Delegate {
+
+ private static final char REPLACEMENT_CHAR = '\uFFFD';
+
+ SanitizingWriter(final XMLStreamWriter2 delegate) {
+ super(delegate);
+ setParent(delegate);
+ }
+
+ @Override
+ public void writeAttribute(final String localName, final String value)
throws XMLStreamException {
+ super.writeAttribute(localName, sanitizeXml10(value));
+ }
+
+ @Override
+ public void writeAttribute(final String namespaceURI, final String
localName, final String value)
+ throws XMLStreamException {
+ super.writeAttribute(namespaceURI, localName,
sanitizeXml10(value));
+ }
+
+ @Override
+ public void writeAttribute(
+ final String prefix, final String namespaceURI, final String
localName, final String value)
+ throws XMLStreamException {
+ super.writeAttribute(prefix, namespaceURI, localName,
sanitizeXml10(value));
+ }
+
+ @Override
+ public void writeCData(String text) throws XMLStreamException {
+ super.writeCData(sanitizeXml10(text));
+ }
+
+ @Override
+ public void writeCData(char[] text, int start, int len) throws
XMLStreamException {
+ super.writeCData(sanitizeXml10(text, start, len));
+ }
+
+ @Override
+ public void writeCharacters(final String text) throws
XMLStreamException {
+ super.writeCharacters(sanitizeXml10(text));
+ }
+
+ @Override
+ public void writeCharacters(final char[] text, final int start, final
int len) throws XMLStreamException {
+ super.writeCharacters(sanitizeXml10(text, start, len));
+ }
+
+ @Override
+ public void writeComment(String text) throws XMLStreamException {
+ super.writeComment(sanitizeXml10(text));
+ }
+
+ private static String sanitizeXml10(final String input) {
+ if (input == null) {
+ return null;
+ }
+ final int length = input.length();
+ // Only create a new string if we find an invalid code point.
+ // In the common case, this should avoid unnecessary allocations.
+ for (int i = 0; i < length; ) {
+ final int cp = input.codePointAt(i);
+ if (!isValidXml10(cp)) {
+ final StringBuilder out = new StringBuilder(length);
+ out.append(input, 0, i);
+ appendSanitized(input, i, length, out);
+ return out.toString();
+ }
+ i += Character.charCount(cp);
+ }
+ return input;
+ }
+
+ private static String sanitizeXml10(final char[] input, final int
start, final int len) {
+ return sanitizeXml10(new String(input, start, len));
+ }
+
+ private static void appendSanitized(final String input, int i, final
int length, final StringBuilder out) {
+ while (i < length) {
+ final int cp = input.codePointAt(i);
+ out.appendCodePoint(isValidXml10(cp) ? cp : REPLACEMENT_CHAR);
+ i += Character.charCount(cp);
+ }
+ }
+
+ /**
+ * Checks if a code point is valid
+ *
+ * @param codePoint a code point between {@code 0} and {@link
Character#MAX_CODE_POINT}
+ * @return {@code true} if it is a valid XML 1.0 code point
+ */
+ private static boolean isValidXml10(final int codePoint) {
+ assert codePoint >= 0 && codePoint <= Character.MAX_CODE_POINT;
+ // XML 1.0 valid characters (Fifth Edition):
+ // #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] |
[#x10000-#x10FFFF]
+
+ // [#x20–#xD7FF] (placed early as a fast path for the most common
case)
+ return (codePoint >= ' ' && codePoint < Character.MIN_SURROGATE)
+ // #x9
+ || codePoint == '\t'
+ // #xA
+ || codePoint == '\n'
+ // #xD
+ || codePoint == '\r'
+ // [#xE000-#xFFFD]
+ || (codePoint > Character.MAX_SURROGATE && codePoint <=
0xFFFD)
+ // [#x10000-#x10FFFF]
+ || codePoint >= Character.MIN_SUPPLEMENTARY_CODE_POINT;
+ }
+ }
+
+ /**
+ * Factory that creates {@link SanitizingWriter} instances to ensure that
all text written to the XML output is valid XML 1.0.
+ */
+ private static final class SanitizingXmlFactory extends XmlFactory {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected XMLStreamWriter _createXmlWriter(final IOContext ctxt, final
Writer w) throws IOException {
+ return new
SanitizingWriter(Stax2WriterAdapter.wrapIfNecessary(super._createXmlWriter(ctxt,
w)));
+ }
+
+ @Override
+ protected XMLStreamWriter _createXmlWriter(final IOContext ctxt, final
OutputStream out) throws IOException {
+ return new
SanitizingWriter(Stax2WriterAdapter.wrapIfNecessary(super._createXmlWriter(ctxt,
out)));
+ }
+
+ @Override
+ public XmlFactory copy() {
+ _checkInvalidCopy(SanitizingXmlFactory.class);
+ return new SanitizingXmlFactory();
+ }
Review Comment:
Fixed in
https://github.com/apache/logging-log4j2/pull/4077/commits/350f7260bc5c162696222b924b0b1922b0e21c78
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]