From 7f2e3b9cf5a592cfe0be3747db0afd39ad9a89e8 Mon Sep 17 00:00:00 2001 From: Haotian Zhang <928016560@qq.com> Date: Fri, 13 Oct 2023 13:35:43 +0800 Subject: [PATCH] fix:fix header validation when using Chinese char. (#1168) --- CHANGELOG.md | 1 + ...odeTransferMedataFeignInterceptorTest.java | 4 ++-- .../listener/ConfigChangeListenerTest.java | 2 +- ...hOptimizationListenerNotTriggeredTest.java | 2 +- ...reshOptimizationListenerTriggeredTest.java | 2 +- .../filter/QuotaCheckReactiveFilter.java | 22 ++++++++++++++----- .../filter/QuotaCheckServletFilter.java | 15 +++++++++++-- .../SCGPluginsAutoConfigurationTest.java | 2 +- .../plugin/PolarisEnhancedPluginUtils.java | 11 +++++++++- .../PolarisEnhancedPluginUtilsTest.java | 8 +++++-- 10 files changed, 52 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1cc8857c..2aa436abd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,3 +11,4 @@ - [feat:add swagger report switch.](https://github.com/Tencent/spring-cloud-tencent/pull/1149) - [fix: dynamic routing using cookies.](https://github.com/Tencent/spring-cloud-tencent/pull/1151) - [fix:fix retry loadbalancer not working bug.](https://github.com/Tencent/spring-cloud-tencent/pull/1156) +- [fix:fix header validation when using Chinese char.](https://github.com/Tencent/spring-cloud-tencent/pull/1168) diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptorTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptorTest.java index 46e8a0e4f..93e553787 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptorTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptorTest.java @@ -47,7 +47,7 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = DEFINED_PORT, classes = EncodeTransferMedataFeignInterceptorTest.TestApplication.class, - properties = {"server.port=8081", "spring.config.location = classpath:application-test.yml"}) + properties = {"server.port=48081", "spring.config.location = classpath:application-test.yml"}) public class EncodeTransferMedataFeignInterceptorTest { @Autowired @@ -74,7 +74,7 @@ public class EncodeTransferMedataFeignInterceptorTest { return MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "b"); } - @FeignClient(name = "test-feign", url = "http://localhost:8081") + @FeignClient(name = "test-feign", url = "http://localhost:48081") public interface TestFeign { @RequestMapping("/test") diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/ConfigChangeListenerTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/ConfigChangeListenerTest.java index 7a0bd5b60..465af4353 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/ConfigChangeListenerTest.java +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/ConfigChangeListenerTest.java @@ -47,7 +47,7 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen */ @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = DEFINED_PORT, classes = ConfigChangeListenerTest.TestApplication.class, - properties = {"server.port=8081", "spring.config.location = classpath:application-test.yml"}) + properties = {"server.port=48081", "spring.config.location = classpath:application-test.yml"}) public class ConfigChangeListenerTest { private static final CountDownLatch hits = new CountDownLatch(2); diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListenerNotTriggeredTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListenerNotTriggeredTest.java index 2a0444a01..eef16a89f 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListenerNotTriggeredTest.java +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListenerNotTriggeredTest.java @@ -58,7 +58,7 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = DEFINED_PORT, classes = PolarisConfigRefreshOptimizationListenerNotTriggeredTest.TestApplication.class, properties = { - "server.port=8081", + "server.port=48081", "spring.cloud.polaris.address=grpc://127.0.0.1:10081", "spring.cloud.polaris.config.connect-remote-server=false", "spring.cloud.polaris.config.refresh-type=reflect", diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListenerTriggeredTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListenerTriggeredTest.java index e62937326..24aa7ae08 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListenerTriggeredTest.java +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListenerTriggeredTest.java @@ -59,7 +59,7 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = DEFINED_PORT, classes = PolarisConfigRefreshOptimizationListenerTriggeredTest.TestApplication.class, properties = { - "server.port=8081", + "server.port=48081", "spring.cloud.polaris.address=grpc://127.0.0.1:10081", "spring.cloud.polaris.config.connect-remote-server=false", "spring.cloud.polaris.config.refresh-type=reflect", diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilter.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilter.java index 27b4c503e..f7ce8d21b 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilter.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilter.java @@ -18,6 +18,8 @@ package com.tencent.cloud.polaris.ratelimit.filter; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.Objects; @@ -51,6 +53,8 @@ import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; +import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; + /** * Reactive filter to check quota. * @@ -58,7 +62,7 @@ import org.springframework.web.server.WebFilterChain; */ public class QuotaCheckReactiveFilter implements WebFilter, Ordered { - private static final Logger LOGGER = LoggerFactory.getLogger(QuotaCheckReactiveFilter.class); + private static final Logger LOG = LoggerFactory.getLogger(QuotaCheckReactiveFilter.class); private final LimitAPI limitAPI; @@ -122,22 +126,28 @@ public class QuotaCheckReactiveFilter implements WebFilter, Ordered { response.getHeaders() .add(HeaderConstant.INTERNAL_CALLEE_RET_STATUS, RetStatus.RetFlowControl.getDesc()); if (Objects.nonNull(quotaResponse.getActiveRule())) { - response.getHeaders() - .add(HeaderConstant.INTERNAL_ACTIVE_RULE_NAME, quotaResponse.getActiveRule().getName() - .getValue()); + try { + String encodedActiveRuleName = URLEncoder.encode( + quotaResponse.getActiveRule().getName().getValue(), UTF_8); + response.getHeaders().add(HeaderConstant.INTERNAL_ACTIVE_RULE_NAME, encodedActiveRuleName); + } + catch (UnsupportedEncodingException e) { + LOG.error("Cannot encode {} for header internal-callee-activerule.", + quotaResponse.getActiveRule().getName().getValue(), e); + } } return response.writeWith(Mono.just(dataBuffer)); } // Unirate if (quotaResponse.getCode() == QuotaResultCode.QuotaResultOk && quotaResponse.getWaitMs() > 0) { - LOGGER.debug("The request of [{}] will waiting for {}ms.", path, quotaResponse.getWaitMs()); + LOG.debug("The request of [{}] will waiting for {}ms.", path, quotaResponse.getWaitMs()); waitMs = quotaResponse.getWaitMs(); } } catch (Throwable t) { // An exception occurs in the rate limiting API call, // which should not affect the call of the business process. - LOGGER.error("fail to invoke getQuota, service is " + localService, t); + LOG.error("fail to invoke getQuota, service is " + localService, t); } if (waitMs > 0) { diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilter.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilter.java index bd8303e66..2f4a56eac 100644 --- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilter.java +++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckServletFilter.java @@ -19,6 +19,8 @@ package com.tencent.cloud.polaris.ratelimit.filter; import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; import java.util.Objects; import java.util.Set; @@ -50,6 +52,8 @@ import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; import org.springframework.web.filter.OncePerRequestFilter; +import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; + /** * Servlet filter to check quota. * @@ -115,8 +119,15 @@ public class QuotaCheckServletFilter extends OncePerRequestFilter { } response.addHeader(HeaderConstant.INTERNAL_CALLEE_RET_STATUS, RetStatus.RetFlowControl.getDesc()); if (Objects.nonNull(quotaResponse.getActiveRule())) { - response.addHeader(HeaderConstant.INTERNAL_ACTIVE_RULE_NAME, quotaResponse.getActiveRule().getName() - .getValue()); + try { + String encodedActiveRuleName = URLEncoder.encode( + quotaResponse.getActiveRule().getName().getValue(), UTF_8); + response.addHeader(HeaderConstant.INTERNAL_ACTIVE_RULE_NAME, encodedActiveRuleName); + } + catch (UnsupportedEncodingException e) { + LOG.error("Cannot encode {} for header internal-callee-activerule.", + quotaResponse.getActiveRule().getName().getValue(), e); + } } return; } diff --git a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/test/java/com/tencent/cloud/plugin/gateway/SCGPluginsAutoConfigurationTest.java b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/test/java/com/tencent/cloud/plugin/gateway/SCGPluginsAutoConfigurationTest.java index 125867a18..38942e366 100644 --- a/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/test/java/com/tencent/cloud/plugin/gateway/SCGPluginsAutoConfigurationTest.java +++ b/spring-cloud-tencent-plugin-starters/spring-cloud-tencent-gateway-plugin/src/test/java/com/tencent/cloud/plugin/gateway/SCGPluginsAutoConfigurationTest.java @@ -45,7 +45,7 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen */ @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = DEFINED_PORT, classes = SCGPluginsAutoConfigurationTest.TestApplication.class, - properties = {"server.port=8081", "spring.config.location = classpath:application-test.yml", + properties = {"server.port=48081", "spring.config.location = classpath:application-test.yml", "spring.cloud.tencent.plugin.scg.staining.rule-staining.enabled = true"}) public class SCGPluginsAutoConfigurationTest { diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/PolarisEnhancedPluginUtils.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/PolarisEnhancedPluginUtils.java index 2ace4619c..188fb9677 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/PolarisEnhancedPluginUtils.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/plugin/PolarisEnhancedPluginUtils.java @@ -79,6 +79,7 @@ public final class PolarisEnhancedPluginUtils { private static final List HTTP_STATUSES = toList(NOT_IMPLEMENTED, BAD_GATEWAY, SERVICE_UNAVAILABLE, GATEWAY_TIMEOUT, HTTP_VERSION_NOT_SUPPORTED, VARIANT_ALSO_NEGOTIATES, INSUFFICIENT_STORAGE, LOOP_DETECTED, BANDWIDTH_LIMIT_EXCEEDED, NOT_EXTENDED, NETWORK_AUTHENTICATION_REQUIRED); + private PolarisEnhancedPluginUtils() { } @@ -216,7 +217,15 @@ public final class PolarisEnhancedPluginUtils { if (headers != null && headers.containsKey(HeaderConstant.INTERNAL_ACTIVE_RULE_NAME)) { Collection values = headers.get(HeaderConstant.INTERNAL_ACTIVE_RULE_NAME); if (CollectionUtils.isNotEmpty(values)) { - return com.tencent.polaris.api.utils.StringUtils.defaultString(new ArrayList<>(values).get(0)); + String decodedActiveRuleName = ""; + try { + decodedActiveRuleName = URLDecoder.decode(new ArrayList<>(values).get(0), UTF_8); + } + catch (UnsupportedEncodingException e) { + LOG.error("Cannot decode {} from header internal-callee-activerule.", + headers.get(HeaderConstant.INTERNAL_ACTIVE_RULE_NAME).get(0), e); + } + return com.tencent.polaris.api.utils.StringUtils.defaultString(decodedActiveRuleName); } } return ""; diff --git a/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/plugin/PolarisEnhancedPluginUtilsTest.java b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/plugin/PolarisEnhancedPluginUtilsTest.java index 6b0006da6..66e850932 100644 --- a/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/plugin/PolarisEnhancedPluginUtilsTest.java +++ b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/plugin/PolarisEnhancedPluginUtilsTest.java @@ -17,9 +17,11 @@ package com.tencent.cloud.rpc.enhancement.plugin; +import java.io.UnsupportedEncodingException; import java.net.SocketTimeoutException; import java.net.URI; import java.net.URISyntaxException; +import java.net.URLEncoder; import java.util.Arrays; import java.util.HashMap; @@ -46,6 +48,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST; import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER; import static org.assertj.core.api.Assertions.assertThat; @@ -324,13 +327,14 @@ public class PolarisEnhancedPluginUtilsTest { } @Test - public void testGetActiveRuleNameFromRequest() { + public void testGetActiveRuleNameFromRequest() throws UnsupportedEncodingException { HttpHeaders headers = new HttpHeaders(); String ruleName = PolarisEnhancedPluginUtils.getActiveRuleNameFromRequest(headers); assertThat(ruleName).isEqualTo(""); - headers.set(HeaderConstant.INTERNAL_ACTIVE_RULE_NAME, "mock_rule"); + String encodedRuleName = URLEncoder.encode("mock_rule", UTF_8); + headers.set(HeaderConstant.INTERNAL_ACTIVE_RULE_NAME, encodedRuleName); ruleName = PolarisEnhancedPluginUtils.getActiveRuleNameFromRequest(headers); assertThat(ruleName).isEqualTo("mock_rule"); }