Commits

Roger Light committed 50b6405

Fix mosquitto_topic_matches_sub() for subscriptions with + as the final
character. Fixes bug #1085797. Thanks to Shane Hanna.

Comments (0)

Files changed (10)

   simplifies non-threaded client handling.
 - Ignore SIGPIPE to prevent unnecessary client quits in threaded mode.
 - Fix document error for mosquitto_message_retry_set().
+- Fix mosquitto_topic_matches_sub() for subscriptions with + as the final
+  character. Fixes bug #1085797.
 
 Clients:
 - Clients now display their own version number and library version number in

lib/python/mosquitto.py

                 spos += 1
                 while tpos < tlen and local_topic[tpos] != '/':
                     tpos += 1
+                if tpos == tlen and spos == slen:
+                    result = True
+                    break
 
             elif local_sub[spos] == '#':
                 multilevel_wildcard = True
 				while(tpos < tlen && local_topic[tpos] != '/'){
 					tpos++;
 				}
+				if(tpos == tlen && spos == slen){
+					*result = true;
+					break;
+				}
 			}else if(local_sub[spos] == '#'){
 				multilevel_wildcard = true;
 				if(spos+1 != slen){

test/lib/09-util-topic-matching

+#!/usr/bin/python
+
+import inspect
+import os
+import subprocess
+import sys
+import time
+
+# From http://stackoverflow.com/questions/279237/python-import-a-module-from-a-folder
+cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"..")))
+if cmd_subfolder not in sys.path:
+    sys.path.insert(0, cmd_subfolder)
+
+rc = 1
+
+client_args = sys.argv[1:]
+env = dict(os.environ)
+env['LD_LIBRARY_PATH'] = '../../lib:../../lib/cpp'
+try:
+    pp = env['PYTHONPATH']
+except KeyError:
+    pp = ''
+env['PYTHONPATH'] = '../../lib/python:'+pp
+
+client = subprocess.Popen(client_args, env=env)
+client.wait()
+exit(client.returncode)

test/lib/c/09-util-topic-matching.c

+#include <mosquitto.h>
+
+int main(int argc, char *argv[])
+{
+	bool match;
+
+	mosquitto_topic_matches_sub("foo/bar", "foo/bar", &match); if(!match) return 1;
+	mosquitto_topic_matches_sub("foo/+", "foo/bar", &match); if(!match) return 1;
+	mosquitto_topic_matches_sub("foo/+/baz", "foo/bar/baz", &match); if(!match) return 1;
+
+	mosquitto_topic_matches_sub("foo/+/#", "foo/bar/baz", &match); if(!match) return 1;
+	mosquitto_topic_matches_sub("#", "foo/bar/baz", &match); if(!match) return 1;
+
+	mosquitto_topic_matches_sub("foo/bar", "foo", &match); if(match) return 1;
+	mosquitto_topic_matches_sub("foo/+", "foo/bar/baz", &match); if(match) return 1;
+	mosquitto_topic_matches_sub("foo/+/baz", "foo/bar/bar", &match); if(match) return 1;
+
+	mosquitto_topic_matches_sub("foo/+/#", "fo2/bar/baz", &match); if(match) return 1;
+
+	return 0;
+}
+

test/lib/c/Makefile

-.PHONY: all test 01 02 03 04 08 clean reallyclean
+.PHONY: all test 01 02 03 04 08 09 clean reallyclean
 
 CFLAGS=-I../../../lib -Werror
 LIBS=../../../lib/libmosquitto.so.1
 
-all : 01 02 03 04 08
+all : 01 02 03 04 08 09
 
 01-con-discon-success.test : 01-con-discon-success.c
 	$(CC) $< -o $@ $(CFLAGS) $(LIBS)
 08-ssl-bad-cacert.test : 08-ssl-bad-cacert.c
 	$(CC) $< -o $@ $(CFLAGS) $(LIBS)
 
+09-util-topic-matching.test : 09-util-topic-matching.c
+	$(CC) $< -o $@ $(CFLAGS) $(LIBS)
+
 01 : 01-con-discon-success.test 01-will-set.test 01-unpwd-set.test 01-will-unpwd-set.test 01-no-clean-session.test 01-keepalive-pingreq.test
 
 02 : 02-subscribe-qos0.test 02-subscribe-qos1.test 02-subscribe-qos2.test 02-unsubscribe.test
 
 08 : 08-ssl-connect-no-auth.test 08-ssl-connect-cert-auth.test 08-ssl-bad-cacert.test
 
+09 : 09-util-topic-matching.test
+
 reallyclean : clean
 	-rm -f *.orig
 

test/lib/cpp/09-util-topic-matching.cpp

