Skip to content

Commit 0fb84fa

Browse files
authored
Merge pull request #181 from sdutry/WW-4888
WW-4888 add escaping possibilities to text-tag
2 parents b886393 + a512f98 commit 0fb84fa

File tree

5 files changed

+150
-2
lines changed

5 files changed

+150
-2
lines changed

core/src/main/java/org/apache/struts2/components/Text.java

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
package org.apache.struts2.components;
2020

2121
import com.opensymphony.xwork2.util.ValueStack;
22+
import org.apache.commons.lang3.StringEscapeUtils;
2223
import org.apache.commons.lang3.StringUtils;
2324
import org.apache.logging.log4j.LogManager;
2425
import org.apache.logging.log4j.Logger;
@@ -58,6 +59,10 @@
5859
*
5960
* <ul>
6061
* <li>name* (String) - the i18n message key</li>
62+
* <li>escapeHtml (Boolean) - Escape HTML. Defaults to false</li>
63+
* <li>escapeJavaScript (Boolean) - Escape JavaScript. Defaults to false</li>
64+
* <li>escapeXml (Boolean) - Escape XML. Defaults to false</li>
65+
* <li>escapeCsv (Boolean) - Escape CSV. Defaults to false</li>
6166
* </ul>
6267
*
6368
* <!-- END SNIPPET: params -->
@@ -119,6 +124,10 @@ public class Text extends ContextBean implements Param.UnnamedParametric {
119124
protected String actualName;
120125
protected String name;
121126
protected String searchStack;
127+
private boolean escapeHtml = false;
128+
private boolean escapeJavaScript = false;
129+
private boolean escapeXml = false;
130+
private boolean escapeCsv = false;
122131

123132
public Text(ValueStack stack) {
124133
super(stack);
@@ -134,6 +143,26 @@ public void setSearchValueStack(String searchStack) {
134143
this.searchStack = searchStack;
135144
}
136145

146+
@StrutsTagAttribute(description="Whether to escape HTML", type="Boolean", defaultValue="false")
147+
public void setEscapeHtml(boolean escape) {
148+
this.escapeHtml = escape;
149+
}
150+
151+
@StrutsTagAttribute(description="Whether to escape Javascript", type="Boolean", defaultValue="false")
152+
public void setEscapeJavaScript(boolean escapeJavaScript) {
153+
this.escapeJavaScript = escapeJavaScript;
154+
}
155+
156+
@StrutsTagAttribute(description="Whether to escape XML", type="Boolean", defaultValue="false")
157+
public void setEscapeXml(boolean escapeXml) {
158+
this.escapeXml = escapeXml;
159+
}
160+
161+
@StrutsTagAttribute(description="Whether to escape CSV (useful to escape a value for a column)", type="Boolean", defaultValue="false")
162+
public void setEscapeCsv(boolean escapeCsv) {
163+
this.escapeCsv = escapeCsv;
164+
}
165+
137166
public boolean usesBody() {
138167
// overriding this to true such that EVAL_BODY_BUFFERED is return and
139168
// bodyContent will be valid hence, text between start & end tag will
@@ -161,7 +190,7 @@ public boolean end(Writer writer, String body) {
161190
if (msg != null) {
162191
try {
163192
if (getVar() == null) {
164-
writer.write(msg);
193+
writer.write(prepare(msg));
165194
} else {
166195
putInContext(msg);
167196
}
@@ -184,4 +213,22 @@ public void addParameter(Object value) {
184213

185214
values.add(value);
186215
}
216+
217+
private String prepare(String value) {
218+
String result = value;
219+
if (escapeHtml) {
220+
result = StringEscapeUtils.escapeHtml4(result);
221+
}
222+
if (escapeJavaScript) {
223+
result = StringEscapeUtils.escapeEcmaScript(result);
224+
}
225+
if (escapeXml) {
226+
result = StringEscapeUtils.escapeXml(result);
227+
}
228+
if (escapeCsv) {
229+
result = StringEscapeUtils.escapeCsv(result);
230+
}
231+
232+
return result;
233+
}
187234
}

core/src/main/java/org/apache/struts2/views/jsp/TextTag.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ public class TextTag extends ContextBeanTag {
3535

3636
protected String name;
3737
protected String searchValueStack;
38+
private boolean escapeHtml = false;
39+
private boolean escapeJavaScript = false;
40+
private boolean escapeXml = false;
41+
private boolean escapeCsv = false;
3842

3943
public Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res) {
4044
return new Text(stack);
@@ -46,6 +50,10 @@ protected void populateParams() {
4650
Text text = (Text) component;
4751
text.setName(name);
4852
text.setSearchValueStack(searchValueStack);
53+
text.setEscapeHtml(escapeHtml);
54+
text.setEscapeJavaScript(escapeJavaScript);
55+
text.setEscapeXml(escapeXml);
56+
text.setEscapeCsv(escapeCsv);
4957
}
5058

5159
public void setName(String name) {
@@ -55,4 +63,21 @@ public void setName(String name) {
5563
public void setSearchValueStack(String searchStack) {
5664
this.searchValueStack = searchStack;
5765
}
66+
67+
public void setEscapeHtml(boolean escapeHtml) {
68+
this.escapeHtml = escapeHtml;
69+
}
70+
71+
public void setEscapeJavaScript(boolean escapeJavaScript) {
72+
this.escapeJavaScript = escapeJavaScript;
73+
}
74+
75+
public void setEscapeXml(boolean escapeXml) {
76+
this.escapeXml = escapeXml;
77+
}
78+
79+
public void setEscapeCsv(boolean escapeCsv) {
80+
this.escapeCsv = escapeCsv;
81+
}
82+
5883
}

core/src/site/resources/tags/text.html

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,38 @@ <h2>Attributes</h2>
3333
<th align="left" valign="top"><h4>Type</h4></th>
3434
<th align="left" valign="top"><h4>Description</h4></th>
3535
</tr>
36+
<tr>
37+
<td align="left" valign="top">escapeCsv</td>
38+
<td align="left" valign="top">false</td>
39+
<td align="left" valign="top">false</td>
40+
<td align="left" valign="top">false</td>
41+
<td align="left" valign="top">Boolean</td>
42+
<td align="left" valign="top">Whether to escape CSV (useful to escape a value for a column)</td>
43+
</tr>
44+
<tr>
45+
<td align="left" valign="top">escapeHtml</td>
46+
<td align="left" valign="top">false</td>
47+
<td align="left" valign="top">false</td>
48+
<td align="left" valign="top">false</td>
49+
<td align="left" valign="top">Boolean</td>
50+
<td align="left" valign="top">Whether to escape HTML</td>
51+
</tr>
52+
<tr>
53+
<td align="left" valign="top">escapeJavaScript</td>
54+
<td align="left" valign="top">false</td>
55+
<td align="left" valign="top">false</td>
56+
<td align="left" valign="top">false</td>
57+
<td align="left" valign="top">Boolean</td>
58+
<td align="left" valign="top">Whether to escape Javascript</td>
59+
</tr>
60+
<tr>
61+
<td align="left" valign="top">escapeXml</td>
62+
<td align="left" valign="top">false</td>
63+
<td align="left" valign="top">false</td>
64+
<td align="left" valign="top">false</td>
65+
<td align="left" valign="top">Boolean</td>
66+
<td align="left" valign="top">Whether to escape XML</td>
67+
</tr>
3668
<tr>
3769
<td align="left" valign="top">name</td>
3870
<td align="left" valign="top"><strong>true</strong></td>

core/src/test/java/org/apache/struts2/views/jsp/TextTagTest.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,46 @@ public void testPutId() throws Exception {
305305
assertEquals("No foo here", stack.findString("myId")); // is in stack now
306306
}
307307

308+
public void testEscapeHtml() throws Exception {
309+
final String key = "foo.escape.html";
310+
final String value = "1 &lt; 2";
311+
tag.setName(key);
312+
tag.setEscapeHtml(true);
313+
tag.doStartTag();
314+
tag.doEndTag();
315+
assertEquals(value, writer.toString());
316+
}
317+
318+
public void testEscapeXml() throws Exception {
319+
final String key = "foo.escape.xml";
320+
final String value = "&lt;&gt;&apos;&quot;&amp;";
321+
tag.setName(key);
322+
tag.setEscapeXml(true);
323+
tag.doStartTag();
324+
tag.doEndTag();
325+
assertEquals(value, writer.toString());
326+
}
327+
328+
public void testEscapeJavaScript() throws Exception {
329+
final String key = "foo.escape.javascript";
330+
final String value = "\\t\\b\\n\\f\\r\\\"\\\'\\/\\\\";
331+
tag.setName(key);
332+
tag.setEscapeJavaScript(true);
333+
tag.doStartTag();
334+
tag.doEndTag();
335+
assertEquals(value, writer.toString());
336+
}
337+
338+
public void testEscapeCsv() throws Exception {
339+
final String key = "foo.escape.csv";
340+
final String value = "\"something,\"\",\"\"\"";
341+
tag.setName(key);
342+
tag.setEscapeCsv(true);
343+
tag.doStartTag();
344+
tag.doEndTag();
345+
assertEquals(value, writer.toString());
346+
}
347+
308348
/**
309349
* todo remove ActionContext set after LocalizedTextUtil is fixed to not use ThreadLocal
310350
*

core/src/test/resources/org/apache/struts2/TestAction.properties

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,8 @@ expressionKey=Foo is ${foo}
2121
messageFormatKey=Params are {0} {1} {2}
2222
foo.bar.baz=This should start with foo
2323
bar.baz=No foo here
24-
some.image.from.properties=some.gif
24+
some.image.from.properties=some.gif
25+
foo.escape.html=1 < 2
26+
foo.escape.xml=<>''\"&
27+
foo.escape.javascript=\u0009\u0008\n\u000C\u000D\"''/\u005C
28+
foo.escape.csv=something,","

0 commit comments

Comments
 (0)