b2ca34e0c1108ed3b41bbcaaa0411b17d261cac4
[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