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

robertlazarski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/axis-axis2-java-core.git

commit acfcec22598133925077d96a38bfdc9a9520b68c
Author: Zibran Khan <[email protected]>
AuthorDate: Mon Oct 26 18:22:49 2026 +0530

    take the operation and http location from the request path only
---
 .../dispatchers/HTTPLocationBasedDispatcher.java   | 12 ++-
 .../RequestURIBasedOperationDispatcher.java        |  8 +-
 .../kernel/src/org/apache/axis2/util/Utils.java    | 10 ++-
 .../HTTPLocationBasedDispatcherTest.java           | 90 ++++++++++++++++++++++
 .../RequestURIBasedOperationDispatcherTest.java    | 28 +++++++
 .../axis2/webapp/RequestURIDispatchITCase.java     | 19 +++--
 6 files changed, 152 insertions(+), 15 deletions(-)

diff --git 
a/modules/kernel/src/org/apache/axis2/dispatchers/HTTPLocationBasedDispatcher.java
 
b/modules/kernel/src/org/apache/axis2/dispatchers/HTTPLocationBasedDispatcher.java
index 5a58882f50..ce561e5aca 100644
--- 
a/modules/kernel/src/org/apache/axis2/dispatchers/HTTPLocationBasedDispatcher.java
+++ 
b/modules/kernel/src/org/apache/axis2/dispatchers/HTTPLocationBasedDispatcher.java
@@ -99,7 +99,14 @@ public class HTTPLocationBasedDispatcher extends 
AbstractDispatcher {
     private String parseRequestURL(String path, String serviceName) {
 
         serviceName = "/" + serviceName;
-        int index = path.lastIndexOf(serviceName);
+        // The query string stays in the location, since location templates may
+        // match on it, but only the path may say where the service name and 
the
+        // location start: a query value can contain both.
+        int pathEnd = path.indexOf('?');
+        if (pathEnd == -1) {
+            pathEnd = path.length();
+        }
+        int index = path.lastIndexOf(serviceName, pathEnd - 
serviceName.length());
         String httpLocation = null;
 
         if (-1 != index) {
@@ -111,7 +118,8 @@ public class HTTPLocationBasedDispatcher extends 
AbstractDispatcher {
 
         if (httpLocation != null) {
             index = httpLocation.indexOf("/");
-            if (-1 != index) {
+            int locationQuery = httpLocation.indexOf("?");
+            if (-1 != index && (locationQuery == -1 || index < locationQuery)) 
{
                 httpLocation = httpLocation.substring(index);
             } else {
                 int queryIndex = httpLocation.indexOf("?");
diff --git 
a/modules/kernel/src/org/apache/axis2/dispatchers/RequestURIBasedOperationDispatcher.java
 
b/modules/kernel/src/org/apache/axis2/dispatchers/RequestURIBasedOperationDispatcher.java
index 761dd1f93d..dbb95001f0 100644
--- 
a/modules/kernel/src/org/apache/axis2/dispatchers/RequestURIBasedOperationDispatcher.java
+++ 
b/modules/kernel/src/org/apache/axis2/dispatchers/RequestURIBasedOperationDispatcher.java
@@ -50,7 +50,13 @@ public class RequestURIBasedOperationDispatcher extends 
AbstractOperationDispatc
         EndpointReference toEPR = messageContext.getTo();
         if (toEPR != null) {
             String filePart = toEPR.getAddress();
-            String operation  = Utils.getOperationName(filePart, 
service.getName());
+            // Read the operation from the part after the service context 
path, the
+            // part the service was resolved from, so a suffix that repeats the
+            // service name cannot pick a different operation.
+            String serviceOpPart = Utils.getServiceAndOperationPart(filePart,
+                    
messageContext.getConfigurationContext().getServiceContextPath());
+            String operation  = Utils.getOperationName(
+                    serviceOpPart != null ? serviceOpPart : filePart, 
service.getName());
 
             if (operation != null) {
                 QName operationName = new QName(operation);
diff --git a/modules/kernel/src/org/apache/axis2/util/Utils.java 
b/modules/kernel/src/org/apache/axis2/util/Utils.java
index 6164016352..edc3d2d030 100644
--- a/modules/kernel/src/org/apache/axis2/util/Utils.java
+++ b/modules/kernel/src/org/apache/axis2/util/Utils.java
@@ -288,7 +288,7 @@ public class Utils {
      * Ex:  ../services/Echo/echoString -> echoString
      *      ../services/foo/1.0.0/Echo/echoString -> echoString
      *      ../services/Echo/ -> null
-     * @param path - request URI
+     * @param path - request URI, or the part of it after the service context 
path
      * @param serviceName - service name
      * @return - operation name if any, else null
      */
@@ -297,15 +297,17 @@ public class Utils {
             return null;
         }
         // The operation is read from the path only; a query value may 
legitimately
-        // contain the service name followed by a slash.
+        // contain the service name followed by a slash. The operation follows 
the
+        // first occurrence of the service name: a later one is a suffix the 
caller
+        // appended.
         path = withoutQuery(path);
-        int idx = path.lastIndexOf(serviceName + "/");
+        int idx = path.indexOf(serviceName + "/");
         String operationName = null;
         if (idx != -1) {
             operationName = path.substring(idx + serviceName.length() + 1);
         } else {
             //this scenario occurs if the endpoint name is there in the URL 
after service name
-            idx = path.lastIndexOf(serviceName + ".");
+            idx = path.indexOf(serviceName + ".");
             if (idx != -1) {
                 operationName = path.substring(idx + serviceName.length() + 1);
                 operationName = 
operationName.substring(operationName.indexOf('/') + 1);
diff --git 
a/modules/kernel/test/org/apache/axis2/dispatchers/HTTPLocationBasedDispatcherTest.java
 
b/modules/kernel/test/org/apache/axis2/dispatchers/HTTPLocationBasedDispatcherTest.java
new file mode 100644
index 0000000000..3773329f3b
--- /dev/null
+++ 
b/modules/kernel/test/org/apache/axis2/dispatchers/HTTPLocationBasedDispatcherTest.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.axis2.dispatchers;
+
+import junit.framework.TestCase;
+import org.apache.axis2.AxisFault;
+import org.apache.axis2.addressing.EndpointReference;
+import org.apache.axis2.context.ConfigurationContext;
+import org.apache.axis2.context.ConfigurationContextFactory;
+import org.apache.axis2.context.MessageContext;
+import org.apache.axis2.description.AxisBinding;
+import org.apache.axis2.description.AxisEndpoint;
+import org.apache.axis2.description.AxisOperation;
+import org.apache.axis2.description.AxisService;
+import org.apache.axis2.description.InOnlyAxisOperation;
+import org.apache.axis2.description.WSDL2Constants;
+import org.apache.axis2.kernel.http.HTTPConstants;
+
+import javax.xml.namespace.QName;
+import java.util.HashMap;
+import java.util.Map;
+
+public class HTTPLocationBasedDispatcherTest extends TestCase {
+
+    private AxisService service;
+    private AxisOperation safe;
+    private AxisOperation delete;
+    private AxisEndpoint endpoint;
+    private ConfigurationContext cc;
+
+    protected void setUp() throws Exception {
+        service = new AxisService("Svc");
+        safe = new InOnlyAxisOperation(new QName("safe"));
+        delete = new InOnlyAxisOperation(new QName("delete"));
+        service.addOperation(safe);
+        service.addOperation(delete);
+
+        Map<String, AxisOperation> httpLocationTable = new HashMap<String, 
AxisOperation>();
+        httpLocationTable.put("GET/safe", safe);
+        httpLocationTable.put("GET/delete", delete);
+        AxisBinding binding = new AxisBinding();
+        binding.setProperty(WSDL2Constants.HTTP_LOCATION_TABLE, 
httpLocationTable);
+        endpoint = new AxisEndpoint();
+        endpoint.setBinding(binding);
+
+        cc = ConfigurationContextFactory.createEmptyConfigurationContext();
+        cc.getAxisConfiguration().addService(service);
+    }
+
+    private AxisOperation findOperation(String to) throws AxisFault {
+        MessageContext messageContext = cc.createMessageContext();
+        messageContext.setTo(new EndpointReference(to));
+        messageContext.setAxisService(service);
+        messageContext.setProperty(WSDL2Constants.ENDPOINT_LOCAL_NAME, 
endpoint);
+        messageContext.setProperty(HTTPConstants.HTTP_METHOD, "GET");
+        return new HTTPLocationBasedDispatcher().findOperation(service, 
messageContext);
+    }
+
+    public void testLocationFromPath() throws AxisFault {
+        assertEquals(safe, findOperation("/axis2/services/Svc/safe"));
+        assertEquals(delete, findOperation("/axis2/services/Svc/delete"));
+        assertEquals(safe, findOperation("/axis2/services/Svc/safe?x=1"));
+    }
+
+    /**
+     * The location starts after the service name in the request path; a query
+     * value that repeats the service name must not select a different 
location.
+     */
+    public void testLocationNotTakenFromQueryString() throws AxisFault {
+        assertEquals(safe, 
findOperation("/axis2/services/Svc/safe?x=/Svc/delete"));
+        assertNull(findOperation("/axis2/services/Svc?x=/Svc/delete"));
+    }
+}
diff --git 
a/modules/kernel/test/org/apache/axis2/dispatchers/RequestURIBasedOperationDispatcherTest.java
 
b/modules/kernel/test/org/apache/axis2/dispatchers/RequestURIBasedOperationDispatcherTest.java
index 39a54f31a2..e74aaab598 100644
--- 
a/modules/kernel/test/org/apache/axis2/dispatchers/RequestURIBasedOperationDispatcherTest.java
+++ 
b/modules/kernel/test/org/apache/axis2/dispatchers/RequestURIBasedOperationDispatcherTest.java
@@ -145,4 +145,32 @@ public class RequestURIBasedOperationDispatcherTest 
extends TestCase {
         ruisd.invoke(messageContext);
         assertNull(messageContext.getAxisOperation());
     }
+
+    /**
+     * A path suffix that repeats the service name must not choose the 
operation:
+     * the operation is the segment right after the service the path names.
+     */
+    public void testOperationNotTakenFromRepeatedServiceName() throws 
AxisFault {
+        AxisService service = new AxisService("Echo");
+        AxisOperation echo = new InOnlyAxisOperation(new QName("echo"));
+        AxisOperation deleteAll = new InOnlyAxisOperation(new 
QName("deleteAll"));
+        service.addOperation(echo);
+        service.addOperation(deleteAll);
+        ConfigurationContext cc = 
ConfigurationContextFactory.createEmptyConfigurationContext();
+        cc.getAxisConfiguration().addService(service);
+        RequestURIBasedOperationDispatcher ruisd = new 
RequestURIBasedOperationDispatcher();
+
+        MessageContext messageContext = cc.createMessageContext();
+        messageContext.setTo(new 
EndpointReference("/axis2/services/Echo/echo/Echo/deleteAll"));
+        messageContext.setAxisService(service);
+        ruisd.invoke(messageContext);
+        assertEquals(echo, messageContext.getAxisOperation());
+
+        messageContext = cc.createMessageContext();
+        messageContext.setTo(new EndpointReference(
+                
"/axis2/services/Echo.EchoEndpoint/echo/Echo.EchoEndpoint/deleteAll"));
+        messageContext.setAxisService(service);
+        ruisd.invoke(messageContext);
+        assertEquals(echo, messageContext.getAxisOperation());
+    }
 }
diff --git 
a/systests/webapp-tests/src/test/java/org/apache/axis2/webapp/RequestURIDispatchITCase.java
 
b/systests/webapp-tests/src/test/java/org/apache/axis2/webapp/RequestURIDispatchITCase.java
index b2767ec32b..4ac7f33071 100644
--- 
a/systests/webapp-tests/src/test/java/org/apache/axis2/webapp/RequestURIDispatchITCase.java
+++ 
b/systests/webapp-tests/src/test/java/org/apache/axis2/webapp/RequestURIDispatchITCase.java
@@ -34,23 +34,26 @@ import org.junit.Test;
  * not select anything.
  */
 public class RequestURIDispatchITCase {
-    private static String get(String pathAndQuery) throws Exception {
+    private static HttpResponse<String> get(String pathAndQuery) throws 
Exception {
         int port = Integer.getInteger("jetty.httpPort", 8080);
         HttpRequest request = HttpRequest.newBuilder(
                 URI.create("http://localhost:"; + port + "/axis2" + 
pathAndQuery)).GET().build();
-        return HttpClient.newHttpClient()
-                .send(request, HttpResponse.BodyHandlers.ofString()).body();
+        return HttpClient.newHttpClient().send(request, 
HttpResponse.BodyHandlers.ofString());
     }
 
     @Test
     public void testServiceIsTakenFromThePathOnly() throws Exception {
         // Control: the operation answers when the path names it.
-        
assertThat(get("/services/Version/getVersion")).contains("getVersionResponse");
+        HttpResponse<String> response = get("/services/Version/getVersion");
+        assertThat(response.statusCode()).isEqualTo(200);
+        assertThat(response.body()).contains("getVersionResponse");
         // The path names no deployed service; neither the query string nor a
         // repeated service path after it may route the request to Version.
-        
assertThat(get("/services/NoSuchService?next=/axis2/services/Version/getVersion"))
-                .doesNotContain("getVersionResponse");
-        
assertThat(get("/services/NoSuchService/axis2/services/Version/getVersion"))
-                .doesNotContain("getVersionResponse");
+        response = 
get("/services/NoSuchService?next=/axis2/services/Version/getVersion");
+        assertThat(response.statusCode()).isEqualTo(404);
+        assertThat(response.body()).doesNotContain("getVersionResponse");
+        response = 
get("/services/NoSuchService/axis2/services/Version/getVersion");
+        assertThat(response.statusCode()).isEqualTo(404);
+        assertThat(response.body()).doesNotContain("getVersionResponse");
     }
 }

Reply via email to