diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 933312c..8e3478d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -32,7 +32,6 @@ file( devices/shutter.c devices/sprinkler.c rest/restd.c - rest/http_resp.c rest/rest_devices_handlers.c rest/rest_server.c ) diff --git a/src/rest/http_resp.c b/src/rest/http_resp.c deleted file mode 100644 index 36bbf88..0000000 --- a/src/rest/http_resp.c +++ /dev/null @@ -1,68 +0,0 @@ -/*! - * http_resp.c - * - * Copyright (c) 2015-2020, NADAL Jean-Baptiste. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * @Author: NADAL Jean-Baptiste - * @Date: 07/02/2020 - * - */ - -/*------------------------------- INCLUDES ----------------------------------*/ - -#include - -#include "http_resp.h" - -#include "macro.h" - -/*--------------------------------------------------------------------------*/ - -http_resp_t *http_resp_new(void) -{ - http_resp_t *resp = NEW_OBJECT(http_resp_t); - if (resp == NULL) - { - return NULL; - } - - resp->ev_req = NULL; - resp->ev_uri = NULL; - //resp->path_params = 0; - resp->head_params = NULL; - //resp->post_params = {0}; - resp->post_param_parsed = false; - resp->str_body = NULL; - resp->resp_headers = NULL; - resp->resp_buf = NULL; - resp->resp_code = HTTP_OK; - - DEBUG("Created an http response object."); - return resp; -} - -/*--------------------------------------------------------------------------*/ - -void http_resp_free(http_resp_t *resp) -{ - if (resp == NULL) - { - return; - } - -} diff --git a/src/rest/http_resp.h b/src/rest/http_resp.h deleted file mode 100644 index 33ae0df..0000000 --- a/src/rest/http_resp.h +++ /dev/null @@ -1,94 +0,0 @@ -/*! - * http_resp.h - * - * Copyright (c) 2015-2020, NADAL Jean-Baptiste. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - * - * @Author: NADAL Jean-Baptiste - * @Date: 07/02/2020 - * - */ - -#ifndef _HTTP_RESP_H -#define _HTTP_RESP_H - -/*------------------------------- INCLUDES ----------------------------------*/ - -#include - -#include - -typedef struct http_resp_s http_resp_t; - -/** - * Server info container. - */ -struct http_resp_s -{ - struct evhttp_request *ev_req; - const struct evhttp_uri *ev_uri; - struct evkeyvalq path_params; - struct evkeyvalq *head_params; - struct evkeyvalq post_params; - bool post_param_parsed; - char *str_body; - struct evkeyvalq *resp_headers; - struct evbuffer *resp_buf; - int resp_code; -}; - - -extern http_resp_t *http_resp_new(void); -extern void http_resp_free(http_resp_t *resp); - -#if 0 - EvHttpResp(struct evhttp_request *req) throw(EvHttpRespRTEXCP); - ~EvHttpResp(); - - std::string GetRequestUri(); - std::string GetUriHost(); //#TODO add const of this - /// It will return -1 if no port set - int GetUriPort(); - std::string GetUriPath(); - std::string GetUriQuery(); - /// Useless to get from a request url, fragment is only for browser to locate sth. - std::string GetUriFragment(); - - std::string GetHeadParam(std::string const &strKey); - std::string GetPathParam(std::string const &strKey); - std::string GetPostParam(std::string const &strKey); - - std::string GetPostMsg(); - - bool AddRespHeadParam(std::string const &key, std::string const &val); - void AddRespHeaders(HttpHeaders& headers); - bool AddRespString(std::string const &str); - /// This will cause data memcpy, if not so, user have to make sure data lifetime last until be read - /// #TODO: This func is dangerious, NOT RECOMMEND to use, for if len is larger than actual, cause overflow - bool AddRespBuf(void const *data, std::size_t len); - bool AddRespFile(std::string const &fileName); - - void SetRespCode(int code); - /// Make sure code and all response body has finished set - void SendResponse(); - void QuickResponse(int code, std::string const &strBody); - void SimpleResponse(int code, HttpHeaders &headers, std::string const &strBody); - /// If strMsg is empty, libevent will use default error code message instead - void RespError(int nCode, std::string const &strMsg); -#endif - -#endif /* _HTTP_RESP_H */ diff --git a/src/rest/restd.c b/src/rest/restd.c index cdd7d69..5f1ceac 100644 --- a/src/rest/restd.c +++ b/src/rest/restd.c @@ -40,6 +40,8 @@ #include #include +#include + #ifdef __linux__ #include #else @@ -181,7 +183,8 @@ void restd_http_response_from_file(struct evhttp_request *req, int code, int fd, /*--------------------------- PUBLIC FUNCTIONS -------------------------------*/ -/** +/*-------------------------------------------------------------------------- + * * Set debug output level. * * @param debug_level debug output level. 0 to disable. @@ -204,7 +207,8 @@ enum restd_log_e restd_log_level(enum restd_log_e log_level) return prev; } -/** +/*-------------------------------------------------------------------------- + * * Create a server object. */ restd_server_t *restd_server_new(void) @@ -235,7 +239,8 @@ restd_server_t *restd_server_new(void) return server; } -/** +/*-------------------------------------------------------------------------- + * * Release server object and all the resources. */ void restd_server_free(restd_server_t *server) @@ -273,20 +278,19 @@ void restd_server_free(restd_server_t *server) { qlist_t *tbl = server->hooks; restd_hook_t *hook; - while ((hook = tbl->popfirst(tbl, NULL))) + while ((hook = qlist_popfirst(tbl, NULL))) { - if (hook->path) - free(hook->path); - free(hook); + restd_hook_free(hook); } - server->hooks->free(server->hooks); + qlist_free(server->hooks); } free(server); DEBUG("Server terminated."); } -/** +/*-------------------------------------------------------------------------- + * * Start server. * * @return 0 if successful, otherwise -1. @@ -441,14 +445,39 @@ void restd_server_set_option(restd_server_t *server, const char *key, const char void restd_server_register_hook_on_path(restd_server_t *server, enum evhttp_cmd_type method, const char *path, restd_callback cb, void *userdata) { - restd_hook_t hook; - bzero((void *)&hook, sizeof(restd_hook_t)); - hook.method = method; - hook.path = (path) ? strdup(path) : NULL; - hook.cb = cb; - hook.userdata = userdata; + restd_hook_t *hook; + char *fragment; - server->hooks->addlast(server->hooks, (void *)&hook, sizeof(restd_hook_t)); + // Init Hook. + hook = restd_hook_new(); + + hook->method = method; + hook->path = (path) ? strdup(path) : NULL; + hook->cb = cb; + hook->userdata = userdata; + hook->path_fragments = qstrtokenizer(path, "/"); + + // Split URI and detect parameter and action. + while ((fragment = qlist_popfirst(hook->path_fragments, NULL)) != NULL) + { + char *param; + + param = strchr(fragment, ':'); + if (param != NULL) + { + hook->has_param = true; + hook->param_name = strdup(param + 1); + } + if (hook->has_param == true) + { + hook->action_name = strdup(fragment); + } + + free(fragment); + } + + server->hooks->addlast(server->hooks, (void *)hook, sizeof(restd_hook_t)); + free(hook); } /*--------------------------------------------------------------------------*/ @@ -488,6 +517,79 @@ char *restd_http_get_body(struct evhttp_request *req) return body; } +/*--------------------------------------------------------------------------*/ + +restd_hook_t *restd_hook_new(void) +{ + restd_hook_t *hook = NEW_OBJECT(restd_hook_t); + if (hook == NULL) + { + return NULL; + } + + bzero((void *)hook, sizeof(restd_hook_t)); + + hook->has_param = false; + + return hook; +} + +/*--------------------------------------------------------------------------*/ + +void restd_hook_free(restd_hook_t *hook) +{ + if (hook == NULL) + return; + + qlist_free(hook->path_fragments); + if (hook->path) + free(hook->path); + + if (hook->param_name) + free(hook->param_name); + + if (hook->action_name) + free(hook->action_name); + + free(hook); +} + +/*--------------------------------------------------------------------------*/ + +restd_resp_t *restd_resp_new(void) +{ + restd_resp_t *resp = NEW_OBJECT(restd_resp_t); + if (resp == NULL) + { + return NULL; + } + + bzero((void *)resp, sizeof(restd_resp_t)); + + return resp; +} + +/*--------------------------------------------------------------------------*/ + +void restd_resp_free(restd_resp_t *response) +{ + if (response == NULL) + { + return; + } + + if (response->parameter) + { + free(response->parameter); + } + if (response->action) + { + free(response->action); + } + free(response); +} + + /*--------------------------- LOCAL FUNCTIONS -------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -509,7 +611,8 @@ static int set_undefined_options(restd_server_t *server) return newentries; } -/** +/*-------------------------------------------------------------------------- + * * Retrieve server option. */ char *restd_server_get_option(restd_server_t *server, const char *key) @@ -517,7 +620,8 @@ char *restd_server_get_option(restd_server_t *server, const char *key) return server->options->getstr(server->options, key, false); } -/** +/*-------------------------------------------------------------------------- + * * Retrieve server option in integer format. */ int restd_server_get_option_int(restd_server_t *server, const char *key) @@ -600,7 +704,8 @@ static void libevent_log_cb(int severity, const char *msg) } } -/** +/*-------------------------------------------------------------------------- + * * If there's no event, loopbreak or loopexit call won't work until one more * event arrived. So we use eventfd as a internal notification channel to let * server get out of the loop without waiting for an event. @@ -748,7 +853,6 @@ void rest_request_cb(struct evhttp_request *req, void *arg) { // TODO 404 } - } #if 0 // TODO if (conn->server->error_handler != NULL) @@ -758,7 +862,7 @@ void rest_request_cb(struct evhttp_request *req, void *arg) else #endif { - evhttp_send_reply(req, 500, "Internal Error", NULL); + evhttp_send_reply(req, 500, "Internal Error", NULL); } } diff --git a/src/rest/restd.h b/src/rest/restd.h index d6e41c6..f4584f6 100644 --- a/src/rest/restd.h +++ b/src/rest/restd.h @@ -38,11 +38,11 @@ typedef struct restd_server_s restd_server_t; typedef struct restd_hook_s restd_hook_t; +typedef struct restd_resp_s restd_resp_t; /** * User callback(hook) prototype. */ -typedef int (*restd_call_hook_cb)(short event, void *conn); typedef int (*restd_callback)(struct evhttp_request *req, void *arg); typedef void (*restd_userdata_free_cb)(void *conn, void *userdata); @@ -60,6 +60,13 @@ extern void restd_server_register_hook_on_path(restd_server_t *server, enum evht extern void restd_http_response(struct evhttp_request *req, int code, const char *contenttype, const char *data); extern char *restd_http_get_body(struct evhttp_request *req); +extern restd_hook_t *restd_hook_new(void); +extern void restd_hook_free(restd_hook_t *hook); + +extern restd_resp_t *restd_resp_new(void); +extern void restd_resp_free(restd_resp_t *response); + + /*------------------------------- DEFINES ------------------------------------*/ /* @@ -107,7 +114,6 @@ struct restd_server_s struct bufferevent *notify_buffer; /*!< internal notification channel */ - restd_call_hook_cb call_hooks; restd_callback request_handler; restd_callback error_handler; }; @@ -121,7 +127,21 @@ struct restd_hook_s char *path; restd_callback cb; void *userdata; + bool has_param; + qlist_t *path_fragments; + char *param_name; + char *action_name; }; +/* + * Response callback parameter. + */ +struct restd_resp_s +{ + struct evhttp_request *request; + bool has_parameter; + char *parameter; + char *action; +}; #endif /*_RESTD_H */