[ https://issues.apache.org/jira/browse/SCB-679?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16520220#comment-16520220 ]
ASF GitHub Bot commented on SCB-679: ------------------------------------ liubao68 closed pull request #771: [SCB-679] Support Cross-Origin Resource Sharing (CORS) URL: https://github.com/apache/incubator-servicecomb-java-chassis/pull/771 This is a PR merged from a forked repository. As GitHub hides the original diff on merge, it is displayed below for the sake of provenance: As this is a foreign pull request (from a fork), the diff is supplied below (as it won't show otherwise due to GitHub magic): diff --git a/core/src/main/resources/META-INF/spring/cse.bean.xml b/core/src/main/resources/META-INF/spring/cse.bean.xml index 44817fbbd9..f0c39aa808 100644 --- a/core/src/main/resources/META-INF/spring/cse.bean.xml +++ b/core/src/main/resources/META-INF/spring/cse.bean.xml @@ -29,12 +29,14 @@ <property name="configId" value="config"/> </bean> - <bean class="org.apache.servicecomb.core.CseContext" factory-method="getInstance"></bean> + <bean class="org.apache.servicecomb.core.CseContext" factory-method="getInstance"/> <bean class="org.apache.servicecomb.core.CseApplicationListener"> </bean> - <bean id="cse.executor.groupThreadPool" class="org.apache.servicecomb.core.executor.FixedThreadExecutor"></bean> + <bean id="cse.executor.groupThreadPool" class="org.apache.servicecomb.core.executor.FixedThreadExecutor"/> <alias name="cse.executor.groupThreadPool" alias="cse.executor.default"/> - <bean id="cse.executor.reactive" class="org.apache.servicecomb.core.executor.ReactiveExecutor"></bean> + <alias name="cse.executor.groupThreadPool" alias="servicecomb.executor.groupThreadPool"/> + <bean id="cse.executor.reactive" class="org.apache.servicecomb.core.executor.ReactiveExecutor"/> + <alias name="cse.executor.reactive" alias="servicecomb.executor.reactive"/> </beans> diff --git a/demo/demo-crossapp/crossapp-client/src/main/java/org/apache/servicecomb/demo/crossapp/CrossappClient.java b/demo/demo-crossapp/crossapp-client/src/main/java/org/apache/servicecomb/demo/crossapp/CrossappClient.java index cc4162b38e..9388953228 100644 --- a/demo/demo-crossapp/crossapp-client/src/main/java/org/apache/servicecomb/demo/crossapp/CrossappClient.java +++ b/demo/demo-crossapp/crossapp-client/src/main/java/org/apache/servicecomb/demo/crossapp/CrossappClient.java @@ -17,13 +17,21 @@ package org.apache.servicecomb.demo.crossapp; +import java.util.Collections; +import java.util.TreeSet; + import org.apache.servicecomb.core.provider.consumer.InvokerUtils; import org.apache.servicecomb.demo.TestMgr; import org.apache.servicecomb.foundation.common.utils.BeanUtils; import org.apache.servicecomb.foundation.common.utils.Log4jUtils; import org.apache.servicecomb.provider.pojo.RpcReference; import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestTemplate; @Component @@ -32,12 +40,14 @@ private static HelloWorld helloWorld; public static void main(String[] args) throws Exception { + System.setProperty("sun.net.http.allowRestrictedHeaders", "true"); Log4jUtils.init(); BeanUtils.init(); run(); TestMgr.summary(); + System.setProperty("sun.net.http.allowRestrictedHeaders", "false"); } public static void run() { @@ -50,5 +60,26 @@ public static void run() { result = helloWorld.sayHello(); TestMgr.check("hello world", result); + + testCorsHandler(); + } + + private static void testCorsHandler() { + RestTemplate springRestTemplate = new RestTemplate(); + MultiValueMap<String, String> requestHeaders = new LinkedMultiValueMap<>(); + requestHeaders.put("Origin", Collections.singletonList("http://localhost:8080")); + requestHeaders.put("Access-Control-Request-Method", Collections.singletonList("PUT")); + + HttpEntity<Object> requestEntity = new HttpEntity<>(requestHeaders); + ResponseEntity<String> responseEntity = springRestTemplate + .exchange("http://127.0.0.1:8080/helloworld/hello", HttpMethod.OPTIONS, requestEntity, + String.class); + + TestMgr.check("204", responseEntity.getStatusCodeValue()); + TreeSet<String> sortedSet = new TreeSet<>(responseEntity.getHeaders().get("Access-Control-Allow-Methods")); + TestMgr.check("[DELETE,POST,GET,PUT]", sortedSet); + sortedSet = new TreeSet<>(responseEntity.getHeaders().get("Access-Control-Allow-Headers")); + TestMgr.check("[abc,def]", sortedSet); + TestMgr.check("*", responseEntity.getHeaders().getFirst("Access-Control-Allow-Origin")); } } diff --git a/demo/demo-crossapp/crossapp-server/src/main/resources/microservice.yaml b/demo/demo-crossapp/crossapp-server/src/main/resources/microservice.yaml index f58cba5e02..bd0158a17e 100644 --- a/demo/demo-crossapp/crossapp-server/src/main/resources/microservice.yaml +++ b/demo/demo-crossapp/crossapp-server/src/main/resources/microservice.yaml @@ -31,3 +31,10 @@ servicecomb: address: http://127.0.0.1:30100 rest: address: 127.0.0.1:8080 + cors: + enabled: true + origin: "*" + allowedHeader: abc,def + allowedMethod: GET,PUT,POST,DELETE + exposedHeader: abc,def + maxAge: 1 diff --git a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/MicroserviceRegisterTask.java b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/MicroserviceRegisterTask.java index 9e7be8ae72..3636682864 100644 --- a/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/MicroserviceRegisterTask.java +++ b/service-registry/src/main/java/org/apache/servicecomb/serviceregistry/task/MicroserviceRegisterTask.java @@ -307,7 +307,10 @@ private void checkRemainingSchema(Map<String, GetSchemaResponse> scSchemaMap) { // Currently nothing to do but print a warning LOGGER.warn("There are schemas only existing in service center: {}, which means there are interfaces changed. " - + "It's recommended to increment microservice version before deploying.", scSchemaMap.keySet()); + + "It's recommended to increment microservice version before deploying.", + scSchemaMap.keySet()); + LOGGER.warn("ATTENTION: The schemas in new version are less than the old version, " + + "which may cause compatibility problems."); } } diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/RestServerVerticle.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/RestServerVerticle.java index f2ac2fb156..3780347e86 100644 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/RestServerVerticle.java +++ b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/RestServerVerticle.java @@ -18,6 +18,7 @@ package org.apache.servicecomb.transport.rest.vertx; import java.util.List; +import java.util.Set; import org.apache.servicecomb.core.Endpoint; import org.apache.servicecomb.core.transport.AbstractTransport; @@ -36,9 +37,11 @@ import io.vertx.core.Context; import io.vertx.core.Future; import io.vertx.core.Vertx; +import io.vertx.core.http.HttpMethod; import io.vertx.core.http.HttpServer; import io.vertx.core.http.HttpServerOptions; import io.vertx.ext.web.Router; +import io.vertx.ext.web.handler.CorsHandler; public class RestServerVerticle extends AbstractVerticle { private static final Logger LOGGER = LoggerFactory.getLogger(RestServerVerticle.class); @@ -68,6 +71,7 @@ public void start(Future<Void> startFuture) throws Exception { } Router mainRouter = Router.router(vertx); mountAccessLogHandler(mainRouter); + mountCorsHandler(mainRouter); initDispatcher(mainRouter); HttpServer httpServer = createHttpServer(); httpServer.requestHandler(mainRouter::accept); @@ -90,6 +94,40 @@ private void mountAccessLogHandler(Router mainRouter) { } } + /** + * Support CORS + */ + void mountCorsHandler(Router mainRouter) { + if (!TransportConfig.isCorsEnabled()) { + return; + } + + CorsHandler corsHandler = getCorsHandler(TransportConfig.getCorsAllowedOrigin()); + // Access-Control-Allow-Credentials + corsHandler.allowCredentials(TransportConfig.isCorsAllowCredentials()); + // Access-Control-Allow-Headers + corsHandler.allowedHeaders(TransportConfig.getCorsAllowedHeaders()); + // Access-Control-Allow-Methods + Set<String> allowedMethods = TransportConfig.getCorsAllowedMethods(); + for (String method : allowedMethods) { + corsHandler.allowedMethod(HttpMethod.valueOf(method)); + } + // Access-Control-Expose-Headers + corsHandler.exposedHeaders(TransportConfig.getCorsExposedHeaders()); + // Access-Control-Max-Age + int maxAge = TransportConfig.getCorsMaxAge(); + if (maxAge >= 0) { + corsHandler.maxAgeSeconds(maxAge); + } + + LOGGER.info("mount CorsHandler"); + mainRouter.route().handler(corsHandler); + } + + private CorsHandler getCorsHandler(String corsAllowedOrigin) { + return CorsHandler.create(corsAllowedOrigin); + } + private void initDispatcher(Router mainRouter) { List<VertxHttpDispatcher> dispatchers = SPIServiceUtils.getSortedService(VertxHttpDispatcher.class); for (VertxHttpDispatcher dispatcher : dispatchers) { diff --git a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/TransportConfig.java b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/TransportConfig.java index 01f13c8d5a..ae08b0c01d 100644 --- a/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/TransportConfig.java +++ b/transports/transport-rest/transport-rest-vertx/src/main/java/org/apache/servicecomb/transport/rest/vertx/TransportConfig.java @@ -17,6 +17,12 @@ package org.apache.servicecomb.transport.rest.vertx; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Stream; + +import org.springframework.util.StringUtils; + import com.netflix.config.DynamicIntProperty; import com.netflix.config.DynamicPropertyFactory; import com.netflix.config.DynamicStringProperty; @@ -34,6 +40,8 @@ // 32K public static final int DEFAULT_SERVER_MAX_HEADER_SIZE = 32 * 1024; + public static final String SERVICECOMB_CORS_CONFIG_BASE = "servicecomb.cors"; + private static Class<? extends Verticle> restServerVerticle = RestServerVerticle.class; private TransportConfig() { @@ -78,4 +86,59 @@ public static int getMaxHeaderSize() { .getIntProperty("cse.rest.server.maxHeaderSize", DEFAULT_SERVER_MAX_HEADER_SIZE) .get(); } + + public static boolean isCorsEnabled() { + return DynamicPropertyFactory.getInstance() + .getBooleanProperty(SERVICECOMB_CORS_CONFIG_BASE + ".enabled", false) + .get(); + } + + public static String getCorsAllowedOrigin() { + return DynamicPropertyFactory.getInstance() + .getStringProperty(SERVICECOMB_CORS_CONFIG_BASE + ".origin", "*") + .get(); + } + + public static boolean isCorsAllowCredentials() { + return DynamicPropertyFactory.getInstance() + .getBooleanProperty(SERVICECOMB_CORS_CONFIG_BASE + ".allowCredentials", false) + .get(); + } + + public static Set<String> getCorsAllowedHeaders() { + String allowedHeaders = DynamicPropertyFactory.getInstance() + .getStringProperty(SERVICECOMB_CORS_CONFIG_BASE + ".allowedHeader", null) + .get(); + return convertToSet(allowedHeaders); + } + + public static Set<String> getCorsAllowedMethods() { + String allowedMethods = DynamicPropertyFactory.getInstance() + .getStringProperty(SERVICECOMB_CORS_CONFIG_BASE + ".allowedMethod", null) + .get(); + return convertToSet(allowedMethods); + } + + public static Set<String> getCorsExposedHeaders() { + String exposedHeaders = DynamicPropertyFactory.getInstance() + .getStringProperty(SERVICECOMB_CORS_CONFIG_BASE + ".exposedHeader", null) + .get(); + return convertToSet(exposedHeaders); + } + + public static int getCorsMaxAge() { + return DynamicPropertyFactory.getInstance() + .getIntProperty(SERVICECOMB_CORS_CONFIG_BASE + ".maxAge", -1) + .get(); + } + + private static Set<String> convertToSet(String setString) { + Set<String> resultSet = new HashSet<>(); + if (!StringUtils.isEmpty(setString)) { + String[] arrString = setString.split(","); + Stream.of(arrString).map(String::trim).filter(str -> !StringUtils.isEmpty(str)) + .forEach(resultSet::add); + } + return resultSet; + } } diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/TestRestServerVerticle.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/TestRestServerVerticle.java index 146c5616e0..4b65435644 100644 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/TestRestServerVerticle.java +++ b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/TestRestServerVerticle.java @@ -17,22 +17,36 @@ package org.apache.servicecomb.transport.rest.vertx; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; + import org.apache.servicecomb.core.CseContext; import org.apache.servicecomb.core.Endpoint; import org.apache.servicecomb.core.Transport; import org.apache.servicecomb.core.transport.AbstractTransport; import org.apache.servicecomb.core.transport.TransportManager; import org.apache.servicecomb.foundation.common.net.URIEndpointObject; +import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; +import org.hamcrest.Matchers; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.mockito.Mockito; import io.vertx.core.Context; import io.vertx.core.Future; import io.vertx.core.Vertx; +import io.vertx.core.http.HttpMethod; import io.vertx.core.json.JsonObject; +import io.vertx.ext.web.Route; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.handler.CorsHandler; +import mockit.Deencapsulation; import mockit.Expectations; +import mockit.Mock; +import mockit.MockUp; import mockit.Mocked; public class TestRestServerVerticle { @@ -42,7 +56,7 @@ Future<Void> startFuture = null; @Before - public void setUp() throws Exception { + public void setUp() { instance = new RestServerVerticle(); startFuture = Future.future(); @@ -50,7 +64,7 @@ public void setUp() throws Exception { } @After - public void tearDown() throws Exception { + public void tearDown() { instance = null; startFuture = null; } @@ -112,7 +126,7 @@ public void testRestServerVerticleWithRouterSSL(@Mocked Transport transport, @Mo @Test public void testRestServerVerticleWithHttp2(@Mocked Transport transport, @Mocked Vertx vertx, @Mocked Context context, - @Mocked JsonObject jsonObject, @Mocked Future<Void> startFuture) throws Exception { + @Mocked JsonObject jsonObject, @Mocked Future<Void> startFuture) { URIEndpointObject endpointObject = new URIEndpointObject("http://127.0.0.1:8080?protocol=http2"); new Expectations() { { @@ -164,4 +178,71 @@ public void testStartFutureAddressNotEmpty() { } Assert.assertFalse(status); } + + @Test + public void testMountCorsHandler() { + ArchaiusUtils.setProperty("servicecomb.cors.enabled", true); + ArchaiusUtils.setProperty("servicecomb.cors.allowedMethod", "GET,PUT,POST"); + ArchaiusUtils.setProperty("servicecomb.cors.allowedHeader", "abc,def"); + ArchaiusUtils.setProperty("servicecomb.cors.exposedHeader", "abc2,def2"); + ArchaiusUtils.setProperty("servicecomb.cors.maxAge", 1); + Set<HttpMethod> methodSet = new HashSet<>(3); + methodSet.add(HttpMethod.GET); + methodSet.add(HttpMethod.PUT); + methodSet.add(HttpMethod.POST); + AtomicInteger counter = new AtomicInteger(0); + + CorsHandler corsHandler = new MockUp<CorsHandler>() { + @Mock + CorsHandler allowCredentials(boolean allow) { + Assert.assertFalse(allow); + counter.incrementAndGet(); + return null; + } + + @Mock + CorsHandler allowedHeaders(Set<String> headerNames) { + Assert.assertThat(headerNames, Matchers.containsInAnyOrder("abc", "def")); + counter.incrementAndGet(); + return null; + } + + @Mock + CorsHandler exposedHeaders(Set<String> headerNames) { + Assert.assertThat(headerNames, Matchers.containsInAnyOrder("abc2", "def2")); + counter.incrementAndGet(); + return null; + } + + @Mock + CorsHandler allowedMethod(HttpMethod method) { + Assert.assertTrue(methodSet.contains(method)); + counter.incrementAndGet(); + methodSet.remove(method); + return null; + } + + @Mock + CorsHandler maxAgeSeconds(int maxAgeSeconds) { + Assert.assertEquals(1, maxAgeSeconds); + counter.incrementAndGet(); + return null; + } + }.getMockInstance(); + + new MockUp<RestServerVerticle>() { + @Mock + CorsHandler getCorsHandler(String corsAllowedOrigin) { + Assert.assertEquals("*", corsAllowedOrigin); + return corsHandler; + } + }; + Router router = Mockito.mock(Router.class); + Mockito.when(router.route()).thenReturn(Mockito.mock(Route.class)); + + RestServerVerticle server = new RestServerVerticle(); + + Deencapsulation.invoke(server, "mountCorsHandler", router); + Assert.assertEquals(7, counter.get()); + } } diff --git a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/TestTransportConfig.java b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/TestTransportConfig.java index e63dcd5b8d..a3e84f85c1 100644 --- a/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/TestTransportConfig.java +++ b/transports/transport-rest/transport-rest-vertx/src/test/java/org/apache/servicecomb/transport/rest/vertx/TestTransportConfig.java @@ -17,26 +17,22 @@ package org.apache.servicecomb.transport.rest.vertx; -import org.apache.commons.configuration.Configuration; import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.junit.AfterClass; +import org.hamcrest.Matchers; +import org.junit.After; import org.junit.Assert; -import org.junit.BeforeClass; +import org.junit.Before; import org.junit.Test; -import com.netflix.config.DynamicPropertyFactory; - public class TestTransportConfig { - Configuration config = (Configuration) DynamicPropertyFactory.getBackingConfigurationSource(); - @BeforeClass - public static void setup() { + @Before + public void before() { ArchaiusUtils.resetConfig(); } - - @AfterClass - public static void teardown() { + @After + public void after() { ArchaiusUtils.resetConfig(); } @@ -47,9 +43,8 @@ public void testGetAddressNull() { @Test public void testGetAddressNormal() { - config.addProperty("cse.rest.address", "1.1.1.1"); + ArchaiusUtils.setProperty("cse.rest.address", "1.1.1.1"); Assert.assertEquals("1.1.1.1", TransportConfig.getAddress()); - config.clearProperty("cse.rest.address"); } @Test @@ -59,18 +54,90 @@ public void testGetThreadCountNull() { @Test public void testGetThreadCountNormal() { - config.addProperty("cse.rest.server.thread-count", 10); + ArchaiusUtils.setProperty("cse.rest.server.thread-count", 10); Assert.assertEquals(10, TransportConfig.getThreadCount()); - config.clearProperty("cse.rest.server.thread-count"); } @Test public void testGetCompressedAndHeaderSize() { - config.addProperty("cse.rest.server.compression", true); + ArchaiusUtils.setProperty("cse.rest.server.compression", true); Assert.assertEquals(true, TransportConfig.getCompressed()); - config.addProperty("cse.rest.server.maxHeaderSize", 2048); + ArchaiusUtils.setProperty("cse.rest.server.maxHeaderSize", 2048); Assert.assertEquals(2048, TransportConfig.getMaxHeaderSize()); - config.clearProperty("cse.rest.server.compression"); - config.clearProperty("cse.rest.server.maxHeaderSize"); + } + + @Test + public void testIsCorsEnabled() { + Assert.assertFalse(TransportConfig.isCorsEnabled()); + ArchaiusUtils.setProperty("servicecomb.cors.enabled", true); + Assert.assertTrue(TransportConfig.isCorsEnabled()); + ArchaiusUtils.setProperty("servicecomb.cors.enabled", false); + Assert.assertFalse(TransportConfig.isCorsEnabled()); + } + + @Test + public void testGetCorsAllowedOrigin() { + Assert.assertEquals("*", TransportConfig.getCorsAllowedOrigin()); + String origin = "http://localhost:8080"; + ArchaiusUtils.setProperty("servicecomb.cors.origin", origin); + Assert.assertEquals(origin, TransportConfig.getCorsAllowedOrigin()); + } + + @Test + public void testIsCorsAllowCredentials() { + Assert.assertFalse(TransportConfig.isCorsAllowCredentials()); + ArchaiusUtils.setProperty("servicecomb.cors.allowCredentials", true); + Assert.assertTrue(TransportConfig.isCorsAllowCredentials()); + ArchaiusUtils.setProperty("servicecomb.cors.allowCredentials", false); + Assert.assertFalse(TransportConfig.isCorsAllowCredentials()); + } + + @Test + public void testGetCorsAllowedHeaders() { + String configKey = "servicecomb.cors.allowedHeader"; + Assert.assertTrue(TransportConfig.getCorsAllowedHeaders().isEmpty()); + ArchaiusUtils.setProperty(configKey, "abc"); + Assert.assertThat(TransportConfig.getCorsAllowedHeaders(), Matchers.containsInAnyOrder("abc")); + ArchaiusUtils.setProperty(configKey, "abc, def"); + Assert.assertThat(TransportConfig.getCorsAllowedHeaders(), Matchers.containsInAnyOrder("abc", "def")); + ArchaiusUtils.setProperty(configKey, "abc ,, def"); + Assert.assertThat(TransportConfig.getCorsAllowedHeaders(), Matchers.containsInAnyOrder("abc", "def")); + ArchaiusUtils.setProperty(configKey, ""); + Assert.assertTrue(TransportConfig.getCorsAllowedHeaders().isEmpty()); + } + + @Test + public void testGetCorsAllowedMethods() { + String configKey = "servicecomb.cors.allowedMethod"; + Assert.assertTrue(TransportConfig.getCorsAllowedMethods().isEmpty()); + ArchaiusUtils.setProperty(configKey, "GET"); + Assert.assertThat(TransportConfig.getCorsAllowedMethods(), Matchers.containsInAnyOrder("GET")); + ArchaiusUtils.setProperty(configKey, "GET, POST"); + Assert.assertThat(TransportConfig.getCorsAllowedMethods(), Matchers.containsInAnyOrder("GET", "POST")); + ArchaiusUtils.setProperty(configKey, "GET,,POST"); + Assert.assertThat(TransportConfig.getCorsAllowedMethods(), Matchers.containsInAnyOrder("GET", "POST")); + ArchaiusUtils.setProperty(configKey, ""); + Assert.assertTrue(TransportConfig.getCorsAllowedMethods().isEmpty()); + } + + @Test + public void testGetCorsExposedHeaders() { + String configKey = "servicecomb.cors.exposedHeader"; + Assert.assertTrue(TransportConfig.getCorsExposedHeaders().isEmpty()); + ArchaiusUtils.setProperty(configKey, "abc"); + Assert.assertThat(TransportConfig.getCorsExposedHeaders(), Matchers.containsInAnyOrder("abc")); + ArchaiusUtils.setProperty(configKey, "abc, def"); + Assert.assertThat(TransportConfig.getCorsExposedHeaders(), Matchers.containsInAnyOrder("abc", "def")); + ArchaiusUtils.setProperty(configKey, "abc ,, def"); + Assert.assertThat(TransportConfig.getCorsExposedHeaders(), Matchers.containsInAnyOrder("abc", "def")); + ArchaiusUtils.setProperty(configKey, ""); + Assert.assertTrue(TransportConfig.getCorsExposedHeaders().isEmpty()); + } + + @Test + public void testGetCorsMaxAge() { + Assert.assertEquals(-1, TransportConfig.getCorsMaxAge()); + ArchaiusUtils.setProperty("servicecomb.cors.maxAge", 3600); + Assert.assertEquals(3600, TransportConfig.getCorsMaxAge()); } } ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org > Support Cross-Origin Resource Sharing (CORS) > -------------------------------------------- > > Key: SCB-679 > URL: https://issues.apache.org/jira/browse/SCB-679 > Project: Apache ServiceComb > Issue Type: New Feature > Components: Java-Chassis > Affects Versions: Java-chassis-1.0.0 > Reporter: YaoHaishi > Assignee: YaoHaishi > Priority: Major > > Provide configurations to let user mount and config Vert.x CorsHandler. -- This message was sent by Atlassian JIRA (v7.6.3#76005)