Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 9 additions & 7 deletions core/src/main/java/org/apache/struts2/result/StreamResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -223,19 +224,20 @@ 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 <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);
}


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);
Expand Down Expand Up @@ -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];
Expand Down
14 changes: 14 additions & 0 deletions core/src/test/java/org/apache/struts2/result/StreamResultTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand Down Expand Up @@ -310,6 +320,10 @@ public String getStreamForImageAsExpression() {
public String getContentCharSetMethod() {
return "UTF-8";
}

public String getNullCharSetMethod() {
return null;
}
}

}