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

commit 70e10cd206e2209ab6109383bc3b9be97466968b
Author: Lukasz Lenart <[email protected]>
AuthorDate: Mon Nov 2 09:56:56 2026 +0100

    WW-4164 fix(core): match the full requested name when slashes are allowed
    
    With slashes in action names the raw name spans the whole path after the
    namespace, so the declaration probe rebuilds the URI from the probe's
    namespace and name instead of comparing only the last segment.
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 .../dispatcher/mapper/DefaultActionMapper.java        | 12 ++++++++----
 .../dispatcher/mapper/DefaultActionMapperTest.java    | 19 +++++++++++++++++++
 2 files changed, 27 insertions(+), 4 deletions(-)

diff --git 
a/core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java
 
b/core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java
index 63208956f..c4ddf8575 100644
--- 
a/core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java
+++ 
b/core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java
@@ -511,7 +511,7 @@ public class DefaultActionMapper implements ActionMapper {
     private boolean declaresExtensions(String candidate, RuntimeConfiguration 
runtimeConfiguration, ConfigurationManager configManager) {
         ActionMapping probe = new ActionMapping();
         parseNameAndNamespace(candidate, probe, configManager);
-        if (!keepsRequestedName(candidate, probe.getName())) {
+        if (!keepsRequestedName(candidate, probe)) {
             return false;
         }
         parseActionName(probe);
@@ -519,9 +519,13 @@ public class DefaultActionMapper implements ActionMapper {
         return config != null && !config.getExtensions().isEmpty();
     }
 
-    private static boolean keepsRequestedName(String uri, String name) {
-        String lastSegment = uri.substring(uri.lastIndexOf('/') + 1);
-        return name.equals(lastSegment) || name.endsWith("/" + lastSegment);
+    private boolean keepsRequestedName(String uri, ActionMapping probe) {
+        String name = probe.getName();
+        if (!allowSlashesInActionNames) {
+            return uri.substring(uri.lastIndexOf('/') + 1).equals(name);
+        }
+        String namespace = "/".equals(probe.getNamespace()) ? "" : 
probe.getNamespace();
+        return uri.equals(name) || uri.equals(namespace + "/" + name);
     }
 
     private DeclaredExtensions declaredExtensions(RuntimeConfiguration 
runtimeConfiguration) {
diff --git 
a/core/src/test/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapperTest.java
 
b/core/src/test/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapperTest.java
index 7113f60d8..cee45edc0 100644
--- 
a/core/src/test/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapperTest.java
+++ 
b/core/src/test/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapperTest.java
@@ -1153,6 +1153,25 @@ public class DefaultActionMapperTest extends 
StrutsInternalTestCase {
         assertThat(mapDeclared(declaredMapper(), "/manual(1).html")).isNull();
     }
 
+    public void 
testDeclaringDefaultActionDoesNotClaimDisallowedNameWithSlashes() {
+        loadConfigurationProviders(new 
StrutsXmlConfigurationProvider(EXTENSION_DEFAULT_ACTION_CONFIG));
+        DefaultActionMapper mapper = declaredMapper();
+        mapper.setSlashesInActionNames("true");
+
+        assertThat(mapDeclared(mapper, "/x(1)/index.html")).isNull();
+    }
+
+    public void testDeclaringDefaultActionClaimsItsOwnNameWithSlashes() {
+        loadConfigurationProviders(new 
StrutsXmlConfigurationProvider(EXTENSION_DEFAULT_ACTION_CONFIG));
+        DefaultActionMapper mapper = declaredMapper();
+        mapper.setSlashesInActionNames("true");
+
+        ActionMapping mapping = mapDeclared(mapper, "/index.html");
+
+        assertThat(mapping.getName()).isEqualTo("index");
+        assertThat(mapping.getExtension()).isEqualTo("html");
+    }
+
     public void testDeclaredExtensionClaimedForLiteralBangNameWithoutDmi() {
         loadConfigurationProviders(new 
StrutsXmlConfigurationProvider(EXTENSION_BANG_CONFIG));
 

Reply via email to