Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
mica
mica-mqtt
提交
c798ae03
mica-mqtt
项目概览
mica
/
mica-mqtt
通知
71
Star
1
Fork
1
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
mica-mqtt
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
c798ae03
编写于
5月 09, 2022
作者:
浅梦2013
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
✨
加强 topic 校验
上级
3de882b5
变更
7
显示空白变更内容
内联
并排
Showing
7 changed file
with
97 addition
and
10 deletion
+97
-10
mica-mqtt-codec/src/main/java/net/dreamlu/iot/mqtt/codec/MqttCodecUtil.java
...c/main/java/net/dreamlu/iot/mqtt/codec/MqttCodecUtil.java
+7
-1
mica-mqtt-core/src/main/java/net/dreamlu/iot/mqtt/core/client/DefaultMqttClientSession.java
...reamlu/iot/mqtt/core/client/DefaultMqttClientSession.java
+5
-2
mica-mqtt-core/src/main/java/net/dreamlu/iot/mqtt/core/client/MqttClient.java
...ain/java/net/dreamlu/iot/mqtt/core/client/MqttClient.java
+8
-0
mica-mqtt-core/src/main/java/net/dreamlu/iot/mqtt/core/server/MqttServer.java
...ain/java/net/dreamlu/iot/mqtt/core/server/MqttServer.java
+8
-4
mica-mqtt-core/src/main/java/net/dreamlu/iot/mqtt/core/server/http/handler/MqttHttpRequestHandler.java
...mqtt/core/server/http/handler/MqttHttpRequestHandler.java
+4
-1
mica-mqtt-core/src/main/java/net/dreamlu/iot/mqtt/core/server/support/DefaultMqttServerProcessor.java
.../mqtt/core/server/support/DefaultMqttServerProcessor.java
+3
-0
mica-mqtt-core/src/main/java/net/dreamlu/iot/mqtt/core/util/TopicUtil.java
...c/main/java/net/dreamlu/iot/mqtt/core/util/TopicUtil.java
+62
-2
未找到文件。
mica-mqtt-codec/src/main/java/net/dreamlu/iot/mqtt/codec/MqttCodecUtil.java
浏览文件 @
c798ae03
...
...
@@ -56,7 +56,13 @@ public final class MqttCodecUtil {
* @return 是否 topic filter
*/
public
static
boolean
isTopicFilter
(
String
topicFilter
)
{
return
topicFilter
.
indexOf
(
TOPIC_WILDCARDS_ONE
)
>=
0
||
topicFilter
.
indexOf
(
TOPIC_WILDCARDS_MORE
)
>=
0
;
char
[]
topicFilterChars
=
topicFilter
.
toCharArray
();
for
(
char
ch
:
topicFilterChars
)
{
if
(
TOPIC_WILDCARDS_ONE
==
ch
||
TOPIC_WILDCARDS_MORE
==
ch
)
{
return
true
;
}
}
return
false
;
}
/**
...
...
mica-mqtt-core/src/main/java/net/dreamlu/iot/mqtt/core/client/DefaultMqttClientSession.java
浏览文件 @
c798ae03
...
...
@@ -19,13 +19,16 @@ package net.dreamlu.iot.mqtt.core.client;
import
net.dreamlu.iot.mqtt.codec.MqttQoS
;
import
net.dreamlu.iot.mqtt.core.common.MqttPendingPublish
;
import
net.dreamlu.iot.mqtt.core.common.MqttPendingQos2Publish
;
import
net.dreamlu.iot.mqtt.core.util.collection.MultiValueMap
;
import
net.dreamlu.iot.mqtt.core.util.collection.IntObjectHashMap
;
import
net.dreamlu.iot.mqtt.core.util.collection.IntObjectMap
;
import
net.dreamlu.iot.mqtt.core.util.collection.MultiValueMap
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
java.util.*
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.Set
;
/**
* 客户端 session 管理,包括 sub 和 pub
...
...
mica-mqtt-core/src/main/java/net/dreamlu/iot/mqtt/core/client/MqttClient.java
浏览文件 @
c798ae03
...
...
@@ -18,6 +18,7 @@ package net.dreamlu.iot.mqtt.core.client;
import
net.dreamlu.iot.mqtt.codec.*
;
import
net.dreamlu.iot.mqtt.core.common.MqttPendingPublish
;
import
net.dreamlu.iot.mqtt.core.util.TopicUtil
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.tio.client.ClientChannelContext
;
...
...
@@ -185,6 +186,8 @@ public final class MqttClient {
// 1. 先判断是否已经订阅过,重复订阅,直接跳出
List
<
MqttClientSubscription
>
needSubscriptionList
=
new
ArrayList
<>();
for
(
MqttClientSubscription
subscription
:
subscriptionList
)
{
// 校验 topicFilter
TopicUtil
.
validateTopicFilter
(
subscription
.
getTopicFilter
());
boolean
subscribed
=
clientSession
.
isSubscribed
(
subscription
);
if
(!
subscribed
)
{
needSubscriptionList
.
add
(
subscription
);
...
...
@@ -229,6 +232,8 @@ public final class MqttClient {
* @return MqttClient
*/
public
MqttClient
unSubscribe
(
List
<
String
>
topicFilters
)
{
// 校验 topicFilter
TopicUtil
.
validateTopicFilter
(
topicFilters
);
int
messageId
=
messageIdGenerator
.
getId
();
MqttUnsubscribeMessage
message
=
MqttMessageBuilders
.
unsubscribe
()
.
addTopicFilters
(
topicFilters
)
...
...
@@ -363,6 +368,9 @@ public final class MqttClient {
* @return 是否发送成功
*/
public
boolean
publish
(
String
topic
,
ByteBuffer
payload
,
MqttQoS
qos
,
Consumer
<
MqttMessageBuilders
.
PublishBuilder
>
builder
)
{
// 校验 topic
TopicUtil
.
validateTopicName
(
topic
);
// qos 判断
boolean
isHighLevelQoS
=
MqttQoS
.
AT_LEAST_ONCE
==
qos
||
MqttQoS
.
EXACTLY_ONCE
==
qos
;
int
messageId
=
isHighLevelQoS
?
messageIdGenerator
.
getId
()
:
-
1
;
if
(
payload
==
null
)
{
...
...
mica-mqtt-core/src/main/java/net/dreamlu/iot/mqtt/core/server/MqttServer.java
浏览文件 @
c798ae03
...
...
@@ -26,10 +26,10 @@ import net.dreamlu.iot.mqtt.core.server.model.Message;
import
net.dreamlu.iot.mqtt.core.server.model.Subscribe
;
import
net.dreamlu.iot.mqtt.core.server.session.IMqttSessionManager
;
import
net.dreamlu.iot.mqtt.core.server.store.IMqttMessageStore
;
import
net.dreamlu.iot.mqtt.core.util.TopicUtil
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.tio.core.ChannelContext
;
import
org.tio.core.Node
;
import
org.tio.core.Tio
;
import
org.tio.server.ServerTioConfig
;
import
org.tio.server.TioServer
;
...
...
@@ -154,6 +154,9 @@ public final class MqttServer {
* @return 是否发送成功
*/
public
boolean
publish
(
String
clientId
,
String
topic
,
ByteBuffer
payload
,
MqttQoS
qos
,
boolean
retain
)
{
// 校验 topic
TopicUtil
.
validateTopicName
(
topic
);
// 获取 context
ChannelContext
context
=
Tio
.
getByBsId
(
getServerConfig
(),
clientId
);
if
(
context
==
null
||
context
.
isClosed
)
{
logger
.
warn
(
"Mqtt Topic:{} publish to clientId:{} ChannelContext is null may be disconnected."
,
topic
,
clientId
);
...
...
@@ -165,8 +168,7 @@ public final class MqttServer {
return
false
;
}
MqttQoS
mqttQoS
=
qos
.
value
()
>
subMqttQoS
?
MqttQoS
.
valueOf
(
subMqttQoS
)
:
qos
;
publish
(
context
,
clientId
,
topic
,
payload
,
mqttQoS
,
retain
);
return
true
;
return
publish
(
context
,
clientId
,
topic
,
payload
,
mqttQoS
,
retain
);
}
/**
...
...
@@ -180,7 +182,7 @@ public final class MqttServer {
* @param retain 是否在服务器上保留消息
* @return 是否发送成功
*/
p
ublic
boolean
publish
(
ChannelContext
context
,
String
clientId
,
String
topic
,
ByteBuffer
payload
,
MqttQoS
qos
,
boolean
retain
)
{
p
rivate
boolean
publish
(
ChannelContext
context
,
String
clientId
,
String
topic
,
ByteBuffer
payload
,
MqttQoS
qos
,
boolean
retain
)
{
boolean
isHighLevelQoS
=
MqttQoS
.
AT_LEAST_ONCE
==
qos
||
MqttQoS
.
EXACTLY_ONCE
==
qos
;
int
messageId
=
isHighLevelQoS
?
sessionManager
.
getMessageId
(
clientId
)
:
-
1
;
// 下行 payload 为空时,构造一个空结构体
...
...
@@ -254,6 +256,8 @@ public final class MqttServer {
* @return 是否发送成功
*/
public
boolean
publishAll
(
String
topic
,
ByteBuffer
payload
,
MqttQoS
qos
,
boolean
retain
)
{
// 校验 topic
TopicUtil
.
validateTopicName
(
topic
);
// 查找订阅该 topic 的客户端
List
<
Subscribe
>
subscribeList
=
sessionManager
.
searchSubscribe
(
topic
);
if
(
subscribeList
.
isEmpty
())
{
...
...
mica-mqtt-core/src/main/java/net/dreamlu/iot/mqtt/core/server/http/handler/MqttHttpRequestHandler.java
浏览文件 @
c798ae03
...
...
@@ -20,7 +20,10 @@ import net.dreamlu.iot.mqtt.core.server.http.api.code.ResultCode;
import
net.dreamlu.iot.mqtt.core.server.http.api.result.Result
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.tio.http.common.*
;
import
org.tio.http.common.HttpConfig
;
import
org.tio.http.common.HttpRequest
;
import
org.tio.http.common.HttpResponse
;
import
org.tio.http.common.RequestLine
;
import
org.tio.http.common.handler.HttpRequestHandler
;
import
java.util.List
;
...
...
mica-mqtt-core/src/main/java/net/dreamlu/iot/mqtt/core/server/support/DefaultMqttServerProcessor.java
浏览文件 @
c798ae03
...
...
@@ -34,6 +34,7 @@ import net.dreamlu.iot.mqtt.core.server.event.IMqttSessionListener;
import
net.dreamlu.iot.mqtt.core.server.model.Message
;
import
net.dreamlu.iot.mqtt.core.server.session.IMqttSessionManager
;
import
net.dreamlu.iot.mqtt.core.server.store.IMqttMessageStore
;
import
net.dreamlu.iot.mqtt.core.util.TopicUtil
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.tio.core.ChannelContext
;
...
...
@@ -334,6 +335,8 @@ public class DefaultMqttServerProcessor implements MqttServerProcessor {
boolean
enableSubscribeValidator
=
subscribeValidator
!=
null
;
for
(
MqttTopicSubscription
subscription
:
topicSubscriptionList
)
{
String
topicFilter
=
subscription
.
topicName
();
// 校验 topicFilter 是否合法
TopicUtil
.
validateTopicFilter
(
topicFilter
);
MqttQoS
mqttQoS
=
subscription
.
qualityOfService
();
// 校验是否可以订阅
if
(
enableSubscribeValidator
&&
!
subscribeValidator
.
verifyTopicFilter
(
context
,
clientId
,
topicFilter
,
mqttQoS
))
{
...
...
mica-mqtt-core/src/main/java/net/dreamlu/iot/mqtt/core/util/TopicUtil.java
浏览文件 @
c798ae03
...
...
@@ -16,6 +16,10 @@
package
net.dreamlu.iot.mqtt.core.util
;
import
net.dreamlu.iot.mqtt.codec.MqttCodecUtil
;
import
java.util.List
;
/**
* Mqtt Topic 工具
*
...
...
@@ -23,6 +27,62 @@ package net.dreamlu.iot.mqtt.core.util;
*/
public
final
class
TopicUtil
{
/**
* 校验 topicFilter
*
* @param topicFilterList topicFilter 集合
*/
public
static
void
validateTopicFilter
(
List
<
String
>
topicFilterList
)
{
for
(
String
topicFilter
:
topicFilterList
)
{
validateTopicFilter
(
topicFilter
);
}
}
/**
* 校验 topicFilter
*
* @param topicFilter topicFilter
*/
public
static
void
validateTopicFilter
(
String
topicFilter
)
{
if
(
topicFilter
==
null
||
topicFilter
.
isEmpty
())
{
throw
new
IllegalArgumentException
(
"TopicFilter is blank:"
+
topicFilter
);
}
char
[]
topicFilterChars
=
topicFilter
.
toCharArray
();
int
topicFilterLength
=
topicFilterChars
.
length
;
int
topicFilterIdxEnd
=
topicFilterLength
-
1
;
char
ch
;
for
(
int
i
=
0
;
i
<
topicFilterLength
;
i
++)
{
ch
=
topicFilterChars
[
i
];
if
(
Character
.
isWhitespace
(
ch
))
{
throw
new
IllegalArgumentException
(
"Mqtt subscribe topicFilter has white space:"
+
topicFilter
);
}
else
if
(
ch
==
MqttCodecUtil
.
TOPIC_WILDCARDS_MORE
)
{
// 校验: # 通配符只能在最后一位
if
(
i
<
topicFilterIdxEnd
)
{
throw
new
IllegalArgumentException
(
"Mqtt subscribe topicFilter illegal:"
+
topicFilter
);
}
}
else
if
(
ch
==
MqttCodecUtil
.
TOPIC_WILDCARDS_ONE
)
{
// 校验: 单独 + 是允许的,判断 + 号前一位是否为 /
if
(
i
>
0
&&
topicFilterChars
[
i
-
1
]
!=
'/'
)
{
throw
new
IllegalArgumentException
(
"Mqtt subscribe topicFilter illegal:"
+
topicFilter
);
}
}
}
}
/**
* 校验 topicName
*
* @param topicName topicName
*/
public
static
void
validateTopicName
(
String
topicName
)
throws
IllegalArgumentException
{
if
(
topicName
==
null
||
topicName
.
isEmpty
())
{
throw
new
IllegalArgumentException
(
"Topic is blank:"
+
topicName
);
}
if
(
MqttCodecUtil
.
isTopicFilter
(
topicName
))
{
throw
new
IllegalArgumentException
(
"Topic has wildcards char [+] or [#], topicName:"
+
topicName
);
}
}
/**
* 判断 topicFilter topicName 是否匹配
*
...
...
@@ -42,13 +102,13 @@ public final class TopicUtil {
boolean
inLayerWildcard
=
false
;
for
(
int
i
=
0
;
i
<
topicFilterLength
;
i
++)
{
ch
=
topicFilterChars
[
i
];
if
(
ch
==
'#'
)
{
if
(
ch
==
MqttCodecUtil
.
TOPIC_WILDCARDS_MORE
)
{
// 校验: # 通配符只能在最后一位
if
(
i
<
topicFilterIdxEnd
)
{
throw
new
IllegalArgumentException
(
"Mqtt subscribe topicFilter illegal:"
+
topicFilter
);
}
return
true
;
}
else
if
(
ch
==
'+'
)
{
}
else
if
(
ch
==
MqttCodecUtil
.
TOPIC_WILDCARDS_ONE
)
{
// 校验: 单独 + 是允许的,判断 + 号前一位是否为 /
if
(
i
>
0
&&
topicFilterChars
[
i
-
1
]
!=
'/'
)
{
throw
new
IllegalArgumentException
(
"Mqtt subscribe topicFilter illegal:"
+
topicFilter
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录