add: endpoint /tags

fix: leaks from config (now using static length for config strings)
This commit is contained in:
Tobias Reisinger 2020-06-13 19:21:32 +02:00
parent 0f1cd9c02c
commit a78815cb32
10 changed files with 147 additions and 16 deletions

View file

@ -61,31 +61,26 @@ config_load(IniDispatch *disp, void *config_void)
} }
if(CONFINI_IS_KEY("core", "database")) if(CONFINI_IS_KEY("core", "database"))
{ {
config->database = malloc(sizeof(char) * (strlen(disp->value) + 1));
strcpy(config->database, disp->value); strcpy(config->database, disp->value);
return 0; return 0;
} }
if(CONFINI_IS_KEY("core", "not-found-file")) if(CONFINI_IS_KEY("core", "not-found-file"))
{ {
config->not_found_file = malloc(sizeof(char) * (strlen(disp->value) + 1));
strcpy(config->not_found_file, disp->value); strcpy(config->not_found_file, disp->value);
return 0; return 0;
} }
if(CONFINI_IS_KEY("core", "not-found-file-type")) if(CONFINI_IS_KEY("core", "not-found-file-type"))
{ {
config->not_found_file_type = malloc(sizeof(char) * (strlen(disp->value) + 1));
strcpy(config->not_found_file_type, disp->value); strcpy(config->not_found_file_type, disp->value);
return 0; return 0;
} }
if(CONFINI_IS_KEY("core", "not-found-content")) if(CONFINI_IS_KEY("core", "not-found-content"))
{ {
config->not_found_content = malloc(sizeof(char) * (strlen(disp->value) + 1));
strcpy(config->not_found_content, disp->value); strcpy(config->not_found_content, disp->value);
return 0; return 0;
} }
if(CONFINI_IS_KEY("core", "not-found-content-type")) if(CONFINI_IS_KEY("core", "not-found-content-type"))
{ {
config->not_found_content_type = malloc(sizeof(char) * (strlen(disp->value) + 1));
strcpy(config->not_found_content_type, disp->value); strcpy(config->not_found_content_type, disp->value);
return 0; return 0;
} }

35
endpoints/api_v1_tags.c Normal file
View file

@ -0,0 +1,35 @@
#include <cJSON.h>
#include <macros.h>
#include <constants.h>
#include <endpoints/api_v1_tags.h>
#include <logger.h>
#include <models/tag.h>
void
api_v1_tags_GET(struct mg_connection *nc, struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response)
{
(void)args;
(void)hm;
(void)nc;
char** all_tags = tag_get_all();
cJSON *json = cJSON_CreateArray();
for(int i = 0; all_tags[i] != NULL; ++i)
{
cJSON *json_tag = cJSON_CreateString(all_tags[i]);
if (json_tag == NULL)
{
LOG_DEBUG("failed to add tag from string '%s'\n", all_tags[i]);
free(all_tags[i]);
continue;
}
cJSON_AddItemToArray(json, json_tag);
free(all_tags[i]);
}
endpoint_response_json(response, 200, json);
cJSON_Delete(json);
free(all_tags);
}

View file

@ -25,15 +25,15 @@ typedef enum
typedef struct typedef struct
{ {
char *file; char *file;
char *database; char database[256];
log_level_t log_level; log_level_t log_level;
run_type_t run_type; run_type_t run_type;
char server_port[6]; char server_port[6];
uint16_t discovery_port; uint16_t discovery_port;
char *not_found_file; char not_found_file[256];
char *not_found_file_type; char not_found_file_type[256];
char *not_found_content; char not_found_content[256];
char *not_found_content_type; char not_found_content_type[256];
struct mg_serve_http_opts http_server_opts; struct mg_serve_http_opts http_server_opts;
} config_t; } config_t;

View file

@ -0,0 +1,9 @@
#ifndef CORE_ENDPOINTS_API_V1_TAGS_H
#define CORE_ENDPOINTS_API_V1_TAGS_H
#include <router.h>
void
api_v1_tags_GET(struct mg_connection *nc, struct http_message *hm, endpoint_args_t *args, endpoint_response_t *response);
#endif /* CORE_ENDPOINTS_API_V1_TAGS_H */

View file

@ -10,8 +10,10 @@ tag_remove(int id);
char* char*
tag_get_tag(int id); tag_get_tag(int id);
char**
tag_get_all();
int int
tag_get_id(const char* tag); tag_get_id(const char* tag);
#endif /* CORE_MODELS_TAG_H */ #endif /* CORE_MODELS_TAG_H */

9
main.c
View file

