blob: 69d6ee652d7693ff91ac72730beb4834025bbf12 [file] [log] [blame]
Thierry Fourniere726b142016-02-11 17:57:57 +01001/*
2 * Lua safe functions
3 *
4 * Copyright 2015-2016 Thierry Fournier <tfournier@arpalert.org>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 *
12 * All the functions in this file runs with a Lua stack, and can
Thierry Fournierfb0b5462016-01-21 09:28:58 +010013 * return with a longjmp. All of these function must be launched
14 * in an environment able to catch a longjmp, otherwise a
15 * critical error can be raised.
16 */
17#include <lauxlib.h>
18#include <lua.h>
19#include <lualib.h>
20
Thierry Fournierb1f46562016-01-21 09:46:15 +010021#include <common/time.h>
22
Thierry Fournier49d48422016-02-19 12:09:29 +010023#include <types/hlua.h>
24
Thierry Fournier8b0d6e12016-03-16 18:29:13 +010025#include <proto/dumpstats.h>
Thierry Fournier94ed1c12016-02-24 08:06:32 +010026#include <proto/proto_http.h>
27
Thierry Fournier1de16592016-01-27 09:49:07 +010028/* Contains the class reference of the concat object. */
29static int class_concat_ref;
30
Thierry Fournier8b0d6e12016-03-16 18:29:13 +010031/* This function gets a struct field and convert it in Lua
32 * variable. The variable is pushed at the top of the stak.
33 */
34int hlua_fcn_pushfield(lua_State *L, struct field *field)
35{
36 /* The lua_Integer is always signed. Its length depends on
37 * compilation opions, so the followinfg code is conditionned
38 * by some macros. Windows maros are not supported.
39 * If the number cannot be represented as integer, we try to
40 * convert to float.
41 */
42 switch (field_format(field, 0)) {
43
44 case FF_EMPTY:
45 lua_pushnil(L);
46 return 1;
47
48 case FF_S32:
49 /* S32 is always supported. */
50 lua_pushinteger(L, field->u.s32);
51 return 1;
52
53 case FF_U32:
54#if (LUA_MAXINTEGER == LLONG_MAX || ((LUA_MAXINTEGER == LONG_MAX) && (__WORDSIZE == 64)))
55 /* 64 bits case, U32 is always supported */
56 lua_pushinteger(L, field->u.u32);
57#else
58 /* 32 bits case, U32 is supported until INT_MAX. */
59 if (field->u.u32 > INT_MAX)
60 lua_pushnumber(L, (lua_Number)field->u.u32);
61 else
62 lua_pushinteger(L, field->u.u32);
63#endif
64 return 1;
65
66 case FF_S64:
67#if (LUA_MAXINTEGER == LLONG_MAX || ((LUA_MAXINTEGER == LONG_MAX) && (__WORDSIZE == 64)))
68 /* 64 bits case, S64 is always supported */
69 lua_pushinteger(L, field->u.s64);
70#else
71 /* 64 bits case, S64 is supported beetween INT_MIN and INT_MAX */
72 if (field->u.s64 < INT_MIN || field->u.s64 > INT_MAX)
73 lua_pushnumber(L, (lua_Number)field->u.s64);
74 else
75 lua_pushinteger(L, (int)field->u.s64);
76#endif
77 return 1;
78
79 case FF_U64:
80#if (LUA_MAXINTEGER == LLONG_MAX || ((LUA_MAXINTEGER == LONG_MAX) && (__WORDSIZE == 64)))
81 /* 64 bits case, U64 is supported until LLONG_MAX */
82 if (field->u.u64 > LLONG_MAX)
83 lua_pushnumber(L, (lua_Number)field->u.u64);
84 else
85 lua_pushinteger(L, field->u.u64);
86#else
87 /* 64 bits case, U64 is supported until INT_MAX */
88 if (field->u.u64 > INT_MAX)
89 lua_pushnumber(L, (lua_Number)field->u.u64);
90 else
91 lua_pushinteger(L, (int)field->u.u64);
92#endif
93 return 1;
94
95 case FF_STR:
96 lua_pushstring(L, field->u.str);
97 return 1;
98
99 default:
100 break;
101 }
102
103 /* Default case, never reached. */
104 lua_pushnil(L);
105 return 1;
106}
107
Thierry Fournier94ed1c12016-02-24 08:06:32 +0100108/* Some string are started or terminated by blank chars,
109 * this function removes the spaces, tabs, \r and
110 * \n at the begin and at the end of the string "str", and
111 * push the result in the lua stack.
112 * Returns a pointer to the Lua internal copy of the string.
113 */
114const char *hlua_pushstrippedstring(lua_State *L, const char *str)
115{
116 const char *p;
117 const char *e;
118
119 for (p = str; HTTP_IS_LWS(*p); p++);
120 for (e = p + strlen(p) - 1; e > p && HTTP_IS_LWS(*e); e--);
121
122 return lua_pushlstring(L, p, e - p);
123}
124
Thierry Fournierddd89882016-02-22 19:52:08 +0100125/* The three following functions are useful for adding entries
126 * in a table. These functions takes a string and respectively an
127 * integer, a string or a function and add it to the table in the
128 * top of the stack.
129 *
130 * These functions throws an error if no more stack size is
131 * available.
132 */
133void hlua_class_const_int(lua_State *L, const char *name, int value)
134{
Thierry Fournierddd89882016-02-22 19:52:08 +0100135 lua_pushstring(L, name);
136 lua_pushinteger(L, value);
137 lua_rawset(L, -3);
138}
139void hlua_class_const_str(lua_State *L, const char *name, const char *value)
140{
Thierry Fournierddd89882016-02-22 19:52:08 +0100141 lua_pushstring(L, name);
142 lua_pushstring(L, value);
143 lua_rawset(L, -3);
144}
145void hlua_class_function(lua_State *L, const char *name, int (*function)(lua_State *L))
146{
Thierry Fournierddd89882016-02-22 19:52:08 +0100147 lua_pushstring(L, name);
148 lua_pushcclosure(L, function, 0);
149 lua_rawset(L, -3);
150}
151
152/* This function returns a string containg the HAProxy object name. */
153int hlua_dump_object(struct lua_State *L)
154{
155 const char *name = (const char *)lua_tostring(L, lua_upvalueindex(1));
156 lua_pushfstring(L, "HAProxy class %s", name);
157 return 1;
158}
159
Thierry Fournier45e78d72016-02-19 18:34:46 +0100160/* This function register a table as metatable and. It names
161 * the metatable, and returns the associated reference.
162 * The original table is poped from the top of the stack.
163 * "name" is the referenced class name.
164 */
165int hlua_register_metatable(struct lua_State *L, char *name)
166{
167 /* Check the type of the top element. it must be
168 * a table.
169 */
170 if (lua_type(L, -1) != LUA_TTABLE)
171 luaL_error(L, "hlua_register_metatable() requires a type Table "
172 "in the top of the stack");
173
174 /* Add the __tostring function which identify the
175 * created object.
176 */
177 lua_pushstring(L, "__tostring");
178 lua_pushstring(L, name);
179 lua_pushcclosure(L, hlua_dump_object, 1);
180 lua_rawset(L, -3);
181
182 /* Register a named entry for the table. The table
183 * reference is copyed first because the function
184 * lua_setfield() pop the entry.
185 */
186 lua_pushvalue(L, -1);
187 lua_setfield(L, LUA_REGISTRYINDEX, name);
188
189 /* Creates the reference of the object. The
190 * function luaL_ref pop the top of the stack.
191 */
192 return luaL_ref(L, LUA_REGISTRYINDEX);
193}
194
Thierry Fournier9e7e3ea2016-01-27 09:55:30 +0100195/* Return an object of the expected type, or throws an error. */
196void *hlua_checkudata(lua_State *L, int ud, int class_ref)
197{
198 void *p;
Thierry Fournier53518272016-01-27 10:34:09 +0100199 int ret;
Thierry Fournier9e7e3ea2016-01-27 09:55:30 +0100200
201 /* Check if the stack entry is an array. */
202 if (!lua_istable(L, ud))
Thierry Fournier53518272016-01-27 10:34:09 +0100203 luaL_argerror(L, ud, NULL);
204
205 /* pop the metatable of the referencecd object. */
206 if (!lua_getmetatable(L, ud))
207 luaL_argerror(L, ud, NULL);
208
209 /* pop the expected metatable. */
210 lua_rawgeti(L, LUA_REGISTRYINDEX, class_ref);
211
Thierry Fournier9e7e3ea2016-01-27 09:55:30 +0100212 /* Check if the metadata have the expected type. */
Thierry Fournier53518272016-01-27 10:34:09 +0100213 ret = lua_rawequal(L, -1, -2);
214 lua_pop(L, 2);
215 if (!ret)
216 luaL_argerror(L, ud, NULL);
217
Thierry Fournier9e7e3ea2016-01-27 09:55:30 +0100218 /* Push on the stack at the entry [0] of the table. */
219 lua_rawgeti(L, ud, 0);
Thierry Fournier53518272016-01-27 10:34:09 +0100220
Thierry Fournier9e7e3ea2016-01-27 09:55:30 +0100221 /* Check if this entry is userdata. */
222 p = lua_touserdata(L, -1);
223 if (!p)
Thierry Fournier53518272016-01-27 10:34:09 +0100224 luaL_argerror(L, ud, NULL);
225
Thierry Fournier9e7e3ea2016-01-27 09:55:30 +0100226 /* Remove the entry returned by lua_rawgeti(). */
227 lua_pop(L, 1);
Thierry Fournier53518272016-01-27 10:34:09 +0100228
Thierry Fournier9e7e3ea2016-01-27 09:55:30 +0100229 /* Return the associated struct. */
230 return p;
231}
232
Thierry Fournierb1f46562016-01-21 09:46:15 +0100233/* This function return the current date at epoch format in milliseconds. */
234int hlua_now(lua_State *L)
235{
236 lua_newtable(L);
237 lua_pushstring(L, "sec");
238 lua_pushinteger(L, now.tv_sec);
239 lua_rawset(L, -3);
240 lua_pushstring(L, "usec");
241 lua_pushinteger(L, now.tv_usec);
242 lua_rawset(L, -3);
243 return 1;
244}
245
Thierry Fournier1550d5d2016-01-21 09:35:41 +0100246/* This functions expects a Lua string as HTTP date, parse it and
247 * returns an integer containing the epoch format of the date, or
248 * nil if the parsing fails.
249 */
250static int hlua_parse_date(lua_State *L, int (*fcn)(const char *, int, struct tm*))
251{
252 const char *str;
253 size_t len;
254 struct tm tm;
255 time_t time;
256
257 str = luaL_checklstring(L, 1, &len);
258
259 if (!fcn(str, len, &tm)) {
260 lua_pushnil(L);
261 return 1;
262 }
263
264 /* This function considers the content of the broken-down time
265 * is exprimed in the UTC timezone. timegm don't care about
266 * the gnu variable tm_gmtoff. If gmtoff is set, or if you know
267 * the timezone from the broken-down time, it must be fixed
268 * after the conversion.
269 */
270 time = timegm(&tm);
271 if (time == -1) {
272 lua_pushnil(L);
273 return 1;
274 }
275
276 lua_pushinteger(L, (int)time);
277 return 1;
278}
279static int hlua_http_date(lua_State *L)
280{
281 return hlua_parse_date(L, parse_http_date);
282}
283static int hlua_imf_date(lua_State *L)
284{
285 return hlua_parse_date(L, parse_imf_date);
286}
287static int hlua_rfc850_date(lua_State *L)
288{
289 return hlua_parse_date(L, parse_rfc850_date);
290}
291static int hlua_asctime_date(lua_State *L)
292{
293 return hlua_parse_date(L, parse_asctime_date);
294}
295
Thierry Fournier49d48422016-02-19 12:09:29 +0100296static struct hlua_concat *hlua_check_concat(lua_State *L, int ud)
Thierry Fournier1de16592016-01-27 09:49:07 +0100297{
Thierry Fournier49d48422016-02-19 12:09:29 +0100298 return (struct hlua_concat *)(hlua_checkudata(L, ud, class_concat_ref));
Thierry Fournier1de16592016-01-27 09:49:07 +0100299}
300
301static int hlua_concat_add(lua_State *L)
302{
Thierry Fournier49d48422016-02-19 12:09:29 +0100303 struct hlua_concat *b;
304 char *buffer;
305 char *new;
Thierry Fournier1de16592016-01-27 09:49:07 +0100306 const char *str;
307 size_t l;
308
309 /* First arg must be a concat object. */
310 b = hlua_check_concat(L, 1);
311
312 /* Second arg must be a string. */
313 str = luaL_checklstring(L, 2, &l);
314
Thierry Fournier49d48422016-02-19 12:09:29 +0100315 /* Get the buffer. */
316 lua_rawgeti(L, 1, 1);
317 buffer = lua_touserdata(L, -1);
318 lua_pop(L, 1);
319
320 /* Update the buffer size if it s required. The old buffer
321 * is crushed by the new in the object array, so it will
322 * be deleted by the GC.
323 * Note that in the first loop, the "new" variable is only
324 * used as a flag.
325 */
326 new = NULL;
327 while (b->size - b->len < l) {
328 b->size += HLUA_CONCAT_BLOCSZ;
329 new = buffer;
330 }
331 if (new) {
332 new = lua_newuserdata(L, b->size);
333 memcpy(new, buffer, b->len);
334 lua_rawseti(L, 1, 1);
335 buffer = new;
336 }
337
338 /* Copy string, and update metadata. */
339 memcpy(buffer + b->len, str, l);
340 b->len += l;
Thierry Fournier1de16592016-01-27 09:49:07 +0100341 return 0;
342}
343
344static int hlua_concat_dump(lua_State *L)
345{
Thierry Fournier49d48422016-02-19 12:09:29 +0100346 struct hlua_concat *b;
347 char *buffer;
Thierry Fournier1de16592016-01-27 09:49:07 +0100348
349 /* First arg must be a concat object. */
350 b = hlua_check_concat(L, 1);
351
Thierry Fournier49d48422016-02-19 12:09:29 +0100352 /* Get the buffer. */
353 lua_rawgeti(L, 1, 1);
354 buffer = lua_touserdata(L, -1);
355 lua_pop(L, 1);
356
Thierry Fournier1de16592016-01-27 09:49:07 +0100357 /* Push the soncatenated strng in the stack. */
Thierry Fournier49d48422016-02-19 12:09:29 +0100358 lua_pushlstring(L, buffer, b->len);
Thierry Fournier1de16592016-01-27 09:49:07 +0100359 return 1;
360}
361
362int hlua_concat_new(lua_State *L)
363{
Thierry Fournier49d48422016-02-19 12:09:29 +0100364 struct hlua_concat *b;
Thierry Fournier1de16592016-01-27 09:49:07 +0100365
366 lua_newtable(L);
Thierry Fournier49d48422016-02-19 12:09:29 +0100367 b = (struct hlua_concat *)lua_newuserdata(L, sizeof(*b));
368 b->size = HLUA_CONCAT_BLOCSZ;
369 b->len = 0;
Thierry Fournier1de16592016-01-27 09:49:07 +0100370 lua_rawseti(L, -2, 0);
Thierry Fournier49d48422016-02-19 12:09:29 +0100371 lua_newuserdata(L, HLUA_CONCAT_BLOCSZ);
372 lua_rawseti(L, -2, 1);
Thierry Fournier1de16592016-01-27 09:49:07 +0100373
374 lua_rawgeti(L, LUA_REGISTRYINDEX, class_concat_ref);
375 lua_setmetatable(L, -2);
376
Thierry Fournier1de16592016-01-27 09:49:07 +0100377 return 1;
378}
379
380static int concat_tostring(lua_State *L)
381{
382 const void *ptr = lua_topointer(L, 1);
383 lua_pushfstring(L, "Concat object: %p", ptr);
384 return 1;
385}
386
387static int hlua_concat_init(lua_State *L)
388{
389 /* Creates the buffered concat object. */
390 lua_newtable(L);
391
392 lua_pushstring(L, "__tostring");
393 lua_pushcclosure(L, concat_tostring, 0);
394 lua_settable(L, -3);
395
396 lua_pushstring(L, "__index"); /* Creates the index entry. */
397 lua_newtable(L); /* The "__index" content. */
398
399 lua_pushstring(L, "add");
400 lua_pushcclosure(L, hlua_concat_add, 0);
401 lua_settable(L, -3);
402
403 lua_pushstring(L, "dump");
404 lua_pushcclosure(L, hlua_concat_dump, 0);
405 lua_settable(L, -3);
406
407 lua_settable(L, -3); /* Sets the __index entry. */
408 class_concat_ref = luaL_ref(L, LUA_REGISTRYINDEX);
409
410 return 1;
411}
412
Thierry Fournier3d4a6752016-02-19 20:53:30 +0100413int hlua_fcn_post_init(lua_State *L)
414{
415 return 1;
416}
417
Thierry Fournierfb0b5462016-01-21 09:28:58 +0100418int hlua_fcn_reg_core_fcn(lua_State *L)
419{
Thierry Fournier1de16592016-01-27 09:49:07 +0100420 if (!hlua_concat_init(L))
421 return 0;
422
Thierry Fournier4f99b272016-02-22 08:40:02 +0100423 hlua_class_function(L, "now", hlua_now);
424 hlua_class_function(L, "http_date", hlua_http_date);
425 hlua_class_function(L, "imf_date", hlua_imf_date);
426 hlua_class_function(L, "rfc850_date", hlua_rfc850_date);
427 hlua_class_function(L, "asctime_date", hlua_asctime_date);
428 hlua_class_function(L, "concat", hlua_concat_new);
429
Thierry Fournier1550d5d2016-01-21 09:35:41 +0100430 return 5;
Thierry Fournierfb0b5462016-01-21 09:28:58 +0100431}