+#include <mosquittopp.h>
+
+int main(int argc, char *argv[])
+{
+	bool match;
+
+	mosqpp::topic_matches_sub("foo/bar", "foo/bar", &match); if(!match) return 1;
+	mosqpp::topic_matches_sub("foo/+", "foo/bar", &match); if(!match) return 1;
+	mosqpp::topic_matches_sub("foo/+/baz", "foo/bar/baz", &match); if(!match) return 1;
+
+	mosqpp::topic_matches_sub("foo/+/#", "foo/bar/baz", &match); if(!match) return 1;
+	mosqpp::topic_matches_sub("#", "foo/bar/baz", &match); if(!match) return 1;
+
+	mosqpp::topic_matches_sub("foo/bar", "foo", &match); if(match) return 1;
+	mosqpp::topic_matches_sub("foo/+", "foo/bar/baz", &match); if(match) return 1;
+	mosqpp::topic_matches_sub("foo/+/baz", "foo/bar/bar", &match); if(match) return 1;
+
+	mosqpp::topic_matches_sub("foo/+/#", "fo2/bar/baz", &match); if(match) return 1;
+
+	return 0;
+}
+

test/lib/cpp/Makefile

-.PHONY: all test 01 02 03 04 08 clean reallyclean
+.PHONY: all test 01 02 03 04 08 09 clean reallyclean
 
 CFLAGS=-I../../../lib -I../../../lib/cpp -DDEBUG -Werror
 LIBS=../../../lib/libmosquitto.so.1 ../../../lib/cpp/libmosquittopp.so.1
 
-all : 01 02 03 04 08
+all : 01 02 03 04 08 09
 
 01-con-discon-success.test : 01-con-discon-success.cpp
 	$(CXX) $< -o $@ $(CFLAGS) $(LIBS)
 08-ssl-bad-cacert.test : 08-ssl-bad-cacert.cpp
 	$(CXX) $< -o $@ $(CFLAGS) $(LIBS)
 
+09-util-topic-matching.test : 09-util-topic-matching.cpp
+	$(CXX) $< -o $@ $(CFLAGS) $(LIBS)
+
 01 : 01-con-discon-success.test 01-will-set.test 01-unpwd-set.test 01-will-unpwd-set.test 01-no-clean-session.test 01-keepalive-pingreq.test
 
 02 : 02-subscribe-qos0.test 02-subscribe-qos1.test 02-subscribe-qos2.test 02-unsubscribe.test
 
 08 : 08-ssl-connect-no-auth.test 08-ssl-connect-cert-auth.test 08-ssl-bad-cacert.test
 
+09 : 09-util-topic-matching.test
+
 reallyclean : clean
 	-rm -f *.orig
 

test/lib/python/09-util-topic-matching.test

+#!/usr/bin/python
+
+# Copyright (c) 2012 Roger Light <roger@atchoo.org>
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+# 1. Redistributions of source code must retain the above copyright notice,
+#   this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# 3. Neither the name of mosquitto nor the names of its
+#   contributors may be used to endorse or promote products derived from
+#   this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+import mosquitto
+import sys
+
+if mosquitto.topic_matches_sub("foo/bar", "foo/bar") == False:
+    sys.exit(1)
+if mosquitto.topic_matches_sub("foo/+", "foo/bar") == False:
+    sys.exit(1)
+if mosquitto.topic_matches_sub("foo/+/baz", "foo/bar/baz") == False:
+    sys.exit(1)
+
+if mosquitto.topic_matches_sub("foo/+/#", "foo/bar/baz") == True:
+    sys.exit(1)
+if mosquitto.topic_matches_sub("#", "foo/bar/baz") == True:
+    sys.exit(1)
+
+if mosquitto.topic_matches_sub("foo/bar", "foo") == True:
+    sys.exit(1)
+if mosquitto.topic_matches_sub("foo/+", "foo/bar/baz") == True:
+    sys.exit(1)
+if mosquitto.topic_matches_sub("foo/+/baz", "foo/bar/bar") == True:
+    sys.exit(1)
+
+if mosquitto.topic_matches_sub("foo/+/#", "fo2/bar/baz") == True:
+    sys.exit(1)
+
+sys.exit(0)

test/lib/python3/09-util-topic-matching.test

+#!/usr/bin/python
+
+# Copyright (c) 2012 Roger Light <roger@atchoo.org>
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 
+# 1. Redistributions of source code must retain the above copyright notice,
+#   this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# 3. Neither the name of mosquitto nor the names of its
+#   contributors may be used to endorse or promote products derived from
+#   this software without specific prior written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+import mosquitto
+import sys
+
+if mosquitto.topic_matches_sub("foo/bar", "foo/bar") == False:
+    sys.exit(1)
+if mosquitto.topic_matches_sub("foo/+", "foo/bar") == False:
+    sys.exit(1)
+if mosquitto.topic_matches_sub("foo/+/baz", "foo/bar/baz") == False:
+    sys.exit(1)
+
+if mosquitto.topic_matches_sub("foo/+/#", "foo/bar/baz") == True:
+    sys.exit(1)
+if mosquitto.topic_matches_sub("#", "foo/bar/baz") == True:
+    sys.exit(1)
+
+if mosquitto.topic_matches_sub("foo/bar", "foo") == True:
+    sys.exit(1)
+if mosquitto.topic_matches_sub("foo/+", "foo/bar/baz") == True:
+    sys.exit(1)
+if mosquitto.topic_matches_sub("foo/+/baz", "foo/bar/bar") == True:
+    sys.exit(1)
+
+if mosquitto.topic_matches_sub("foo/+/#", "fo2/bar/baz") == True:
+    sys.exit(1)
+
+sys.exit(0)