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"); } }
