diff --git a/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/SentinelGatewayConstants.java b/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/SentinelGatewayConstants.java index 2c56e6b7..d448779f 100644 --- a/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/SentinelGatewayConstants.java +++ b/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/SentinelGatewayConstants.java @@ -30,6 +30,7 @@ public final class SentinelGatewayConstants { public static final int PARAM_PARSE_STRATEGY_HOST = 1; public static final int PARAM_PARSE_STRATEGY_HEADER = 2; public static final int PARAM_PARSE_STRATEGY_URL_PARAM = 3; + public static final int PARAM_PARSE_STRATEGY_COOKIE = 4; public static final int PARAM_MATCH_STRATEGY_EXACT = 0; public static final int PARAM_MATCH_STRATEGY_PREFIX = 1; diff --git a/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/param/GatewayParamParser.java b/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/param/GatewayParamParser.java index f326468b..1c9a8dbb 100644 --- a/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/param/GatewayParamParser.java +++ b/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/param/GatewayParamParser.java @@ -42,8 +42,8 @@ public class GatewayParamParser { /** * Parse parameters for given resource from the request entity on condition of the rule predicate. * - * @param resource valid resource name - * @param request valid request + * @param resource valid resource name + * @param request valid request * @param rulePredicate rule predicate indicating the rules to refer * @return the parameter array */ @@ -92,6 +92,8 @@ public class GatewayParamParser { return parseHeader(item, request); case SentinelGatewayConstants.PARAM_PARSE_STRATEGY_URL_PARAM: return parseUrlParameter(item, request); + case SentinelGatewayConstants.PARAM_PARSE_STRATEGY_COOKIE: + return parseCookie(item, request); default: return null; } @@ -139,6 +141,17 @@ public class GatewayParamParser { return parseWithMatchStrategyInternal(item.getMatchStrategy(), param, pattern); } + private String parseCookie(/*@Valid*/ GatewayParamFlowItem item, T request) { + String cookieName = item.getFieldName(); + String pattern = item.getPattern(); + String param = requestItemParser.getCookieValue(request, cookieName); + if (pattern == null) { + return param; + } + // Match value according to regex pattern or exact mode. + return parseWithMatchStrategyInternal(item.getMatchStrategy(), param, pattern); + } + private String parseWithMatchStrategyInternal(int matchStrategy, String value, String pattern) { // TODO: implement here. if (value == null) { diff --git a/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/param/RequestItemParser.java b/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/param/RequestItemParser.java index 5b28abe7..7eb71c52 100644 --- a/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/param/RequestItemParser.java +++ b/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/param/RequestItemParser.java @@ -41,7 +41,7 @@ public interface RequestItemParser { * Get the header associated with the header key. * * @param request valid request - * @param key valid header key + * @param key valid header key * @return the header */ String getHeader(T request, String key); @@ -49,9 +49,19 @@ public interface RequestItemParser { /** * Get the parameter value associated with the parameter name. * - * @param request valid request + * @param request valid request * @param paramName valid parameter name * @return the parameter value */ String getUrlParam(T request, String paramName); + + /** + * Get the cookie value associated with the cookie name. + * + * @param request valid request + * @param cookieName valid cookie name + * @return the cookie value + * @since 1.7.0 + */ + String getCookieValue(T request, String cookieName); } diff --git a/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/rule/GatewayRuleManager.java b/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/rule/GatewayRuleManager.java index e4880bed..c1084227 100644 --- a/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/rule/GatewayRuleManager.java +++ b/sentinel-adapter/sentinel-api-gateway-adapter-common/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/common/rule/GatewayRuleManager.java @@ -16,6 +16,7 @@ package com.alibaba.csp.sentinel.adapter.gateway.common.rule; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -242,14 +243,18 @@ public final class GatewayRuleManager { if (item.getParseStrategy() < 0) { return false; } - if (item.getParseStrategy() == SentinelGatewayConstants.PARAM_PARSE_STRATEGY_URL_PARAM || - item.getParseStrategy() == SentinelGatewayConstants.PARAM_PARSE_STRATEGY_HEADER) { - if (StringUtil.isBlank(item.getFieldName())) { - return false; - } + // Check required field name for item types. + if (FIELD_REQUIRED_SET.contains(item.getParseStrategy()) && StringUtil.isBlank(item.getFieldName())) { + return false; } return StringUtil.isEmpty(item.getPattern()) || item.getMatchStrategy() >= 0; } + private static final Set FIELD_REQUIRED_SET = new HashSet<>( + Arrays.asList(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_URL_PARAM, + SentinelGatewayConstants.PARAM_PARSE_STRATEGY_HEADER, + SentinelGatewayConstants.PARAM_PARSE_STRATEGY_COOKIE) + ); + private GatewayRuleManager() {} } diff --git a/sentinel-adapter/sentinel-api-gateway-adapter-common/src/test/java/com/alibaba/csp/sentinel/adapter/gateway/common/param/GatewayParamParserTest.java b/sentinel-adapter/sentinel-api-gateway-adapter-common/src/test/java/com/alibaba/csp/sentinel/adapter/gateway/common/param/GatewayParamParserTest.java index 7edc7844..fe418b21 100644 --- a/sentinel-adapter/sentinel-api-gateway-adapter-common/src/test/java/com/alibaba/csp/sentinel/adapter/gateway/common/param/GatewayParamParserTest.java +++ b/sentinel-adapter/sentinel-api-gateway-adapter-common/src/test/java/com/alibaba/csp/sentinel/adapter/gateway/common/param/GatewayParamParserTest.java @@ -94,6 +94,7 @@ public class GatewayParamParserTest { final String api1 = "my_test_route_B"; final String headerName = "X-Sentinel-Flag"; final String paramName = "p"; + final String cookieName = "myCookie"; GatewayFlowRule routeRuleNoParam = new GatewayFlowRule(routeId1) .setCount(10) .setIntervalSec(10); @@ -128,6 +129,13 @@ public class GatewayParamParserTest { .setParamItem(new GatewayParamFlowItem() .setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_HOST) ); + GatewayFlowRule routeRule5 = new GatewayFlowRule(routeId1) + .setCount(50) + .setIntervalSec(30) + .setParamItem(new GatewayParamFlowItem() + .setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_COOKIE) + .setFieldName(cookieName) + ); GatewayFlowRule apiRule1 = new GatewayFlowRule(api1) .setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_CUSTOM_API_NAME) .setCount(5) @@ -140,6 +148,7 @@ public class GatewayParamParserTest { rules.add(routeRule2); rules.add(routeRule3); rules.add(routeRule4); + rules.add(routeRule5); rules.add(routeRuleNoParam); rules.add(apiRule1); GatewayRuleManager.loadRules(rules); @@ -148,19 +157,24 @@ public class GatewayParamParserTest { final String expectedAddress = "66.77.88.99"; final String expectedHeaderValue1 = "Sentinel"; final String expectedUrlParamValue1 = "17"; + final String expectedCookieValue1 = "Sentinel-Foo"; + mockClientHostAddress(itemParser, expectedAddress); Map expectedHeaders = new HashMap() {{ put(headerName, expectedHeaderValue1); put("Host", expectedHost); }}; mockHeaders(itemParser, expectedHeaders); mockSingleUrlParam(itemParser, paramName, expectedUrlParamValue1); + mockSingleCookie(itemParser, cookieName, expectedCookieValue1); + Object[] params = paramParser.parseParameterFor(routeId1, request, routeIdPredicate); - // Param length should be 5 (4 with parameters, 1 normal flow with generated constant) - assertThat(params.length).isEqualTo(5); + // Param length should be 6 (5 with parameters, 1 normal flow with generated constant) + assertThat(params.length).isEqualTo(6); assertThat(params[routeRule1.getParamItem().getIndex()]).isEqualTo(expectedAddress); assertThat(params[routeRule2.getParamItem().getIndex()]).isEqualTo(expectedHeaderValue1); assertThat(params[routeRule3.getParamItem().getIndex()]).isEqualTo(expectedUrlParamValue1); assertThat(params[routeRule4.getParamItem().getIndex()]).isEqualTo(expectedHost); + assertThat(params[routeRule5.getParamItem().getIndex()]).isEqualTo(expectedCookieValue1); assertThat(params[params.length - 1]).isEqualTo(SentinelGatewayConstants.GATEWAY_DEFAULT_PARAM); assertThat(paramParser.parseParameterFor(api1, request, routeIdPredicate).length).isZero(); @@ -196,6 +210,10 @@ public class GatewayParamParserTest { when(parser.getHeader(any(), eq(key))).thenReturn(value); } + private void mockSingleCookie(/*@Mock*/ RequestItemParser parser, String key, String value) { + when(parser.getCookieValue(any(), eq(key))).thenReturn(value); + } + @Before public void setUp() { GatewayApiDefinitionManager.loadApiDefinitions(new HashSet()); diff --git a/sentinel-adapter/sentinel-spring-cloud-gateway-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/sc/ServerWebExchangeItemParser.java b/sentinel-adapter/sentinel-spring-cloud-gateway-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/sc/ServerWebExchangeItemParser.java index 6088cd2d..fcf00ecb 100644 --- a/sentinel-adapter/sentinel-spring-cloud-gateway-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/sc/ServerWebExchangeItemParser.java +++ b/sentinel-adapter/sentinel-spring-cloud-gateway-adapter/src/main/java/com/alibaba/csp/sentinel/adapter/gateway/sc/ServerWebExchangeItemParser.java @@ -16,9 +16,11 @@ package com.alibaba.csp.sentinel.adapter.gateway.sc; import java.net.InetSocketAddress; +import java.util.Optional; import com.alibaba.csp.sentinel.adapter.gateway.common.param.RequestItemParser; +import org.springframework.http.HttpCookie; import org.springframework.web.server.ServerWebExchange; /** @@ -50,4 +52,11 @@ public class ServerWebExchangeItemParser implements RequestItemParser