From b7b54034ccb89a5cecff0c4cd6c0af78c31a429d Mon Sep 17 00:00:00 2001 From: dani3lWong Date: Mon, 14 Sep 2020 10:03:58 +0800 Subject: [PATCH] Fix NPE bug when updating gateway flow rules before the route/API has been requested once (#1729) --- .../common/rule/GatewayRuleManager.java | 98 +++++++++---------- 1 file changed, 48 insertions(+), 50 deletions(-) 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 257b5c03..9476b5f3 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 @@ -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; @@ -33,10 +24,14 @@ import com.alibaba.csp.sentinel.property.SentinelProperty; 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 @@ -51,12 +46,20 @@ public final class GatewayRuleManager { private static final Map> CONVERTED_PARAM_RULE_MAP = new ConcurrentHashMap<>(); private static final GatewayRulePropertyListener LISTENER = new GatewayRulePropertyListener(); + 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 static SentinelProperty> currentProperty = new DynamicSentinelProperty<>(); static { currentProperty.addListener(LISTENER); } + private GatewayRuleManager() { + } + public static void register2Property(SentinelProperty> property) { AssertUtil.notNull(property, "property cannot be null"); synchronized (LISTENER) { @@ -111,6 +114,36 @@ public final class GatewayRuleManager { 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> { @Override @@ -136,7 +169,7 @@ public final class GatewayRuleManager { 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); } @@ -205,7 +238,7 @@ public final class GatewayRuleManager { private void applyToConvertedParamMap(Set paramFlowRules) { Map> 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()) { @@ -227,7 +260,10 @@ public final class GatewayRuleManager { List 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); + } } } @@ -238,42 +274,4 @@ public final class GatewayRuleManager { 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 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() {} }