diff --git a/CLAUDE.md b/CLAUDE.md index 3710f03544..408f7c02da 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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 diff --git a/core/src/main/java/org/apache/struts2/result/StreamResult.java b/core/src/main/java/org/apache/struts2/result/StreamResult.java index 9324d5bb55..235152e984 100644 --- a/core/src/main/java/org/apache/struts2/result/StreamResult.java +++ b/core/src/main/java/org/apache/struts2/result/StreamResult.java @@ -21,6 +21,7 @@ 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 @@ protected void doExecute(String finalLocation, ActionInvocation invocation) thro if (inputStream == null) { String msg = ("Can not find a java.io.InputStream with the name [" + parsedInputName + "] in the invocation stack. " + - "Check the tag specified for this action is correct, not excluded and accepted."); + "Check the tag specified for this action is correct, not excluded and accepted."); LOG.error(msg); throw new IllegalArgumentException(msg); } @@ -231,11 +232,12 @@ protected void doExecute(String finalLocation, ActionInvocation invocation) thro 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 @@ protected void doExecute(String finalLocation, ActionInvocation invocation) thro 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]; diff --git a/core/src/test/java/org/apache/struts2/result/StreamResultTest.java b/core/src/test/java/org/apache/struts2/result/StreamResultTest.java index a02781812f..a7621e8e94 100644 --- a/core/src/test/java/org/apache/struts2/result/StreamResultTest.java +++ b/core/src/test/java/org/apache/struts2/result/StreamResultTest.java @@ -120,6 +120,16 @@ public void testStreamResultWithCharSet2() throws Exception { 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 String getStreamForImageAsExpression() { public String getContentCharSetMethod() { return "UTF-8"; } + + public String getNullCharSetMethod() { + return null; + } } }