Author: markt Date: Wed Oct 18 10:39:54 2017 New Revision: 1812489 URL: http://svn.apache.org/viewvc?rev=1812489&view=rev Log: Refactor XML and HTML escaping to a single location
Added: tomcat/trunk/java/org/apache/tomcat/util/security/Escape.java (with props) Modified: tomcat/trunk/java/org/apache/catalina/connector/Response.java tomcat/trunk/java/org/apache/catalina/manager/HTMLManagerServlet.java tomcat/trunk/java/org/apache/catalina/manager/ManagerServlet.java tomcat/trunk/java/org/apache/catalina/manager/StatusTransformer.java tomcat/trunk/java/org/apache/catalina/manager/host/HTMLHostManagerServlet.java tomcat/trunk/java/org/apache/catalina/servlets/DefaultServlet.java tomcat/trunk/java/org/apache/catalina/servlets/WebdavServlet.java tomcat/trunk/java/org/apache/catalina/ssi/SSIMediator.java tomcat/trunk/java/org/apache/catalina/storeconfig/StoreAppender.java tomcat/trunk/java/org/apache/catalina/users/MemoryUser.java tomcat/trunk/java/org/apache/catalina/util/DOMWriter.java tomcat/trunk/java/org/apache/catalina/util/RequestUtil.java tomcat/trunk/java/org/apache/catalina/valves/ErrorReportValve.java tomcat/trunk/java/org/apache/jasper/compiler/JspUtil.java tomcat/trunk/java/org/apache/jasper/compiler/PageDataImpl.java tomcat/trunk/java/org/apache/jasper/compiler/Validator.java tomcat/trunk/java/org/apache/jasper/security/SecurityUtil.java tomcat/trunk/java/org/apache/jasper/servlet/JspServlet.java tomcat/trunk/java/org/apache/tomcat/util/descriptor/web/WebXml.java tomcat/trunk/test/org/apache/jasper/compiler/TesterValidator.java Modified: tomcat/trunk/java/org/apache/catalina/connector/Response.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/connector/Response.java?rev=1812489&r1=1812488&r2=1812489&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/connector/Response.java (original) +++ tomcat/trunk/java/org/apache/catalina/connector/Response.java Wed Oct 18 10:39:54 2017 @@ -51,7 +51,6 @@ import org.apache.catalina.Globals; import org.apache.catalina.Session; import org.apache.catalina.Wrapper; import org.apache.catalina.security.SecurityUtil; -import org.apache.catalina.util.RequestUtil; import org.apache.catalina.util.SessionConfig; import org.apache.coyote.ActionCode; import org.apache.juli.logging.Log; @@ -64,6 +63,7 @@ import org.apache.tomcat.util.http.FastH import org.apache.tomcat.util.http.MimeHeaders; import org.apache.tomcat.util.http.parser.MediaTypeCache; import org.apache.tomcat.util.res.StringManager; +import org.apache.tomcat.util.security.Escape; /** * Wrapper object for the Coyote response. @@ -1374,7 +1374,7 @@ public class Response implements HttpSer if (getContext().getSendRedirectBody()) { PrintWriter writer = getWriter(); writer.print(sm.getString("coyoteResponse.sendRedirect.note", - RequestUtil.filter(locationUri))); + Escape.htmlElementContent(locationUri))); flushBuffer(); } } catch (IllegalArgumentException e) { Modified: tomcat/trunk/java/org/apache/catalina/manager/HTMLManagerServlet.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/manager/HTMLManagerServlet.java?rev=1812489&r1=1812488&r2=1812489&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/manager/HTMLManagerServlet.java (original) +++ tomcat/trunk/java/org/apache/catalina/manager/HTMLManagerServlet.java Wed Oct 18 10:39:54 2017 @@ -49,10 +49,10 @@ import org.apache.catalina.Session; import org.apache.catalina.manager.util.BaseSessionComparator; import org.apache.catalina.manager.util.SessionUtils; import org.apache.catalina.util.ContextName; -import org.apache.catalina.util.RequestUtil; import org.apache.catalina.util.ServerInfo; import org.apache.catalina.util.URLEncoder; import org.apache.tomcat.util.res.StringManager; +import org.apache.tomcat.util.security.Escape; /** * Servlet that enables remote management of the web applications deployed @@ -349,7 +349,7 @@ public final class HTMLManagerServlet ex if (message == null || message.length() == 0) { args[1] = "OK"; } else { - args[1] = RequestUtil.filter(message); + args[1] = Escape.htmlElementContent(message); } writer.print(MessageFormat.format(Constants.MESSAGE_SECTION, args)); @@ -442,19 +442,19 @@ public final class HTMLManagerServlet ex args = new Object[7]; args[0] = "<a href=\"" + URLEncoder.DEFAULT.encode(contextPath + "/", StandardCharsets.UTF_8) + - "\">" + RequestUtil.filter(displayPath) + "</a>"; + "\">" + Escape.htmlElementContent(displayPath) + "</a>"; if ("".equals(ctxt.getWebappVersion())) { args[1] = noVersion; } else { - args[1] = RequestUtil.filter(ctxt.getWebappVersion()); + args[1] = Escape.htmlElementContent(ctxt.getWebappVersion()); } if (ctxt.getDisplayName() == null) { args[2] = " "; } else { - args[2] = RequestUtil.filter(ctxt.getDisplayName()); + args[2] = Escape.htmlElementContent(ctxt.getDisplayName()); } args[3] = Boolean.valueOf(ctxt.getState().isAvailable()); - args[4] = RequestUtil.filter(response.encodeURL(request.getContextPath() + + args[4] = Escape.htmlElementContent(response.encodeURL(request.getContextPath() + "/html/sessions?" + pathVersion)); Manager manager = ctxt.getManager(); if (manager instanceof DistributedManager && showProxySessions) { @@ -472,19 +472,19 @@ public final class HTMLManagerServlet ex (MessageFormat.format(APPS_ROW_DETAILS_SECTION, args)); args = new Object[14]; - args[0] = RequestUtil.filter(response.encodeURL(request + args[0] = Escape.htmlElementContent(response.encodeURL(request .getContextPath() + "/html/start?" + pathVersion)); args[1] = appsStart; - args[2] = RequestUtil.filter(response.encodeURL(request + args[2] = Escape.htmlElementContent(response.encodeURL(request .getContextPath() + "/html/stop?" + pathVersion)); args[3] = appsStop; - args[4] = RequestUtil.filter(response.encodeURL(request + args[4] = Escape.htmlElementContent(response.encodeURL(request .getContextPath() + "/html/reload?" + pathVersion)); args[5] = appsReload; - args[6] = RequestUtil.filter(response.encodeURL(request + args[6] = Escape.htmlElementContent(response.encodeURL(request .getContextPath() + "/html/undeploy?" + pathVersion)); args[7] = appsUndeploy; - args[8] = RequestUtil.filter(response.encodeURL(request + args[8] = Escape.htmlElementContent(response.encodeURL(request .getContextPath() + "/html/expire?" + pathVersion)); args[9] = appsExpire; args[10] = smClient.getString("htmlManagerServlet.expire.explain"); @@ -824,14 +824,14 @@ public final class HTMLManagerServlet ex } throw new IllegalArgumentException(smClient.getString( "managerServlet.invalidPath", - RequestUtil.filter(path))); + Escape.htmlElementContent(path))); } Context ctxt = (Context) host.findChild(cn.getName()); if (null == ctxt) { throw new IllegalArgumentException(smClient.getString( "managerServlet.noContext", - RequestUtil.filter(cn.getDisplayName()))); + Escape.htmlElementContent(cn.getDisplayName()))); } Manager manager = ctxt.getManager(); List<Session> sessions = new ArrayList<>(); Modified: tomcat/trunk/java/org/apache/catalina/manager/ManagerServlet.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/manager/ManagerServlet.java?rev=1812489&r1=1812488&r2=1812489&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/manager/ManagerServlet.java (original) +++ tomcat/trunk/java/org/apache/catalina/manager/ManagerServlet.java Wed Oct 18 10:39:54 2017 @@ -58,13 +58,13 @@ import org.apache.catalina.connector.Con import org.apache.catalina.core.StandardHost; import org.apache.catalina.startup.ExpandWar; import org.apache.catalina.util.ContextName; -import org.apache.catalina.util.RequestUtil; import org.apache.catalina.util.ServerInfo; import org.apache.tomcat.util.Diagnostics; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.modeler.Registry; import org.apache.tomcat.util.net.SSLHostConfig; import org.apache.tomcat.util.res.StringManager; +import org.apache.tomcat.util.security.Escape; /** @@ -993,7 +993,7 @@ public class ManagerServlet extends Http Context context = (Context) host.findChild(cn.getName()); if (context == null) { writer.println(smClient.getString("managerServlet.noContext", - RequestUtil.filter(cn.getDisplayName()))); + Escape.htmlElementContent(cn.getDisplayName()))); return; } // It isn't possible for the manager to reload itself @@ -1173,13 +1173,13 @@ public class ManagerServlet extends Http Context context = (Context) host.findChild(cn.getName()); if (context == null) { writer.println(smClient.getString("managerServlet.noContext", - RequestUtil.filter(displayPath))); + Escape.htmlElementContent(displayPath))); return; } Manager manager = context.getManager() ; if(manager == null) { writer.println(smClient.getString("managerServlet.noManager", - RequestUtil.filter(displayPath))); + Escape.htmlElementContent(displayPath))); return; } int maxCount = 60; @@ -1299,7 +1299,7 @@ public class ManagerServlet extends Http Context context = (Context) host.findChild(cn.getName()); if (context == null) { writer.println(smClient.getString("managerServlet.noContext", - RequestUtil.filter(displayPath))); + Escape.htmlElementContent(displayPath))); return; } context.start(); @@ -1345,7 +1345,7 @@ public class ManagerServlet extends Http Context context = (Context) host.findChild(cn.getName()); if (context == null) { writer.println(smClient.getString("managerServlet.noContext", - RequestUtil.filter(displayPath))); + Escape.htmlElementContent(displayPath))); return; } // It isn't possible for the manager to stop itself @@ -1393,13 +1393,13 @@ public class ManagerServlet extends Http Context context = (Context) host.findChild(name); if (context == null) { writer.println(smClient.getString("managerServlet.noContext", - RequestUtil.filter(displayPath))); + Escape.htmlElementContent(displayPath))); return; } if (!isDeployed(name)) { writer.println(smClient.getString("managerServlet.notDeployed", - RequestUtil.filter(displayPath))); + Escape.htmlElementContent(displayPath))); return; } @@ -1610,7 +1610,7 @@ public class ManagerServlet extends Http String path = null; if (cn != null) { - path = RequestUtil.filter(cn.getPath()); + path = Escape.htmlElementContent(cn.getPath()); } writer.println(sm.getString("managerServlet.invalidPath", path)); return false; Modified: tomcat/trunk/java/org/apache/catalina/manager/StatusTransformer.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/manager/StatusTransformer.java?rev=1812489&r1=1812488&r2=1812489&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/manager/StatusTransformer.java (original) +++ tomcat/trunk/java/org/apache/catalina/manager/StatusTransformer.java Wed Oct 18 10:39:54 2017 @@ -37,8 +37,8 @@ import javax.management.ObjectInstance; import javax.management.ObjectName; import javax.servlet.http.HttpServletResponse; -import org.apache.catalina.util.RequestUtil; import org.apache.tomcat.util.ExceptionUtils; +import org.apache.tomcat.util.security.Escape; /** * This is a refactoring of the servlet to externalize @@ -260,7 +260,7 @@ public class StatusTransformer { for (MemoryPoolMXBean memoryPoolMBean : memoryPoolMBeans.values()) { MemoryUsage usage = memoryPoolMBean.getUsage(); writer.write("<memorypool"); - writer.write(" name='" + filterXml(memoryPoolMBean.getName()) + "'"); + writer.write(" name='" + Escape.xml("", memoryPoolMBean.getName()) + "'"); writer.write(" type='" + memoryPoolMBean.getType() + "'"); writer.write(" usageInit='" + usage.getInit() + "'"); writer.write(" usageCommitted='" + usage.getCommitted() + "'"); @@ -500,32 +500,32 @@ public class StatusTransformer { } writer.write("</td>"); writer.write("<td>"); - writer.print(filter(mBeanServer.getAttribute + writer.print(Escape.htmlElementContext(mBeanServer.getAttribute (pName, "remoteAddrForwarded"))); writer.write("</td>"); writer.write("<td>"); - writer.print(filter(mBeanServer.getAttribute + writer.print(Escape.htmlElementContext(mBeanServer.getAttribute (pName, "remoteAddr"))); writer.write("</td>"); writer.write("<td nowrap>"); - writer.write(filter(mBeanServer.getAttribute + writer.write(Escape.htmlElementContext(mBeanServer.getAttribute (pName, "virtualHost"))); writer.write("</td>"); writer.write("<td nowrap class=\"row-left\">"); if (showRequest) { - writer.write(filter(mBeanServer.getAttribute + writer.write(Escape.htmlElementContext(mBeanServer.getAttribute (pName, "method"))); writer.write(" "); - writer.write(filter(mBeanServer.getAttribute + writer.write(Escape.htmlElementContext(mBeanServer.getAttribute (pName, "currentUri"))); String queryString = (String) mBeanServer.getAttribute (pName, "currentQueryString"); if ((queryString != null) && (!queryString.equals(""))) { writer.write("?"); - writer.print(RequestUtil.filter(queryString)); + writer.print(Escape.htmlElementContent(queryString)); } writer.write(" "); - writer.write(filter(mBeanServer.getAttribute + writer.write(Escape.htmlElementContext(mBeanServer.getAttribute (pName, "protocol"))); } else { writer.write("?"); @@ -559,30 +559,30 @@ public class StatusTransformer { } writer.write("\""); writer.write(" remoteAddr=\"" - + filter(mBeanServer.getAttribute + + Escape.htmlElementContext(mBeanServer.getAttribute (pName, "remoteAddr")) + "\""); writer.write(" virtualHost=\"" - + filter(mBeanServer.getAttribute + + Escape.htmlElementContext(mBeanServer.getAttribute (pName, "virtualHost")) + "\""); if (showRequest) { writer.write(" method=\"" - + filter(mBeanServer.getAttribute + + Escape.htmlElementContext(mBeanServer.getAttribute (pName, "method")) + "\""); writer.write(" currentUri=\"" - + filter(mBeanServer.getAttribute + + Escape.htmlElementContext(mBeanServer.getAttribute (pName, "currentUri")) + "\""); String queryString = (String) mBeanServer.getAttribute (pName, "currentQueryString"); if ((queryString != null) && (!queryString.equals(""))) { writer.write(" currentQueryString=\"" - + RequestUtil.filter(queryString) + "\""); + + Escape.htmlElementContent(queryString) + "\""); } else { writer.write(" currentQueryString=\"?\""); } writer.write(" protocol=\"" - + filter(mBeanServer.getAttribute + + Escape.htmlElementContext(mBeanServer.getAttribute (pName, "protocol")) + "\""); } else { writer.write(" method=\"?\""); @@ -644,7 +644,7 @@ public class StatusTransformer { } writer.print("<a href=\"#" + (count++) + ".0\">"); - writer.print(filter(webModuleName)); + writer.print(Escape.htmlElementContext(webModuleName)); writer.print("</a>"); if (iterator.hasNext()) { writer.print("<br>"); @@ -726,7 +726,7 @@ public class StatusTransformer { } writer.print("<h1>"); - writer.print(filter(name)); + writer.print(Escape.htmlElementContext(name)); writer.print("</h1>"); writer.print("</a>"); @@ -869,11 +869,11 @@ public class StatusTransformer { mBeanServer.invoke(objectName, "findMappings", null, null); writer.print("<h2>"); - writer.print(filter(servletName)); + writer.print(Escape.htmlElementContext(servletName)); if ((mappings != null) && (mappings.length > 0)) { writer.print(" [ "); for (int i = 0; i < mappings.length; i++) { - writer.print(filter(mappings[i])); + writer.print(Escape.htmlElementContext(mappings[i])); if (i < mappings.length - 1) { writer.print(" , "); } @@ -914,7 +914,10 @@ public class StatusTransformer { * * @param obj The message string to be filtered * @return filtered HTML content + * + * @deprecated This method will be removed in Tomcat 9 */ + @Deprecated public static String filter(Object obj) { if (obj == null) @@ -951,7 +954,10 @@ public class StatusTransformer { * Escape the 5 entities defined by XML. * @param s The message string to be filtered * @return filtered XML content + * + * @deprecated This method will be removed in Tomcat 9 */ + @Deprecated public static String filterXml(String s) { if (s == null) return ""; Modified: tomcat/trunk/java/org/apache/catalina/manager/host/HTMLHostManagerServlet.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/manager/host/HTMLHostManagerServlet.java?rev=1812489&r1=1812488&r2=1812489&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/manager/host/HTMLHostManagerServlet.java (original) +++ tomcat/trunk/java/org/apache/catalina/manager/host/HTMLHostManagerServlet.java Wed Oct 18 10:39:54 2017 @@ -32,9 +32,9 @@ import javax.servlet.http.HttpServletRes import org.apache.catalina.Container; import org.apache.catalina.Host; -import org.apache.catalina.util.RequestUtil; import org.apache.catalina.util.ServerInfo; import org.apache.tomcat.util.res.StringManager; +import org.apache.tomcat.util.security.Escape; /** * Servlet that enables remote management of the virtual hosts deployed @@ -282,7 +282,7 @@ public final class HTMLHostManagerServle if (message == null || message.length() == 0) { args[1] = "OK"; } else { - args[1] = RequestUtil.filter(message); + args[1] = Escape.htmlElementContent(message); } writer.print(MessageFormat.format(Constants.MESSAGE_SECTION, args)); @@ -337,7 +337,7 @@ public final class HTMLHostManagerServle if (host != null ) { args = new Object[2]; - args[0] = RequestUtil.filter(hostName); + args[0] = Escape.htmlElementContent(hostName); String[] aliases = host.findAliases(); StringBuilder buf = new StringBuilder(); if (aliases.length > 0) { @@ -351,7 +351,7 @@ public final class HTMLHostManagerServle buf.append(" "); args[1] = buf.toString(); } else { - args[1] = RequestUtil.filter(buf.toString()); + args[1] = Escape.htmlElementContent(buf.toString()); } writer.print Modified: tomcat/trunk/java/org/apache/catalina/servlets/DefaultServlet.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/servlets/DefaultServlet.java?rev=1812489&r1=1812488&r2=1812489&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/servlets/DefaultServlet.java (original) +++ tomcat/trunk/java/org/apache/catalina/servlets/DefaultServlet.java Wed Oct 18 10:39:54 2017 @@ -72,11 +72,11 @@ import org.apache.catalina.WebResource; import org.apache.catalina.WebResourceRoot; import org.apache.catalina.connector.RequestFacade; import org.apache.catalina.connector.ResponseFacade; -import org.apache.catalina.util.RequestUtil; import org.apache.catalina.util.ServerInfo; import org.apache.catalina.util.URLEncoder; import org.apache.tomcat.util.buf.B2CConverter; import org.apache.tomcat.util.res.StringManager; +import org.apache.tomcat.util.security.Escape; import org.apache.tomcat.util.security.PrivilegedGetTccl; import org.apache.tomcat.util.security.PrivilegedSetTccl; import org.w3c.dom.Document; @@ -1616,7 +1616,7 @@ public class DefaultServlet extends Http .append("'"); sb.append(">"); - sb.append(RequestUtil.filter(entry)); + sb.append(Escape.htmlElementContent(entry)); if (childResource.isDirectory()) sb.append("/"); sb.append("</entry>"); @@ -1783,7 +1783,7 @@ public class DefaultServlet extends Http if (childResource.isDirectory()) sb.append("/"); sb.append("\"><tt>"); - sb.append(RequestUtil.filter(entry)); + sb.append(Escape.htmlElementContent(entry)); if (childResource.isDirectory()) sb.append("/"); sb.append("</tt></a></td>\r\n"); Modified: tomcat/trunk/java/org/apache/catalina/servlets/WebdavServlet.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/servlets/WebdavServlet.java?rev=1812489&r1=1812488&r2=1812489&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/servlets/WebdavServlet.java (original) +++ tomcat/trunk/java/org/apache/catalina/servlets/WebdavServlet.java Wed Oct 18 10:39:54 2017 @@ -1090,7 +1090,7 @@ public class WebdavServlet extends Defau break; case Node.ELEMENT_NODE: strWriter = new StringWriter(); - domWriter = new DOMWriter(strWriter, true); + domWriter = new DOMWriter(strWriter); domWriter.print(currentNode); lock.owner += strWriter.toString(); break; Modified: tomcat/trunk/java/org/apache/catalina/ssi/SSIMediator.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/ssi/SSIMediator.java?rev=1812489&r1=1812488&r2=1812489&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/ssi/SSIMediator.java (original) +++ tomcat/trunk/java/org/apache/catalina/ssi/SSIMediator.java Wed Oct 18 10:39:54 2017 @@ -26,9 +26,9 @@ import java.util.Locale; import java.util.Set; import java.util.TimeZone; -import org.apache.catalina.util.RequestUtil; import org.apache.catalina.util.Strftime; import org.apache.catalina.util.URLEncoder; +import org.apache.tomcat.util.security.Escape; /** * Allows the different SSICommand implementations to share data/talk to each @@ -284,7 +284,7 @@ public class SSIMediator { } else if (encoding.equalsIgnoreCase("none")) { retVal = value; } else if (encoding.equalsIgnoreCase("entity")) { - retVal = RequestUtil.filter(value); + retVal = Escape.htmlElementContent(value); } else { //This shouldn't be possible throw new IllegalArgumentException("Unknown encoding: " + encoding); Modified: tomcat/trunk/java/org/apache/catalina/storeconfig/StoreAppender.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/storeconfig/StoreAppender.java?rev=1812489&r1=1812488&r2=1812489&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/storeconfig/StoreAppender.java (original) +++ tomcat/trunk/java/org/apache/catalina/storeconfig/StoreAppender.java Wed Oct 18 10:39:54 2017 @@ -26,6 +26,7 @@ import java.util.Iterator; import org.apache.tomcat.util.IntrospectionUtils; import org.apache.tomcat.util.descriptor.web.ResourceBase; +import org.apache.tomcat.util.security.Escape; /** * StoreAppends generate really the xml tag elements @@ -106,7 +107,7 @@ public class StoreAppender { aWriter.print("<"); aWriter.print(tag); aWriter.print(">"); - aWriter.print(convertStr(content)); + aWriter.print(Escape.xml(content)); aWriter.print("</"); aWriter.print(tag); aWriter.println(">"); @@ -341,7 +342,7 @@ public class StoreAppender { if (!(value instanceof String)) { value = value.toString(); } - String strValue = convertStr((String) value); + String strValue = Escape.xml((String) value); pos = pos + name.length() + strValue.length(); if (pos > 60) { writer.println(); @@ -360,7 +361,9 @@ public class StoreAppender { * '&', and '"'. * @param input The string to escape * @return the escaped string + * @deprecated This method will be removed in Tomcat 9 */ + @Deprecated public String convertStr(String input) { StringBuffer filtered = new StringBuffer(input.length()); Modified: tomcat/trunk/java/org/apache/catalina/users/MemoryUser.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/users/MemoryUser.java?rev=1812489&r1=1812488&r2=1812489&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/users/MemoryUser.java (original) +++ tomcat/trunk/java/org/apache/catalina/users/MemoryUser.java Wed Oct 18 10:39:54 2017 @@ -25,8 +25,8 @@ import java.util.Iterator; import org.apache.catalina.Group; import org.apache.catalina.Role; import org.apache.catalina.UserDatabase; -import org.apache.catalina.util.RequestUtil; import org.apache.tomcat.util.buf.StringUtils; +import org.apache.tomcat.util.security.Escape; /** * <p>Concrete implementation of {@link org.apache.catalina.User} for the @@ -250,26 +250,26 @@ public class MemoryUser extends Abstract public String toXml() { StringBuilder sb = new StringBuilder("<user username=\""); - sb.append(RequestUtil.filter(username)); + sb.append(Escape.xml(username)); sb.append("\" password=\""); - sb.append(RequestUtil.filter(password)); + sb.append(Escape.xml(password)); sb.append("\""); if (fullName != null) { sb.append(" fullName=\""); - sb.append(RequestUtil.filter(fullName)); + sb.append(Escape.xml(fullName)); sb.append("\""); } synchronized (groups) { if (groups.size() > 0) { sb.append(" groups=\""); - StringUtils.join(groups, ',', (x) -> RequestUtil.filter(x.getGroupname()), sb); + StringUtils.join(groups, ',', (x) -> Escape.xml(x.getGroupname()), sb); sb.append("\""); } } synchronized (roles) { if (roles.size() > 0) { sb.append(" roles=\""); - StringUtils.join(roles, ',', (x) -> RequestUtil.filter(x.getRolename()), sb); + StringUtils.join(roles, ',', (x) -> Escape.xml(x.getRolename()), sb); sb.append("\""); } } @@ -285,24 +285,24 @@ public class MemoryUser extends Abstract public String toString() { StringBuilder sb = new StringBuilder("User username=\""); - sb.append(RequestUtil.filter(username)); + sb.append(Escape.xml(username)); sb.append("\""); if (fullName != null) { sb.append(", fullName=\""); - sb.append(RequestUtil.filter(fullName)); + sb.append(Escape.xml(fullName)); sb.append("\""); } synchronized (groups) { if (groups.size() > 0) { sb.append(", groups=\""); - StringUtils.join(groups, ',', (x) -> RequestUtil.filter(x.getGroupname()), sb); + StringUtils.join(groups, ',', (x) -> Escape.xml(x.getGroupname()), sb); sb.append("\""); } } synchronized (roles) { if (roles.size() > 0) { sb.append(", roles=\""); - StringUtils.join(roles, ',', (x) -> RequestUtil.filter(x.getRolename()), sb); + StringUtils.join(roles, ',', (x) -> Escape.xml(x.getRolename()), sb); sb.append("\""); } } Modified: tomcat/trunk/java/org/apache/catalina/util/DOMWriter.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/util/DOMWriter.java?rev=1812489&r1=1812488&r2=1812489&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/util/DOMWriter.java (original) +++ tomcat/trunk/java/org/apache/catalina/util/DOMWriter.java Wed Oct 18 10:39:54 2017 @@ -19,6 +19,7 @@ package org.apache.catalina.util; import java.io.PrintWriter; import java.io.Writer; +import org.apache.tomcat.util.security.Escape; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; @@ -35,6 +36,12 @@ public class DOMWriter { private final boolean canonical; + public DOMWriter(Writer writer) { + this (writer, true); + } + + + @Deprecated public DOMWriter(Writer writer, boolean canonical) { out = new PrintWriter(writer); this.canonical = canonical; @@ -74,7 +81,7 @@ public class DOMWriter { out.print(attr.getLocalName()); out.print("=\""); - out.print(escape(attr.getNodeValue())); + out.print(Escape.xml("", canonical, attr.getNodeValue())); out.print('"'); } out.print('>'); @@ -95,7 +102,7 @@ public class DOMWriter { // print cdata sections case Node.CDATA_SECTION_NODE: if (canonical) { - out.print(escape(node.getNodeValue())); + out.print(Escape.xml("", canonical, node.getNodeValue())); } else { out.print("<![CDATA["); out.print(node.getNodeValue()); @@ -105,7 +112,7 @@ public class DOMWriter { // print text case Node.TEXT_NODE: - out.print(escape(node.getNodeValue())); + out.print(Escape.xml("", canonical, node.getNodeValue())); break; // print processing instruction @@ -180,50 +187,4 @@ public class DOMWriter { return array; } - - /** - * Normalizes the given string. - * @param s The string to escape - * @return the escaped string - */ - private String escape(String s) { - if (s == null) { - return ""; - } - - StringBuilder str = new StringBuilder(); - - int len = s.length(); - for (int i = 0; i < len; i++) { - char ch = s.charAt(i); - switch (ch) { - case '<': - str.append("<"); - break; - case '>': - str.append(">"); - break; - case '&': - str.append("&"); - break; - case '"': - str.append("""); - break; - case '\r': - case '\n': - if (canonical) { - str.append("&#"); - str.append(Integer.toString(ch)); - str.append(';'); - break; - } - // else, default append char - //$FALL-THROUGH$ - default: - str.append(ch); - } - } - - return str.toString(); - } } Modified: tomcat/trunk/java/org/apache/catalina/util/RequestUtil.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/util/RequestUtil.java?rev=1812489&r1=1812488&r2=1812489&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/util/RequestUtil.java (original) +++ tomcat/trunk/java/org/apache/catalina/util/RequestUtil.java Wed Oct 18 10:39:54 2017 @@ -34,7 +34,10 @@ public final class RequestUtil { * @param message The message string to be filtered * * @return the filtered message + * + * @deprecated This method will be removed in Tomcat 9 */ + @Deprecated public static String filter(String message) { if (message == null) { Modified: tomcat/trunk/java/org/apache/catalina/valves/ErrorReportValve.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/valves/ErrorReportValve.java?rev=1812489&r1=1812488&r2=1812489&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/valves/ErrorReportValve.java (original) +++ tomcat/trunk/java/org/apache/catalina/valves/ErrorReportValve.java Wed Oct 18 10:39:54 2017 @@ -27,12 +27,12 @@ import javax.servlet.http.HttpServletRes import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; -import org.apache.catalina.util.RequestUtil; import org.apache.catalina.util.ServerInfo; import org.apache.catalina.util.TomcatCSS; import org.apache.coyote.ActionCode; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.res.StringManager; +import org.apache.tomcat.util.security.Escape; /** * <p>Implementation of a Valve that outputs HTML error pages.</p> @@ -159,12 +159,12 @@ public class ErrorReportValve extends Va return; } - String message = RequestUtil.filter(response.getMessage()); + String message = Escape.htmlElementContent(response.getMessage()); if (message == null) { if (throwable != null) { String exceptionMessage = throwable.getMessage(); if (exceptionMessage != null && exceptionMessage.length() > 0) { - message = RequestUtil.filter((new Scanner(exceptionMessage)).nextLine()); + message = Escape.htmlElementContent((new Scanner(exceptionMessage)).nextLine()); } } if (message == null) { @@ -237,7 +237,7 @@ public class ErrorReportValve extends Va sb.append("<p><b>"); sb.append(smClient.getString("errorReportValve.exception")); sb.append("</b></p><pre>"); - sb.append(RequestUtil.filter(stackTrace)); + sb.append(Escape.htmlElementContent(stackTrace)); sb.append("</pre>"); int loops = 0; @@ -247,7 +247,7 @@ public class ErrorReportValve extends Va sb.append("<p><b>"); sb.append(smClient.getString("errorReportValve.rootCause")); sb.append("</b></p><pre>"); - sb.append(RequestUtil.filter(stackTrace)); + sb.append(Escape.htmlElementContent(stackTrace)); sb.append("</pre>"); // In case root cause is somehow heavily nested rootCause = rootCause.getCause(); Modified: tomcat/trunk/java/org/apache/jasper/compiler/JspUtil.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/compiler/JspUtil.java?rev=1812489&r1=1812488&r2=1812489&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/jasper/compiler/JspUtil.java (original) +++ tomcat/trunk/java/org/apache/jasper/compiler/JspUtil.java Wed Oct 18 10:39:54 2017 @@ -28,6 +28,7 @@ import org.apache.jasper.Constants; import org.apache.jasper.JasperException; import org.apache.jasper.JspCompilationContext; import org.apache.tomcat.Jar; +import org.apache.tomcat.util.security.Escape; import org.xml.sax.Attributes; import org.xml.sax.InputSource; @@ -81,7 +82,7 @@ public class JspUtil { returnString = expression; } - return escapeXml(returnString); + return Escape.xml(returnString); } /** @@ -218,7 +219,9 @@ public class JspUtil { * Escape the 5 entities defined by XML. * @param s String to escape * @return XML escaped string + * @deprecated This method will be removed in Tomcat 9 */ + @Deprecated public static String escapeXml(String s) { if (s == null) { return null; Modified: tomcat/trunk/java/org/apache/jasper/compiler/PageDataImpl.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/compiler/PageDataImpl.java?rev=1812489&r1=1812488&r2=1812489&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/jasper/compiler/PageDataImpl.java (original) +++ tomcat/trunk/java/org/apache/jasper/compiler/PageDataImpl.java Wed Oct 18 10:39:54 2017 @@ -24,6 +24,7 @@ import java.nio.charset.StandardCharsets import javax.servlet.jsp.tagext.PageData; import org.apache.jasper.JasperException; +import org.apache.tomcat.util.security.Escape; import org.xml.sax.Attributes; import org.xml.sax.helpers.AttributesImpl; @@ -330,7 +331,7 @@ class PageDataImpl extends PageData impl buf.append(jspId++).append("\">"); } buf.append("${"); - buf.append(JspUtil.escapeXml(n.getText())); + buf.append(Escape.xml(n.getText())); buf.append("}"); if (!n.getRoot().isXmlSyntax()) { buf.append(JSP_TEXT_ACTION_END); Modified: tomcat/trunk/java/org/apache/jasper/compiler/Validator.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/compiler/Validator.java?rev=1812489&r1=1812488&r2=1812489&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/jasper/compiler/Validator.java (original) +++ tomcat/trunk/java/org/apache/jasper/compiler/Validator.java Wed Oct 18 10:39:54 2017 @@ -42,6 +42,7 @@ import javax.servlet.jsp.tagext.Validati import org.apache.jasper.JasperException; import org.apache.jasper.compiler.ELNode.Text; import org.apache.jasper.el.ELContextImpl; +import org.apache.tomcat.util.security.Escape; import org.xml.sax.Attributes; /** @@ -1405,7 +1406,7 @@ class Validator { el.visit(v); value = v.getText(); } else { - value = xmlEscape(value); + value = Escape.xml(value); } } @@ -1454,7 +1455,7 @@ class Validator { @Override public void visit(Text n) throws JasperException { output.append(ELParser.escapeLiteralExpression( - xmlEscape(n.getText()), + Escape.xml(n.getText()), isDeferredSyntaxAllowedAsLiteral)); } } @@ -1915,67 +1916,4 @@ class Validator { errDisp.jspError(errMsg.toString()); } } - - protected static String xmlEscape(String s) { - if (s == null) { - return null; - } - int len = s.length(); - - /* - * Look for any "bad" characters, Escape "bad" character was found - */ - // ASCII " 34 & 38 ' 39 < 60 > 62 - for (int i = 0; i < len; i++) { - char c = s.charAt(i); - if (c >= '\"' && c <= '>' && - (c == '<' || c == '>' || c == '\'' || c == '&' || c == '"')) { - // need to escape them and then quote the whole string - StringBuilder sb = new StringBuilder((int) (len * 1.2)); - sb.append(s, 0, i); - int pos = i + 1; - for (int j = i; j < len; j++) { - c = s.charAt(j); - if (c >= '\"' && c <= '>') { - if (c == '<') { - if (j > pos) { - sb.append(s, pos, j); - } - sb.append("<"); - pos = j + 1; - } else if (c == '>') { - if (j > pos) { - sb.append(s, pos, j); - } - sb.append(">"); - pos = j + 1; - } else if (c == '\'') { - if (j > pos) { - sb.append(s, pos, j); - } - sb.append("'"); // ' - pos = j + 1; - } else if (c == '&') { - if (j > pos) { - sb.append(s, pos, j); - } - sb.append("&"); - pos = j + 1; - } else if (c == '"') { - if (j > pos) { - sb.append(s, pos, j); - } - sb.append("""); // " - pos = j + 1; - } - } - } - if (pos < len) { - sb.append(s, pos, len); - } - return sb.toString(); - } - } - return s; - } } Modified: tomcat/trunk/java/org/apache/jasper/security/SecurityUtil.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/security/SecurityUtil.java?rev=1812489&r1=1812488&r2=1812489&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/jasper/security/SecurityUtil.java (original) +++ tomcat/trunk/java/org/apache/jasper/security/SecurityUtil.java Wed Oct 18 10:39:54 2017 @@ -47,7 +47,10 @@ public final class SecurityUtil{ * * @param message The message string to be filtered * @return the HTML filtered message + * + * @deprecated This method will be removed in Tomcat 9 */ + @Deprecated public static String filter(String message) { if (message == null) @@ -77,5 +80,4 @@ public final class SecurityUtil{ return result.toString(); } - } Modified: tomcat/trunk/java/org/apache/jasper/servlet/JspServlet.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/servlet/JspServlet.java?rev=1812489&r1=1812488&r2=1812489&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/jasper/servlet/JspServlet.java (original) +++ tomcat/trunk/java/org/apache/jasper/servlet/JspServlet.java Wed Oct 18 10:39:54 2017 @@ -43,6 +43,7 @@ import org.apache.jasper.security.Securi import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.PeriodicEventListener; +import org.apache.tomcat.util.security.Escape; /** * The JSP engine (a.k.a Jasper). @@ -404,7 +405,7 @@ public class JspServlet extends HttpServ Localizer.getMessage("jsp.error.file.not.found",jspUri); // Strictly, filtering this is an application // responsibility but just in case... - throw new ServletException(SecurityUtil.filter(msg)); + throw new ServletException(Escape.htmlElementContent(msg)); } else { try { response.sendError(HttpServletResponse.SC_NOT_FOUND, Modified: tomcat/trunk/java/org/apache/tomcat/util/descriptor/web/WebXml.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/descriptor/web/WebXml.java?rev=1812489&r1=1812488&r2=1812489&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/descriptor/web/WebXml.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/descriptor/web/WebXml.java Wed Oct 18 10:39:54 2017 @@ -46,6 +46,7 @@ import org.apache.tomcat.util.buf.UDecod import org.apache.tomcat.util.descriptor.XmlIdentifiers; import org.apache.tomcat.util.digester.DocumentProperties; import org.apache.tomcat.util.res.StringManager; +import org.apache.tomcat.util.security.Escape; /** * Representation of common elements of web.xml and web-fragment.xml. Provides @@ -1386,7 +1387,7 @@ public class WebXml extends XmlEncodingB sb.append('<'); sb.append(elementName); sb.append('>'); - sb.append(escapeXml(value)); + sb.append(Escape.xml(value)); sb.append("</"); sb.append(elementName); sb.append(">\n"); @@ -1400,33 +1401,6 @@ public class WebXml extends XmlEncodingB } - /** - * Escape the 5 entities defined by XML. - */ - private static String escapeXml(String s) { - if (s == null) - return null; - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < s.length(); i++) { - char c = s.charAt(i); - if (c == '<') { - sb.append("<"); - } else if (c == '>') { - sb.append(">"); - } else if (c == '\'') { - sb.append("'"); - } else if (c == '&') { - sb.append("&"); - } else if (c == '"') { - sb.append("""); - } else { - sb.append(c); - } - } - return sb.toString(); - } - - /** * Merge the supplied web fragments into this main web.xml. * Added: tomcat/trunk/java/org/apache/tomcat/util/security/Escape.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/security/Escape.java?rev=1812489&view=auto ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/security/Escape.java (added) +++ tomcat/trunk/java/org/apache/tomcat/util/security/Escape.java Wed Oct 18 10:39:54 2017 @@ -0,0 +1,160 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.util.security; + +/** + * Provides utility methods to escape content for different contexts. It is + * critical that the escaping used is correct for the context in which the data + * is to be used. + */ +public class Escape { + + /** + * Escape content for use in HTML. This escaping is suitable for the + * following uses: + * <ul> + * <li>Element content when the escaped data will be placed directly inside + * tags such as <p>, <td> etc.</li> + * <li>Attribute values when the attribute value is quoted with " or + * '.</li> + * </ul> + * + * @param content The content to escape + * + * @return The escaped content or {@code null} if the content was + * {@code null} + */ + public static String htmlElementContent(String content) { + if (content == null) { + return null; + } + + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < content.length(); i++) { + char c = content.charAt(i); + if (c == '<') { + sb.append("<"); + } else if (c == '>') { + sb.append(">"); + } else if (c == '\'') { + sb.append("'"); + } else if (c == '&') { + sb.append("&"); + } else if (c == '"') { + sb.append("""); + } else if (c == '/') { + sb.append("/"); + } else { + sb.append(c); + } + } + + return sb.toString(); + } + + + /** + * Convert the object to a string via {@link Object#toString()} and HTML + * escape the resulting string for use in HTMl content. + * + * @param obj The object to convert to String and then escape + * + * @return The escaped content or <code>"?"</code> if obj is + * {@code null} + */ + public static String htmlElementContext(Object obj) { + if (obj == null) { + return "?"; + } + + try { + return xml(obj.toString()); + } catch (Exception e) { + return null; + } + } + + + /** + * Escape content for use in XML. + * + * @param content The content to escape + * + * @return The escaped content or {@code null} if the content was + * {@code null} + */ + public static String xml(String content) { + return xml(null, content); + } + + + /** + * Escape content for use in XML. + * + * @param ifNull The value to return if content is {@code null} + * @param content The content to escape + * + * @return The escaped content or the value of ifNull if the content was + * {@code null} + */ + public static String xml(String ifNull, String content) { + return xml(ifNull, false, content); + } + + + /** + * Escape content for use in XML. + * + * @param ifNull The value to return if content is {@code null} + * @param escapeCRLF Should CR and LF also be escaped? + * @param content The content to escape + * + * @return The escaped content or the value of ifNull if the content was + * {@code null} + */ + public static String xml(String ifNull, boolean escapeCRLF, String content) { + if (content == null) { + return ifNull; + } + + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < content.length(); i++) { + char c = content.charAt(i); + if (c == '<') { + sb.append("<"); + } else if (c == '>') { + sb.append(">"); + } else if (c == '\'') { + sb.append("'"); + } else if (c == '&') { + sb.append("&"); + } else if (c == '"') { + sb.append("""); + } else if (escapeCRLF && c == '\r') { + sb.append(" "); + } else if (escapeCRLF && c == '\n') { + sb.append(" "); + } else { + sb.append(c); + } + } + + return sb.toString(); + } +} Propchange: tomcat/trunk/java/org/apache/tomcat/util/security/Escape.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: tomcat/trunk/test/org/apache/jasper/compiler/TesterValidator.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/jasper/compiler/TesterValidator.java?rev=1812489&r1=1812488&r2=1812489&view=diff ============================================================================== --- tomcat/trunk/test/org/apache/jasper/compiler/TesterValidator.java (original) +++ tomcat/trunk/test/org/apache/jasper/compiler/TesterValidator.java Wed Oct 18 10:39:54 2017 @@ -16,6 +16,7 @@ */ package org.apache.jasper.compiler; +import org.apache.tomcat.util.security.Escape; import org.junit.Assert; import org.junit.Test; @@ -42,7 +43,7 @@ public class TesterValidator { for (int j = 0; j < bug53867TestData.length; j++) { Assert.assertEquals(doTestBug53867OldVersion(bug53867TestData[j]), - Validator.xmlEscape(bug53867TestData[j])); + Escape.xml(bug53867TestData[j])); } for (int i = 0; i < 100; i++) { @@ -52,7 +53,7 @@ public class TesterValidator { } for (int i = 0; i < 100; i++) { for (int j = 0; j < bug53867TestData.length; j++) { - Validator.xmlEscape(bug53867TestData[j]); + Escape.xml(bug53867TestData[j]); } } @@ -68,7 +69,7 @@ public class TesterValidator { start = System.currentTimeMillis(); for (int i = 0; i < count; i++) { for (int j = 0; j < bug53867TestData.length; j++) { - Validator.xmlEscape(bug53867TestData[j]); + Escape.xml(bug53867TestData[j]); } } System.out.println( --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org