root/luci/trunk/contrib/package/uhttpd/src/uhttpd-lua.c @ 5898

Revision 5898, 7.3 KB (checked in by jow, 3 years ago)

uhttpd: expose uh_http_sendc() to Lua, move server functions into uhttpd namespace

Line 
1/*
2 * uhttpd - Tiny non-forking httpd - Lua handler
3 *
4 *   Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org>
5 *
6 *  Licensed under the Apache License, Version 2.0 (the "License");
7 *  you may not use this file except in compliance with the License.
8 *  You may obtain a copy of the License at
9 *
10 *      http://www.apache.org/licenses/LICENSE-2.0
11 *
12 *  Unless required by applicable law or agreed to in writing, software
13 *  distributed under the License is distributed on an "AS IS" BASIS,
14 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 *  See the License for the specific language governing permissions and
16 *  limitations under the License.
17 */
18
19#include "uhttpd.h"
20#include "uhttpd-utils.h"
21#include "uhttpd-lua.h"
22
23
24static int uh_lua_recv(lua_State *L)
25{
26    size_t length;
27    char buffer[UH_LIMIT_MSGHEAD];
28    ssize_t rlen = 0;
29    fd_set reader;
30    struct timeval timeout;
31    struct client *cl;
32
33    luaL_checktype(L, 1, LUA_TLIGHTUSERDATA);
34    cl = (struct client *) lua_topointer(L, 1);
35    length = luaL_checknumber(L, 2);
36
37    if( (cl != NULL) && (length > 0) && (length <= sizeof(buffer)) )
38    {
39        FD_ZERO(&reader);
40        FD_SET(cl->socket, &reader);
41
42        /* fail after 0.1s */
43        timeout.tv_sec  = 0;
44        timeout.tv_usec = 100000;
45
46        /* first return stuff from peek buffer */
47        if( cl->peeklen > 0 )
48        {
49            /* receive data */
50            rlen = uh_tcp_recv(cl, buffer, min(cl->peeklen, length));
51            lua_pushnumber(L, rlen);
52            lua_pushlstring(L, buffer, rlen);
53
54            return 2;
55        }
56
57        /* check whether fd is readable */
58        else if( select(cl->socket + 1, &reader, NULL, NULL, &timeout) > 0 )
59        {
60            /* receive data */
61            rlen = uh_tcp_recv(cl, buffer, length);
62            lua_pushnumber(L, rlen);
63
64            if( rlen > 0 )
65            {
66                lua_pushlstring(L, buffer, rlen);
67                return 2;
68            }
69
70            return 1;
71        }
72
73        /* no, timeout and actually no data */
74        lua_pushnumber(L, -2);
75        return 1;
76    }
77
78    /* parameter error */
79    lua_pushnumber(L, -3);
80    return 1;
81}
82
83static int uh_lua_send_common(lua_State *L, int chunked)
84{
85    size_t length;
86    const char *buffer;
87    ssize_t slen = 0;
88    struct client *cl;
89
90    luaL_checktype(L, 1, LUA_TLIGHTUSERDATA);
91    cl = (struct client *) lua_topointer(L, 1);
92    buffer = luaL_checklstring(L, 2, &length);
93
94    if( (cl != NULL) && (length > 0) )
95    {
96        if( chunked )
97            slen = uh_http_sendc(cl, buffer, length);
98        else
99            slen = uh_tcp_send(cl, buffer, length);
100
101        lua_pushnumber(L, slen);
102        return 1;
103    }
104
105    lua_pushnumber(L, -1);
106    return 1;
107}
108
109static int uh_lua_send(lua_State *L)
110{
111    return uh_lua_send_common(L, 0);
112}
113
114static int uh_lua_sendc(lua_State *L)
115{
116    return uh_lua_send_common(L, 1);
117}
118
119static int uh_lua_urldecode(lua_State *L)
120{
121    size_t inlen, outlen;
122    const char *inbuf;
123    char outbuf[UH_LIMIT_MSGHEAD];
124
125    inbuf = luaL_checklstring(L, 1, &inlen);
126    outlen = uh_urldecode(outbuf, sizeof(outbuf), inbuf, inlen);
127
128    lua_pushlstring(L, outbuf, outlen);
129    return 1;
130}
131
132
133lua_State * uh_lua_init(const char *handler)
134{
135    lua_State *L = lua_open();
136    const luaL_reg *lib;
137    const char *err_str = NULL;
138
139    /* Declare the Lua libraries we wish to use. */
140    /* Note: If you are opening and running a file containing Lua code */
141    /* using 'lua_dofile(l, "myfile.lua") - you must delcare all the libraries */
142    /* used in that file here also. */
143    static const luaL_reg lualibs[] =
144    {
145            { "base",       luaopen_base },
146            { "string",     luaopen_string },
147            { NULL,         NULL }
148    };
149
150    /* preload libraries */
151    for (lib = lualibs; lib->func != NULL; lib++)
152    {
153            lib->func(L);
154            lua_settop(L, 0);
155    }
156
157    /* build uhttpd api table */
158    lua_newtable(L);
159
160    /* register global send and receive functions */
161    lua_pushcfunction(L, uh_lua_recv);
162    lua_setfield(L, -2, "recv");
163
164    lua_pushcfunction(L, uh_lua_send);
165    lua_setfield(L, -2, "send");
166
167    lua_pushcfunction(L, uh_lua_sendc);
168    lua_setfield(L, -2, "sendc");
169
170    lua_pushcfunction(L, uh_lua_urldecode);
171    lua_setfield(L, -2, "urldecode");
172
173    /* _G.uhttpd = { ... } */
174    lua_setfield(L, LUA_GLOBALSINDEX, "uhttpd");
175
176
177    /* load Lua handler */
178    switch( luaL_loadfile(L, handler) )
179    {
180        case LUA_ERRSYNTAX:
181            fprintf(stderr,
182                "Lua handler contains syntax errors, unable to continue\n");
183            exit(1);
184
185        case LUA_ERRMEM:
186            fprintf(stderr,
187                "Lua handler ran out of memory, unable to continue\n");
188            exit(1);
189
190        case LUA_ERRFILE:
191            fprintf(stderr,
192                "Lua cannot open the handler script, unable to continue\n");
193            exit(1);
194
195        default:
196            /* compile Lua handler */
197            switch( lua_pcall(L, 0, 0, 0) )
198            {
199                case LUA_ERRRUN:
200                    err_str = luaL_checkstring(L, -1);
201                    fprintf(stderr,
202                        "Lua handler had runtime error, unable to continue\n"
203                        "Error: %s\n", err_str
204                    );
205                    exit(1);
206
207                case LUA_ERRMEM:
208                    err_str = luaL_checkstring(L, -1);
209                    fprintf(stderr,
210                        "Lua handler ran out of memory, unable to continue\n"
211                        "Error: %s\n", err_str
212                    );
213                    exit(1);
214
215                default:
216                    /* test handler function */
217                    lua_getglobal(L, UH_LUA_CALLBACK);
218
219                    if( ! lua_isfunction(L, -1) )
220                    {
221                        fprintf(stderr,
222                            "Lua handler provides no " UH_LUA_CALLBACK "(), unable to continue\n");
223                        exit(1);
224                    }
225
226                    lua_pop(L, 1);
227                    break;
228            }
229
230            break;
231    }
232
233    return L;
234}
235
236void uh_lua_request(struct client *cl, struct http_request *req, lua_State *L)
237{
238    int i;
239    char *query_string;
240    const char *prefix = cl->server->conf->lua_prefix;
241    const char *err_str = NULL;
242
243    /* put handler callback on stack */
244    lua_getglobal(L, UH_LUA_CALLBACK);
245
246
247    /* build env table */
248    lua_newtable(L);
249
250    /* client object */
251    lua_pushlightuserdata(L, (void *)cl);
252    lua_setfield(L, -2, "client");
253
254    /* request method */
255    switch(req->method)
256    {
257        case UH_HTTP_MSG_GET:
258            lua_pushstring(L, "get");
259            break;
260
261        case UH_HTTP_MSG_HEAD:
262            lua_pushstring(L, "head");
263            break;
264
265        case UH_HTTP_MSG_POST:
266            lua_pushstring(L, "post");
267            break;
268    }
269
270    lua_setfield(L, -2, "request_method");
271
272    /* request url */
273    lua_pushstring(L, req->url);
274    lua_setfield(L, -2, "request_url");
275
276    /* query string, path info */
277    if( (query_string = strchr(req->url, '?')) != NULL )
278    {
279        lua_pushstring(L, query_string + 1);
280        lua_setfield(L, -2, "query_string");
281
282        if( (int)(query_string - req->url) > strlen(prefix) )
283        {
284            lua_pushlstring(L,
285                &req->url[strlen(prefix)],
286                (int)(query_string - req->url) - strlen(prefix)
287            );
288
289            lua_setfield(L, -2, "path_info");
290        }
291    }
292    else if( strlen(req->url) > strlen(prefix) )
293    {
294        lua_pushstring(L, &req->url[strlen(prefix)]);
295        lua_setfield(L, -2, "path_info");
296    }
297
298    /* http protcol version */
299    lua_pushnumber(L, floor(req->version * 10) / 10);
300    lua_setfield(L, -2, "http_version");
301
302
303    /* address information */
304    lua_pushstring(L, sa_straddr(&cl->peeraddr));
305    lua_setfield(L, -2, "remote_addr");
306
307    lua_pushinteger(L, sa_port(&cl->peeraddr));
308    lua_setfield(L, -2, "remote_port");
309
310    lua_pushstring(L, sa_straddr(&cl->servaddr));
311    lua_setfield(L, -2, "server_addr");
312
313    lua_pushinteger(L, sa_port(&cl->servaddr));
314    lua_setfield(L, -2, "server_port");
315
316
317    /* headers */
318    lua_newtable(L);
319
320    foreach_header(i, req->headers)
321    {
322        lua_pushstring(L, req->headers[i+1]);
323        lua_setfield(L, -2, req->headers[i]);
324    }
325
326    lua_setfield(L, -2, "headers");
327
328
329    /* call */
330    switch( lua_pcall(L, 1, 0, 0) )
331    {
332        case LUA_ERRRUN:
333            err_str = luaL_checkstring(L, -1);
334            uh_http_sendhf(cl, 500, "Lua runtime error",
335                "Lua raised an error:\n%s\n", err_str);
336            break;
337
338        case LUA_ERRMEM:
339            err_str = luaL_checkstring(L, -1);
340            uh_http_sendhf(cl, 500, "Lua out of memory",
341                "Lua raised an error:\n%s\n", err_str);
342            break;
343
344        default:
345            break;
346    }
347}
348
Note: See TracBrowser for help on using the browser.