From 6dd81e6c0f14f4bddefab700c023b18816aaad51 Mon Sep 17 00:00:00 2001 From: Sean Yang Date: Thu, 25 Jul 2024 22:56:02 +0800 Subject: [PATCH] OPTIONS request support --- .../dubbo/remoting/http12/HttpMethods.java | 4 +-- .../dubbo/remoting/http12/rest/Mapping.java | 2 ++ .../tri/rest/mapping/RequestMapping.java | 4 +++ .../mapping/RestRequestHandlerMapping.java | 32 ++++++++++++++++++- .../mapping/condition/MethodsCondition.java | 15 ++++++--- .../basic/BasicRequestMappingResolver.java | 12 +++++-- 6 files changed, 58 insertions(+), 11 deletions(-) diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpMethods.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpMethods.java index 8cdf0e9f735..4792ccd9bdb 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpMethods.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpMethods.java @@ -20,12 +20,12 @@ public enum HttpMethods { GET, + HEAD, POST, PUT, + PATCH, DELETE, - HEAD, OPTIONS, - PATCH, TRACE; public static final byte[][] HTTP_METHODS_BYTES; diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Mapping.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Mapping.java index a05e479306d..0aea2292ed4 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Mapping.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Mapping.java @@ -42,4 +42,6 @@ String[] consumes() default {}; String[] produces() default {}; + + boolean disabled() default false; } 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 5e8171b8984..99abe12fc0c 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 @@ -204,6 +204,10 @@ public PathCondition getPathCondition() { return pathCondition; } + public MethodsCondition getMethodsCondition() { + return methodsCondition; + } + public ProducesCondition getProducesCondition() { return producesCondition; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RestRequestHandlerMapping.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RestRequestHandlerMapping.java index ea7158be124..1fe540af6d0 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RestRequestHandlerMapping.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RestRequestHandlerMapping.java @@ -25,6 +25,9 @@ import org.apache.dubbo.remoting.http12.HttpMethods; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.HttpResult; +import org.apache.dubbo.remoting.http12.HttpStatus; +import org.apache.dubbo.remoting.http12.exception.HttpResultPayloadException; import org.apache.dubbo.remoting.http12.message.MediaType; import org.apache.dubbo.remoting.http12.message.codec.CodecUtils; import org.apache.dubbo.rpc.model.FrameworkModel; @@ -35,11 +38,14 @@ import org.apache.dubbo.rpc.protocol.tri.rest.argument.CompositeArgumentResolver; import org.apache.dubbo.rpc.protocol.tri.rest.argument.GeneralTypeConverter; import org.apache.dubbo.rpc.protocol.tri.rest.argument.TypeConverter; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.MethodsCondition; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.HandlerMeta; import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils; import org.apache.dubbo.rpc.protocol.tri.route.RequestHandler; import org.apache.dubbo.rpc.protocol.tri.route.RequestHandlerMapping; +import java.util.Set; + @Activate(order = -2000) public final class RestRequestHandlerMapping implements RequestHandlerMapping { @@ -71,6 +77,11 @@ public RequestHandler getRequestHandler(URL url, HttpRequest request, HttpRespon return null; } + String method = request.method(); + if (HttpMethods.OPTIONS.name().equals(method)) { + handleOptionsRequest(request); + } + String requestMediaType = request.mediaType(); String responseMediaType = contentNegotiator.negotiate(request); if (responseMediaType != null) { @@ -90,7 +101,7 @@ public RequestHandler getRequestHandler(URL url, HttpRequest request, HttpRespon typeConverter, codecUtils.determineHttpMessageEncoder(url, frameworkModel, responseMediaType)); - if (HttpMethods.supportBody(request.method()) && !RequestUtils.isFormOrMultiPart(request)) { + if (HttpMethods.supportBody(method) && !RequestUtils.isFormOrMultiPart(request)) { if (StringUtils.isEmpty(requestMediaType)) { requestMediaType = responseMediaType; } @@ -111,6 +122,25 @@ public RequestHandler getRequestHandler(URL url, HttpRequest request, HttpRespon return handler; } + private static void handleOptionsRequest(HttpRequest request) { + RequestMapping mapping = request.attribute(RestConstants.MAPPING_ATTRIBUTE); + MethodsCondition condition = mapping.getMethodsCondition(); + if (condition == null) { + throw new HttpResultPayloadException(HttpResult.builder() + .status(HttpStatus.NO_CONTENT) + .header("allow", "GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS") + .build()); + } + Set methods = condition.getMethods(); + if (methods.size() == 1 && methods.contains(HttpMethods.OPTIONS.name())) { + return; + } + throw new HttpResultPayloadException(HttpResult.builder() + .status(HttpStatus.NO_CONTENT) + .header("allow", StringUtils.join(methods, ",")) + .build()); + } + @Override public String getType() { return TripleConstant.TRIPLE_HANDLER_TYPE_REST; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/MethodsCondition.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/MethodsCondition.java index 96b8eec3c49..1790d50f61d 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/MethodsCondition.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/MethodsCondition.java @@ -52,17 +52,22 @@ public MethodsCondition combine(MethodsCondition other) { @Override public MethodsCondition match(HttpRequest request) { String method = request.method(); + + if (OPTIONS.name().equals(method)) { + if (request.hasHeader("origin") && request.hasHeader("access-control-request-method")) { + return new MethodsCondition(OPTIONS.name()); + } else { + return this; + } + } + if (methods.contains(method)) { return new MethodsCondition(method); } + if (HEAD.name().equals(method) && methods.contains(GET.name())) { return new MethodsCondition(GET.name()); } - if (OPTIONS.name().equals(method) - && request.hasHeader("origin") - && request.hasHeader("access-control-request-method")) { - return new MethodsCondition(OPTIONS.name()); - } return null; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicRequestMappingResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicRequestMappingResolver.java index 7e2fc07d595..7c6377f8737 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicRequestMappingResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicRequestMappingResolver.java @@ -18,6 +18,7 @@ import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.remoting.http12.rest.Mapping; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.cors.CorsUtils; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMapping; @@ -51,12 +52,13 @@ public RestToolKit getRestToolKit() { @Override public boolean accept(MethodMeta methodMeta) { - return methodMeta.getMethodDescriptor() != null || methodMeta.findAnnotation(Annotations.Mapping) != null; + AnnotationMeta mapping = methodMeta.findAnnotation(Mapping.class); + return mapping != null ? !mapping.getAnnotation().disabled() : methodMeta.getMethodDescriptor() != null; } @Override public RequestMapping resolve(ServiceMeta serviceMeta) { - AnnotationMeta mapping = serviceMeta.findAnnotation(Annotations.Mapping); + AnnotationMeta mapping = serviceMeta.findAnnotation(Mapping.class); Builder builder = builder(mapping); String[] paths = getPaths(mapping); @@ -74,7 +76,11 @@ public RequestMapping resolve(ServiceMeta serviceMeta) { @Override public RequestMapping resolve(MethodMeta methodMeta) { Method method = methodMeta.getMethod(); - AnnotationMeta mapping = methodMeta.findAnnotation(Annotations.Mapping); + AnnotationMeta mapping = methodMeta.findAnnotation(Mapping.class); + if (mapping != null && mapping.getAnnotation().disabled()) { + return null; + } + Builder builder = builder(mapping); String[] paths = getPaths(mapping);