Use response encoding when escaping HTML

With SPR-9293, it is now possible to HTML escape text while taking into
account the current response encoding. When using UTF-* encodings, only
XML markup significant characters are escaped, since UTF-* natively
support those characters.

This commit adds a new servlet context parameter to enable this fix by
default in a Spring MVC application:

    <context-param>
      <param-name>responseEncodedHtmlEscape</param-name>
      <param-value>true</param-value>
    </context-param>

Issue: SPR-12350, SPR-12132
This commit is contained in:
Brian Clozel
2014-10-24 11:46:09 +02:00
parent 73e398a165
commit a0c210457b
9 changed files with 124 additions and 17 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -115,6 +115,8 @@ public class RequestContext {
private Boolean defaultHtmlEscape;
private Boolean responseEncodedHtmlEscape;
private UrlPathHelper urlPathHelper;
private RequestDataValueProcessor requestDataValueProcessor;
@@ -263,6 +265,8 @@ public class RequestContext {
// context-param in web.xml, if any.
this.defaultHtmlEscape = WebUtils.getDefaultHtmlEscape(this.webApplicationContext.getServletContext());
this.responseEncodedHtmlEscape = WebUtils.getResponseEncodedHtmlEscape(this.webApplicationContext.getServletContext());
this.urlPathHelper = new UrlPathHelper();
if (this.webApplicationContext.containsBean(REQUEST_DATA_VALUE_PROCESSOR_BEAN_NAME)) {
@@ -484,6 +488,27 @@ public class RequestContext {
return this.defaultHtmlEscape;
}
/**
* Is HTML escaping using the response encoding by default?
* If enabled, only XML markup significant characters will be escaped with UTF-* encodings.
* <p>Falls back to {@code false} in case of no explicit default given.
* @since 4.1.2
*/
public boolean isResponseEncodedHtmlEscape() {
return (this.responseEncodedHtmlEscape != null && this.responseEncodedHtmlEscape.booleanValue());
}
/**
* Return the default setting about use of response encoding for HTML escape setting,
* differentiating between no default specified and an explicit value.
* @return whether default use of response encoding HTML escaping is enabled (null = no explicit default)
* @since 4.1.2
*/
public Boolean getResponseEncodedHtmlEscape() {
return this.responseEncodedHtmlEscape;
}
/**
* Set the UrlPathHelper to use for context path and request URI decoding.
* Can be used to pass a shared UrlPathHelper instance in.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,7 +21,6 @@ import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.BodyTag;
import org.springframework.web.util.HtmlUtils;
import org.springframework.web.util.JavaScriptUtils;
/**
@@ -79,7 +78,7 @@ public class EscapeBodyTag extends HtmlEscapingAwareTag implements BodyTag {
try {
String content = readBodyContent();
// HTML and/or JavaScript escape, if demanded
content = isHtmlEscape() ? HtmlUtils.htmlEscape(content) : content;
content = htmlEscape(content);
content = this.javaScriptEscape ? JavaScriptUtils.javaScriptEscape(content) : content;
writeBodyContent(content);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,7 +34,6 @@ import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.expression.spel.support.StandardTypeConverter;
import org.springframework.util.ObjectUtils;
import org.springframework.web.util.HtmlUtils;
import org.springframework.web.util.JavaScriptUtils;
import org.springframework.web.util.TagUtils;
@@ -121,7 +120,7 @@ public class EvalTag extends HtmlEscapingAwareTag {
try {
String result = this.expression.getValue(evaluationContext, String.class);
result = ObjectUtils.getDisplayString(result);
result = (isHtmlEscape() ? HtmlUtils.htmlEscape(result) : result);
result = htmlEscape(result);
result = (this.javaScriptEscape ? JavaScriptUtils.javaScriptEscape(result) : result);
this.pageContext.getOut().print(result);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,8 @@ package org.springframework.web.servlet.tags;
import javax.servlet.jsp.JspException;
import org.springframework.web.util.HtmlUtils;
/**
* Superclass for tags that output content that might get HTML-escaped.
*
@@ -31,7 +33,8 @@ import javax.servlet.jsp.JspException;
* @see #setHtmlEscape
* @see HtmlEscapeTag
* @see org.springframework.web.servlet.support.RequestContext#isDefaultHtmlEscape
* @see org.springframework.web.util.WebUtils#isDefaultHtmlEscape
* @see org.springframework.web.util.WebUtils#getDefaultHtmlEscape
* @see org.springframework.web.util.WebUtils#getResponseEncodedHtmlEscape
*/
@SuppressWarnings("serial")
public abstract class HtmlEscapingAwareTag extends RequestContextAwareTag {
@@ -72,4 +75,37 @@ public abstract class HtmlEscapingAwareTag extends RequestContextAwareTag {
return getRequestContext().isDefaultHtmlEscape();
}
/**
* Return the applicable default for the use of response encoding with HTML escape for this tag.
* <p>The default implementation checks the RequestContext's setting,
* falling back to {@code false} in case of no explicit default given.
* @see #getRequestContext()
* @since 4.1.2
*/
protected boolean isResponseEncodedHtmlEscape() {
return getRequestContext().isResponseEncodedHtmlEscape();
}
/**
* HTML encodes the given string, only if the htmlEscape setting is enabled.
* The response encoding will be taken into account if the responseEncodedHtmlEscape setting is enabled.
* @param content
* @return
* @see #isHtmlEscape()
* @see #isResponseEncodedHtmlEscape()
* @since 4.1.2
*/
protected String htmlEscape(String content) {
String out = content;
if(isHtmlEscape()) {
if(isResponseEncodedHtmlEscape()) {
out = HtmlUtils.htmlEscape(content, this.pageContext.getResponse().getCharacterEncoding());
}
else {
out = HtmlUtils.htmlEscape(content);
}
}
return out;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,7 +28,6 @@ import org.springframework.context.MessageSourceResolvable;
import org.springframework.context.NoSuchMessageException;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.util.HtmlUtils;
import org.springframework.web.util.JavaScriptUtils;
import org.springframework.web.util.TagUtils;
@@ -181,7 +180,7 @@ public class MessageTag extends HtmlEscapingAwareTag implements ArgumentAware {
String msg = resolveMessage();
// HTML and/or JavaScript escape, if demanded.
msg = isHtmlEscape() ? HtmlUtils.htmlEscape(msg) : msg;
msg = htmlEscape(msg);
msg = this.javaScriptEscape ? JavaScriptUtils.javaScriptEscape(msg) : msg;
// Expose as variable, if demanded, else write to the page.

View File

@@ -105,7 +105,7 @@ public class TransformTag extends HtmlEscapingAwareTag {
// Else, just do a toString.
result = this.value.toString();
}
result = isHtmlEscape() ? HtmlUtils.htmlEscape(result) : result;
result = htmlEscape(result);
if (this.var != null) {
pageContext.setAttribute(this.var, result, TagUtils.getScope(this.scope));
}

View File

@@ -226,7 +226,7 @@ public class UrlTag extends HtmlEscapingAwareTag implements ParamAware {
}
// HTML and/or JavaScript escape, if demanded.
urlStr = isHtmlEscape() ? HtmlUtils.htmlEscape(urlStr) : urlStr;
urlStr = htmlEscape(urlStr);
urlStr = this.javaScriptEscape ? JavaScriptUtils.javaScriptEscape(urlStr) : urlStr;
return urlStr;