From 1bb98e5e8ee183c2ba9f234ee7a4561b3b97fc2d Mon Sep 17 00:00:00 2001
From: Sergey Lyubka <valenok@gmail.com>
Date: Fri, 25 Apr 2014 18:04:24 +0100
Subject: [PATCH] Exported mg_websocket_printf(), mg_url_encode(). Added unit
 test for mg_url_encode()

---
 examples/unit_test.c | 12 +++++++++
 mongoose.c           | 59 +++++++++++++++++++++++++-------------------
 mongoose.h           |  5 ++++
 3 files changed, 51 insertions(+), 25 deletions(-)

diff --git a/examples/unit_test.c b/examples/unit_test.c
index 3575e7de5..64e350cc6 100644
--- a/examples/unit_test.c
+++ b/examples/unit_test.c
@@ -271,6 +271,17 @@ static const char *test_url_decode(void) {
   return NULL;
 }
 
+static const char *test_url_encode(void) {
+  char buf[100];
+  ASSERT(mg_url_encode("", 0, buf, sizeof(buf)) == 0);
+  ASSERT(buf[0] == '\0');
+  ASSERT(mg_url_encode("foo", 3, buf, sizeof(buf)) == 3);
+  ASSERT(strcmp(buf, "foo") == 0);
+  ASSERT(mg_url_encode("f o", 3, buf, sizeof(buf)) == 5);
+  ASSERT(strcmp(buf, "f%20o") == 0);
+  return NULL;
+}
+
 static const char *test_to64(void) {
   ASSERT(to64("0") == 0);
   ASSERT(to64("") == 0);
@@ -498,6 +509,7 @@ static const char *run_all_tests(void) {
   RUN_TEST(test_parse_http_message);
   RUN_TEST(test_to64);
   RUN_TEST(test_url_decode);
+  RUN_TEST(test_url_encode);
   RUN_TEST(test_base64_encode);
   RUN_TEST(test_mg_parse_header);
   RUN_TEST(test_get_var);
diff --git a/mongoose.c b/mongoose.c
index bd89ac15e..97e15038a 100644
--- a/mongoose.c
+++ b/mongoose.c
@@ -3065,24 +3065,25 @@ static int scan_directory(struct connection *conn, const char *dir,
   return arr_ind;
 }
 
-static void mg_url_encode(const char *src, char *dst, size_t dst_len) {
+int mg_url_encode(const char *src, size_t s_len, char *dst, size_t dst_len) {
   static const char *dont_escape = "._-$,;~()";
   static const char *hex = "0123456789abcdef";
-  const char *end = dst + dst_len - 1;
-
-  for (; *src != '\0' && dst < end; src++, dst++) {
-    if (isalnum(*(const unsigned char *) src) ||
-        strchr(dont_escape, * (const unsigned char *) src) != NULL) {
-      *dst = *src;
-    } else if (dst + 2 < end) {
-      dst[0] = '%';
-      dst[1] = hex[(* (const unsigned char *) src) >> 4];
-      dst[2] = hex[(* (const unsigned char *) src) & 0xf];
-      dst += 2;
+  size_t i = 0, j = 0;
+
+  for (i = j = 0; dst_len > 0 && i < s_len && j < dst_len - 1; i++, j++) {
+    if (isalnum(* (const unsigned char *) (src + i)) ||
+        strchr(dont_escape, * (const unsigned char *) (src + i)) != NULL) {
+      dst[j] = src[i];
+    } else if (j + 3 < dst_len) {
+      dst[j] = '%';
+      dst[j + 1] = hex[(* (const unsigned char *) (src + i)) >> 4];
+      dst[j + 2] = hex[(* (const unsigned char *) (src + i)) & 0xf];
+      j += 2;
     }
   }
 
-  *dst = '\0';
+  dst[j] = '\0';
+  return j;
 }
 #endif  // !NO_DIRECTORY_LISTING || !MONGOOSE_NO_DAV
 
@@ -3110,7 +3111,7 @@ static void print_dir_entry(const struct dir_entry *de) {
     }
   }
   strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime(&de->st.st_mtime));
-  mg_url_encode(de->file_name, href, sizeof(href));
+  mg_url_encode(de->file_name, strlen(de->file_name), href, sizeof(href));
   mg_printf_data(&de->conn->mg_conn,
                   "<tr><td><a href=\"%s%s\">%s%s</a></td>"
                   "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
@@ -3231,7 +3232,7 @@ static void handle_propfind(struct connection *conn, const char *path,
       for (i = 0; i < num_entries; i++) {
         char buf[MAX_PATH_SIZE * 3];
         struct dir_entry *de = &arr[i];
-        mg_url_encode(de->file_name, buf, sizeof(buf) - 1);
+        mg_url_encode(de->file_name, strlen(de->file_name), buf, sizeof(buf));
         print_props(conn, buf, &de->st);
       }
     }
@@ -4306,7 +4307,7 @@ static void iter(struct ns_connection *nsconn, enum ns_event ev, void *param) {
   if (ev == NS_POLL) {
     struct mg_iterator *it = (struct mg_iterator *) param;
     struct connection *c = (struct connection *) nsconn->connection_data;
-    c->mg_conn.callback_param = it->param;
+    if (c != NULL) c->mg_conn.callback_param = it->param;
     it->cb(&c->mg_conn, MG_POLL);
   }
 }
@@ -4572,9 +4573,26 @@ static void mg_ev_handler(struct ns_connection *nc, enum ns_event ev, void *p) {
   struct connection *conn = (struct connection *) nc->connection_data;
   struct mg_server *server = (struct mg_server *) nc->server;
 
+  // Send NS event to the handler. Note that call_user won't send an event
+  // if conn == NULL. Therefore, repeat this for NS_ACCEPT event as well.
+#ifdef MONGOOSE_SEND_NS_EVENTS
+  {
+    struct connection *conn = (struct connection *) nc->connection_data;
+    if (conn != NULL) conn->mg_conn.callback_param = p;
+    call_user(conn, (enum mg_event) ev);
+  }
+#endif
+
   switch (ev) {
     case NS_ACCEPT:
       on_accept(nc, (union socket_address *) p);
+#ifdef MONGOOSE_SEND_NS_EVENTS
+      {
+        struct connection *conn = (struct connection *) nc->connection_data;
+        if (conn != NULL) conn->mg_conn.callback_param = p;
+        call_user(conn, (enum mg_event) ev);
+      }
+#endif
       break;
 
     case NS_CONNECT:
@@ -4653,15 +4671,6 @@ static void mg_ev_handler(struct ns_connection *nc, enum ns_event ev, void *p) {
     default:
       break;
   }
-
-#ifdef MONGOOSE_SEND_NS_EVENTS
-  {
-    struct connection *conn = (struct connection *) nc->connection_data;
-    struct mg_connection *c = conn == NULL ? NULL : &conn->mg_conn;
-    if (c != NULL) c->callback_param = p;
-    if (server->event_handler) server->event_handler(c, (enum mg_event) ev);
-  }
-#endif
 }
 
 void mg_wakeup_server(struct mg_server *server) {
diff --git a/mongoose.h b/mongoose.h
index ac7ceec28..0fd4251de 100644
--- a/mongoose.h
+++ b/mongoose.h
@@ -103,6 +103,8 @@ void mg_printf_data(struct mg_connection *, const char *format, ...);
 
 int mg_websocket_write(struct mg_connection *, int opcode,
                        const char *data, size_t data_len);
+int mg_websocket_printf(struct mg_connection* conn, int opcode,
+                        const char *fmt, ...);
 
 // Deprecated in favor of mg_send_* interface
 int mg_write(struct mg_connection *, const void *buf, int len);
@@ -122,7 +124,10 @@ int mg_parse_multipart(const char *buf, int buf_len,
 void *mg_start_thread(void *(*func)(void *), void *param);
 char *mg_md5(char buf[33], ...);
 int mg_authorize_digest(struct mg_connection *c, FILE *fp);
+int mg_url_encode(const char *src, size_t s_len, char *dst, size_t dst_len);
+int mg_url_decode(const char *src, int src_len, char *dst, int dst_len, int);
 
+// Templates support
 struct mg_expansion {
   const char *keyword;
   void (*handler)(struct mg_connection *);
-- 
GitLab