Commit afb7e4ff authored by Woonsan Ko's avatar Woonsan Ko

HSTTWO-4310 Reintegrate bugfix/HSTTWO-4310

parents b40b9dbd eb8e2653
/*
* Copyright 2014-2016 Hippo B.V. (http://www.onehippo.com)
* Copyright 2014-2018 Hippo B.V. (http://www.onehippo.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -53,6 +53,7 @@ public class MessagesReplaceTag extends BodyTagSupport {
protected String variablePrefix;
protected String variableSuffix;
protected Character escapeChar;
protected boolean escapeMessageXml = true;
@Override
public int doStartTag() throws JspException{
......@@ -95,7 +96,7 @@ public class MessagesReplaceTag extends BodyTagSupport {
if (bundle != null) {
textContent = MessageUtils.replaceMessagesByBundle(bundle, textContent,
variablePrefix, variableSuffix,
escapeChar);
escapeChar, isEscapeMessageXml());
}
if (var == null) {
......@@ -124,6 +125,7 @@ public class MessagesReplaceTag extends BodyTagSupport {
basename = null;
locale = null;
localeString = null;
escapeMessageXml = true;
}
@Override
......@@ -195,6 +197,14 @@ public class MessagesReplaceTag extends BodyTagSupport {
this.escapeChar = escapeChar;
}
public boolean isEscapeMessageXml() {
return escapeMessageXml;
}
public void setEscapeMessageXml(boolean escapeMessageXml) {
this.escapeMessageXml = escapeMessageXml;
}
protected LocalizationContext getLocalizationContext() {
LocalizationContext locCtx = null;
......
/*
* Copyright 2014-2014 Hippo B.V. (http://www.onehippo.com)
* Copyright 2014-2018 Hippo B.V. (http://www.onehippo.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -22,6 +22,7 @@ import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.text.StrLookup;
import org.apache.commons.lang.text.StrSubstitutor;
import org.hippoecm.hst.resourcebundle.ResourceBundleUtils;
import org.hippoecm.hst.util.HstRequestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -55,7 +56,7 @@ public class MessageUtils {
* @return replaced string by the values found in the given resource bundle
*/
public static String replaceMessages(String basename, String text) {
return replaceMessages(basename, text, null, null, null);
return replaceMessages(basename, text, null, null, null, false);
}
/**
......@@ -68,7 +69,7 @@ public class MessageUtils {
*/
public static String replaceMessages(String basename, String text, String variablePrefix,
String variableSuffix) {
return replaceMessages(basename, text, variablePrefix, variableSuffix, null);
return replaceMessages(basename, text, variablePrefix, variableSuffix, null, false);
}
/**
......@@ -82,6 +83,21 @@ public class MessageUtils {
*/
public static String replaceMessages(String basename, String text, String variablePrefix,
String variableSuffix, Character escapeChar) {
return replaceMessages(basename, text, variablePrefix, variableSuffix, escapeChar, false);
}
/**
* Replaces the given text by looking up values from the resolved resource bundle by the <code>basename</code>.
* @param basename resource bundle base name
* @param text text to replace
* @param variablePrefix variable reference prefix. "${" by default.
* @param variableSuffix variable reference suffix. "}" by default.
* @param escapeChar escape character which can be put just before a variable reference to ignore the expression.
* @param escapeMessageXml whether or not to escape a message value having &amp;,&gt;,&lt;,", and '.
* @return replaced string by the values found in the given resource bundle
*/
public static String replaceMessages(String basename, String text, String variablePrefix,
String variableSuffix, Character escapeChar, boolean escapeMessageXml) {
ResourceBundle bundle = null;
try {
......@@ -94,7 +110,7 @@ public class MessageUtils {
return text;
}
return replaceMessagesByBundle(bundle, text, variablePrefix, variableSuffix, escapeChar);
return replaceMessagesByBundle(bundle, text, variablePrefix, variableSuffix, escapeChar, escapeMessageXml);
}
/**
......@@ -104,7 +120,7 @@ public class MessageUtils {
* @return replaced string by the values found in the given resource bundle
*/
public static String replaceMessagesByBundle(ResourceBundle bundle, String text) {
return replaceMessagesByBundle(bundle, text, null, null, null);
return replaceMessagesByBundle(bundle, text, null, null, null, false);
}
/**
......@@ -117,7 +133,7 @@ public class MessageUtils {
*/
public static String replaceMessagesByBundle(ResourceBundle bundle, String text, String variablePrefix,
String variableSuffix) {
return replaceMessagesByBundle(bundle, text, variablePrefix, variableSuffix, null);
return replaceMessagesByBundle(bundle, text, variablePrefix, variableSuffix, null, false);
}
/**
......@@ -131,11 +147,26 @@ public class MessageUtils {
*/
public static String replaceMessagesByBundle(ResourceBundle bundle, String text, String variablePrefix,
String variableSuffix, Character escapeChar) {
return replaceMessagesByBundle(bundle, text, variablePrefix, variableSuffix, escapeChar, false);
}
/**
* Replaces the given text by looking up values from the given resource bundle.
* @param bundle resource bundle
* @param text text to replace
* @param variablePrefix variable reference prefix. "${" by default.
* @param variableSuffix variable reference suffix. "}" by default.
* @param escapeChar escape character which can be put just before a variable reference to ignore the expression.
* @param escapeMessageXml whether or not to escape a message value having &amp;,&gt;,&lt;,", and '.
* @return replaced string by the values found in the given resource bundle
*/
public static String replaceMessagesByBundle(ResourceBundle bundle, String text, String variablePrefix,
String variableSuffix, Character escapeChar, boolean escapeMessageXml) {
if (bundle == null) {
throw new IllegalArgumentException("The bundle must not be null.");
}
StrSubstitutor subst = new StrSubstitutor(new ResourceBundleVariableResolver(bundle),
StrSubstitutor subst = new StrSubstitutor(new ResourceBundleVariableResolver(bundle, escapeMessageXml),
StrSubstitutor.DEFAULT_PREFIX,
StrSubstitutor.DEFAULT_SUFFIX,
DEFAULT_ESCAPE);
......@@ -161,16 +192,24 @@ public class MessageUtils {
*/
private static class ResourceBundleVariableResolver extends StrLookup {
private ResourceBundle bundle;
private final ResourceBundle bundle;
private final boolean escapeMessageXml;
ResourceBundleVariableResolver(ResourceBundle bundle) {
ResourceBundleVariableResolver(final ResourceBundle bundle, final boolean escapeMessageXml) {
this.bundle = bundle;
this.escapeMessageXml = escapeMessageXml;
}
@Override
public String lookup(String key) {
try {
return bundle.getString(key);
String value = bundle.getString(key);
if (escapeMessageXml) {
value = HstRequestUtils.escapeXml(value);
}
return value;
} catch (MissingResourceException e) {
return "???" + key + "???";
}
......
......@@ -1097,9 +1097,23 @@
<rtexprvalue>true</rtexprvalue>
<type>java.lang.Character</type>
</attribute>
<attribute>
<description>
Whether or not to escape a message value having &amp;,&gt;,&lt;,", and '. When escapeMessageXml = true, the
replaced message text can be safely used as a tag attribute (e.g, href, src, etc.) value.
By default escapeMessageXml is set to true.
</description>
<name>escapeMessageXml</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
<type>java.lang.Boolean</type>
</attribute>
<example><![CDATA[
<%-- Replaces all the variables (e.g, ${company.name}) in the html output --%>
<hst:messagesReplace>
${document.title}
</hst:messagesReplace>
<hst:messagesReplace escapeXml="false">
<hst:html hippohtml="${document.body}" />
</hst:messagesReplace>
]]></example>
......
/*
* Copyright 2014-2018 Hippo B.V. (http://www.onehippo.com)
*
* Licensed 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.hippoecm.hst.tag;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import org.apache.commons.lang.StringUtils;
import org.hippoecm.hst.resourcebundle.SimpleListResourceBundle;
import org.hippoecm.hst.util.HstRequestUtils;
import org.junit.Before;
import org.junit.Test;
import org.springframework.mock.web.MockBodyContent;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockPageContext;
import org.springframework.mock.web.MockServletContext;
import static org.junit.Assert.assertEquals;
/**
* MessagesReplaceTagTest.
*/
public class MessagesReplaceTagTest {
private MockServletContext servletContext;
private MockHttpServletRequest request;
private MockHttpServletResponse response;
private MockPageContext pageContext;
private ResourceBundle bundle;
private MessagesReplaceTag messagesReplaceTag;
@Before
public void before() throws Exception {
servletContext = new MockServletContext();
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
pageContext = new MockPageContext(servletContext, request, response);
final Map<String, String> bundleContent = new HashMap<>();
bundleContent.put("example.title", "<script>alert('hi there')</script>");
bundleContent.put("example.subtitle", "<b>howdy?</b>");
bundleContent.put("example.introduction", "This is an example introduction.");
bundleContent.put("example.body", "<h1>Hello, World!</h1><p>This is the body.</p>");
bundle = new SimpleListResourceBundle(bundleContent);
messagesReplaceTag = new MessagesReplaceTag();
messagesReplaceTag.setPageContext(pageContext);
messagesReplaceTag.setBundle(bundle);
}
@Test
public void testMessagesReplaceTagOutputWithoutEscaping() throws Exception {
messagesReplaceTag.setEscapeMessageXml(false);
messagesReplaceTag.doStartTag();
final MockBodyContent bodyContent =
new MockBodyContent(
"<h2>${example.subtitle}</h2>\n"
+ "<p>${example.introduction}</p>\n"
+ "<div>${example.body}</div>",
response);
messagesReplaceTag.setBodyContent(bodyContent);
messagesReplaceTag.doEndTag();
final String[] lines = StringUtils.split(response.getContentAsString(), "\n");
assertEquals("<h2><b>howdy?</b></h2>", lines[0]);
assertEquals("<p>This is an example introduction.</p>", lines[1]);
assertEquals("<div><h1>Hello, World!</h1><p>This is the body.</p></div>", lines[2]);
}
@Test
public void testMessagesReplaceTagOutputByDefault() throws Exception {
messagesReplaceTag.doStartTag();
final MockBodyContent bodyContent =
new MockBodyContent(
"<h1>${example.title}</h1>\n"
+ "<div>${example.introduction}</div>",
response);
messagesReplaceTag.setBodyContent(bodyContent);
messagesReplaceTag.doEndTag();
final String[] lines = StringUtils.split(response.getContentAsString(), "\n");
assertEquals("<h1>" + HstRequestUtils.escapeXml("<script>alert('hi there')</script>") + "</h1>", lines[0]);
assertEquals("<div>" + HstRequestUtils.escapeXml("This is an example introduction.") + "</div>", lines[1]);
}
}
/*
* Copyright 2014-2014 Hippo B.V. (http://www.onehippo.com)
* Copyright 2014-2018 Hippo B.V. (http://www.onehippo.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -15,14 +15,15 @@
*/
package org.hippoecm.hst.utils;
import static org.junit.Assert.assertEquals;
import java.util.ResourceBundle;
import org.hippoecm.hst.resourcebundle.ResourceBundleUtils;
import org.hippoecm.hst.util.HstRequestUtils;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
/**
* TestMessageUtils
*/
......@@ -54,6 +55,14 @@ public class TestMessageUtils {
private static final String DOLLAR_SIGN_TEST_EXPECTED_MESSAGE =
"The annual payment is $500.";
private static final String ESCAPABLE_GREETING_VALUE = "<script>alert('hi there!');</script>";
private static final String ESCAPABLE_TEST_MESSAGE_EXPR = "<h1>${escapable.greeting}</h1>";
private static final String EXPECTED_UNESCAPED_TEST_MESSAGE = "<h1>" + ESCAPABLE_GREETING_VALUE + "</h1>";
private static final String EXPECTED_ESCAPED_TEST_MESSAGE = "<h1>" + HstRequestUtils.escapeXml(ESCAPABLE_GREETING_VALUE) + "</h1>";
@Before
public void before() throws Exception {
bundle = ResourceBundleUtils.getBundle(BUNDLE_NAME, null);
......@@ -140,5 +149,16 @@ public class TestMessageUtils {
assertEquals(DOLLAR_SIGN_TEST_EXPECTED_MESSAGE, replacedMessage);
}
@Test
public void testEscaping() throws Exception {
String replacedMessage = MessageUtils.replaceMessages(BUNDLE_NAME, ESCAPABLE_TEST_MESSAGE_EXPR, "${", "}", '\\', true);
assertEquals(EXPECTED_ESCAPED_TEST_MESSAGE, replacedMessage);
replacedMessage = MessageUtils.replaceMessages(BUNDLE_NAME, ESCAPABLE_TEST_MESSAGE_EXPR, "${", "}", '\\', false);
assertEquals(EXPECTED_UNESCAPED_TEST_MESSAGE, replacedMessage);
replacedMessage = MessageUtils.replaceMessages(BUNDLE_NAME, ESCAPABLE_TEST_MESSAGE_EXPR, "${", "}", '\\');
assertEquals(EXPECTED_UNESCAPED_TEST_MESSAGE, replacedMessage);
}
}
#
# Copyright 2014-2014 Hippo B.V. (http://www.onehippo.com)
# Copyright 2014-2018 Hippo B.V. (http://www.onehippo.com)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
......@@ -18,3 +18,4 @@ ns1.target.environment.url=http://web24.ns1.com:9090
header.search.form.action.path.en=/PS/en/Redirect.do
header.search.form.action.path.fr=/PS/fr/Redirect.do
annual.payment=500
escapable.greeting=<script>alert('hi there!');</script>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment