diff --git a/lib/include/restd.h b/lib/include/restd.h index c8171d8..63f7b13 100644 --- a/lib/include/restd.h +++ b/lib/include/restd.h @@ -41,6 +41,7 @@ typedef struct restd_hook_s restd_hook_t; typedef struct restd_resp_s restd_resp_t; typedef int (*restd_callback)(restd_resp_t *response, void *arg); +typedef int (*restd__error_callback)(restd_resp_t *response, int reason, void *arg); /*------------------------------- INCLUDES ----------------------------------*/ @@ -50,9 +51,12 @@ extern int restd_server_start(restd_server_t *server); extern int restd_server_attach_event_loop(restd_server_t *server, struct event_base *ev_base); extern void restd_server_set_option(restd_server_t *server, const char *key, const char *value); + extern void restd_server_register_hook_on_path(restd_server_t *server, enum evhttp_cmd_type method, const char *path, restd_callback cb, void *userdata); +extern void restd_server_register_error_handler(restd_server_t *server, restd__error_callback cb, void *userdata); + extern void restd_http_response(restd_resp_t *response, int code, const char *contenttype, const char *data); extern char *restd_http_get_body(restd_resp_t *response); @@ -81,6 +85,9 @@ enum restd_log_e #define RESTD_OK (0) /*!< I'm done with this request. Escalate to other hooks. */ #define RESTD_FAILED (1) /*!< I'm done with this request. But the Process failed. */ +#define RESTD_ERROR_METHOD_NOT_ALLOWED (2) +#define RESTD_ERROR_PATH_NOT_FOUND (3) + /*---------------------------------------------------------------------------*\ | DATA STRUCTURES | \*---------------------------------------------------------------------------*/ @@ -100,7 +107,8 @@ struct restd_server_s struct bufferevent *notify_buffer; /*!< internal notification channel */ - restd_callback error_handler; + restd__error_callback error_handler; + void *error_userdata; }; /* diff --git a/lib/src/restd.c b/lib/src/restd.c index f74cb2a..d203fc2 100644 --- a/lib/src/restd.c +++ b/lib/src/restd.c @@ -450,6 +450,9 @@ void restd_server_register_hook_on_path(restd_server_t *server, enum evhttp_cmd_ char *fragment; qlist_obj_t obj; + if (server == NULL) + return; + // Init Hook. hook = restd_hook_new(); @@ -487,6 +490,17 @@ void restd_server_register_hook_on_path(restd_server_t *server, enum evhttp_cmd_ /*--------------------------------------------------------------------------*/ +void restd_server_register_error_handler(restd_server_t *server, restd__error_callback cb, void *userdata) +{ + if (server == NULL) + return; + + server->error_handler = cb; + server->error_userdata = userdata; +} + +/*--------------------------------------------------------------------------*/ + void restd_http_response(restd_resp_t *response, int code, const char *contenttype, const char *data) { struct evbuffer *resp_buf; @@ -794,7 +808,7 @@ void rest_request_cb(struct evhttp_request *req, void *arg) const char *request_path = evhttp_request_get_uri(req); qlist_t *hooks = server->hooks; - //int reason = RESTD_ERROR_PATH_NOT_FOUND; + int reason = RESTD_ERROR_PATH_NOT_FOUND; qlist_obj_t obj; bzero((void *)&obj, sizeof(qlist_obj_t)); while (hooks->getnext(hooks, &obj, false) == true) @@ -807,8 +821,6 @@ void rest_request_cb(struct evhttp_request *req, void *arg) //printf("==== HOOK FOUND !!!!\n"); if (hook->method != evhttp_request_get_command(req)) { - //printf("==== Hook found but method failed -> next.\n"); - //reason = RESTD_ERROR_METHOD_NOT_ALLOWED; continue; } @@ -819,7 +831,7 @@ void rest_request_cb(struct evhttp_request *req, void *arg) } } } - restd_resp_free(response); + // No Hook Found check if it's a real file into document root. root_path = restd_server_get_option(server, "server.root_path"); if ((root_path != NULL) && (strlen(root_path) != 0)) @@ -831,6 +843,7 @@ void rest_request_cb(struct evhttp_request *req, void *arg) if (fd != -1) { restd_http_response_from_file(req, 200, fd, file_mime_lookup(buf)); + restd_resp_free(response); return; } else @@ -838,16 +851,17 @@ void rest_request_cb(struct evhttp_request *req, void *arg) // TODO 404 } } -#if 0 // TODO - if (conn->server->error_handler != NULL) + + if (server->error_handler != NULL) { - return conn->server->error_handler(reason, conn, NULL); + server->error_handler(response, reason, NULL); } else -#endif { evhttp_send_reply(req, 500, "Internal Error", NULL); } + + restd_resp_free(response); } /*--------------------------------------------------------------------------*/ diff --git a/src/tests/test_rest.c b/src/tests/test_rest.c index 5ccac2d..5c38086 100644 --- a/src/tests/test_rest.c +++ b/src/tests/test_rest.c @@ -25,11 +25,13 @@ /*--------------------------------------------------------------------------*/ -#define ksuccess_get_body "{\"status\":\"ok\"}" -#define ksuccess_delete_body "{\"status\":\"delete\"}" -#define ksuccess_put_body "{\"status\":\"put\"}" -#define ksuccess_post_body "{\"status\":\"post\"}" -#define kerror_body "{\"status\":\"error\"}" +#define ksuccess_get_body "{ \"status\": \"ok\" }" +#define ksuccess_delete_body "{ \"status\": \"delete\" }" +#define ksuccess_put_body "{ \"status\": \"put\" }" +#define ksuccess_post_body "{ \"status\": \"post\" }" +#define kerror_body_not_allowed "{ \"status\": \"error\", \"reason\": \"not allowed\" }" +#define kerror_body_not_found "{ \"status\": \"error\", \"reason\": \"not found\" }" +#define kerror_body "{ \"status\": \"error\" }" #define ksuccess_put_param1 "{ \"id\": 1 }" #define ksuccess_put_param2 "{ \"year\": 1977, \"action\": \"todo\" }" @@ -49,9 +51,15 @@ /*--------------------------------------------------------------------------*/ -int my_error_handler(restd_resp_t *response, void *arg) +int my_error_handler(restd_resp_t *response, int reason, void *arg) { - restd_http_response(response, 200, "application/json", kerror_body); + if (reason == RESTD_ERROR_METHOD_NOT_ALLOWED) + restd_http_response(response, 200, "application/json", kerror_body_not_allowed); + else if (reason == RESTD_ERROR_PATH_NOT_FOUND) + restd_http_response(response, 200, "application/json", kerror_body_not_found); + else + restd_http_response(response, 200, "application/json", kerror_body); + return RESTD_OK; } @@ -158,7 +166,7 @@ size_t write_callback(void *ptr, size_t size, size_t nmemb, void *stream) /*--------------------------------------------------------------------------*/ -int exec_request(const char *request, const char *path, int expected_code, const char *body, const char *expected_body) +int exec_request(const char *request, const char *path, int expected_code, const char *body, const char *expected_body, bool debug) { int ret = 0; CURL *curl_handle; @@ -200,8 +208,8 @@ int exec_request(const char *request, const char *path, int expected_code, const curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 2); - // Debug Only - // curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1); + if (debug) + curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1); /* send all data to this function */ curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_callback); @@ -227,7 +235,10 @@ int exec_request(const char *request, const char *path, int expected_code, const { res = strcmp(expected_body, resp_body); } - //printf ("body: %s != expected_body: %s\n", resp_body, expected_body); + + if (debug) + printf ("body: %s != expected_body: %s\n", resp_body, expected_body); + if (res != 0) { ret = 2; @@ -346,7 +357,7 @@ TEST("Rest - create free\t") restd_server_set_option(rest_server, "server.port", kserver_port); - restd_server_register_hook_on_path(rest_server, EVHTTP_REQ_POST, "/api/v1/test", my_error_handler, NULL); + restd_server_register_hook_on_path(rest_server, EVHTTP_REQ_POST, "/api/v1/test", my_success_http_handler, NULL); restd_server_free(rest_server); } @@ -440,7 +451,7 @@ TEST("Rest - create start access http hook free\t") ret = restd_server_start(rest_server); ASSERT_EQUAL_INT(ret, 0); - ret = exec_request(kget_method, "http://localhost:" kserver_port kapi_test_get, 200, ksuccess_get_body, ksuccess_get_body); + ret = exec_request(kget_method, "http://localhost:" kserver_port kapi_test_get, 200, ksuccess_get_body, ksuccess_get_body, false); ASSERT_EQUAL_INT(ret, 0); restd_server_free(rest_server); @@ -474,19 +485,19 @@ TEST("Rest - create start access to all rest hook free\t") sleep(1); //PRINTLN("\n - GET"); - ret = exec_request(kget_method, "http://localhost:" kserver_port kapi_test_get, 200, ksuccess_get_body, ksuccess_get_body); + ret = exec_request(kget_method, "http://localhost:" kserver_port kapi_test_get, 200, ksuccess_get_body, ksuccess_get_body, false); ASSERT_EQUAL_INT(ret, 0); //PRINTLN("\n - DELETE"); - ret = exec_request(kdelete_method, "http://localhost:" kserver_port kapi_test_get, 200, ksuccess_delete_body, ksuccess_delete_body); + ret = exec_request(kdelete_method, "http://localhost:" kserver_port kapi_test_get, 200, ksuccess_delete_body, ksuccess_delete_body, false); ASSERT_EQUAL_INT(ret, 0); //PRINTLN("\n - PUT"); - ret = exec_request(kput_method, "http://localhost:" kserver_port kapi_test_get, 200, ksuccess_put_body, ksuccess_put_body); + ret = exec_request(kput_method, "http://localhost:" kserver_port kapi_test_get, 200, ksuccess_put_body, ksuccess_put_body, false); ASSERT_EQUAL_INT(ret, 0); //PRINTLN("\n - POST"); - ret = exec_request(kpost_method, "http://localhost:" kserver_port kapi_test_get, 200, ksuccess_post_body, ksuccess_post_body); + ret = exec_request(kpost_method, "http://localhost:" kserver_port kapi_test_get, 200, ksuccess_post_body, ksuccess_post_body, false); ASSERT_EQUAL_INT(ret, 0); restd_server_free(rest_server); @@ -519,11 +530,41 @@ TEST("Rest - create start access to rest hook with params free\t") sleep(1); //PRINTLN("\n - Param1"); - ret = exec_request(kput_method, "http://localhost:" kserver_port kapi_test_put_id1_body, 200, "", ksuccess_put_param1); + ret = exec_request(kput_method, "http://localhost:" kserver_port kapi_test_put_id1_body, 200, "", ksuccess_put_param1, false); ASSERT_EQUAL_INT(ret, 0); //PRINTLN("\n - Param2"); - ret = exec_request(kput_method, "http://localhost:" kserver_port kapi_test_put_id2_body, 200, "", ksuccess_put_param2); + ret = exec_request(kput_method, "http://localhost:" kserver_port kapi_test_put_id2_body, 200, "", ksuccess_put_param2, false); + ASSERT_EQUAL_INT(ret, 0); + + restd_server_free(rest_server); +} + +/*--------------------------------------------------------------------------*/ + +TEST("Rest - create start access to wrong path\t") +{ + int ret; + restd_server_t *rest_server; + + rest_server = restd_server_new(); + ASSERT_NOT_NULL(rest_server); + + restd_server_set_option(rest_server, "server.port", kserver_port); + restd_server_set_option(rest_server, "server.thread", "1"); + + restd_server_register_hook_on_path(rest_server, EVHTTP_REQ_GET, kapi_test_get, my_success_rest_get_handler, NULL); + restd_server_register_error_handler(rest_server, my_error_handler, NULL); + + ret = restd_server_start(rest_server); + ASSERT_EQUAL_INT(ret, 0); + + sleep(1); + + ret = exec_request(kput_method, "http://localhost:" kserver_port kapi_test_get, 200, "", kerror_body_not_found, false); + ASSERT_EQUAL_INT(ret, 0); + + ret = exec_request(kput_method, "http://localhost:" kserver_port "/api/v1/donkey", 200, "", kerror_body_not_found, false); ASSERT_EQUAL_INT(ret, 0); restd_server_free(rest_server);