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