This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch fix/WW-5548-forward
in repository https://gitbox.apache.org/repos/asf/struts.git

commit ab727f3d16b38953dd35219f3e7d4e0abd594e18
Author: Lukasz Lenart <lukaszlen...@apache.org>
AuthorDate: Thu May 8 07:58:19 2025 +0200

    WW-5548 Defines proper request attributes when forwarding or including 
final path
---
 .../struts2/result/ServletDispatcherResult.java    | 30 ++++++++++++++------
 .../result/ServletDispatcherResultTest.java        | 33 ++++++++++++++++++----
 2 files changed, 49 insertions(+), 14 deletions(-)

diff --git 
a/core/src/main/java/org/apache/struts2/result/ServletDispatcherResult.java 
b/core/src/main/java/org/apache/struts2/result/ServletDispatcherResult.java
index feced67bb..3d8aeb8f3 100644
--- a/core/src/main/java/org/apache/struts2/result/ServletDispatcherResult.java
+++ b/core/src/main/java/org/apache/struts2/result/ServletDispatcherResult.java
@@ -18,8 +18,6 @@
  */
 package org.apache.struts2.result;
 
-import org.apache.struts2.ActionInvocation;
-import org.apache.struts2.inject.Inject;
 import jakarta.servlet.RequestDispatcher;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
@@ -28,9 +26,11 @@ import org.apache.commons.lang3.ObjectUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
+import org.apache.struts2.ActionInvocation;
 import org.apache.struts2.ServletActionContext;
 import org.apache.struts2.StrutsStatics;
 import org.apache.struts2.dispatcher.HttpParameters;
+import org.apache.struts2.inject.Inject;
 import org.apache.struts2.url.QueryStringParser;
 
 import java.io.Serial;
@@ -158,13 +158,6 @@ public class ServletDispatcherResult extends 
StrutsResultSupport {
             //if we are inside an action tag, we always need to do an include
             boolean insideActionTag = (Boolean) 
ObjectUtils.defaultIfNull(request.getAttribute(StrutsStatics.STRUTS_ACTION_TAG_INVOCATION),
 Boolean.FALSE);
 
-            // this should allow integration with third-party view related 
frameworks
-            if (finalLocation.contains("?")) {
-                request.setAttribute(RequestDispatcher.FORWARD_SERVLET_PATH, 
finalLocation.substring(0, finalLocation.indexOf('?')));
-            } else {
-                request.setAttribute(RequestDispatcher.FORWARD_SERVLET_PATH, 
finalLocation);
-            }
-
             // If we're included, then include the view
             // Otherwise do forward
             // This allow the page to, for example, set content type
@@ -173,9 +166,28 @@ public class ServletDispatcherResult extends 
StrutsResultSupport {
                 request.setAttribute("struts.view_uri", finalLocation);
                 request.setAttribute("struts.request_uri", 
request.getRequestURI());
 
+                // These attributes are required when forwarding to another 
servlet, see specification:
+                // 
https://jakarta.ee/specifications/servlet/6.0/jakarta-servlet-spec-6.0#forwarded-request-parameters
+                request.setAttribute(RequestDispatcher.FORWARD_MAPPING, 
request.getHttpServletMapping());
+                request.setAttribute(RequestDispatcher.FORWARD_REQUEST_URI, 
request.getRequestURI());
+                request.setAttribute(RequestDispatcher.FORWARD_CONTEXT_PATH, 
request.getContextPath());
+                request.setAttribute(RequestDispatcher.FORWARD_SERVLET_PATH, 
request.getServletPath());
+                request.setAttribute(RequestDispatcher.FORWARD_PATH_INFO, 
request.getPathInfo());
+                request.setAttribute(RequestDispatcher.FORWARD_QUERY_STRING, 
request.getQueryString());
+
                 dispatcher.forward(request, response);
             } else {
                 LOG.debug("Including location: {}", finalLocation);
+
+                // These attributes are required when forwarding to another 
servlet, see specification:
+                // 
https://jakarta.ee/specifications/servlet/6.0/jakarta-servlet-spec-6.0#included-request-parameters
+                request.setAttribute(RequestDispatcher.INCLUDE_MAPPING, 
request.getHttpServletMapping());
+                request.setAttribute(RequestDispatcher.INCLUDE_REQUEST_URI, 
request.getRequestURI());
+                request.setAttribute(RequestDispatcher.INCLUDE_CONTEXT_PATH, 
request.getContextPath());
+                request.setAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH, 
request.getServletPath());
+                request.setAttribute(RequestDispatcher.INCLUDE_PATH_INFO, 
request.getPathInfo());
+                request.setAttribute(RequestDispatcher.INCLUDE_QUERY_STRING, 
request.getQueryString());
+
                 dispatcher.include(request, response);
             }
         }
