Skip to content

Commit

Permalink
Fix NPE bug when updating gateway flow rules before the route/API has…
Browse files Browse the repository at this point in the history
… been requested once (alibaba#1729)
  • Loading branch information
dani3lWong authored Sep 14, 2020
1 parent 62ec7cb commit 53237e8
Showing 1 changed file with 48 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,6 @@
*/
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;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants;
import com.alibaba.csp.sentinel.adapter.gateway.common.param.GatewayRegexCache;
import com.alibaba.csp.sentinel.log.RecordLog;
Expand All @@ -33,10 +24,14 @@
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleUtil;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParameterMetric;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParameterMetricStorage;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.alibaba.csp.sentinel.util.StringUtil;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
* @author Eric Zhao
* @since 1.6.0
Expand All @@ -51,12 +46,20 @@ public final class GatewayRuleManager {
private static final Map<String, List<ParamFlowRule>> CONVERTED_PARAM_RULE_MAP = new ConcurrentHashMap<>();

private static final GatewayRulePropertyListener LISTENER = new GatewayRulePropertyListener();
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 static SentinelProperty<Set<GatewayFlowRule>> currentProperty = new DynamicSentinelProperty<>();

static {
currentProperty.addListener(LISTENER);
}

private GatewayRuleManager() {
}

public static void register2Property(SentinelProperty<Set<GatewayFlowRule>> property) {
AssertUtil.notNull(property, "property cannot be null");
synchronized (LISTENER) {
Expand Down Expand Up @@ -111,6 +114,36 @@ public static List<ParamFlowRule> getConvertedParamRules(String resourceName) {
return CONVERTED_PARAM_RULE_MAP.get(resourceName);
}

public static boolean isValidRule(GatewayFlowRule rule) {
if (rule == null || StringUtil.isBlank(rule.getResource()) || rule.getResourceMode() < 0
|| rule.getGrade() < 0 || rule.getCount() < 0 || rule.getBurst() < 0 || rule.getControlBehavior() < 0) {
return false;
}
if (rule.getGrade() == RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER
&& rule.getMaxQueueingTimeoutMs() < 0) {
return false;
}
if (rule.getIntervalSec() <= 0) {
return false;
}
GatewayParamFlowItem item = rule.getParamItem();
if (item != null) {
return isValidParamItem(item);
}
return true;
}

static boolean isValidParamItem(/*@NonNull*/ GatewayParamFlowItem item) {
if (item.getParseStrategy() < 0) {
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 class GatewayRulePropertyListener implements PropertyListener<Set<GatewayFlowRule>> {

@Override
Expand All @@ -136,7 +169,7 @@ private int getIdxInternal(Map<String, Integer> idxMap, String resourceName) {
private void cacheRegexPattern(/*@NonNull*/ GatewayParamFlowItem item) {
String pattern = item.getPattern();
if (StringUtil.isNotEmpty(pattern) &&
item.getMatchStrategy() == SentinelGatewayConstants.PARAM_MATCH_STRATEGY_REGEX) {
item.getMatchStrategy() == SentinelGatewayConstants.PARAM_MATCH_STRATEGY_REGEX) {
if (GatewayRegexCache.getRegexPattern(pattern) == null) {
GatewayRegexCache.addRegexPattern(pattern);
}
Expand Down Expand Up @@ -205,7 +238,7 @@ private synchronized void applyGatewayRuleInternal(Set<GatewayFlowRule> conf) {

private void applyToConvertedParamMap(Set<ParamFlowRule> paramFlowRules) {
Map<String, List<ParamFlowRule>> newRuleMap = ParamFlowRuleUtil.buildParamRuleMap(
new ArrayList<>(paramFlowRules));
new ArrayList<>(paramFlowRules));
if (newRuleMap == null || newRuleMap.isEmpty()) {
// No parameter flow rules, so clear all the metrics.
for (String resource : CONVERTED_PARAM_RULE_MAP.keySet()) {
Expand All @@ -227,7 +260,10 @@ private void applyToConvertedParamMap(Set<ParamFlowRule> paramFlowRules) {
List<ParamFlowRule> oldRuleList = new ArrayList<>(entry.getValue());
oldRuleList.removeAll(newRuleList);
for (ParamFlowRule rule : oldRuleList) {
ParameterMetricStorage.getParamMetricForResource(resource).clearForRule(rule);
ParameterMetric metric = ParameterMetricStorage.getParamMetricForResource(resource);
if (null != metric) {
metric.clearForRule(rule);
}
}
}

Expand All @@ -238,42 +274,4 @@ private void applyToConvertedParamMap(Set<ParamFlowRule> paramFlowRules) {
RecordLog.info("[GatewayRuleManager] Converted internal param rules: " + CONVERTED_PARAM_RULE_MAP);
}
}

public static boolean isValidRule(GatewayFlowRule rule) {
if (rule == null || StringUtil.isBlank(rule.getResource()) || rule.getResourceMode() < 0
|| rule.getGrade() < 0 || rule.getCount() < 0 || rule.getBurst() < 0 || rule.getControlBehavior() < 0) {
return false;
}
if (rule.getGrade() == RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER
&& rule.getMaxQueueingTimeoutMs() < 0) {
return false;
}
if (rule.getIntervalSec() <= 0) {
return false;
}
GatewayParamFlowItem item = rule.getParamItem();
if (item != null) {
return isValidParamItem(item);
}
return true;
}

static boolean isValidParamItem(/*@NonNull*/ GatewayParamFlowItem item) {
if (item.getParseStrategy() < 0) {
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() {}
}

0 comments on commit 53237e8

Please sign in to comment.