173 lines
5.5 KiB
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 "misc.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 |