vcpe/srcs/libs/network/http_svr.c

173 lines
5.5 KiB
C

//
// Created by xajhuang on 2022/11/4.
//
#ifdef HTTPSERVER_ON
#include <uv.h>
#include "http_svr.h"
#include "user_errno.h"
#include "config.h"
#include "common.h"
#include "uthash/uthash.h"
#include "zlog_module.h"
#include "s2j/cJSON.h"
#include "proto.h"
typedef struct {
HTTP_METHOD httpMethod;
char methodName[16];
} HTTP_METHOD_INFO;
#define GENERATE_HTTP_ENUM_ARRAY(ENUM, desc) {ENUM, desc},
static HTTP_METHOD_INFO g_httpMethod[] = {
DEF_HTTP_METHOD(GENERATE_HTTP_ENUM_ARRAY) {-1, "UNKNOWN"}
};
typedef struct {
char routeName[MAX_URI];
char *pMethod;
HTTP_ROUTE_PRIORITY priority;
HTTP_REQUEST_CB pCallbackHandler;
void *pUserData;
UT_hash_handle hh;
} HTTP_ROUTE_TABLE, *PHTTP_ROUTE_TABLE;
static uv_rwlock_t g_uvRouteLock;
static PHTTP_ROUTE_TABLE g_pHttpRoute = NULL;
static void rsp_err_msg(struct mg_connection *c, int httpCode, int errCode) {
cJSON *pRspMsg = cJSON_CreateObject();
cJSON_AddNumberToObject(pRspMsg, "status", errCode);
cJSON_AddStringToObject(pRspMsg, "message", getErrorEnumDesc(errCode));
const char *pStrPro = proto_create_new(pRspMsg, httpCode);
mg_http_reply(c, httpCode, "Content-Type: application/json\r\n", "%s\n", pStrPro ? pStrPro : "");
LOG_MOD(debug, ZLOG_MOD_HTTPD, "Response(%d): %s\n", httpCode, pStrPro);
if (pStrPro) {
free((void *)pStrPro);
}
}
static void on_mg_event_cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *)ev_data;
PHTTP_ROUTE_TABLE pItem, pTmp;
int matched = FALSE;
LOG_MOD(trace, ZLOG_MOD_HTTPD, "Request: %s\n", hm->uri.ptr);
HASH_ITER(hh, g_pHttpRoute, pItem, pTmp) {
if (mg_http_match_uri(hm, pItem->routeName)) {
struct mg_str m = mg_str(pItem->pMethod);
if (mg_strcmp(m, hm->method) == 0) {
PHTTP_RSP_CTX pCtx = (PHTTP_RSP_CTX)malloc(sizeof(HTTP_RSP_CTX));
if (pCtx) {
pItem->pCallbackHandler(hm, pItem->pUserData, pCtx);
if (pCtx->errCode == ERR_SUCCESS && pCtx->pRspData) {
mg_http_reply(c, pCtx->httpCode, pCtx->pRspHeads, "%s\n", pCtx->pRspData);
LOG_MOD(debug,
ZLOG_MOD_HTTPD,
"Response:(%d) %s\n",
pCtx->httpCode,
(char *)pCtx->pRspData);
} else {
rsp_err_msg(c, pCtx->httpCode, pCtx->errCode);
}
if (pCtx->pRspData) {
free(pCtx->pRspData);
}
} else {
rsp_err_msg(c, 500, ERR_MALLOC_MEMORY);
}
free(pCtx);
} else {
rsp_err_msg(c, 405, ERR_HTTP_UNSUP_METHOD);
}
matched = TRUE;
}
}
if (!matched) {
rsp_err_msg(c, 404, ERR_HTTP_UNSUP_PAGE);
}
}
}
static void httpLoopCb(void *UNUSED(pArg)) {
struct mg_mgr mgr;
char svrUrl[MAX_URI];
memset(svrUrl, 0, MAX_URI);
mg_log_set(MG_LL_DEBUG);
mg_mgr_init(&mgr); // Init manager
mg_http_listen(&mgr, config_get_http_server_addr(), on_mg_event_cb, &mgr); // Setup listener
for (;;) {
mg_mgr_poll(&mgr, 1000); // Event loop
}
mg_mgr_free(&mgr);
}
static int route_sort(PHTTP_ROUTE_TABLE a, PHTTP_ROUTE_TABLE b) {
return ((int)b->priority - (int)a->priority);
}
int http_add_route(const char *path,
HTTP_METHOD method,
HTTP_ROUTE_PRIORITY priority,
HTTP_REQUEST_CB cb,
void *pUserData) {
unsigned int nSize = sizeof(HTTP_ROUTE_TABLE);
PHTTP_ROUTE_TABLE pTbl;
if (path == NULL || strlen(path) == 0) {
return -ERR_INPUT_PARAMS;
} else if (method >= ARRAY_SIZE(g_httpMethod) || method < 0) {
return -ERR_INPUT_PARAMS;
} else if (cb == NULL) {
return -ERR_INPUT_PARAMS;
}
pTbl = (PHTTP_ROUTE_TABLE)malloc(nSize);
if (pTbl == NULL) {
LOG_MOD(error, ZLOG_MOD_HTTPD, "Malloc memory error size %u\n", nSize);
return -ERR_MALLOC_MEMORY;
}
memset(pTbl, 0, nSize);
pTbl->pMethod = g_httpMethod[method].methodName;
pTbl->priority = (priority < 0) ? PRI_LOWEASE : (priority > PRI_HIGHEST ? PRI_HIGHEST : priority);
pTbl->pCallbackHandler = cb;
pTbl->pUserData = pUserData;
strncpy(pTbl->routeName, path, MAX_URI);
uv_rwlock_wrlock(&g_uvRouteLock);
HASH_ADD_STR(g_pHttpRoute, routeName, pTbl);
HASH_SORT(g_pHttpRoute, route_sort);
uv_rwlock_wrunlock(&g_uvRouteLock);
return -ERR_SUCCESS;
}
int http_svr_init() {
static uv_thread_t uvThread;
uv_rwlock_init(&g_uvRouteLock);
uv_thread_create(&uvThread, httpLoopCb, NULL);
return ERR_SUCCESS;
}
int http_svr_uinit() {
PHTTP_ROUTE_TABLE pItem, pTmp;
HASH_ITER(hh, g_pHttpRoute, pItem, pTmp) {
uv_rwlock_wrlock(&g_uvRouteLock);
HASH_DEL(g_pHttpRoute, pItem);
uv_rwlock_wrunlock(&g_uvRouteLock);
free(pItem);
}
return ERR_SUCCESS;
}
#endif