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

Add support for parsing cookie as request items in gateway flow control #814

Merged
merged 1 commit into from
Jun 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ public GatewayParamParser(RequestItemParser<T> requestItemParser) {
/**
* 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
*/
Expand Down Expand Up @@ -92,6 +92,8 @@ private String parseInternal(GatewayParamFlowItem item, T request) {
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;
}
Expand Down Expand Up @@ -139,6 +141,17 @@ private String parseUrlParameter(/*@Valid*/ GatewayParamFlowItem item, T request
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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,27 @@ public interface RequestItemParser<T> {
* 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);

/**
* 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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -242,14 +243,18 @@ static boolean isValidParamItem(/*@NonNull*/ GatewayParamFlowItem item) {
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<Integer> 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() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ public void testParseParametersWithItems() {
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);
Expand Down Expand Up @@ -128,6 +129,13 @@ public void testParseParametersWithItems() {
.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)
Expand All @@ -140,6 +148,7 @@ public void testParseParametersWithItems() {
rules.add(routeRule2);
rules.add(routeRule3);
rules.add(routeRule4);
rules.add(routeRule5);
rules.add(routeRuleNoParam);
rules.add(apiRule1);
GatewayRuleManager.loadRules(rules);
Expand All @@ -148,19 +157,24 @@ public void testParseParametersWithItems() {
final String expectedAddress = "66.77.88.99";
final String expectedHeaderValue1 = "Sentinel";
final String expectedUrlParamValue1 = "17";
final String expectedCookieValue1 = "Sentinel-Foo";

mockClientHostAddress(itemParser, expectedAddress);
Map<String, String> expectedHeaders = new HashMap<String, String>() {{
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();
Expand Down Expand Up @@ -196,6 +210,10 @@ private void mockSingleHeader(/*@Mock*/ RequestItemParser parser, String key, St
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<ApiDefinition>());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down Expand Up @@ -50,4 +52,11 @@ public String getHeader(ServerWebExchange exchange, String key) {
public String getUrlParam(ServerWebExchange exchange, String paramName) {
return exchange.getRequest().getQueryParams().getFirst(paramName);
}

@Override
public String getCookieValue(ServerWebExchange exchange, String cookieName) {
return Optional.ofNullable(exchange.getResponse().getCookies().getFirst(cookieName))
.map(HttpCookie::getValue)
.orElse(null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
*/
package com.alibaba.csp.sentinel.adapter.gateway.zuul;

import javax.servlet.http.Cookie;

import com.alibaba.csp.sentinel.adapter.gateway.common.param.RequestItemParser;

import com.netflix.zuul.context.RequestContext;
Expand Down Expand Up @@ -44,4 +46,18 @@ public String getHeader(RequestContext requestContext, String headerKey) {
public String getUrlParam(RequestContext requestContext, String paramName) {
return requestContext.getRequest().getParameter(paramName);
}

@Override
public String getCookieValue(RequestContext requestContext, String cookieName) {
Cookie[] cookies = requestContext.getRequest().getCookies();
if (cookies == null || cookieName == null) {
return null;
}
for (Cookie cookie : cookies) {
if (cookie != null && cookieName.equals(cookie.getName())) {
return cookie.getValue();
}
}
return null;
}
}