-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(kafka): validate topic name when create (#1788)
- Loading branch information
Showing
2 changed files
with
45 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ | |
module HStream.Kafka.Server.Handler.Topic | ||
( -- 19: CreateTopics | ||
handleCreateTopics | ||
, validateTopicName | ||
-- 20: DeleteTopics | ||
, handleDeleteTopics | ||
-- 37: CreatePartitions | ||
|
@@ -55,7 +56,7 @@ handleCreateTopics ctx@ServerContext{scLDClient} reqCtx K.CreateTopicsRequest{.. | |
| V.null topics_ -> return $ K.CreateTopicsResponse {topics = K.KaArray $ Just V.empty, throttleTimeMs = 0} | ||
| otherwise -> do | ||
(errRes, topics') <- mapM (\tp -> mapErr tp.name | ||
<$> liftM2 (*>) (authorizeTopic tp) (pure . validateTopic $ tp) | ||
<$> liftM2 (*>) (authorizeTopic tp) (doValidate tp) | ||
) topics_ <&> V.partitionWith id | ||
if | null topics' -> | ||
-- all topics validate failed, return directly | ||
|
@@ -93,6 +94,12 @@ handleCreateTopics ctx@ServerContext{scLDClient} reqCtx K.CreateTopicsRequest{.. | |
mapErr name (Left (errorCode, msg)) = Left $ K.CreatableTopicResult name errorCode msg | ||
mapErr _ (Right tp) = Right tp | ||
|
||
doValidate tp = case validateTopic tp of | ||
Left err'@(_, msg) -> do | ||
Log.warning $ "Topic " <> Log.build tp.name <> " validate failed: " <> Log.build (show msg) | ||
return $ Left err' | ||
Right tp' -> return $ Right tp' | ||
|
||
createTopic :: K.CreatableTopic -> IO K.CreatableTopicResult | ||
createTopic topic@K.CreatableTopic{..} = do | ||
authorizeTopic topic >>= \case | ||
|
@@ -104,7 +111,8 @@ handleCreateTopics ctx@ServerContext{scLDClient} reqCtx K.CreateTopicsRequest{.. | |
|
||
validateTopic :: K.CreatableTopic -> Either (ErrorCode, NullableString) K.CreatableTopic | ||
validateTopic topic@K.CreatableTopic{..} = do | ||
validateNullConfig configs | ||
validateName name | ||
*> validateNullConfig configs | ||
*> validateAssignments assignments | ||
*> validateReplica replicationFactor | ||
*> validateNumPartitions numPartitions | ||
|
@@ -113,6 +121,8 @@ validateTopic [email protected]{..} = do | |
invalidNumPartitionsMsg = Just . T.pack $ "Number of partitions must be larger than 0, or -1 to use the default value." | ||
unsuportedPartitionAssignments = Just . T.pack $ "Partition assignments is not supported now." | ||
|
||
validateName n = topic <$ validateTopicName n | ||
|
||
validateNullConfig (K.unKaArray -> Just configs') = | ||
let nullConfigs = V.filter (\K.CreateableTopicConfig{value} -> isNothing value) configs' | ||
in if V.null nullConfigs | ||
|
@@ -133,6 +143,28 @@ validateTopic [email protected]{..} = do | |
| partitions < -1 || partitions == 0 = Left (K.INVALID_PARTITIONS, invalidNumPartitionsMsg) | ||
| otherwise = Right topic | ||
|
||
validateTopicName :: T.Text -> Either (ErrorCode, Maybe T.Text) () | ||
validateTopicName name | ||
| T.null name = Left (K.INVALID_TOPIC_EXCEPTION, Just "Topic name should not be empty.") | ||
| name == "." = Left (K.INVALID_TOPIC_EXCEPTION, Just "Topic name should not be '.'") | ||
| name == ".." = Left (K.INVALID_TOPIC_EXCEPTION, Just "Topic name should not be '..'") | ||
| T.length name > maxNameLength = Left (K.INVALID_TOPIC_EXCEPTION, topicNameTooLong name) | ||
| not (containsValidChars name) = Left (K.INVALID_TOPIC_EXCEPTION, invalidChars name) | ||
| otherwise = Right () | ||
where | ||
maxNameLength = 249 | ||
|
||
containsValidChars = T.all isValidChar | ||
isValidChar c = (c >= 'a' && c <= 'z') | ||
|| (c >= 'A' && c <= 'Z') | ||
|| (c >= '0' && c <= '9') | ||
|| c == '.' | ||
|| c == '_' | ||
|| c == '-' | ||
|
||
topicNameTooLong n = Just $ "the lenght of " <> n <> " is longer than the max allowd length " <> (T.pack . show $ maxNameLength) | ||
invalidChars n = Just $ n <> " contains one or more characters other than ASCII alphanumeric, '.', '_', and '-'" | ||
|
||
-------------------- | ||
-- 20: DeleteTopics | ||
-------------------- | ||
|