Lua binding: Make the code more robust

Signed-off-by: Jianhui Zhao <jianhuizhao329@gmail.com>
main
Jianhui Zhao 2018-07-25 13:19:38 +08:00
parent deaec21076
commit 34e94f6d5e
3 changed files with 354 additions and 276 deletions

View File

@ -55,10 +55,10 @@ local http_version = {
} }
srv:on_error404(function(cl, path) srv:on_error404(function(cl, path)
uh.send_header(cl, 200, "OK", -1) cl:send_header(200, "OK", -1)
uh.header_end(cl) cl:header_end()
uh.chunk_send(cl, string.format("<h1>Libuhttpd-Lua: '%s' Not found</h1>", path)) cl:chunk_send(string.format("<h1>Libuhttpd-Lua: '%s' Not found</h1>", path))
uh.request_done(cl) cl:request_done()
end) end)
@ -67,41 +67,41 @@ srv:on_request(function(cl, path)
return uh.REQUEST_CONTINUE return uh.REQUEST_CONTINUE
end end
uh.send_header(cl, 200, "OK", -1) cl:send_header(200, "OK", -1)
uh.append_header(cl, "Myheader", "Hello") cl:append_header("Myheader", "Hello")
uh.header_end(cl) cl:header_end()
uh.chunk_send(cl, string.format("<h1>Hello Libuhttpd %s</h1>", uh.VERSION)) cl:chunk_send(string.format("<h1>Hello Libuhttpd %s</h1>", uh.VERSION))
uh.chunk_send(cl, string.format("<h1>REMOTE_ADDR: %s</h1>", uh.get_remote_addr(cl))) cl:chunk_send(string.format("<h1>REMOTE_ADDR: %s</h1>", cl:get_remote_addr()))
uh.chunk_send(cl, string.format("<h1>METHOD: %s</h1>", http_methods[uh.get_http_method(cl)])) cl:chunk_send(string.format("<h1>METHOD: %s</h1>", http_methods[cl:get_http_method()]))
uh.chunk_send(cl, string.format("<h1>HTTP Version: %s</h1>", http_version[uh.get_http_version(cl)])) cl:chunk_send(string.format("<h1>HTTP Version: %s</h1>", http_version[cl:get_http_version()]))
uh.chunk_send(cl, string.format("<h1>URL: %s</h1>", uh.get_url(cl))) cl:chunk_send(string.format("<h1>URL: %s</h1>", cl:get_url()))
uh.chunk_send(cl, string.format("<h1>QUERY: %s</h1>", uh.get_query(cl) or "")) cl:chunk_send(string.format("<h1>QUERY: %s</h1>", cl:get_query() or ""))
uh.chunk_send(cl, string.format("<h1>Body: %s</h1>", uh.get_body(cl) or "")) cl:chunk_send(string.format("<h1>Body: %s</h1>", cl:get_body() or ""))
-- Get a http var -- Get a http var
local var_x = uh.get_var(cl, "x") local var_x = cl:get_var("x")
uh.chunk_send(cl, string.format("<h1>Var x: %s</h1>", var_x or "")) cl:chunk_send(string.format("<h1>Var x: %s</h1>", var_x or ""))
-- Get a http header -- Get a http header
local user_agent = uh.get_header(cl, "user-agent") local user_agent = cl:get_header("user-agent")
uh.chunk_send(cl, string.format("<h1>User-Agent: %s</h1>", user_agent)) cl:chunk_send(string.format("<h1>User-Agent: %s</h1>", user_agent))
uh.chunk_send(cl, "<hr />") cl:chunk_send("<hr />")
-- Get all http vars -- Get all http vars
local vars = uh.get_var(cl) local vars = cl:get_var()
for k, v in pairs(vars) do for k, v in pairs(vars) do
uh.chunk_send(cl, string.format("<h1>%s: %s</h1>", k, v)) cl:chunk_send(string.format("<h1>%s: %s</h1>", k, v))
end end
uh.chunk_send(cl, "<hr />") cl:chunk_send("<hr />")
-- Get all http headers -- Get all http headers
local headers = uh.get_header(cl) local headers = cl:get_header()
for k, v in pairs(headers) do for k, v in pairs(headers) do
uh.chunk_send(cl, string.format("<h1>%s: %s</h1>", k, v)) cl:chunk_send(string.format("<h1>%s: %s</h1>", k, v))
end end
uh.request_done(cl) cl:request_done()
return uh.REQUEST_DONE return uh.REQUEST_DONE
end) end)

