Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature 3.3] Triple Rest Cors Support #14073

Merged
merged 73 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from 63 commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
96b82c2
feat(): add cors key
Rawven Apr 8, 2024
513789a
feat(): add base cors class
Rawven Apr 8, 2024
6897c8f
feat(): add cors class in rpc-triple and rest-spring
Rawven Apr 8, 2024
a21d7a2
feat(): add cors class in rpc-triple and rest-spring
Rawven Apr 9, 2024
f6594c5
test(): add rpc-triple cors test
Rawven Apr 9, 2024
cf42edb
fix(): fix CorsUtil bug
Rawven Apr 9, 2024
352e974
fix(): fix CorsUtil bug
Rawven Apr 9, 2024
32015a3
fix(): fix objectUtil bug
Rawven Apr 10, 2024
c785a5e
fix(): fix corsmeta set bug
Rawven Apr 10, 2024
194bbc5
fix(): fix config load fail bug
Rawven Apr 10, 2024
995b87b
fix(): option method can not be look fail
Rawven Apr 10, 2024
f45cc0c
fix(): CorsMeta method will null
Rawven Apr 10, 2024
755d39b
fix(): request-header not set will fail
Rawven Apr 10, 2024
7efd588
refactor(): improve CorsMeta CorsProcess some code
Rawven Apr 11, 2024
e743a54
fix(): coreMeta combine priority
Rawven Apr 11, 2024
5445bbe
test(): remove rest-spring cors test to sample
Rawven Apr 11, 2024
d089ad3
docs(): add docs
Rawven Apr 11, 2024
e64fad4
revert(): test version
Rawven Apr 11, 2024
342c64f
fix(): getCorsMeta can be null
Rawven Apr 11, 2024
8137167
fix(): combine can be null
Rawven Apr 11, 2024
791c905
fix(): save option and vary bug
Rawven Apr 11, 2024
81fff53
fix(): pom version
Rawven Apr 11, 2024
8be4988
fix(): spring version will cause allowPrivateWork resolve error
Rawven Apr 11, 2024
a93b3e8
fix(): ci
Rawven Apr 11, 2024
fd60c82
Merge branch '3.3-triple-cors' into 3.3
Rawven Apr 12, 2024
e1fb1e7
Merge pull request #4 from Rawven/3.3
Rawven Apr 12, 2024
fa1020e
refactor(): delete useless code
Rawven Apr 12, 2024
8a4c279
refactor(): accept some sonarcloud issue
Rawven Apr 12, 2024
5b44226
refactor(): add @Nullable to point the CorsMeta Attributes
Rawven Apr 12, 2024
c3c0771
refactor(): style
Rawven Apr 12, 2024
1875011
fix(): fix prelight logic
Rawven Apr 19, 2024
a7912fa
fix(): remove credential & privateNetWork report
Rawven Apr 23, 2024
6f4b817
refactor(): Move globalMetaMerge in RequestMappingResolver
Rawven Apr 23, 2024
3cb3af7
refactor(): use array replace corsConfig string
Rawven Apr 24, 2024
4eb0546
refactor(): move CorsProcessor to CorsHeaderFilterAdapter
Rawven Apr 24, 2024
ff60f3d
fix(): fix unit test
Rawven Apr 24, 2024
1cfab7f
fix(): fix test failure
Rawven Apr 24, 2024
4fcb1cc
fix(): delete useless param
Rawven Apr 24, 2024
639ca84
fix(): fix sonarcloud
Rawven Apr 24, 2024
e1b4a7f
Merge branch '3.3' into 3.3-triple-cors
Rawven Apr 24, 2024
73951bd
fix(): fix wrong class place & naming
Rawven Apr 25, 2024
1326607
fix(): fix wrong static global corsMeta
Rawven Apr 25, 2024
f100803
Merge remote-tracking branch 'origin/3.3-triple-cors' into 3.3-triple…
Rawven May 17, 2024
70f0404
fix(): refactor CorsUtil from sonar issue
Rawven May 17, 2024
854c9bb
feat(rest): refine cors support
oxsean May 18, 2024
5f9bfd7
feat(rest): refine cors support
oxsean May 18, 2024
5b01155
Merge remote-tracking branch 'oxsean/triple-cors' into 3.3-triple-cors
Rawven May 18, 2024
4d84717
feat(rest): refine cors support bugfix
oxsean May 18, 2024
d3b3eaf
fix(): getBoolean will throw exception when null
Rawven May 18, 2024
c8dcb9e
fix(rest-spring): fix crossOrigin allowCredentials is string
Rawven May 18, 2024
87f6423
fix(): fix globalCorsMeta load null
Rawven May 18, 2024
360e9e8
fix(): fix vary header bug
Rawven May 18, 2024
8269417
fix(): update unit test
Rawven May 18, 2024
9be5013
fix(): fix unit test && Fix cors specification
Rawven May 18, 2024
e503110
Merge branch '3.3' into 3.3-triple-cors
Rawven May 18, 2024
e90185f
fix(): fix pom
Rawven May 18, 2024
4385532
fix(): fix combine bug
Rawven May 19, 2024
c0026bd
Merge remote-tracking branch 'origin/3.3-triple-cors' into 3.3-triple…
Rawven May 19, 2024
00aa06a
fix(): fix some sonar issue
Rawven May 19, 2024
c4b501a
fix(): fix style
Rawven May 19, 2024
8bae639
feat(rest): refine cors support
oxsean May 20, 2024
88ebc5a
fix(): fix style
Rawven May 20, 2024
12d1b87
fix(): fix needed sonar issue
Rawven May 20, 2024
c04a61f
refactor(): refactor CorsMeta.combine() and add comment
Rawven May 20, 2024
c61a130
fix(): Replenish license
Rawven May 21, 2024
a9467cc
Merge branch '3.3' into 3.3-triple-cors
Rawven May 21, 2024
6151c67
fix(): update test
Rawven May 21, 2024
e399e92
Merge remote-tracking branch 'origin/3.3-triple-cors' into 3.3-triple…
Rawven May 21, 2024
b7cb8c7
test(): Refactor the test class and add credential test cases
Rawven May 21, 2024
db4503b
test(): Refactor the test class and add credential test cases
Rawven May 21, 2024
1a9d770
Merge branch '3.3' into 3.3-triple-cors
EarthChen May 22, 2024
edf9363
fix(rest): revert api HeaderFilter
oxsean May 22, 2024
852ad86
fix(): accept sonar issue
Rawven May 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions dubbo-common/src/main/java/org/apache/dubbo/config/CorsConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*
* 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.dubbo.config;

