diff --git a/ChangeLog.txt b/ChangeLog.txt index 51f94aad1d..3448f9a07d 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -4,6 +4,11 @@ Broker: - Fix bridge not respecting receive-maximum when reconnecting with MQTT v5. +Client library: +- Fix mosquitto_topic_matches_sub2() not using the length parameters. + Closes #2364. + + 2.0.13 - 2021-10-27 =================== diff --git a/lib/util_topic.c b/lib/util_topic.c index 62b531127c..e29102f739 100644 --- a/lib/util_topic.c +++ b/lib/util_topic.c @@ -189,19 +189,11 @@ int mosquitto_sub_topic_check2(const char *str, size_t len) return MOSQ_ERR_SUCCESS; } -int mosquitto_topic_matches_sub(const char *sub, const char *topic, bool *result) -{ - return mosquitto_topic_matches_sub2(sub, 0, topic, 0, result); -} - /* Does a topic match a subscription? */ -int mosquitto_topic_matches_sub2(const char *sub, size_t sublen, const char *topic, size_t topiclen, bool *result) +int mosquitto_topic_matches_sub(const char *sub, const char *topic, bool *result) { size_t spos; - UNUSED(sublen); - UNUSED(topiclen); - if(!result) return MOSQ_ERR_INVAL; *result = false; @@ -325,3 +317,130 @@ int mosquitto_topic_matches_sub2(const char *sub, size_t sublen, const char *top return MOSQ_ERR_SUCCESS; } + +/* Does a topic match a subscription? */ +int mosquitto_topic_matches_sub2(const char *sub, size_t sublen, const char *topic, size_t topiclen, bool *result) +{ + size_t spos, tpos; + + if(!result) return MOSQ_ERR_INVAL; + *result = false; + + if(!sub || !topic || !sublen || !topiclen){ + return MOSQ_ERR_INVAL; + } + + if((sub[0] == '$' && topic[0] != '$') + || (topic[0] == '$' && sub[0] != '$')){ + + return MOSQ_ERR_SUCCESS; + } + + spos = 0; + tpos = 0; + + while(spos < sublen){ + if(tpos < topiclen && (topic[tpos] == '+' || topic[tpos] == '#')){ + return MOSQ_ERR_INVAL; + } + if(tpos == topiclen || sub[spos] != topic[tpos]){ + if(sub[spos] == '+'){ + /* Check for bad "+foo" or "a/+foo" subscription */ + if(spos > 0 && sub[spos-1] != '/'){ + return MOSQ_ERR_INVAL; + } + /* Check for bad "foo+" or "foo+/a" subscription */ + if(spos+1 < sublen && sub[spos+1] != '/'){ + return MOSQ_ERR_INVAL; + } + spos++; + while(tpos < topiclen && topic[tpos] != '/'){ + if(topic[tpos] == '+' || topic[tpos] == '#'){ + return MOSQ_ERR_INVAL; + } + tpos++; + } + if(tpos == topiclen && spos == sublen){ + *result = true; + return MOSQ_ERR_SUCCESS; + } + }else if(sub[spos] == '#'){ + /* Check for bad "foo#" subscription */ + if(spos > 0 && sub[spos-1] != '/'){ + return MOSQ_ERR_INVAL; + } + /* Check for # not the final character of the sub, e.g. "#foo" */ + if(spos+1 < sublen){ + return MOSQ_ERR_INVAL; + }else{ + while(tpos < topiclen){ + if(topic[tpos] == '+' || topic[tpos] == '#'){ + return MOSQ_ERR_INVAL; + } + tpos++; + } + *result = true; + return MOSQ_ERR_SUCCESS; + } + }else{ + /* Check for e.g. foo/bar matching foo/+/# */ + if(tpos == topiclen + && spos > 0 + && sub[spos-1] == '+' + && sub[spos] == '/' + && spos+1 < sublen + && sub[spos+1] == '#') + { + *result = true; + return MOSQ_ERR_SUCCESS; + } + + /* There is no match at this point, but is the sub invalid? */ + while(spos < sublen){ + if(sub[spos] == '#' && spos+1 < sublen){ + return MOSQ_ERR_INVAL; + } + spos++; + } + + /* Valid input, but no match */ + return MOSQ_ERR_SUCCESS; + } + }else{ + /* sub[spos] == topic[tpos] */ + if(tpos+1 == topiclen){ + /* Check for e.g. foo matching foo/# */ + if(spos+3 == sublen + && sub[spos+1] == '/' + && sub[spos+2] == '#'){ + *result = true; + return MOSQ_ERR_SUCCESS; + } + } + spos++; + tpos++; + if(spos == sublen && tpos == topiclen){ + *result = true; + return MOSQ_ERR_SUCCESS; + }else if(tpos == topiclen && sub[spos] == '+' && spos+1 == sublen){ + if(spos > 0 && sub[spos-1] != '/'){ + return MOSQ_ERR_INVAL; + } + spos++; + *result = true; + return MOSQ_ERR_SUCCESS; + } + } + } + if(tpos < topiclen || spos < sublen){ + *result = false; + } + while(tpos < topiclen){ + if(topic[tpos] == '+' || topic[tpos] == '#'){ + return MOSQ_ERR_INVAL; + } + tpos++; + } + + return MOSQ_ERR_SUCCESS; +} diff --git a/test/unit/util_topic_test.c b/test/unit/util_topic_test.c index b669fcc9c4..df5ee6971d 100644 --- a/test/unit/util_topic_test.c +++ b/test/unit/util_topic_test.c @@ -11,6 +11,16 @@ static void match_helper(const char *sub, const char *topic) rc = mosquitto_topic_matches_sub(sub, topic, &match); CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); CU_ASSERT_EQUAL(match, true); + if(match == false){ + printf("1: %s:%s\n", sub, topic); + } + + rc = mosquitto_topic_matches_sub2(sub, strlen(sub), topic, strlen(topic), &match); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_EQUAL(match, true); + if(match == false){ + printf("2: %s:%s\n", sub, topic); + } } static void no_match_helper(int rc_expected, const char *sub, const char *topic) @@ -24,6 +34,13 @@ static void no_match_helper(int rc_expected, const char *sub, const char *topic) printf("%d:%d %s:%s\n", rc, rc_expected, sub, topic); } CU_ASSERT_EQUAL(match, false); + + rc = mosquitto_topic_matches_sub2(sub, strlen(sub), topic, strlen(topic), &match); + CU_ASSERT_EQUAL(rc, rc_expected); + if(rc != rc_expected){ + printf("%d:%d %s:%s\n", rc, rc_expected, sub, topic); + } + CU_ASSERT_EQUAL(match, false); } /* ========================================================================