@ -25,8 +25,6 @@ terminate(int signum)
sqlite3_close(global_database); sqlite3_close(global_database);
free(global_config.database);
router_free(); router_free();
exit(signum); exit(signum);
@ -51,9 +49,10 @@ main(int argc, const char** argv)
/******************** LOAD CONFIG ********************/ /******************** LOAD CONFIG ********************/
global_config.file = "core.ini"; global_config.file = "core.ini";
global_config.not_found_file = "404.html"; strcpy(global_config.not_found_file, "404.html");
global_config.not_found_content = "404 - NOT FOUND"; strcpy(global_config.not_found_file_type, "text/html");
global_config.not_found_content_type = "text/plain"; strcpy(global_config.not_found_content, "404 - NOT FOUND");
strcpy(global_config.not_found_content_type, "text/plain");
global_config.log_level = LOG_LEVEL_INFO; global_config.log_level = LOG_LEVEL_INFO;
helper_parse_cli(argc, argv, &global_config); helper_parse_cli(argc, argv, &global_config);

View file

@ -77,6 +77,50 @@ tag_get_tag(int id)
return result; return result;
} }
char**
tag_get_all()
{
sqlite3_stmt *stmt;
sqlite3_prepare_v2(global_database, "SELECT tag FROM tags;", -1, &stmt, NULL);
char **all_tags = malloc(sizeof(char*));
int row = 0;
while(true)
{
int s;
s = sqlite3_step(stmt);
if (s == SQLITE_ROW)
{
const char *new_tag = (const char *)sqlite3_column_text(stmt, 0);
int new_tag_len = strlen(new_tag);
row++;
all_tags = (char**)realloc(all_tags, sizeof(char*) * (row + 1));
all_tags[row - 1] = malloc(sizeof(char) * (new_tag_len + 1));
strcpy(all_tags[row - 1], new_tag);
}
else
{
if(s == SQLITE_DONE)
{
break;
}
else
{
LOG_ERROR("error selecting tags from database: %s\n", sqlite3_errstr(s));
break;
}
}
}
sqlite3_finalize(stmt);
all_tags[row] = NULL;
return all_tags;
}
int int
tag_get_id(const char *tag) tag_get_id(const char *tag)
{ {

View file

@ -8,6 +8,7 @@
#include <endpoints/api_v1_schedules.h> #include <endpoints/api_v1_schedules.h>
#include <endpoints/api_v1_controllers.h> #include <endpoints/api_v1_controllers.h>
#include <endpoints/api_v1_relays.h> #include <endpoints/api_v1_relays.h>
#include <endpoints/api_v1_tags.h>
static endpoint_t endpoints[ROUTER_ENDPOINTS_MAX_COUNT]; static endpoint_t endpoints[ROUTER_ENDPOINTS_MAX_COUNT];
static endpoint_t endpoint_not_found; static endpoint_t endpoint_not_found;
@ -75,6 +76,8 @@ router_init()
router_register_endpoint("/api/v1/relays/", HTTP_METHOD_GET, api_v1_relays_GET); router_register_endpoint("/api/v1/relays/", HTTP_METHOD_GET, api_v1_relays_GET);
router_register_endpoint("/api/v1/relays/tag/{str}", HTTP_METHOD_GET, api_v1_relays_tag_STR_GET); router_register_endpoint("/api/v1/relays/tag/{str}", HTTP_METHOD_GET, api_v1_relays_tag_STR_GET);
router_register_endpoint("/api/v1/tags/", HTTP_METHOD_GET, api_v1_tags_GET);
} }
endpoint_t* endpoint_t*
@ -304,6 +307,7 @@ router_find_endpoint(const char *uri_str, size_t uri_len, struct mg_str *method_
if(best_endpoint == NULL) if(best_endpoint == NULL)
{ {
free(uri);
return NULL; return NULL;
} }

View file

@ -97,3 +97,12 @@ stages:
number: !int "{returned_number:d}" number: !int "{returned_number:d}"
controller_id: "{returned_id}" controller_id: "{returned_id}"
tag: "{returned_tag}" tag: "{returned_tag}"
- name: "[tags] get tags"
request:
method: GET
url: "http://localhost:5000/api/v1/tags/"
response:
status_code: 200
verify_response_with:
function: validate_tag:multiple

View file

@ -0,0 +1,34 @@
import json
def _verify_single(tag):
assert isinstance(tag, str), "tag is not a string"
def single(response):
_verify_single(response.json())
def multiple(response):
assert isinstance(response.json(), list), "response is not a list"
for tag in response.json():
_verify_single(tag)
#def find(response, name=None, number=None, controller_id=None, tag=None):
# print(response.json())
# for tag in response.json():
# if number != None and number != tag.get("number"):
# continue
#
# if name != None and name != tag.get("name"):
# continue
#
# if controller_id != None and controller_id != tag.get("controller_id"):
# continue
#
# if tag != None:
# found_in_response = False
# for response_tag in tag.get("tags"):
# if response_tag == tag:
# found_in_response = True
# if not found_in_response:
# continue
# return
# assert False, "tag not found in list"