Fixed issue #43, not clean handlng of bad formatted topic filters during subscrion
This commit is contained in:
+1
-1
@@ -118,7 +118,7 @@
|
||||
<artifactId>mapdb</artifactId>
|
||||
<!--version>1.1.0-SNAPSHOT</version-->
|
||||
<!--<version>2.0.0-SNAPSHOT</version>-->
|
||||
<!--<version>2.0-alpha2</version>-->
|
||||
<!--<version>2.0-alpha3</version>-->
|
||||
<version>1.0.7</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -602,38 +602,38 @@ class ProtocolProcessor implements EventHandler<ValueEvent> {
|
||||
boolean cleanSession = (Boolean) session.getAttribute(NettyChannel.ATTR_KEY_CLEANSESSION);
|
||||
LOG.debug("SUBSCRIBE client <{}> packetID {}", clientID, msg.getMessageID());
|
||||
|
||||
for (SubscribeMessage.Couple req : msg.subscriptions()) {
|
||||
AbstractMessage.QOSType qos = AbstractMessage.QOSType.values()[req.getQos()];
|
||||
Subscription newSubscription = new Subscription(clientID, req.getTopicFilter(), qos, cleanSession);
|
||||
subscribeSingleTopic(newSubscription, req.getTopicFilter());
|
||||
}
|
||||
|
||||
//ack the client
|
||||
SubAckMessage ackMessage = new SubAckMessage();
|
||||
ackMessage.setMessageID(msg.getMessageID());
|
||||
|
||||
//reply with requested qos
|
||||
for(SubscribeMessage.Couple req : msg.subscriptions()) {
|
||||
for (SubscribeMessage.Couple req : msg.subscriptions()) {
|
||||
AbstractMessage.QOSType qos = AbstractMessage.QOSType.values()[req.getQos()];
|
||||
ackMessage.addType(qos);
|
||||
Subscription newSubscription = new Subscription(clientID, req.getTopicFilter(), qos, cleanSession);
|
||||
boolean valid = subscribeSingleTopic(newSubscription, req.getTopicFilter());
|
||||
ackMessage.addType(valid ? qos : AbstractMessage.QOSType.FAILURE);
|
||||
}
|
||||
|
||||
|
||||
LOG.debug("SUBACK for packetID {}", msg.getMessageID());
|
||||
session.write(ackMessage);
|
||||
}
|
||||
|
||||
private void subscribeSingleTopic(Subscription newSubscription, final String topic) {
|
||||
private boolean subscribeSingleTopic(Subscription newSubscription, final String topic) {
|
||||
LOG.info("<{}> subscribed to topic <{}> with QoS {}",
|
||||
newSubscription.getClientId(), topic,
|
||||
AbstractMessage.QOSType.formatQoS(newSubscription.getRequestedQos()));
|
||||
String clientID = newSubscription.getClientId();
|
||||
boolean validTopic = SubscriptionsStore.validate(newSubscription);
|
||||
if (!validTopic) {
|
||||
//send SUBACK with 0x80 for this topic filter
|
||||
return false;
|
||||
}
|
||||
m_sessionsStore.addNewSubscription(newSubscription, clientID);
|
||||
subscriptions.add(newSubscription);
|
||||
|
||||
//scans retained messages to be published to the new subscription
|
||||
Collection<IMessagesStore.StoredMessage> messages = m_messagesStore.searchMatching(new IMatchingCondition() {
|
||||
public boolean match(String key) {
|
||||
return SubscriptionsStore.matchTopics(key, topic);
|
||||
return SubscriptionsStore.matchTopics(key, topic);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -645,6 +645,7 @@ class ProtocolProcessor implements EventHandler<ValueEvent> {
|
||||
m_messagesStore.nextPacketID(newSubscription.getClientId());
|
||||
sendPublish(newSubscription.getClientId(), storedMsg.getTopic(), storedMsg.getQos(), storedMsg.getPayload(), true, packetID);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void disruptorPublish(OutputMessagingEvent msgEvent) {
|
||||
|
||||
+13
@@ -30,6 +30,19 @@ import org.slf4j.LoggerFactory;
|
||||
*/
|
||||
public class SubscriptionsStore {
|
||||
|
||||
/**
|
||||
* Check if the topic filter of the subscription is well formed
|
||||
* */
|
||||
public static boolean validate(Subscription newSubscription) {
|
||||
try {
|
||||
parseTopic(newSubscription.topicFilter);
|
||||
return true;
|
||||
} catch (ParseException pex) {
|
||||
LOG.info("Bad matching topic filter <{}>", newSubscription.topicFilter);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static interface IVisitor<T> {
|
||||
void visit(TreeNode node);
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ public class ProtocolProcessorTest {
|
||||
final static String FAKE_CLIENT_ID2 = "FAKE_456";
|
||||
final static String FAKE_PUBLISHER_ID = "Publisher";
|
||||
final static String FAKE_TOPIC = "/news";
|
||||
final static String BAD_FORMATTED_TOPIC = "#MQTTClient";
|
||||
|
||||
final static String TEST_USER = "fakeuser";
|
||||
final static String TEST_PWD = "fakepwd";
|
||||
@@ -456,6 +457,27 @@ public class ProtocolProcessorTest {
|
||||
assertTrue(subscriptions.contains(expectedSubscription));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSubscribeWithBadFormattedTopic() {
|
||||
SubscribeMessage msg = new SubscribeMessage();
|
||||
msg.addSubscription(new SubscribeMessage.Couple((byte)AbstractMessage.QOSType.MOST_ONE.ordinal(), BAD_FORMATTED_TOPIC));
|
||||
m_session.setAttribute(NettyChannel.ATTR_KEY_CLIENTID, FAKE_CLIENT_ID);
|
||||
m_session.setAttribute(NettyChannel.ATTR_KEY_CLEANSESSION, false);
|
||||
subscriptions.clearAllSubscriptions();
|
||||
assertEquals(0, subscriptions.size());
|
||||
|
||||
//Exercise
|
||||
m_processor.processSubscribe(m_session, msg);
|
||||
|
||||
//Verify
|
||||
assertEquals(0, subscriptions.size());
|
||||
assertTrue(m_receivedMessage instanceof SubAckMessage);
|
||||
List<QOSType> qosSubAcked = ((SubAckMessage) m_receivedMessage).types();
|
||||
assertEquals(1, qosSubAcked.size());
|
||||
assertEquals(QOSType.FAILURE, qosSubAcked.get(0));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testPublishOfRetainedMessage_afterNewSubscription() throws Exception {
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.eclipse.moquette.parser.netty;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import org.eclipse.moquette.proto.messages.AbstractMessage;
|
||||
import org.eclipse.moquette.proto.messages.AbstractMessage.QOSType;
|
||||
import org.eclipse.moquette.proto.messages.SubAckMessage;
|
||||
|
||||
/**
|
||||
@@ -38,8 +39,9 @@ class SubAckEncoder extends DemuxEncoder<SubAckMessage> {
|
||||
buff.writeByte(AbstractMessage.SUBACK << 4 );
|
||||
buff.writeBytes(Utils.encodeRemainingLength(variableHeaderSize));
|
||||
buff.writeShort(message.getMessageID());
|
||||
for (AbstractMessage.QOSType c : message.types()) {
|
||||
buff.writeByte(c.ordinal());
|
||||
for (QOSType c : message.types()) {
|
||||
int qosValue = (c == QOSType.FAILURE) ? qosValue = 0x80 : c.ordinal();
|
||||
buff.writeByte(qosValue);
|
||||
}
|
||||
|
||||
out.writeBytes(buff);
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ public abstract class AbstractMessage {
|
||||
public static final byte DISCONNECT = 14; //Client is Disconnecting
|
||||
|
||||
public static enum QOSType {
|
||||
MOST_ONE, LEAST_ONE, EXACTLY_ONCE, RESERVED;
|
||||
MOST_ONE, LEAST_ONE, EXACTLY_ONCE, RESERVED, FAILURE;
|
||||
|
||||
public static String formatQoS(QOSType qos) {
|
||||
return String.format("%d - %s", qos.ordinal(), qos.name());
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
@Grab(group='org.fusesource.mqtt-client', module='mqtt-client', version='1.10')
|
||||
|
||||
import org.fusesource.mqtt.client.BlockingConnection
|
||||
import org.fusesource.mqtt.client.MQTT
|
||||
import org.fusesource.mqtt.client.Message
|
||||
import org.fusesource.mqtt.client.QoS
|
||||
import org.fusesource.mqtt.client.Topic
|
||||
|
||||
String host = args.size() == 1 ? args[0] : "localhost"
|
||||
|
||||
MQTT mqttSub = new MQTT()
|
||||
mqttSub.setHost(host, 1883)
|
||||
mqttSub.setClientId("Subscriber(A)")
|
||||
mqttSub.cleanSession = false
|
||||
//AT_MOST_ONCE,
|
||||
//AT_LEAST_ONCE,
|
||||
//EXACTLY_ONCE
|
||||
BlockingConnection clientSub = mqttSub.blockingConnection()
|
||||
clientSub.connect()
|
||||
println "Sub connected"
|
||||
Topic[] topics = [new Topic("#MQTTClient", QoS.AT_MOST_ONCE)]
|
||||
byte[] qoses = clientSub.subscribe(topics)
|
||||
println "Sub subscribed"
|
||||
clientSub.disconnect()
|
||||
clientSub.kill()
|
||||
println "Sub disconnected"
|
||||
|
||||
println "Finished!!\n\n"
|
||||
Reference in New Issue
Block a user