2c2821d065580941cb75aaa44997c8ed0505b486
[project/luci.git] / contrib / package / uhttpd / src / uhttpd-lua.c
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
24 static 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
83 static 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
109 static int uh_lua_send(lua_State *L)
110 {
111 return uh_lua_send_common(L, 0);
112 }
113
114 static int uh_lua_sendc(lua_State *L)
115 {
116 return uh_lua_send_common(L, 1);
117 }
118
119 static 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
133 lua_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
236 void 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