From 6db405df1f7b504b3378e0b5c30bfde48a338296 Mon Sep 17 00:00:00 2001 From: NADAL Jean-Baptiste Date: Wed, 19 Feb 2020 11:18:07 +0100 Subject: [PATCH] WIP to test with params --- src/rest/restd.c | 277 ++++++++++++++++++------------------------ src/tests/test_rest.c | 96 +++++++++++---- 2 files changed, 187 insertions(+), 186 deletions(-) diff --git a/src/rest/restd.c b/src/rest/restd.c index 79b0605..cdd7d69 100644 --- a/src/rest/restd.c +++ b/src/rest/restd.c @@ -26,6 +26,7 @@ /*------------------------------- INCLUDES ----------------------------------*/ #include +#include #include #include @@ -37,6 +38,7 @@ #include #include #include +#include #ifdef __linux__ #include @@ -174,6 +176,8 @@ static void libevent_log_cb(int severity, const char *msg); static int notify_loopexit(restd_server_t *server); static void notify_cb(struct bufferevent *buffer, void *userdata); void rest_request_cb(struct evhttp_request *req, void *arg); +void print_request_info(struct evhttp_request *req); +void restd_http_response_from_file(struct evhttp_request *req, int code, int fd, const char *content_type); /*--------------------------- PUBLIC FUNCTIONS -------------------------------*/ @@ -459,12 +463,12 @@ void restd_http_response(struct evhttp_request *req, int code, const char *conte if (data != NULL) { - evbuffer_add_printf(resp_buf, "%s", data); + evbuffer_add(resp_buf, data, strlen(data)); } evhttp_add_header(resp_headers, "Content-Type", contenttype); - evhttp_send_reply(req, code, NULL ,resp_buf); + evhttp_send_reply(req, code, NULL, resp_buf); } /*--------------------------------------------------------------------------*/ @@ -474,10 +478,10 @@ char *restd_http_get_body(struct evhttp_request *req) char *body = NULL; struct evbuffer *buf; - buf = evhttp_request_get_input_buffer(req); + buf = evhttp_request_get_input_buffer(req); size_t len = evbuffer_get_length(buf); - body = malloc(len +1 ); + body = malloc(len + 1); int ret = evbuffer_copyout(buf, body, len); body[len] = '\0'; @@ -670,10 +674,102 @@ static bool contain(const char *src, const char *dest, int len) void rest_request_cb(struct evhttp_request *req, void *arg) { - const char *cmdtype; restd_server_t *server = (restd_server_t *)arg; + char *root_path; #if 0 + print_request_info(req); +#endif + + const char *request_path = evhttp_request_get_uri(req); + qlist_t *hooks = server->hooks; + //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) + { + restd_hook_t *hook = (restd_hook_t *)obj.data; + if (hook->cb) + { + //printf("==== call_hooks: method: %d - %d \n", hook->method, evhttp_request_get_command(req)); + //printf("==== call_hooks: path: %s - %s\n", hook->path, request_path); + //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; + } + + if ((hook->path != NULL) && (request_path != NULL)) + { + int i = 0; + int pos = -1; + while (hook->path[i]) + { + if (hook->path[i] == ':') + pos = i; + i++; + } + if (pos != -1 && contain(hook->path, request_path, pos)) + { + const char *buffer = &request_path[pos]; + // printf("buffer: <%s>\n", buffer); + // TODO conn->id = atoi(buffer); + hook->cb(req, hook->userdata); + return; + } + else + { + int rett = strcmp(hook->path, request_path); + if (rett == 0) + { + hook->cb(req, hook->userdata); + return; + } + } + } + } + } + // 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)) + { + int fd; + char buf[1024] = ""; + qstrcatf(buf, "%s%s", root_path, request_path); + fd = open(buf, 0); + if (fd != -1) + { + restd_http_response_from_file(req, 200, fd, file_mime_lookup(buf)); + return; + } + else + { + // TODO 404 + } + + } +#if 0 // TODO + if (conn->server->error_handler != NULL) + { + return conn->server->error_handler(reason, conn, NULL); + } + else +#endif + { + evhttp_send_reply(req, 500, "Internal Error", NULL); + } +} + +/*--------------------------------------------------------------------------*/ + +void print_request_info(struct evhttp_request *req) +{ + const char *cmdtype; + struct evkeyvalq *headers; + struct evkeyval *header; + printf("request.\n"); switch (evhttp_request_get_command(req)) { @@ -711,168 +807,31 @@ void rest_request_cb(struct evhttp_request *req, void *arg) printf("Received a %s request for %s\nHeaders:\n", cmdtype, evhttp_request_get_uri(req)); -#endif - qlist_t *hooks = server->hooks; - //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) + headers = evhttp_request_get_input_headers(req); + for (header = headers->tqh_first; header; + header = header->next.tqe_next) { - restd_hook_t *hook = (restd_hook_t *)obj.data; - if (hook->cb) - { - const char *request_path = evhttp_request_get_uri(req); - //printf("==== call_hooks: method: %d - %d \n", hook->method, evhttp_request_get_command(req)); - //printf("==== call_hooks: path: %s - %s\n", hook->path, request_path); - //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; - } - - if ((hook->path != NULL) && (request_path != NULL)) - { - int i = 0; - int pos = -1; - while (hook->path[i]) - { - if (hook->path[i] == ':') - pos = i; - i++; - } - if (pos != -1 && contain(hook->path, request_path, pos)) - { - const char *buffer = &request_path[pos]; - // printf("buffer: <%s>\n", buffer); - // TODO conn->id = atoi(buffer); - hook->cb(req, hook->userdata); - return; - } - else - { - int rett = strcmp(hook->path, request_path); - if (rett == 0) - { - hook->cb(req, hook->userdata); - return; - } - - } - } - } + printf(" %s: %s\n", header->key, header->value); } - - evhttp_send_reply(req, 500, "Internal Error", NULL); } -#if 0 -int restd_rest_handler(short event, restd_conn_t *conn) + +/*--------------------------------------------------------------------------*/ + +void restd_http_response_from_file(struct evhttp_request *req, int code, int fd, const char *content_type) { - if (event & RESTD_EVENT_INIT) - { - DEBUG("==> HTTP INIT"); - restd_http_t *http = http_new(conn->out); - if (http == NULL) - return RESTD_CLOSE; - restd_conn_set_extra(conn, http, http_free_cb); - return RESTD_OK; - } - else if (event & RESTD_EVENT_CLOSE) - { - DEBUG("==> HTTP CLOSE=%x (TIMEOUT=%d, SHUTDOWN=%d)", - event, event & RESTD_EVENT_TIMEOUT, event & RESTD_EVENT_SHUTDOWN); - return RESTD_OK; - } - else if ((event & RESTD_EVENT_READ) || (event & RESTD_EVENT_WRITE)) - { - restd_http_t *http = (restd_http_t *)restd_conn_get_extra(conn); - int status = http_parser(http, conn->in); - if (conn->method == NULL && http->request.method != NULL) - { - restd_conn_set_method(conn, http->request.method); - } - DEBUG("==> HTTP READ || HTTP WRITE"); - int reason = RESTD_ERROR_PATH_NOT_FOUND; - DEBUG("********restd_rest_handler: event 0x%x", event); - char *root_path; - qlist_t *hooks = conn->server->hooks; + struct evbuffer *resp_buf; + struct evkeyvalq *resp_headers; + ev_off_t len; - qlist_obj_t obj; - bzero((void *)&obj, sizeof(qlist_obj_t)); - while (hooks->getnext(hooks, &obj, false) == true) - { - restd_hook_t *hook = (restd_hook_t *)obj.data; - if (hook->cb) - { - printf("==== call_hooks: method: %s - %s \n", hook->method, conn->method); - printf("==== call_hooks: path: %s - %s\n", hook->path, http->request.path); - printf("==== HOOK FOUND !!!!\n"); - if ((hook->method == NULL) || (conn->method == NULL) || (strcmp(hook->method, conn->method) != 0)) - { - printf("==== Hook found but method failed -> next.\n"); - reason = RESTD_ERROR_METHOD_NOT_ALLOWED; - continue; - } + resp_buf = evhttp_request_get_output_buffer(req); + resp_headers = evhttp_request_get_output_headers(req); - if ((hook->path != NULL) && (http->request.path != NULL)) - { - int i = 0; - int pos = -1; - while (hook->path[i]) - { - if (hook->path[i] == ':') - pos = i; - i++; - } - if (pos != -1 && contain(hook->path, http->request.path, pos)) - { - const char *buffer = &http->request.path[pos]; - // printf("buffer: <%s>\n", buffer); - conn->id = atoi(buffer); - return hook->cb(event, conn, hook->userdata); - } - else - { - int rett = strcmp(hook->path, http->request.path); - if (rett == 0) - return hook->cb(event, conn, hook->userdata); - } - } - } - } - // No Hook Found check if it's a real file into document root. - root_path = restd_server_get_option(conn->server, "server.root_path"); - if ((root_path != NULL) && (strlen(root_path) != 0)) - { - FILE *file; - char buf[1024] = ""; - qstrcatf(buf, "%s%s", root_path, http->request.path); - if ((file = fopen(buf, "r"))) - { - long fsize; - char *file_buf; - fseek(file, 0, SEEK_END); - fsize = ftell(file); - fseek(file, 0, SEEK_SET); - file_buf = malloc(fsize + 1); - fread(file_buf, 1, fsize, file); - fclose(file); - file_buf[fsize] = 0; + len = lseek(fd, 0, SEEK_END); - printf("mime type:%s\n", file_mime_lookup(buf)); - restd_http_response(conn, 200, file_mime_lookup(buf), file_buf, fsize); - return RESTD_CLOSE; - } - } + evbuffer_add_file(resp_buf, fd, 0, len); - if (conn->server->error_handler != NULL) - return conn->server->error_handler(reason, conn, NULL); - return RESTD_CLOSE; - } + evhttp_add_header(resp_headers, "Content-Type", content_type); - BUG_EXIT(); - return RESTD_CLOSE; + evhttp_send_reply(req, code, NULL, resp_buf); } -#endif \ No newline at end of file diff --git a/src/tests/test_rest.c b/src/tests/test_rest.c index 4ea4f1e..e876c62 100644 --- a/src/tests/test_rest.c +++ b/src/tests/test_rest.c @@ -31,9 +31,18 @@ #define ksuccess_post_body "{\"status\":\"post\"}" #define kerror_body "{\"status\":\"error\"}" +#define ksuccess_put_param1 "{\"id\":\"1\"}" +#define ksuccess_put_param2 "{\"id\":\"1977\"}" + + #define kserver_port "7777" #define kapi_test_get "/api/v1/test_get" +#define kapi_test_put_id1 "/api/v1/test_put/:id" +#define kapi_test_put_id1_body "/api/v1/test_put/1" +#define kapi_test_put_id2 "/api/v1/test_put/:id/action" +#define kapi_test_put_id2_body "/api/v1/test_put/1977/action" + #define kpost_method "POST" #define kget_method "GET" #define kput_method "PUT" @@ -125,12 +134,12 @@ 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 *expected_body) +int exec_request(const char *request, const char *path, int expected_code, const char *body, const char *expected_body) { int ret = 0; CURL *curl_handle; CURLcode res; - char *body = NULL; + char *resp_body = NULL; long http_result_code; /* init libcurl */ @@ -155,14 +164,14 @@ int exec_request(const char *request, const char *path, int expected_code, const { curl_easy_setopt(curl_handle, CURLOPT_HTTPGET, 0); curl_easy_setopt(curl_handle, CURLOPT_CUSTOMREQUEST, kput_method); - curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, strlen(expected_body)); - curl_easy_setopt(curl_handle, CURLOPT_COPYPOSTFIELDS, expected_body); + curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, strlen(body)); + curl_easy_setopt(curl_handle, CURLOPT_COPYPOSTFIELDS, body); } else if (strcmp(request, kpost_method) == 0) { curl_easy_setopt(curl_handle, CURLOPT_POST, 0); - curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, strlen(expected_body)); - curl_easy_setopt(curl_handle, CURLOPT_COPYPOSTFIELDS, expected_body); + curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, strlen(body)); + curl_easy_setopt(curl_handle, CURLOPT_COPYPOSTFIELDS, body); } curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 2); @@ -172,7 +181,7 @@ int exec_request(const char *request, const char *path, int expected_code, const /* send all data to this function */ curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_callback); - curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &body); + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &resp_body); curl_easy_setopt(curl_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); /* get it! */ @@ -186,15 +195,15 @@ int exec_request(const char *request, const char *path, int expected_code, const curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &http_result_code); ASSERT_EQUAL_INT(http_result_code, expected_code); - if (body == NULL) + if (resp_body == NULL) { res = 1; } else { - res = strcmp(expected_body, body); + res = strcmp(expected_body, resp_body); } - //printf ("body: %s != expected_body: %s\n", body, expected_body); + // printf ("body: %s != expected_body: %s\n", resp_body, expected_body); if (res != 0) { ret = 2; @@ -203,7 +212,7 @@ int exec_request(const char *request, const char *path, int expected_code, const ASSERT_EQUAL_INT(res, 0); exit: - free(body); + free(resp_body); /* cleanup curl stuff */ curl_easy_cleanup(curl_handle); @@ -407,7 +416,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); + ret = exec_request(kget_method, "http://localhost:" kserver_port kapi_test_get, 200, ksuccess_get_body, ksuccess_get_body); ASSERT_EQUAL_INT(ret, 0); restd_server_free(rest_server); @@ -415,7 +424,7 @@ TEST("Rest - create start access http hook free\t") /*--------------------------------------------------------------------------*/ -TEST("Rest - create start access rest hook free\t") +TEST("Rest - create start access to all rest hook free\t") { int ret; restd_server_t *rest_server; @@ -435,27 +444,60 @@ TEST("Rest - create start access rest hook free\t") restd_server_register_hook_on_path(rest_server, EVHTTP_REQ_DELETE, kapi_test_get, my_success_rest_delete_handler, NULL); restd_server_register_hook_on_path(rest_server, EVHTTP_REQ_POST, kapi_test_get, my_success_rest_post_handler, NULL); + ret = restd_server_start(rest_server); + ASSERT_EQUAL_INT(ret, 0); + + sleep(1); + + //PRINTLN("\n - GET"); + ret = exec_request(kget_method, "http://localhost:" kserver_port kapi_test_get, 200, ksuccess_get_body, ksuccess_get_body); + 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); + 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); + 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); + ASSERT_EQUAL_INT(ret, 0); + + restd_server_free(rest_server); +} + +/*--------------------------------------------------------------------------*/ +#if 0 +TEST("Rest - create start access to rest hook with params free\t") +{ + int ret; + restd_server_t *rest_server; + + rest_server = restd_server_new(); + ASSERT_NOT_NULL(rest_server); + + //restd_log_level(RESTD_LOG_DEBUG); + + restd_server_set_option(rest_server, "server.port", kserver_port); + restd_server_set_option(rest_server, "server.thread", "1"); + + //restd_server_register_call_hooks_handler(rest_server, restd_rest_handler); + + restd_server_register_hook_on_path(rest_server, EVHTTP_REQ_GET, kapi_test_get, my_success_rest_get_handler, NULL); + restd_server_register_hook_on_path(rest_server, EVHTTP_REQ_PUT, kapi_test_put_id1, my_success_rest_put_handler, NULL); + restd_server_register_hook_on_path(rest_server, EVHTTP_REQ_PUT, kapi_test_put_id2, my_success_rest_put_handler, NULL); ret = restd_server_start(rest_server); ASSERT_EQUAL_INT(ret, 0); sleep(1); - PRINTLN("\n - GET"); - ret = exec_request(kget_method, "http://localhost:" kserver_port kapi_test_get, 200, ksuccess_get_body); - ASSERT_EQUAL_INT(ret, 0); - - PRINTLN("\n - DELETE"); - ret = exec_request(kdelete_method, "http://localhost:" kserver_port kapi_test_get, 200, ksuccess_delete_body); - ASSERT_EQUAL_INT(ret, 0); - - PRINTLN("\n - PUT"); - ret = exec_request(kput_method, "http://localhost:" kserver_port kapi_test_get, 200, ksuccess_put_body); - ASSERT_EQUAL_INT(ret, 0); - - PRINTLN("\n - POST"); - ret = exec_request(kpost_method, "http://localhost:" kserver_port kapi_test_get, 200, ksuccess_post_body); + PRINTLN("\n - Param1"); + ret = exec_request(kput_method, "http://localhost:" kserver_port kapi_test_put_id1_body, 200, "", ksuccess_put_param1); ASSERT_EQUAL_INT(ret, 0); restd_server_free(rest_server); } +#endif \ No newline at end of file