This is an automated email from the ASF dual-hosted git repository.
lukaszlenart pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/struts.git
The following commit(s) were added to refs/heads/main by this push:
new de599c91d WW-5646 Modernize path normalization in Include component
(#1780)
de599c91d is described below
commit de599c91d3519d216c4e048fc207717881a6144c
Author: Arun <[email protected]>
AuthorDate: Fri Jul 17 15:48:08 2026 +0530
WW-5646 Modernize path normalization in Include component (#1780)
* Modernize path normalization in Include component and handle edge cases
* Add tests for edge case dot-dot handling in Include path normalization
* Fix reversed path segment order in getContextRelativePath()
The for-each loop iterated the ArrayDeque head-to-tail (most
recently pushed first), which is the reverse of the old Stack's
insertion-order iteration. This caused rebuilt paths like
"car/view.jsp" to come out as "view.jsp/car".
Use descendingIterator() to restore the original oldest-first
ordering when rebuilding the flat path string.
---
.../java/org/apache/struts2/components/Include.java | 19 ++++++++++++-------
.../org/apache/struts2/views/jsp/IncludeTagTest.java | 12 ++++++++++++
2 files changed, 24 insertions(+), 7 deletions(-)
diff --git a/core/src/main/java/org/apache/struts2/components/Include.java
b/core/src/main/java/org/apache/struts2/components/Include.java
index f8decac25..55f0baaf8 100644
--- a/core/src/main/java/org/apache/struts2/components/Include.java
+++ b/core/src/main/java/org/apache/struts2/components/Include.java
@@ -47,8 +47,10 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import java.util.Stack;
+import java.util.ArrayDeque;
+import java.util.Deque;
import java.util.StringTokenizer;
+import java.util.Iterator;
/**
* <!-- START SNIPPET: javadoc -->
@@ -203,7 +205,7 @@ public class Include extends Component {
// .. is illegal in an absolute path according to the Servlet Spec and
will cause
// known problems on Orion application servers.
if (returnValue.contains("..")) {
- Stack<String> stack = new Stack<>();
+ Deque<String> segments = new ArrayDeque<>();
StringTokenizer pathParts = new
StringTokenizer(returnValue.replace('\\', '/'), "/");
while (pathParts.hasMoreTokens()) {
@@ -211,20 +213,23 @@ public class Include extends Component {
if (!part.equals(".")) {
if (part.equals("..")) {
- stack.pop();
+ if (!segments.isEmpty()) {
+ segments.pop();
+ }
} else {
- stack.push(part);
+ segments.push(part);
}
}
}
StringBuilder flatPathBuffer = new StringBuilder();
- for (int i = 0; i < stack.size(); i++) {
- flatPathBuffer.append("/").append(stack.elementAt(i));
+ Iterator<String> it = segments.descendingIterator();
+ while (it.hasNext()) {
+ flatPathBuffer.append("/").append(it.next());
}
- returnValue = flatPathBuffer.toString();
+ returnValue = flatPathBuffer.length() > 0 ?
flatPathBuffer.toString() : "/";
}
return returnValue;
diff --git
a/core/src/test/java/org/apache/struts2/views/jsp/IncludeTagTest.java
b/core/src/test/java/org/apache/struts2/views/jsp/IncludeTagTest.java
index 7ca1daf12..9ca0587e3 100644
--- a/core/src/test/java/org/apache/struts2/views/jsp/IncludeTagTest.java
+++ b/core/src/test/java/org/apache/struts2/views/jsp/IncludeTagTest.java
@@ -220,6 +220,18 @@ public class IncludeTagTest extends AbstractTagTest {
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
+ public void testGetContextRelativePathExcessDotDot() {
+ // Excess ".." segments beyond root should be silently clamped, not
throw EmptyStackException
+ String result = Include.getContextRelativePath(request,
"/../../../other/resource.jsp");
+ assertEquals("/other/resource.jsp", result);
+ }
+
+ public void testGetContextRelativePathAllDotDot() {
+ // All segments are ".." - should resolve to root
+ String result = Include.getContextRelativePath(request, "/a/../../..");
+ assertEquals("/", result);
+ }
+
public void testIncludeSetUseResponseEncodingTrue() throws Exception {
// TODO: If possible in future mock-test an actual content-includes
with various encodings
// while setting the response encoding to match. Doesn't appear to
be possible