mirror of
https://github.com/apache/struts.git
synced 2026-08-06 23:27:07 +00:00
WW-5602 fix StreamResult contentCharSet handling (#1511)
Evaluates contentCharSet expression before emptiness check to prevent malformed content-type headers when expression evaluates to null. - Parse contentCharSet expression first, then check if result is empty - Use StringUtils.isNotEmpty() for proper null/empty validation - Use setCharacterEncoding() instead of appending to content-type string - Add test for null-evaluating charset expressions 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -148,6 +148,7 @@ Each plugin is a separate Maven module with:
|
||||
### Important Notes
|
||||
- **Version**: Currently 6.7.5-SNAPSHOT (release branch: `release/struts-6-7-x`)
|
||||
- **Java Compatibility**: Compiled for Java 8, tested through Java 21
|
||||
- **Servlet API**: Uses javax.servlet (Java EE), NOT Jakarta EE (jakarta.servlet)
|
||||
- **Security**: Always validate inputs and follow OWASP guidelines
|
||||
- **Performance**: Leverage built-in caching (OGNL expressions, templates)
|
||||
- **Deprecation**: Some legacy XWork components marked for removal
|
||||
|
||||
@@ -21,6 +21,7 @@ package org.apache.struts2.result;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.security.NotExcludedAcceptedPatternsChecker;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@@ -223,7 +224,7 @@ public class StreamResult extends StrutsResultSupport {
|
||||
|
||||
if (inputStream == null) {
|
||||
String msg = ("Can not find a java.io.InputStream with the name [" + parsedInputName + "] in the invocation stack. " +
|
||||
"Check the <param name=\"inputName\"> tag specified for this action is correct, not excluded and accepted.");
|
||||
"Check the <param name=\"inputName\"> tag specified for this action is correct, not excluded and accepted.");
|
||||
LOG.error(msg);
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
@@ -231,11 +232,12 @@ public class StreamResult extends StrutsResultSupport {
|
||||
|
||||
HttpServletResponse oResponse = invocation.getInvocationContext().getServletResponse();
|
||||
|
||||
LOG.debug("Set the content type: {};charset{}", contentType, contentCharSet);
|
||||
if (contentCharSet != null && !contentCharSet.equals("")) {
|
||||
oResponse.setContentType(conditionalParse(contentType, invocation) + ";charset=" + conditionalParse(contentCharSet, invocation));
|
||||
} else {
|
||||
oResponse.setContentType(conditionalParse(contentType, invocation));
|
||||
LOG.debug("Set the content type: {};charset={}", contentType, contentCharSet);
|
||||
String parsedContentType = conditionalParse(contentType, invocation);
|
||||
String parsedContentCharSet = conditionalParse(contentCharSet, invocation);
|
||||
oResponse.setContentType(parsedContentType);
|
||||
if (StringUtils.isNotEmpty(parsedContentCharSet)) {
|
||||
oResponse.setCharacterEncoding(parsedContentCharSet);
|
||||
}
|
||||
|
||||
LOG.debug("Set the content length: {}", contentLength);
|
||||
@@ -267,7 +269,7 @@ public class StreamResult extends StrutsResultSupport {
|
||||
oOutput = oResponse.getOutputStream();
|
||||
|
||||
LOG.debug("Streaming result [{}] type=[{}] length=[{}] content-disposition=[{}] charset=[{}]",
|
||||
inputName, contentType, contentLength, contentDisposition, contentCharSet);
|
||||
inputName, contentType, contentLength, contentDisposition, contentCharSet);
|
||||
|
||||
LOG.debug("Streaming to output buffer +++ START +++");
|
||||
byte[] oBuff = new byte[bufferSize];
|
||||
|
||||
@@ -120,6 +120,16 @@ public class StreamResultTest extends StrutsInternalTestCase {
|
||||
assertEquals("inline", response.getHeader("Content-disposition"));
|
||||
}
|
||||
|
||||
public void testStreamResultWithNullCharSetExpression() throws Exception {
|
||||
result.setParse(true);
|
||||
result.setInputName("streamForImage");
|
||||
result.setContentCharSet("${nullCharSetMethod}");
|
||||
|
||||
result.doExecute("helloworld", mai);
|
||||
|
||||
assertEquals("text/plain", response.getContentType());
|
||||
}
|
||||
|
||||
public void testAllowCacheDefault() throws Exception {
|
||||
result.setInputName("streamForImage");
|
||||
|
||||
@@ -310,6 +320,10 @@ public class StreamResultTest extends StrutsInternalTestCase {
|
||||
public String getContentCharSetMethod() {
|
||||
return "UTF-8";
|
||||
}
|
||||
|
||||
public String getNullCharSetMethod() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user