diff options
author | Jo-Philipp Wich <jow@openwrt.org> | 2010-03-18 17:45:50 +0000 |
---|---|---|
committer | Jo-Philipp Wich <jow@openwrt.org> | 2010-03-18 17:45:50 +0000 |
commit | 87329b4522760f0a4a9a7962a52faf76d2db6f55 (patch) | |
tree | 09f47c80b40eda6de245cfb9ac05377243b603c7 /contrib/package/uhttpd/src/uhttpd-lua.c | |
parent | 1661add529c525939a27ae47c1429bfe50615211 (diff) |
contrib/package: add uhttpd, a drop-in replacement for busybox httpd
Diffstat (limited to 'contrib/package/uhttpd/src/uhttpd-lua.c')
-rw-r--r-- | contrib/package/uhttpd/src/uhttpd-lua.c | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/contrib/package/uhttpd/src/uhttpd-lua.c b/contrib/package/uhttpd/src/uhttpd-lua.c new file mode 100644 index 000000000..79fb76770 --- /dev/null +++ b/contrib/package/uhttpd/src/uhttpd-lua.c @@ -0,0 +1,299 @@ +#include "uhttpd.h" +#include "uhttpd-lua.h" +#include "uhttpd-utils.h" + + +static int uh_lua_recv(lua_State *L) +{ + size_t length; + char buffer[UH_LIMIT_MSGHEAD]; + ssize_t rlen = 0; + fd_set reader; + struct timeval timeout; + struct client *cl; + + luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); + cl = (struct client *) lua_topointer(L, 1); + length = luaL_checknumber(L, 2); + + if( (cl != NULL) && (length > 0) && (length <= sizeof(buffer)) ) + { + FD_ZERO(&reader); + FD_SET(cl->socket, &reader); + + /* fail after 0.1s */ + timeout.tv_sec = 0; + timeout.tv_usec = 100000; + + /* first return stuff from peek buffer */ + if( cl->peeklen > 0 ) + { + /* receive data */ + rlen = uh_tcp_recv(cl, buffer, min(cl->peeklen, length)); + lua_pushnumber(L, rlen); + lua_pushlstring(L, buffer, rlen); + + return 2; + } + + /* check whether fd is readable */ + else if( select(cl->socket + 1, &reader, NULL, NULL, &timeout) > 0 ) + { + /* receive data */ + rlen = uh_tcp_recv(cl, buffer, length); + lua_pushnumber(L, rlen); + + if( rlen > 0 ) + { + lua_pushlstring(L, buffer, rlen); + return 2; + } + + return 1; + } + + /* no, timeout and actually no data */ + lua_pushnumber(L, -2); + return 1; + } + + /* parameter error */ + lua_pushnumber(L, -3); + return 1; +} + +static int uh_lua_send(lua_State *L) +{ + size_t length; + const char *buffer; + ssize_t slen = 0; + struct client *cl; + + luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); + cl = (struct client *) lua_topointer(L, 1); + buffer = luaL_checklstring(L, 2, &length); + + if( (cl != NULL) && (length > 0) ) + { + slen = uh_tcp_send(cl, buffer, length); + lua_pushnumber(L, slen); + return 1; + } + + lua_pushnumber(L, -1); + return 1; +} + +static int uh_lua_urldecode(lua_State *L) +{ + size_t inlen, outlen; + const char *inbuf; + char outbuf[UH_LIMIT_MSGHEAD]; + + inbuf = luaL_checklstring(L, 1, &inlen); + outlen = uh_urldecode(outbuf, sizeof(outbuf), inbuf, inlen); + + lua_pushlstring(L, outbuf, outlen); + return 1; +} + + +lua_State * uh_lua_init(const char *handler) +{ + lua_State *L = lua_open(); + const luaL_reg *lib; + const char *err_str = NULL; + + /* Declare the Lua libraries we wish to use. */ + /* Note: If you are opening and running a file containing Lua code */ + /* using 'lua_dofile(l, "myfile.lua") - you must delcare all the libraries */ + /* used in that file here also. */ + static const luaL_reg lualibs[] = + { + { "base", luaopen_base }, + { "string", luaopen_string }, + { NULL, NULL } + }; + + /* preload libraries */ + for (lib = lualibs; lib->func != NULL; lib++) + { + lib->func(L); + lua_settop(L, 0); + } + + /* register global send and receive functions */ + lua_pushcfunction(L, uh_lua_recv); + lua_setfield(L, LUA_GLOBALSINDEX, "recv"); + + lua_pushcfunction(L, uh_lua_send); + lua_setfield(L, LUA_GLOBALSINDEX, "send"); + + lua_pushcfunction(L, uh_lua_urldecode); + lua_setfield(L, LUA_GLOBALSINDEX, "urldecode"); + + + /* load Lua handler */ + switch( luaL_loadfile(L, handler) ) + { + case LUA_ERRSYNTAX: + fprintf(stderr, + "Lua handler contains syntax errors, unable to continue\n"); + exit(1); + + case LUA_ERRMEM: + fprintf(stderr, + "Lua handler ran out of memory, unable to continue\n"); + exit(1); + + case LUA_ERRFILE: + fprintf(stderr, + "Lua cannot open the handler script, unable to continue\n"); + exit(1); + + default: + /* compile Lua handler */ + switch( lua_pcall(L, 0, 0, 0) ) + { + case LUA_ERRRUN: + err_str = luaL_checkstring(L, -1); + fprintf(stderr, + "Lua handler had runtime error, unable to continue\n" + "Error: %s\n", err_str + ); + exit(1); + + case LUA_ERRMEM: + err_str = luaL_checkstring(L, -1); + fprintf(stderr, + "Lua handler ran out of memory, unable to continue\n" + "Error: %s\n", err_str + ); + exit(1); + + default: + /* test handler function */ + lua_getglobal(L, UH_LUA_CALLBACK); + + if( ! lua_isfunction(L, -1) ) + { + fprintf(stderr, + "Lua handler provides no " UH_LUA_CALLBACK "(), unable to continue\n"); + exit(1); + } + + lua_pop(L, 1); + break; + } + + break; + } + + return L; +} + +void uh_lua_request(struct client *cl, struct http_request *req, lua_State *L) +{ + int i; + char *query_string; + const char *err_str = NULL; + + /* put handler callback on stack */ + lua_getglobal(L, UH_LUA_CALLBACK); + + + /* build env table */ + lua_newtable(L); + + /* client object */ + lua_pushlightuserdata(L, (void *)cl); + lua_setfield(L, -2, "client"); + + /* request method */ + switch(req->method) + { + case UH_HTTP_MSG_GET: + lua_pushstring(L, "get"); + break; + + case UH_HTTP_MSG_HEAD: + lua_pushstring(L, "head"); + break; + + case UH_HTTP_MSG_POST: + lua_pushstring(L, "post"); + break; + } + + lua_setfield(L, -2, "request_method"); + + /* request url */ + lua_pushstring(L, req->url); + lua_setfield(L, -2, "request_url"); + + /* query string, path info */ + if( (query_string = strchr(req->url, '?')) != NULL ) + { + lua_pushstring(L, query_string + 1); + lua_setfield(L, -2, "query_string"); + + lua_pushlstring(L, req->url, (int)(query_string - req->url)); + lua_setfield(L, -2, "path_info"); + } + else + { + lua_pushstring(L, req->url); + lua_setfield(L, -2, "path_info"); + } + + /* http protcol version */ + lua_pushnumber(L, floor(req->version * 10) / 10); + lua_setfield(L, -2, "http_version"); + + + /* address information */ + lua_pushstring(L, sa_straddr(&cl->peeraddr)); + lua_setfield(L, -2, "remote_addr"); + + lua_pushinteger(L, sa_port(&cl->peeraddr)); + lua_setfield(L, -2, "remote_port"); + + lua_pushstring(L, sa_straddr(&cl->servaddr)); + lua_setfield(L, -2, "server_addr"); + + lua_pushinteger(L, sa_port(&cl->servaddr)); + lua_setfield(L, -2, "server_port"); + + + /* headers */ + lua_newtable(L); + + foreach_header(i, req->headers) + { + lua_pushstring(L, req->headers[i+1]); + lua_setfield(L, -2, req->headers[i]); + } + + lua_setfield(L, -2, "headers"); + + + /* call */ + switch( lua_pcall(L, 1, 0, 0) ) + { + case LUA_ERRRUN: + err_str = luaL_checkstring(L, -1); + uh_http_sendhf(cl, 500, "Lua runtime error", + "Lua raised an error:\n%s\n", err_str); + break; + + case LUA_ERRMEM: + err_str = luaL_checkstring(L, -1); + uh_http_sendhf(cl, 500, "Lua out of memory", + "Lua raised an error:\n%s\n", err_str); + break; + + default: + break; + } +} + |