From 97a19135ceb9ce385e33ba68f3bce40175a311dd Mon Sep 17 00:00:00 2001
From: Tobias Reisinger <tobias@msrg.cc>
Date: Sun, 15 Nov 2020 16:36:44 +0100
Subject: [PATCH] Fix leaks and remove some non-standard functions

---
 include/endpoint.h                          |  5 +++-
 src/config.c                                | 18 ++++++-------
 src/endpoint.c                              | 29 ++++++++++++++++++++-
 src/endpoints/api_v1_controllers_discover.c |  2 +-
 src/handlers/http.c                         | 12 ++++-----
 src/logger.c                                | 24 ++++++++++-------
 6 files changed, 63 insertions(+), 27 deletions(-)

diff --git a/include/endpoint.h b/include/endpoint.h
index ea4ba66..c259938 100644
--- a/include/endpoint.h
+++ b/include/endpoint.h
@@ -24,7 +24,7 @@ typedef struct
     int status_code;
     const char *content_type;
     size_t content_length;
-    const char *content;
+    char *content;
     int alloced_content;
 } endpoint_response_t;
 
@@ -62,4 +62,7 @@ endpoint_response_text(endpoint_response_t *response, int status_code, const cha
 void
 endpoint_response_json(endpoint_response_t *response, int status_code, const cJSON *json_root);
 
+void
+endpoint_response_free_content(endpoint_response_t *response);
+
 #endif /* CORE_ENDPOINT_H */
diff --git a/src/config.c b/src/config.c
index 686fddf..e9cf4bf 100644
--- a/src/config.c
+++ b/src/config.c
@@ -15,43 +15,43 @@ config_t *global_config;
 static int
 config_load_log_level(IniDispatch *disp, config_t *config)
 {
-    if(strcasecmp(disp->value, "debug") == 0)
+    if(strcmp(disp->value, "debug") == 0)
     {
         setlogmask(LOG_UPTO(LOG_DEBUG));
         config->log_level = LOG_DEBUG;
         return 0;
     }
-    if(strcasecmp(disp->value, "info") == 0)
+    if(strcmp(disp->value, "info") == 0)
     {
         setlogmask(LOG_UPTO(LOG_INFO));
         config->log_level = LOG_INFO;
         return 0;
     }
-    if(strcasecmp(disp->value, "notice") == 0)
+    if(strcmp(disp->value, "notice") == 0)
     {
         setlogmask(LOG_UPTO(LOG_NOTICE));
         config->log_level = LOG_NOTICE;
         return 0;
     }
-    if(strcasecmp(disp->value, "warning") == 0)
+    if(strcmp(disp->value, "warning") == 0)
     {
         setlogmask(LOG_UPTO(LOG_WARNING));
         config->log_level = LOG_WARNING;
         return 0;
     }
-    if(strcasecmp(disp->value, "err") == 0)
+    if(strcmp(disp->value, "err") == 0)
     {
         setlogmask(LOG_UPTO(LOG_ERR));
         config->log_level = LOG_ERR;
         return 0;
     }
-    if(strcasecmp(disp->value, "crit") == 0)
+    if(strcmp(disp->value, "crit") == 0)
     {
         setlogmask(LOG_UPTO(LOG_CRIT));
         config->log_level = LOG_CRIT;
         return 0;
     }
-    if(strcasecmp(disp->value, "emerg") == 0)
+    if(strcmp(disp->value, "emerg") == 0)
     {
         setlogmask(LOG_UPTO(LOG_EMERG));
         config->log_level = LOG_EMERG;
@@ -65,12 +65,12 @@ config_load_log_level(IniDispatch *disp, config_t *config)
 static int
 config_load_log_file(IniDispatch *disp, config_t *config)
 {
-    if(strcasecmp(disp->value, "stdout") == 0)
+    if(strcmp(disp->value, "stdout") == 0)
     {
         config->log_file = stdout;
         return 0;
     }
-    if(strcasecmp(disp->value, "stderr") == 0)
+    if(strcmp(disp->value, "stderr") == 0)
     {
         config->log_file = stderr;
         return 0;
diff --git a/src/endpoint.c b/src/endpoint.c
index 4d0ad01..12b7742 100644
--- a/src/endpoint.c
+++ b/src/endpoint.c
@@ -1,3 +1,5 @@
+#include <bsd/string.h>
+
 #include <logger.h>
 #include <cJSON.h>
 #include <mongoose.h>
@@ -33,6 +35,9 @@ endpoint_func_not_found(struct mg_connection *nc, struct http_message *hm, endpo
     else
     {
         LOGGER_DEBUG("404 file not found\n");
+
+        endpoint_response_free_content(response);
+
         response->status_code = 404;
         response->content_type = global_config->not_found_content_type;
         response->content_length = strlen(global_config->not_found_content);
@@ -45,6 +50,8 @@ endpoint_func_not_found(struct mg_connection *nc, struct http_message *hm, endpo
 void
 endpoint_response_msg(endpoint_response_t *response, int status_code, const char *content, int content_length)
 {
+    endpoint_response_free_content(response);
+
     cJSON *json;
 
     json = cJSON_CreateObject();
@@ -66,11 +73,14 @@ endpoint_response_msg(endpoint_response_t *response, int status_code, const char
     cJSON_AddItemToObject(json, "msg", json_msg);
 
     endpoint_response_json(response, status_code, json);
+
+    cJSON_Delete(json);
 }
 
 void
 endpoint_response_text(endpoint_response_t *response, int status_code, const char *content, int content_length)
 {
+    endpoint_response_free_content(response);
     if(content == NULL)
     {
         content = "";
@@ -83,18 +93,24 @@ endpoint_response_text(endpoint_response_t *response, int status_code, const cha
     {
         response->content_length = content_length;
         response->alloced_content = false;
+        response->content = (char*)content;
     }
     else
     {
         response->content_length = strlen(content);
         response->alloced_content = true;
+
+        int content_size = response->content_length + 1;
+
+        response->content = malloc(sizeof(char) * content_size);
+        strlcpy(response->content, content, content_size);
     }
-    response->content = content;
 }
 
 void
 endpoint_response_json(endpoint_response_t *response, int status_code, const cJSON *json_root)
 {
+    endpoint_response_free_content(response);
     if(json_root != NULL)
     {
         char *json_str = cJSON_Print(json_root);
@@ -112,3 +128,14 @@ endpoint_response_json(endpoint_response_t *response, int status_code, const cJS
 
     M_RESPONSE_MSG(LOGGER_ERR, response, 500, "failed to print json");
 }
+
+void
+endpoint_response_free_content(endpoint_response_t *response)
+{
+    if(response->alloced_content)
+    {
+        free(response->content);
+        response->content = NULL;
+        response->alloced_content = false;
+    }
+}
diff --git a/src/endpoints/api_v1_controllers_discover.c b/src/endpoints/api_v1_controllers_discover.c
index d3ad5cd..157ba1d 100644
--- a/src/endpoints/api_v1_controllers_discover.c
+++ b/src/endpoints/api_v1_controllers_discover.c
@@ -172,7 +172,7 @@ api_v1_controllers_discover_PUT(struct mg_connection *nc, struct http_message *h
             continue;
         }
 
-        char *answer_payload = (char*)malloc((payload_length));
+        char *answer_payload = (char*)malloc((payload_length + 1));
         if(recv(client_fd, answer_payload, payload_length, 0) <= 0)
         {
             LOGGER_ERR("error receiving payload from client\n");
diff --git a/src/handlers/http.c b/src/handlers/http.c
index 5ef3bbd..5596f44 100644
--- a/src/handlers/http.c
+++ b/src/handlers/http.c
@@ -45,11 +45,6 @@ send_response(struct mg_connection *nc, endpoint_response_t *response)
 
         free(response_headers);
         free(extra_headers);
-
-        if(response->alloced_content)
-        {
-            free((char*)response->content);
-        }
     }
 }
 
@@ -83,8 +78,10 @@ handle_http_request(struct mg_connection *nc, struct http_message *hm)
     endpoint_t *endpoint = router_find_endpoint(hm->uri.p, hm->uri.len, &hm->method);
 
     endpoint_response_t response;
+    response.content = NULL;
+    response.alloced_content = false;
 
-    M_RESPONSE_MSG(LOGGER_NONE, &response, 500, "server did not create a response");
+    M_RESPONSE_MSG(LOGGER_WARNING, &response, 500, "server did not create a response");
 
     if(!endpoint)
     {
@@ -92,6 +89,7 @@ handle_http_request(struct mg_connection *nc, struct http_message *hm)
         if (!mg_normalize_uri_path(&hm->uri, &hm->uri)) {
             mg_http_send_error(nc, 400, global_config->http_server_opts.extra_headers);
             LOGGER_DEBUG("failed to normalize uri %.*s\n", hm->uri.len, hm->uri.p);
+            endpoint_response_free_content(&response);
             return;
         }
         LOGGER_DEBUG("no endpoint found - serving file\n");
@@ -116,6 +114,7 @@ handle_http_request(struct mg_connection *nc, struct http_message *hm)
             response.status_code = 0;
             mg_serve_http(nc, hm, global_config->http_server_opts);
             LOGGER_DEBUG("serving %.*s\n", hm->uri.len, hm->uri.p);
+            endpoint_response_free_content(&response);
             return;
         }
 
@@ -147,6 +146,7 @@ handle_http_request(struct mg_connection *nc, struct http_message *hm)
         send_response(nc, &response);
     }
 
+    endpoint_response_free_content(&response);
     LOGGER_DEBUG("freeing endpoint args\n");
     for(int i = 0; i < endpoint->args_count; ++i)
     {
diff --git a/src/logger.c b/src/logger.c
index 7b22049..0a03418 100644
--- a/src/logger.c
+++ b/src/logger.c
@@ -21,6 +21,7 @@ logger_log(int level, const char *filename, int line, const char *func, const ch
     {
         return;
     }
+    va_list args;
     const char *level_str;
     const char *color;
 
@@ -62,23 +63,28 @@ logger_log(int level, const char *filename, int line, const char *func, const ch
     time_t rawtime;
     time(&rawtime);
     strftime(timestamp_str, 32, "%Y-%m-%d %H:%M:%S", localtime(&rawtime));
+    size_t timestamp_len = strlen(timestamp_str);
 
-    char *buffer = malloc(sizeof(char) * (128 + strlen(msg)));
-    sprintf(buffer, "%s[%5s] %s:%d:%s " COLOR_NONE "%s", color, level_str, filename, line, func, msg);
+    char *buffer = malloc(sizeof(char) * (128 + strlen(msg) + timestamp_len));
+    sprintf(buffer, "%s %s[%5s] %s:%d:%s " COLOR_NONE "%s", timestamp_str, color, level_str, filename, line, func, msg);
 
-    va_list args;
+    // start arg va_list and find log_len
     va_start(args, msg);
-    vsyslog(level, buffer, args);
+    size_t log_len = vsnprintf(NULL, 0, buffer, args); // NOLINT(clang-analyzer-valist.Uninitialized): clang-tidy bug
     va_end(args);
 
-    char *buffer_timed = malloc(sizeof(char) * (strlen(timestamp_str) + strlen(buffer) + 2));
-    sprintf(buffer_timed, "%s %s", timestamp_str, buffer);
+    char *log_line = malloc(sizeof(char) * (log_len + 1));
 
+    // start arg va_list again and write log_line
     va_start(args, msg);
-    vfprintf(global_config->log_file, buffer_timed, args); // NOLINT(clang-analyzer-valist.Uninitialized): clang-tidy bug
+    vsprintf(log_line, buffer, args); // NOLINT(clang-analyzer-valist.Uninitialized): clang-tidy bug
+    va_end(args);
+
+    syslog(level, "%s", log_line + timestamp_len + 1);
+
+    fprintf(global_config->log_file, "%s", log_line);
     fflush(global_config->log_file);
-    va_end(args);
 
     free(buffer);
-    free(buffer_timed);
+    free(log_line);
 }