From 3942914945d13316b72d5d9057479c9a8cbdeb06 Mon Sep 17 00:00:00 2001
From: Dmitry Frank <mail@dmitryfrank.com>
Date: Fri, 24 Feb 2017 14:10:58 +0000
Subject: [PATCH] Fix subscription to wildcard topics

`mg_mqtt_match_topic_expression()` and friends are public now.

So far, only `#` is supported.

PUBLISHED_FROM=20c031bcf34be84771c4a9c456318634eb9a517c
---
 docs/c-api/mqtt.h/intro.md                    |  2 +
 .../mqtt.h/mg_mqtt_match_topic_expression.md  | 12 ++++++
 .../mqtt.h/mg_mqtt_vmatch_topic_expression.md | 11 ++++++
 mongoose.c                                    | 39 ++++++++-----------
 mongoose.h                                    | 13 +++++++
 5 files changed, 55 insertions(+), 22 deletions(-)
 create mode 100644 docs/c-api/mqtt.h/mg_mqtt_match_topic_expression.md
 create mode 100644 docs/c-api/mqtt.h/mg_mqtt_vmatch_topic_expression.md

diff --git a/docs/c-api/mqtt.h/intro.md b/docs/c-api/mqtt.h/intro.md
index 5ae849aa3..bb5d31b43 100644
--- a/docs/c-api/mqtt.h/intro.md
+++ b/docs/c-api/mqtt.h/intro.md
@@ -5,6 +5,7 @@ decl_name: "mqtt.h"
 items:
   - { name: mg_mqtt_connack.md }
   - { name: mg_mqtt_disconnect.md }
+  - { name: mg_mqtt_match_topic_expression.md }
   - { name: mg_mqtt_next_subscribe_topic.md }
   - { name: mg_mqtt_ping.md }
   - { name: mg_mqtt_pong.md }
@@ -17,6 +18,7 @@ items:
   - { name: mg_mqtt_subscribe.md }
   - { name: mg_mqtt_unsuback.md }
   - { name: mg_mqtt_unsubscribe.md }
+  - { name: mg_mqtt_vmatch_topic_expression.md }
   - { name: mg_send_mqtt_handshake.md }
   - { name: mg_send_mqtt_handshake_opt.md }
   - { name: mg_set_protocol_mqtt.md }
diff --git a/docs/c-api/mqtt.h/mg_mqtt_match_topic_expression.md b/docs/c-api/mqtt.h/mg_mqtt_match_topic_expression.md
new file mode 100644
index 000000000..81575b47f
--- /dev/null
+++ b/docs/c-api/mqtt.h/mg_mqtt_match_topic_expression.md
@@ -0,0 +1,12 @@
+---
+title: "mg_mqtt_match_topic_expression()"
+decl_name: "mg_mqtt_match_topic_expression"
+symbol_kind: "func"
+signature: |
+  int mg_mqtt_match_topic_expression(struct mg_str exp, struct mg_str topic);
+---
+
+Matches a topic against a topic expression
+
+Returns 1 if it matches; 0 otherwise. 
+
diff --git a/docs/c-api/mqtt.h/mg_mqtt_vmatch_topic_expression.md b/docs/c-api/mqtt.h/mg_mqtt_vmatch_topic_expression.md
new file mode 100644
index 000000000..4b0a42315
--- /dev/null
+++ b/docs/c-api/mqtt.h/mg_mqtt_vmatch_topic_expression.md
@@ -0,0 +1,11 @@
+---
+title: "mg_mqtt_vmatch_topic_expression()"
+decl_name: "mg_mqtt_vmatch_topic_expression"
+symbol_kind: "func"
+signature: |
+  int mg_mqtt_vmatch_topic_expression(const char *exp, struct mg_str topic);
+---
+
+Same as `mg_mqtt_match_topic_expression()`, but takes `exp` as a
+NULL-terminated string. 
+
diff --git a/mongoose.c b/mongoose.c
index 0bda1e291..b5ba29a8b 100644
--- a/mongoose.c
+++ b/mongoose.c
@@ -9703,6 +9703,21 @@ static void mg_mqtt_proto_data_destructor(void *proto_data) {
   MG_FREE(proto_data);
 }
 
+int mg_mqtt_match_topic_expression(struct mg_str exp, struct mg_str topic) {
+  /* TODO(mkm): implement real matching */
+  if (memchr(exp.p, '#', exp.len)) {
+    exp.len -= 2;
+    if (topic.len < exp.len) {
+      exp.len = topic.len;
+    }
+  }
+  return strncmp(topic.p, exp.p, exp.len) == 0;
+}
+
+int mg_mqtt_vmatch_topic_expression(const char *exp, struct mg_str topic) {
+  return mg_mqtt_match_topic_expression(mg_mk_str(exp), topic);
+}
+
 void mg_set_protocol_mqtt(struct mg_connection *nc) {
   nc->proto_handler = mqtt_handler;
   nc->proto_data = MG_CALLOC(1, sizeof(struct mg_mqtt_proto_data));
@@ -10040,26 +10055,6 @@ static void mg_mqtt_broker_handle_subscribe(struct mg_connection *nc,
   mg_mqtt_suback(nc, qoss, qoss_len, msg->message_id);
 }
 
-/*
- * Matches a topic against a topic expression
- *
- * See http://goo.gl/iWk21X
- *
- * Returns 1 if it matches; 0 otherwise.
- */
-static int mg_mqtt_match_topic_expression(const char *exp,
-                                          const struct mg_str *topic) {
-  /* TODO(mkm): implement real matching */
-  size_t len = strlen(exp);
-  if (strchr(exp, '#')) {
-    len -= 2;
-    if (topic->len < len) {
-      len = topic->len;
-    }
-  }
-  return strncmp(topic->p, exp, len) == 0;
-}
-
 static void mg_mqtt_broker_handle_publish(struct mg_mqtt_broker *brk,
                                           struct mg_mqtt_message *msg) {
   struct mg_mqtt_session *s;
@@ -10067,8 +10062,8 @@ static void mg_mqtt_broker_handle_publish(struct mg_mqtt_broker *brk,
 
   for (s = mg_mqtt_next(brk, NULL); s != NULL; s = mg_mqtt_next(brk, s)) {
     for (i = 0; i < s->num_subscriptions; i++) {
-      if (mg_mqtt_match_topic_expression(s->subscriptions[i].topic,
-                                         &msg->topic)) {
+      if (mg_mqtt_vmatch_topic_expression(s->subscriptions[i].topic,
+                                          msg->topic)) {
         char buf[100], *p = buf;
         mg_asprintf(&p, sizeof(buf), "%.*s", (int) msg->topic.len,
                     msg->topic.p);
diff --git a/mongoose.h b/mongoose.h
index 1ec11e512..2933d48ad 100644
--- a/mongoose.h
+++ b/mongoose.h
@@ -5152,6 +5152,19 @@ void mg_mqtt_pong(struct mg_connection *nc);
 int mg_mqtt_next_subscribe_topic(struct mg_mqtt_message *msg,
                                  struct mg_str *topic, uint8_t *qos, int pos);
 
+/*
+ * Matches a topic against a topic expression
+ *
+ * Returns 1 if it matches; 0 otherwise.
+ */
+int mg_mqtt_match_topic_expression(struct mg_str exp, struct mg_str topic);
+
+/*
+ * Same as `mg_mqtt_match_topic_expression()`, but takes `exp` as a
+ * NULL-terminated string.
+ */
+int mg_mqtt_vmatch_topic_expression(const char *exp, struct mg_str topic);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
-- 
GitLab