import java.io.Serializable;

public class CorsConfig implements Serializable {
private static final long serialVersionUID = 1L;

/**
* A list of origins for which cross-origin requests are allowed. Values may be a specific domain, e.g.
* {@code "https://domain1.com"}, or the CORS defined special value {@code "*"} for all origins.
* <p>By default this is not set which means that no origins are allowed.
* However, an instance of this class is often initialized further, e.g. for {@code @CrossOrigin}, via
* {@code org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.CorsMeta.Builder#applyDefault()}.
*/
private String[] allowedOrigins;

/**
* Set the HTTP methods to allow, e.g. {@code "GET"}, {@code "POST"},
* {@code "PUT"}, etc. The special value {@code "*"} allows all methods.
* <p>If not set, only {@code "GET"} and {@code "HEAD"} are allowed.
* <p>By default this is not set.
*/
private String[] allowedMethods;

/**
* /**
* Set the list of headers that a pre-flight request can list as allowed
* for use during an actual request. The special value {@code "*"} allows
* actual requests to send any header.
* <p>By default this is not set.
*/
private String[] allowedHeaders;

/**
* Set the list of response headers that an actual response might have
* and can be exposed to the client. The special value {@code "*"}
* allows all headers to be exposed.
* <p>By default this is not set.
*/
private String[] exposedHeaders;

/**
* Whether user credentials are supported.
* <p>By default this is not set (i.e. user credentials are not supported).
*/
private Boolean allowCredentials;

/**
* Configure how long, as a duration, the response from a pre-flight request
* can be cached by clients.
*/
private Long maxAge;

public String[] getAllowedOrigins() {
return allowedOrigins;
}

public void setAllowedOrigins(String[] allowedOrigins) {
this.allowedOrigins = allowedOrigins;
}

public String[] getAllowedMethods() {
return allowedMethods;
}

public void setAllowedMethods(String[] allowedMethods) {
this.allowedMethods = allowedMethods;
}

public String[] getAllowedHeaders() {
return allowedHeaders;
}

public void setAllowedHeaders(String[] allowedHeaders) {
this.allowedHeaders = allowedHeaders;
}

public String[] getExposedHeaders() {
return exposedHeaders;
}

public void setExposedHeaders(String[] exposedHeaders) {
this.exposedHeaders = exposedHeaders;
}

public Boolean getAllowCredentials() {
return allowCredentials;
}

public void setAllowCredentials(Boolean allowCredentials) {
this.allowCredentials = allowCredentials;
}

public Long getMaxAge() {
return maxAge;
}

public void setMaxAge(Long maxAge) {
this.maxAge = maxAge;
}
}
16 changes: 16 additions & 0 deletions dubbo-common/src/main/java/org/apache/dubbo/config/RestConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
*/
package org.apache.dubbo.config;

