add: endpoint /tags
fix: leaks from config (now using static length for config strings)
This commit is contained in:
parent
0f1cd9c02c
commit
a78815cb32
10 changed files with 147 additions and 16 deletions
5
config.c
5
config.c
|
@ -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
35
endpoints/api_v1_tags.c
Normal 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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
||||||
|
|
9
include/endpoints/api_v1_tags.h
Normal file
9
include/endpoints/api_v1_tags.h
Normal 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 */
|
|
@ -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
9
main.c
|
@ -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);
|
||||||
|
|
44
models/tag.c
44
models/tag.c
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
4
router.c
4
router.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
34
tests/tavern_utils/validate_tag.py
Normal file
34
tests/tavern_utils/validate_tag.py
Normal 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"
|
Loading…
Reference in a new issue