diff --git 
a/core/src/test/java/org/apache/struts2/result/ServletDispatcherResultTest.java 
b/core/src/test/java/org/apache/struts2/result/ServletDispatcherResultTest.java
index c64c9d76a..c14332665 100644
--- 
a/core/src/test/java/org/apache/struts2/result/ServletDispatcherResultTest.java
+++ 
b/core/src/test/java/org/apache/struts2/result/ServletDispatcherResultTest.java
@@ -39,30 +39,54 @@ public class ServletDispatcherResultTest extends 
StrutsInternalTestCase implemen
         ServletDispatcherResult view = new ServletDispatcherResult();
         view.setLocation("foo.jsp");
 
+        request.setRequestURI("/app/namespace/my.action");
+        request.setContextPath("/app");
+        request.setServletPath("/namespace/my.action");
+        request.setPathInfo(null);
+        request.setQueryString("a=1&b=2");
+
         request.setAttribute("struts.actiontag.invocation", null);
         request.setAttribute("jakarta.servlet.include.servlet_path", null);
-        request.setRequestURI("foo.jsp");
 
         response.setCommitted(Boolean.FALSE);
 
         view.execute(invocation);
 
         assertEquals("foo.jsp", response.getForwardedUrl());
-        assertEquals("foo.jsp", 
request.getAttribute(RequestDispatcher.FORWARD_SERVLET_PATH));
+
+        // Attributes required by Specification when forwarding to another 
resource
+        // 
https://jakarta.ee/specifications/servlet/6.0/jakarta-servlet-spec-6.0#forwarded-request-parameters
+        assertEquals("/app/namespace/my.action", 
request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI));
+        assertEquals("/app", 
request.getAttribute(RequestDispatcher.FORWARD_CONTEXT_PATH));
+        assertEquals("/namespace/my.action", 
request.getAttribute(RequestDispatcher.FORWARD_SERVLET_PATH));
+        assertNull(request.getAttribute(RequestDispatcher.FORWARD_PATH_INFO));
+        assertEquals("a=1&b=2", 
request.getAttribute(RequestDispatcher.FORWARD_QUERY_STRING));
     }
 
     public void testInclude() throws Exception {
         ServletDispatcherResult view = new ServletDispatcherResult();
         view.setLocation("foo.jsp");
 
+        request.setRequestURI("/app/namespace/my.action");
+        request.setContextPath("/app");
+        request.setServletPath("/namespace/my.action");
+        request.setPathInfo(null);
+        request.setQueryString("a=1&b=2");
+
         request.setAttribute("struts.actiontag.invocation", null);
         response.setCommitted(Boolean.TRUE);
-        request.setRequestURI("foo.jsp");
 
         view.execute(invocation);
 
         assertEquals("foo.jsp", response.getIncludedUrl());
-        assertEquals("foo.jsp", 
request.getAttribute(RequestDispatcher.FORWARD_SERVLET_PATH));
+
+        // These attributes must be set when including another resource
+        // 
https://jakarta.ee/specifications/servlet/6.0/jakarta-servlet-spec-6.0#included-request-parameters
+        assertEquals("/app/namespace/my.action", 
request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI));
+        assertEquals("/app", 
request.getAttribute(RequestDispatcher.INCLUDE_CONTEXT_PATH));
+        assertEquals("/namespace/my.action", 
request.getAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH));
+        assertNull(request.getAttribute(RequestDispatcher.INCLUDE_PATH_INFO));
+        assertEquals("a=1&b=2", 
request.getAttribute(RequestDispatcher.INCLUDE_QUERY_STRING));
     }
 
     public void testWithParameter() throws Exception {
@@ -76,7 +100,6 @@ public class ServletDispatcherResultTest extends 
StrutsInternalTestCase implemen
 
         // See https://issues.apache.org/jira/browse/WW-5486
         assertEquals("1", stack.findString("#parameters.bar"));
-        assertEquals("foo.jsp", 
request.getAttribute(RequestDispatcher.FORWARD_SERVLET_PATH));
     }
 
     @Override

Reply via email to