import org.apache.dubbo.config.support.Nested;

import java.io.Serializable;

/**
Expand Down Expand Up @@ -68,6 +70,12 @@ public class RestConfig implements Serializable {
*/
private String formatParameterName;

/**
* The config is used to set the Global CORS configuration properties.
*/
@Nested
private CorsConfig cors;

public Integer getMaxBodySize() {
return maxBodySize;
}
Expand Down Expand Up @@ -115,4 +123,12 @@ public String getFormatParameterName() {
public void setFormatParameterName(String formatParameterName) {
this.formatParameterName = formatParameterName;
}

public CorsConfig getCors() {
return cors;
}

public void setCors(CorsConfig cors) {
this.cors = cors;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,27 @@

import org.apache.dubbo.common.extension.Activate;
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;
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMapping.Builder;
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver;
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.ServiceVersionCondition;
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationSupport;
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.CorsMeta;
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta;
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta;
import org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit;

@Activate(onClass = "javax.ws.rs.Path")
public class JaxrsRequestMappingResolver implements RequestMappingResolver {

private final FrameworkModel frameworkModel;
private final RestToolKit toolKit;
private CorsMeta globalCorsMeta;

public JaxrsRequestMappingResolver(FrameworkModel frameworkModel) {
this.frameworkModel = frameworkModel;
toolKit = new JaxrsRestToolKit(frameworkModel);
}

Expand Down Expand Up @@ -65,10 +70,14 @@ public RequestMapping resolve(MethodMeta methodMeta) {
return null;
}
ServiceMeta serviceMeta = methodMeta.getServiceMeta();
if (globalCorsMeta == null) {
globalCorsMeta = CorsUtils.getGlobalCorsMeta(frameworkModel);
}
return builder(methodMeta, path, httpMethod)
.name(methodMeta.getMethod().getName())
.contextPath(methodMeta.getServiceMeta().getContextPath())
.custom(new ServiceVersionCondition(serviceMeta.getServiceGroup(), serviceMeta.getServiceVersion()))
.cors(globalCorsMeta)
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,17 @@
*/
package org.apache.dubbo.rpc.protocol.tri.rest.support.spring;

import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.common.utils.StringUtils;
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;
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMapping.Builder;
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver;
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.ServiceVersionCondition;
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.CorsMeta;
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta;
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta;
import org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit;
Expand All @@ -35,6 +38,7 @@ public class SpringMvcRequestMappingResolver implements RequestMappingResolver {

private final FrameworkModel frameworkModel;
private volatile RestToolKit toolKit;
private CorsMeta globalCorsMeta;

public SpringMvcRequestMappingResolver(FrameworkModel frameworkModel) {
this.frameworkModel = frameworkModel;
Expand Down Expand Up @@ -62,9 +66,13 @@ public RequestMapping resolve(ServiceMeta serviceMeta) {
return null;
}
AnnotationMeta<?> responseStatus = serviceMeta.findMergedAnnotation(Annotations.ResponseStatus);
AnnotationMeta<?> crossOrigin = serviceMeta.findMergedAnnotation(Annotations.CrossOrigin);
String[] methods = requestMapping.getStringArray("method");
return builder(requestMapping, responseStatus)
.method(methods)
.name(serviceMeta.getType().getSimpleName())
.contextPath(serviceMeta.getContextPath())
.cors(buildCorsMeta(crossOrigin, methods))
.build();
}

Expand All @@ -80,10 +88,14 @@ public RequestMapping resolve(MethodMeta methodMeta) {
}
ServiceMeta serviceMeta = methodMeta.getServiceMeta();
AnnotationMeta<?> responseStatus = methodMeta.findMergedAnnotation(Annotations.ResponseStatus);
AnnotationMeta<?> crossOrigin = methodMeta.findMergedAnnotation(Annotations.CrossOrigin);
String[] methods = requestMapping.getStringArray("method");
return builder(requestMapping, responseStatus)
.method(methods)
.name(methodMeta.getMethod().getName())
.contextPath(serviceMeta.getContextPath())
.custom(new ServiceVersionCondition(serviceMeta.getServiceGroup(), serviceMeta.getServiceVersion()))
.cors(buildCorsMeta(crossOrigin, methods))
.build();
}

Expand All @@ -98,10 +110,34 @@ private Builder builder(AnnotationMeta<?> requestMapping, AnnotationMeta<?> resp
}
}
return builder.path(requestMapping.getValueArray())
.method(requestMapping.getStringArray("method"))
.param(requestMapping.getStringArray("params"))
.header(requestMapping.getStringArray("headers"))
.consume(requestMapping.getStringArray("consumes"))
.produce(requestMapping.getStringArray("produces"));
}

private CorsMeta buildCorsMeta(AnnotationMeta<?> crossOrigin, String[] methods) {
if (globalCorsMeta == null) {
globalCorsMeta = CorsUtils.getGlobalCorsMeta(frameworkModel);
}
if (crossOrigin == null) {
return globalCorsMeta;
}
String[] allowedMethods = crossOrigin.getStringArray("methods");
if (allowedMethods.length == 0) {
allowedMethods = methods;
if (allowedMethods.length == 0) {
allowedMethods = new String[] {CommonConstants.ANY_VALUE};
}
}
CorsMeta corsMeta = CorsMeta.builder()
.allowedOrigins(crossOrigin.getStringArray("origins"))
.allowedMethods(allowedMethods)
.allowedHeaders(crossOrigin.getStringArray("allowedHeaders"))
.exposedHeaders(crossOrigin.getStringArray("exposedHeaders"))
.allowCredentials(crossOrigin.getString("allowCredentials"))
.maxAge(crossOrigin.getNumber("maxAge"))
.build();
return globalCorsMeta.combine(corsMeta);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@
import java.util.Map;

import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.ExceptionHandler;

@CrossOrigin
public class SpringDemoServiceImpl implements SpringRestDemoService {
private static Map<String, Object> context;
private boolean called;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ protected void doOnNext(Object data) throws Throwable {
public final void onError(Throwable throwable) {
if (throwable instanceof HttpResultPayloadException) {
onNext(((HttpResultPayloadException) throwable).getResult());
doOnCompleted(null);
return;
}
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public enum HttpStatus {
OK(200),
CREATED(201),
ACCEPTED(202),
NO_CONTENT(204),
FOUND(302),
BAD_REQUEST(400),
UNAUTHORIZED(401),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@
@SPI(scope = ExtensionScope.FRAMEWORK)
public interface HeaderFilter {

RpcInvocation invoke(Invoker<?> invoker, RpcInvocation invocation) throws RpcException;
void invoke(Invoker<?> invoker, RpcInvocation invocation) throws RpcException;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why change this api?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't notice that this API was introduced in 3.0. indeed shouldn't be modified, I'll revert it later. However, this return value not being used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revert have done

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
@Activate
public class TokenHeaderFilter implements HeaderFilter {
@Override
public RpcInvocation invoke(Invoker<?> invoker, RpcInvocation invocation) throws RpcException {
public void invoke(Invoker<?> invoker, RpcInvocation invocation) throws RpcException {
String token = invoker.getUrl().getParameter(TOKEN_KEY);
if (ConfigUtils.isNotEmpty(token)) {
Class<?> serviceType = invoker.getInterface();
Expand All @@ -46,6 +46,5 @@ public RpcInvocation invoke(Invoker<?> invoker, RpcInvocation invocation) throws
+ ", consumer incorrect token is " + remoteToken);
}
}
return invocation;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,10 @@ protected void onDataCompletion(MESSAGE message) {
protected void logError(Throwable t) {
if (t instanceof HttpStatusException) {
HttpStatusException e = (HttpStatusException) t;
if (e.getStatusCode() == HttpStatus.INTERNAL_SERVER_ERROR.getCode()) {
if (e.getStatusCode() >= HttpStatus.BAD_REQUEST.getCode()) {
LOGGER.debug("http status exception", e);
return;
}
return;
}
LOGGER.error(INTERNAL_ERROR, "", "", "server internal error", t);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,14 @@ public final class RestConstants {
public static final String CASE_SENSITIVE_MATCH_KEY = CONFIG_PREFIX + "case-sensitive-match";
public static final String FORMAT_PARAMETER_NAME_KEY = CONFIG_PREFIX + "format-parameter-name";

/* Cors Configuration Key */
public static final String CORS_CONFIG_PREFIX = CONFIG_PREFIX + "cors.";
public static final String ALLOWED_ORIGINS = CORS_CONFIG_PREFIX + "allowed-origins";
public static final String ALLOWED_METHODS = CORS_CONFIG_PREFIX + "allowed-methods";
public static final String ALLOWED_HEADERS = CORS_CONFIG_PREFIX + "allowed-headers";
public static final String ALLOW_CREDENTIALS = CORS_CONFIG_PREFIX + "allow-credentials";
public static final String EXPOSED_HEADERS = CORS_CONFIG_PREFIX + "exposed-headers";
public static final String MAX_AGE = CORS_CONFIG_PREFIX + "max-age";

private RestConstants() {}
}
Loading
Loading