575
src/lua/uhttpd-lua.c 100644 → 100755
View File

@ -23,13 +23,27 @@
#include "uhttpd.h" #include "uhttpd.h"
#include "uhttpd-lua.h" #include "uhttpd-lua.h"
static void *uh_create_userdata(lua_State *L, size_t size, const luaL_Reg *reg, lua_CFunction gc) static const char *cli_registry = "libuhttpd-cli{obj}";
#if 0
static void lua_print_stack(lua_State *L, const char *info)
{
int i = 1;
printf("----------%s----------\n", info);
for (; i <= lua_gettop(L); i++) {
printf("%d %s\n", i, lua_typename(L, lua_type(L, i)));
}
}
#endif
static void *uh_create_userdata(lua_State *L, size_t size, const luaL_Reg *reg, const char *mt, lua_CFunction gc)
{ {
void *obj = lua_newuserdata(L, size); void *obj = lua_newuserdata(L, size);
memset(obj, 0, size); memset(obj, 0, size);
luaL_newmetatable(L, LUA_UH_SERVER_MT); luaL_newmetatable(L, mt);
/* metatable.__index = metatable */ /* metatable.__index = metatable */
lua_pushvalue(L, -1); lua_pushvalue(L, -1);
@ -45,22 +59,313 @@ static void *uh_create_userdata(lua_State *L, size_t size, const luaL_Reg *reg,
return obj; return obj;
} }
static int lua_uh_send_header(lua_State *L)
{
struct lua_uh_client *lcl = luaL_checkudata(L, 1, LUA_UH_CLIENT_MT);
struct uh_client *cl = lcl->cl;
int code = lua_tointeger(L, 2);
const char *summary = lua_tostring(L, 3);
int len = lua_tointeger(L, 4);
cl->send_header(cl, code, summary, len);
return 0;
}
static int lua_uh_append_header(lua_State *L)
{
struct lua_uh_client *lcl = luaL_checkudata(L, 1, LUA_UH_CLIENT_MT);
struct uh_client *cl = lcl->cl;
const char *name = lua_tostring(L, 2);
const char *value = lua_tostring(L, 2);
cl->append_header(cl, name, value);
return 0;
}
static int lua_uh_header_end(lua_State *L)
{
struct lua_uh_client *lcl = luaL_checkudata(L, 1, LUA_UH_CLIENT_MT);
struct uh_client *cl = lcl->cl;
cl->header_end(cl);
return 0;
}
static int lua_uh_send(lua_State *L)
{
struct lua_uh_client *lcl = luaL_checkudata(L, 1, LUA_UH_CLIENT_MT);
struct uh_client *cl = lcl->cl;
const char *data;
size_t len;
data = lua_tolstring(L, 2, &len);
cl->send(cl, data, len);
return 0;
}
static int lua_uh_chunk_send(lua_State *L)
{
struct lua_uh_client *lcl = luaL_checkudata(L, 1, LUA_UH_CLIENT_MT);
struct uh_client *cl = lcl->cl;
const char *data;
size_t len;
data = lua_tolstring(L, 2, &len);
cl->chunk_send(cl, data, len);
return 0;
}
static int lua_uh_send_error(lua_State *L)
{
struct lua_uh_client *lcl = luaL_checkudata(L, 1, LUA_UH_CLIENT_MT);
struct uh_client *cl = lcl->cl;
int code = lua_tointeger(L, 2);
const char *summary = lua_tostring(L, 3);
const char *msg = lua_tostring(L, 4);
cl->send_error(cl, code, summary, msg);
return 0;
}
static int lua_uh_redirect(lua_State *L)
{
struct lua_uh_client *lcl = luaL_checkudata(L, 1, LUA_UH_CLIENT_MT);
struct uh_client *cl = lcl->cl;
int code = lua_tointeger(L, 2);
const char *url = lua_tostring(L, 3);
cl->redirect(cl, code, url);
return 0;
}
static int lua_uh_request_done(lua_State *L)
{
struct lua_uh_client *lcl = luaL_checkudata(L, 1, LUA_UH_CLIENT_MT);
struct uh_client *cl = lcl->cl;
cl->request_done(cl);
return 0;
}
static int lua_uh_get_http_method(lua_State *L)
{
struct lua_uh_client *lcl = luaL_checkudata(L, 1, LUA_UH_CLIENT_MT);
struct uh_client *cl = lcl->cl;
lua_pushinteger(L, cl->request.method);
return 1;
}
static int lua_uh_get_http_version(lua_State *L)
{
struct lua_uh_client *lcl = luaL_checkudata(L, 1, LUA_UH_CLIENT_MT);
struct uh_client *cl = lcl->cl;
lua_pushinteger(L, cl->request.version);
return 1;
}
static int lua_uh_get_remote_addr(lua_State *L)
{
struct lua_uh_client *lcl = luaL_checkudata(L, 1, LUA_UH_CLIENT_MT);
struct uh_client *cl = lcl->cl;
const char *addr = cl->get_peer_addr(cl);
if (addr)
lua_pushstring(L, addr);
else
lua_pushnil(L);
return 1;
}
static int lua_uh_get_header(lua_State *L)
{
struct lua_uh_client *lcl = luaL_checkudata(L, 1, LUA_UH_CLIENT_MT);
struct uh_client *cl = lcl->cl;
const char *name = lua_tostring(L, 2);
const char *value;
if (name) {
value = cl->get_header(cl, name);
if (value)
lua_pushstring(L, value);
else
lua_pushnil(L);
return 1;
}
lua_newtable(L);
kvlist_for_each(&cl->request.header, name, value) {
lua_pushstring(L, value);
lua_setfield(L, -2, name);
}
return 1;
}
static int lua_uh_get_var(lua_State *L)
{
struct lua_uh_client *lcl = luaL_checkudata(L, 1, LUA_UH_CLIENT_MT);
struct uh_client *cl = lcl->cl;
const char *name = lua_tostring(L, 2);
const char *value;
if (name) {
value = cl->get_var(cl, name);
if (value)
lua_pushstring(L, value);
else
lua_pushnil(L);
return 1;
}
lua_newtable(L);
kvlist_for_each(&cl->request.var, name, value) {
lua_pushstring(L, value);
lua_setfield(L, -2, name);
}
return 1;
}
static int lua_uh_get_query(lua_State *L)
{
struct lua_uh_client *lcl = luaL_checkudata(L, 1, LUA_UH_CLIENT_MT);
struct uh_client *cl = lcl->cl;
const char *query = cl->get_query(cl);
if (query)
lua_pushstring(L, query);
else
lua_pushnil(L);
return 1;
}
static int lua_uh_get_url(lua_State *L)
{
struct lua_uh_client *lcl = luaL_checkudata(L, 1, LUA_UH_CLIENT_MT);
struct uh_client *cl = lcl->cl;
const char *url = cl->get_url(cl);
if (url)
lua_pushstring(L, url);
else
lua_pushnil(L);
return 1;
}
static int lua_uh_get_body(lua_State *L)
{
struct lua_uh_client *lcl = luaL_checkudata(L, 1, LUA_UH_CLIENT_MT);
struct uh_client *cl = lcl->cl;
const char *body;
int len;
body = cl->get_body(cl, &len);
if (body)
lua_pushlstring(L, body, len);
else
lua_pushnil(L);
return 1;
}
static int lua_uh_cli_free(lua_State *L)
{
return 0;
}
static const luaL_Reg client_reg[] = {
{"send_header", lua_uh_send_header},
{"append_header", lua_uh_append_header},
{"header_end", lua_uh_header_end},
{"send", lua_uh_send},
{"chunk_send", lua_uh_chunk_send},
{"send_error", lua_uh_send_error},
{"redirect", lua_uh_redirect},
{"request_done", lua_uh_request_done},
{"get_http_method", lua_uh_get_http_method},
{"get_http_version", lua_uh_get_http_version},
{"get_remote_addr", lua_uh_get_remote_addr},
{"get_header", lua_uh_get_header},
{"get_var", lua_uh_get_var},
{"get_query", lua_uh_get_query},
{"get_url", lua_uh_get_url},
{"get_body", lua_uh_get_body},
{ "free", lua_uh_cli_free },
{ NULL, NULL }
};
static void lua_on_accept(struct uh_client *cl)
{
lua_State *L = cl->srv->L;
struct lua_uh_client *lcl;
lua_pushlightuserdata(L, &cli_registry);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_pushlightuserdata(L, cl);
lcl = uh_create_userdata(L, sizeof(struct lua_uh_client), client_reg, LUA_UH_CLIENT_MT, lua_uh_cli_free);
lcl->cl = cl;
lua_rawset(L, -3);
}
static int lua_do_request_cb(lua_State *L, struct uh_client *cl)
{
const char *path = cl->get_path(cl);
lua_pushlightuserdata(L, &cli_registry);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_pushlightuserdata(L, cl);
lua_rawget(L, -2);
lua_insert(L, -2);
lua_pop(L, 1);
lua_pushstring(L, path);
lua_call(L, 2, 1);
return lua_tointeger(L, -1);
}
static int lua_on_request(struct uh_client *cl) static int lua_on_request(struct uh_client *cl)
{ {
struct lua_uh_server *lsrv = container_of(cl->srv, struct lua_uh_server, srv); struct lua_uh_server *lsrv = container_of(cl->srv, struct lua_uh_server, srv);
const char *path = cl->get_path(cl);
lua_State *L = cl->srv->L; lua_State *L = cl->srv->L;
lua_getglobal(L, "__uh_on_request"); lua_getglobal(L, "__uh_on_request");
lua_rawgeti(L, -1, lsrv->request_ref); lua_rawgeti(L, -1, lsrv->request_ref);
lua_remove(L, -2); lua_remove(L, -2);
lua_pushlightuserdata(L, cl); return lua_do_request_cb(L, cl);
lua_pushstring(L, path); }
lua_call(L, 2, 1); static void lua_on_error404(struct uh_client *cl)
{
struct lua_uh_server *lsrv = container_of(cl->srv, struct lua_uh_server, srv);
lua_State *L = cl->srv->L;
return lua_tointeger(L, -1); lua_getglobal(L, "__uh_on_error404");
lua_rawgeti(L, -1, lsrv->error404_ref);
lua_remove(L, -2);
lua_do_request_cb(L, cl);
} }
static int lua_uh_ssl_init(lua_State *L) static int lua_uh_ssl_init(lua_State *L)
@ -80,22 +385,6 @@ static int lua_uh_ssl_init(lua_State *L)
return 0; return 0;
} }
static void lua_on_error404(struct uh_client *cl)
{
struct lua_uh_server *lsrv = container_of(cl->srv, struct lua_uh_server, srv);
const char *path = cl->get_path(cl);
lua_State *L = cl->srv->L;
lua_getglobal(L, "__uh_on_error404");
lua_rawgeti(L, -1, lsrv->error404_ref);
lua_remove(L, -2);
lua_pushlightuserdata(L, cl);
lua_pushstring(L, path);
lua_call(L, 2, 0);
}
static int lua_uh_set_options(lua_State *L) static int lua_uh_set_options(lua_State *L)
{ {
struct lua_uh_server *lsrv = luaL_checkudata(L, 1, LUA_UH_SERVER_MT); struct lua_uh_server *lsrv = luaL_checkudata(L, 1, LUA_UH_SERVER_MT);
@ -155,7 +444,7 @@ static int lua_uh_server_free(lua_State *L)
return 0; return 0;
} }
static const luaL_Reg server_mt[] = { static const luaL_Reg server_reg[] = {
{ "ssl_init", lua_uh_ssl_init }, { "ssl_init", lua_uh_ssl_init },
{ "set_options", lua_uh_set_options }, { "set_options", lua_uh_set_options },
{ "on_error404", lua_uh_set_error404_cb }, { "on_error404", lua_uh_set_error404_cb },
@ -178,220 +467,12 @@ static int lua_uh_new(lua_State *L)
return 2; return 2;
} }
lsrv = uh_create_userdata(L, sizeof(struct lua_uh_server), server_mt, lua_uh_server_free); lsrv = uh_create_userdata(L, sizeof(struct lua_uh_server), server_reg, LUA_UH_SERVER_MT, lua_uh_server_free);
uh_server_init(&lsrv->srv, sock); uh_server_init(&lsrv->srv, sock);
lsrv->srv.L = L; lsrv->srv.L = L;
lsrv->srv.on_accept = lua_on_accept;
return 1;
}
static int lua_uh_send_header(lua_State *L)
{
struct uh_client *cl = lua_touserdata(L, 1);
int code = lua_tointeger(L, 2);
const char *summary = lua_tostring(L, 3);
int len = lua_tointeger(L, 4);
cl->send_header(cl, code, summary, len);
return 0;
}
static int lua_uh_append_header(lua_State *L)
{
struct uh_client *cl = lua_touserdata(L, 1);
const char *name = lua_tostring(L, 2);
const char *value = lua_tostring(L, 2);
cl->append_header(cl, name, value);
return 0;
}
static int lua_uh_header_end(lua_State *L)
{
struct uh_client *cl = lua_touserdata(L, 1);
cl->header_end(cl);
return 0;
}
static int lua_uh_send(lua_State *L)
{
struct uh_client *cl = lua_touserdata(L, 1);
const char *data;
size_t len;
data = lua_tolstring(L, 2, &len);
cl->send(cl, data, len);
return 0;
}
static int lua_uh_chunk_send(lua_State *L)
{
struct uh_client *cl = lua_touserdata(L, 1);
const char *data;
size_t len;
data = lua_tolstring(L, 2, &len);
cl->chunk_send(cl, data, len);
return 0;
}
static int lua_uh_send_error(lua_State *L)
{
struct uh_client *cl = lua_touserdata(L, 1);
int code = lua_tointeger(L, 2);
const char *summary = lua_tostring(L, 3);
const char *msg = lua_tostring(L, 4);
cl->send_error(cl, code, summary, msg);
return 0;
}
static int lua_uh_redirect(lua_State *L)
{
struct uh_client *cl = lua_touserdata(L, 1);
int code = lua_tointeger(L, 2);
const char *url = lua_tostring(L, 3);
cl->redirect(cl, code, url);
return 0;
}
static int lua_uh_request_done(lua_State *L)
{
struct uh_client *cl = lua_touserdata(L, 1);
cl->request_done(cl);
return 0;
}
static int lua_uh_get_http_method(lua_State *L)
{
struct uh_client *cl = lua_touserdata(L, 1);
lua_pushinteger(L, cl->request.method);
return 1;
}
static int lua_uh_get_http_version(lua_State *L)
{
struct uh_client *cl = lua_touserdata(L, 1);
lua_pushinteger(L, cl->request.version);
return 1;
}
static int lua_uh_get_remote_addr(lua_State *L)
{
struct uh_client *cl = lua_touserdata(L, 1);
const char *addr = cl->get_peer_addr(cl);
if (addr)
lua_pushstring(L, addr);
else
lua_pushnil(L);
return 1;
}
static int lua_uh_get_header(lua_State *L)
{
struct uh_client *cl = lua_touserdata(L, 1);
const char *name = lua_tostring(L, 2);
const char *value;
if (name) {
value = cl->get_header(cl, name);
if (value)
lua_pushstring(L, value);
else
lua_pushnil(L);
return 1;
}
lua_newtable(L);
kvlist_for_each(&cl->request.header, name, value) {
lua_pushstring(L, value);
lua_setfield(L, -2, name);
}
return 1;
}
static int lua_uh_get_var(lua_State *L)
{
struct uh_client *cl = lua_touserdata(L, 1);
const char *name = lua_tostring(L, 2);
const char *value;
if (name) {
value = cl->get_var(cl, name);
if (value)
lua_pushstring(L, value);
else
lua_pushnil(L);
return 1;
}
lua_newtable(L);
kvlist_for_each(&cl->request.var, name, value) {
lua_pushstring(L, value);
lua_setfield(L, -2, name);
}
return 1;
}
static int lua_uh_get_query(lua_State *L)
{
struct uh_client *cl = lua_touserdata(L, 1);
const char *query = cl->get_query(cl);
if (query)
lua_pushstring(L, query);
else
lua_pushnil(L);
return 1;
}
static int lua_uh_get_url(lua_State *L)
{
struct uh_client *cl = lua_touserdata(L, 1);
const char *url = cl->get_url(cl);
if (url)
lua_pushstring(L, url);
else
lua_pushnil(L);
return 1;
}
static int lua_uh_get_body(lua_State *L)
{
struct uh_client *cl = lua_touserdata(L, 1);
const char *body;
int len;
body = cl->get_body(cl, &len);
if (body)
lua_pushlstring(L, body, len);
else
lua_pushnil(L);
return 1; return 1;
} }
@ -417,22 +498,6 @@ static int lua_uh_set_log_threshold(lua_State *L)
static const luaL_Reg uhttpd_fun[] = { static const luaL_Reg uhttpd_fun[] = {
{"new", lua_uh_new}, {"new", lua_uh_new},
{"send_header", lua_uh_send_header},
{"append_header", lua_uh_append_header},
{"header_end", lua_uh_header_end},
{"send", lua_uh_send},
{"chunk_send", lua_uh_chunk_send},
{"send_error", lua_uh_send_error},
{"redirect", lua_uh_redirect},
{"request_done", lua_uh_request_done},
{"get_http_method", lua_uh_get_http_method},
{"get_http_version", lua_uh_get_http_version},
{"get_remote_addr", lua_uh_get_remote_addr},
{"get_header", lua_uh_get_header},
{"get_var", lua_uh_get_var},
{"get_query", lua_uh_get_query},
{"get_url", lua_uh_get_url},
{"get_body", lua_uh_get_body},
{"log", lua_uh_log}, {"log", lua_uh_log},
{"set_log_threshold", lua_uh_set_log_threshold}, {"set_log_threshold", lua_uh_set_log_threshold},
{NULL, NULL} {NULL, NULL}
@ -440,6 +505,14 @@ static const luaL_Reg uhttpd_fun[] = {
int luaopen_uhttpd(lua_State *L) int luaopen_uhttpd(lua_State *L)
{ {
/**
* Create a "registry" of light userdata pointers into the
* fulluserdata so that we can get handles into the lua objects.
*/
lua_pushlightuserdata(L, &cli_registry);
lua_newtable(L);
lua_rawset(L, LUA_REGISTRYINDEX);
lua_newtable(L); lua_newtable(L);
lua_setglobal(L, "__uh_on_request"); lua_setglobal(L, "__uh_on_request");

5
src/lua/uhttpd-lua.h 100644 → 100755
View File

@ -32,6 +32,11 @@
#endif #endif
#define LUA_UH_SERVER_MT "libuhttpd" #define LUA_UH_SERVER_MT "libuhttpd"
#define LUA_UH_CLIENT_MT "libuhttpd(cli)"
struct lua_uh_client {
struct uh_client *cl;
};
struct lua_uh_server { struct lua_uh_server {
struct uh_server srv; struct uh_server srv;