From 50d45f23a186051d177990fd00a89d152c5c4dae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=99=E4=BB=A3=E7=A0=81=E7=9A=84=E7=8C=AB?= <33629004+shuangchengsun@users.noreply.github.com> Date: Thu, 9 Dec 2021 10:50:52 +0800 Subject: [PATCH] [ISSUE 3585] [Part F] eliminate regex match in topic/group name check (#3594) --- .../apache/rocketmq/client/Validators.java | 52 +++++-------------- .../rocketmq/client/ValidatorsTest.java | 2 +- .../rocketmq/common/topic/TopicValidator.java | 47 ++++++++++++----- 3 files changed, 49 insertions(+), 52 deletions(-) diff --git a/client/src/main/java/org/apache/rocketmq/client/Validators.java b/client/src/main/java/org/apache/rocketmq/client/Validators.java index e712e2f5e4..19208c3155 100644 --- a/client/src/main/java/org/apache/rocketmq/client/Validators.java +++ b/client/src/main/java/org/apache/rocketmq/client/Validators.java @@ -17,8 +17,8 @@ package org.apache.rocketmq.client; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import static org.apache.rocketmq.common.topic.TopicValidator.isTopicOrGroupIllegal; + import org.apache.rocketmq.client.exception.MQClientException; import org.apache.rocketmq.client.producer.DefaultMQProducer; import org.apache.rocketmq.common.UtilAll; @@ -30,23 +30,9 @@ import org.apache.rocketmq.common.topic.TopicValidator; * Common Validator */ public class Validators { - public static final String VALID_PATTERN_STR = "^[%|a-zA-Z0-9_-]+$"; - public static final Pattern PATTERN = Pattern.compile(VALID_PATTERN_STR); public static final int CHARACTER_MAX_LENGTH = 255; public static final int TOPIC_MAX_LENGTH = 127; - /** - * @return The resulting {@code String} - */ - public static String getGroupWithRegularExpression(String origin, String patternStr) { - Pattern pattern = Pattern.compile(patternStr); - Matcher matcher = pattern.matcher(origin); - while (matcher.find()) { - return matcher.group(0); - } - return null; - } - /** * Validate group */ @@ -59,27 +45,15 @@ public class Validators { throw new MQClientException("the specified group is longer than group max length 255.", null); } - if (!regularExpressionMatcher(group, PATTERN)) { + + if (isTopicOrGroupIllegal(group)) { throw new MQClientException(String.format( - "the specified group[%s] contains illegal characters, allowing only %s", group, - VALID_PATTERN_STR), null); + "the specified group[%s] contains illegal characters, allowing only %s", group, + "^[%|a-zA-Z0-9_-]+$"), null); } - } - /** - * @return true if, and only if, the entire origin sequence matches this matcher's pattern - */ - public static boolean regularExpressionMatcher(String origin, Pattern pattern) { - if (pattern == null) { - return true; - } - Matcher matcher = pattern.matcher(origin); - return matcher.matches(); - } - - public static void checkMessage(Message msg, DefaultMQProducer defaultMQProducer) - throws MQClientException { + public static void checkMessage(Message msg, DefaultMQProducer defaultMQProducer) throws MQClientException { if (null == msg) { throw new MQClientException(ResponseCode.MESSAGE_ILLEGAL, "the message is null"); } @@ -107,16 +81,16 @@ public class Validators { throw new MQClientException("The specified topic is blank", null); } - if (!regularExpressionMatcher(topic, PATTERN)) { - throw new MQClientException(String.format( - "The specified topic[%s] contains illegal characters, allowing only %s", topic, - VALID_PATTERN_STR), null); - } - if (topic.length() > TOPIC_MAX_LENGTH) { throw new MQClientException( String.format("The specified topic is longer than topic max length %d.", TOPIC_MAX_LENGTH), null); } + + if (isTopicOrGroupIllegal(topic)) { + throw new MQClientException(String.format( + "The specified topic[%s] contains illegal characters, allowing only %s", topic, + "^[%|a-zA-Z0-9_-]+$"), null); + } } public static void isSystemTopic(String topic) throws MQClientException { diff --git a/client/src/test/java/org/apache/rocketmq/client/ValidatorsTest.java b/client/src/test/java/org/apache/rocketmq/client/ValidatorsTest.java index 343fe4bca6..aa448dc07f 100644 --- a/client/src/test/java/org/apache/rocketmq/client/ValidatorsTest.java +++ b/client/src/test/java/org/apache/rocketmq/client/ValidatorsTest.java @@ -44,7 +44,7 @@ public class ValidatorsTest { Validators.checkTopic(illegalTopic); failBecauseExceptionWasNotThrown(MQClientException.class); } catch (MQClientException e) { - assertThat(e).hasMessageStartingWith(String.format("The specified topic[%s] contains illegal characters, allowing only %s", illegalTopic, Validators.VALID_PATTERN_STR)); + assertThat(e).hasMessageStartingWith(String.format("The specified topic[%s] contains illegal characters, allowing only %s", illegalTopic, "^[%|a-zA-Z0-9_-]+$")); } } diff --git a/common/src/main/java/org/apache/rocketmq/common/topic/TopicValidator.java b/common/src/main/java/org/apache/rocketmq/common/topic/TopicValidator.java index 7b0a8394a1..c0525fa158 100644 --- a/common/src/main/java/org/apache/rocketmq/common/topic/TopicValidator.java +++ b/common/src/main/java/org/apache/rocketmq/common/topic/TopicValidator.java @@ -22,8 +22,6 @@ import org.apache.rocketmq.remoting.protocol.RemotingCommand; import java.util.HashSet; import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; public class TopicValidator { @@ -38,9 +36,7 @@ public class TopicValidator { public static final String RMQ_SYS_OFFSET_MOVED_EVENT = "OFFSET_MOVED_EVENT"; public static final String SYSTEM_TOPIC_PREFIX = "rmq_sys_"; - - private static final String VALID_PATTERN_STR = "^[%|a-zA-Z0-9_-]+$"; - private static final Pattern PATTERN = Pattern.compile(VALID_PATTERN_STR); + public static final boolean[] VALID_CHAR_BIT_MAP = new boolean[128]; private static final int TOPIC_MAX_LENGTH = 127; private static final Set SYSTEM_TOPIC_SET = new HashSet(); @@ -62,14 +58,41 @@ public class TopicValidator { SYSTEM_TOPIC_SET.add(RMQ_SYS_OFFSET_MOVED_EVENT); NOT_ALLOWED_SEND_TOPIC_SET.add(RMQ_SYS_SCHEDULE_TOPIC); + + // regex: ^[%|a-zA-Z0-9_-]+$ + // % + VALID_CHAR_BIT_MAP['%'] = true; + // - + VALID_CHAR_BIT_MAP['-'] = true; + // _ + VALID_CHAR_BIT_MAP['_'] = true; + // | + VALID_CHAR_BIT_MAP['|'] = true; + for (int i = 0; i < VALID_CHAR_BIT_MAP.length; i++) { + if (i >= '0' && i <= '9') { + // 0-9 + VALID_CHAR_BIT_MAP[i] = true; + } else if (i >= 'A' && i <= 'Z') { + // A-Z + VALID_CHAR_BIT_MAP[i] = true; + } else if (i >= 'a' && i <= 'z') { + // a-z + VALID_CHAR_BIT_MAP[i] = true; + } + } } - private static boolean regularExpressionMatcher(String origin, Pattern pattern) { - if (pattern == null) { - return true; + public static boolean isTopicOrGroupIllegal(String str) { + int strLen = str.length(); + int len = VALID_CHAR_BIT_MAP.length; + boolean[] bitMap = VALID_CHAR_BIT_MAP; + for (int i = 0; i < strLen; i++) { + char ch = str.charAt(i); + if (ch >= len || !bitMap[ch]) { + return true; + } } - Matcher matcher = pattern.matcher(origin); - return matcher.matches(); + return false; } public static boolean validateTopic(String topic, RemotingCommand response) { @@ -80,9 +103,9 @@ public class TopicValidator { return false; } - if (!regularExpressionMatcher(topic, PATTERN)) { + if (isTopicOrGroupIllegal(topic)) { response.setCode(ResponseCode.SYSTEM_ERROR); - response.setRemark("The specified topic contains illegal characters, allowing only " + VALID_PATTERN_STR); + response.setRemark("The specified topic contains illegal characters, allowing only ^[%|a-zA-Z0-9_-]+$"); return false; }