You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by sw...@apache.org on 2026/05/16 02:21:52 UTC

(logging-log4cxx) branch master updated: Preserve HTMLLayout attribute values during XML normalization (#666)

This is an automated email from the ASF dual-hosted git repository.

swebb2066 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4cxx.git


The following commit(s) were added to refs/heads/master by this push:
     new 9b3d2199 Preserve HTMLLayout attribute values during XML normalization (#666)
9b3d2199 is described below

commit 9b3d21992d6ecc07eff07df95855bc0249cca019
Author: jmestwa-coder <jm...@gmail.com>
AuthorDate: Sat May 16 07:51:47 2026 +0530

    Preserve HTMLLayout attribute values during XML normalization (#666)
---
 src/main/cpp/htmllayout.cpp                  |  4 +-
 src/main/cpp/transform.cpp                   | 59 ++++++++++++++++++++--------
 src/main/include/log4cxx/helpers/transform.h | 13 ++++++
 src/test/cpp/xml/xmllayouttest.cpp           |  6 ++-
 4 files changed, 63 insertions(+), 19 deletions(-)

diff --git a/src/main/cpp/htmllayout.cpp b/src/main/cpp/htmllayout.cpp
index 2655e0b4..d7404435 100644
--- a/src/main/cpp/htmllayout.cpp
+++ b/src/main/cpp/htmllayout.cpp
@@ -97,7 +97,7 @@ void HTMLLayout::format( LOG4CXX_FORMAT_LAYOUT_FORMAL_PARAMETERS ) const
 
 	output.append(LOG4CXX_STR("<td title=\""));
 	LogString threadName(event->getThreadName());
-	Transform::appendLegalCharacters(output, threadName);
+	Transform::appendEscapingAttribute(output, threadName);
 	output.append(LOG4CXX_STR(" thread\">"));
 	Transform::appendEscapingTags(output, threadName);
 	output.append(LOG4CXX_STR("</td>"));
@@ -126,7 +126,7 @@ void HTMLLayout::format( LOG4CXX_FORMAT_LAYOUT_FORMAL_PARAMETERS ) const
 	output.append(LOG4CXX_EOL);
 
 	output.append(LOG4CXX_STR("<td title=\""));
-	Transform::appendLegalCharacters(output, event->getLoggerName());
+	Transform::appendEscapingAttribute(output, event->getLoggerName());
 	output.append(LOG4CXX_STR(" logger\">"));
 	Transform::appendEscapingTags(output, event->getLoggerName());
 	output.append(LOG4CXX_STR("</td>"));
diff --git a/src/main/cpp/transform.cpp b/src/main/cpp/transform.cpp
index 32397a76..ec7c68c4 100644
--- a/src/main/cpp/transform.cpp
+++ b/src/main/cpp/transform.cpp
@@ -26,11 +26,11 @@ using namespace LOG4CXX_NS::helpers;
 
 namespace
 {
-using CharProcessor = std::function<void(LogString&, int)>;
+using CharProcessor = std::function<bool(LogString&, int)>;
 
 // Allowable XML 1.0 characters are:
 // #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
-void appendValidCharacters(LogString& buf, const LogString& input, CharProcessor handler = {})
+void appendValidCharacters(LogString& buf, const LogString& input, CharProcessor handler = {}, bool handleValidCharacters = false)
 {
 	static const unsigned int specials[] =
 		{ 0x22 /* " */
@@ -46,18 +46,23 @@ void appendValidCharacters(LogString& buf, const LogString& input, CharProcessor
 		auto ch = Transcoder::decode(input, nextCodePoint);
 		if (nextCodePoint == lastCodePoint) // failed to decode input?
 			nextCodePoint = input.end();
-		else if ((0x20 <= ch && ch <= 0xD7FF) &&
-			specials[0] != ch &&
-			specials[1] != ch &&
-			specials[2] != ch &&
-			specials[3] != ch)
-		{
-			continue;
-		}
-		else if ((0x9 == ch || 0xA == ch || 0xD == ch) ||
-				(0xE000 <= ch && ch <= 0xFFFD) ||
-				(0x10000 <= ch && ch <= 0x10FFFF))
+		else if (((0x20 <= ch && ch <= 0xD7FF) &&
+				specials[0] != ch &&
+				specials[1] != ch &&
+				specials[2] != ch &&
+				specials[3] != ch) ||
+			(0x9 == ch || 0xA == ch || 0xD == ch) ||
+			(0xE000 <= ch && ch <= 0xFFFD) ||
+			(0x10000 <= ch && ch <= 0x10FFFF))
 		{
+			LogString escaped;
+			if (handleValidCharacters && handler && handler(escaped, ch))
+			{
+				if (start != lastCodePoint)
+					buf.append(start, lastCodePoint);
+				buf.append(escaped);
+				start = nextCodePoint;
+			}
 			continue;
 		}
 
@@ -89,14 +94,31 @@ void appendValidCharacters(LogString& buf, const LogString& input, CharProcessor
 				break;
 
 			default:
-				if (handler)
-					handler(buf, ch);
+				if (handler && !handler(buf, ch))
+					Transform::appendCharacterReference(buf, ch);
 				break;
 		}
 	}
 	buf.append(start, input.end());
 }
 
+bool appendCharacterReferenceHandler(LogString& buf, int ch)
+{
+	Transform::appendCharacterReference(buf, ch);
+	return true;
+}
+
+bool appendAttributeCharacterReference(LogString& buf, int ch)
+{
+	if (0x27 == ch || 0x9 == ch || 0xA == ch || 0xD == ch)
+	{
+		Transform::appendCharacterReference(buf, ch);
+		return true;
+	}
+
+	return false;
+}
+
 } // namespace
 
 void Transform::appendEscapingCDATA(
@@ -177,7 +199,12 @@ void Transform::appendCharacterReference(LogString& buf, unsigned int ch)
 
 void Transform::appendEscapingTags(LogString& buf, const LogString& input)
 {
-	appendValidCharacters(buf, input, appendCharacterReference);
+	appendValidCharacters(buf, input, appendCharacterReferenceHandler);
+}
+
+void Transform::appendEscapingAttribute(LogString& buf, const LogString& input)
+{
+	appendValidCharacters(buf, input, appendAttributeCharacterReference, true);
 }
 
 void Transform::appendLegalCharacters(LogString& buf, const LogString& input)
diff --git a/src/main/include/log4cxx/helpers/transform.h b/src/main/include/log4cxx/helpers/transform.h
index 301ea63c..537aeff9 100644
--- a/src/main/include/log4cxx/helpers/transform.h
+++ b/src/main/include/log4cxx/helpers/transform.h
@@ -45,6 +45,19 @@ class LOG4CXX_EXPORT Transform
 		static void appendEscapingTags(
 			LogString& buf, const LogString& input);
 
+		/**
+		* Add \c input to an HTML attribute value while replacing characters
+		* that can break out of quoted attributes with entity references.
+		* Any NUL character in \c input is not copied to \c buf.
+		* A character reference is used in place of a character
+		* whose value is not permitted by the XML 1.0 specification.
+		*
+		* @param buf output stream where to write the modified string.
+		* @param input The text to be converted.
+		* */
+		static void appendEscapingAttribute(
+			LogString& buf, const LogString& input);
+
 		/**
 		* Add \c input to \c buf while ensuring embedded CDEnd strings (]]&gt;)
 		* are handled properly within the message.
diff --git a/src/test/cpp/xml/xmllayouttest.cpp b/src/test/cpp/xml/xmllayouttest.cpp
index 7869ea81..2ffbb2f0 100644
--- a/src/test/cpp/xml/xmllayouttest.cpp
+++ b/src/test/cpp/xml/xmllayouttest.cpp
@@ -473,7 +473,7 @@ public:
 	 */
 	void testHTMLLayout()
 	{
-		LogString problemName = LOG4CXX_STR("com.example.bar<>&\"'");
+		LogString problemName = LOG4CXX_STR("com.example.bar<>&\"'\n\t");
 		auto level = std::make_shared<XLevel>(6000, problemName, 7);
 		NDC context(problemName);
 		auto event = std::make_shared<LoggingEvent>(problemName, level, problemName, LOG4CXX_LOCATION);
@@ -491,6 +491,10 @@ public:
 		encoder->encode(html, iter, buf);
 		LOGUNIT_ASSERT(iter == html.end());
 		buf.flip();
+
+		LOGUNIT_ASSERT(html.find(LOG4CXX_STR(
+			"title=\"com.example.bar&lt;&gt;&amp;&quot;&#x27;&#xa;&#x9; logger\"")) != LogString::npos);
+
 		Pool p;
 		auto parser = apr_xml_parser_create(p.getAPRPool());
 		LOGUNIT_ASSERT(parser != 0);