diff --git a/src/share/org/apache/struts/taglib/html/BaseHandlerTag.java b/src/share/org/apache/struts/taglib/html/BaseHandlerTag.java index 403ff97..386ccf3 100644 --- a/src/share/org/apache/struts/taglib/html/BaseHandlerTag.java +++ b/src/share/org/apache/struts/taglib/html/BaseHandlerTag.java @@ -35,6 +35,7 @@ import org.apache.struts.taglib.TagUtils; import org.apache.struts.taglib.logic.IterateTag; import org.apache.struts.util.MessageResources; import org.apache.struts.util.RequestUtils; +import org.apache.struts.util.ResponseUtils; /** * Base class for tags that render form elements capable of including JavaScript @@ -898,10 +899,12 @@ public abstract class BaseHandlerTag extends BodyTagSupport { */ protected void prepareAttribute(StringBuffer handlers, String name, Object value) { if (value != null) { + if (name.indexOf('"') >= 0) + throw new IllegalArgumentException("quote character in attribute name"); handlers.append(" "); handlers.append(name); handlers.append("=\""); - handlers.append(value); + handlers.append(ResponseUtils.filterIfQuote(value.toString())); handlers.append("\""); } } diff --git a/src/share/org/apache/struts/taglib/html/FormTag.java b/src/share/org/apache/struts/taglib/html/FormTag.java index e8eb9b4..ba2d782 100644 --- a/src/share/org/apache/struts/taglib/html/FormTag.java +++ b/src/share/org/apache/struts/taglib/html/FormTag.java @@ -37,6 +37,7 @@ import org.apache.struts.config.ModuleConfig; import org.apache.struts.taglib.TagUtils; import org.apache.struts.util.MessageResources; import org.apache.struts.util.RequestUtils; +import org.apache.struts.util.ResponseUtils; /** * Custom tag that represents an input form, associated with a bean whose @@ -547,10 +548,10 @@ public class FormTag extends TagSupport { results.append(" action=\""); results.append( - response.encodeURL( + ResponseUtils.filterIfQuote(response.encodeURL( TagUtils.getInstance().getActionMappingURL( this.action, - this.pageContext))); + this.pageContext)))); results.append("\""); } @@ -580,7 +581,7 @@ public class FormTag extends TagSupport { results.append("
"); } else { @@ -598,10 +599,12 @@ public class FormTag extends TagSupport { */ protected void renderAttribute(StringBuffer results, String attribute, String value) { if (value != null) { + if (attribute.indexOf('"') >= 0) + throw new IllegalArgumentException("quote character in attribute name"); results.append(" "); results.append(attribute); results.append("=\""); - results.append(value); + results.append(ResponseUtils.filterIfQuote(value)); results.append("\""); } } diff --git a/src/share/org/apache/struts/taglib/html/HtmlTag.java b/src/share/org/apache/struts/taglib/html/HtmlTag.java index fb64875..d4da38d 100644 --- a/src/share/org/apache/struts/taglib/html/HtmlTag.java +++ b/src/share/org/apache/struts/taglib/html/HtmlTag.java @@ -29,6 +29,7 @@ import javax.servlet.jsp.tagext.TagSupport; import org.apache.struts.Globals; import org.apache.struts.taglib.TagUtils; import org.apache.struts.util.MessageResources; +import org.apache.struts.util.ResponseUtils; /** * Renders an HTML element with appropriate language attributes if @@ -151,20 +152,20 @@ public class HtmlTag extends TagSupport { if ((this.lang || this.locale || this.xhtml) && validLanguage) { sb.append(" lang=\""); - sb.append(language); + sb.append(ResponseUtils.filterIfQuote(language)); if (validCountry) { sb.append("-"); - sb.append(country); + sb.append(ResponseUtils.filterIfQuote(country)); } sb.append("\""); } if (this.xhtml && validLanguage) { sb.append(" xml:lang=\""); - sb.append(language); + sb.append(ResponseUtils.filterIfQuote(language)); if (validCountry) { sb.append("-"); - sb.append(country); + sb.append(ResponseUtils.filterIfQuote(country)); } sb.append("\""); } diff --git a/src/share/org/apache/struts/taglib/html/JavascriptValidatorTag.java b/src/share/org/apache/struts/taglib/html/JavascriptValidatorTag.java index 77d7dba..5da8317 100644 --- a/src/share/org/apache/struts/taglib/html/JavascriptValidatorTag.java +++ b/src/share/org/apache/struts/taglib/html/JavascriptValidatorTag.java @@ -45,6 +45,7 @@ import org.apache.struts.Globals; import org.apache.struts.action.ActionMapping; import org.apache.struts.config.ModuleConfig; import org.apache.struts.taglib.TagUtils; +import org.apache.struts.util.ResponseUtils; import org.apache.struts.util.MessageResources; import org.apache.struts.validator.Resources; import org.apache.struts.validator.ValidatorPlugIn; @@ -850,7 +851,7 @@ public class JavascriptValidatorTag extends BodyTagSupport { } if (this.src != null) { - start.append(" src=\"" + src + "\""); + start.append(" src=\"" + ResponseUtils.filterIfQuote(src) + "\""); } start.append("> \n"); diff --git a/src/share/org/apache/struts/taglib/html/OptionTag.java b/src/share/org/apache/struts/taglib/html/OptionTag.java index 4df5c95..e9e4b2e 100644 --- a/src/share/org/apache/struts/taglib/html/OptionTag.java +++ b/src/share/org/apache/struts/taglib/html/OptionTag.java @@ -26,6 +26,7 @@ import javax.servlet.jsp.tagext.BodyTagSupport; import org.apache.struts.Globals; import org.apache.struts.taglib.TagUtils; import org.apache.struts.util.MessageResources; +import org.apache.struts.util.ResponseUtils; /** * Tag for select options. The body of this tag is presented to the user @@ -235,7 +236,7 @@ public class OptionTag extends BodyTagSupport { protected String renderOptionElement() throws JspException { StringBuffer results = new StringBuffer("\r\n"); diff --git a/src/share/org/apache/struts/taglib/html/OptionsTag.java b/src/share/org/apache/struts/taglib/html/OptionsTag.java index 90d716a..dbc14cf 100644 --- a/src/share/org/apache/struts/taglib/html/OptionsTag.java +++ b/src/share/org/apache/struts/taglib/html/OptionsTag.java @@ -32,6 +32,7 @@ import org.apache.commons.beanutils.PropertyUtils; import org.apache.struts.util.IteratorAdapter; import org.apache.struts.taglib.TagUtils; import org.apache.struts.util.MessageResources; +import org.apache.struts.util.ResponseUtils; /** * Tag for creating multiple <select> options from a collection. The @@ -313,7 +314,7 @@ public class OptionsTag extends TagSupport { if (filter) { sb.append(TagUtils.getInstance().filter(value)); } else { - sb.append(value); + sb.append(ResponseUtils.filterIfQuote(value)); } sb.append("\""); if (matched) { @@ -321,12 +322,12 @@ public class OptionsTag extends TagSupport { } if (style != null) { sb.append(" style=\""); - sb.append(style); + sb.append(ResponseUtils.filterIfQuote(style)); sb.append("\""); } if (styleClass != null) { sb.append(" class=\""); - sb.append(styleClass); + sb.append(ResponseUtils.filterIfQuote(styleClass)); sb.append("\""); } @@ -335,7 +336,7 @@ public class OptionsTag extends TagSupport { if (filter) { sb.append(TagUtils.getInstance().filter(label)); } else { - sb.append(label); + sb.append(ResponseUtils.filterIfQuote(label)); } sb.append("\r\n"); diff --git a/src/share/org/apache/struts/taglib/html/RewriteTag.java b/src/share/org/apache/struts/taglib/html/RewriteTag.java index 804e50c..63a2f03 100644 --- a/src/share/org/apache/struts/taglib/html/RewriteTag.java +++ b/src/share/org/apache/struts/taglib/html/RewriteTag.java @@ -24,6 +24,7 @@ import java.util.Map; import javax.servlet.jsp.JspException; import org.apache.struts.taglib.TagUtils; +import org.apache.struts.util.ResponseUtils; /** * Generate a URL-encoded URI as a string. @@ -72,7 +73,8 @@ public class RewriteTag extends LinkTag { (messages.getMessage("rewrite.url", e.toString())); } - TagUtils.getInstance().write(pageContext, url); + TagUtils.getInstance().write(pageContext, + ResponseUtils.filterIfQuote(url)); return (SKIP_BODY); diff --git a/src/share/org/apache/struts/util/ResponseUtils.java b/src/share/org/apache/struts/util/ResponseUtils.java index 4588bb2..fe7e517 100644 --- a/src/share/org/apache/struts/util/ResponseUtils.java +++ b/src/share/org/apache/struts/util/ResponseUtils.java @@ -137,6 +137,37 @@ public class ResponseUtils { } + /** + * Replace double-quote characters in the input string with + * proper HTML encoding. + * + * No other HTML-encoding is performed. As a result, the return value + * can only be safely used in (X)HTML attributes surrounded by + * double-quote characters ("). + * + *

Note that you should not use this function in new code. + * It is only intended for old code which needs to be + * backwards-compatible with incompletely-quoted attributes. + * + * @return a fresh string object if quoting is needed, + * otherwise the input string + */ + public static String filterIfQuote(String value) { + if (value == null) + return null; + if (value.indexOf('"') >= 0) { + StringBuffer sb = new StringBuffer(value.length() + 2); + for (int i = 0; i < value.length(); ++i) { + final char ch = value.charAt(i); + if (ch == '"') + sb.append("""); + else + sb.append(ch); + } + return sb.toString(); + } + return value; + } /**