From b292ca59c0b0e54c1d661b67ed99008458a5478b Mon Sep 17 00:00:00 2001 From: Arun Date: Sat, 11 Jul 2026 05:36:42 +0530 Subject: [PATCH 1/2] Modernize path normalization in Include component and handle edge cases --- .../org/apache/struts2/components/Include.java | 17 ++++++++++------- 1 file changed, 10 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 f8decac25f..039b4b03eb 100644 --- a/core/src/main/java/org/apache/struts2/components/Include.java +++ b/core/src/main/java/org/apache/struts2/components/Include.java @@ -47,7 +47,8 @@ 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; /** @@ -203,7 +204,7 @@ public static String getContextRelativePath(ServletRequest request, String relat // .. is illegal in an absolute path according to the Servlet Spec and will cause // known problems on Orion application servers. if (returnValue.contains("..")) { - Stack stack = new Stack<>(); + Deque segments = new ArrayDeque<>(); StringTokenizer pathParts = new StringTokenizer(returnValue.replace('\\', '/'), "/"); while (pathParts.hasMoreTokens()) { @@ -211,20 +212,22 @@ public static String getContextRelativePath(ServletRequest request, String relat 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)); + for (String segment : segments) { + flatPathBuffer.append("/").append(segment); } - returnValue = flatPathBuffer.toString(); + returnValue = flatPathBuffer.length() > 0 ? flatPathBuffer.toString() : "/"; } return returnValue; From 6b33fdcc56d2ea9ad5d4767f8209139a23f79e12 Mon Sep 17 00:00:00 2001 From: Arun Date: Sat, 11 Jul 2026 05:42:44 +0530 Subject: [PATCH 2/2] Add tests for edge case dot-dot handling in Include path normalization --- .../org/apache/struts2/views/jsp/IncludeTagTest.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) 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 7ca1daf127..9ca0587e3e 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 void testIncludeRelative2Dots_clearTagStateSet() throws Exception { 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