Skip to content

Commit 177bb01

Browse files
committed
HTML escape should align with character encoding
1 parent 4fac6a9 commit 177bb01

File tree

3 files changed

+60
-4
lines changed

3 files changed

+60
-4
lines changed

spring-webmvc/src/main/java/org/springframework/web/servlet/tags/form/AbstractFormTag.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ protected final int doStartTagInternal() throws Exception {
9292
* as required. This version is <strong>not</strong> {@link PropertyEditor}-aware.
9393
*/
9494
protected String getDisplayString(@Nullable Object value) {
95-
return ValueFormatter.getDisplayString(value, isHtmlEscape());
95+
return ValueFormatter.getDisplayString(value, this::htmlEscape);
9696
}
9797

9898
/**
@@ -102,7 +102,7 @@ protected String getDisplayString(@Nullable Object value) {
102102
* to obtain the display value.
103103
*/
104104
protected String getDisplayString(@Nullable Object value, @Nullable PropertyEditor propertyEditor) {
105-
return ValueFormatter.getDisplayString(value, propertyEditor, isHtmlEscape());
105+
return ValueFormatter.getDisplayString(value, propertyEditor, this::htmlEscape);
106106
}
107107

108108
/**

spring-webmvc/src/main/java/org/springframework/web/servlet/tags/form/ValueFormatter.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.springframework.web.servlet.tags.form;
1818

1919
import java.beans.PropertyEditor;
20+
import java.util.function.UnaryOperator;
2021

2122
import org.springframework.lang.Nullable;
2223
import org.springframework.util.ObjectUtils;
@@ -49,6 +50,16 @@ public static String getDisplayString(@Nullable Object value, boolean htmlEscape
4950
return (htmlEscape ? HtmlUtils.htmlEscape(displayValue) : displayValue);
5051
}
5152

53+
/**
54+
* Build the display value of the supplied {@code Object}, HTML escaped
55+
* as required. This version is <strong>not</strong> {@link PropertyEditor}-aware.
56+
* @see #getDisplayString(Object, java.beans.PropertyEditor, UnaryOperator)
57+
*/
58+
public static String getDisplayString(@Nullable Object value, UnaryOperator<String> htmlEscape) {
59+
String displayValue = ObjectUtils.getDisplayString(value);
60+
return htmlEscape.apply(displayValue);
61+
}
62+
5263
/**
5364
* Build the display value of the supplied {@code Object}, HTML escaped
5465
* as required. If the supplied value is not a {@link String} and the supplied
@@ -74,4 +85,29 @@ public static String getDisplayString(
7485
return getDisplayString(value, htmlEscape);
7586
}
7687

88+
/**
89+
* Build the display value of the supplied {@code Object}, HTML escaped
90+
* as required. If the supplied value is not a {@link String} and the supplied
91+
* {@link PropertyEditor} is not null then the {@link PropertyEditor} is used
92+
* to obtain the display value.
93+
* @see #getDisplayString(Object, UnaryOperator)
94+
*/
95+
public static String getDisplayString(
96+
@Nullable Object value, @Nullable PropertyEditor propertyEditor, UnaryOperator<String> htmlEscape) {
97+
98+
if (propertyEditor != null && !(value instanceof String)) {
99+
try {
100+
propertyEditor.setValue(value);
101+
String text = propertyEditor.getAsText();
102+
if (text != null) {
103+
return getDisplayString(text, htmlEscape);
104+
}
105+
}
106+
catch (Throwable ex) {
107+
// The PropertyEditor might not support this value... pass through.
108+
}
109+
}
110+
return getDisplayString(value, htmlEscape);
111+
}
112+
77113
}

spring-webmvc/src/test/java/org/springframework/web/servlet/tags/form/InputTagTests.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ void simpleBindTagWithinForm() throws Exception {
9696

9797
@Test
9898
void simpleBindWithHtmlEscaping() throws Exception {
99-
final String NAME = "Rob \"I Love Mangos\" Harrop";
100-
final String HTML_ESCAPED_NAME = "Rob &quot;I Love Mangos&quot; Harrop";
99+
final String NAME = "Rob \"I Love Café\" Harrop";
100+
final String HTML_ESCAPED_NAME = "Rob &quot;I Love Caf&eacute;&quot; Harrop";
101101

102102
this.tag.setPath("name");
103103
this.rob.setName(NAME);
@@ -112,6 +112,26 @@ void simpleBindWithHtmlEscaping() throws Exception {
112112
assertValueAttribute(output, HTML_ESCAPED_NAME);
113113
}
114114

115+
@Test
116+
void simpleBindWithHtmlEscapingAndCharacterEncoding() throws Exception {
117+
final String NAME = "Rob \"I Love Café\" Harrop";
118+
final String HTML_ESCAPED_NAME = "Rob &quot;I Love Café&quot; Harrop";
119+
120+
this.getPageContext().getResponse().setCharacterEncoding("UTF-8");
121+
this.tag.setPath("name");
122+
this.rob.setName(NAME);
123+
124+
assertThat(this.tag.doStartTag()).isEqualTo(Tag.SKIP_BODY);
125+
126+
String output = getOutput();
127+
assertTagOpened(output);
128+
assertTagClosed(output);
129+
130+
assertContainsAttribute(output, "type", getType());
131+
assertValueAttribute(output, HTML_ESCAPED_NAME);
132+
}
133+
134+
115135
protected void assertValueAttribute(String output, String expectedValue) {
116136
assertContainsAttribute(output, "value", expectedValue);
117137
}

0 commit comments

Comments
 (0)