add: OPTIONS method support

add: relay tag endpoint
This commit is contained in:
Tobias Reisinger 2020-05-14 01:37:08 +02:00
parent dab106c1f6
commit 420bdeb2aa
6 changed files with 158 additions and 26 deletions

View file

@ -0,0 +1,57 @@
#include <cJSON.h>
#include <constants.h>
#include <endpoints/api_v1_relays.h>
#include <logger.h>
#include <models/junction_tag.h>
#include <models/relay.h>
#include <models/tag.h>
void
api_v1_relays_tag_STR_GET(struct mg_connection *c, endpoint_args_t *args, struct http_message *hm)
{
(void)hm;
int tag_id = tag_get_id(args[0].value.v_str);
int *relays_ids = junction_tag_get_relays_for_tag_id(tag_id);
if(relays_ids == NULL)
{
LOG_ERROR("failed to print relays json\n");
mg_send_head(c, 500, 2, "Content-Type: application/json\r\n" STANDARD_HEADERS);
mg_printf(c, "[]");
return;
}
cJSON *json = cJSON_CreateArray();
for(int i = 0; relays_ids[i] != 0; ++i)
{
relay_t* relay = relay_get_by_id(relays_ids[i]);
if(!relay)
{
continue;
}
cJSON *json_relay = relay_to_json(relay);
cJSON_AddItemToArray(json, json_relay);
relay_free(relay);
}
char *json_str = cJSON_Print(json);
if (json_str == NULL)
{
LOG_ERROR("failed to print relays json\n");
mg_send_head(c, 500, 2, "Content-Type: application/json\r\n" STANDARD_HEADERS);
mg_printf(c, "[]");
}
else
{
mg_send_head(c, 200, strlen(json_str), "Content-Type: application/json\r\n" STANDARD_HEADERS);
mg_printf(c, "%s", json_str);
free(json_str);
}
cJSON_Delete(json);
free(relays_ids);
}

View file

