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

albumenj pushed a commit to branch 3.3
in repository https://gitbox.apache.org/repos/asf/dubbo.git


The following commit(s) were added to refs/heads/3.3 by this push:
     new 70f6e03636 Returns a matching http status code based on the rest 
mappings (#14714)
70f6e03636 is described below

commit 70f6e036363ac5f66e13dbf706c41287bc34ac73
Author: Sean Yang <[email protected]>
AuthorDate: Fri Sep 27 16:14:57 2024 +0800

    Returns a matching http status code based on the rest mappings (#14714)
---
 .../mapping/DefaultRequestMappingRegistry.java     | 56 ++++++++++++++++++++--
 .../protocol/tri/rest/mapping/RequestMapping.java  | 16 +++++--
 .../tri/rest/support/basic/RestProtocolTest.groovy | 22 ++++++++-
 .../rpc/protocol/tri/rest/service/DemoService.java |  4 ++
 .../protocol/tri/rest/service/DemoServiceImpl.java |  5 ++
 5 files changed, 93 insertions(+), 10 deletions(-)

diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java
 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java
index f219b85403..8ec6bf4716 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java
+++ 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java
@@ -22,6 +22,7 @@ import org.apache.dubbo.common.utils.ClassUtils;
 import org.apache.dubbo.config.context.ConfigManager;
 import org.apache.dubbo.config.nested.RestConfig;
 import org.apache.dubbo.remoting.http12.HttpRequest;
+import org.apache.dubbo.remoting.http12.exception.HttpStatusException;
 import org.apache.dubbo.remoting.http12.message.MethodMetadata;
 import org.apache.dubbo.rpc.Invoker;
 import org.apache.dubbo.rpc.model.FrameworkModel;
@@ -45,6 +46,7 @@ import org.apache.dubbo.rpc.protocol.tri.rest.util.PathUtils;
 
 import java.lang.reflect.Method;
 import java.util.ArrayList;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -205,7 +207,8 @@ public final class DefaultRequestMappingRegistry implements 
RequestMappingRegist
         KeyString path = new KeyString(stringPath, 
restConfig.getCaseSensitiveMatchOrDefault());
 
         List<Candidate> candidates = new ArrayList<>();
-        tryMatch(request, path, candidates);
+        List<RequestMapping> partialMatches = new LinkedList<>();
+        tryMatch(request, path, candidates, partialMatches);
 
         if (candidates.isEmpty()) {
             int end = path.length();
@@ -213,7 +216,7 @@ public final class DefaultRequestMappingRegistry implements 
RequestMappingRegist
             if (restConfig.getTrailingSlashMatchOrDefault()) {
                 if (path.charAt(end - 1) == '/') {
                     end--;
-                    tryMatch(request, path.subSequence(0, end), candidates);
+                    tryMatch(request, path.subSequence(0, end), candidates, 
partialMatches);
                 }
             }
 
@@ -225,7 +228,7 @@ public final class DefaultRequestMappingRegistry implements 
RequestMappingRegist
                     }
                     if (ch == '.' && 
restConfig.getSuffixPatternMatchOrDefault()) {
                         if (contentNegotiator.supportExtension(path.toString(i 
+ 1, end))) {
-                            tryMatch(request, path.subSequence(0, i), 
candidates);
+                            tryMatch(request, path.subSequence(0, i), 
candidates, partialMatches);
                             if (!candidates.isEmpty()) {
                                 break;
                             }
@@ -234,7 +237,7 @@ public final class DefaultRequestMappingRegistry implements 
RequestMappingRegist
                     }
                     if (ch == '~') {
                         request.setAttribute(RestConstants.SIG_ATTRIBUTE, 
path.toString(i + 1, end));
-                        tryMatch(request, path.subSequence(0, i), candidates);
+                        tryMatch(request, path.subSequence(0, i), candidates, 
partialMatches);
                         if (!candidates.isEmpty()) {
                             break;
                         }
@@ -245,6 +248,7 @@ public final class DefaultRequestMappingRegistry implements 
RequestMappingRegist
 
         int size = candidates.size();
         if (size == 0) {
+            handleNoMatch(request, partialMatches);
             return null;
         }
         if (size > 1) {
@@ -289,7 +293,8 @@ public final class DefaultRequestMappingRegistry implements 
RequestMappingRegist
         return handler;
     }
 
-    private void tryMatch(HttpRequest request, KeyString path, List<Candidate> 
candidates) {
+    private void tryMatch(
+            HttpRequest request, KeyString path, List<Candidate> candidates, 
List<RequestMapping> partialMatches) {
         List<Match<Registration>> matches = new ArrayList<>();
 
         lock.readLock().lock();
@@ -315,6 +320,47 @@ public final class DefaultRequestMappingRegistry 
implements RequestMappingRegist
                 candidates.add(candidate);
             }
         }
+        if (candidates.isEmpty()) {
+            for (int i = 0; i < size; i++) {
+                partialMatches.add(matches.get(i).getValue().mapping);
+            }
+        }
+    }
+
+    private void handleNoMatch(HttpRequest request, List<RequestMapping> 
partialMatches) {
+        if (partialMatches.isEmpty()) {
+            return;
+        }
+        boolean methodsMismatch = true;
+        boolean consumesMismatch = true;
+        boolean producesMismatch = true;
+        boolean paramsMismatch = true;
+        for (RequestMapping mapping : partialMatches) {
+            if (methodsMismatch) {
+                methodsMismatch = !mapping.matchMethod(request.method());
+            }
+            if (consumesMismatch) {
+                consumesMismatch = !mapping.matchConsumes(request);
+            }
+            if (producesMismatch) {
+                producesMismatch = !mapping.matchProduces(request);
+            }
+            if (paramsMismatch) {
+                paramsMismatch = !mapping.matchParams(request);
+            }
+        }
+        if (methodsMismatch) {
+            throw new HttpStatusException(405, "Request method '" + 
request.method() + "' not supported");
+        }
+        if (consumesMismatch) {
+            throw new HttpStatusException(415, "Content type '" + 
request.contentType() + "' not supported");
+        }
+        if (producesMismatch) {
+            throw new HttpStatusException(406, "Could not find acceptable 
representation");
+        }
+        if (paramsMismatch) {
+            throw new HttpStatusException(400, "Unsatisfied query parameter 
conditions");
+        }
     }
 
     @Override
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMapping.java
 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMapping.java
index 1ea35e0e82..4264594e01 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMapping.java
+++ 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMapping.java
@@ -119,6 +119,18 @@ public final class RequestMapping implements 
Condition<RequestMapping, HttpReque
         return methodsCondition == null || 
methodsCondition.getMethods().contains(method);
     }
 
+    public boolean matchParams(HttpRequest request) {
+        return paramsCondition == null || paramsCondition.match(request) != 
null;
+    }
+
+    public boolean matchConsumes(HttpRequest request) {
+        return consumesCondition == null || consumesCondition.match(request) 
!= null;
+    }
+
+    public boolean matchProduces(HttpRequest request) {
+        return producesCondition == null || producesCondition.match(request) 
!= null;
+    }
+
     @Override
     public RequestMapping match(HttpRequest request) {
         return doMatch(request, null);
@@ -196,10 +208,6 @@ public final class RequestMapping implements 
Condition<RequestMapping, HttpReque
         return name;
     }
 
-    public String getSig() {
-        return sig;
-    }
-
     public PathCondition getPathCondition() {
         return pathCondition;
     }
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/test/groovy/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/RestProtocolTest.groovy
 
b/dubbo-rpc/dubbo-rpc-triple/src/test/groovy/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/RestProtocolTest.groovy
index 4b3547d238..4a2da172b9 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/test/groovy/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/RestProtocolTest.groovy
+++ 
b/dubbo-rpc/dubbo-rpc-triple/src/test/groovy/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/RestProtocolTest.groovy
@@ -241,7 +241,27 @@ class RestProtocolTest extends BaseServiceTest {
             path                      | accept             | output
             '/produceTest?name=world' | ''                 | 'world'
             '/produceTest?name=world' | 'text/plain'       | 'world'
-            '/produceTest?name=world' | 'application/json' | 
'{"message":"Invoker not found","status":"404"}'
+            '/produceTest?name=world' | 'application/json' | 
'{"message":"Could not find acceptable representation","status":"406"}'
+    }
+
+    def "mismatch test"() {
+        given:
+            def request = new TestRequest(
+                method: method,
+                path: path,
+                contentType: contentType,
+                accept: accept
+            )
+        expect:
+            runner.run(request, String.class) == output
+        where:
+            method | path                       | contentType        | accept  
           | output
+            'POST' | '/mismatchTest?name=world' | 'text/plain'       | 
'text/plain'       | 'world'
+            'POST' | '/mismatchTest1'           | 'text/plain'       | 
'text/plain'       | '{"message":"Invoker not found","status":"404"}'
+            'GET'  | '/mismatchTest'            | ''                 | ''      
           | '{"message":"Request method \'GET\' not supported","status":"405"}'
+            'POST' | '/mismatchTest'            | 'application/json' | 
'text/plain'       | '{"message":"Content type \'application/json\' not 
supported","status":"415"}'
+            'POST' | '/mismatchTest'            | 'text/plain'       | 
'application/json' | '{"message":"Could not find acceptable 
representation","status":"406"}'
+            'POST' | '/mismatchTest?name=earth' | 'text/plain'       | 
'text/plain'       | '{"message":"Unsatisfied query parameter 
conditions","status":"400"}'
     }
 
 }
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/service/DemoService.java
 
b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/service/DemoService.java
index 8469f14080..b9597f057a 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/service/DemoService.java
+++ 
b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/service/DemoService.java
@@ -17,6 +17,7 @@
 package org.apache.dubbo.rpc.protocol.tri.rest.service;
 
 import org.apache.dubbo.common.stream.StreamObserver;
+import org.apache.dubbo.remoting.http12.HttpMethods;
 import org.apache.dubbo.remoting.http12.rest.Mapping;
 import org.apache.dubbo.remoting.http12.rest.Param;
 import org.apache.dubbo.rpc.protocol.tri.rest.service.User.Group;
@@ -71,4 +72,7 @@ public interface DemoService {
 
     @Mapping(produces = "text/plain")
     String produceTest(String name);
+
+    @Mapping(method = HttpMethods.POST, consumes = "text/plain", produces = 
"text/plain", params = "name=world")
+    String mismatchTest(String name);
 }
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/service/DemoServiceImpl.java
 
b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/service/DemoServiceImpl.java
index 767cd7e684..b5575fdbae 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/service/DemoServiceImpl.java
+++ 
b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/rest/service/DemoServiceImpl.java
@@ -148,4 +148,9 @@ public class DemoServiceImpl implements DemoService {
     public String produceTest(String name) {
         return name;
     }
+
+    @Override
+    public String mismatchTest(String name) {
+        return name;
+    }
 }

Reply via email to