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 <[email protected]>
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);

Reply via email to