@ -1,3 +1,4 @@
#include <constants.h>
#include <mongoose.h> #include <mongoose.h>
#include <logger.h> #include <logger.h>
#include <router.h> #include <router.h>
@ -13,7 +14,7 @@ handler_connection(struct mg_connection *c, int ev, void *p)
endpoint_t *endpoint = router_find_endpoint(hm->uri.p, hm->uri.len, &hm->method); endpoint_t *endpoint = router_find_endpoint(hm->uri.p, hm->uri.len, &hm->method);
if(endpoint && endpoint->func) if(endpoint)
{ {
if(endpoint->func) if(endpoint->func)
{ {
@ -28,10 +29,24 @@ handler_connection(struct mg_connection *c, int ev, void *p)
} }
} }
else else
{
if(endpoint->method == HTTP_METHOD_OPTIONS)
{
char options_header[256]; // TODO make more generic
sprintf(options_header, "Allow: OPTIONS%s%s%s%s\r\n" STANDARD_HEADERS,
endpoint->options & HTTP_METHOD_GET ? ", GET" : "",
endpoint->options & HTTP_METHOD_POST ? ", POST" : "",
endpoint->options & HTTP_METHOD_PUT ? ", PUT" : "",
endpoint->options & HTTP_METHOD_DELETE ? ", DELETE" : ""
);
mg_send_head(c, 204, 0, options_header);
}
else
{ {
mg_send_head(c, 501, 0, "Content-Type: text/plain"); mg_send_head(c, 501, 0, "Content-Type: text/plain");
} }
} }
}
else else
{ {
mg_send_head(c, 500, 0, "Content-Type: text/plain"); mg_send_head(c, 500, 0, "Content-Type: text/plain");

View file

@ -6,4 +6,7 @@
void void
api_v1_relays_GET(struct mg_connection *c, endpoint_args_t *args, struct http_message *hm); api_v1_relays_GET(struct mg_connection *c, endpoint_args_t *args, struct http_message *hm);
void
api_v1_relays_tag_STR_GET(struct mg_connection *c, endpoint_args_t *args, struct http_message *hm);
#endif /* CORE_ENDPOINTS_API_V1_RELAYS_H */ #endif /* CORE_ENDPOINTS_API_V1_RELAYS_H */

View file

@ -3,7 +3,7 @@
#include <mongoose.h> #include <mongoose.h>
#define ENDPOINTS_MAX_COUNT 16 #define ENDPOINTS_MAX_COUNT 128
typedef enum typedef enum
{ {
@ -11,6 +11,15 @@ typedef enum
ENDPOINT_ARG_TYPE_STR ENDPOINT_ARG_TYPE_STR
} endpoint_arg_type_e; } endpoint_arg_type_e;
typedef enum
{
HTTP_METHOD_GET = (1 << 0),
HTTP_METHOD_POST = (1 << 1),
HTTP_METHOD_PUT = (1 << 2),
HTTP_METHOD_DELETE = (1 << 3),
HTTP_METHOD_OPTIONS = (1 << 4)
} http_method_e;
typedef struct typedef struct
{ {
endpoint_arg_type_e type; endpoint_arg_type_e type;
@ -25,10 +34,13 @@ typedef void (*endpoint_func_f)(struct mg_connection *c, endpoint_args_t *args,
typedef struct typedef struct
{ {
const char *full_route;
char **route; char **route;
char *route_keeper; char *route_keeper;
int methods; int method;
int options;
endpoint_func_f func; endpoint_func_f func;
int trailing_slash;
int args_count; int args_count;
endpoint_args_t *args; endpoint_args_t *args;
@ -40,11 +52,11 @@ typedef struct
void void
router_init(); router_init();
void endpoint_t*
router_register_endpoint(const char *route, int methods, endpoint_func_f func); router_register_endpoint(const char *route, int method, endpoint_func_f func);
endpoint_t* endpoint_t*
router_find_endpoint(const char *uri_str, size_t uri_len, struct mg_str *method); router_find_endpoint(const char *uri_str, size_t uri_len, struct mg_str *method_str);
void void
router_free(); router_free();

View file

@ -7,12 +7,6 @@
#include <endpoints/api_v1_controllers.h> #include <endpoints/api_v1_controllers.h>
#include <endpoints/api_v1_relays.h> #include <endpoints/api_v1_relays.h>
static const int HTTP_METHOD_GET = (1 << 0);
static const int HTTP_METHOD_POST = (1 << 1);
static const int HTTP_METHOD_PUT = (1 << 2);
static const int HTTP_METHOD_DELETE = (1 << 3);
static const int HTTP_METHOD_OPTIONS = (1 << 4);
static endpoint_t endpoints[ENDPOINTS_MAX_COUNT]; static endpoint_t endpoints[ENDPOINTS_MAX_COUNT];
static endpoint_t endpoint_index; static endpoint_t endpoint_index;
static endpoint_t endpoint_not_found; static endpoint_t endpoint_not_found;
@ -37,29 +31,55 @@ endpoint_not_found_func(struct mg_connection *c, endpoint_args_t *args, struct h
mg_printf(c, "not found"); mg_printf(c, "not found");
} }
static struct mg_str
get_method_str_for_int(int method_int)
{
if(method_int == HTTP_METHOD_GET)
{
return mg_mk_str("GET");
}
if(method_int == HTTP_METHOD_POST)
{
return mg_mk_str("POST");
}
if(method_int == HTTP_METHOD_PUT)
{
return mg_mk_str("PUT");
}
if(method_int == HTTP_METHOD_DELETE)
{
return mg_mk_str("DELETE");
}
if(method_int == HTTP_METHOD_OPTIONS)
{
return mg_mk_str("OPTIONS");
}
return mg_mk_str("GET");
}
void void
router_init() router_init()
{ {
// add index endpoint // add index endpoint
endpoint_index.route = NULL; endpoint_index.route = NULL;
endpoint_index.func = endpoint_index_func; endpoint_index.func = endpoint_index_func;
endpoint_index.methods = 0; endpoint_index.method = 0;
endpoint_index.args_count = 0; endpoint_index.args_count = 0;
endpoint_index.args = NULL; endpoint_index.args = NULL;
// add 404 endpoint // add 404 endpoint
endpoint_not_found.route = NULL; endpoint_not_found.route = NULL;
endpoint_not_found.func = endpoint_not_found_func; endpoint_not_found.func = endpoint_not_found_func;
endpoint_not_found.methods = 0; endpoint_not_found.method = 0;
endpoint_not_found.args_count = 0; endpoint_not_found.args_count = 0;
endpoint_not_found.args = NULL; endpoint_not_found.args = NULL;
router_register_endpoint("/api/v1/schedules/", HTTP_METHOD_GET, api_v1_schedules_GET); router_register_endpoint("/api/v1/schedules/", HTTP_METHOD_GET, api_v1_schedules_GET);
router_register_endpoint("/api/v1/schedules/", HTTP_METHOD_POST, api_v1_schedules_POST); router_register_endpoint("/api/v1/schedules/", HTTP_METHOD_POST, api_v1_schedules_POST);
router_register_endpoint("/api/v1/schedules/{str}/", HTTP_METHOD_GET, api_v1_schedules_STR_GET); router_register_endpoint("/api/v1/schedules/{str}", HTTP_METHOD_GET, api_v1_schedules_STR_GET);
router_register_endpoint("/api/v1/schedules/{str}/", HTTP_METHOD_PUT, api_v1_schedules_STR_PUT); router_register_endpoint("/api/v1/schedules/{str}", HTTP_METHOD_PUT, api_v1_schedules_STR_PUT);
router_register_endpoint("/api/v1/schedules/{str}/", HTTP_METHOD_DELETE, api_v1_schedules_STR_DELETE); router_register_endpoint("/api/v1/schedules/{str}", HTTP_METHOD_DELETE, api_v1_schedules_STR_DELETE);
router_register_endpoint("/api/v1/schedules/tag/{str}/", HTTP_METHOD_GET, api_v1_schedules_tag_STR_GET); router_register_endpoint("/api/v1/schedules/tag/{str}", HTTP_METHOD_GET, api_v1_schedules_tag_STR_GET);
router_register_endpoint("/api/v1/controllers/discover/", HTTP_METHOD_POST, api_v1_controllers_discover_POST); router_register_endpoint("/api/v1/controllers/discover/", HTTP_METHOD_POST, api_v1_controllers_discover_POST);
router_register_endpoint("/api/v1/controllers/", HTTP_METHOD_GET, api_v1_controllers_GET); router_register_endpoint("/api/v1/controllers/", HTTP_METHOD_GET, api_v1_controllers_GET);
@ -72,19 +92,38 @@ router_init()
router_register_endpoint("/api/v1/controllers/{str}/relays/{int}", HTTP_METHOD_PUT, api_v1_controllers_STR_relays_INT_PUT); router_register_endpoint("/api/v1/controllers/{str}/relays/{int}", HTTP_METHOD_PUT, api_v1_controllers_STR_relays_INT_PUT);
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);
} }
void endpoint_t*
router_register_endpoint(const char *route, int methods, endpoint_func_f func) router_register_endpoint(const char *route, int method, endpoint_func_f func)
{ {
endpoint_t *options_endpoint = NULL;
if(method != HTTP_METHOD_OPTIONS)
{
struct mg_str method_str = get_method_str_for_int(HTTP_METHOD_OPTIONS);
options_endpoint = router_find_endpoint(route, strlen(route), &method_str);
if(options_endpoint == &endpoint_not_found)
{
options_endpoint = router_register_endpoint(route, HTTP_METHOD_OPTIONS, NULL);
}
}
if(endpoints_registered >= ENDPOINTS_MAX_COUNT) if(endpoints_registered >= ENDPOINTS_MAX_COUNT)
{ {
LOG_ERROR("can't register more than %d endpoints\n", ENDPOINTS_MAX_COUNT); LOG_ERROR("can't register more than %d endpoints\n", ENDPOINTS_MAX_COUNT);
return; return NULL;
} }
endpoint_t *endpoint = &endpoints[endpoints_registered]; endpoint_t *endpoint = &endpoints[endpoints_registered];
endpoint->full_route = route;
endpoint->trailing_slash = 0; // unused because trailing slashes are optional. TODO make option
if(route[strlen(route)] == delimiter[0])
{
endpoint->trailing_slash = 1;
}
int route_parts_count = 1; int route_parts_count = 1;
size_t route_len = strlen(route); size_t route_len = strlen(route);
@ -130,8 +169,16 @@ router_register_endpoint(const char *route, int methods, endpoint_func_f func)
} }
endpoint->func = func; endpoint->func = func;
endpoint->methods = methods; endpoint->method = method;
endpoint->options = 0;
if(options_endpoint)
{
options_endpoint->options |= method;
}
++endpoints_registered; ++endpoints_registered;
return endpoint;
} }
static int static int
@ -163,8 +210,6 @@ get_method_int_for_str(struct mg_str *method_str)
endpoint_t* endpoint_t*
router_find_endpoint(const char *uri_str, size_t uri_len, struct mg_str *method_str) router_find_endpoint(const char *uri_str, size_t uri_len, struct mg_str *method_str)
{ {
(void)uri_str;
(void)uri_len;
char *uri = malloc(sizeof(char) * (uri_len + 1)); char *uri = malloc(sizeof(char) * (uri_len + 1));
strncpy(uri, uri_str, uri_len); strncpy(uri, uri_str, uri_len);
uri[uri_len] = '\0'; uri[uri_len] = '\0';
@ -173,7 +218,7 @@ router_find_endpoint(const char *uri_str, size_t uri_len, struct mg_str *method_
for(int i = 0; i < endpoints_registered; ++i) for(int i = 0; i < endpoints_registered; ++i)
{ {
if(endpoints[i].methods & method) if(endpoints[i].method & method)
{ {
endpoints[i].possible_route = 1; endpoints[i].possible_route = 1;
} }