parameter management WIP.
This commit is contained in:
@@ -32,7 +32,6 @@ file(
|
|||||||
devices/shutter.c
|
devices/shutter.c
|
||||||
devices/sprinkler.c
|
devices/sprinkler.c
|
||||||
rest/restd.c
|
rest/restd.c
|
||||||
rest/http_resp.c
|
|
||||||
rest/rest_devices_handlers.c
|
rest/rest_devices_handlers.c
|
||||||
rest/rest_server.c
|
rest/rest_server.c
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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 <stdlib.h>
|
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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 <stdbool.h>
|
|
||||||
|
|
||||||
#include <evhttp.h>
|
|
||||||
|
|
||||||
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 */
|
|
||||||
146
src/rest/restd.c
146
src/rest/restd.c
@@ -40,6 +40,8 @@
|
|||||||
#include <event2/listener.h>
|
#include <event2/listener.h>
|
||||||
#include <event2/keyvalq_struct.h>
|
#include <event2/keyvalq_struct.h>
|
||||||
|
|
||||||
|
#include <qlibc/qlibc.h>
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
#include <sys/eventfd.h>
|
#include <sys/eventfd.h>
|
||||||
#else
|
#else
|
||||||
@@ -181,7 +183,8 @@ void restd_http_response_from_file(struct evhttp_request *req, int code, int fd,
|
|||||||
|
|
||||||
/*--------------------------- PUBLIC FUNCTIONS -------------------------------*/
|
/*--------------------------- PUBLIC FUNCTIONS -------------------------------*/
|
||||||
|
|
||||||
/**
|
/*--------------------------------------------------------------------------
|
||||||
|
*
|
||||||
* Set debug output level.
|
* Set debug output level.
|
||||||
*
|
*
|
||||||
* @param debug_level debug output level. 0 to disable.
|
* @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;
|
return prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*--------------------------------------------------------------------------
|
||||||
|
*
|
||||||
* Create a server object.
|
* Create a server object.
|
||||||
*/
|
*/
|
||||||
restd_server_t *restd_server_new(void)
|
restd_server_t *restd_server_new(void)
|
||||||
@@ -235,7 +239,8 @@ restd_server_t *restd_server_new(void)
|
|||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*--------------------------------------------------------------------------
|
||||||
|
*
|
||||||
* Release server object and all the resources.
|
* Release server object and all the resources.
|
||||||
*/
|
*/
|
||||||
void restd_server_free(restd_server_t *server)
|
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;
|
qlist_t *tbl = server->hooks;
|
||||||
restd_hook_t *hook;
|
restd_hook_t *hook;
|
||||||
while ((hook = tbl->popfirst(tbl, NULL)))
|
while ((hook = qlist_popfirst(tbl, NULL)))
|
||||||
{
|
{
|
||||||
if (hook->path)
|
restd_hook_free(hook);
|
||||||
free(hook->path);
|
|
||||||
free(hook);
|
|
||||||
}
|
}
|
||||||
server->hooks->free(server->hooks);
|
qlist_free(server->hooks);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(server);
|
free(server);
|
||||||
DEBUG("Server terminated.");
|
DEBUG("Server terminated.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*--------------------------------------------------------------------------
|
||||||
|
*
|
||||||
* Start server.
|
* Start server.
|
||||||
*
|
*
|
||||||
* @return 0 if successful, otherwise -1.
|
* @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,
|
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_callback cb, void *userdata)
|
||||||
{
|
{
|
||||||
restd_hook_t hook;
|
restd_hook_t *hook;
|
||||||
bzero((void *)&hook, sizeof(restd_hook_t));
|
char *fragment;
|
||||||
hook.method = method;
|
|
||||||
hook.path = (path) ? strdup(path) : NULL;
|
|
||||||
hook.cb = cb;
|
|
||||||
hook.userdata = userdata;
|
|
||||||
|
|
||||||
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;
|
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 -------------------------------*/
|
/*--------------------------- LOCAL FUNCTIONS -------------------------------*/
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------*/
|
||||||
@@ -509,7 +611,8 @@ static int set_undefined_options(restd_server_t *server)
|
|||||||
return newentries;
|
return newentries;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*--------------------------------------------------------------------------
|
||||||
|
*
|
||||||
* Retrieve server option.
|
* Retrieve server option.
|
||||||
*/
|
*/
|
||||||
char *restd_server_get_option(restd_server_t *server, const char *key)
|
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);
|
return server->options->getstr(server->options, key, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*--------------------------------------------------------------------------
|
||||||
|
*
|
||||||
* Retrieve server option in integer format.
|
* Retrieve server option in integer format.
|
||||||
*/
|
*/
|
||||||
int restd_server_get_option_int(restd_server_t *server, const char *key)
|
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
|
* 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
|
* event arrived. So we use eventfd as a internal notification channel to let
|
||||||
* server get out of the loop without waiting for an event.
|
* 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
|
// TODO 404
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
#if 0 // TODO
|
#if 0 // TODO
|
||||||
if (conn->server->error_handler != NULL)
|
if (conn->server->error_handler != NULL)
|
||||||
@@ -758,7 +862,7 @@ void rest_request_cb(struct evhttp_request *req, void *arg)
|
|||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
evhttp_send_reply(req, 500, "Internal Error", NULL);
|
evhttp_send_reply(req, 500, "Internal Error", NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,11 +38,11 @@
|
|||||||
|
|
||||||
typedef struct restd_server_s restd_server_t;
|
typedef struct restd_server_s restd_server_t;
|
||||||
typedef struct restd_hook_s restd_hook_t;
|
typedef struct restd_hook_s restd_hook_t;
|
||||||
|
typedef struct restd_resp_s restd_resp_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User callback(hook) prototype.
|
* 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 int (*restd_callback)(struct evhttp_request *req, void *arg);
|
||||||
typedef void (*restd_userdata_free_cb)(void *conn, void *userdata);
|
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 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 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 ------------------------------------*/
|
/*------------------------------- DEFINES ------------------------------------*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -107,7 +114,6 @@ struct restd_server_s
|
|||||||
|
|
||||||
struct bufferevent *notify_buffer; /*!< internal notification channel */
|
struct bufferevent *notify_buffer; /*!< internal notification channel */
|
||||||
|
|
||||||
restd_call_hook_cb call_hooks;
|
|
||||||
restd_callback request_handler;
|
restd_callback request_handler;
|
||||||
restd_callback error_handler;
|
restd_callback error_handler;
|
||||||
};
|
};
|
||||||
@@ -121,7 +127,21 @@ struct restd_hook_s
|
|||||||
char *path;
|
char *path;
|
||||||
restd_callback cb;
|
restd_callback cb;
|
||||||
void *userdata;
|
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 */
|
#endif /*_RESTD_H */
|
||||||
|
|||||||
Reference in New Issue
Block a user