diff --git a/config.c b/config.c index 4ee8dcf..60f9d23 100644 --- a/config.c +++ b/config.c @@ -54,12 +54,41 @@ config_load(IniDispatch *disp, void *config_void) 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")) { config->database = malloc(sizeof(char) * (strlen(disp->value) + 1)); strcpy(config->database, disp->value); 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")) { return config_load_log_level(disp, config); @@ -69,12 +98,6 @@ config_load(IniDispatch *disp, void *config_void) config->discovery_port = atoi(disp->value); return 0; } - if(CONFINI_IS_KEY("core", "server-port")) - { - strcpy(config->server_port, disp->value); - return 0; - } } return 0; } - diff --git a/core.ini b/core.ini index 8bb6185..4d2e6f8 100644 --- a/core.ini +++ b/core.ini @@ -1,7 +1,11 @@ [core] 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 discovery-port = 4421 -database = core.sqlite log-level = debug diff --git a/endpoint.c b/endpoint.c index f7a0c90..b068ed4 100644 --- a/endpoint.c +++ b/endpoint.c @@ -10,13 +10,9 @@ endpoint_func_index(struct mg_connection *nc, struct http_message *hm, endpoint_ (void)args; (void)hm; (void)nc; + (void)response; - static const char content[] = "Emgauwa"; - response->status_code = 200; - response->content_type = "text/plain"; - response->content_length = STRLEN(content);; - response->content = content; - response->alloced_content = false; + response->status_code = 0; 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)hm; (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 diff --git a/handlers/connection.c b/handlers/connection.c index b36e75e..c7e7870 100644 --- a/handlers/connection.c +++ b/handlers/connection.c @@ -7,12 +7,31 @@ #include #include -#define STD_HEADERS "Access-Control-Allow-Origin: *\r\nAccess-Control-Allow-Headers: *\r\nAccess-Control-Allow-Methods: *\r\n" -#define HEADERS_FMT STD_HEADERS "Content-Type: %s" +#define HEADERS_FMT "Content-Type: %s" // -2 for "%s" -1 for \0 #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 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); - 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"; - endpoint_response_text(&response, 500, content, STRLEN(content)); - - endpoint->func(nc, hm, endpoint->args, &response); - - 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); - } - - 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); - } - } + LOG_DEBUG("%s\n", request_file); + int access_result = access(request_file, R_OK); + free(request_file_org); + if(access_result != -1) + { + response.status_code = 0; + mg_serve_http(nc, hm, global_config.http_server_opts); + return; } else { - if(endpoint->method == HTTP_METHOD_OPTIONS) - { - 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"); - } + endpoint = router_get_not_found_endpoint(); } } - 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); - //mg_printf(c, "%.*s", (int)hm->body.len, hm->body.p); + endpoint->func(nc, hm, endpoint->args, &response); + 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); + } + } } } diff --git a/include/config.h b/include/config.h index 53b4772..17d6db5 100644 --- a/include/config.h +++ b/include/config.h @@ -30,6 +30,10 @@ typedef struct run_type_t run_type; char server_port[6]; 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; } config_t; diff --git a/include/router.h b/include/router.h index b52ba89..93bfec9 100644 --- a/include/router.h +++ b/include/router.h @@ -15,6 +15,9 @@ typedef enum HTTP_METHOD_OPTIONS = (1 << 4) } http_method_e; +endpoint_t* +router_get_not_found_endpoint(); + void router_init(); diff --git a/main.c b/main.c index f077cf4..f470e0a 100644 --- a/main.c +++ b/main.c @@ -51,6 +51,9 @@ main(int argc, const char** argv) /******************** LOAD CONFIG ********************/ 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; helper_parse_cli(argc, argv, &global_config); @@ -69,8 +72,10 @@ main(int argc, const char** argv) 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.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 ********************/ diff --git a/router.c b/router.c index bd4734f..a4b477a 100644 --- a/router.c +++ b/router.c @@ -10,7 +10,6 @@ #include static endpoint_t endpoints[ROUTER_ENDPOINTS_MAX_COUNT]; -static endpoint_t endpoint_index; static endpoint_t endpoint_not_found; static int endpoints_registered = 0; static const char delimiter[2] = "/"; @@ -41,16 +40,15 @@ get_method_str_for_int(int method_int) return mg_mk_str("GET"); } +endpoint_t* +router_get_not_found_endpoint() +{ + return &endpoint_not_found; +} + void 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 endpoint_not_found.route = NULL; 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); 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); } @@ -232,7 +230,7 @@ router_find_endpoint(const char *uri_str, size_t uri_len, struct mg_str *method_ if(!uri_token) { free(uri); - return &endpoint_index; + return NULL; } while(uri_token) @@ -292,15 +290,22 @@ router_find_endpoint(const char *uri_str, size_t uri_len, struct mg_str *method_ ++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) { int rating = endpoints[i].possible_route; - if(rating > best_endpoint->possible_route) + if(rating > best_rating) { 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) {