Author: carnold
Date: Fri Aug 10 15:05:16 2007
New Revision: 564779
URL: http://svn.apache.org/viewvc?view=rev&rev=564779
Log:
Bug 34875: XML and HTMLLayout do not always escape special characters
Modified:
logging/log4j/branches/v1_2-branch/src/changes/changes.xml
logging/log4j/branches/v1_2-branch/src/main/java/org/apache/log4j/HTMLLayout.java
logging/log4j/branches/v1_2-branch/src/main/java/org/apache/log4j/helpers/Transform.java
logging/log4j/branches/v1_2-branch/src/main/java/org/apache/log4j/xml/XMLLayout.java
logging/log4j/branches/v1_2-branch/tests/src/java/org/apache/log4j/HTMLLayoutTest.java
logging/log4j/branches/v1_2-branch/tests/src/java/org/apache/log4j/xml/XMLLayoutTest.java
Modified: logging/log4j/branches/v1_2-branch/src/changes/changes.xml
URL:
http://svn.apache.org/viewvc/logging/log4j/branches/v1_2-branch/src/changes/changes.xml?view=diff&rev=564779&r1=564778&r2=564779
==============================================================================
--- logging/log4j/branches/v1_2-branch/src/changes/changes.xml (original)
+++ logging/log4j/branches/v1_2-branch/src/changes/changes.xml Fri Aug 10
15:05:16 2007
@@ -22,6 +22,7 @@
<body>
<release version="1.2.15" date="2007-06-27" description="SyslogAppender
enhancements, NTEventLogAppender and Maven build.">
+ <action action="fix" issue="34875">XML and HTMLLayout do not always
escape special characters.</action>
<action action="add" issue="43078">Optionally render MDC content in
XMLLayout</action>
<action action="fix" issue="42694">Typo in log4j.dtd concerning
threshold.</action>
<action action="fix" issue="42611">ERFATestCase fails on some
JDK's.</action>
Modified:
logging/log4j/branches/v1_2-branch/src/main/java/org/apache/log4j/HTMLLayout.java
URL:
http://svn.apache.org/viewvc/logging/log4j/branches/v1_2-branch/src/main/java/org/apache/log4j/HTMLLayout.java?view=diff&rev=564779&r1=564778&r2=564779
==============================================================================
---
logging/log4j/branches/v1_2-branch/src/main/java/org/apache/log4j/HTMLLayout.java
(original)
+++
logging/log4j/branches/v1_2-branch/src/main/java/org/apache/log4j/HTMLLayout.java
Fri Aug 10 15:05:16 2007
@@ -135,27 +135,29 @@
sbuf.append(event.timeStamp - LoggingEvent.getStartTime());
sbuf.append("</td>" + Layout.LINE_SEP);
- sbuf.append("<td title=\"" + event.getThreadName() + " thread\">");
- sbuf.append(Transform.escapeTags(event.getThreadName()));
+ String escapedThread = Transform.escapeTags(event.getThreadName());
+ sbuf.append("<td title=\"" + escapedThread + " thread\">");
+ sbuf.append(escapedThread);
sbuf.append("</td>" + Layout.LINE_SEP);
sbuf.append("<td title=\"Level\">");
if (event.getLevel().equals(Level.DEBUG)) {
sbuf.append("<font color=\"#339933\">");
- sbuf.append(event.getLevel());
+ sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));
sbuf.append("</font>");
}
else if(event.getLevel().isGreaterOrEqual(Level.WARN)) {
sbuf.append("<font color=\"#993300\"><strong>");
- sbuf.append(event.getLevel());
+ sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));
sbuf.append("</strong></font>");
} else {
- sbuf.append(event.getLevel());
+ sbuf.append(Transform.escapeTags(String.valueOf(event.getLevel())));
}
sbuf.append("</td>" + Layout.LINE_SEP);
- sbuf.append("<td title=\"" + event.getLoggerName() + " category\">");
- sbuf.append(Transform.escapeTags(event.getLoggerName()));
+ String escapedLogger = Transform.escapeTags(event.getLoggerName());
+ sbuf.append("<td title=\"" + escapedLogger + " category\">");
+ sbuf.append(escapedLogger);
sbuf.append("</td>" + Layout.LINE_SEP);
if(locationInfo) {
Modified:
logging/log4j/branches/v1_2-branch/src/main/java/org/apache/log4j/helpers/Transform.java
URL:
http://svn.apache.org/viewvc/logging/log4j/branches/v1_2-branch/src/main/java/org/apache/log4j/helpers/Transform.java?view=diff&rev=564779&r1=564778&r2=564779
==============================================================================
---
logging/log4j/branches/v1_2-branch/src/main/java/org/apache/log4j/helpers/Transform.java
(original)
+++
logging/log4j/branches/v1_2-branch/src/main/java/org/apache/log4j/helpers/Transform.java
Fri Aug 10 15:05:16 2007
@@ -33,18 +33,23 @@
/**
* This method takes a string which may contain HTML tags (ie,
- * <b>, <table>, etc) and replaces any '<' and '>'
+ * <b>, <table>, etc) and replaces any
+ * '<', '>' , '&' or '"'
* characters with respective predefined entity references.
*
* @param input The text to be converted.
- * @return The input string with the characters '<' and '>' replaced with
- * &lt; and &gt; respectively.
+ * @return The input string with the special characters replaced.
* */
- static public String escapeTags(String input) {
- //Check if the string is null or zero length -- if so, return
- //what was sent in.
+ static public String escapeTags(final String input) {
+ //Check if the string is null, zero length or devoid of special characters
+ // if so, return what was sent in.
- if( input == null || input.length() == 0 ) {
+ if(input == null
+ || input.length() == 0
+ || (input.indexOf('"') == -1 &&
+ input.indexOf('&') == -1 &&
+ input.indexOf('<') == -1 &&
+ input.indexOf('>') == -1)) {
return input;
}
@@ -57,12 +62,18 @@
int len = input.length();
for(int i=0; i < len; i++) {
ch = input.charAt(i);
- if(ch == '<') {
- buf.append("<");
+ if (ch > '>') {
+ buf.append(ch);
+ } else if(ch == '<') {
+ buf.append("<");
} else if(ch == '>') {
- buf.append(">");
+ buf.append(">");
+ } else if(ch == '&') {
+ buf.append("&");
+ } else if(ch == '"') {
+ buf.append(""");
} else {
- buf.append(ch);
+ buf.append(ch);
}
}
return buf.toString();
@@ -77,30 +88,26 @@
* section are the responsibility of the calling method.
* @param str The String that is inserted into an existing CDATA Section
within buf.
* */
- static public void appendEscapingCDATA(StringBuffer buf, String str) {
- if(str == null) {
- buf.append("");
- return;
- }
-
- int end = str.indexOf(CDATA_END);
- if (end < 0) {
- buf.append(str);
- return;
- }
-
- int start = 0;
- while (end > -1) {
- buf.append(str.substring(start,end));
- buf.append(CDATA_EMBEDED_END);
- start = end + CDATA_END_LEN;
- if (start < str.length()) {
- end = str.indexOf(CDATA_END, start);
- } else {
- return;
+ static public void appendEscapingCDATA(final StringBuffer buf,
+ final String str) {
+ if (str != null) {
+ int end = str.indexOf(CDATA_END);
+ if (end < 0) {
+ buf.append(str);
+ } else {
+ int start = 0;
+ while (end > -1) {
+ buf.append(str.substring(start, end));
+ buf.append(CDATA_EMBEDED_END);
+ start = end + CDATA_END_LEN;
+ if (start < str.length()) {
+ end = str.indexOf(CDATA_END, start);
+ } else {
+ return;
+ }
+ }
+ buf.append(str.substring(start));
+ }
}
- }
-
- buf.append(str.substring(start));
}
}
Modified:
logging/log4j/branches/v1_2-branch/src/main/java/org/apache/log4j/xml/XMLLayout.java
URL:
http://svn.apache.org/viewvc/logging/log4j/branches/v1_2-branch/src/main/java/org/apache/log4j/xml/XMLLayout.java?view=diff&rev=564779&r1=564778&r2=564779
==============================================================================
---
logging/log4j/branches/v1_2-branch/src/main/java/org/apache/log4j/xml/XMLLayout.java
(original)
+++
logging/log4j/branches/v1_2-branch/src/main/java/org/apache/log4j/xml/XMLLayout.java
Fri Aug 10 15:05:16 2007
@@ -115,7 +115,7 @@
/**
* Formats a [EMAIL PROTECTED] org.apache.log4j.spi.LoggingEvent} in
conformance with the log4j.dtd.
* */
- public String format(LoggingEvent event) {
+ public String format(final LoggingEvent event) {
// Reset working buffer. If the buffer is too large, then we need a new
// one in order to avoid the penalty of creating a large array.
@@ -128,13 +128,13 @@
// We yield to the \r\n heresy.
buf.append("<log4j:event logger=\"");
- buf.append(event.getLoggerName());
+ buf.append(Transform.escapeTags(event.getLoggerName()));
buf.append("\" timestamp=\"");
buf.append(event.timeStamp);
buf.append("\" level=\"");
- buf.append(event.getLevel());
+ buf.append(Transform.escapeTags(String.valueOf(event.getLevel())));
buf.append("\" thread=\"");
- buf.append(event.getThreadName());
+ buf.append(Transform.escapeTags(event.getThreadName()));
buf.append("\">\r\n");
buf.append("<log4j:message><![CDATA[");
@@ -167,7 +167,7 @@
buf.append("\" method=\"");
buf.append(Transform.escapeTags(locationInfo.getMethodName()));
buf.append("\" file=\"");
- buf.append(locationInfo.getFileName());
+ buf.append(Transform.escapeTags(locationInfo.getFileName()));
buf.append("\" line=\"");
buf.append(locationInfo.getLineNumber());
buf.append("\"/>\r\n");
@@ -186,7 +186,7 @@
buf.append("<log4j:data name=\"");
buf.append(Transform.escapeTags(key));
buf.append("\" value=\"");
- buf.append(Transform.escapeTags(val.toString()));
+ buf.append(Transform.escapeTags(String.valueOf(val)));
buf.append("\"/>\r\n");
}
}
Modified:
logging/log4j/branches/v1_2-branch/tests/src/java/org/apache/log4j/HTMLLayoutTest.java
URL:
http://svn.apache.org/viewvc/logging/log4j/branches/v1_2-branch/tests/src/java/org/apache/log4j/HTMLLayoutTest.java?view=diff&rev=564779&r1=564778&r2=564779
==============================================================================
---
logging/log4j/branches/v1_2-branch/tests/src/java/org/apache/log4j/HTMLLayoutTest.java
(original)
+++
logging/log4j/branches/v1_2-branch/tests/src/java/org/apache/log4j/HTMLLayoutTest.java
Fri Aug 10 15:05:16 2007
@@ -18,16 +18,14 @@
package org.apache.log4j;
import org.apache.log4j.spi.LoggingEvent;
-
import org.w3c.dom.Document;
-
import org.xml.sax.InputSource;
-import java.io.Reader;
-import java.io.StringReader;
-
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.Hashtable;
/**
@@ -177,4 +175,66 @@
Layout.LINE_SEP + "<tr>",
result.substring(0, Layout.LINE_SEP.length() + 4));
}
+
+
+ /**
+ * Level with arbitrary toString value.
+ */
+ private static final class ProblemLevel extends Level {
+ /**
+ * Construct new instance.
+ * @param levelName level name, may not be null.
+ */
+ public ProblemLevel(final String levelName) {
+ super(6000, levelName, 6);
+ }
+ }
+
+ /**
+ * Tests problematic characters in multiple fields.
+ * @throws Exception if parser can not be constructed
+ * or source is not a valid XML document.
+ */
+ public void testProblemCharacters() throws Exception {
+ String problemName = "com.example.bar<>&\"'";
+ Logger logger = Logger.getLogger(problemName);
+ Level level = new ProblemLevel(problemName);
+ Exception ex = new IllegalArgumentException(problemName);
+ String threadName = Thread.currentThread().getName();
+ Thread.currentThread().setName(problemName);
+ NDC.push(problemName);
+ Hashtable mdcMap = MDC.getContext();
+ if (mdcMap != null) {
+ mdcMap.clear();
+ }
+ MDC.put(problemName, problemName);
+ LoggingEvent event =
+ new LoggingEvent(
+ problemName, logger, level, problemName, ex);
+ HTMLLayout layout = (HTMLLayout) createLayout();
+ String result = layout.format(event);
+ mdcMap = MDC.getContext();
+ if (mdcMap != null) {
+ mdcMap.clear();
+ }
+
+ Thread.currentThread().setName(threadName);
+
+ //
+ // do a little fixup to make output XHTML
+ //
+ StringBuffer buf = new StringBuffer(
+ "<!DOCTYPE table [<!ENTITY nbsp ' '>]><table>");
+ buf.append(result);
+ buf.append("</table>");
+ String doc = buf.toString();
+ for(int i = doc.lastIndexOf("<br>");
+ i != -1;
+ i = doc.lastIndexOf("<br>", i - 1)) {
+ buf.replace(i, i + 4, "<br/>");
+ }
+
+ parse(buf.toString());
+ }
+
}
Modified:
logging/log4j/branches/v1_2-branch/tests/src/java/org/apache/log4j/xml/XMLLayoutTest.java
URL:
http://svn.apache.org/viewvc/logging/log4j/branches/v1_2-branch/tests/src/java/org/apache/log4j/xml/XMLLayoutTest.java?view=diff&rev=564779&r1=564778&r2=564779
==============================================================================
---
logging/log4j/branches/v1_2-branch/tests/src/java/org/apache/log4j/xml/XMLLayoutTest.java
(original)
+++
logging/log4j/branches/v1_2-branch/tests/src/java/org/apache/log4j/xml/XMLLayoutTest.java
Fri Aug 10 15:05:16 2007
@@ -22,6 +22,7 @@
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.NDC;
+import org.apache.log4j.MDC;
import org.apache.log4j.spi.LoggingEvent;
import org.w3c.dom.Document;
@@ -32,6 +33,7 @@
import java.io.Reader;
import java.io.StringReader;
+import java.util.Hashtable;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
@@ -86,10 +88,10 @@
final Element element, final LoggingEvent event) {
assertEquals("log4j:event", element.getTagName());
assertEquals(
- "org.apache.log4j.xml.XMLLayoutTest", element.getAttribute("logger"));
+ event.getLoggerName(), element.getAttribute("logger"));
assertEquals(
Long.toString(event.timeStamp), element.getAttribute("timestamp"));
- assertEquals("INFO", element.getAttribute("level"));
+ assertEquals(event.getLevel().toString(), element.getAttribute("level"));
assertEquals(event.getThreadName(), element.getAttribute("thread"));
}
@@ -142,6 +144,31 @@
assertNull(messageNode.getNextSibling());
}
+ /**
+ * Checks a log4j:properties element against expectations.
+ * @param element element, may not be null.
+ * @param key key.
+ * @param value value.
+ */
+ private void checkPropertiesElement(
+ final Element element, final String key, final String value) {
+ assertEquals("log4j:properties", element.getTagName());
+
+ int childNodeCount = 0;
+ for(Node child = element.getFirstChild();
+ child != null;
+ child = child.getNextSibling()) {
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ assertEquals("log4j:data", child.getNodeName());
+ Element childElement = (Element) child;
+ assertEquals(key, childElement.getAttribute("name"));
+ assertEquals(value, childElement.getAttribute("value"));
+ childNodeCount++;
+ }
+ }
+ assertEquals(1, childNodeCount);
+ }
+
/**
* Tests formatted results.
* @throws Exception if parser can not be constructed or source is not a
valid XML document.
@@ -308,4 +335,98 @@
XMLLayout layout = new XMLLayout();
layout.activateOptions();
}
+
+ /**
+ * Level with arbitrary toString value.
+ */
+ private static final class ProblemLevel extends Level {
+ /**
+ * Construct new instance.
+ * @param levelName level name, may not be null.
+ */
+ public ProblemLevel(final String levelName) {
+ super(6000, levelName, 6);
+ }
+ }
+
+ /**
+ * Tests problematic characters in multiple fields.
+ * @throws Exception if parser can not be constructed or source is not a
valid XML document.
+ */
+ public void testProblemCharacters() throws Exception {
+ String problemName = "com.example.bar<>&\"'";
+ Logger logger = Logger.getLogger(problemName);
+ Level level = new ProblemLevel(problemName);
+ Exception ex = new IllegalArgumentException(problemName);
+ String threadName = Thread.currentThread().getName();
+ Thread.currentThread().setName(problemName);
+ NDC.push(problemName);
+ Hashtable mdcMap = MDC.getContext();
+ if (mdcMap != null) {
+ mdcMap.clear();
+ }
+ MDC.put(problemName, problemName);
+ LoggingEvent event =
+ new LoggingEvent(
+ problemName, logger, level, problemName, ex);
+ XMLLayout layout = (XMLLayout) createLayout();
+ layout.setProperties(true);
+ String result = layout.format(event);
+ mdcMap = MDC.getContext();
+ if (mdcMap != null) {
+ mdcMap.clear();
+ }
+ Thread.currentThread().setName(threadName);
+
+ Element parsedResult = parse(result);
+ checkEventElement(parsedResult, event);
+
+ int childElementCount = 0;
+
+ for (
+ Node node = parsedResult.getFirstChild(); node != null;
+ node = node.getNextSibling()) {
+ switch (node.getNodeType()) {
+ case Node.ELEMENT_NODE:
+ childElementCount++;
+ switch(childElementCount) {
+ case 1:
+ checkMessageElement((Element) node, problemName);
+ break;
+
+ case 2:
+ checkNDCElement((Element) node, problemName);
+ break;
+
+ case 3:
+ checkThrowableElement((Element) node, ex);
+ break;
+
+ case 4:
+ checkPropertiesElement((Element) node, problemName, problemName);
+ break;
+
+ default:
+ fail("Unexpected element");
+ break;
+ }
+
+ break;
+
+ case Node.COMMENT_NODE:
+ break;
+
+ case Node.TEXT_NODE:
+
+ // should only be whitespace
+ break;
+
+ default:
+ fail("Unexpected node type");
+
+ break;
+ }
+ }
+ }
+
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]