add: file handling with 404
This commit is contained in:
parent
865caa627e
commit
20d38730c9
8 changed files with 157 additions and 83 deletions
35
config.c
35
config.c
|
@ -54,12 +54,41 @@ config_load(IniDispatch *disp, void *config_void)
|
||||||
|
|
||||||
if(disp->type == INI_KEY)
|
if(disp->type == INI_KEY)
|
||||||
{
|
{
|
||||||
|
if(CONFINI_IS_KEY("core", "server-port"))
|
||||||
|
{
|
||||||
|
strcpy(config->server_port, disp->value);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if(CONFINI_IS_KEY("core", "database"))
|
if(CONFINI_IS_KEY("core", "database"))
|
||||||
{
|
{
|
||||||
config->database = malloc(sizeof(char) * (strlen(disp->value) + 1));
|
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"))
|
||||||
|
{
|
||||||
|
config->not_found_file = malloc(sizeof(char) * (strlen(disp->value) + 1));
|
||||||
|
strcpy(config->not_found_file, disp->value);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if(CONFINI_IS_KEY("core", "log-level"))
|
if(CONFINI_IS_KEY("core", "log-level"))
|
||||||
{
|
{
|
||||||
return config_load_log_level(disp, config);
|
return config_load_log_level(disp, config);
|
||||||
|
@ -69,12 +98,6 @@ config_load(IniDispatch *disp, void *config_void)
|
||||||
config->discovery_port = atoi(disp->value);
|
config->discovery_port = atoi(disp->value);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if(CONFINI_IS_KEY("core", "server-port"))
|
|
||||||
{
|
|
||||||
strcpy(config->server_port, disp->value);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
6
core.ini
6
core.ini
|
@ -1,7 +1,11 @@
|
||||||
[core]
|
[core]
|
||||||
server-port = 5000
|
server-port = 5000
|
||||||
|
database = core.sqlite
|
||||||
|
not-found-file = 404.html
|
||||||
|
not-found-file-mime = text/html
|
||||||
|
not-found-content = 404 - NOT FOUND
|
||||||
|
not-found-content-type = text/plain
|
||||||
|
|
||||||
: 4421 for dev-env; 4420 for testing-env; 4419 for prod-env; 4422 for testing
|
: 4421 for dev-env; 4420 for testing-env; 4419 for prod-env; 4422 for testing
|
||||||
discovery-port = 4421
|
discovery-port = 4421
|
||||||
database = core.sqlite
|
|
||||||
log-level = debug
|
log-level = debug
|
||||||
|
|
32
endpoint.c
32
endpoint.c
|
@ -10,13 +10,9 @@ endpoint_func_index(struct mg_connection *nc, struct http_message *hm, endpoint_
|
||||||
(void)args;
|
(void)args;
|
||||||
(void)hm;
|
(void)hm;
|
||||||
(void)nc;
|
(void)nc;
|
||||||
|
(void)response;
|
||||||
|
|
||||||
static const char content[] = "Emgauwa";
|
response->status_code = 0;
|
||||||
response->status_code = 200;
|
|
||||||
response->content_type = "text/plain";
|
|
||||||
response->content_length = STRLEN(content);;
|
|
||||||
response->content = content;
|
|
||||||
response->alloced_content = false;
|
|
||||||
|
|
||||||
mg_serve_http(nc, hm, global_config.http_server_opts);
|
mg_serve_http(nc, hm, global_config.http_server_opts);
|
||||||
}
|
}
|
||||||
|
@ -27,15 +23,23 @@ endpoint_func_not_found(struct mg_connection *nc, struct http_message *hm, endpo
|
||||||
(void)args;
|
(void)args;
|
||||||
(void)hm;
|
(void)hm;
|
||||||
(void)nc;
|
(void)nc;
|
||||||
|
|
||||||
|
if(access(global_config.not_found_file, R_OK) != -1)
|
||||||
|
{
|
||||||
|
struct mg_str mime_type = mg_mk_str(global_config.not_found_file_type);
|
||||||
|
response->status_code = 0;
|
||||||
|
mg_http_serve_file(nc, hm, global_config.not_found_file, mime_type, mg_mk_str(""));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_DEBUG("404 file not found\n");
|
||||||
|
response->status_code = 404;
|
||||||
|
response->content_type = global_config.not_found_content_type;
|
||||||
|
response->content_length = strlen(global_config.not_found_content);
|
||||||
|
response->content = global_config.not_found_content;
|
||||||
|
response->alloced_content = false;
|
||||||
|
}
|
||||||
|
|
||||||
static const char content[] = "404 - NOT FOUND";
|
|
||||||
response->status_code = 404;
|
|
||||||
response->content_type = "text/plain";
|
|
||||||
response->content_length = STRLEN(content);;
|
|
||||||
response->content = content;
|
|
||||||
response->alloced_content = false;
|
|
||||||
|
|
||||||
mg_serve_http(nc, hm, global_config.http_server_opts);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -7,12 +7,31 @@
|
||||||
#include <router.h>
|
#include <router.h>
|
||||||
#include <handlers.h>
|
#include <handlers.h>
|
||||||
|
|
||||||
#define STD_HEADERS "Access-Control-Allow-Origin: *\r\nAccess-Control-Allow-Headers: *\r\nAccess-Control-Allow-Methods: *\r\n"
|
#define HEADERS_FMT "Content-Type: %s"
|
||||||
#define HEADERS_FMT STD_HEADERS "Content-Type: %s"
|
|
||||||
|
|
||||||
// -2 for "%s" -1 for \0
|
// -2 for "%s" -1 for \0
|
||||||
#define HEADERS_FMT_LEN (sizeof(HEADERS_FMT) - 3)
|
#define HEADERS_FMT_LEN (sizeof(HEADERS_FMT) - 3)
|
||||||
|
|
||||||
|
static void
|
||||||
|
send_response(struct mg_connection *nc, endpoint_response_t *response)
|
||||||
|
{
|
||||||
|
if(response->status_code)
|
||||||
|
{
|
||||||
|
char *response_headers = malloc(sizeof(char) * (HEADERS_FMT_LEN + strlen(response->content_type) + 1));
|
||||||
|
sprintf(response_headers, HEADERS_FMT, response->content_type);
|
||||||
|
|
||||||
|
mg_send_head(nc, response->status_code, response->content_length, response_headers);
|
||||||
|
mg_printf(nc, "%s", response->content);
|
||||||
|
|
||||||
|
free(response_headers);
|
||||||
|
|
||||||
|
if(response->alloced_content)
|
||||||
|
{
|
||||||
|
free((char*)response->content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
handler_connection(struct mg_connection *nc, int ev, void *p)
|
handler_connection(struct mg_connection *nc, int ev, void *p)
|
||||||
{
|
{
|
||||||
|
@ -23,63 +42,70 @@ handler_connection(struct mg_connection *nc, 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_response_t response;
|
||||||
|
static const char content[] = "the server did not create a response";
|
||||||
|
endpoint_response_text(&response, 500, content, STRLEN(content));
|
||||||
|
|
||||||
|
if(!endpoint)
|
||||||
{
|
{
|
||||||
if(endpoint->func)
|
/* Normalize path - resolve "." and ".." (in-place). */
|
||||||
|
if (!mg_normalize_uri_path(&hm->uri, &hm->uri)) {
|
||||||
|
mg_http_send_error(nc, 400, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char *request_file_org = malloc(sizeof(char) * hm->uri.len);
|
||||||
|
strncpy(request_file_org, hm->uri.p + 1, hm->uri.len);
|
||||||
|
request_file_org[hm->uri.len - 1] = '\0';
|
||||||
|
|
||||||
|
char *request_file = request_file_org;
|
||||||
|
while(request_file[0] == '/')
|
||||||
{
|
{
|
||||||
endpoint_response_t response;
|
++request_file;
|
||||||
|
}
|
||||||
|
|
||||||
static const char content[] = "the server did not create a response";
|
LOG_DEBUG("%s\n", request_file);
|
||||||
endpoint_response_text(&response, 500, content, STRLEN(content));
|
int access_result = access(request_file, R_OK);
|
||||||
|
free(request_file_org);
|
||||||
endpoint->func(nc, hm, endpoint->args, &response);
|
if(access_result != -1)
|
||||||
|
{
|
||||||
char *response_headers = malloc(sizeof(char) * (HEADERS_FMT_LEN + strlen(response.content_type) + 1));
|
response.status_code = 0;
|
||||||
sprintf(response_headers, HEADERS_FMT, response.content_type);
|
mg_serve_http(nc, hm, global_config.http_server_opts);
|
||||||
|
return;
|
||||||
mg_send_head(nc, response.status_code, response.content_length, response_headers);
|
|
||||||
mg_printf(nc, "%s", response.content);
|
|
||||||
|
|
||||||
free(response_headers);
|
|
||||||
|
|
||||||
if(response.alloced_content)
|
|
||||||
{
|
|
||||||
free((char*)response.content);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i = 0; i < endpoint->args_count; ++i)
|
|
||||||
{
|
|
||||||
if(endpoint->args[i].type == ENDPOINT_ARG_TYPE_STR)
|
|
||||||
{
|
|
||||||
free((char*)endpoint->args[i].value.v_str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(endpoint->method == HTTP_METHOD_OPTIONS)
|
endpoint = router_get_not_found_endpoint();
|
||||||
{
|
|
||||||
char options_header[256]; // TODO make more generic
|
|
||||||
sprintf(options_header, STD_HEADERS "Allow: OPTIONS%s%s%s%s",
|
|
||||||
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(nc, 204, 0, options_header);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mg_send_head(nc, 501, 0, "Content-Type: text/plain");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if(!endpoint->func)
|
||||||
{
|
{
|
||||||
mg_send_head(nc, 500, 0, "Content-Type: text/plain");
|
if(endpoint->method == HTTP_METHOD_OPTIONS)
|
||||||
|
{
|
||||||
|
char options_header[256]; // TODO make more generic
|
||||||
|
sprintf(options_header, "Allow: OPTIONS%s%s%s%s",
|
||||||
|
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(nc, 204, 0, options_header);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mg_send_head(nc, 501, 0, "Content-Type: text/plain");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//mg_printf(c, "%.*s", (int)hm->message.len, hm->message.p);
|
endpoint->func(nc, hm, endpoint->args, &response);
|
||||||
//mg_printf(c, "%.*s", (int)hm->body.len, hm->body.p);
|
send_response(nc, &response);
|
||||||
|
|
||||||
|
for(int i = 0; i < endpoint->args_count; ++i)
|
||||||
|
{
|
||||||
|
if(endpoint->args[i].type == ENDPOINT_ARG_TYPE_STR)
|
||||||
|
{
|
||||||
|
free((char*)endpoint->args[i].value.v_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,10 @@ typedef struct
|
||||||
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_type;
|
||||||
|
char *not_found_content;
|
||||||
|
char *not_found_content_type;
|
||||||
struct mg_serve_http_opts http_server_opts;
|
struct mg_serve_http_opts http_server_opts;
|
||||||
} config_t;
|
} config_t;
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,9 @@ typedef enum
|
||||||
HTTP_METHOD_OPTIONS = (1 << 4)
|
HTTP_METHOD_OPTIONS = (1 << 4)
|
||||||
} http_method_e;
|
} http_method_e;
|
||||||
|
|
||||||
|
endpoint_t*
|
||||||
|
router_get_not_found_endpoint();
|
||||||
|
|
||||||
void
|
void
|
||||||
router_init();
|
router_init();
|
||||||
|
|
||||||
|
|
7
main.c
7
main.c
|
@ -51,6 +51,9 @@ 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";
|
||||||
|
global_config.not_found_content = "404 - NOT FOUND";
|
||||||
|
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);
|
||||||
|
@ -69,8 +72,10 @@ main(int argc, const char** argv)
|
||||||
|
|
||||||
fclose(ini_file);
|
fclose(ini_file);
|
||||||
|
|
||||||
|
memset(&global_config.http_server_opts, 0, sizeof(global_config.http_server_opts));
|
||||||
global_config.http_server_opts.document_root = "."; // Serve current directory
|
global_config.http_server_opts.document_root = "."; // Serve current directory
|
||||||
global_config.http_server_opts.enable_directory_listing = "yes";
|
global_config.http_server_opts.enable_directory_listing = "no";
|
||||||
|
global_config.http_server_opts.extra_headers = "Access-Control-Allow-Origin: *\r\nAccess-Control-Allow-Headers: *\r\nAccess-Control-Allow-Methods: *";
|
||||||
|
|
||||||
|
|
||||||
/******************** SETUP DATABASE ********************/
|
/******************** SETUP DATABASE ********************/
|
||||||
|
|
29
router.c
29
router.c
|
@ -10,7 +10,6 @@
|
||||||
#include <endpoints/api_v1_relays.h>
|
#include <endpoints/api_v1_relays.h>
|
||||||
|
|
||||||
static endpoint_t endpoints[ROUTER_ENDPOINTS_MAX_COUNT];
|
static endpoint_t endpoints[ROUTER_ENDPOINTS_MAX_COUNT];
|
||||||
static endpoint_t endpoint_index;
|
|
||||||
static endpoint_t endpoint_not_found;
|
static endpoint_t endpoint_not_found;
|
||||||
static int endpoints_registered = 0;
|
static int endpoints_registered = 0;
|
||||||
static const char delimiter[2] = "/";
|
static const char delimiter[2] = "/";
|
||||||
|
@ -41,16 +40,15 @@ get_method_str_for_int(int method_int)
|
||||||
return mg_mk_str("GET");
|
return mg_mk_str("GET");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
endpoint_t*
|
||||||
|
router_get_not_found_endpoint()
|
||||||
|
{
|
||||||
|
return &endpoint_not_found;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
router_init()
|
router_init()
|
||||||
{
|
{
|
||||||
// add index endpoint
|
|
||||||
endpoint_index.route = NULL;
|
|
||||||
endpoint_index.func = endpoint_func_index;
|
|
||||||
endpoint_index.method = 0;
|
|
||||||
endpoint_index.args_count = 0;
|
|
||||||
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_func_not_found;
|
endpoint_not_found.func = endpoint_func_not_found;
|
||||||
|
@ -87,7 +85,7 @@ router_register_endpoint(const char *route, int method, endpoint_func_f func)
|
||||||
{
|
{
|
||||||
struct mg_str method_str = get_method_str_for_int(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);
|
options_endpoint = router_find_endpoint(route, strlen(route), &method_str);
|
||||||
if(options_endpoint == &endpoint_not_found)
|
if(options_endpoint == NULL)
|
||||||
{
|
{
|
||||||
options_endpoint = router_register_endpoint(route, HTTP_METHOD_OPTIONS, NULL);
|
options_endpoint = router_register_endpoint(route, HTTP_METHOD_OPTIONS, NULL);
|
||||||
}
|
}
|
||||||
|
@ -232,7 +230,7 @@ router_find_endpoint(const char *uri_str, size_t uri_len, struct mg_str *method_
|
||||||
if(!uri_token)
|
if(!uri_token)
|
||||||
{
|
{
|
||||||
free(uri);
|
free(uri);
|
||||||
return &endpoint_index;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(uri_token)
|
while(uri_token)
|
||||||
|
@ -292,15 +290,22 @@ router_find_endpoint(const char *uri_str, size_t uri_len, struct mg_str *method_
|
||||||
++route_part;
|
++route_part;
|
||||||
}
|
}
|
||||||
|
|
||||||
endpoint_t *best_endpoint = &endpoint_not_found;
|
int best_rating = 0;
|
||||||
|
endpoint_t *best_endpoint = NULL;
|
||||||
for(int i = 0; i < endpoints_registered; ++i)
|
for(int i = 0; i < endpoints_registered; ++i)
|
||||||
{
|
{
|
||||||
int rating = endpoints[i].possible_route;
|
int rating = endpoints[i].possible_route;
|
||||||
if(rating > best_endpoint->possible_route)
|
if(rating > best_rating)
|
||||||
{
|
{
|
||||||
best_endpoint = &endpoints[i];
|
best_endpoint = &endpoints[i];
|
||||||
|
best_rating = best_endpoint->possible_route;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(best_endpoint == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
for(int i = 0; i < best_endpoint->args_count; ++i)
|
for(int i = 0; i < best_endpoint->args_count; ++i)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue