blob: 71aa702d87901e1c2f77d15bb78b416137b854e5 [file] [log] [blame]
Thierry Fourniere726b142016-02-11 17:57:57 +01001/*
2 * Lua unsafe core engine
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
Bertrand Jacquinf4c12d42021-01-21 21:14:07 +000013#define _GNU_SOURCE
14
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +010015#include <ctype.h>
Thierry FOURNIERbabae282015-09-17 11:36:37 +020016#include <setjmp.h>
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +010017
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +010018#include <lauxlib.h>
19#include <lua.h>
20#include <lualib.h>
21
Thierry FOURNIER463119c2015-03-10 00:35:36 +010022#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 503
23#error "Requires Lua 5.3 or later."
Cyril Bontédc0306e2015-03-02 00:08:40 +010024#endif
25
Willy Tarreau8d2b7772020-05-27 10:58:19 +020026#include <import/ebpttree.h>
Thierry FOURNIER380d0932015-01-23 14:27:52 +010027
Willy Tarreaub2551052020-06-09 09:07:15 +020028#include <haproxy/api.h>
29#include <haproxy/applet.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020030#include <haproxy/arg.h>
Christopher Fauletd25d9262020-08-06 11:04:46 +020031#include <haproxy/auth.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020032#include <haproxy/cfgparse.h>
Willy Tarreauf1d32c42020-06-04 21:07:02 +020033#include <haproxy/channel.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020034#include <haproxy/cli.h>
Willy Tarreau7ea393d2020-06-04 18:02:10 +020035#include <haproxy/connection.h>
Willy Tarreau5413a872020-06-02 19:33:08 +020036#include <haproxy/h1.h>
Willy Tarreau86416052020-06-04 09:20:54 +020037#include <haproxy/hlua.h>
Willy Tarreau8c794002020-06-04 10:05:25 +020038#include <haproxy/hlua_fcn.h>
Willy Tarreauc2b1ff02020-06-04 21:21:03 +020039#include <haproxy/http_ana.h>
Willy Tarreau126ba3a2020-06-04 18:26:43 +020040#include <haproxy/http_fetch.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020041#include <haproxy/http_htx.h>
Willy Tarreauc761f842020-06-04 11:40:28 +020042#include <haproxy/http_rules.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020043#include <haproxy/log.h>
Willy Tarreau2cd58092020-06-04 15:10:43 +020044#include <haproxy/map.h>
Willy Tarreau8efbdfb2020-06-04 11:29:21 +020045#include <haproxy/obj_type.h>
Willy Tarreau225a90a2020-06-04 15:06:28 +020046#include <haproxy/pattern.h>
Willy Tarreau469509b2020-06-04 15:13:30 +020047#include <haproxy/payload.h>
Willy Tarreau3d6ee402021-05-08 20:28:07 +020048#include <haproxy/proxy.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020049#include <haproxy/regex.h>
Willy Tarreaue6ce10b2020-06-04 15:33:47 +020050#include <haproxy/sample.h>
Willy Tarreau198e92a2021-03-05 10:23:32 +010051#include <haproxy/server.h>
Willy Tarreau48d25b32020-06-04 18:58:52 +020052#include <haproxy/session.h>
Willy Tarreau2eec9b52020-06-04 19:58:55 +020053#include <haproxy/stats-t.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020054#include <haproxy/stream.h>
Willy Tarreau5e539c92020-06-04 20:45:39 +020055#include <haproxy/stream_interface.h>
Willy Tarreaucea0e1b2020-06-04 17:25:40 +020056#include <haproxy/task.h>
Willy Tarreau8b550af2020-06-04 17:42:48 +020057#include <haproxy/tcp_rules.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020058#include <haproxy/thread.h>
Willy Tarreau48fbcae2020-06-03 18:09:46 +020059#include <haproxy/tools.h>
Willy Tarreaua1718922020-06-04 16:25:31 +020060#include <haproxy/vars.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020061#include <haproxy/xref.h>
62
Thierry FOURNIER380d0932015-01-23 14:27:52 +010063
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +010064/* Lua uses longjmp to perform yield or throwing errors. This
65 * macro is used only for identifying the function that can
66 * not return because a longjmp is executed.
67 * __LJMP marks a prototype of hlua file that can use longjmp.
68 * WILL_LJMP() marks an lua function that will use longjmp.
69 * MAY_LJMP() marks an lua function that may use longjmp.
70 */
71#define __LJMP
Willy Tarreau4e7cc332018-10-20 17:45:48 +020072#define WILL_LJMP(func) do { func; my_unreachable(); } while(0)
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +010073#define MAY_LJMP(func) func
74
Thierry FOURNIERbabae282015-09-17 11:36:37 +020075/* This couple of function executes securely some Lua calls outside of
76 * the lua runtime environment. Each Lua call can return a longjmp
77 * if it encounter a memory error.
78 *
79 * Lua documentation extract:
80 *
81 * If an error happens outside any protected environment, Lua calls
82 * a panic function (see lua_atpanic) and then calls abort, thus
83 * exiting the host application. Your panic function can avoid this
84 * exit by never returning (e.g., doing a long jump to your own
85 * recovery point outside Lua).
86 *
87 * The panic function runs as if it were a message handler (see
88 * §2.3); in particular, the error message is at the top of the
89 * stack. However, there is no guarantee about stack space. To push
90 * anything on the stack, the panic function must first check the
91 * available space (see §4.2).
92 *
93 * We must check all the Lua entry point. This includes:
94 * - The include/proto/hlua.h exported functions
95 * - the task wrapper function
96 * - The action wrapper function
97 * - The converters wrapper function
98 * - The sample-fetch wrapper functions
99 *
Ilya Shipitsin46a030c2020-07-05 16:36:08 +0500100 * It is tolerated that the initialisation function returns an abort.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -0800101 * Before each Lua abort, an error message is written on stderr.
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200102 *
103 * The macro SET_SAFE_LJMP initialise the longjmp. The Macro
104 * RESET_SAFE_LJMP reset the longjmp. These function must be macro
105 * because they must be exists in the program stack when the longjmp
106 * is called.
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +0200107 *
108 * Note that the Lua processing is not really thread safe. It provides
109 * heavy system which consists to add our own lock function in the Lua
110 * code and recompile the library. This system will probably not accepted
111 * by maintainers of various distribs.
112 *
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500113 * Our main execution point of the Lua is the function lua_resume(). A
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +0200114 * quick looking on the Lua sources displays a lua_lock() a the start
115 * of function and a lua_unlock() at the end of the function. So I
116 * conclude that the Lua thread safe mode just perform a mutex around
117 * all execution. So I prefer to do this in the HAProxy code, it will be
118 * easier for distro maintainers.
119 *
120 * Note that the HAProxy lua functions rounded by the macro SET_SAFE_LJMP
121 * and RESET_SAFE_LJMP manipulates the Lua stack, so it will be careful
122 * to set mutex around these functions.
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200123 */
Willy Tarreau86abe442018-11-25 20:12:18 +0100124__decl_spinlock(hlua_global_lock);
Thierry FOURNIERffbad792017-07-12 11:39:04 +0200125THREAD_LOCAL jmp_buf safe_ljmp_env;
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200126static int hlua_panic_safe(lua_State *L) { return 0; }
Willy Tarreau69c66e32021-07-14 19:41:25 +0200127static int hlua_panic_ljmp(lua_State *L) { WILL_LJMP(longjmp(safe_ljmp_env, 1)); return 0; }
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200128
Thierry Fournier62a22aa2020-11-28 21:06:35 +0100129/* This is the chained list of struct hlua_function referenced
130 * for haproxy action, sample-fetches, converters, cli and
131 * applet bindings. It is used for a post-initialisation control.
132 */
133static struct list referenced_functions = LIST_HEAD_INIT(referenced_functions);
134
Thierry Fournierc7492592020-11-28 23:57:24 +0100135/* This variable is used only during initialization to identify the Lua state
136 * currently being initialized. 0 is the common lua state, 1 to n are the Lua
137 * states dedicated to each thread (in this case hlua_state_id==tid+1).
138 */
139static int hlua_state_id;
140
Thierry Fournier59f11be2020-11-29 00:37:41 +0100141/* This is a NULL-terminated list of lua file which are referenced to load per thread */
142static char **per_thread_load = NULL;
143
144lua_State *hlua_init_state(int thread_id);
145
Willy Tarreau3eb2e472021-08-20 15:47:25 +0200146/* This function takes the Lua global lock. Keep this function's visibility
147 * global so that it can appear in stack dumps and performance profiles!
148 */
149void lua_take_global_lock()
150{
151 HA_SPIN_LOCK(LUA_LOCK, &hlua_global_lock);
152}
153
154static inline void lua_drop_global_lock()
155{
156 HA_SPIN_UNLOCK(LUA_LOCK, &hlua_global_lock);
157}
158
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100159#define SET_SAFE_LJMP_L(__L, __HLUA) \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200160 ({ \
161 int ret; \
Thierry Fournier021d9862020-11-28 23:42:03 +0100162 if ((__HLUA)->state_id == 0) \
Willy Tarreau3eb2e472021-08-20 15:47:25 +0200163 lua_take_global_lock(); \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200164 if (setjmp(safe_ljmp_env) != 0) { \
165 lua_atpanic(__L, hlua_panic_safe); \
166 ret = 0; \
Thierry Fournier021d9862020-11-28 23:42:03 +0100167 if ((__HLUA)->state_id == 0) \
Willy Tarreau3eb2e472021-08-20 15:47:25 +0200168 lua_drop_global_lock(); \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200169 } else { \
170 lua_atpanic(__L, hlua_panic_ljmp); \
171 ret = 1; \
172 } \
173 ret; \
174 })
175
176/* If we are the last function catching Lua errors, we
177 * must reset the panic function.
178 */
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100179#define RESET_SAFE_LJMP_L(__L, __HLUA) \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200180 do { \
181 lua_atpanic(__L, hlua_panic_safe); \
Thierry Fournier021d9862020-11-28 23:42:03 +0100182 if ((__HLUA)->state_id == 0) \
Willy Tarreau3eb2e472021-08-20 15:47:25 +0200183 lua_drop_global_lock(); \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200184 } while(0)
185
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100186#define SET_SAFE_LJMP(__HLUA) \
187 SET_SAFE_LJMP_L((__HLUA)->T, __HLUA)
188
189#define RESET_SAFE_LJMP(__HLUA) \
190 RESET_SAFE_LJMP_L((__HLUA)->T, __HLUA)
191
192#define SET_SAFE_LJMP_PARENT(__HLUA) \
Thierry Fournier021d9862020-11-28 23:42:03 +0100193 SET_SAFE_LJMP_L(hlua_states[(__HLUA)->state_id], __HLUA)
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100194
195#define RESET_SAFE_LJMP_PARENT(__HLUA) \
Thierry Fournier021d9862020-11-28 23:42:03 +0100196 RESET_SAFE_LJMP_L(hlua_states[(__HLUA)->state_id], __HLUA)
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100197
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +0200198/* Applet status flags */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200199#define APPLET_DONE 0x01 /* applet processing is done. */
Christopher Faulet18c2e8d2019-03-01 12:02:08 +0100200/* unused: 0x02 */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200201#define APPLET_HDR_SENT 0x04 /* Response header sent. */
Christopher Fauleta2097962019-07-15 16:25:33 +0200202/* unused: 0x08, 0x10 */
Thierry FOURNIERd93ea2b2015-12-20 19:14:52 +0100203#define APPLET_HTTP11 0x20 /* Last chunk sent. */
Christopher Faulet56a3d6e2019-02-27 22:06:23 +0100204#define APPLET_RSP_SENT 0x40 /* The response was fully sent */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200205
Thierry Fournierafc63e22020-11-28 17:06:51 +0100206/* The main Lua execution context. The 0 index is the
207 * common state shared by all threads.
208 */
Willy Tarreau186f3762020-12-04 11:48:12 +0100209static lua_State *hlua_states[MAX_THREADS + 1];
Thierry FOURNIER380d0932015-01-23 14:27:52 +0100210
Thierry FOURNIERebed6e92016-12-16 11:54:07 +0100211/* This is the memory pool containing struct lua for applets
212 * (including cli).
213 */
Willy Tarreau8ceae722018-11-26 11:58:30 +0100214DECLARE_STATIC_POOL(pool_head_hlua, "hlua", sizeof(struct hlua));
Thierry FOURNIERebed6e92016-12-16 11:54:07 +0100215
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +0100216/* Used for Socket connection. */
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +0100217static struct proxy *socket_proxy;
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +0100218static struct server *socket_tcp;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +0100219#ifdef USE_OPENSSL
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +0100220static struct server *socket_ssl;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +0100221#endif
222
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +0100223/* List head of the function called at the initialisation time. */
Thierry Fournierc7492592020-11-28 23:57:24 +0100224struct list hlua_init_functions[MAX_THREADS + 1];
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +0100225
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +0100226/* The following variables contains the reference of the different
227 * Lua classes. These references are useful for identify metadata
228 * associated with an object.
229 */
Thierry FOURNIER65f34c62015-02-16 20:11:43 +0100230static int class_txn_ref;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +0100231static int class_socket_ref;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +0100232static int class_channel_ref;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +0100233static int class_fetches_ref;
Thierry FOURNIER594afe72015-03-10 23:58:30 +0100234static int class_converters_ref;
Thierry FOURNIER08504f42015-03-16 14:17:08 +0100235static int class_http_ref;
Thierry FOURNIER3def3932015-04-07 11:27:54 +0200236static int class_map_ref;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +0200237static int class_applet_tcp_ref;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200238static int class_applet_http_ref;
Christopher Faulet700d9e82020-01-31 12:21:52 +0100239static int class_txn_reply_ref;
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +0100240
Thierry FOURNIERbd413492015-03-03 16:52:26 +0100241/* Global Lua execution timeout. By default Lua, execution linked
Willy Tarreau87b09662015-04-03 00:22:06 +0200242 * with stream (actions, sample-fetches and converters) have a
Thierry FOURNIERbd413492015-03-03 16:52:26 +0100243 * short timeout. Lua linked with tasks doesn't have a timeout
244 * because a task may remain alive during all the haproxy execution.
245 */
246static unsigned int hlua_timeout_session = 4000; /* session timeout. */
247static unsigned int hlua_timeout_task = TICK_ETERNITY; /* task timeout. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +0200248static unsigned int hlua_timeout_applet = 4000; /* applet timeout. */
Thierry FOURNIERbd413492015-03-03 16:52:26 +0100249
Thierry FOURNIERee9f8022015-03-03 17:37:37 +0100250/* Interrupts the Lua processing each "hlua_nb_instruction" instructions.
251 * it is used for preventing infinite loops.
252 *
253 * I test the scheer with an infinite loop containing one incrementation
254 * and one test. I run this loop between 10 seconds, I raise a ceil of
255 * 710M loops from one interrupt each 9000 instructions, so I fix the value
256 * to one interrupt each 10 000 instructions.
257 *
258 * configured | Number of
259 * instructions | loops executed
260 * between two | in milions
261 * forced yields |
262 * ---------------+---------------
263 * 10 | 160
264 * 500 | 670
265 * 1000 | 680
266 * 5000 | 700
267 * 7000 | 700
268 * 8000 | 700
269 * 9000 | 710 <- ceil
270 * 10000 | 710
271 * 100000 | 710
272 * 1000000 | 710
273 *
274 */
275static unsigned int hlua_nb_instruction = 10000;
276
Willy Tarreaucdb53462020-12-02 12:12:00 +0100277/* Descriptor for the memory allocation state. The limit is pre-initialised to
278 * 0 until it is replaced by "tune.lua.maxmem" during the config parsing, or it
279 * is replaced with ~0 during post_init after everything was loaded. This way
280 * it is guaranteed that if limit is ~0 the boot is complete and that if it's
281 * zero it's not yet limited and proper accounting is required.
Willy Tarreau32f61e22015-03-18 17:54:59 +0100282 */
283struct hlua_mem_allocator {
284 size_t allocated;
285 size_t limit;
286};
287
Willy Tarreaucdb53462020-12-02 12:12:00 +0100288static struct hlua_mem_allocator hlua_global_allocator THREAD_ALIGNED(64);
Willy Tarreau32f61e22015-03-18 17:54:59 +0100289
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100290/* These functions converts types between HAProxy internal args or
291 * sample and LUA types. Another function permits to check if the
292 * LUA stack contains arguments according with an required ARG_T
293 * format.
294 */
295static int hlua_arg2lua(lua_State *L, const struct arg *arg);
296static int hlua_lua2arg(lua_State *L, int ud, struct arg *arg);
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100297__LJMP static int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp,
David Carlier0c437f42016-04-27 16:21:56 +0100298 uint64_t mask, struct proxy *p);
Willy Tarreau5eadada2015-03-10 17:28:54 +0100299static int hlua_smp2lua(lua_State *L, struct sample *smp);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100300static int hlua_smp2lua_str(lua_State *L, struct sample *smp);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100301static int hlua_lua2smp(lua_State *L, int ud, struct sample *smp);
302
Christopher Faulet9d1332b2020-02-24 16:46:16 +0100303__LJMP static int hlua_http_get_headers(lua_State *L, struct http_msg *msg);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200304
Thierry Fournier59f11be2020-11-29 00:37:41 +0100305struct prepend_path {
306 struct list l;
307 char *type;
308 char *path;
309};
310
311static struct list prepend_path_list = LIST_HEAD_INIT(prepend_path_list);
312
Thierry FOURNIER23bc3752015-09-11 19:15:43 +0200313#define SEND_ERR(__be, __fmt, __args...) \
314 do { \
315 send_log(__be, LOG_ERR, __fmt, ## __args); \
316 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) \
Christopher Faulet767a84b2017-11-24 16:50:31 +0100317 ha_alert(__fmt, ## __args); \
Thierry FOURNIER23bc3752015-09-11 19:15:43 +0200318 } while (0)
319
Thierry Fournier62a22aa2020-11-28 21:06:35 +0100320static inline struct hlua_function *new_hlua_function()
321{
322 struct hlua_function *fcn;
Thierry Fournierc7492592020-11-28 23:57:24 +0100323 int i;
Thierry Fournier62a22aa2020-11-28 21:06:35 +0100324
325 fcn = calloc(1, sizeof(*fcn));
326 if (!fcn)
327 return NULL;
Willy Tarreau2b718102021-04-21 07:32:39 +0200328 LIST_APPEND(&referenced_functions, &fcn->l);
Thierry Fournierc7492592020-11-28 23:57:24 +0100329 for (i = 0; i < MAX_THREADS + 1; i++)
330 fcn->function_ref[i] = -1;
Thierry Fournier62a22aa2020-11-28 21:06:35 +0100331 return fcn;
332}
333
Christopher Fauletdda44442021-04-12 14:05:43 +0200334static inline void release_hlua_function(struct hlua_function *fcn)
335{
336 if (!fcn)
337 return;
338 if (fcn->name)
339 ha_free(&fcn->name);
Willy Tarreau2b718102021-04-21 07:32:39 +0200340 LIST_DELETE(&fcn->l);
Christopher Fauletdda44442021-04-12 14:05:43 +0200341 ha_free(&fcn);
342}
343
Thierry Fournierc7492592020-11-28 23:57:24 +0100344/* If the common state is set, the stack id is 0, otherwise it is the tid + 1 */
345static inline int fcn_ref_to_stack_id(struct hlua_function *fcn)
346{
347 if (fcn->function_ref[0] == -1)
348 return tid + 1;
349 return 0;
350}
351
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100352/* Used to check an Lua function type in the stack. It creates and
353 * returns a reference of the function. This function throws an
354 * error if the rgument is not a "function".
355 */
356__LJMP unsigned int hlua_checkfunction(lua_State *L, int argno)
357{
358 if (!lua_isfunction(L, argno)) {
Thierry FOURNIERfd1e9552018-02-23 18:41:18 +0100359 const char *msg = lua_pushfstring(L, "function expected, got %s", luaL_typename(L, argno));
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100360 WILL_LJMP(luaL_argerror(L, argno, msg));
361 }
362 lua_pushvalue(L, argno);
363 return luaL_ref(L, LUA_REGISTRYINDEX);
364}
365
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200366/* Return the string that is of the top of the stack. */
367const char *hlua_get_top_error_string(lua_State *L)
368{
369 if (lua_gettop(L) < 1)
370 return "unknown error";
371 if (lua_type(L, -1) != LUA_TSTRING)
372 return "unknown error";
373 return lua_tostring(L, -1);
374}
375
Christopher Fauletd09cc512021-03-24 14:48:45 +0100376__LJMP const char *hlua_traceback(lua_State *L, const char* sep)
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200377{
378 lua_Debug ar;
379 int level = 0;
Willy Tarreau83061a82018-07-13 11:56:34 +0200380 struct buffer *msg = get_trash_chunk();
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200381
382 while (lua_getstack(L, level++, &ar)) {
383
384 /* Add separator */
Christopher Fauletd09cc512021-03-24 14:48:45 +0100385 if (b_data(msg))
386 chunk_appendf(msg, "%s", sep);
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200387
388 /* Fill fields:
389 * 'S': fills in the fields source, short_src, linedefined, lastlinedefined, and what;
390 * 'l': fills in the field currentline;
391 * 'n': fills in the field name and namewhat;
392 * 't': fills in the field istailcall;
393 */
394 lua_getinfo(L, "Slnt", &ar);
395
396 /* Append code localisation */
397 if (ar.currentline > 0)
Christopher Fauletd09cc512021-03-24 14:48:45 +0100398 chunk_appendf(msg, "%s:%d: ", ar.short_src, ar.currentline);
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200399 else
Christopher Fauletd09cc512021-03-24 14:48:45 +0100400 chunk_appendf(msg, "%s: ", ar.short_src);
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200401
402 /*
403 * Get function name
404 *
405 * if namewhat is no empty, name is defined.
406 * what contains "Lua" for Lua function, "C" for C function,
407 * or "main" for main code.
408 */
409 if (*ar.namewhat != '\0' && ar.name != NULL) /* is there a name from code? */
Christopher Fauletd09cc512021-03-24 14:48:45 +0100410 chunk_appendf(msg, "in %s '%s'", ar.namewhat, ar.name); /* use it */
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200411
412 else if (*ar.what == 'm') /* "main", the code is not executed in a function */
Christopher Fauletd09cc512021-03-24 14:48:45 +0100413 chunk_appendf(msg, "in main chunk");
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200414
415 else if (*ar.what != 'C') /* for Lua functions, use <file:line> */
Christopher Fauletd09cc512021-03-24 14:48:45 +0100416 chunk_appendf(msg, "in function line %d", ar.linedefined);
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200417
418 else /* nothing left... */
419 chunk_appendf(msg, "?");
420
421
422 /* Display tailed call */
423 if (ar.istailcall)
424 chunk_appendf(msg, " ...");
425 }
426
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200427 return msg->area;
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200428}
429
430
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100431/* This function check the number of arguments available in the
432 * stack. If the number of arguments available is not the same
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +0500433 * then <nb> an error is thrown.
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100434 */
435__LJMP static inline void check_args(lua_State *L, int nb, char *fcn)
436{
437 if (lua_gettop(L) == nb)
438 return;
439 WILL_LJMP(luaL_error(L, "'%s' needs %d arguments", fcn, nb));
440}
441
Mark Lakes22154b42018-01-29 14:38:40 -0800442/* This function pushes an error string prefixed by the file name
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100443 * and the line number where the error is encountered.
444 */
445static int hlua_pusherror(lua_State *L, const char *fmt, ...)
446{
447 va_list argp;
448 va_start(argp, fmt);
449 luaL_where(L, 1);
450 lua_pushvfstring(L, fmt, argp);
451 va_end(argp);
452 lua_concat(L, 2);
453 return 1;
454}
455
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100456/* This functions is used with sample fetch and converters. It
457 * converts the HAProxy configuration argument in a lua stack
458 * values.
459 *
460 * It takes an array of "arg", and each entry of the array is
461 * converted and pushed in the LUA stack.
462 */
463static int hlua_arg2lua(lua_State *L, const struct arg *arg)
464{
465 switch (arg->type) {
466 case ARGT_SINT:
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100467 case ARGT_TIME:
468 case ARGT_SIZE:
Thierry FOURNIERf90838b2015-03-06 13:48:32 +0100469 lua_pushinteger(L, arg->data.sint);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100470 break;
471
472 case ARGT_STR:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200473 lua_pushlstring(L, arg->data.str.area, arg->data.str.data);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100474 break;
475
476 case ARGT_IPV4:
477 case ARGT_IPV6:
478 case ARGT_MSK4:
479 case ARGT_MSK6:
480 case ARGT_FE:
481 case ARGT_BE:
482 case ARGT_TAB:
483 case ARGT_SRV:
484 case ARGT_USR:
485 case ARGT_MAP:
486 default:
487 lua_pushnil(L);
488 break;
489 }
490 return 1;
491}
492
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +0500493/* This function take one entry in an LUA stack at the index "ud",
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100494 * and try to convert it in an HAProxy argument entry. This is useful
Ilya Shipitsind4259502020-04-08 01:07:56 +0500495 * with sample fetch wrappers. The input arguments are given to the
496 * lua wrapper and converted as arg list by the function.
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100497 */
498static int hlua_lua2arg(lua_State *L, int ud, struct arg *arg)
499{
500 switch (lua_type(L, ud)) {
501
502 case LUA_TNUMBER:
503 case LUA_TBOOLEAN:
504 arg->type = ARGT_SINT;
505 arg->data.sint = lua_tointeger(L, ud);
506 break;
507
508 case LUA_TSTRING:
509 arg->type = ARGT_STR;
Tim Duesterhus2e89dec2019-09-29 23:03:08 +0200510 arg->data.str.area = (char *)lua_tolstring(L, ud, &arg->data.str.data);
Tim Duesterhus29d2e8a2019-09-29 23:03:07 +0200511 /* We don't know the actual size of the underlying allocation, so be conservative. */
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200512 arg->data.str.size = arg->data.str.data+1; /* count the terminating null byte */
Tim Duesterhus29d2e8a2019-09-29 23:03:07 +0200513 arg->data.str.head = 0;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100514 break;
515
516 case LUA_TUSERDATA:
517 case LUA_TNIL:
518 case LUA_TTABLE:
519 case LUA_TFUNCTION:
520 case LUA_TTHREAD:
521 case LUA_TLIGHTUSERDATA:
522 arg->type = ARGT_SINT;
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200523 arg->data.sint = 0;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100524 break;
525 }
526 return 1;
527}
528
529/* the following functions are used to convert a struct sample
530 * in Lua type. This useful to convert the return of the
Ilya Shipitsind4259502020-04-08 01:07:56 +0500531 * fetches or converters.
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100532 */
Willy Tarreau5eadada2015-03-10 17:28:54 +0100533static int hlua_smp2lua(lua_State *L, struct sample *smp)
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100534{
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200535 switch (smp->data.type) {
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100536 case SMP_T_SINT:
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100537 case SMP_T_BOOL:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200538 lua_pushinteger(L, smp->data.u.sint);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100539 break;
540
541 case SMP_T_BIN:
542 case SMP_T_STR:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200543 lua_pushlstring(L, smp->data.u.str.area, smp->data.u.str.data);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100544 break;
545
546 case SMP_T_METH:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200547 switch (smp->data.u.meth.meth) {
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100548 case HTTP_METH_OPTIONS: lua_pushstring(L, "OPTIONS"); break;
549 case HTTP_METH_GET: lua_pushstring(L, "GET"); break;
550 case HTTP_METH_HEAD: lua_pushstring(L, "HEAD"); break;
551 case HTTP_METH_POST: lua_pushstring(L, "POST"); break;
552 case HTTP_METH_PUT: lua_pushstring(L, "PUT"); break;
553 case HTTP_METH_DELETE: lua_pushstring(L, "DELETE"); break;
554 case HTTP_METH_TRACE: lua_pushstring(L, "TRACE"); break;
555 case HTTP_METH_CONNECT: lua_pushstring(L, "CONNECT"); break;
556 case HTTP_METH_OTHER:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200557 lua_pushlstring(L, smp->data.u.meth.str.area, smp->data.u.meth.str.data);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100558 break;
559 default:
560 lua_pushnil(L);
561 break;
562 }
563 break;
564
565 case SMP_T_IPV4:
566 case SMP_T_IPV6:
567 case SMP_T_ADDR: /* This type is never used to qualify a sample. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200568 if (sample_casts[smp->data.type][SMP_T_STR] &&
569 sample_casts[smp->data.type][SMP_T_STR](smp))
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200570 lua_pushlstring(L, smp->data.u.str.area, smp->data.u.str.data);
Willy Tarreau5eadada2015-03-10 17:28:54 +0100571 else
572 lua_pushnil(L);
573 break;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100574 default:
575 lua_pushnil(L);
576 break;
577 }
578 return 1;
579}
580
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100581/* the following functions are used to convert a struct sample
582 * in Lua strings. This is useful to convert the return of the
Ilya Shipitsind4259502020-04-08 01:07:56 +0500583 * fetches or converters.
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100584 */
585static int hlua_smp2lua_str(lua_State *L, struct sample *smp)
586{
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200587 switch (smp->data.type) {
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100588
589 case SMP_T_BIN:
590 case SMP_T_STR:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200591 lua_pushlstring(L, smp->data.u.str.area, smp->data.u.str.data);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100592 break;
593
594 case SMP_T_METH:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200595 switch (smp->data.u.meth.meth) {
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100596 case HTTP_METH_OPTIONS: lua_pushstring(L, "OPTIONS"); break;
597 case HTTP_METH_GET: lua_pushstring(L, "GET"); break;
598 case HTTP_METH_HEAD: lua_pushstring(L, "HEAD"); break;
599 case HTTP_METH_POST: lua_pushstring(L, "POST"); break;
600 case HTTP_METH_PUT: lua_pushstring(L, "PUT"); break;
601 case HTTP_METH_DELETE: lua_pushstring(L, "DELETE"); break;
602 case HTTP_METH_TRACE: lua_pushstring(L, "TRACE"); break;
603 case HTTP_METH_CONNECT: lua_pushstring(L, "CONNECT"); break;
604 case HTTP_METH_OTHER:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200605 lua_pushlstring(L, smp->data.u.meth.str.area, smp->data.u.meth.str.data);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100606 break;
607 default:
608 lua_pushstring(L, "");
609 break;
610 }
611 break;
612
613 case SMP_T_SINT:
614 case SMP_T_BOOL:
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100615 case SMP_T_IPV4:
616 case SMP_T_IPV6:
617 case SMP_T_ADDR: /* This type is never used to qualify a sample. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200618 if (sample_casts[smp->data.type][SMP_T_STR] &&
619 sample_casts[smp->data.type][SMP_T_STR](smp))
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200620 lua_pushlstring(L, smp->data.u.str.area, smp->data.u.str.data);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100621 else
622 lua_pushstring(L, "");
623 break;
624 default:
625 lua_pushstring(L, "");
626 break;
627 }
628 return 1;
629}
630
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100631/* the following functions are used to convert an Lua type in a
632 * struct sample. This is useful to provide data from a converter
633 * to the LUA code.
634 */
635static int hlua_lua2smp(lua_State *L, int ud, struct sample *smp)
636{
637 switch (lua_type(L, ud)) {
638
639 case LUA_TNUMBER:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200640 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200641 smp->data.u.sint = lua_tointeger(L, ud);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100642 break;
643
644
645 case LUA_TBOOLEAN:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200646 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200647 smp->data.u.sint = lua_toboolean(L, ud);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100648 break;
649
650 case LUA_TSTRING:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200651 smp->data.type = SMP_T_STR;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100652 smp->flags |= SMP_F_CONST;
Tim Duesterhus2e89dec2019-09-29 23:03:08 +0200653 smp->data.u.str.area = (char *)lua_tolstring(L, ud, &smp->data.u.str.data);
Tim Duesterhus29d2e8a2019-09-29 23:03:07 +0200654 /* We don't know the actual size of the underlying allocation, so be conservative. */
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200655 smp->data.u.str.size = smp->data.u.str.data+1; /* count the terminating null byte */
Tim Duesterhus29d2e8a2019-09-29 23:03:07 +0200656 smp->data.u.str.head = 0;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100657 break;
658
659 case LUA_TUSERDATA:
660 case LUA_TNIL:
661 case LUA_TTABLE:
662 case LUA_TFUNCTION:
663 case LUA_TTHREAD:
664 case LUA_TLIGHTUSERDATA:
Thierry FOURNIER93405e12015-08-26 14:19:03 +0200665 case LUA_TNONE:
666 default:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200667 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200668 smp->data.u.sint = 0;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100669 break;
670 }
671 return 1;
672}
673
Ilya Shipitsind4259502020-04-08 01:07:56 +0500674/* This function check the "argp" built by another conversion function
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -0800675 * is in accord with the expected argp defined by the "mask". The function
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100676 * returns true or false. It can be adjust the types if there compatibles.
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100677 *
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +0500678 * This function assumes that the argp argument contains ARGM_NBARGS + 1
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100679 * entries.
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100680 */
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100681__LJMP int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp,
David Carlier0c437f42016-04-27 16:21:56 +0100682 uint64_t mask, struct proxy *p)
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100683{
684 int min_arg;
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200685 int i, idx;
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100686 struct proxy *px;
Christopher Fauletd25d9262020-08-06 11:04:46 +0200687 struct userlist *ul;
Christopher Fauletfd2e9062020-08-06 11:10:57 +0200688 struct my_regex *reg;
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200689 const char *msg = NULL;
Christopher Fauletfd2e9062020-08-06 11:10:57 +0200690 char *sname, *pname, *err = NULL;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100691
692 idx = 0;
693 min_arg = ARGM(mask);
694 mask >>= ARGM_BITS;
695
696 while (1) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200697 struct buffer tmp = BUF_NULL;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100698
699 /* Check oversize. */
700 if (idx >= ARGM_NBARGS && argp[idx].type != ARGT_STOP) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200701 msg = "Malformed argument mask";
702 goto error;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100703 }
704
705 /* Check for mandatory arguments. */
706 if (argp[idx].type == ARGT_STOP) {
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100707 if (idx < min_arg) {
708
709 /* If miss other argument than the first one, we return an error. */
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200710 if (idx > 0) {
711 msg = "Mandatory argument expected";
712 goto error;
713 }
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100714
715 /* If first argument have a certain type, some default values
716 * may be used. See the function smp_resolve_args().
717 */
718 switch (mask & ARGT_MASK) {
719
720 case ARGT_FE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200721 if (!(p->cap & PR_CAP_FE)) {
722 msg = "Mandatory argument expected";
723 goto error;
724 }
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100725 argp[idx].data.prx = p;
726 argp[idx].type = ARGT_FE;
727 argp[idx+1].type = ARGT_STOP;
728 break;
729
730 case ARGT_BE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200731 if (!(p->cap & PR_CAP_BE)) {
732 msg = "Mandatory argument expected";
733 goto error;
734 }
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100735 argp[idx].data.prx = p;
736 argp[idx].type = ARGT_BE;
737 argp[idx+1].type = ARGT_STOP;
738 break;
739
740 case ARGT_TAB:
741 argp[idx].data.prx = p;
742 argp[idx].type = ARGT_TAB;
743 argp[idx+1].type = ARGT_STOP;
744 break;
745
746 default:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200747 msg = "Mandatory argument expected";
748 goto error;
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100749 break;
750 }
751 }
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200752 break;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100753 }
754
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500755 /* Check for exceed the number of required argument. */
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100756 if ((mask & ARGT_MASK) == ARGT_STOP &&
757 argp[idx].type != ARGT_STOP) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200758 msg = "Last argument expected";
759 goto error;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100760 }
761
762 if ((mask & ARGT_MASK) == ARGT_STOP &&
763 argp[idx].type == ARGT_STOP) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200764 break;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100765 }
766
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200767 /* Convert some argument types. All string in argp[] are for not
768 * duplicated yet.
769 */
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100770 switch (mask & ARGT_MASK) {
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100771 case ARGT_SINT:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200772 if (argp[idx].type != ARGT_SINT) {
773 msg = "integer expected";
774 goto error;
775 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100776 argp[idx].type = ARGT_SINT;
777 break;
778
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100779 case ARGT_TIME:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200780 if (argp[idx].type != ARGT_SINT) {
781 msg = "integer expected";
782 goto error;
783 }
Thierry FOURNIER29176f32015-07-07 00:41:29 +0200784 argp[idx].type = ARGT_TIME;
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100785 break;
786
787 case ARGT_SIZE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200788 if (argp[idx].type != ARGT_SINT) {
789 msg = "integer expected";
790 goto error;
791 }
Thierry FOURNIER29176f32015-07-07 00:41:29 +0200792 argp[idx].type = ARGT_SIZE;
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100793 break;
794
795 case ARGT_FE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200796 if (argp[idx].type != ARGT_STR) {
797 msg = "string expected";
798 goto error;
799 }
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200800 argp[idx].data.prx = proxy_fe_by_name(argp[idx].data.str.area);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200801 if (!argp[idx].data.prx) {
802 msg = "frontend doesn't exist";
803 goto error;
804 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100805 argp[idx].type = ARGT_FE;
806 break;
807
808 case ARGT_BE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200809 if (argp[idx].type != ARGT_STR) {
810 msg = "string expected";
811 goto error;
812 }
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200813 argp[idx].data.prx = proxy_be_by_name(argp[idx].data.str.area);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200814 if (!argp[idx].data.prx) {
815 msg = "backend doesn't exist";
816 goto error;
817 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100818 argp[idx].type = ARGT_BE;
819 break;
820
821 case ARGT_TAB:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200822 if (argp[idx].type != ARGT_STR) {
823 msg = "string expected";
824 goto error;
825 }
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200826 argp[idx].data.t = stktable_find_by_name(argp[idx].data.str.area);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200827 if (!argp[idx].data.t) {
828 msg = "table doesn't exist";
829 goto error;
830 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100831 argp[idx].type = ARGT_TAB;
832 break;
833
834 case ARGT_SRV:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200835 if (argp[idx].type != ARGT_STR) {
836 msg = "string expected";
837 goto error;
838 }
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200839 sname = strrchr(argp[idx].data.str.area, '/');
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100840 if (sname) {
841 *sname++ = '\0';
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200842 pname = argp[idx].data.str.area;
Willy Tarreau9e0bb102015-05-26 11:24:42 +0200843 px = proxy_be_by_name(pname);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200844 if (!px) {
845 msg = "backend doesn't exist";
846 goto error;
847 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100848 }
849 else {
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200850 sname = argp[idx].data.str.area;
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100851 px = p;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100852 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100853 argp[idx].data.srv = findserver(px, sname);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200854 if (!argp[idx].data.srv) {
855 msg = "server doesn't exist";
856 goto error;
857 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100858 argp[idx].type = ARGT_SRV;
859 break;
860
861 case ARGT_IPV4:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200862 if (argp[idx].type != ARGT_STR) {
863 msg = "string expected";
864 goto error;
865 }
866 if (inet_pton(AF_INET, argp[idx].data.str.area, &argp[idx].data.ipv4)) {
867 msg = "invalid IPv4 address";
868 goto error;
869 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100870 argp[idx].type = ARGT_IPV4;
871 break;
872
873 case ARGT_MSK4:
Christopher Faulete663a6e2020-08-07 09:11:22 +0200874 if (argp[idx].type == ARGT_SINT)
875 len2mask4(argp[idx].data.sint, &argp[idx].data.ipv4);
876 else if (argp[idx].type == ARGT_STR) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200877 if (!str2mask(argp[idx].data.str.area, &argp[idx].data.ipv4)) {
878 msg = "invalid IPv4 mask";
879 goto error;
880 }
881 }
882 else {
883 msg = "integer or string expected";
884 goto error;
Christopher Faulete663a6e2020-08-07 09:11:22 +0200885 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100886 argp[idx].type = ARGT_MSK4;
887 break;
888
889 case ARGT_IPV6:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200890 if (argp[idx].type != ARGT_STR) {
891 msg = "string expected";
892 goto error;
893 }
894 if (inet_pton(AF_INET6, argp[idx].data.str.area, &argp[idx].data.ipv6)) {
895 msg = "invalid IPv6 address";
896 goto error;
897 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100898 argp[idx].type = ARGT_IPV6;
899 break;
900
901 case ARGT_MSK6:
Christopher Faulete663a6e2020-08-07 09:11:22 +0200902 if (argp[idx].type == ARGT_SINT)
903 len2mask6(argp[idx].data.sint, &argp[idx].data.ipv6);
904 else if (argp[idx].type == ARGT_STR) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200905 if (!str2mask6(argp[idx].data.str.area, &argp[idx].data.ipv6)) {
906 msg = "invalid IPv6 mask";
907 goto error;
908 }
909 }
910 else {
911 msg = "integer or string expected";
912 goto error;
Christopher Faulete663a6e2020-08-07 09:11:22 +0200913 }
Tim Duesterhusb814da62018-01-25 16:24:50 +0100914 argp[idx].type = ARGT_MSK6;
915 break;
916
Christopher Fauletfd2e9062020-08-06 11:10:57 +0200917 case ARGT_REG:
918 if (argp[idx].type != ARGT_STR) {
919 msg = "string expected";
920 goto error;
921 }
922 reg = regex_comp(argp[idx].data.str.area, !(argp[idx].type_flags & ARGF_REG_ICASE), 1, &err);
923 if (!reg) {
924 msg = lua_pushfstring(L, "error compiling regex '%s' : '%s'",
925 argp[idx].data.str.area, err);
926 free(err);
927 goto error;
928 }
929 argp[idx].type = ARGT_REG;
930 argp[idx].data.reg = reg;
931 break;
932
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100933 case ARGT_USR:
Christopher Fauletd25d9262020-08-06 11:04:46 +0200934 if (argp[idx].type != ARGT_STR) {
935 msg = "string expected";
936 goto error;
937 }
938 if (p->uri_auth && p->uri_auth->userlist &&
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100939 strcmp(p->uri_auth->userlist->name, argp[idx].data.str.area) == 0)
Christopher Fauletd25d9262020-08-06 11:04:46 +0200940 ul = p->uri_auth->userlist;
941 else
942 ul = auth_find_userlist(argp[idx].data.str.area);
943
944 if (!ul) {
945 msg = lua_pushfstring(L, "unable to find userlist '%s'", argp[idx].data.str.area);
946 goto error;
947 }
948 argp[idx].type = ARGT_USR;
949 argp[idx].data.usr = ul;
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200950 break;
951
952 case ARGT_STR:
953 if (!chunk_dup(&tmp, &argp[idx].data.str)) {
954 msg = "unable to duplicate string arg";
955 goto error;
956 }
957 argp[idx].data.str = tmp;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100958 break;
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200959
Christopher Fauletd25d9262020-08-06 11:04:46 +0200960 case ARGT_MAP:
Christopher Fauletd25d9262020-08-06 11:04:46 +0200961 msg = "type not yet supported";
962 goto error;
963 break;
964
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100965 }
966
967 /* Check for type of argument. */
968 if ((mask & ARGT_MASK) != argp[idx].type) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200969 msg = lua_pushfstring(L, "'%s' expected, got '%s'",
970 arg_type_names[(mask & ARGT_MASK)],
971 arg_type_names[argp[idx].type & ARGT_MASK]);
972 goto error;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100973 }
974
975 /* Next argument. */
976 mask >>= ARGT_BITS;
977 idx++;
978 }
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200979 return 0;
980
981 error:
982 for (i = 0; i < idx; i++) {
983 if (argp[i].type == ARGT_STR)
984 chunk_destroy(&argp[i].data.str);
Christopher Fauletfd2e9062020-08-06 11:10:57 +0200985 else if (argp[i].type == ARGT_REG)
986 regex_free(argp[i].data.reg);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200987 }
988 WILL_LJMP(luaL_argerror(L, first + idx, msg));
989 return 0; /* Never reached */
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100990}
991
Thierry FOURNIER380d0932015-01-23 14:27:52 +0100992/*
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +0500993 * The following functions are used to make correspondence between the the
Thierry FOURNIER380d0932015-01-23 14:27:52 +0100994 * executed lua pointer and the "struct hlua *" that contain the context.
Thierry FOURNIER380d0932015-01-23 14:27:52 +0100995 *
996 * - hlua_gethlua : return the hlua context associated with an lua_State.
Thierry FOURNIER380d0932015-01-23 14:27:52 +0100997 * - hlua_sethlua : create the association between hlua context and lua_state.
998 */
999static inline struct hlua *hlua_gethlua(lua_State *L)
1000{
Thierry FOURNIER38c5fd62015-03-10 02:40:29 +01001001 struct hlua **hlua = lua_getextraspace(L);
1002 return *hlua;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001003}
1004static inline void hlua_sethlua(struct hlua *hlua)
1005{
Thierry FOURNIER38c5fd62015-03-10 02:40:29 +01001006 struct hlua **hlua_store = lua_getextraspace(hlua->T);
1007 *hlua_store = hlua;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001008}
1009
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001010/* This function is used to send logs. It try to send on screen (stderr)
1011 * and on the default syslog server.
1012 */
1013static inline void hlua_sendlog(struct proxy *px, int level, const char *msg)
1014{
1015 struct tm tm;
1016 char *p;
1017
1018 /* Cleanup the log message. */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001019 p = trash.area;
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001020 for (; *msg != '\0'; msg++, p++) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001021 if (p >= trash.area + trash.size - 1) {
Thierry FOURNIERccf00632015-09-16 12:47:03 +02001022 /* Break the message if exceed the buffer size. */
1023 *(p-4) = ' ';
1024 *(p-3) = '.';
1025 *(p-2) = '.';
1026 *(p-1) = '.';
1027 break;
1028 }
Willy Tarreau90807112020-02-25 08:16:33 +01001029 if (isprint((unsigned char)*msg))
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001030 *p = *msg;
1031 else
1032 *p = '.';
1033 }
1034 *p = '\0';
1035
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001036 send_log(px, level, "%s\n", trash.area);
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001037 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
Christopher Fauletf98d8212020-10-02 18:13:52 +02001038 if (level == LOG_DEBUG && !(global.mode & MODE_DEBUG))
1039 return;
1040
Willy Tarreaua678b432015-08-28 10:14:59 +02001041 get_localtime(date.tv_sec, &tm);
1042 fprintf(stderr, "[%s] %03d/%02d%02d%02d (%d) : %s\n",
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001043 log_levels[level], tm.tm_yday, tm.tm_hour, tm.tm_min, tm.tm_sec,
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001044 (int)getpid(), trash.area);
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001045 fflush(stderr);
1046 }
1047}
1048
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001049/* This function just ensure that the yield will be always
1050 * returned with a timeout and permit to set some flags
1051 */
1052__LJMP void hlua_yieldk(lua_State *L, int nresults, int ctx,
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01001053 lua_KFunction k, int timeout, unsigned int flags)
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001054{
Thierry Fournier4234dbd2020-11-28 13:18:23 +01001055 struct hlua *hlua;
1056
1057 /* Get hlua struct, or NULL if we execute from main lua state */
1058 hlua = hlua_gethlua(L);
1059 if (!hlua) {
1060 return;
1061 }
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001062
1063 /* Set the wake timeout. If timeout is required, we set
1064 * the expiration time.
1065 */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001066 hlua->wake_time = timeout;
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001067
Thierry FOURNIER4abd3ae2015-03-03 17:29:06 +01001068 hlua->flags |= flags;
1069
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001070 /* Process the yield. */
Willy Tarreau9635e032018-10-16 17:52:55 +02001071 MAY_LJMP(lua_yieldk(L, nresults, ctx, k));
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001072}
1073
Willy Tarreau87b09662015-04-03 00:22:06 +02001074/* This function initialises the Lua environment stored in the stream.
1075 * It must be called at the start of the stream. This function creates
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001076 * an LUA coroutine. It can not be use to crete the main LUA context.
Thierry FOURNIERbabae282015-09-17 11:36:37 +02001077 *
1078 * This function is particular. it initialises a new Lua thread. If the
1079 * initialisation fails (example: out of memory error), the lua function
1080 * throws an error (longjmp).
1081 *
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001082 * In some case (at least one), this function can be called from safe
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001083 * environment, so we must not initialise it. While the support of
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001084 * threads appear, the safe environment set a lock to ensure only one
1085 * Lua execution at a time. If we initialize safe environment in another
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001086 * safe environment, we have a dead lock.
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001087 *
1088 * set "already_safe" true if the context is initialized form safe
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001089 * Lua function.
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001090 *
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001091 * This function manipulates two Lua stacks: the main and the thread. Only
Thierry FOURNIERbabae282015-09-17 11:36:37 +02001092 * the main stack can fail. The thread is not manipulated. This function
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001093 * MUST NOT manipulate the created thread stack state, because it is not
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001094 * protected against errors thrown by the thread stack.
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001095 */
Thierry Fournier021d9862020-11-28 23:42:03 +01001096int hlua_ctx_init(struct hlua *lua, int state_id, struct task *task, int already_safe)
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001097{
1098 lua->Mref = LUA_REFNIL;
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01001099 lua->flags = 0;
Willy Tarreauf31af932020-01-14 09:59:38 +01001100 lua->gc_count = 0;
Christopher Fauletbc275a92020-02-26 14:55:16 +01001101 lua->wake_time = TICK_ETERNITY;
Thierry Fournier021d9862020-11-28 23:42:03 +01001102 lua->state_id = state_id;
Thierry FOURNIER9ff7e6e2015-01-23 11:08:20 +01001103 LIST_INIT(&lua->com);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001104 if (!already_safe) {
1105 if (!SET_SAFE_LJMP_PARENT(lua)) {
1106 lua->Tref = LUA_REFNIL;
1107 return 0;
1108 }
1109 }
Thierry Fournier021d9862020-11-28 23:42:03 +01001110 lua->T = lua_newthread(hlua_states[state_id]);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001111 if (!lua->T) {
1112 lua->Tref = LUA_REFNIL;
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001113 if (!already_safe)
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001114 RESET_SAFE_LJMP_PARENT(lua);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001115 return 0;
1116 }
1117 hlua_sethlua(lua);
Thierry Fournier021d9862020-11-28 23:42:03 +01001118 lua->Tref = luaL_ref(hlua_states[state_id], LUA_REGISTRYINDEX);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001119 lua->task = task;
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001120 if (!already_safe)
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001121 RESET_SAFE_LJMP_PARENT(lua);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001122 return 1;
1123}
1124
Willy Tarreau87b09662015-04-03 00:22:06 +02001125/* Used to destroy the Lua coroutine when the attached stream or task
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001126 * is destroyed. The destroy also the memory context. The struct "lua"
1127 * is not freed.
1128 */
1129void hlua_ctx_destroy(struct hlua *lua)
1130{
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01001131 if (!lua)
Thierry FOURNIERa718b292015-03-04 16:48:34 +01001132 return;
1133
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01001134 if (!lua->T)
1135 goto end;
1136
Thierry FOURNIER9ff7e6e2015-01-23 11:08:20 +01001137 /* Purge all the pending signals. */
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001138 notification_purge(&lua->com);
Thierry FOURNIER9ff7e6e2015-01-23 11:08:20 +01001139
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001140 if (!SET_SAFE_LJMP(lua))
Thierry FOURNIER75d02082017-07-12 13:41:33 +02001141 return;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001142 luaL_unref(lua->T, LUA_REGISTRYINDEX, lua->Mref);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001143 RESET_SAFE_LJMP(lua);
Thierry FOURNIER5a50a852015-09-23 16:59:28 +02001144
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001145 if (!SET_SAFE_LJMP_PARENT(lua))
Thierry FOURNIER75d02082017-07-12 13:41:33 +02001146 return;
Thierry Fournier021d9862020-11-28 23:42:03 +01001147 luaL_unref(hlua_states[lua->state_id], LUA_REGISTRYINDEX, lua->Tref);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001148 RESET_SAFE_LJMP_PARENT(lua);
Thierry FOURNIER5a50a852015-09-23 16:59:28 +02001149 /* Forces a garbage collecting process. If the Lua program is finished
1150 * without error, we run the GC on the thread pointer. Its freed all
1151 * the unused memory.
1152 * If the thread is finnish with an error or is currently yielded,
1153 * it seems that the GC applied on the thread doesn't clean anything,
1154 * so e run the GC on the main thread.
1155 * NOTE: maybe this action locks all the Lua threads untiml the en of
1156 * the garbage collection.
1157 */
Willy Tarreauf31af932020-01-14 09:59:38 +01001158 if (lua->gc_count) {
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001159 if (!SET_SAFE_LJMP_PARENT(lua))
Thierry FOURNIER75d02082017-07-12 13:41:33 +02001160 return;
Thierry Fournier021d9862020-11-28 23:42:03 +01001161 lua_gc(hlua_states[lua->state_id], LUA_GCCOLLECT, 0);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001162 RESET_SAFE_LJMP_PARENT(lua);
Thierry FOURNIER7c39ab42015-09-27 22:53:33 +02001163 }
Thierry FOURNIER5a50a852015-09-23 16:59:28 +02001164
Thierry FOURNIERa7b536b2015-09-21 22:50:24 +02001165 lua->T = NULL;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01001166
1167end:
Willy Tarreaubafbe012017-11-24 17:34:44 +01001168 pool_free(pool_head_hlua, lua);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001169}
1170
1171/* This function is used to restore the Lua context when a coroutine
1172 * fails. This function copy the common memory between old coroutine
1173 * and the new coroutine. The old coroutine is destroyed, and its
1174 * replaced by the new coroutine.
1175 * If the flag "keep_msg" is set, the last entry of the old is assumed
1176 * as string error message and it is copied in the new stack.
1177 */
1178static int hlua_ctx_renew(struct hlua *lua, int keep_msg)
1179{
1180 lua_State *T;
1181 int new_ref;
1182
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001183 /* New Lua coroutine. */
Thierry Fournier021d9862020-11-28 23:42:03 +01001184 T = lua_newthread(hlua_states[lua->state_id]);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001185 if (!T)
1186 return 0;
1187
1188 /* Copy last error message. */
1189 if (keep_msg)
1190 lua_xmove(lua->T, T, 1);
1191
1192 /* Copy data between the coroutines. */
1193 lua_rawgeti(lua->T, LUA_REGISTRYINDEX, lua->Mref);
1194 lua_xmove(lua->T, T, 1);
Ilya Shipitsin46a030c2020-07-05 16:36:08 +05001195 new_ref = luaL_ref(T, LUA_REGISTRYINDEX); /* Value popped. */
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001196
1197 /* Destroy old data. */
1198 luaL_unref(lua->T, LUA_REGISTRYINDEX, lua->Mref);
1199
1200 /* The thread is garbage collected by Lua. */
Thierry Fournier021d9862020-11-28 23:42:03 +01001201 luaL_unref(hlua_states[lua->state_id], LUA_REGISTRYINDEX, lua->Tref);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001202
1203 /* Fill the struct with the new coroutine values. */
1204 lua->Mref = new_ref;
1205 lua->T = T;
Thierry Fournier021d9862020-11-28 23:42:03 +01001206 lua->Tref = luaL_ref(hlua_states[lua->state_id], LUA_REGISTRYINDEX);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001207
1208 /* Set context. */
1209 hlua_sethlua(lua);
1210
1211 return 1;
1212}
1213
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001214void hlua_hook(lua_State *L, lua_Debug *ar)
1215{
Thierry Fournier4234dbd2020-11-28 13:18:23 +01001216 struct hlua *hlua;
1217
1218 /* Get hlua struct, or NULL if we execute from main lua state */
1219 hlua = hlua_gethlua(L);
1220 if (!hlua)
1221 return;
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001222
1223 /* Lua cannot yield when its returning from a function,
1224 * so, we can fix the interrupt hook to 1 instruction,
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001225 * expecting that the function is finished.
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001226 */
1227 if (lua_gethookmask(L) & LUA_MASKRET) {
1228 lua_sethook(hlua->T, hlua_hook, LUA_MASKCOUNT, 1);
1229 return;
1230 }
1231
1232 /* restore the interrupt condition. */
1233 lua_sethook(hlua->T, hlua_hook, LUA_MASKCOUNT, hlua_nb_instruction);
1234
1235 /* If we interrupt the Lua processing in yieldable state, we yield.
1236 * If the state is not yieldable, trying yield causes an error.
1237 */
1238 if (lua_isyieldable(L))
Willy Tarreau9635e032018-10-16 17:52:55 +02001239 MAY_LJMP(hlua_yieldk(L, 0, 0, NULL, TICK_ETERNITY, HLUA_CTRLYIELD));
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001240
Thierry FOURNIERa85cfb12015-03-13 14:50:06 +01001241 /* If we cannot yield, update the clock and check the timeout. */
1242 tv_update_date(0, 1);
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001243 hlua->run_time += now_ms - hlua->start_time;
1244 if (hlua->max_time && hlua->run_time >= hlua->max_time) {
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001245 lua_pushfstring(L, "execution timeout");
1246 WILL_LJMP(lua_error(L));
1247 }
1248
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001249 /* Update the start time. */
1250 hlua->start_time = now_ms;
1251
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001252 /* Try to interrupt the process at the end of the current
1253 * unyieldable function.
1254 */
1255 lua_sethook(hlua->T, hlua_hook, LUA_MASKRET|LUA_MASKCOUNT, hlua_nb_instruction);
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001256}
1257
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001258/* This function start or resumes the Lua stack execution. If the flag
1259 * "yield_allowed" if no set and the LUA stack execution returns a yield
1260 * The function return an error.
1261 *
1262 * The function can returns 4 values:
1263 * - HLUA_E_OK : The execution is terminated without any errors.
1264 * - HLUA_E_AGAIN : The execution must continue at the next associated
1265 * task wakeup.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001266 * - HLUA_E_ERRMSG : An error has occurred, an error message is set in
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001267 * the top of the stack.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001268 * - HLUA_E_ERR : An error has occurred without error message.
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001269 *
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001270 * If an error occurred, the stack is renewed and it is ready to run new
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001271 * LUA code.
1272 */
1273static enum hlua_exec hlua_ctx_resume(struct hlua *lua, int yield_allowed)
1274{
Christopher Faulet08ed98f2020-07-28 10:33:25 +02001275#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
1276 int nres;
1277#endif
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001278 int ret;
1279 const char *msg;
Thierry FOURNIERfc044c92018-06-07 14:40:48 +02001280 const char *trace;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001281
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001282 /* Initialise run time counter. */
1283 if (!HLUA_IS_RUNNING(lua))
1284 lua->run_time = 0;
Thierry FOURNIERdc9ca962015-03-05 11:16:52 +01001285
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +02001286 /* Lock the whole Lua execution. This lock must be before the
1287 * label "resume_execution".
1288 */
Thierry Fournier021d9862020-11-28 23:42:03 +01001289 if (lua->state_id == 0)
Willy Tarreau3eb2e472021-08-20 15:47:25 +02001290 lua_take_global_lock();
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +02001291
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001292resume_execution:
1293
1294 /* This hook interrupts the Lua processing each 'hlua_nb_instruction'
1295 * instructions. it is used for preventing infinite loops.
1296 */
1297 lua_sethook(lua->T, hlua_hook, LUA_MASKCOUNT, hlua_nb_instruction);
1298
Thierry FOURNIER1bfc09b2015-03-05 17:10:14 +01001299 /* Remove all flags except the running flags. */
Thierry FOURNIER2f3867f2015-09-28 01:02:01 +02001300 HLUA_SET_RUN(lua);
1301 HLUA_CLR_CTRLYIELD(lua);
1302 HLUA_CLR_WAKERESWR(lua);
1303 HLUA_CLR_WAKEREQWR(lua);
Thierry FOURNIER1bfc09b2015-03-05 17:10:14 +01001304
Christopher Fauletbc275a92020-02-26 14:55:16 +01001305 /* Update the start time and reset wake_time. */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001306 lua->start_time = now_ms;
Christopher Fauletbc275a92020-02-26 14:55:16 +01001307 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001308
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001309 /* Call the function. */
Christopher Faulet08ed98f2020-07-28 10:33:25 +02001310#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
Thierry Fournier021d9862020-11-28 23:42:03 +01001311 ret = lua_resume(lua->T, hlua_states[lua->state_id], lua->nargs, &nres);
Christopher Faulet08ed98f2020-07-28 10:33:25 +02001312#else
Thierry Fournier021d9862020-11-28 23:42:03 +01001313 ret = lua_resume(lua->T, hlua_states[lua->state_id], lua->nargs);
Christopher Faulet08ed98f2020-07-28 10:33:25 +02001314#endif
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001315 switch (ret) {
1316
1317 case LUA_OK:
1318 ret = HLUA_E_OK;
1319 break;
1320
1321 case LUA_YIELD:
Thierry FOURNIERdc9ca962015-03-05 11:16:52 +01001322 /* Check if the execution timeout is expired. It it is the case, we
1323 * break the Lua execution.
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001324 */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001325 tv_update_date(0, 1);
1326 lua->run_time += now_ms - lua->start_time;
1327 if (lua->max_time && lua->run_time > lua->max_time) {
Thierry FOURNIERdc9ca962015-03-05 11:16:52 +01001328 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001329 ret = HLUA_E_ETMOUT;
Thierry FOURNIERdc9ca962015-03-05 11:16:52 +01001330 break;
1331 }
1332 /* Process the forced yield. if the general yield is not allowed or
1333 * if no task were associated this the current Lua execution
1334 * coroutine, we resume the execution. Else we want to return in the
1335 * scheduler and we want to be waked up again, to continue the
1336 * current Lua execution. So we schedule our own task.
1337 */
1338 if (HLUA_IS_CTRLYIELDING(lua)) {
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001339 if (!yield_allowed || !lua->task)
1340 goto resume_execution;
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001341 task_wakeup(lua->task, TASK_WOKEN_MSG);
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001342 }
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001343 if (!yield_allowed) {
1344 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001345 ret = HLUA_E_YIELD;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001346 break;
1347 }
1348 ret = HLUA_E_AGAIN;
1349 break;
1350
1351 case LUA_ERRRUN:
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001352
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001353 /* Special exit case. The traditional exit is returned as an error
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001354 * because the errors ares the only one mean to return immediately
1355 * from and lua execution.
1356 */
1357 if (lua->flags & HLUA_EXIT) {
1358 ret = HLUA_E_OK;
Christopher Faulet7716cdf2020-01-29 11:53:30 +01001359 hlua_ctx_renew(lua, 1);
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001360 break;
1361 }
1362
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001363 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001364 if (!lua_checkstack(lua->T, 1)) {
1365 ret = HLUA_E_ERR;
1366 break;
1367 }
1368 msg = lua_tostring(lua->T, -1);
1369 lua_settop(lua->T, 0); /* Empty the stack. */
1370 lua_pop(lua->T, 1);
Christopher Fauletd09cc512021-03-24 14:48:45 +01001371 trace = hlua_traceback(lua->T, ", ");
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001372 if (msg)
Thierry Fournier46278ff2020-11-29 11:48:12 +01001373 lua_pushfstring(lua->T, "[state-id %d] runtime error: %s from %s", lua->state_id, msg, trace);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001374 else
Thierry Fournier46278ff2020-11-29 11:48:12 +01001375 lua_pushfstring(lua->T, "[state-id %d] unknown runtime error from %s", lua->state_id, trace);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001376 ret = HLUA_E_ERRMSG;
1377 break;
1378
1379 case LUA_ERRMEM:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001380 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001381 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001382 ret = HLUA_E_NOMEM;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001383 break;
1384
1385 case LUA_ERRERR:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001386 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001387 if (!lua_checkstack(lua->T, 1)) {
1388 ret = HLUA_E_ERR;
1389 break;
1390 }
1391 msg = lua_tostring(lua->T, -1);
1392 lua_settop(lua->T, 0); /* Empty the stack. */
1393 lua_pop(lua->T, 1);
1394 if (msg)
Thierry Fournier46278ff2020-11-29 11:48:12 +01001395 lua_pushfstring(lua->T, "[state-id %d] message handler error: %s", lua->state_id, msg);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001396 else
Thierry Fournier46278ff2020-11-29 11:48:12 +01001397 lua_pushfstring(lua->T, "[state-id %d] message handler error", lua->state_id);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001398 ret = HLUA_E_ERRMSG;
1399 break;
1400
1401 default:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001402 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001403 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001404 ret = HLUA_E_ERR;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001405 break;
1406 }
1407
1408 switch (ret) {
1409 case HLUA_E_AGAIN:
1410 break;
1411
1412 case HLUA_E_ERRMSG:
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001413 notification_purge(&lua->com);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001414 hlua_ctx_renew(lua, 1);
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01001415 HLUA_CLR_RUN(lua);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001416 break;
1417
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001418 case HLUA_E_ETMOUT:
1419 case HLUA_E_NOMEM:
1420 case HLUA_E_YIELD:
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001421 case HLUA_E_ERR:
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01001422 HLUA_CLR_RUN(lua);
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001423 notification_purge(&lua->com);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001424 hlua_ctx_renew(lua, 0);
1425 break;
1426
1427 case HLUA_E_OK:
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01001428 HLUA_CLR_RUN(lua);
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001429 notification_purge(&lua->com);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001430 break;
1431 }
1432
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +02001433 /* This is the main exit point, remove the Lua lock. */
Thierry Fournier021d9862020-11-28 23:42:03 +01001434 if (lua->state_id == 0)
Willy Tarreau3eb2e472021-08-20 15:47:25 +02001435 lua_drop_global_lock();
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +02001436
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001437 return ret;
1438}
1439
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001440/* This function exit the current code. */
1441__LJMP static int hlua_done(lua_State *L)
1442{
Thierry Fournier4234dbd2020-11-28 13:18:23 +01001443 struct hlua *hlua;
1444
1445 /* Get hlua struct, or NULL if we execute from main lua state */
1446 hlua = hlua_gethlua(L);
1447 if (!hlua)
1448 return 0;
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001449
1450 hlua->flags |= HLUA_EXIT;
1451 WILL_LJMP(lua_error(L));
1452
1453 return 0;
1454}
1455
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001456/* This function is an LUA binding. It provides a function
1457 * for deleting ACL from a referenced ACL file.
1458 */
1459__LJMP static int hlua_del_acl(lua_State *L)
1460{
1461 const char *name;
1462 const char *key;
1463 struct pat_ref *ref;
1464
1465 MAY_LJMP(check_args(L, 2, "del_acl"));
1466
1467 name = MAY_LJMP(luaL_checkstring(L, 1));
1468 key = MAY_LJMP(luaL_checkstring(L, 2));
1469
1470 ref = pat_ref_lookup(name);
1471 if (!ref)
Vincent Bernata72db182015-10-06 16:05:59 +02001472 WILL_LJMP(luaL_error(L, "'del_acl': unknown acl file '%s'", name));
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001473
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001474 HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001475 pat_ref_delete(ref, key);
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001476 HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001477 return 0;
1478}
1479
1480/* This function is an LUA binding. It provides a function
1481 * for deleting map entry from a referenced map file.
1482 */
1483static int hlua_del_map(lua_State *L)
1484{
1485 const char *name;
1486 const char *key;
1487 struct pat_ref *ref;
1488
1489 MAY_LJMP(check_args(L, 2, "del_map"));
1490
1491 name = MAY_LJMP(luaL_checkstring(L, 1));
1492 key = MAY_LJMP(luaL_checkstring(L, 2));
1493
1494 ref = pat_ref_lookup(name);
1495 if (!ref)
Vincent Bernata72db182015-10-06 16:05:59 +02001496 WILL_LJMP(luaL_error(L, "'del_map': unknown acl file '%s'", name));
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001497
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001498 HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001499 pat_ref_delete(ref, key);
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001500 HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001501 return 0;
1502}
1503
1504/* This function is an LUA binding. It provides a function
1505 * for adding ACL pattern from a referenced ACL file.
1506 */
1507static int hlua_add_acl(lua_State *L)
1508{
1509 const char *name;
1510 const char *key;
1511 struct pat_ref *ref;
1512
1513 MAY_LJMP(check_args(L, 2, "add_acl"));
1514
1515 name = MAY_LJMP(luaL_checkstring(L, 1));
1516 key = MAY_LJMP(luaL_checkstring(L, 2));
1517
1518 ref = pat_ref_lookup(name);
1519 if (!ref)
Vincent Bernata72db182015-10-06 16:05:59 +02001520 WILL_LJMP(luaL_error(L, "'add_acl': unknown acl file '%s'", name));
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001521
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001522 HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001523 if (pat_ref_find_elt(ref, key) == NULL)
1524 pat_ref_add(ref, key, NULL, NULL);
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001525 HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001526 return 0;
1527}
1528
1529/* This function is an LUA binding. It provides a function
1530 * for setting map pattern and sample from a referenced map
1531 * file.
1532 */
1533static int hlua_set_map(lua_State *L)
1534{
1535 const char *name;
1536 const char *key;
1537 const char *value;
1538 struct pat_ref *ref;
1539
1540 MAY_LJMP(check_args(L, 3, "set_map"));
1541
1542 name = MAY_LJMP(luaL_checkstring(L, 1));
1543 key = MAY_LJMP(luaL_checkstring(L, 2));
1544 value = MAY_LJMP(luaL_checkstring(L, 3));
1545
1546 ref = pat_ref_lookup(name);
1547 if (!ref)
Vincent Bernata72db182015-10-06 16:05:59 +02001548 WILL_LJMP(luaL_error(L, "'set_map': unknown map file '%s'", name));
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001549
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001550 HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001551 if (pat_ref_find_elt(ref, key) != NULL)
1552 pat_ref_set(ref, key, value, NULL);
1553 else
1554 pat_ref_add(ref, key, value, NULL);
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001555 HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001556 return 0;
1557}
1558
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01001559/* A class is a lot of memory that contain data. This data can be a table,
1560 * an integer or user data. This data is associated with a metatable. This
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +05001561 * metatable have an original version registered in the global context with
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01001562 * the name of the object (_G[<name>] = <metable> ).
1563 *
1564 * A metable is a table that modify the standard behavior of a standard
1565 * access to the associated data. The entries of this new metatable are
1566 * defined as is:
1567 *
1568 * http://lua-users.org/wiki/MetatableEvents
1569 *
1570 * __index
1571 *
1572 * we access an absent field in a table, the result is nil. This is
1573 * true, but it is not the whole truth. Actually, such access triggers
1574 * the interpreter to look for an __index metamethod: If there is no
1575 * such method, as usually happens, then the access results in nil;
1576 * otherwise, the metamethod will provide the result.
1577 *
1578 * Control 'prototype' inheritance. When accessing "myTable[key]" and
1579 * the key does not appear in the table, but the metatable has an __index
1580 * property:
1581 *
1582 * - if the value is a function, the function is called, passing in the
1583 * table and the key; the return value of that function is returned as
1584 * the result.
1585 *
1586 * - if the value is another table, the value of the key in that table is
1587 * asked for and returned (and if it doesn't exist in that table, but that
1588 * table's metatable has an __index property, then it continues on up)
1589 *
1590 * - Use "rawget(myTable,key)" to skip this metamethod.
1591 *
1592 * http://www.lua.org/pil/13.4.1.html
1593 *
1594 * __newindex
1595 *
1596 * Like __index, but control property assignment.
1597 *
1598 * __mode - Control weak references. A string value with one or both
1599 * of the characters 'k' and 'v' which specifies that the the
1600 * keys and/or values in the table are weak references.
1601 *
1602 * __call - Treat a table like a function. When a table is followed by
1603 * parenthesis such as "myTable( 'foo' )" and the metatable has
1604 * a __call key pointing to a function, that function is invoked
1605 * (passing any specified arguments) and the return value is
1606 * returned.
1607 *
1608 * __metatable - Hide the metatable. When "getmetatable( myTable )" is
1609 * called, if the metatable for myTable has a __metatable
1610 * key, the value of that key is returned instead of the
1611 * actual metatable.
1612 *
1613 * __tostring - Control string representation. When the builtin
1614 * "tostring( myTable )" function is called, if the metatable
1615 * for myTable has a __tostring property set to a function,
1616 * that function is invoked (passing myTable to it) and the
1617 * return value is used as the string representation.
1618 *
1619 * __len - Control table length. When the table length is requested using
1620 * the length operator ( '#' ), if the metatable for myTable has
1621 * a __len key pointing to a function, that function is invoked
1622 * (passing myTable to it) and the return value used as the value
1623 * of "#myTable".
1624 *
1625 * __gc - Userdata finalizer code. When userdata is set to be garbage
1626 * collected, if the metatable has a __gc field pointing to a
1627 * function, that function is first invoked, passing the userdata
1628 * to it. The __gc metamethod is not called for tables.
1629 * (See http://lua-users.org/lists/lua-l/2006-11/msg00508.html)
1630 *
1631 * Special metamethods for redefining standard operators:
1632 * http://www.lua.org/pil/13.1.html
1633 *
1634 * __add "+"
1635 * __sub "-"
1636 * __mul "*"
1637 * __div "/"
1638 * __unm "!"
1639 * __pow "^"
1640 * __concat ".."
1641 *
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001642 * Special methods for redefining standard relations
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01001643 * http://www.lua.org/pil/13.2.html
1644 *
1645 * __eq "=="
1646 * __lt "<"
1647 * __le "<="
1648 */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001649
1650/*
1651 *
1652 *
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001653 * Class Map
1654 *
1655 *
1656 */
1657
1658/* Returns a struct hlua_map if the stack entry "ud" is
1659 * a class session, otherwise it throws an error.
1660 */
1661__LJMP static struct map_descriptor *hlua_checkmap(lua_State *L, int ud)
1662{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02001663 return MAY_LJMP(hlua_checkudata(L, ud, class_map_ref));
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001664}
1665
1666/* This function is the map constructor. It don't need
1667 * the class Map object. It creates and return a new Map
1668 * object. It must be called only during "body" or "init"
1669 * context because it process some filesystem accesses.
1670 */
1671__LJMP static int hlua_map_new(struct lua_State *L)
1672{
1673 const char *fn;
1674 int match = PAT_MATCH_STR;
1675 struct sample_conv conv;
1676 const char *file = "";
1677 int line = 0;
1678 lua_Debug ar;
1679 char *err = NULL;
1680 struct arg args[2];
1681
1682 if (lua_gettop(L) < 1 || lua_gettop(L) > 2)
1683 WILL_LJMP(luaL_error(L, "'new' needs at least 1 argument."));
1684
1685 fn = MAY_LJMP(luaL_checkstring(L, 1));
1686
1687 if (lua_gettop(L) >= 2) {
1688 match = MAY_LJMP(luaL_checkinteger(L, 2));
1689 if (match < 0 || match >= PAT_MATCH_NUM)
1690 WILL_LJMP(luaL_error(L, "'new' needs a valid match method."));
1691 }
1692
1693 /* Get Lua filename and line number. */
1694 if (lua_getstack(L, 1, &ar)) { /* check function at level */
1695 lua_getinfo(L, "Sl", &ar); /* get info about it */
1696 if (ar.currentline > 0) { /* is there info? */
1697 file = ar.short_src;
1698 line = ar.currentline;
1699 }
1700 }
1701
1702 /* fill fake sample_conv struct. */
1703 conv.kw = ""; /* unused. */
1704 conv.process = NULL; /* unused. */
1705 conv.arg_mask = 0; /* unused. */
1706 conv.val_args = NULL; /* unused. */
1707 conv.out_type = SMP_T_STR;
1708 conv.private = (void *)(long)match;
1709 switch (match) {
1710 case PAT_MATCH_STR: conv.in_type = SMP_T_STR; break;
1711 case PAT_MATCH_BEG: conv.in_type = SMP_T_STR; break;
1712 case PAT_MATCH_SUB: conv.in_type = SMP_T_STR; break;
1713 case PAT_MATCH_DIR: conv.in_type = SMP_T_STR; break;
1714 case PAT_MATCH_DOM: conv.in_type = SMP_T_STR; break;
1715 case PAT_MATCH_END: conv.in_type = SMP_T_STR; break;
1716 case PAT_MATCH_REG: conv.in_type = SMP_T_STR; break;
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001717 case PAT_MATCH_INT: conv.in_type = SMP_T_SINT; break;
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001718 case PAT_MATCH_IP: conv.in_type = SMP_T_ADDR; break;
1719 default:
1720 WILL_LJMP(luaL_error(L, "'new' doesn't support this match mode."));
1721 }
1722
1723 /* fill fake args. */
1724 args[0].type = ARGT_STR;
Christopher Faulet73292e92020-08-06 08:40:09 +02001725 args[0].data.str.area = strdup(fn);
1726 args[0].data.str.data = strlen(fn);
1727 args[0].data.str.size = args[0].data.str.data+1;
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001728 args[1].type = ARGT_STOP;
1729
1730 /* load the map. */
1731 if (!sample_load_map(args, &conv, file, line, &err)) {
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05001732 /* error case: we can't use luaL_error because we must
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001733 * free the err variable.
1734 */
1735 luaL_where(L, 1);
1736 lua_pushfstring(L, "'new': %s.", err);
1737 lua_concat(L, 2);
1738 free(err);
Christopher Faulet6ad7df42020-08-07 11:45:18 +02001739 chunk_destroy(&args[0].data.str);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001740 WILL_LJMP(lua_error(L));
1741 }
1742
1743 /* create the lua object. */
1744 lua_newtable(L);
1745 lua_pushlightuserdata(L, args[0].data.map);
1746 lua_rawseti(L, -2, 0);
1747
1748 /* Pop a class Map metatable and affect it to the userdata. */
1749 lua_rawgeti(L, LUA_REGISTRYINDEX, class_map_ref);
1750 lua_setmetatable(L, -2);
1751
1752
1753 return 1;
1754}
1755
1756__LJMP static inline int _hlua_map_lookup(struct lua_State *L, int str)
1757{
1758 struct map_descriptor *desc;
1759 struct pattern *pat;
1760 struct sample smp;
1761
1762 MAY_LJMP(check_args(L, 2, "lookup"));
1763 desc = MAY_LJMP(hlua_checkmap(L, 1));
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001764 if (desc->pat.expect_type == SMP_T_SINT) {
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001765 smp.data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001766 smp.data.u.sint = MAY_LJMP(luaL_checkinteger(L, 2));
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001767 }
1768 else {
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001769 smp.data.type = SMP_T_STR;
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001770 smp.flags = SMP_F_CONST;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001771 smp.data.u.str.area = (char *)MAY_LJMP(luaL_checklstring(L, 2, (size_t *)&smp.data.u.str.data));
Thierry Fournier91dc0c02020-11-10 20:38:20 +01001772 smp.data.u.str.size = smp.data.u.str.data + 1;
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001773 }
1774
1775 pat = pattern_exec_match(&desc->pat, &smp, 1);
Thierry FOURNIER503bb092015-08-19 08:35:43 +02001776 if (!pat || !pat->data) {
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001777 if (str)
1778 lua_pushstring(L, "");
1779 else
1780 lua_pushnil(L);
1781 return 1;
1782 }
1783
1784 /* The Lua pattern must return a string, so we can't check the returned type */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001785 lua_pushlstring(L, pat->data->u.str.area, pat->data->u.str.data);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001786 return 1;
1787}
1788
1789__LJMP static int hlua_map_lookup(struct lua_State *L)
1790{
1791 return _hlua_map_lookup(L, 0);
1792}
1793
1794__LJMP static int hlua_map_slookup(struct lua_State *L)
1795{
1796 return _hlua_map_lookup(L, 1);
1797}
1798
1799/*
1800 *
1801 *
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001802 * Class Socket
1803 *
1804 *
1805 */
1806
1807__LJMP static struct hlua_socket *hlua_checksocket(lua_State *L, int ud)
1808{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02001809 return MAY_LJMP(hlua_checkudata(L, ud, class_socket_ref));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001810}
1811
1812/* This function is the handler called for each I/O on the established
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001813 * connection. It is used for notify space available to send or data
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001814 * received.
1815 */
Willy Tarreau00a37f02015-04-13 12:05:19 +02001816static void hlua_socket_handler(struct appctx *appctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001817{
Willy Tarreau00a37f02015-04-13 12:05:19 +02001818 struct stream_interface *si = appctx->owner;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001819
Thierry FOURNIERb13b20a2017-07-16 20:48:54 +02001820 if (appctx->ctx.hlua_cosocket.die) {
1821 si_shutw(si);
1822 si_shutr(si);
1823 si_ic(si)->flags |= CF_READ_NULL;
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001824 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_read);
1825 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_write);
Thierry FOURNIERb13b20a2017-07-16 20:48:54 +02001826 stream_shutdown(si_strm(si), SF_ERR_KILLED);
1827 }
1828
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05001829 /* If we can't write, wakeup the pending write signals. */
Thierry FOURNIER6d695e62015-09-27 19:29:38 +02001830 if (channel_output_closed(si_ic(si)))
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001831 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_write);
Thierry FOURNIER6d695e62015-09-27 19:29:38 +02001832
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05001833 /* If we can't read, wakeup the pending read signals. */
Thierry FOURNIER6d695e62015-09-27 19:29:38 +02001834 if (channel_input_closed(si_oc(si)))
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001835 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_read);
Thierry FOURNIER6d695e62015-09-27 19:29:38 +02001836
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02001837 /* if the connection is not established, inform the stream that we want
Thierry FOURNIER316e3192015-09-04 18:25:53 +02001838 * to be notified whenever the connection completes.
1839 */
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02001840 if (si_opposite(si)->state < SI_ST_EST) {
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01001841 si_cant_get(si);
Willy Tarreau12c24232018-12-06 15:29:50 +01001842 si_rx_conn_blk(si);
Willy Tarreau3367d412018-11-15 10:57:41 +01001843 si_rx_endp_more(si);
Willy Tarreaud4da1962015-04-20 01:31:23 +02001844 return;
Thierry FOURNIER316e3192015-09-04 18:25:53 +02001845 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001846
1847 /* This function is called after the connect. */
Thierry FOURNIER18d09902016-12-16 09:25:38 +01001848 appctx->ctx.hlua_cosocket.connected = 1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001849
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001850 /* Wake the tasks which wants to write if the buffer have available space. */
Thierry FOURNIEReba6f642015-09-26 22:01:07 +02001851 if (channel_may_recv(si_ic(si)))
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001852 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_write);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001853
1854 /* Wake the tasks which wants to read if the buffer contains data. */
Thierry FOURNIEReba6f642015-09-26 22:01:07 +02001855 if (!channel_is_empty(si_oc(si)))
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001856 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_read);
Thierry FOURNIER101b9762018-05-27 01:27:40 +02001857
1858 /* Some data were injected in the buffer, notify the stream
1859 * interface.
1860 */
1861 if (!channel_is_empty(si_ic(si)))
Willy Tarreau14bfe9a2018-12-19 15:19:27 +01001862 si_update(si);
Thierry FOURNIER101b9762018-05-27 01:27:40 +02001863
1864 /* If write notifications are registered, we considers we want
Willy Tarreau3367d412018-11-15 10:57:41 +01001865 * to write, so we clear the blocking flag.
Thierry FOURNIER101b9762018-05-27 01:27:40 +02001866 */
1867 if (notification_registered(&appctx->ctx.hlua_cosocket.wake_on_write))
Willy Tarreau3367d412018-11-15 10:57:41 +01001868 si_rx_endp_more(si);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001869}
1870
Willy Tarreau87b09662015-04-03 00:22:06 +02001871/* This function is called when the "struct stream" is destroyed.
1872 * Remove the link from the object to this stream.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001873 * Wake all the pending signals.
1874 */
Willy Tarreau00a37f02015-04-13 12:05:19 +02001875static void hlua_socket_release(struct appctx *appctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001876{
Thierry FOURNIER952939d2017-09-01 14:17:32 +02001877 struct xref *peer;
1878
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001879 /* Remove my link in the original object. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02001880 peer = xref_get_peer_and_lock(&appctx->ctx.hlua_cosocket.xref);
1881 if (peer)
1882 xref_disconnect(&appctx->ctx.hlua_cosocket.xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001883
1884 /* Wake all the task waiting for me. */
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001885 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_read);
1886 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_write);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001887}
1888
1889/* If the garbage collectio of the object is launch, nobody
Willy Tarreau87b09662015-04-03 00:22:06 +02001890 * uses this object. If the stream does not exists, just quit.
1891 * Send the shutdown signal to the stream. In some cases,
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001892 * pending signal can rest in the read and write lists. destroy
1893 * it.
1894 */
1895__LJMP static int hlua_socket_gc(lua_State *L)
1896{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01001897 struct hlua_socket *socket;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001898 struct appctx *appctx;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001899 struct xref *peer;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001900
Willy Tarreau80f5fae2015-02-27 16:38:20 +01001901 MAY_LJMP(check_args(L, 1, "__gc"));
1902
1903 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02001904 peer = xref_get_peer_and_lock(&socket->xref);
1905 if (!peer)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001906 return 0;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001907 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001908
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001909 /* Set the flag which destroy the session. */
Thierry FOURNIERb13b20a2017-07-16 20:48:54 +02001910 appctx->ctx.hlua_cosocket.die = 1;
1911 appctx_wakeup(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001912
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001913 /* Remove all reference between the Lua stack and the coroutine stream. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02001914 xref_disconnect(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001915 return 0;
1916}
1917
1918/* The close function send shutdown signal and break the
Willy Tarreau87b09662015-04-03 00:22:06 +02001919 * links between the stream and the object.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001920 */
sada05ed3302018-05-11 11:48:18 -07001921__LJMP static int hlua_socket_close_helper(lua_State *L)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001922{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01001923 struct hlua_socket *socket;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001924 struct appctx *appctx;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001925 struct xref *peer;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01001926 struct hlua *hlua;
1927
1928 /* Get hlua struct, or NULL if we execute from main lua state */
1929 hlua = hlua_gethlua(L);
1930 if (!hlua)
1931 return 0;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001932
Willy Tarreau80f5fae2015-02-27 16:38:20 +01001933 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02001934
1935 /* Check if we run on the same thread than the xreator thread.
1936 * We cannot access to the socket if the thread is different.
1937 */
1938 if (socket->tid != tid)
1939 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
1940
Thierry FOURNIER952939d2017-09-01 14:17:32 +02001941 peer = xref_get_peer_and_lock(&socket->xref);
1942 if (!peer)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001943 return 0;
Willy Tarreauf31af932020-01-14 09:59:38 +01001944
1945 hlua->gc_count--;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001946 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001947
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001948 /* Set the flag which destroy the session. */
Thierry FOURNIERb13b20a2017-07-16 20:48:54 +02001949 appctx->ctx.hlua_cosocket.die = 1;
1950 appctx_wakeup(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001951
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001952 /* Remove all reference between the Lua stack and the coroutine stream. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02001953 xref_disconnect(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001954 return 0;
1955}
1956
sada05ed3302018-05-11 11:48:18 -07001957/* The close function calls close_helper.
1958 */
1959__LJMP static int hlua_socket_close(lua_State *L)
1960{
1961 MAY_LJMP(check_args(L, 1, "close"));
1962 return hlua_socket_close_helper(L);
1963}
1964
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001965/* This Lua function assumes that the stack contain three parameters.
1966 * 1 - USERDATA containing a struct socket
1967 * 2 - INTEGER with values of the macro defined below
1968 * If the integer is -1, we must read at most one line.
1969 * If the integer is -2, we ust read all the data until the
1970 * end of the stream.
1971 * If the integer is positive value, we must read a number of
1972 * bytes corresponding to this value.
1973 */
1974#define HLSR_READ_LINE (-1)
1975#define HLSR_READ_ALL (-2)
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01001976__LJMP static int hlua_socket_receive_yield(struct lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001977{
1978 struct hlua_socket *socket = MAY_LJMP(hlua_checksocket(L, 1));
1979 int wanted = lua_tointeger(L, 2);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01001980 struct hlua *hlua;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001981 struct appctx *appctx;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02001982 size_t len;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001983 int nblk;
Willy Tarreau206ba832018-06-14 15:27:31 +02001984 const char *blk1;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02001985 size_t len1;
Willy Tarreau206ba832018-06-14 15:27:31 +02001986 const char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02001987 size_t len2;
Thierry FOURNIER00543922015-03-09 18:35:06 +01001988 int skip_at_end = 0;
Willy Tarreau81389672015-03-10 12:03:52 +01001989 struct channel *oc;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001990 struct stream_interface *si;
1991 struct stream *s;
1992 struct xref *peer;
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02001993 int missing_bytes;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001994
Thierry Fournier4234dbd2020-11-28 13:18:23 +01001995 /* Get hlua struct, or NULL if we execute from main lua state */
1996 hlua = hlua_gethlua(L);
1997
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001998 /* Check if this lua stack is schedulable. */
1999 if (!hlua || !hlua->task)
2000 WILL_LJMP(luaL_error(L, "The 'receive' function is only allowed in "
2001 "'frontend', 'backend' or 'task'"));
2002
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002003 /* Check if we run on the same thread than the xreator thread.
2004 * We cannot access to the socket if the thread is different.
2005 */
2006 if (socket->tid != tid)
2007 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2008
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002009 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002010 peer = xref_get_peer_and_lock(&socket->xref);
2011 if (!peer)
2012 goto no_peer;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002013 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2014 si = appctx->owner;
2015 s = si_strm(si);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002016
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002017 oc = &s->res;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002018 if (wanted == HLSR_READ_LINE) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002019 /* Read line. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02002020 nblk = co_getline_nc(oc, &blk1, &len1, &blk2, &len2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002021 if (nblk < 0) /* Connection close. */
2022 goto connection_closed;
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002023 if (nblk == 0) /* No data available. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002024 goto connection_empty;
Thierry FOURNIER00543922015-03-09 18:35:06 +01002025
2026 /* remove final \r\n. */
2027 if (nblk == 1) {
2028 if (blk1[len1-1] == '\n') {
2029 len1--;
2030 skip_at_end++;
2031 if (blk1[len1-1] == '\r') {
2032 len1--;
2033 skip_at_end++;
2034 }
2035 }
2036 }
2037 else {
2038 if (blk2[len2-1] == '\n') {
2039 len2--;
2040 skip_at_end++;
2041 if (blk2[len2-1] == '\r') {
2042 len2--;
2043 skip_at_end++;
2044 }
2045 }
2046 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002047 }
2048
2049 else if (wanted == HLSR_READ_ALL) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002050 /* Read all the available data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02002051 nblk = co_getblk_nc(oc, &blk1, &len1, &blk2, &len2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002052 if (nblk < 0) /* Connection close. */
2053 goto connection_closed;
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002054 if (nblk == 0) /* No data available. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002055 goto connection_empty;
2056 }
2057
2058 else {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002059 /* Read a block of data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02002060 nblk = co_getblk_nc(oc, &blk1, &len1, &blk2, &len2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002061 if (nblk < 0) /* Connection close. */
2062 goto connection_closed;
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002063 if (nblk == 0) /* No data available. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002064 goto connection_empty;
2065
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02002066 missing_bytes = wanted - socket->b.n;
2067 if (len1 > missing_bytes) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002068 nblk = 1;
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02002069 len1 = missing_bytes;
2070 } if (nblk == 2 && len1 + len2 > missing_bytes)
2071 len2 = missing_bytes - len1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002072 }
2073
2074 len = len1;
2075
2076 luaL_addlstring(&socket->b, blk1, len1);
2077 if (nblk == 2) {
2078 len += len2;
2079 luaL_addlstring(&socket->b, blk2, len2);
2080 }
2081
2082 /* Consume data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02002083 co_skip(oc, len + skip_at_end);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002084
2085 /* Don't wait anything. */
Thierry FOURNIER7e4ee472018-05-25 15:03:50 +02002086 appctx_wakeup(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002087
2088 /* If the pattern reclaim to read all the data
2089 * in the connection, got out.
2090 */
2091 if (wanted == HLSR_READ_ALL)
2092 goto connection_empty;
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02002093 else if (wanted >= 0 && socket->b.n < wanted)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002094 goto connection_empty;
2095
2096 /* Return result. */
2097 luaL_pushresult(&socket->b);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002098 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002099 return 1;
2100
2101connection_closed:
2102
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002103 xref_unlock(&socket->xref, peer);
2104
2105no_peer:
2106
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002107 /* If the buffer containds data. */
2108 if (socket->b.n > 0) {
2109 luaL_pushresult(&socket->b);
2110 return 1;
2111 }
2112 lua_pushnil(L);
2113 lua_pushstring(L, "connection closed.");
2114 return 2;
2115
2116connection_empty:
2117
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002118 if (!notification_new(&hlua->com, &appctx->ctx.hlua_cosocket.wake_on_read, hlua->task)) {
2119 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002120 WILL_LJMP(luaL_error(L, "out of memory"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002121 }
2122 xref_unlock(&socket->xref, peer);
Willy Tarreau9635e032018-10-16 17:52:55 +02002123 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_receive_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002124 return 0;
2125}
2126
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002127/* This Lua function gets two parameters. The first one can be string
2128 * or a number. If the string is "*l", the user requires one line. If
2129 * the string is "*a", the user requires all the contents of the stream.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002130 * If the value is a number, the user require a number of bytes equal
2131 * to the value. The default value is "*l" (a line).
2132 *
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002133 * This parameter with a variable type is converted in integer. This
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002134 * integer takes this values:
2135 * -1 : read a line
2136 * -2 : read all the stream
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002137 * >0 : amount of bytes.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002138 *
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002139 * The second parameter is optional. It contains a string that must be
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002140 * concatenated with the read data.
2141 */
2142__LJMP static int hlua_socket_receive(struct lua_State *L)
2143{
2144 int wanted = HLSR_READ_LINE;
2145 const char *pattern;
Christopher Fauletc31b2002021-05-03 10:11:13 +02002146 int lastarg, type;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002147 char *error;
2148 size_t len;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002149 struct hlua_socket *socket;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002150
2151 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
2152 WILL_LJMP(luaL_error(L, "The 'receive' function requires between 1 and 3 arguments."));
2153
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002154 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002155
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002156 /* Check if we run on the same thread than the xreator thread.
2157 * We cannot access to the socket if the thread is different.
2158 */
2159 if (socket->tid != tid)
2160 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2161
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002162 /* check for pattern. */
2163 if (lua_gettop(L) >= 2) {
2164 type = lua_type(L, 2);
2165 if (type == LUA_TSTRING) {
2166 pattern = lua_tostring(L, 2);
2167 if (strcmp(pattern, "*a") == 0)
2168 wanted = HLSR_READ_ALL;
2169 else if (strcmp(pattern, "*l") == 0)
2170 wanted = HLSR_READ_LINE;
2171 else {
2172 wanted = strtoll(pattern, &error, 10);
2173 if (*error != '\0')
2174 WILL_LJMP(luaL_error(L, "Unsupported pattern."));
2175 }
2176 }
2177 else if (type == LUA_TNUMBER) {
2178 wanted = lua_tointeger(L, 2);
2179 if (wanted < 0)
2180 WILL_LJMP(luaL_error(L, "Unsupported size."));
2181 }
2182 }
2183
2184 /* Set pattern. */
2185 lua_pushinteger(L, wanted);
Tim Duesterhusc6e377e2018-01-04 19:32:13 +01002186
2187 /* Check if we would replace the top by itself. */
2188 if (lua_gettop(L) != 2)
2189 lua_replace(L, 2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002190
Christopher Fauletc31b2002021-05-03 10:11:13 +02002191 /* Save index of the top of the stack because since buffers are used, it
2192 * may change
2193 */
2194 lastarg = lua_gettop(L);
2195
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002196 /* init buffer, and fill it with prefix. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002197 luaL_buffinit(L, &socket->b);
2198
2199 /* Check prefix. */
Christopher Fauletc31b2002021-05-03 10:11:13 +02002200 if (lastarg >= 3) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002201 if (lua_type(L, 3) != LUA_TSTRING)
2202 WILL_LJMP(luaL_error(L, "Expect a 'string' for the prefix"));
2203 pattern = lua_tolstring(L, 3, &len);
2204 luaL_addlstring(&socket->b, pattern, len);
2205 }
2206
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002207 return __LJMP(hlua_socket_receive_yield(L, 0, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002208}
2209
2210/* Write the Lua input string in the output buffer.
Mark Lakes22154b42018-01-29 14:38:40 -08002211 * This function returns a yield if no space is available.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002212 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002213static int hlua_socket_write_yield(struct lua_State *L,int status, lua_KContext ctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002214{
2215 struct hlua_socket *socket;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002216 struct hlua *hlua;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002217 struct appctx *appctx;
2218 size_t buf_len;
2219 const char *buf;
2220 int len;
2221 int send_len;
2222 int sent;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002223 struct xref *peer;
2224 struct stream_interface *si;
2225 struct stream *s;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002226
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002227 /* Get hlua struct, or NULL if we execute from main lua state */
2228 hlua = hlua_gethlua(L);
2229
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002230 /* Check if this lua stack is schedulable. */
2231 if (!hlua || !hlua->task)
2232 WILL_LJMP(luaL_error(L, "The 'write' function is only allowed in "
2233 "'frontend', 'backend' or 'task'"));
2234
2235 /* Get object */
2236 socket = MAY_LJMP(hlua_checksocket(L, 1));
2237 buf = MAY_LJMP(luaL_checklstring(L, 2, &buf_len));
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002238 sent = MAY_LJMP(luaL_checkinteger(L, 3));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002239
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002240 /* Check if we run on the same thread than the xreator thread.
2241 * We cannot access to the socket if the thread is different.
2242 */
2243 if (socket->tid != tid)
2244 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2245
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002246 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002247 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002248 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002249 lua_pushinteger(L, -1);
2250 return 1;
2251 }
2252 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2253 si = appctx->owner;
2254 s = si_strm(si);
2255
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002256 /* Check for connection close. */
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002257 if (channel_output_closed(&s->req)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002258 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002259 lua_pushinteger(L, -1);
2260 return 1;
2261 }
2262
2263 /* Update the input buffer data. */
2264 buf += sent;
2265 send_len = buf_len - sent;
2266
2267 /* All the data are sent. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002268 if (sent >= buf_len) {
2269 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002270 return 1; /* Implicitly return the length sent. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002271 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002272
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002273 /* Check if the buffer is available because HAProxy doesn't allocate
Thierry FOURNIER486d52a2015-03-09 17:51:43 +01002274 * the request buffer if its not required.
2275 */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02002276 if (s->req.buf.size == 0) {
Willy Tarreau581abd32018-10-25 10:21:41 +02002277 if (!si_alloc_ibuf(si, &appctx->buffer_wait))
Christopher Faulet33834b12016-12-19 09:29:06 +01002278 goto hlua_socket_write_yield_return;
Thierry FOURNIER486d52a2015-03-09 17:51:43 +01002279 }
2280
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002281 /* Check for available space. */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02002282 len = b_room(&s->req.buf);
Christopher Faulet33834b12016-12-19 09:29:06 +01002283 if (len <= 0) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002284 goto hlua_socket_write_yield_return;
Christopher Faulet33834b12016-12-19 09:29:06 +01002285 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002286
2287 /* send data */
2288 if (len < send_len)
2289 send_len = len;
Thierry FOURNIER66b89192018-05-27 01:14:47 +02002290 len = ci_putblk(&s->req, buf, send_len);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002291
2292 /* "Not enough space" (-1), "Buffer too little to contain
2293 * the data" (-2) are not expected because the available length
2294 * is tested.
2295 * Other unknown error are also not expected.
2296 */
2297 if (len <= 0) {
Willy Tarreaubc18da12015-03-13 14:00:47 +01002298 if (len == -1)
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002299 s->req.flags |= CF_WAKE_WRITE;
Willy Tarreaubc18da12015-03-13 14:00:47 +01002300
sada05ed3302018-05-11 11:48:18 -07002301 MAY_LJMP(hlua_socket_close_helper(L));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002302 lua_pop(L, 1);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002303 lua_pushinteger(L, -1);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002304 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002305 return 1;
2306 }
2307
2308 /* update buffers. */
Thierry FOURNIER101b9762018-05-27 01:27:40 +02002309 appctx_wakeup(appctx);
Willy Tarreaude70fa12015-09-26 11:25:05 +02002310
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002311 s->req.rex = TICK_ETERNITY;
2312 s->res.wex = TICK_ETERNITY;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002313
2314 /* Update length sent. */
2315 lua_pop(L, 1);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002316 lua_pushinteger(L, sent + len);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002317
2318 /* All the data buffer is sent ? */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002319 if (sent + len >= buf_len) {
2320 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002321 return 1;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002322 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002323
2324hlua_socket_write_yield_return:
Thierry FOURNIERba42fcd2018-05-27 00:59:48 +02002325 if (!notification_new(&hlua->com, &appctx->ctx.hlua_cosocket.wake_on_write, hlua->task)) {
2326 xref_unlock(&socket->xref, peer);
2327 WILL_LJMP(luaL_error(L, "out of memory"));
2328 }
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002329 xref_unlock(&socket->xref, peer);
Willy Tarreau9635e032018-10-16 17:52:55 +02002330 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_write_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002331 return 0;
2332}
2333
2334/* This function initiate the send of data. It just check the input
2335 * parameters and push an integer in the Lua stack that contain the
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002336 * amount of data written to the buffer. This is used by the function
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002337 * "hlua_socket_write_yield" that can yield.
2338 *
2339 * The Lua function gets between 3 and 4 parameters. The first one is
2340 * the associated object. The second is a string buffer. The third is
2341 * a facultative integer that represents where is the buffer position
2342 * of the start of the data that can send. The first byte is the
2343 * position "1". The default value is "1". The fourth argument is a
2344 * facultative integer that represents where is the buffer position
2345 * of the end of the data that can send. The default is the last byte.
2346 */
2347static int hlua_socket_send(struct lua_State *L)
2348{
2349 int i;
2350 int j;
2351 const char *buf;
2352 size_t buf_len;
2353
2354 /* Check number of arguments. */
2355 if (lua_gettop(L) < 2 || lua_gettop(L) > 4)
2356 WILL_LJMP(luaL_error(L, "'send' needs between 2 and 4 arguments"));
2357
2358 /* Get the string. */
2359 buf = MAY_LJMP(luaL_checklstring(L, 2, &buf_len));
2360
2361 /* Get and check j. */
2362 if (lua_gettop(L) == 4) {
2363 j = MAY_LJMP(luaL_checkinteger(L, 4));
2364 if (j < 0)
2365 j = buf_len + j + 1;
2366 if (j > buf_len)
2367 j = buf_len + 1;
2368 lua_pop(L, 1);
2369 }
2370 else
2371 j = buf_len;
2372
2373 /* Get and check i. */
2374 if (lua_gettop(L) == 3) {
2375 i = MAY_LJMP(luaL_checkinteger(L, 3));
2376 if (i < 0)
2377 i = buf_len + i + 1;
2378 if (i > buf_len)
2379 i = buf_len + 1;
2380 lua_pop(L, 1);
2381 } else
2382 i = 1;
2383
2384 /* Check bth i and j. */
2385 if (i > j) {
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002386 lua_pushinteger(L, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002387 return 1;
2388 }
2389 if (i == 0 && j == 0) {
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002390 lua_pushinteger(L, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002391 return 1;
2392 }
2393 if (i == 0)
2394 i = 1;
2395 if (j == 0)
2396 j = 1;
2397
2398 /* Pop the string. */
2399 lua_pop(L, 1);
2400
2401 /* Update the buffer length. */
2402 buf += i - 1;
2403 buf_len = j - i + 1;
2404 lua_pushlstring(L, buf, buf_len);
2405
2406 /* This unsigned is used to remember the amount of sent data. */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002407 lua_pushinteger(L, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002408
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002409 return MAY_LJMP(hlua_socket_write_yield(L, 0, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002410}
2411
Willy Tarreau22b0a682015-06-17 19:43:49 +02002412#define SOCKET_INFO_MAX_LEN sizeof("[0000:0000:0000:0000:0000:0000:0000:0000]:12345")
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002413__LJMP static inline int hlua_socket_info(struct lua_State *L, struct sockaddr_storage *addr)
2414{
2415 static char buffer[SOCKET_INFO_MAX_LEN];
2416 int ret;
2417 int len;
2418 char *p;
2419
2420 ret = addr_to_str(addr, buffer+1, SOCKET_INFO_MAX_LEN-1);
2421 if (ret <= 0) {
2422 lua_pushnil(L);
2423 return 1;
2424 }
2425
2426 if (ret == AF_UNIX) {
2427 lua_pushstring(L, buffer+1);
2428 return 1;
2429 }
2430 else if (ret == AF_INET6) {
2431 buffer[0] = '[';
2432 len = strlen(buffer);
2433 buffer[len] = ']';
2434 len++;
2435 buffer[len] = ':';
2436 len++;
2437 p = buffer;
2438 }
2439 else if (ret == AF_INET) {
2440 p = buffer + 1;
2441 len = strlen(p);
2442 p[len] = ':';
2443 len++;
2444 }
2445 else {
2446 lua_pushnil(L);
2447 return 1;
2448 }
2449
2450 if (port_to_str(addr, p + len, SOCKET_INFO_MAX_LEN-1 - len) <= 0) {
2451 lua_pushnil(L);
2452 return 1;
2453 }
2454
2455 lua_pushstring(L, p);
2456 return 1;
2457}
2458
2459/* Returns information about the peer of the connection. */
2460__LJMP static int hlua_socket_getpeername(struct lua_State *L)
2461{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002462 struct hlua_socket *socket;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002463 struct xref *peer;
2464 struct appctx *appctx;
2465 struct stream_interface *si;
2466 struct stream *s;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002467 int ret;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002468
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002469 MAY_LJMP(check_args(L, 1, "getpeername"));
2470
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002471 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002472
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002473 /* Check if we run on the same thread than the xreator thread.
2474 * We cannot access to the socket if the thread is different.
2475 */
2476 if (socket->tid != tid)
2477 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2478
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002479 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002480 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002481 if (!peer) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002482 lua_pushnil(L);
2483 return 1;
2484 }
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002485 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2486 si = appctx->owner;
2487 s = si_strm(si);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002488
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002489 if (!s->target_addr) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002490 xref_unlock(&socket->xref, peer);
Willy Tarreaua71f6422016-11-16 17:00:14 +01002491 lua_pushnil(L);
2492 return 1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002493 }
2494
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002495 ret = MAY_LJMP(hlua_socket_info(L, s->target_addr));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002496 xref_unlock(&socket->xref, peer);
2497 return ret;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002498}
2499
2500/* Returns information about my connection side. */
2501static int hlua_socket_getsockname(struct lua_State *L)
2502{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002503 struct hlua_socket *socket;
2504 struct connection *conn;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002505 struct appctx *appctx;
2506 struct xref *peer;
2507 struct stream_interface *si;
2508 struct stream *s;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002509 int ret;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002510
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002511 MAY_LJMP(check_args(L, 1, "getsockname"));
2512
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002513 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002514
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002515 /* Check if we run on the same thread than the xreator thread.
2516 * We cannot access to the socket if the thread is different.
2517 */
2518 if (socket->tid != tid)
2519 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2520
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002521 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002522 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002523 if (!peer) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002524 lua_pushnil(L);
2525 return 1;
2526 }
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002527 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2528 si = appctx->owner;
2529 s = si_strm(si);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002530
Olivier Houchard9aaf7782017-09-13 18:30:23 +02002531 conn = cs_conn(objt_cs(s->si[1].end));
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002532 if (!conn || !conn_get_src(conn)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002533 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002534 lua_pushnil(L);
2535 return 1;
2536 }
2537
Willy Tarreau9da9a6f2019-07-17 14:49:44 +02002538 ret = hlua_socket_info(L, conn->src);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002539 xref_unlock(&socket->xref, peer);
2540 return ret;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002541}
2542
2543/* This struct define the applet. */
Willy Tarreau30576452015-04-13 13:50:30 +02002544static struct applet update_applet = {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002545 .obj_type = OBJ_TYPE_APPLET,
2546 .name = "<LUA_TCP>",
2547 .fct = hlua_socket_handler,
2548 .release = hlua_socket_release,
2549};
2550
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002551__LJMP static int hlua_socket_connect_yield(struct lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002552{
2553 struct hlua_socket *socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002554 struct hlua *hlua;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002555 struct xref *peer;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002556 struct appctx *appctx;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002557 struct stream_interface *si;
2558 struct stream *s;
2559
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002560 /* Get hlua struct, or NULL if we execute from main lua state */
2561 hlua = hlua_gethlua(L);
2562 if (!hlua)
2563 return 0;
2564
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002565 /* Check if we run on the same thread than the xreator thread.
2566 * We cannot access to the socket if the thread is different.
2567 */
2568 if (socket->tid != tid)
2569 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2570
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002571 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002572 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002573 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002574 lua_pushnil(L);
2575 lua_pushstring(L, "Can't connect");
2576 return 2;
2577 }
2578 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2579 si = appctx->owner;
2580 s = si_strm(si);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002581
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002582 /* Check if we run on the same thread than the xreator thread.
2583 * We cannot access to the socket if the thread is different.
2584 */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002585 if (socket->tid != tid) {
2586 xref_unlock(&socket->xref, peer);
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002587 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002588 }
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002589
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002590 /* Check for connection close. */
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002591 if (!hlua || channel_output_closed(&s->req)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002592 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002593 lua_pushnil(L);
2594 lua_pushstring(L, "Can't connect");
2595 return 2;
2596 }
2597
Willy Tarreaue09101e2018-10-16 17:37:12 +02002598 appctx = __objt_appctx(s->si[0].end);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002599
2600 /* Check for connection established. */
Thierry FOURNIER18d09902016-12-16 09:25:38 +01002601 if (appctx->ctx.hlua_cosocket.connected) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002602 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002603 lua_pushinteger(L, 1);
2604 return 1;
2605 }
2606
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002607 if (!notification_new(&hlua->com, &appctx->ctx.hlua_cosocket.wake_on_write, hlua->task)) {
2608 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002609 WILL_LJMP(luaL_error(L, "out of memory error"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002610 }
2611 xref_unlock(&socket->xref, peer);
Willy Tarreau9635e032018-10-16 17:52:55 +02002612 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_connect_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002613 return 0;
2614}
2615
2616/* This function fail or initite the connection. */
2617__LJMP static int hlua_socket_connect(struct lua_State *L)
2618{
2619 struct hlua_socket *socket;
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002620 int port = -1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002621 const char *ip;
Thierry FOURNIER95ad96a2015-03-09 18:12:40 +01002622 struct hlua *hlua;
2623 struct appctx *appctx;
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002624 int low, high;
2625 struct sockaddr_storage *addr;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002626 struct xref *peer;
2627 struct stream_interface *si;
2628 struct stream *s;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002629
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002630 if (lua_gettop(L) < 2)
2631 WILL_LJMP(luaL_error(L, "connect: need at least 2 arguments"));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002632
2633 /* Get args. */
2634 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002635
2636 /* Check if we run on the same thread than the xreator thread.
2637 * We cannot access to the socket if the thread is different.
2638 */
2639 if (socket->tid != tid)
2640 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2641
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002642 ip = MAY_LJMP(luaL_checkstring(L, 2));
Tim Duesterhus6edab862018-01-06 19:04:45 +01002643 if (lua_gettop(L) >= 3) {
2644 luaL_Buffer b;
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002645 port = MAY_LJMP(luaL_checkinteger(L, 3));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002646
Tim Duesterhus6edab862018-01-06 19:04:45 +01002647 /* Force the ip to end with a colon, to support IPv6 addresses
2648 * that are not enclosed within square brackets.
2649 */
2650 if (port > 0) {
2651 luaL_buffinit(L, &b);
2652 luaL_addstring(&b, ip);
2653 luaL_addchar(&b, ':');
2654 luaL_pushresult(&b);
2655 ip = lua_tolstring(L, lua_gettop(L), NULL);
2656 }
2657 }
2658
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002659 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002660 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002661 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002662 lua_pushnil(L);
2663 return 1;
2664 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002665
2666 /* Parse ip address. */
Willy Tarreau5fc93282020-09-16 18:25:03 +02002667 addr = str2sa_range(ip, NULL, &low, &high, NULL, NULL, NULL, NULL, NULL, PA_O_PORT_OK | PA_O_STREAM);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002668 if (!addr) {
2669 xref_unlock(&socket->xref, peer);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002670 WILL_LJMP(luaL_error(L, "connect: cannot parse destination address '%s'", ip));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002671 }
Willy Tarreau9da9a6f2019-07-17 14:49:44 +02002672
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002673 /* Set port. */
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002674 if (low == 0) {
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002675 if (addr->ss_family == AF_INET) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002676 if (port == -1) {
2677 xref_unlock(&socket->xref, peer);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002678 WILL_LJMP(luaL_error(L, "connect: port missing"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002679 }
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002680 ((struct sockaddr_in *)addr)->sin_port = htons(port);
2681 } else if (addr->ss_family == AF_INET6) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002682 if (port == -1) {
2683 xref_unlock(&socket->xref, peer);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002684 WILL_LJMP(luaL_error(L, "connect: port missing"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002685 }
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002686 ((struct sockaddr_in6 *)addr)->sin6_port = htons(port);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002687 }
2688 }
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002689
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002690 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2691 si = appctx->owner;
2692 s = si_strm(si);
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002693
Willy Tarreau9b7587a2020-10-15 07:32:10 +02002694 if (!sockaddr_alloc(&s->target_addr, addr, sizeof(*addr))) {
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002695 xref_unlock(&socket->xref, peer);
2696 WILL_LJMP(luaL_error(L, "connect: internal error"));
2697 }
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002698 s->flags |= SF_ADDR_SET;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002699
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002700 /* Get hlua struct, or NULL if we execute from main lua state */
Thierry FOURNIER95ad96a2015-03-09 18:12:40 +01002701 hlua = hlua_gethlua(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002702 if (!hlua)
2703 return 0;
Willy Tarreaubdc97a82015-08-24 15:42:28 +02002704
2705 /* inform the stream that we want to be notified whenever the
2706 * connection completes.
2707 */
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01002708 si_cant_get(&s->si[0]);
Willy Tarreau3367d412018-11-15 10:57:41 +01002709 si_rx_endp_more(&s->si[0]);
Thierry FOURNIER8c8fbbe2015-09-26 17:02:35 +02002710 appctx_wakeup(appctx);
Willy Tarreaubdc97a82015-08-24 15:42:28 +02002711
Willy Tarreauf31af932020-01-14 09:59:38 +01002712 hlua->gc_count++;
Thierry FOURNIER7c39ab42015-09-27 22:53:33 +02002713
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002714 if (!notification_new(&hlua->com, &appctx->ctx.hlua_cosocket.wake_on_write, hlua->task)) {
2715 xref_unlock(&socket->xref, peer);
Thierry FOURNIER95ad96a2015-03-09 18:12:40 +01002716 WILL_LJMP(luaL_error(L, "out of memory"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002717 }
2718 xref_unlock(&socket->xref, peer);
PiBa-NL706d5ee2018-05-05 23:51:42 +02002719
2720 task_wakeup(s->task, TASK_WOKEN_INIT);
2721 /* Return yield waiting for connection. */
2722
Willy Tarreau9635e032018-10-16 17:52:55 +02002723 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_connect_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002724
2725 return 0;
2726}
2727
Baptiste Assmann84bb4932015-03-02 21:40:06 +01002728#ifdef USE_OPENSSL
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002729__LJMP static int hlua_socket_connect_ssl(struct lua_State *L)
2730{
2731 struct hlua_socket *socket;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002732 struct xref *peer;
2733 struct appctx *appctx;
2734 struct stream_interface *si;
2735 struct stream *s;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002736
2737 MAY_LJMP(check_args(L, 3, "connect_ssl"));
2738 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002739
2740 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002741 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002742 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002743 lua_pushnil(L);
2744 return 1;
2745 }
2746 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2747 si = appctx->owner;
2748 s = si_strm(si);
2749
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +01002750 s->target = &socket_ssl->obj_type;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002751 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002752 return MAY_LJMP(hlua_socket_connect(L));
2753}
Baptiste Assmann84bb4932015-03-02 21:40:06 +01002754#endif
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002755
2756__LJMP static int hlua_socket_setoption(struct lua_State *L)
2757{
2758 return 0;
2759}
2760
2761__LJMP static int hlua_socket_settimeout(struct lua_State *L)
2762{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002763 struct hlua_socket *socket;
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002764 int tmout;
Mark Lakes56cc1252018-03-27 09:48:06 +02002765 double dtmout;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002766 struct xref *peer;
2767 struct appctx *appctx;
2768 struct stream_interface *si;
2769 struct stream *s;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002770
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002771 MAY_LJMP(check_args(L, 2, "settimeout"));
2772
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002773 socket = MAY_LJMP(hlua_checksocket(L, 1));
Mark Lakes56cc1252018-03-27 09:48:06 +02002774
Cyril Bonté7ee465f2018-08-19 22:08:50 +02002775 /* convert the timeout to millis */
2776 dtmout = MAY_LJMP(luaL_checknumber(L, 2)) * 1000;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002777
Thierry Fournier17a921b2018-03-08 09:59:02 +01002778 /* Check for negative values */
Mark Lakes56cc1252018-03-27 09:48:06 +02002779 if (dtmout < 0)
Thierry Fournier17a921b2018-03-08 09:59:02 +01002780 WILL_LJMP(luaL_error(L, "settimeout: cannot set negatives values"));
2781
Mark Lakes56cc1252018-03-27 09:48:06 +02002782 if (dtmout > INT_MAX) /* overflow check */
Cyril Bonté7ee465f2018-08-19 22:08:50 +02002783 WILL_LJMP(luaL_error(L, "settimeout: cannot set values larger than %d ms", INT_MAX));
Mark Lakes56cc1252018-03-27 09:48:06 +02002784
2785 tmout = MS_TO_TICKS((int)dtmout);
Cyril Bonté7ee465f2018-08-19 22:08:50 +02002786 if (tmout == 0)
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05002787 tmout++; /* very small timeouts are adjusted to a minimum of 1ms */
Mark Lakes56cc1252018-03-27 09:48:06 +02002788
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002789 /* Check if we run on the same thread than the xreator thread.
2790 * We cannot access to the socket if the thread is different.
2791 */
2792 if (socket->tid != tid)
2793 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2794
Mark Lakes56cc1252018-03-27 09:48:06 +02002795 /* check for connection break. If some data were read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002796 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002797 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002798 hlua_pusherror(L, "socket: not yet initialised, you can't set timeouts.");
2799 WILL_LJMP(lua_error(L));
2800 return 0;
2801 }
2802 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2803 si = appctx->owner;
2804 s = si_strm(si);
2805
Cyril Bonté7bb63452018-08-17 23:51:02 +02002806 s->sess->fe->timeout.connect = tmout;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002807 s->req.rto = tmout;
2808 s->req.wto = tmout;
2809 s->res.rto = tmout;
2810 s->res.wto = tmout;
Cyril Bonté7bb63452018-08-17 23:51:02 +02002811 s->req.rex = tick_add_ifset(now_ms, tmout);
2812 s->req.wex = tick_add_ifset(now_ms, tmout);
2813 s->res.rex = tick_add_ifset(now_ms, tmout);
2814 s->res.wex = tick_add_ifset(now_ms, tmout);
2815
2816 s->task->expire = tick_add_ifset(now_ms, tmout);
2817 task_queue(s->task);
2818
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002819 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002820
Thierry Fourniere9636f12018-03-08 09:54:32 +01002821 lua_pushinteger(L, 1);
Tim Duesterhus119a5f12018-01-06 19:16:25 +01002822 return 1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002823}
2824
2825__LJMP static int hlua_socket_new(lua_State *L)
2826{
2827 struct hlua_socket *socket;
2828 struct appctx *appctx;
Willy Tarreau15b5e142015-04-04 14:38:25 +02002829 struct session *sess;
Willy Tarreau61cf7c82015-04-06 00:48:33 +02002830 struct stream *strm;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002831
2832 /* Check stack size. */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01002833 if (!lua_checkstack(L, 3)) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002834 hlua_pusherror(L, "socket: full stack");
2835 goto out_fail_conf;
2836 }
2837
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01002838 /* Create the object: obj[0] = userdata. */
2839 lua_newtable(L);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002840 socket = MAY_LJMP(lua_newuserdata(L, sizeof(*socket)));
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01002841 lua_rawseti(L, -2, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002842 memset(socket, 0, sizeof(*socket));
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002843 socket->tid = tid;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002844
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05002845 /* Check if the various memory pools are initialized. */
Willy Tarreaubafbe012017-11-24 17:34:44 +01002846 if (!pool_head_stream || !pool_head_buffer) {
Thierry FOURNIER4a6170c2015-03-09 17:07:10 +01002847 hlua_pusherror(L, "socket: uninitialized pools.");
2848 goto out_fail_conf;
2849 }
2850
Willy Tarreau87b09662015-04-03 00:22:06 +02002851 /* Pop a class stream metatable and affect it to the userdata. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002852 lua_rawgeti(L, LUA_REGISTRYINDEX, class_socket_ref);
2853 lua_setmetatable(L, -2);
2854
Willy Tarreaud420a972015-04-06 00:39:18 +02002855 /* Create the applet context */
Willy Tarreau5f4a47b2017-10-31 15:59:32 +01002856 appctx = appctx_new(&update_applet, tid_bit);
Willy Tarreau61cf7c82015-04-06 00:48:33 +02002857 if (!appctx) {
2858 hlua_pusherror(L, "socket: out of memory");
Willy Tarreaufeb76402015-04-03 14:10:06 +02002859 goto out_fail_conf;
Willy Tarreau61cf7c82015-04-06 00:48:33 +02002860 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002861
Thierry FOURNIER18d09902016-12-16 09:25:38 +01002862 appctx->ctx.hlua_cosocket.connected = 0;
Thierry FOURNIERb13b20a2017-07-16 20:48:54 +02002863 appctx->ctx.hlua_cosocket.die = 0;
Thierry FOURNIER18d09902016-12-16 09:25:38 +01002864 LIST_INIT(&appctx->ctx.hlua_cosocket.wake_on_write);
2865 LIST_INIT(&appctx->ctx.hlua_cosocket.wake_on_read);
Willy Tarreaub2bf8332015-04-04 15:58:58 +02002866
Willy Tarreaud420a972015-04-06 00:39:18 +02002867 /* Now create a session, task and stream for this applet */
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +01002868 sess = session_new(socket_proxy, NULL, &appctx->obj_type);
Willy Tarreaud420a972015-04-06 00:39:18 +02002869 if (!sess) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002870 hlua_pusherror(L, "socket: out of memory");
Willy Tarreaud420a972015-04-06 00:39:18 +02002871 goto out_fail_sess;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002872 }
2873
Christopher Faulet26256f82020-09-14 11:40:13 +02002874 strm = stream_new(sess, &appctx->obj_type, &BUF_NULL);
Willy Tarreau61cf7c82015-04-06 00:48:33 +02002875 if (!strm) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002876 hlua_pusherror(L, "socket: out of memory");
Willy Tarreaud420a972015-04-06 00:39:18 +02002877 goto out_fail_stream;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002878 }
2879
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002880 /* Initialise cross reference between stream and Lua socket object. */
2881 xref_create(&socket->xref, &appctx->ctx.hlua_cosocket.xref);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002882
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002883 /* Configure "right" stream interface. this "si" is used to connect
2884 * and retrieve data from the server. The connection is initialized
2885 * with the "struct server".
2886 */
Willy Tarreau61cf7c82015-04-06 00:48:33 +02002887 si_set_state(&strm->si[1], SI_ST_ASS);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002888
2889 /* Force destination server. */
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002890 strm->flags |= SF_DIRECT | SF_ASSIGNED | SF_BE_ASSIGNED;
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +01002891 strm->target = &socket_tcp->obj_type;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002892
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002893 return 1;
2894
Willy Tarreaud420a972015-04-06 00:39:18 +02002895 out_fail_stream:
Willy Tarreau11c36242015-04-04 15:54:03 +02002896 session_free(sess);
Willy Tarreaud420a972015-04-06 00:39:18 +02002897 out_fail_sess:
2898 appctx_free(appctx);
2899 out_fail_conf:
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002900 WILL_LJMP(lua_error(L));
2901 return 0;
2902}
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01002903
2904/*
2905 *
2906 *
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002907 * Class Channel
2908 *
2909 *
2910 */
2911
2912/* Returns the struct hlua_channel join to the class channel in the
2913 * stack entry "ud" or throws an argument error.
2914 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01002915__LJMP static struct channel *hlua_checkchannel(lua_State *L, int ud)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002916{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02002917 return MAY_LJMP(hlua_checkudata(L, ud, class_channel_ref));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002918}
2919
Willy Tarreau47860ed2015-03-10 14:07:50 +01002920/* Pushes the channel onto the top of the stack. If the stask does not have a
2921 * free slots, the function fails and returns 0;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002922 */
Willy Tarreau2a71af42015-03-10 13:51:50 +01002923static int hlua_channel_new(lua_State *L, struct channel *channel)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002924{
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002925 /* Check stack size. */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01002926 if (!lua_checkstack(L, 3))
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002927 return 0;
2928
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01002929 lua_newtable(L);
Willy Tarreau47860ed2015-03-10 14:07:50 +01002930 lua_pushlightuserdata(L, channel);
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01002931 lua_rawseti(L, -2, 0);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002932
2933 /* Pop a class sesison metatable and affect it to the userdata. */
2934 lua_rawgeti(L, LUA_REGISTRYINDEX, class_channel_ref);
2935 lua_setmetatable(L, -2);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002936 return 1;
2937}
2938
2939/* Duplicate all the data present in the input channel and put it
2940 * in a string LUA variables. Returns -1 and push a nil value in
2941 * the stack if the channel is closed and all the data are consumed,
2942 * returns 0 if no data are available, otherwise it returns the length
Ilya Shipitsind4259502020-04-08 01:07:56 +05002943 * of the built string.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002944 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01002945static inline int _hlua_channel_dup(struct channel *chn, lua_State *L)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002946{
2947 char *blk1;
2948 char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02002949 size_t len1;
2950 size_t len2;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002951 int ret;
2952 luaL_Buffer b;
2953
Willy Tarreau06d80a92017-10-19 14:32:15 +02002954 ret = ci_getblk_nc(chn, &blk1, &len1, &blk2, &len2);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002955 if (unlikely(ret == 0))
2956 return 0;
2957
2958 if (unlikely(ret < 0)) {
2959 lua_pushnil(L);
2960 return -1;
2961 }
2962
2963 luaL_buffinit(L, &b);
2964 luaL_addlstring(&b, blk1, len1);
2965 if (unlikely(ret == 2))
2966 luaL_addlstring(&b, blk2, len2);
2967 luaL_pushresult(&b);
2968
2969 if (unlikely(ret == 2))
2970 return len1 + len2;
2971 return len1;
2972}
2973
2974/* "_hlua_channel_dup" wrapper. If no data are available, it returns
2975 * a yield. This function keep the data in the buffer.
2976 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002977__LJMP static int hlua_channel_dup_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002978{
Willy Tarreau47860ed2015-03-10 14:07:50 +01002979 struct channel *chn;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002980
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002981 chn = MAY_LJMP(hlua_checkchannel(L, 1));
2982
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01002983 if (IS_HTX_STRM(chn_strm(chn))) {
Thierry Fournier77016da2020-08-15 14:35:51 +02002984 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01002985 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02002986 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01002987
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002988 if (_hlua_channel_dup(chn, L) == 0)
Willy Tarreau9635e032018-10-16 17:52:55 +02002989 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_dup_yield, TICK_ETERNITY, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002990 return 1;
2991}
2992
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002993/* Check arguments for the function "hlua_channel_dup_yield". */
2994__LJMP static int hlua_channel_dup(lua_State *L)
2995{
2996 MAY_LJMP(check_args(L, 1, "dup"));
2997 MAY_LJMP(hlua_checkchannel(L, 1));
2998 return MAY_LJMP(hlua_channel_dup_yield(L, 0, 0));
2999}
3000
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003001/* "_hlua_channel_dup" wrapper. If no data are available, it returns
3002 * a yield. This function consumes the data in the buffer. It returns
3003 * a string containing the data or a nil pointer if no data are available
3004 * and the channel is closed.
3005 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003006__LJMP static int hlua_channel_get_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003007{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003008 struct channel *chn;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003009 int ret;
3010
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003011 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003012
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01003013 if (IS_HTX_STRM(chn_strm(chn))) {
Thierry Fournier77016da2020-08-15 14:35:51 +02003014 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01003015 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02003016 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01003017
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003018 ret = _hlua_channel_dup(chn, L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003019 if (unlikely(ret == 0))
Willy Tarreau9635e032018-10-16 17:52:55 +02003020 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_get_yield, TICK_ETERNITY, 0));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003021
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003022 if (unlikely(ret == -1))
3023 return 1;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003024
Willy Tarreauc9fa0482018-07-10 17:43:27 +02003025 b_sub(&chn->buf, ret);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003026 return 1;
3027}
3028
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003029/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003030__LJMP static int hlua_channel_get(lua_State *L)
3031{
3032 MAY_LJMP(check_args(L, 1, "get"));
3033 MAY_LJMP(hlua_checkchannel(L, 1));
3034 return MAY_LJMP(hlua_channel_get_yield(L, 0, 0));
3035}
3036
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003037/* This functions consumes and returns one line. If the channel is closed,
3038 * and the last data does not contains a final '\n', the data are returned
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003039 * without the final '\n'. When no more data are available, it returns nil
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003040 * value.
3041 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003042__LJMP static int hlua_channel_getline_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003043{
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003044 char *blk1;
3045 char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02003046 size_t len1;
3047 size_t len2;
3048 size_t len;
Willy Tarreau47860ed2015-03-10 14:07:50 +01003049 struct channel *chn;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003050 int ret;
3051 luaL_Buffer b;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003052
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003053 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3054
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01003055 if (IS_HTX_STRM(chn_strm(chn))) {
Thierry Fournier77016da2020-08-15 14:35:51 +02003056 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01003057 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02003058 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01003059
Willy Tarreau06d80a92017-10-19 14:32:15 +02003060 ret = ci_getline_nc(chn, &blk1, &len1, &blk2, &len2);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003061 if (ret == 0)
Willy Tarreau9635e032018-10-16 17:52:55 +02003062 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_getline_yield, TICK_ETERNITY, 0));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003063
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003064 if (ret == -1) {
3065 lua_pushnil(L);
3066 return 1;
3067 }
3068
3069 luaL_buffinit(L, &b);
3070 luaL_addlstring(&b, blk1, len1);
3071 len = len1;
3072 if (unlikely(ret == 2)) {
3073 luaL_addlstring(&b, blk2, len2);
3074 len += len2;
3075 }
3076 luaL_pushresult(&b);
Willy Tarreauc9fa0482018-07-10 17:43:27 +02003077 b_rep_blk(&chn->buf, ci_head(chn), ci_head(chn) + len, NULL, 0);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003078 return 1;
3079}
3080
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003081/* Check arguments for the function "hlua_channel_getline_yield". */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003082__LJMP static int hlua_channel_getline(lua_State *L)
3083{
3084 MAY_LJMP(check_args(L, 1, "getline"));
3085 MAY_LJMP(hlua_checkchannel(L, 1));
3086 return MAY_LJMP(hlua_channel_getline_yield(L, 0, 0));
3087}
3088
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003089/* This function takes a string as input, and append it at the
3090 * input side of channel. If the data is too big, but a space
3091 * is probably available after sending some data, the function
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003092 * yields. If the data is bigger than the buffer, or if the
3093 * channel is closed, it returns -1. Otherwise, it returns the
3094 * amount of data written.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003095 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003096__LJMP static int hlua_channel_append_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003097{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003098 struct channel *chn = MAY_LJMP(hlua_checkchannel(L, 1));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003099 size_t len;
3100 const char *str = MAY_LJMP(luaL_checklstring(L, 2, &len));
3101 int l = MAY_LJMP(luaL_checkinteger(L, 3));
3102 int ret;
3103 int max;
3104
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01003105 if (IS_HTX_STRM(chn_strm(chn))) {
Thierry Fournier77016da2020-08-15 14:35:51 +02003106 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01003107 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02003108 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01003109
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003110 /* Check if the buffer is available because HAProxy doesn't allocate
Christopher Fauleta73e59b2016-12-09 17:30:18 +01003111 * the request buffer if its not required.
3112 */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02003113 if (chn->buf.size == 0) {
Willy Tarreau4b962a42018-11-15 11:03:21 +01003114 si_rx_buff_blk(chn_prod(chn));
Willy Tarreau9635e032018-10-16 17:52:55 +02003115 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_append_yield, TICK_ETERNITY, 0));
Christopher Fauleta73e59b2016-12-09 17:30:18 +01003116 }
3117
Willy Tarreauc9fa0482018-07-10 17:43:27 +02003118 max = channel_recv_limit(chn) - b_data(&chn->buf);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003119 if (max > len - l)
3120 max = len - l;
3121
Willy Tarreau06d80a92017-10-19 14:32:15 +02003122 ret = ci_putblk(chn, str + l, max);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003123 if (ret == -2 || ret == -3) {
3124 lua_pushinteger(L, -1);
3125 return 1;
3126 }
Willy Tarreaubc18da12015-03-13 14:00:47 +01003127 if (ret == -1) {
3128 chn->flags |= CF_WAKE_WRITE;
Willy Tarreau9635e032018-10-16 17:52:55 +02003129 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_append_yield, TICK_ETERNITY, 0));
Willy Tarreaubc18da12015-03-13 14:00:47 +01003130 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003131 l += ret;
3132 lua_pop(L, 1);
3133 lua_pushinteger(L, l);
3134
Willy Tarreauc9fa0482018-07-10 17:43:27 +02003135 max = channel_recv_limit(chn) - b_data(&chn->buf);
Willy Tarreaua79021a2018-06-15 18:07:57 +02003136 if (max == 0 && co_data(chn) == 0) {
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003137 /* There are no space available, and the output buffer is empty.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003138 * in this case, we cannot add more data, so we cannot yield,
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003139 * we return the amount of copied data.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003140 */
3141 return 1;
3142 }
3143 if (l < len)
Willy Tarreau9635e032018-10-16 17:52:55 +02003144 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_append_yield, TICK_ETERNITY, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003145 return 1;
3146}
3147
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003148/* Just a wrapper of "hlua_channel_append_yield". It returns the length
3149 * of the written string, or -1 if the channel is closed or if the
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003150 * buffer size is too little for the data.
3151 */
3152__LJMP static int hlua_channel_append(lua_State *L)
3153{
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003154 size_t len;
3155
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003156 MAY_LJMP(check_args(L, 2, "append"));
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003157 MAY_LJMP(hlua_checkchannel(L, 1));
3158 MAY_LJMP(luaL_checklstring(L, 2, &len));
3159 MAY_LJMP(luaL_checkinteger(L, 3));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003160 lua_pushinteger(L, 0);
3161
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003162 return MAY_LJMP(hlua_channel_append_yield(L, 0, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003163}
3164
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003165/* Just a wrapper of "hlua_channel_append_yield". This wrapper starts
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003166 * his process by cleaning the buffer. The result is a replacement
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003167 * of the current data. It returns the length of the written string,
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003168 * or -1 if the channel is closed or if the buffer size is too
3169 * little for the data.
3170 */
3171__LJMP static int hlua_channel_set(lua_State *L)
3172{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003173 struct channel *chn;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003174
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003175 MAY_LJMP(check_args(L, 2, "set"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003176 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003177 lua_pushinteger(L, 0);
3178
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01003179 if (IS_HTX_STRM(chn_strm(chn))) {
Thierry Fournier77016da2020-08-15 14:35:51 +02003180 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01003181 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02003182 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01003183
Willy Tarreauc9fa0482018-07-10 17:43:27 +02003184 b_set_data(&chn->buf, co_data(chn));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003185
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003186 return MAY_LJMP(hlua_channel_append_yield(L, 0, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003187}
3188
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003189/* Append data in the output side of the buffer. This data is immediately
3190 * sent. The function returns the amount of data written. If the buffer
3191 * cannot contain the data, the function yields. The function returns -1
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003192 * if the channel is closed.
3193 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003194__LJMP static int hlua_channel_send_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003195{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003196 struct channel *chn = MAY_LJMP(hlua_checkchannel(L, 1));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003197 size_t len;
3198 const char *str = MAY_LJMP(luaL_checklstring(L, 2, &len));
3199 int l = MAY_LJMP(luaL_checkinteger(L, 3));
3200 int max;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01003201 struct hlua *hlua;
3202
3203 /* Get hlua struct, or NULL if we execute from main lua state */
3204 hlua = hlua_gethlua(L);
3205 if (!hlua) {
3206 lua_pushnil(L);
3207 return 1;
3208 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003209
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01003210 if (IS_HTX_STRM(chn_strm(chn))) {
Thierry Fournier77016da2020-08-15 14:35:51 +02003211 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01003212 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02003213 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01003214
Willy Tarreau47860ed2015-03-10 14:07:50 +01003215 if (unlikely(channel_output_closed(chn))) {
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003216 lua_pushinteger(L, -1);
3217 return 1;
3218 }
3219
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003220 /* Check if the buffer is available because HAProxy doesn't allocate
Thierry FOURNIER3e3a6082015-03-05 17:06:12 +01003221 * the request buffer if its not required.
3222 */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02003223 if (chn->buf.size == 0) {
Willy Tarreau4b962a42018-11-15 11:03:21 +01003224 si_rx_buff_blk(chn_prod(chn));
Willy Tarreau9635e032018-10-16 17:52:55 +02003225 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_send_yield, TICK_ETERNITY, 0));
Thierry FOURNIER3e3a6082015-03-05 17:06:12 +01003226 }
3227
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003228 /* The written data will be immediately sent, so we can check
3229 * the available space without taking in account the reserve.
3230 * The reserve is guaranteed for the processing of incoming
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003231 * data, because the buffer will be flushed.
3232 */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02003233 max = b_room(&chn->buf);
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003234
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003235 /* If there is no space available, and the output buffer is empty.
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003236 * in this case, we cannot add more data, so we cannot yield,
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003237 * we return the amount of copied data.
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003238 */
Willy Tarreaua79021a2018-06-15 18:07:57 +02003239 if (max == 0 && co_data(chn) == 0)
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003240 return 1;
3241
3242 /* Adjust the real required length. */
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003243 if (max > len - l)
3244 max = len - l;
3245
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003246 /* The buffer available size may be not contiguous. This test
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003247 * detects a non contiguous buffer and realign it.
3248 */
Willy Tarreau3f679992018-06-15 15:06:42 +02003249 if (ci_space_for_replace(chn) < max)
Willy Tarreau843b7cb2018-07-13 10:54:26 +02003250 channel_slow_realign(chn, trash.area);
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003251
3252 /* Copy input data in the buffer. */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02003253 max = b_rep_blk(&chn->buf, ci_head(chn), ci_head(chn), str + l, max);
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003254
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003255 /* buffer replace considers that the input part is filled.
3256 * so, I must forward these new data in the output part.
3257 */
Willy Tarreaubcbd3932018-06-06 07:13:22 +02003258 c_adv(chn, max);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003259
3260 l += max;
3261 lua_pop(L, 1);
3262 lua_pushinteger(L, l);
3263
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003264 /* If there is no space available, and the output buffer is empty.
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003265 * in this case, we cannot add more data, so we cannot yield,
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003266 * we return the amount of copied data.
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003267 */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02003268 max = b_room(&chn->buf);
Willy Tarreaua79021a2018-06-15 18:07:57 +02003269 if (max == 0 && co_data(chn) == 0)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003270 return 1;
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003271
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003272 if (l < len) {
3273 /* If we are waiting for space in the response buffer, we
3274 * must set the flag WAKERESWR. This flag required the task
3275 * wake up if any activity is detected on the response buffer.
3276 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01003277 if (chn->flags & CF_ISRESP)
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003278 HLUA_SET_WAKERESWR(hlua);
Thierry FOURNIER53e08ec2015-03-06 00:35:53 +01003279 else
3280 HLUA_SET_WAKEREQWR(hlua);
Willy Tarreau9635e032018-10-16 17:52:55 +02003281 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_send_yield, TICK_ETERNITY, 0));
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003282 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003283
3284 return 1;
3285}
3286
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003287/* Just a wrapper of "_hlua_channel_send". This wrapper permits
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003288 * yield the LUA process, and resume it without checking the
3289 * input arguments.
3290 */
3291__LJMP static int hlua_channel_send(lua_State *L)
3292{
3293 MAY_LJMP(check_args(L, 2, "send"));
3294 lua_pushinteger(L, 0);
3295
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003296 return MAY_LJMP(hlua_channel_send_yield(L, 0, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003297}
3298
3299/* This function forward and amount of butes. The data pass from
3300 * the input side of the buffer to the output side, and can be
3301 * forwarded. This function never fails.
3302 *
3303 * The Lua function takes an amount of bytes to be forwarded in
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003304 * input. It returns the number of bytes forwarded.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003305 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003306__LJMP static int hlua_channel_forward_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003307{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003308 struct channel *chn;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003309 int len;
3310 int l;
3311 int max;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01003312 struct hlua *hlua;
3313
3314 /* Get hlua struct, or NULL if we execute from main lua state */
3315 hlua = hlua_gethlua(L);
3316 if (!hlua)
3317 return 1;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003318
3319 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet3f829a42018-12-13 21:56:45 +01003320
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01003321 if (IS_HTX_STRM(chn_strm(chn))) {
Thierry Fournier77016da2020-08-15 14:35:51 +02003322 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01003323 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02003324 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01003325
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003326 len = MAY_LJMP(luaL_checkinteger(L, 2));
3327 l = MAY_LJMP(luaL_checkinteger(L, -1));
3328
3329 max = len - l;
Willy Tarreaua79021a2018-06-15 18:07:57 +02003330 if (max > ci_data(chn))
3331 max = ci_data(chn);
Willy Tarreau47860ed2015-03-10 14:07:50 +01003332 channel_forward(chn, max);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003333 l += max;
3334
3335 lua_pop(L, 1);
3336 lua_pushinteger(L, l);
3337
3338 /* Check if it miss bytes to forward. */
3339 if (l < len) {
3340 /* The the input channel or the output channel are closed, we
3341 * must return the amount of data forwarded.
3342 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01003343 if (channel_input_closed(chn) || channel_output_closed(chn))
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003344 return 1;
3345
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003346 /* If we are waiting for space data in the response buffer, we
3347 * must set the flag WAKERESWR. This flag required the task
3348 * wake up if any activity is detected on the response buffer.
3349 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01003350 if (chn->flags & CF_ISRESP)
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003351 HLUA_SET_WAKERESWR(hlua);
Thierry FOURNIER53e08ec2015-03-06 00:35:53 +01003352 else
3353 HLUA_SET_WAKEREQWR(hlua);
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003354
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003355 /* Otherwise, we can yield waiting for new data in the inpout side. */
Willy Tarreau9635e032018-10-16 17:52:55 +02003356 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_forward_yield, TICK_ETERNITY, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003357 }
3358
3359 return 1;
3360}
3361
3362/* Just check the input and prepare the stack for the previous
3363 * function "hlua_channel_forward_yield"
3364 */
3365__LJMP static int hlua_channel_forward(lua_State *L)
3366{
3367 MAY_LJMP(check_args(L, 2, "forward"));
3368 MAY_LJMP(hlua_checkchannel(L, 1));
3369 MAY_LJMP(luaL_checkinteger(L, 2));
3370
3371 lua_pushinteger(L, 0);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003372 return MAY_LJMP(hlua_channel_forward_yield(L, 0, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003373}
3374
3375/* Just returns the number of bytes available in the input
3376 * side of the buffer. This function never fails.
3377 */
3378__LJMP static int hlua_channel_get_in_len(lua_State *L)
3379{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003380 struct channel *chn;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003381
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003382 MAY_LJMP(check_args(L, 1, "get_in_len"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003383 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta3ceac12018-12-14 13:39:09 +01003384 if (IS_HTX_STRM(chn_strm(chn))) {
3385 struct htx *htx = htxbuf(&chn->buf);
3386 lua_pushinteger(L, htx->data - co_data(chn));
3387 }
3388 else
3389 lua_pushinteger(L, ci_data(chn));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003390 return 1;
3391}
3392
Thierry FOURNIER / OZON.IO65192f32016-11-07 15:28:40 +01003393/* Returns true if the channel is full. */
3394__LJMP static int hlua_channel_is_full(lua_State *L)
3395{
3396 struct channel *chn;
Thierry FOURNIER / OZON.IO65192f32016-11-07 15:28:40 +01003397
3398 MAY_LJMP(check_args(L, 1, "is_full"));
3399 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet0ec740e2020-02-26 11:59:19 +01003400 /* ignore the reserve, we are not on a producer side (ie in an
3401 * applet).
3402 */
3403 lua_pushboolean(L, channel_full(chn, 0));
Thierry FOURNIER / OZON.IO65192f32016-11-07 15:28:40 +01003404 return 1;
3405}
3406
Christopher Faulet2ac9ba22020-02-25 10:15:50 +01003407/* Returns true if the channel is the response channel. */
3408__LJMP static int hlua_channel_is_resp(lua_State *L)
3409{
3410 struct channel *chn;
3411
3412 MAY_LJMP(check_args(L, 1, "is_resp"));
3413 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3414
3415 lua_pushboolean(L, !!(chn->flags & CF_ISRESP));
3416 return 1;
3417}
3418
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003419/* Just returns the number of bytes available in the output
3420 * side of the buffer. This function never fails.
3421 */
3422__LJMP static int hlua_channel_get_out_len(lua_State *L)
3423{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003424 struct channel *chn;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003425
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003426 MAY_LJMP(check_args(L, 1, "get_out_len"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003427 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Willy Tarreaua79021a2018-06-15 18:07:57 +02003428 lua_pushinteger(L, co_data(chn));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003429 return 1;
3430}
3431
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003432/*
3433 *
3434 *
3435 * Class Fetches
3436 *
3437 *
3438 */
3439
3440/* Returns a struct hlua_session if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02003441 * a class stream, otherwise it throws an error.
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003442 */
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01003443__LJMP static struct hlua_smp *hlua_checkfetches(lua_State *L, int ud)
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003444{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02003445 return MAY_LJMP(hlua_checkudata(L, ud, class_fetches_ref));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003446}
3447
3448/* This function creates and push in the stack a fetch object according
3449 * with a current TXN.
3450 */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003451static int hlua_fetches_new(lua_State *L, struct hlua_txn *txn, unsigned int flags)
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003452{
Willy Tarreau7073c472015-04-06 11:15:40 +02003453 struct hlua_smp *hsmp;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003454
3455 /* Check stack size. */
3456 if (!lua_checkstack(L, 3))
3457 return 0;
3458
3459 /* Create the object: obj[0] = userdata.
3460 * Note that the base of the Fetches object is the
3461 * transaction object.
3462 */
3463 lua_newtable(L);
Willy Tarreau7073c472015-04-06 11:15:40 +02003464 hsmp = lua_newuserdata(L, sizeof(*hsmp));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003465 lua_rawseti(L, -2, 0);
3466
Willy Tarreau7073c472015-04-06 11:15:40 +02003467 hsmp->s = txn->s;
3468 hsmp->p = txn->p;
Thierry FOURNIERc4eebc82015-11-02 10:01:59 +01003469 hsmp->dir = txn->dir;
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003470 hsmp->flags = flags;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003471
3472 /* Pop a class sesison metatable and affect it to the userdata. */
3473 lua_rawgeti(L, LUA_REGISTRYINDEX, class_fetches_ref);
3474 lua_setmetatable(L, -2);
3475
3476 return 1;
3477}
3478
3479/* This function is an LUA binding. It is called with each sample-fetch.
3480 * It uses closure argument to store the associated sample-fetch. It
3481 * returns only one argument or throws an error. An error is thrown
3482 * only if an error is encountered during the argument parsing. If
3483 * the "sample-fetch" function fails, nil is returned.
3484 */
3485__LJMP static int hlua_run_sample_fetch(lua_State *L)
3486{
Willy Tarreaub2ccb562015-04-06 11:11:15 +02003487 struct hlua_smp *hsmp;
Willy Tarreau2ec22742015-03-10 14:27:20 +01003488 struct sample_fetch *f;
Frédéric Lécaillef874a832018-06-15 13:56:04 +02003489 struct arg args[ARGM_NBARGS + 1] = {{0}};
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003490 int i;
3491 struct sample smp;
3492
3493 /* Get closure arguments. */
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02003494 f = lua_touserdata(L, lua_upvalueindex(1));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003495
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003496 /* Get traditional arguments. */
Willy Tarreaub2ccb562015-04-06 11:11:15 +02003497 hsmp = MAY_LJMP(hlua_checkfetches(L, 1));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003498
Thierry FOURNIERca988662015-12-20 18:43:03 +01003499 /* Check execution authorization. */
3500 if (f->use & SMP_USE_HTTP_ANY &&
3501 !(hsmp->flags & HLUA_F_MAY_USE_HTTP)) {
3502 lua_pushfstring(L, "the sample-fetch '%s' needs an HTTP parser which "
3503 "is not available in Lua services", f->kw);
3504 WILL_LJMP(lua_error(L));
3505 }
3506
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003507 /* Get extra arguments. */
3508 for (i = 0; i < lua_gettop(L) - 1; i++) {
3509 if (i >= ARGM_NBARGS)
3510 break;
3511 hlua_lua2arg(L, i + 2, &args[i]);
3512 }
3513 args[i].type = ARGT_STOP;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02003514 args[i].data.str.area = NULL;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003515
3516 /* Check arguments. */
Willy Tarreaub2ccb562015-04-06 11:11:15 +02003517 MAY_LJMP(hlua_lua2arg_check(L, 2, args, f->arg_mask, hsmp->p));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003518
3519 /* Run the special args checker. */
Willy Tarreau2ec22742015-03-10 14:27:20 +01003520 if (f->val_args && !f->val_args(args, NULL)) {
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003521 lua_pushfstring(L, "error in arguments");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003522 goto error;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003523 }
3524
3525 /* Initialise the sample. */
3526 memset(&smp, 0, sizeof(smp));
3527
3528 /* Run the sample fetch process. */
Willy Tarreau1777ea62016-03-10 16:15:46 +01003529 smp_set_owner(&smp, hsmp->p, hsmp->s->sess, hsmp->s, hsmp->dir & SMP_OPT_DIR);
Thierry FOURNIER0786d052015-05-11 15:42:45 +02003530 if (!f->process(args, &smp, f->kw, f->private)) {
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003531 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01003532 lua_pushstring(L, "");
3533 else
3534 lua_pushnil(L);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003535 goto end;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003536 }
3537
3538 /* Convert the returned sample in lua value. */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003539 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01003540 hlua_smp2lua_str(L, &smp);
3541 else
3542 hlua_smp2lua(L, &smp);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003543
3544 end:
3545 for (i = 0; args[i].type != ARGT_STOP; i++) {
3546 if (args[i].type == ARGT_STR)
3547 chunk_destroy(&args[i].data.str);
Christopher Fauletfd2e9062020-08-06 11:10:57 +02003548 else if (args[i].type == ARGT_REG)
3549 regex_free(args[i].data.reg);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003550 }
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003551 return 1;
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003552
3553 error:
3554 for (i = 0; args[i].type != ARGT_STOP; i++) {
3555 if (args[i].type == ARGT_STR)
3556 chunk_destroy(&args[i].data.str);
Christopher Fauletfd2e9062020-08-06 11:10:57 +02003557 else if (args[i].type == ARGT_REG)
3558 regex_free(args[i].data.reg);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003559 }
3560 WILL_LJMP(lua_error(L));
3561 return 0; /* Never reached */
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003562}
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003563
3564/*
3565 *
3566 *
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003567 * Class Converters
3568 *
3569 *
3570 */
3571
3572/* Returns a struct hlua_session if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02003573 * a class stream, otherwise it throws an error.
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003574 */
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01003575__LJMP static struct hlua_smp *hlua_checkconverters(lua_State *L, int ud)
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003576{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02003577 return MAY_LJMP(hlua_checkudata(L, ud, class_converters_ref));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003578}
3579
3580/* This function creates and push in the stack a Converters object
3581 * according with a current TXN.
3582 */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003583static int hlua_converters_new(lua_State *L, struct hlua_txn *txn, unsigned int flags)
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003584{
Willy Tarreau7073c472015-04-06 11:15:40 +02003585 struct hlua_smp *hsmp;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003586
3587 /* Check stack size. */
3588 if (!lua_checkstack(L, 3))
3589 return 0;
3590
3591 /* Create the object: obj[0] = userdata.
3592 * Note that the base of the Converters object is the
3593 * same than the TXN object.
3594 */
3595 lua_newtable(L);
Willy Tarreau7073c472015-04-06 11:15:40 +02003596 hsmp = lua_newuserdata(L, sizeof(*hsmp));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003597 lua_rawseti(L, -2, 0);
3598
Willy Tarreau7073c472015-04-06 11:15:40 +02003599 hsmp->s = txn->s;
3600 hsmp->p = txn->p;
Thierry FOURNIERc4eebc82015-11-02 10:01:59 +01003601 hsmp->dir = txn->dir;
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003602 hsmp->flags = flags;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003603
Willy Tarreau87b09662015-04-03 00:22:06 +02003604 /* Pop a class stream metatable and affect it to the table. */
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003605 lua_rawgeti(L, LUA_REGISTRYINDEX, class_converters_ref);
3606 lua_setmetatable(L, -2);
3607
3608 return 1;
3609}
3610
3611/* This function is an LUA binding. It is called with each converter.
3612 * It uses closure argument to store the associated converter. It
3613 * returns only one argument or throws an error. An error is thrown
3614 * only if an error is encountered during the argument parsing. If
3615 * the converter function function fails, nil is returned.
3616 */
3617__LJMP static int hlua_run_sample_conv(lua_State *L)
3618{
Willy Tarreauda5f1082015-04-06 11:17:13 +02003619 struct hlua_smp *hsmp;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003620 struct sample_conv *conv;
Frédéric Lécaillef874a832018-06-15 13:56:04 +02003621 struct arg args[ARGM_NBARGS + 1] = {{0}};
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003622 int i;
3623 struct sample smp;
3624
3625 /* Get closure arguments. */
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02003626 conv = lua_touserdata(L, lua_upvalueindex(1));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003627
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003628 /* Get traditional arguments. */
Willy Tarreauda5f1082015-04-06 11:17:13 +02003629 hsmp = MAY_LJMP(hlua_checkconverters(L, 1));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003630
3631 /* Get extra arguments. */
3632 for (i = 0; i < lua_gettop(L) - 2; i++) {
3633 if (i >= ARGM_NBARGS)
3634 break;
3635 hlua_lua2arg(L, i + 3, &args[i]);
3636 }
3637 args[i].type = ARGT_STOP;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02003638 args[i].data.str.area = NULL;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003639
3640 /* Check arguments. */
Willy Tarreauda5f1082015-04-06 11:17:13 +02003641 MAY_LJMP(hlua_lua2arg_check(L, 3, args, conv->arg_mask, hsmp->p));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003642
3643 /* Run the special args checker. */
3644 if (conv->val_args && !conv->val_args(args, conv, "", 0, NULL)) {
3645 hlua_pusherror(L, "error in arguments");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003646 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003647 }
3648
3649 /* Initialise the sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01003650 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003651 if (!hlua_lua2smp(L, 2, &smp)) {
3652 hlua_pusherror(L, "error in the input argument");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003653 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003654 }
3655
Willy Tarreau1777ea62016-03-10 16:15:46 +01003656 smp_set_owner(&smp, hsmp->p, hsmp->s->sess, hsmp->s, hsmp->dir & SMP_OPT_DIR);
3657
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003658 /* Apply expected cast. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02003659 if (!sample_casts[smp.data.type][conv->in_type]) {
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003660 hlua_pusherror(L, "invalid input argument: cannot cast '%s' to '%s'",
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02003661 smp_to_type[smp.data.type], smp_to_type[conv->in_type]);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003662 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003663 }
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02003664 if (sample_casts[smp.data.type][conv->in_type] != c_none &&
3665 !sample_casts[smp.data.type][conv->in_type](&smp)) {
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003666 hlua_pusherror(L, "error during the input argument casting");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003667 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003668 }
3669
3670 /* Run the sample conversion process. */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02003671 if (!conv->process(args, &smp, conv->private)) {
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003672 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01003673 lua_pushstring(L, "");
3674 else
Willy Tarreaua678b432015-08-28 10:14:59 +02003675 lua_pushnil(L);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003676 goto end;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003677 }
3678
3679 /* Convert the returned sample in lua value. */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003680 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01003681 hlua_smp2lua_str(L, &smp);
3682 else
3683 hlua_smp2lua(L, &smp);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003684 end:
3685 for (i = 0; args[i].type != ARGT_STOP; i++) {
3686 if (args[i].type == ARGT_STR)
3687 chunk_destroy(&args[i].data.str);
Christopher Fauletfd2e9062020-08-06 11:10:57 +02003688 else if (args[i].type == ARGT_REG)
3689 regex_free(args[i].data.reg);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003690 }
Willy Tarreaua678b432015-08-28 10:14:59 +02003691 return 1;
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003692
3693 error:
3694 for (i = 0; args[i].type != ARGT_STOP; i++) {
3695 if (args[i].type == ARGT_STR)
3696 chunk_destroy(&args[i].data.str);
Christopher Fauletfd2e9062020-08-06 11:10:57 +02003697 else if (args[i].type == ARGT_REG)
3698 regex_free(args[i].data.reg);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003699 }
3700 WILL_LJMP(lua_error(L));
3701 return 0; /* Never reached */
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003702}
3703
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003704/*
3705 *
3706 *
3707 * Class AppletTCP
3708 *
3709 *
3710 */
3711
3712/* Returns a struct hlua_txn if the stack entry "ud" is
3713 * a class stream, otherwise it throws an error.
3714 */
3715__LJMP static struct hlua_appctx *hlua_checkapplet_tcp(lua_State *L, int ud)
3716{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02003717 return MAY_LJMP(hlua_checkudata(L, ud, class_applet_tcp_ref));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003718}
3719
3720/* This function creates and push in the stack an Applet object
3721 * according with a current TXN.
3722 */
3723static int hlua_applet_tcp_new(lua_State *L, struct appctx *ctx)
3724{
Willy Tarreau7e702d12021-04-28 17:59:21 +02003725 struct hlua_appctx *luactx;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003726 struct stream_interface *si = ctx->owner;
3727 struct stream *s = si_strm(si);
3728 struct proxy *p = s->be;
3729
3730 /* Check stack size. */
3731 if (!lua_checkstack(L, 3))
3732 return 0;
3733
3734 /* Create the object: obj[0] = userdata.
3735 * Note that the base of the Converters object is the
3736 * same than the TXN object.
3737 */
3738 lua_newtable(L);
Willy Tarreau7e702d12021-04-28 17:59:21 +02003739 luactx = lua_newuserdata(L, sizeof(*luactx));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003740 lua_rawseti(L, -2, 0);
Willy Tarreau7e702d12021-04-28 17:59:21 +02003741 luactx->appctx = ctx;
3742 luactx->htxn.s = s;
3743 luactx->htxn.p = p;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003744
3745 /* Create the "f" field that contains a list of fetches. */
3746 lua_pushstring(L, "f");
Willy Tarreau7e702d12021-04-28 17:59:21 +02003747 if (!hlua_fetches_new(L, &luactx->htxn, 0))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003748 return 0;
3749 lua_settable(L, -3);
3750
3751 /* Create the "sf" field that contains a list of stringsafe fetches. */
3752 lua_pushstring(L, "sf");
Willy Tarreau7e702d12021-04-28 17:59:21 +02003753 if (!hlua_fetches_new(L, &luactx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003754 return 0;
3755 lua_settable(L, -3);
3756
3757 /* Create the "c" field that contains a list of converters. */
3758 lua_pushstring(L, "c");
Willy Tarreau7e702d12021-04-28 17:59:21 +02003759 if (!hlua_converters_new(L, &luactx->htxn, 0))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003760 return 0;
3761 lua_settable(L, -3);
3762
3763 /* Create the "sc" field that contains a list of stringsafe converters. */
3764 lua_pushstring(L, "sc");
Willy Tarreau7e702d12021-04-28 17:59:21 +02003765 if (!hlua_converters_new(L, &luactx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003766 return 0;
3767 lua_settable(L, -3);
3768
3769 /* Pop a class stream metatable and affect it to the table. */
3770 lua_rawgeti(L, LUA_REGISTRYINDEX, class_applet_tcp_ref);
3771 lua_setmetatable(L, -2);
3772
3773 return 1;
3774}
3775
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003776__LJMP static int hlua_applet_tcp_set_var(lua_State *L)
3777{
Willy Tarreau7e702d12021-04-28 17:59:21 +02003778 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003779 struct stream *s;
3780 const char *name;
3781 size_t len;
3782 struct sample smp;
3783
Tim Duesterhus4e172c92020-05-19 13:49:42 +02003784 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
3785 WILL_LJMP(luaL_error(L, "'set_var' needs between 3 and 4 arguments"));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003786
3787 /* It is useles to retrieve the stream, but this function
3788 * runs only in a stream context.
3789 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02003790 luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003791 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02003792 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003793
3794 /* Converts the third argument in a sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01003795 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003796 hlua_lua2smp(L, 3, &smp);
3797
3798 /* Store the sample in a variable. */
3799 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus4e172c92020-05-19 13:49:42 +02003800
3801 if (lua_gettop(L) == 4 && lua_toboolean(L, 4))
3802 lua_pushboolean(L, vars_set_by_name_ifexist(name, len, &smp) != 0);
3803 else
3804 lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
3805
Tim Duesterhus84ebc132020-05-19 13:49:41 +02003806 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003807}
3808
3809__LJMP static int hlua_applet_tcp_unset_var(lua_State *L)
3810{
Willy Tarreau7e702d12021-04-28 17:59:21 +02003811 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003812 struct stream *s;
3813 const char *name;
3814 size_t len;
3815 struct sample smp;
3816
3817 MAY_LJMP(check_args(L, 2, "unset_var"));
3818
3819 /* It is useles to retrieve the stream, but this function
3820 * runs only in a stream context.
3821 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02003822 luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003823 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02003824 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003825
3826 /* Unset the variable. */
3827 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus84ebc132020-05-19 13:49:41 +02003828 lua_pushboolean(L, vars_unset_by_name_ifexist(name, len, &smp) != 0);
3829 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003830}
3831
3832__LJMP static int hlua_applet_tcp_get_var(lua_State *L)
3833{
Willy Tarreau7e702d12021-04-28 17:59:21 +02003834 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003835 struct stream *s;
3836 const char *name;
3837 size_t len;
3838 struct sample smp;
3839
3840 MAY_LJMP(check_args(L, 2, "get_var"));
3841
3842 /* It is useles to retrieve the stream, but this function
3843 * runs only in a stream context.
3844 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02003845 luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003846 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02003847 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01003848
3849 smp_set_owner(&smp, s->be, s->sess, s, 0);
3850 if (!vars_get_by_name(name, len, &smp)) {
3851 lua_pushnil(L);
3852 return 1;
3853 }
3854
3855 return hlua_smp2lua(L, &smp);
3856}
3857
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01003858__LJMP static int hlua_applet_tcp_set_priv(lua_State *L)
3859{
Willy Tarreau7e702d12021-04-28 17:59:21 +02003860 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
3861 struct stream *s = luactx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01003862 struct hlua *hlua;
3863
3864 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01003865 if (!s->hlua)
3866 return 0;
3867 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01003868
3869 MAY_LJMP(check_args(L, 2, "set_priv"));
3870
3871 /* Remove previous value. */
Thierry FOURNIERe068b602017-04-26 13:27:05 +02003872 luaL_unref(L, LUA_REGISTRYINDEX, hlua->Mref);
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01003873
3874 /* Get and store new value. */
3875 lua_pushvalue(L, 2); /* Copy the element 2 at the top of the stack. */
3876 hlua->Mref = luaL_ref(L, LUA_REGISTRYINDEX); /* pop the previously pushed value. */
3877
3878 return 0;
3879}
3880
3881__LJMP static int hlua_applet_tcp_get_priv(lua_State *L)
3882{
Willy Tarreau7e702d12021-04-28 17:59:21 +02003883 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
3884 struct stream *s = luactx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01003885 struct hlua *hlua;
3886
3887 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01003888 if (!s->hlua) {
3889 lua_pushnil(L);
3890 return 1;
3891 }
3892 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01003893
3894 /* Push configuration index in the stack. */
3895 lua_rawgeti(L, LUA_REGISTRYINDEX, hlua->Mref);
3896
3897 return 1;
3898}
3899
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003900/* If expected data not yet available, it returns a yield. This function
3901 * consumes the data in the buffer. It returns a string containing the
3902 * data. This string can be empty.
3903 */
3904__LJMP static int hlua_applet_tcp_getline_yield(lua_State *L, int status, lua_KContext ctx)
3905{
Willy Tarreau7e702d12021-04-28 17:59:21 +02003906 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
3907 struct stream_interface *si = luactx->appctx->owner;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003908 int ret;
Willy Tarreau206ba832018-06-14 15:27:31 +02003909 const char *blk1;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02003910 size_t len1;
Willy Tarreau206ba832018-06-14 15:27:31 +02003911 const char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02003912 size_t len2;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003913
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003914 /* Read the maximum amount of data available. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02003915 ret = co_getline_nc(si_oc(si), &blk1, &len1, &blk2, &len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003916
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003917 /* Data not yet available. return yield. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003918 if (ret == 0) {
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01003919 si_cant_get(si);
Willy Tarreau9635e032018-10-16 17:52:55 +02003920 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_getline_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003921 }
3922
3923 /* End of data: commit the total strings and return. */
3924 if (ret < 0) {
Willy Tarreau7e702d12021-04-28 17:59:21 +02003925 luaL_pushresult(&luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003926 return 1;
3927 }
3928
3929 /* Ensure that the block 2 length is usable. */
3930 if (ret == 1)
3931 len2 = 0;
3932
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07003933 /* don't check the max length read and don't check. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02003934 luaL_addlstring(&luactx->b, blk1, len1);
3935 luaL_addlstring(&luactx->b, blk2, len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003936
3937 /* Consume input channel output buffer data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02003938 co_skip(si_oc(si), len1 + len2);
Willy Tarreau7e702d12021-04-28 17:59:21 +02003939 luaL_pushresult(&luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003940 return 1;
3941}
3942
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003943/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003944__LJMP static int hlua_applet_tcp_getline(lua_State *L)
3945{
Willy Tarreau7e702d12021-04-28 17:59:21 +02003946 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003947
3948 /* Initialise the string catenation. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02003949 luaL_buffinit(L, &luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003950
3951 return MAY_LJMP(hlua_applet_tcp_getline_yield(L, 0, 0));
3952}
3953
3954/* If expected data not yet available, it returns a yield. This function
3955 * consumes the data in the buffer. It returns a string containing the
3956 * data. This string can be empty.
3957 */
3958__LJMP static int hlua_applet_tcp_recv_yield(lua_State *L, int status, lua_KContext ctx)
3959{
Willy Tarreau7e702d12021-04-28 17:59:21 +02003960 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
3961 struct stream_interface *si = luactx->appctx->owner;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02003962 size_t len = MAY_LJMP(luaL_checkinteger(L, 2));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003963 int ret;
Willy Tarreau206ba832018-06-14 15:27:31 +02003964 const char *blk1;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02003965 size_t len1;
Willy Tarreau206ba832018-06-14 15:27:31 +02003966 const char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02003967 size_t len2;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003968
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003969 /* Read the maximum amount of data available. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02003970 ret = co_getblk_nc(si_oc(si), &blk1, &len1, &blk2, &len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003971
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003972 /* Data not yet available. return yield. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003973 if (ret == 0) {
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01003974 si_cant_get(si);
Willy Tarreau9635e032018-10-16 17:52:55 +02003975 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003976 }
3977
3978 /* End of data: commit the total strings and return. */
3979 if (ret < 0) {
Willy Tarreau7e702d12021-04-28 17:59:21 +02003980 luaL_pushresult(&luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003981 return 1;
3982 }
3983
3984 /* Ensure that the block 2 length is usable. */
3985 if (ret == 1)
3986 len2 = 0;
3987
3988 if (len == -1) {
3989
3990 /* If len == -1, catenate all the data avalaile and
3991 * yield because we want to get all the data until
3992 * the end of data stream.
3993 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02003994 luaL_addlstring(&luactx->b, blk1, len1);
3995 luaL_addlstring(&luactx->b, blk2, len2);
Willy Tarreau06d80a92017-10-19 14:32:15 +02003996 co_skip(si_oc(si), len1 + len2);
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01003997 si_cant_get(si);
Willy Tarreau9635e032018-10-16 17:52:55 +02003998 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003999
4000 } else {
4001
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05004002 /* Copy the first block caping to the length required. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004003 if (len1 > len)
4004 len1 = len;
Willy Tarreau7e702d12021-04-28 17:59:21 +02004005 luaL_addlstring(&luactx->b, blk1, len1);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004006 len -= len1;
4007
4008 /* Copy the second block. */
4009 if (len2 > len)
4010 len2 = len;
Willy Tarreau7e702d12021-04-28 17:59:21 +02004011 luaL_addlstring(&luactx->b, blk2, len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004012 len -= len2;
4013
4014 /* Consume input channel output buffer data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02004015 co_skip(si_oc(si), len1 + len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004016
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004017 /* If there is no other data available, yield waiting for new data. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004018 if (len > 0) {
4019 lua_pushinteger(L, len);
4020 lua_replace(L, 2);
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01004021 si_cant_get(si);
Willy Tarreau9635e032018-10-16 17:52:55 +02004022 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004023 }
4024
4025 /* return the result. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004026 luaL_pushresult(&luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004027 return 1;
4028 }
4029
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004030 /* we never execute this */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004031 hlua_pusherror(L, "Lua: internal error");
4032 WILL_LJMP(lua_error(L));
4033 return 0;
4034}
4035
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004036/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004037__LJMP static int hlua_applet_tcp_recv(lua_State *L)
4038{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004039 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004040 int len = -1;
4041
4042 if (lua_gettop(L) > 2)
4043 WILL_LJMP(luaL_error(L, "The 'recv' function requires between 1 and 2 arguments."));
4044 if (lua_gettop(L) >= 2) {
4045 len = MAY_LJMP(luaL_checkinteger(L, 2));
4046 lua_pop(L, 1);
4047 }
4048
4049 /* Confirm or set the required length */
4050 lua_pushinteger(L, len);
4051
4052 /* Initialise the string catenation. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004053 luaL_buffinit(L, &luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004054
4055 return MAY_LJMP(hlua_applet_tcp_recv_yield(L, 0, 0));
4056}
4057
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004058/* Append data in the output side of the buffer. This data is immediately
4059 * sent. The function returns the amount of data written. If the buffer
4060 * cannot contain the data, the function yields. The function returns -1
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004061 * if the channel is closed.
4062 */
4063__LJMP static int hlua_applet_tcp_send_yield(lua_State *L, int status, lua_KContext ctx)
4064{
4065 size_t len;
Willy Tarreau7e702d12021-04-28 17:59:21 +02004066 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004067 const char *str = MAY_LJMP(luaL_checklstring(L, 2, &len));
4068 int l = MAY_LJMP(luaL_checkinteger(L, 3));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004069 struct stream_interface *si = luactx->appctx->owner;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004070 struct channel *chn = si_ic(si);
4071 int max;
4072
4073 /* Get the max amount of data which can write as input in the channel. */
4074 max = channel_recv_max(chn);
4075 if (max > (len - l))
4076 max = len - l;
4077
4078 /* Copy data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02004079 ci_putblk(chn, str + l, max);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004080
4081 /* update counters. */
4082 l += max;
4083 lua_pop(L, 1);
4084 lua_pushinteger(L, l);
4085
4086 /* If some data is not send, declares the situation to the
4087 * applet, and returns a yield.
4088 */
4089 if (l < len) {
Willy Tarreaudb398432018-11-15 11:08:52 +01004090 si_rx_room_blk(si);
Willy Tarreau9635e032018-10-16 17:52:55 +02004091 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_send_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004092 }
4093
4094 return 1;
4095}
4096
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05004097/* Just a wrapper of "hlua_applet_tcp_send_yield". This wrapper permits
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004098 * yield the LUA process, and resume it without checking the
4099 * input arguments.
4100 */
4101__LJMP static int hlua_applet_tcp_send(lua_State *L)
4102{
4103 MAY_LJMP(check_args(L, 2, "send"));
4104 lua_pushinteger(L, 0);
4105
4106 return MAY_LJMP(hlua_applet_tcp_send_yield(L, 0, 0));
4107}
4108
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004109/*
4110 *
4111 *
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004112 * Class AppletHTTP
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004113 *
4114 *
4115 */
4116
4117/* Returns a struct hlua_txn if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02004118 * a class stream, otherwise it throws an error.
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004119 */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004120__LJMP static struct hlua_appctx *hlua_checkapplet_http(lua_State *L, int ud)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004121{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02004122 return MAY_LJMP(hlua_checkudata(L, ud, class_applet_http_ref));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004123}
4124
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004125/* This function creates and push in the stack an Applet object
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004126 * according with a current TXN.
4127 */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004128static int hlua_applet_http_new(lua_State *L, struct appctx *ctx)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004129{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004130 struct hlua_appctx *luactx;
Thierry FOURNIER841475e2015-12-11 17:10:09 +01004131 struct hlua_txn htxn;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004132 struct stream_interface *si = ctx->owner;
4133 struct stream *s = si_strm(si);
4134 struct proxy *px = s->be;
Christopher Fauleta2097962019-07-15 16:25:33 +02004135 struct htx *htx;
4136 struct htx_blk *blk;
4137 struct htx_sl *sl;
4138 struct ist path;
4139 unsigned long long len = 0;
4140 int32_t pos;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004141
4142 /* Check stack size. */
4143 if (!lua_checkstack(L, 3))
4144 return 0;
4145
4146 /* Create the object: obj[0] = userdata.
4147 * Note that the base of the Converters object is the
4148 * same than the TXN object.
4149 */
4150 lua_newtable(L);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004151 luactx = lua_newuserdata(L, sizeof(*luactx));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004152 lua_rawseti(L, -2, 0);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004153 luactx->appctx = ctx;
4154 luactx->appctx->ctx.hlua_apphttp.status = 200; /* Default status code returned. */
4155 luactx->appctx->ctx.hlua_apphttp.reason = NULL; /* Use default reason based on status */
4156 luactx->htxn.s = s;
4157 luactx->htxn.p = px;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004158
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004159 /* Create the "f" field that contains a list of fetches. */
4160 lua_pushstring(L, "f");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004161 if (!hlua_fetches_new(L, &luactx->htxn, 0))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004162 return 0;
4163 lua_settable(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004164
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004165 /* Create the "sf" field that contains a list of stringsafe fetches. */
4166 lua_pushstring(L, "sf");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004167 if (!hlua_fetches_new(L, &luactx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004168 return 0;
4169 lua_settable(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004170
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004171 /* Create the "c" field that contains a list of converters. */
4172 lua_pushstring(L, "c");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004173 if (!hlua_converters_new(L, &luactx->htxn, 0))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004174 return 0;
4175 lua_settable(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004176
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004177 /* Create the "sc" field that contains a list of stringsafe converters. */
4178 lua_pushstring(L, "sc");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004179 if (!hlua_converters_new(L, &luactx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004180 return 0;
4181 lua_settable(L, -3);
Willy Tarreaueee5b512015-04-03 23:46:31 +02004182
Christopher Fauleta2097962019-07-15 16:25:33 +02004183 htx = htxbuf(&s->req.buf);
4184 blk = htx_get_first_blk(htx);
Christopher Fauletea009732019-11-18 15:50:25 +01004185 BUG_ON(!blk || htx_get_blk_type(blk) != HTX_BLK_REQ_SL);
Christopher Fauleta2097962019-07-15 16:25:33 +02004186 sl = htx_get_blk_ptr(htx, blk);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004187
Christopher Fauleta2097962019-07-15 16:25:33 +02004188 /* Stores the request method. */
4189 lua_pushstring(L, "method");
4190 lua_pushlstring(L, HTX_SL_REQ_MPTR(sl), HTX_SL_REQ_MLEN(sl));
4191 lua_settable(L, -3);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004192
Christopher Fauleta2097962019-07-15 16:25:33 +02004193 /* Stores the http version. */
4194 lua_pushstring(L, "version");
4195 lua_pushlstring(L, HTX_SL_REQ_VPTR(sl), HTX_SL_REQ_VLEN(sl));
4196 lua_settable(L, -3);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004197
Christopher Fauleta2097962019-07-15 16:25:33 +02004198 /* creates an array of headers. hlua_http_get_headers() crates and push
4199 * the array on the top of the stack.
4200 */
4201 lua_pushstring(L, "headers");
4202 htxn.s = s;
4203 htxn.p = px;
4204 htxn.dir = SMP_OPT_DIR_REQ;
Christopher Faulet9d1332b2020-02-24 16:46:16 +01004205 if (!hlua_http_get_headers(L, &htxn.s->txn->req))
Christopher Fauleta2097962019-07-15 16:25:33 +02004206 return 0;
4207 lua_settable(L, -3);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004208
Christopher Fauleta2097962019-07-15 16:25:33 +02004209 path = http_get_path(htx_sl_req_uri(sl));
Tim Duesterhused526372020-03-05 17:56:33 +01004210 if (isttest(path)) {
Christopher Fauleta2097962019-07-15 16:25:33 +02004211 char *p, *q, *end;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004212
Christopher Fauleta2097962019-07-15 16:25:33 +02004213 p = path.ptr;
4214 end = path.ptr + path.len;
4215 q = p;
4216 while (q < end && *q != '?')
4217 q++;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004218
Thierry FOURNIER7d388632017-02-22 02:06:16 +01004219 /* Stores the request path. */
Christopher Fauleta2097962019-07-15 16:25:33 +02004220 lua_pushstring(L, "path");
4221 lua_pushlstring(L, p, q - p);
Thierry FOURNIER7d388632017-02-22 02:06:16 +01004222 lua_settable(L, -3);
Thierry FOURNIER04c57b32015-03-18 13:43:10 +01004223
Christopher Fauleta2097962019-07-15 16:25:33 +02004224 /* Stores the query string. */
4225 lua_pushstring(L, "qs");
4226 if (*q == '?')
4227 q++;
4228 lua_pushlstring(L, q, end - q);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004229 lua_settable(L, -3);
Christopher Fauleta2097962019-07-15 16:25:33 +02004230 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004231
Christopher Fauleta2097962019-07-15 16:25:33 +02004232 for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
4233 struct htx_blk *blk = htx_get_blk(htx, pos);
4234 enum htx_blk_type type = htx_get_blk_type(blk);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004235
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01004236 if (type == HTX_BLK_TLR || type == HTX_BLK_EOT)
Christopher Fauleta2097962019-07-15 16:25:33 +02004237 break;
4238 if (type == HTX_BLK_DATA)
4239 len += htx_get_blksz(blk);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004240 }
Christopher Fauleta2097962019-07-15 16:25:33 +02004241 if (htx->extra != ULLONG_MAX)
4242 len += htx->extra;
4243
4244 /* Stores the request path. */
4245 lua_pushstring(L, "length");
4246 lua_pushinteger(L, len);
4247 lua_settable(L, -3);
Thierry FOURNIER04c57b32015-03-18 13:43:10 +01004248
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004249 /* Create an empty array of HTTP request headers. */
4250 lua_pushstring(L, "response");
4251 lua_newtable(L);
4252 lua_settable(L, -3);
Thierry FOURNIER04c57b32015-03-18 13:43:10 +01004253
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004254 /* Pop a class stream metatable and affect it to the table. */
4255 lua_rawgeti(L, LUA_REGISTRYINDEX, class_applet_http_ref);
4256 lua_setmetatable(L, -2);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004257
4258 return 1;
4259}
4260
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004261__LJMP static int hlua_applet_http_set_var(lua_State *L)
4262{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004263 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004264 struct stream *s;
4265 const char *name;
4266 size_t len;
4267 struct sample smp;
4268
Tim Duesterhus4e172c92020-05-19 13:49:42 +02004269 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
4270 WILL_LJMP(luaL_error(L, "'set_var' needs between 3 and 4 arguments"));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004271
4272 /* It is useles to retrieve the stream, but this function
4273 * runs only in a stream context.
4274 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004275 luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004276 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004277 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004278
4279 /* Converts the third argument in a sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01004280 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004281 hlua_lua2smp(L, 3, &smp);
4282
4283 /* Store the sample in a variable. */
4284 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus4e172c92020-05-19 13:49:42 +02004285
4286 if (lua_gettop(L) == 4 && lua_toboolean(L, 4))
4287 lua_pushboolean(L, vars_set_by_name_ifexist(name, len, &smp) != 0);
4288 else
4289 lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
4290
Tim Duesterhus84ebc132020-05-19 13:49:41 +02004291 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004292}
4293
4294__LJMP static int hlua_applet_http_unset_var(lua_State *L)
4295{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004296 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004297 struct stream *s;
4298 const char *name;
4299 size_t len;
4300 struct sample smp;
4301
4302 MAY_LJMP(check_args(L, 2, "unset_var"));
4303
4304 /* It is useles to retrieve the stream, but this function
4305 * runs only in a stream context.
4306 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004307 luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004308 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004309 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004310
4311 /* Unset the variable. */
4312 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus84ebc132020-05-19 13:49:41 +02004313 lua_pushboolean(L, vars_unset_by_name_ifexist(name, len, &smp) != 0);
4314 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004315}
4316
4317__LJMP static int hlua_applet_http_get_var(lua_State *L)
4318{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004319 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004320 struct stream *s;
4321 const char *name;
4322 size_t len;
4323 struct sample smp;
4324
4325 MAY_LJMP(check_args(L, 2, "get_var"));
4326
4327 /* It is useles to retrieve the stream, but this function
4328 * runs only in a stream context.
4329 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004330 luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004331 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004332 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004333
4334 smp_set_owner(&smp, s->be, s->sess, s, 0);
4335 if (!vars_get_by_name(name, len, &smp)) {
4336 lua_pushnil(L);
4337 return 1;
4338 }
4339
4340 return hlua_smp2lua(L, &smp);
4341}
4342
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004343__LJMP static int hlua_applet_http_set_priv(lua_State *L)
4344{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004345 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4346 struct stream *s = luactx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01004347 struct hlua *hlua;
4348
4349 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01004350 if (!s->hlua)
4351 return 0;
4352 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004353
4354 MAY_LJMP(check_args(L, 2, "set_priv"));
4355
4356 /* Remove previous value. */
Thierry FOURNIERe068b602017-04-26 13:27:05 +02004357 luaL_unref(L, LUA_REGISTRYINDEX, hlua->Mref);
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004358
4359 /* Get and store new value. */
4360 lua_pushvalue(L, 2); /* Copy the element 2 at the top of the stack. */
4361 hlua->Mref = luaL_ref(L, LUA_REGISTRYINDEX); /* pop the previously pushed value. */
4362
4363 return 0;
4364}
4365
4366__LJMP static int hlua_applet_http_get_priv(lua_State *L)
4367{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004368 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4369 struct stream *s = luactx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01004370 struct hlua *hlua;
4371
4372 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01004373 if (!s->hlua) {
4374 lua_pushnil(L);
4375 return 1;
4376 }
4377 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004378
4379 /* Push configuration index in the stack. */
4380 lua_rawgeti(L, LUA_REGISTRYINDEX, hlua->Mref);
4381
4382 return 1;
4383}
4384
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004385/* If expected data not yet available, it returns a yield. This function
4386 * consumes the data in the buffer. It returns a string containing the
4387 * data. This string can be empty.
4388 */
Christopher Fauleta2097962019-07-15 16:25:33 +02004389__LJMP static int hlua_applet_http_getline_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004390{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004391 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4392 struct stream_interface *si = luactx->appctx->owner;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004393 struct channel *req = si_oc(si);
4394 struct htx *htx;
4395 struct htx_blk *blk;
4396 size_t count;
4397 int stop = 0;
4398
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004399 htx = htx_from_buf(&req->buf);
4400 count = co_data(req);
Christopher Fauleta3f15502019-05-13 15:27:23 +02004401 blk = htx_get_first_blk(htx);
Christopher Fauletcc26b132018-12-18 21:20:57 +01004402
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004403 while (count && !stop && blk) {
4404 enum htx_blk_type type = htx_get_blk_type(blk);
4405 uint32_t sz = htx_get_blksz(blk);
4406 struct ist v;
4407 uint32_t vlen;
4408 char *nl;
4409
4410 vlen = sz;
4411 if (vlen > count) {
4412 if (type != HTX_BLK_DATA)
4413 break;
4414 vlen = count;
4415 }
4416
4417 switch (type) {
4418 case HTX_BLK_UNUSED:
4419 break;
4420
4421 case HTX_BLK_DATA:
4422 v = htx_get_blk_value(htx, blk);
4423 v.len = vlen;
4424 nl = istchr(v, '\n');
4425 if (nl != NULL) {
4426 stop = 1;
4427 vlen = nl - v.ptr + 1;
4428 }
Willy Tarreau7e702d12021-04-28 17:59:21 +02004429 luaL_addlstring(&luactx->b, v.ptr, vlen);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004430 break;
4431
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004432 case HTX_BLK_TLR:
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01004433 case HTX_BLK_EOT:
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004434 stop = 1;
4435 break;
4436
4437 default:
4438 break;
4439 }
4440
4441 co_set_data(req, co_data(req) - vlen);
4442 count -= vlen;
4443 if (sz == vlen)
4444 blk = htx_remove_blk(htx, blk);
4445 else {
4446 htx_cut_data_blk(htx, blk, vlen);
4447 break;
4448 }
4449 }
4450
Christopher Fauleteccb31c2021-04-02 14:24:56 +02004451 /* The message was fully consumed and no more data are expected
4452 * (EOM flag set).
4453 */
4454 if (htx_is_empty(htx) && (htx->flags & HTX_FL_EOM))
4455 stop = 1;
4456
Christopher Faulet0ae79d02019-02-27 21:36:59 +01004457 htx_to_buf(htx, &req->buf);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004458 if (!stop) {
4459 si_cant_get(si);
Christopher Fauleta2097962019-07-15 16:25:33 +02004460 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_getline_yield, TICK_ETERNITY, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004461 }
4462
4463 /* return the result. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004464 luaL_pushresult(&luactx->b);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004465 return 1;
4466}
4467
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004468
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004469/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004470__LJMP static int hlua_applet_http_getline(lua_State *L)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004471{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004472 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004473
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004474 /* Initialise the string catenation. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004475 luaL_buffinit(L, &luactx->b);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004476
Christopher Fauleta2097962019-07-15 16:25:33 +02004477 return MAY_LJMP(hlua_applet_http_getline_yield(L, 0, 0));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004478}
4479
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004480/* If expected data not yet available, it returns a yield. This function
4481 * consumes the data in the buffer. It returns a string containing the
4482 * data. This string can be empty.
4483 */
Christopher Fauleta2097962019-07-15 16:25:33 +02004484__LJMP static int hlua_applet_http_recv_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004485{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004486 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4487 struct stream_interface *si = luactx->appctx->owner;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004488 struct channel *req = si_oc(si);
4489 struct htx *htx;
4490 struct htx_blk *blk;
4491 size_t count;
4492 int len;
4493
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004494 htx = htx_from_buf(&req->buf);
4495 len = MAY_LJMP(luaL_checkinteger(L, 2));
4496 count = co_data(req);
Christopher Faulet29f17582019-05-23 11:03:26 +02004497 blk = htx_get_head_blk(htx);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004498 while (count && len && blk) {
4499 enum htx_blk_type type = htx_get_blk_type(blk);
4500 uint32_t sz = htx_get_blksz(blk);
4501 struct ist v;
4502 uint32_t vlen;
4503
4504 vlen = sz;
4505 if (len > 0 && vlen > len)
4506 vlen = len;
4507 if (vlen > count) {
4508 if (type != HTX_BLK_DATA)
4509 break;
4510 vlen = count;
4511 }
4512
4513 switch (type) {
4514 case HTX_BLK_UNUSED:
4515 break;
4516
4517 case HTX_BLK_DATA:
4518 v = htx_get_blk_value(htx, blk);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004519 luaL_addlstring(&luactx->b, v.ptr, vlen);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004520 break;
4521
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004522 case HTX_BLK_TLR:
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01004523 case HTX_BLK_EOT:
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004524 len = 0;
4525 break;
4526
4527 default:
4528 break;
4529 }
4530
4531 co_set_data(req, co_data(req) - vlen);
4532 count -= vlen;
4533 if (len > 0)
4534 len -= vlen;
4535 if (sz == vlen)
4536 blk = htx_remove_blk(htx, blk);
4537 else {
4538 htx_cut_data_blk(htx, blk, vlen);
4539 break;
4540 }
4541 }
4542
Christopher Fauleteccb31c2021-04-02 14:24:56 +02004543 /* The message was fully consumed and no more data are expected
4544 * (EOM flag set).
4545 */
4546 if (htx_is_empty(htx) && (htx->flags & HTX_FL_EOM))
4547 len = 0;
4548
Christopher Faulet0ae79d02019-02-27 21:36:59 +01004549 htx_to_buf(htx, &req->buf);
4550
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004551 /* If we are no other data available, yield waiting for new data. */
4552 if (len) {
4553 if (len > 0) {
4554 lua_pushinteger(L, len);
4555 lua_replace(L, 2);
4556 }
4557 si_cant_get(si);
Willy Tarreau9635e032018-10-16 17:52:55 +02004558 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004559 }
4560
4561 /* return the result. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004562 luaL_pushresult(&luactx->b);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004563 return 1;
4564}
4565
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004566/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004567__LJMP static int hlua_applet_http_recv(lua_State *L)
4568{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004569 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004570 int len = -1;
4571
4572 /* Check arguments. */
4573 if (lua_gettop(L) > 2)
4574 WILL_LJMP(luaL_error(L, "The 'recv' function requires between 1 and 2 arguments."));
4575 if (lua_gettop(L) >= 2) {
4576 len = MAY_LJMP(luaL_checkinteger(L, 2));
4577 lua_pop(L, 1);
4578 }
4579
Christopher Fauleta2097962019-07-15 16:25:33 +02004580 lua_pushinteger(L, len);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004581
Christopher Fauleta2097962019-07-15 16:25:33 +02004582 /* Initialise the string catenation. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004583 luaL_buffinit(L, &luactx->b);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004584
Christopher Fauleta2097962019-07-15 16:25:33 +02004585 return MAY_LJMP(hlua_applet_http_recv_yield(L, 0, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004586}
4587
4588/* Append data in the output side of the buffer. This data is immediately
4589 * sent. The function returns the amount of data written. If the buffer
4590 * cannot contain the data, the function yields. The function returns -1
4591 * if the channel is closed.
4592 */
Christopher Fauleta2097962019-07-15 16:25:33 +02004593__LJMP static int hlua_applet_http_send_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004594{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004595 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4596 struct stream_interface *si = luactx->appctx->owner;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004597 struct channel *res = si_ic(si);
4598 struct htx *htx = htx_from_buf(&res->buf);
4599 const char *data;
4600 size_t len;
4601 int l = MAY_LJMP(luaL_checkinteger(L, 3));
4602 int max;
4603
Christopher Faulet9060fc02019-07-03 11:39:30 +02004604 max = htx_get_max_blksz(htx, channel_htx_recv_max(res, htx));
Christopher Faulet4b0e9b22019-01-09 12:16:58 +01004605 if (!max)
4606 goto snd_yield;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004607
4608 data = MAY_LJMP(luaL_checklstring(L, 2, &len));
4609
4610 /* Get the max amount of data which can write as input in the channel. */
4611 if (max > (len - l))
4612 max = len - l;
4613
4614 /* Copy data. */
Willy Tarreau0a7ef022019-05-28 10:30:11 +02004615 max = htx_add_data(htx, ist2(data + l, max));
Christopher Fauletf6cce3f2019-02-27 21:20:09 +01004616 channel_add_input(res, max);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004617
4618 /* update counters. */
4619 l += max;
4620 lua_pop(L, 1);
4621 lua_pushinteger(L, l);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004622
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004623 /* If some data is not send, declares the situation to the
4624 * applet, and returns a yield.
4625 */
4626 if (l < len) {
Christopher Faulet4b0e9b22019-01-09 12:16:58 +01004627 snd_yield:
Christopher Faulet0ae79d02019-02-27 21:36:59 +01004628 htx_to_buf(htx, &res->buf);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004629 si_rx_room_blk(si);
Willy Tarreau9635e032018-10-16 17:52:55 +02004630 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_send_yield, TICK_ETERNITY, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004631 }
4632
Christopher Fauleta2097962019-07-15 16:25:33 +02004633 htx_to_buf(htx, &res->buf);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004634 return 1;
4635}
4636
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05004637/* Just a wrapper of "hlua_applet_send_yield". This wrapper permits
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004638 * yield the LUA process, and resume it without checking the
4639 * input arguments.
4640 */
4641__LJMP static int hlua_applet_http_send(lua_State *L)
4642{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004643 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004644
4645 /* We want to send some data. Headers must be sent. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004646 if (!(luactx->appctx->ctx.hlua_apphttp.flags & APPLET_HDR_SENT)) {
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004647 hlua_pusherror(L, "Lua: 'send' you must call start_response() before sending data.");
4648 WILL_LJMP(lua_error(L));
4649 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004650
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05004651 /* This integer is used for followinf the amount of data sent. */
Christopher Fauleta2097962019-07-15 16:25:33 +02004652 lua_pushinteger(L, 0);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004653
Christopher Fauleta2097962019-07-15 16:25:33 +02004654 return MAY_LJMP(hlua_applet_http_send_yield(L, 0, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004655}
4656
4657__LJMP static int hlua_applet_http_addheader(lua_State *L)
4658{
4659 const char *name;
4660 int ret;
4661
4662 MAY_LJMP(hlua_checkapplet_http(L, 1));
4663 name = MAY_LJMP(luaL_checkstring(L, 2));
4664 MAY_LJMP(luaL_checkstring(L, 3));
4665
4666 /* Push in the stack the "response" entry. */
4667 ret = lua_getfield(L, 1, "response");
4668 if (ret != LUA_TTABLE) {
4669 hlua_pusherror(L, "Lua: 'add_header' internal error: AppletHTTP['response'] "
4670 "is expected as an array. %s found", lua_typename(L, ret));
4671 WILL_LJMP(lua_error(L));
4672 }
4673
4674 /* check if the header is already registered if it is not
4675 * the case, register it.
4676 */
4677 ret = lua_getfield(L, -1, name);
4678 if (ret == LUA_TNIL) {
4679
4680 /* Entry not found. */
4681 lua_pop(L, 1); /* remove the nil. The "response" table is the top of the stack. */
4682
4683 /* Insert the new header name in the array in the top of the stack.
4684 * It left the new array in the top of the stack.
4685 */
4686 lua_newtable(L);
4687 lua_pushvalue(L, 2);
4688 lua_pushvalue(L, -2);
4689 lua_settable(L, -4);
4690
4691 } else if (ret != LUA_TTABLE) {
4692
4693 /* corruption error. */
4694 hlua_pusherror(L, "Lua: 'add_header' internal error: AppletHTTP['response']['%s'] "
4695 "is expected as an array. %s found", name, lua_typename(L, ret));
4696 WILL_LJMP(lua_error(L));
4697 }
4698
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07004699 /* Now the top of thestack is an array of values. We push
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004700 * the header value as new entry.
4701 */
4702 lua_pushvalue(L, 3);
4703 ret = lua_rawlen(L, -2);
4704 lua_rawseti(L, -2, ret + 1);
4705 lua_pushboolean(L, 1);
4706 return 1;
4707}
4708
4709__LJMP static int hlua_applet_http_status(lua_State *L)
4710{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004711 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004712 int status = MAY_LJMP(luaL_checkinteger(L, 2));
Robin H. Johnson52f5db22017-01-01 13:10:52 -08004713 const char *reason = MAY_LJMP(luaL_optlstring(L, 3, NULL, NULL));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004714
4715 if (status < 100 || status > 599) {
4716 lua_pushboolean(L, 0);
4717 return 1;
4718 }
4719
Willy Tarreau7e702d12021-04-28 17:59:21 +02004720 luactx->appctx->ctx.hlua_apphttp.status = status;
4721 luactx->appctx->ctx.hlua_apphttp.reason = reason;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004722 lua_pushboolean(L, 1);
4723 return 1;
4724}
4725
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004726
Christopher Fauleta2097962019-07-15 16:25:33 +02004727__LJMP static int hlua_applet_http_send_response(lua_State *L)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004728{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004729 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4730 struct stream_interface *si = luactx->appctx->owner;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004731 struct channel *res = si_ic(si);
4732 struct htx *htx;
4733 struct htx_sl *sl;
4734 struct h1m h1m;
4735 const char *status, *reason;
4736 const char *name, *value;
4737 size_t nlen, vlen;
4738 unsigned int flags;
4739
4740 /* Send the message at once. */
4741 htx = htx_from_buf(&res->buf);
4742 h1m_init_res(&h1m);
4743
4744 /* Use the same http version than the request. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004745 status = ultoa_r(luactx->appctx->ctx.hlua_apphttp.status, trash.area, trash.size);
4746 reason = luactx->appctx->ctx.hlua_apphttp.reason;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004747 if (reason == NULL)
Willy Tarreau7e702d12021-04-28 17:59:21 +02004748 reason = http_get_reason(luactx->appctx->ctx.hlua_apphttp.status);
4749 if (luactx->appctx->ctx.hlua_apphttp.flags & APPLET_HTTP11) {
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004750 flags = (HTX_SL_F_IS_RESP|HTX_SL_F_VER_11);
4751 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.1"), ist(status), ist(reason));
4752 }
4753 else {
4754 flags = HTX_SL_F_IS_RESP;
4755 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.0"), ist(status), ist(reason));
4756 }
4757 if (!sl) {
4758 hlua_pusherror(L, "Lua applet http '%s': Failed to create response.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02004759 luactx->appctx->rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004760 WILL_LJMP(lua_error(L));
4761 }
Willy Tarreau7e702d12021-04-28 17:59:21 +02004762 sl->info.res.status = luactx->appctx->ctx.hlua_apphttp.status;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004763
4764 /* Get the array associated to the field "response" in the object AppletHTTP. */
4765 lua_pushvalue(L, 0);
4766 if (lua_getfield(L, 1, "response") != LUA_TTABLE) {
4767 hlua_pusherror(L, "Lua applet http '%s': AppletHTTP['response'] missing.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02004768 luactx->appctx->rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004769 WILL_LJMP(lua_error(L));
4770 }
4771
4772 /* Browse the list of headers. */
4773 lua_pushnil(L);
4774 while(lua_next(L, -2) != 0) {
4775 /* We expect a string as -2. */
4776 if (lua_type(L, -2) != LUA_TSTRING) {
4777 hlua_pusherror(L, "Lua applet http '%s': AppletHTTP['response'][] element must be a string. got %s.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02004778 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004779 lua_typename(L, lua_type(L, -2)));
4780 WILL_LJMP(lua_error(L));
4781 }
4782 name = lua_tolstring(L, -2, &nlen);
4783
4784 /* We expect an array as -1. */
4785 if (lua_type(L, -1) != LUA_TTABLE) {
4786 hlua_pusherror(L, "Lua applet http '%s': AppletHTTP['response']['%s'] element must be an table. got %s.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02004787 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004788 name,
4789 lua_typename(L, lua_type(L, -1)));
4790 WILL_LJMP(lua_error(L));
4791 }
4792
4793 /* Browse the table who is on the top of the stack. */
4794 lua_pushnil(L);
4795 while(lua_next(L, -2) != 0) {
4796 int id;
4797
4798 /* We expect a number as -2. */
4799 if (lua_type(L, -2) != LUA_TNUMBER) {
4800 hlua_pusherror(L, "Lua applet http '%s': AppletHTTP['response']['%s'][] element must be a number. got %s.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02004801 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004802 name,
4803 lua_typename(L, lua_type(L, -2)));
4804 WILL_LJMP(lua_error(L));
4805 }
4806 id = lua_tointeger(L, -2);
4807
4808 /* We expect a string as -2. */
4809 if (lua_type(L, -1) != LUA_TSTRING) {
4810 hlua_pusherror(L, "Lua applet http '%s': AppletHTTP['response']['%s'][%d] element must be a string. got %s.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02004811 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004812 name, id,
4813 lua_typename(L, lua_type(L, -1)));
4814 WILL_LJMP(lua_error(L));
4815 }
4816 value = lua_tolstring(L, -1, &vlen);
4817
4818 /* Simple Protocol checks. */
4819 if (isteqi(ist2(name, nlen), ist("transfer-encoding")))
Christopher Faulet700d9e82020-01-31 12:21:52 +01004820 h1_parse_xfer_enc_header(&h1m, ist2(value, vlen));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004821 else if (isteqi(ist2(name, nlen), ist("content-length"))) {
4822 struct ist v = ist2(value, vlen);
4823 int ret;
4824
4825 ret = h1_parse_cont_len_header(&h1m, &v);
4826 if (ret < 0) {
4827 hlua_pusherror(L, "Lua applet http '%s': Invalid '%s' header.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02004828 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004829 name);
4830 WILL_LJMP(lua_error(L));
4831 }
4832 else if (ret == 0)
4833 goto next; /* Skip it */
4834 }
4835
4836 /* Add a new header */
4837 if (!htx_add_header(htx, ist2(name, nlen), ist2(value, vlen))) {
4838 hlua_pusherror(L, "Lua applet http '%s': Failed to add header '%s' in the response.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02004839 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004840 name);
4841 WILL_LJMP(lua_error(L));
4842 }
4843 next:
4844 /* Remove the array from the stack, and get next element with a remaining string. */
4845 lua_pop(L, 1);
4846 }
4847
4848 /* Remove the array from the stack, and get next element with a remaining string. */
4849 lua_pop(L, 1);
4850 }
4851
4852 if (h1m.flags & H1_MF_CHNK)
4853 h1m.flags &= ~H1_MF_CLEN;
4854 if (h1m.flags & (H1_MF_CLEN|H1_MF_CHNK))
4855 h1m.flags |= H1_MF_XFER_LEN;
4856
4857 /* Uset HTX start-line flags */
4858 if (h1m.flags & H1_MF_XFER_ENC)
4859 flags |= HTX_SL_F_XFER_ENC;
4860 if (h1m.flags & H1_MF_XFER_LEN) {
4861 flags |= HTX_SL_F_XFER_LEN;
4862 if (h1m.flags & H1_MF_CHNK)
4863 flags |= HTX_SL_F_CHNK;
4864 else if (h1m.flags & H1_MF_CLEN)
4865 flags |= HTX_SL_F_CLEN;
4866 if (h1m.body_len == 0)
4867 flags |= HTX_SL_F_BODYLESS;
4868 }
4869 sl->flags |= flags;
4870
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07004871 /* If we don't have a content-length set, and the HTTP version is 1.1
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004872 * and the status code implies the presence of a message body, we must
4873 * announce a transfer encoding chunked. This is required by haproxy
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05004874 * for the keepalive compliance. If the applet announces a transfer-encoding
4875 * chunked itself, don't do anything.
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004876 */
4877 if ((flags & (HTX_SL_F_VER_11|HTX_SL_F_XFER_LEN)) == HTX_SL_F_VER_11 &&
Willy Tarreau7e702d12021-04-28 17:59:21 +02004878 luactx->appctx->ctx.hlua_apphttp.status >= 200 &&
4879 luactx->appctx->ctx.hlua_apphttp.status != 204 &&
4880 luactx->appctx->ctx.hlua_apphttp.status != 304) {
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004881 /* Add a new header */
4882 sl->flags |= (HTX_SL_F_XFER_ENC|H1_MF_CHNK|H1_MF_XFER_LEN);
4883 if (!htx_add_header(htx, ist("transfer-encoding"), ist("chunked"))) {
4884 hlua_pusherror(L, "Lua applet http '%s': Failed to add header 'transfer-encoding' in the response.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02004885 luactx->appctx->rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004886 WILL_LJMP(lua_error(L));
4887 }
4888 }
4889
4890 /* Finalize headers. */
4891 if (!htx_add_endof(htx, HTX_BLK_EOH)) {
4892 hlua_pusherror(L, "Lua applet http '%s': Failed create the response.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02004893 luactx->appctx->rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004894 WILL_LJMP(lua_error(L));
4895 }
4896
4897 if (htx_used_space(htx) > b_size(&res->buf) - global.tune.maxrewrite) {
4898 b_reset(&res->buf);
4899 hlua_pusherror(L, "Lua: 'start_response': response header block too big");
4900 WILL_LJMP(lua_error(L));
4901 }
4902
4903 htx_to_buf(htx, &res->buf);
Christopher Fauletf6cce3f2019-02-27 21:20:09 +01004904 channel_add_input(res, htx->data);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004905
4906 /* Headers sent, set the flag. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004907 luactx->appctx->ctx.hlua_apphttp.flags |= APPLET_HDR_SENT;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004908 return 0;
4909
4910}
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004911/* We will build the status line and the headers of the HTTP response.
4912 * We will try send at once if its not possible, we give back the hand
4913 * waiting for more room.
4914 */
Christopher Fauleta2097962019-07-15 16:25:33 +02004915__LJMP static int hlua_applet_http_start_response_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004916{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004917 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4918 struct stream_interface *si = luactx->appctx->owner;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004919 struct channel *res = si_ic(si);
4920
4921 if (co_data(res)) {
4922 si_rx_room_blk(si);
Christopher Fauleta2097962019-07-15 16:25:33 +02004923 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_start_response_yield, TICK_ETERNITY, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004924 }
Christopher Fauleta2097962019-07-15 16:25:33 +02004925 return MAY_LJMP(hlua_applet_http_send_response(L));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004926}
4927
4928
Christopher Fauleta2097962019-07-15 16:25:33 +02004929__LJMP static int hlua_applet_http_start_response(lua_State *L)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004930{
Christopher Fauleta2097962019-07-15 16:25:33 +02004931 return MAY_LJMP(hlua_applet_http_start_response_yield(L, 0, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004932}
4933
Christopher Fauleta2097962019-07-15 16:25:33 +02004934/*
4935 *
4936 *
4937 * Class HTTP
4938 *
4939 *
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004940 */
Christopher Fauleta2097962019-07-15 16:25:33 +02004941
4942/* Returns a struct hlua_txn if the stack entry "ud" is
4943 * a class stream, otherwise it throws an error.
4944 */
4945__LJMP static struct hlua_txn *hlua_checkhttp(lua_State *L, int ud)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004946{
Christopher Fauleta2097962019-07-15 16:25:33 +02004947 return MAY_LJMP(hlua_checkudata(L, ud, class_http_ref));
4948}
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004949
Christopher Fauleta2097962019-07-15 16:25:33 +02004950/* This function creates and push in the stack a HTTP object
4951 * according with a current TXN.
4952 */
4953static int hlua_http_new(lua_State *L, struct hlua_txn *txn)
4954{
4955 struct hlua_txn *htxn;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004956
Christopher Fauleta2097962019-07-15 16:25:33 +02004957 /* Check stack size. */
4958 if (!lua_checkstack(L, 3))
4959 return 0;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004960
Christopher Fauleta2097962019-07-15 16:25:33 +02004961 /* Create the object: obj[0] = userdata.
4962 * Note that the base of the Converters object is the
4963 * same than the TXN object.
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004964 */
Christopher Fauleta2097962019-07-15 16:25:33 +02004965 lua_newtable(L);
4966 htxn = lua_newuserdata(L, sizeof(*htxn));
4967 lua_rawseti(L, -2, 0);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004968
4969 htxn->s = txn->s;
4970 htxn->p = txn->p;
Christopher Faulet256b69a2019-05-23 11:14:21 +02004971 htxn->dir = txn->dir;
4972 htxn->flags = txn->flags;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004973
4974 /* Pop a class stream metatable and affect it to the table. */
4975 lua_rawgeti(L, LUA_REGISTRYINDEX, class_http_ref);
4976 lua_setmetatable(L, -2);
4977
4978 return 1;
4979}
4980
4981/* This function creates ans returns an array of HTTP headers.
4982 * This function does not fails. It is used as wrapper with the
4983 * 2 following functions.
4984 */
Christopher Faulet9d1332b2020-02-24 16:46:16 +01004985__LJMP static int hlua_http_get_headers(lua_State *L, struct http_msg *msg)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004986{
Christopher Fauleta2097962019-07-15 16:25:33 +02004987 struct htx *htx;
4988 int32_t pos;
4989
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004990 /* Create the table. */
4991 lua_newtable(L);
4992
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004993
Christopher Fauleta2097962019-07-15 16:25:33 +02004994 htx = htxbuf(&msg->chn->buf);
4995 for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
4996 struct htx_blk *blk = htx_get_blk(htx, pos);
4997 enum htx_blk_type type = htx_get_blk_type(blk);
4998 struct ist n, v;
4999 int len;
Christopher Faulet724a12c2018-12-13 22:12:15 +01005000
Christopher Fauleta2097962019-07-15 16:25:33 +02005001 if (type == HTX_BLK_HDR) {
5002 n = htx_get_blk_name(htx,blk);
5003 v = htx_get_blk_value(htx, blk);
Christopher Faulet724a12c2018-12-13 22:12:15 +01005004 }
Christopher Fauleta2097962019-07-15 16:25:33 +02005005 else if (type == HTX_BLK_EOH)
5006 break;
5007 else
5008 continue;
Christopher Faulet724a12c2018-12-13 22:12:15 +01005009
Christopher Fauleta2097962019-07-15 16:25:33 +02005010 /* Check for existing entry:
5011 * assume that the table is on the top of the stack, and
5012 * push the key in the stack, the function lua_gettable()
5013 * perform the lookup.
5014 */
5015 lua_pushlstring(L, n.ptr, n.len);
5016 lua_gettable(L, -2);
Christopher Faulet724a12c2018-12-13 22:12:15 +01005017
Christopher Fauleta2097962019-07-15 16:25:33 +02005018 switch (lua_type(L, -1)) {
5019 case LUA_TNIL:
5020 /* Table not found, create it. */
5021 lua_pop(L, 1); /* remove the nil value. */
5022 lua_pushlstring(L, n.ptr, n.len); /* push the header name as key. */
5023 lua_newtable(L); /* create and push empty table. */
5024 lua_pushlstring(L, v.ptr, v.len); /* push header value. */
5025 lua_rawseti(L, -2, 0); /* index header value (pop it). */
5026 lua_rawset(L, -3); /* index new table with header name (pop the values). */
Christopher Faulet724a12c2018-12-13 22:12:15 +01005027 break;
Christopher Faulet724a12c2018-12-13 22:12:15 +01005028
Christopher Fauleta2097962019-07-15 16:25:33 +02005029 case LUA_TTABLE:
5030 /* Entry found: push the value in the table. */
5031 len = lua_rawlen(L, -1);
5032 lua_pushlstring(L, v.ptr, v.len); /* push header value. */
5033 lua_rawseti(L, -2, len+1); /* index header value (pop it). */
5034 lua_pop(L, 1); /* remove the table (it is stored in the main table). */
5035 break;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005036
Christopher Fauleta2097962019-07-15 16:25:33 +02005037 default:
5038 /* Other cases are errors. */
5039 hlua_pusherror(L, "internal error during the parsing of headers.");
5040 WILL_LJMP(lua_error(L));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005041 }
5042 }
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005043 return 1;
5044}
5045
5046__LJMP static int hlua_http_req_get_headers(lua_State *L)
5047{
5048 struct hlua_txn *htxn;
5049
5050 MAY_LJMP(check_args(L, 1, "req_get_headers"));
5051 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5052
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005053 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005054 WILL_LJMP(lua_error(L));
5055
Christopher Faulet9d1332b2020-02-24 16:46:16 +01005056 return hlua_http_get_headers(L, &htxn->s->txn->req);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005057}
5058
5059__LJMP static int hlua_http_res_get_headers(lua_State *L)
5060{
5061 struct hlua_txn *htxn;
5062
5063 MAY_LJMP(check_args(L, 1, "res_get_headers"));
5064 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5065
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005066 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005067 WILL_LJMP(lua_error(L));
5068
Christopher Faulet9d1332b2020-02-24 16:46:16 +01005069 return hlua_http_get_headers(L, &htxn->s->txn->rsp);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005070}
5071
5072/* This function replace full header, or just a value in
5073 * the request or in the response. It is a wrapper fir the
5074 * 4 following functions.
5075 */
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005076__LJMP static inline int hlua_http_rep_hdr(lua_State *L, struct http_msg *msg, int full)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005077{
5078 size_t name_len;
5079 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
5080 const char *reg = MAY_LJMP(luaL_checkstring(L, 3));
5081 const char *value = MAY_LJMP(luaL_checkstring(L, 4));
Christopher Fauleta2097962019-07-15 16:25:33 +02005082 struct htx *htx;
Dragan Dosen26743032019-04-30 15:54:36 +02005083 struct my_regex *re;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005084
Dragan Dosen26743032019-04-30 15:54:36 +02005085 if (!(re = regex_comp(reg, 1, 1, NULL)))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005086 WILL_LJMP(luaL_argerror(L, 3, "invalid regex"));
5087
Christopher Fauleta2097962019-07-15 16:25:33 +02005088 htx = htxbuf(&msg->chn->buf);
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005089 http_replace_hdrs(chn_strm(msg->chn), htx, ist2(name, name_len), value, re, full);
Dragan Dosen26743032019-04-30 15:54:36 +02005090 regex_free(re);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005091 return 0;
5092}
5093
5094__LJMP static int hlua_http_req_rep_hdr(lua_State *L)
5095{
5096 struct hlua_txn *htxn;
5097
5098 MAY_LJMP(check_args(L, 4, "req_rep_hdr"));
5099 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5100
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005101 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005102 WILL_LJMP(lua_error(L));
5103
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005104 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->req, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005105}
5106
5107__LJMP static int hlua_http_res_rep_hdr(lua_State *L)
5108{
5109 struct hlua_txn *htxn;
5110
5111 MAY_LJMP(check_args(L, 4, "res_rep_hdr"));
5112 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5113
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005114 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005115 WILL_LJMP(lua_error(L));
5116
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005117 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->rsp, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005118}
5119
5120__LJMP static int hlua_http_req_rep_val(lua_State *L)
5121{
5122 struct hlua_txn *htxn;
5123
5124 MAY_LJMP(check_args(L, 4, "req_rep_hdr"));
5125 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5126
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005127 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005128 WILL_LJMP(lua_error(L));
5129
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005130 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->req, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005131}
5132
5133__LJMP static int hlua_http_res_rep_val(lua_State *L)
5134{
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005135 struct hlua_txn *htxn;
5136
5137 MAY_LJMP(check_args(L, 4, "res_rep_val"));
5138 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5139
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005140 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005141 WILL_LJMP(lua_error(L));
5142
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005143 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->rsp, 0));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005144}
5145
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08005146/* This function deletes all the occurrences of an header.
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005147 * It is a wrapper for the 2 following functions.
5148 */
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005149__LJMP static inline int hlua_http_del_hdr(lua_State *L, struct http_msg *msg)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005150{
5151 size_t len;
5152 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Christopher Fauleta2097962019-07-15 16:25:33 +02005153 struct htx *htx = htxbuf(&msg->chn->buf);
5154 struct http_hdr_ctx ctx;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005155
Christopher Fauleta2097962019-07-15 16:25:33 +02005156 ctx.blk = NULL;
5157 while (http_find_header(htx, ist2(name, len), &ctx, 1))
5158 http_remove_header(htx, &ctx);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005159 return 0;
5160}
5161
5162__LJMP static int hlua_http_req_del_hdr(lua_State *L)
5163{
5164 struct hlua_txn *htxn;
5165
5166 MAY_LJMP(check_args(L, 2, "req_del_hdr"));
5167 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5168
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005169 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005170 WILL_LJMP(lua_error(L));
5171
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005172 return hlua_http_del_hdr(L, &htxn->s->txn->req);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005173}
5174
5175__LJMP static int hlua_http_res_del_hdr(lua_State *L)
5176{
5177 struct hlua_txn *htxn;
5178
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005179 MAY_LJMP(check_args(L, 2, "res_del_hdr"));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005180 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5181
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005182 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005183 WILL_LJMP(lua_error(L));
5184
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005185 return hlua_http_del_hdr(L, &htxn->s->txn->rsp);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005186}
5187
5188/* This function adds an header. It is a wrapper used by
5189 * the 2 following functions.
5190 */
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005191__LJMP static inline int hlua_http_add_hdr(lua_State *L, struct http_msg *msg)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005192{
5193 size_t name_len;
5194 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
5195 size_t value_len;
5196 const char *value = MAY_LJMP(luaL_checklstring(L, 3, &value_len));
Christopher Fauleta2097962019-07-15 16:25:33 +02005197 struct htx *htx = htxbuf(&msg->chn->buf);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005198
Christopher Fauleta2097962019-07-15 16:25:33 +02005199 lua_pushboolean(L, http_add_header(htx, ist2(name, name_len),
5200 ist2(value, value_len)));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005201 return 0;
5202}
5203
5204__LJMP static int hlua_http_req_add_hdr(lua_State *L)
5205{
5206 struct hlua_txn *htxn;
5207
5208 MAY_LJMP(check_args(L, 3, "req_add_hdr"));
5209 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5210
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005211 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005212 WILL_LJMP(lua_error(L));
5213
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005214 return hlua_http_add_hdr(L, &htxn->s->txn->req);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005215}
5216
5217__LJMP static int hlua_http_res_add_hdr(lua_State *L)
5218{
5219 struct hlua_txn *htxn;
5220
5221 MAY_LJMP(check_args(L, 3, "res_add_hdr"));
5222 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5223
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005224 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005225 WILL_LJMP(lua_error(L));
5226
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005227 return hlua_http_add_hdr(L, &htxn->s->txn->rsp);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005228}
5229
5230static int hlua_http_req_set_hdr(lua_State *L)
5231{
5232 struct hlua_txn *htxn;
5233
5234 MAY_LJMP(check_args(L, 3, "req_set_hdr"));
5235 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5236
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005237 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005238 WILL_LJMP(lua_error(L));
5239
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005240 hlua_http_del_hdr(L, &htxn->s->txn->req);
5241 return hlua_http_add_hdr(L, &htxn->s->txn->req);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005242}
5243
5244static int hlua_http_res_set_hdr(lua_State *L)
5245{
5246 struct hlua_txn *htxn;
5247
5248 MAY_LJMP(check_args(L, 3, "res_set_hdr"));
5249 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5250
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005251 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005252 WILL_LJMP(lua_error(L));
5253
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005254 hlua_http_del_hdr(L, &htxn->s->txn->rsp);
5255 return hlua_http_add_hdr(L, &htxn->s->txn->rsp);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005256}
5257
5258/* This function set the method. */
5259static int hlua_http_req_set_meth(lua_State *L)
5260{
Willy Tarreaubcb39cc2015-04-06 11:21:44 +02005261 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005262 size_t name_len;
5263 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005264
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005265 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005266 WILL_LJMP(lua_error(L));
5267
Christopher Fauletfc9cfe42019-07-16 14:54:53 +02005268 lua_pushboolean(L, http_req_replace_stline(0, name, name_len, htxn->p, htxn->s) != -1);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005269 return 1;
5270}
5271
5272/* This function set the method. */
5273static int hlua_http_req_set_path(lua_State *L)
5274{
Willy Tarreaubcb39cc2015-04-06 11:21:44 +02005275 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005276 size_t name_len;
5277 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
Thierry FOURNIER / OZON.IOb84ae922016-08-02 23:44:58 +02005278
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005279 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005280 WILL_LJMP(lua_error(L));
5281
Christopher Fauletfc9cfe42019-07-16 14:54:53 +02005282 lua_pushboolean(L, http_req_replace_stline(1, name, name_len, htxn->p, htxn->s) != -1);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005283 return 1;
5284}
5285
5286/* This function set the query-string. */
5287static int hlua_http_req_set_query(lua_State *L)
5288{
Willy Tarreaubcb39cc2015-04-06 11:21:44 +02005289 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005290 size_t name_len;
5291 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005292
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005293 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005294 WILL_LJMP(lua_error(L));
5295
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005296 /* Check length. */
5297 if (name_len > trash.size - 1) {
5298 lua_pushboolean(L, 0);
5299 return 1;
5300 }
5301
5302 /* Add the mark question as prefix. */
5303 chunk_reset(&trash);
Willy Tarreau843b7cb2018-07-13 10:54:26 +02005304 trash.area[trash.data++] = '?';
5305 memcpy(trash.area + trash.data, name, name_len);
5306 trash.data += name_len;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005307
Willy Tarreau843b7cb2018-07-13 10:54:26 +02005308 lua_pushboolean(L,
Christopher Fauletfc9cfe42019-07-16 14:54:53 +02005309 http_req_replace_stline(2, trash.area, trash.data, htxn->p, htxn->s) != -1);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005310 return 1;
5311}
5312
5313/* This function set the uri. */
5314static int hlua_http_req_set_uri(lua_State *L)
5315{
Willy Tarreaubcb39cc2015-04-06 11:21:44 +02005316 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005317 size_t name_len;
5318 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005319
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005320 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005321 WILL_LJMP(lua_error(L));
5322
Christopher Fauletfc9cfe42019-07-16 14:54:53 +02005323 lua_pushboolean(L, http_req_replace_stline(3, name, name_len, htxn->p, htxn->s) != -1);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005324 return 1;
5325}
5326
Robin H. Johnson52f5db22017-01-01 13:10:52 -08005327/* This function set the response code & optionally reason. */
Thierry FOURNIER35d70ef2015-08-26 16:21:56 +02005328static int hlua_http_res_set_status(lua_State *L)
5329{
5330 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5331 unsigned int code = MAY_LJMP(luaL_checkinteger(L, 2));
Christopher Faulet96bff762019-12-17 13:46:18 +01005332 const char *str = MAY_LJMP(luaL_optlstring(L, 3, NULL, NULL));
5333 const struct ist reason = ist2(str, (str ? strlen(str) : 0));
Thierry FOURNIER35d70ef2015-08-26 16:21:56 +02005334
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005335 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005336 WILL_LJMP(lua_error(L));
5337
Christopher Fauletfc9cfe42019-07-16 14:54:53 +02005338 http_res_set_status(code, reason, htxn->s);
Thierry FOURNIER35d70ef2015-08-26 16:21:56 +02005339 return 0;
5340}
5341
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005342/*
5343 *
5344 *
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005345 * Class TXN
5346 *
5347 *
5348 */
5349
5350/* Returns a struct hlua_session if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02005351 * a class stream, otherwise it throws an error.
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005352 */
5353__LJMP static struct hlua_txn *hlua_checktxn(lua_State *L, int ud)
5354{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02005355 return MAY_LJMP(hlua_checkudata(L, ud, class_txn_ref));
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005356}
5357
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02005358__LJMP static int hlua_set_var(lua_State *L)
5359{
5360 struct hlua_txn *htxn;
5361 const char *name;
5362 size_t len;
5363 struct sample smp;
5364
Tim Duesterhus4e172c92020-05-19 13:49:42 +02005365 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
5366 WILL_LJMP(luaL_error(L, "'set_var' needs between 3 and 4 arguments"));
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02005367
5368 /* It is useles to retrieve the stream, but this function
5369 * runs only in a stream context.
5370 */
5371 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5372 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
5373
5374 /* Converts the third argument in a sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01005375 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02005376 hlua_lua2smp(L, 3, &smp);
5377
5378 /* Store the sample in a variable. */
Willy Tarreau7560dd42016-03-10 16:28:58 +01005379 smp_set_owner(&smp, htxn->p, htxn->s->sess, htxn->s, htxn->dir & SMP_OPT_DIR);
Tim Duesterhus4e172c92020-05-19 13:49:42 +02005380
5381 if (lua_gettop(L) == 4 && lua_toboolean(L, 4))
5382 lua_pushboolean(L, vars_set_by_name_ifexist(name, len, &smp) != 0);
5383 else
5384 lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
5385
Tim Duesterhus84ebc132020-05-19 13:49:41 +02005386 return 1;
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02005387}
5388
Christopher Faulet85d79c92016-11-09 16:54:56 +01005389__LJMP static int hlua_unset_var(lua_State *L)
5390{
5391 struct hlua_txn *htxn;
5392 const char *name;
5393 size_t len;
5394 struct sample smp;
5395
5396 MAY_LJMP(check_args(L, 2, "unset_var"));
5397
5398 /* It is useles to retrieve the stream, but this function
5399 * runs only in a stream context.
5400 */
5401 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5402 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
5403
5404 /* Unset the variable. */
5405 smp_set_owner(&smp, htxn->p, htxn->s->sess, htxn->s, htxn->dir & SMP_OPT_DIR);
Tim Duesterhus84ebc132020-05-19 13:49:41 +02005406 lua_pushboolean(L, vars_unset_by_name_ifexist(name, len, &smp) != 0);
5407 return 1;
Christopher Faulet85d79c92016-11-09 16:54:56 +01005408}
5409
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02005410__LJMP static int hlua_get_var(lua_State *L)
5411{
5412 struct hlua_txn *htxn;
5413 const char *name;
5414 size_t len;
5415 struct sample smp;
5416
5417 MAY_LJMP(check_args(L, 2, "get_var"));
5418
5419 /* It is useles to retrieve the stream, but this function
5420 * runs only in a stream context.
5421 */
5422 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5423 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
5424
Willy Tarreau7560dd42016-03-10 16:28:58 +01005425 smp_set_owner(&smp, htxn->p, htxn->s->sess, htxn->s, htxn->dir & SMP_OPT_DIR);
Willy Tarreau6204cd92016-03-10 16:33:04 +01005426 if (!vars_get_by_name(name, len, &smp)) {
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02005427 lua_pushnil(L);
5428 return 1;
5429 }
5430
5431 return hlua_smp2lua(L, &smp);
5432}
5433
Willy Tarreau59551662015-03-10 14:23:13 +01005434__LJMP static int hlua_set_priv(lua_State *L)
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005435{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01005436 struct hlua *hlua;
5437
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005438 MAY_LJMP(check_args(L, 2, "set_priv"));
5439
Willy Tarreau87b09662015-04-03 00:22:06 +02005440 /* It is useles to retrieve the stream, but this function
5441 * runs only in a stream context.
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005442 */
5443 MAY_LJMP(hlua_checktxn(L, 1));
Thierry Fournier4234dbd2020-11-28 13:18:23 +01005444
5445 /* Get hlua struct, or NULL if we execute from main lua state */
Willy Tarreau80f5fae2015-02-27 16:38:20 +01005446 hlua = hlua_gethlua(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01005447 if (!hlua)
5448 return 0;
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005449
5450 /* Remove previous value. */
Thierry FOURNIERe068b602017-04-26 13:27:05 +02005451 luaL_unref(L, LUA_REGISTRYINDEX, hlua->Mref);
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005452
5453 /* Get and store new value. */
5454 lua_pushvalue(L, 2); /* Copy the element 2 at the top of the stack. */
5455 hlua->Mref = luaL_ref(L, LUA_REGISTRYINDEX); /* pop the previously pushed value. */
5456
5457 return 0;
5458}
5459
Willy Tarreau59551662015-03-10 14:23:13 +01005460__LJMP static int hlua_get_priv(lua_State *L)
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005461{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01005462 struct hlua *hlua;
5463
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005464 MAY_LJMP(check_args(L, 1, "get_priv"));
5465
Willy Tarreau87b09662015-04-03 00:22:06 +02005466 /* It is useles to retrieve the stream, but this function
5467 * runs only in a stream context.
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005468 */
5469 MAY_LJMP(hlua_checktxn(L, 1));
Thierry Fournier4234dbd2020-11-28 13:18:23 +01005470
5471 /* Get hlua struct, or NULL if we execute from main lua state */
Willy Tarreau80f5fae2015-02-27 16:38:20 +01005472 hlua = hlua_gethlua(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01005473 if (!hlua) {
5474 lua_pushnil(L);
5475 return 1;
5476 }
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005477
5478 /* Push configuration index in the stack. */
5479 lua_rawgeti(L, LUA_REGISTRYINDEX, hlua->Mref);
5480
5481 return 1;
5482}
5483
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005484/* Create stack entry containing a class TXN. This function
5485 * return 0 if the stack does not contains free slots,
5486 * otherwise it returns 1.
5487 */
Thierry FOURNIERab00df62016-07-14 11:42:37 +02005488static int hlua_txn_new(lua_State *L, struct stream *s, struct proxy *p, int dir, int flags)
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005489{
Willy Tarreaude491382015-04-06 11:04:28 +02005490 struct hlua_txn *htxn;
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005491
5492 /* Check stack size. */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01005493 if (!lua_checkstack(L, 3))
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005494 return 0;
5495
5496 /* NOTE: The allocation never fails. The failure
5497 * throw an error, and the function never returns.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08005498 * if the throw is not available, the process is aborted.
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005499 */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01005500 /* Create the object: obj[0] = userdata. */
5501 lua_newtable(L);
Willy Tarreaude491382015-04-06 11:04:28 +02005502 htxn = lua_newuserdata(L, sizeof(*htxn));
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01005503 lua_rawseti(L, -2, 0);
5504
Willy Tarreaude491382015-04-06 11:04:28 +02005505 htxn->s = s;
5506 htxn->p = p;
Thierry FOURNIERc4eebc82015-11-02 10:01:59 +01005507 htxn->dir = dir;
Thierry FOURNIERab00df62016-07-14 11:42:37 +02005508 htxn->flags = flags;
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005509
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01005510 /* Create the "f" field that contains a list of fetches. */
5511 lua_pushstring(L, "f");
Thierry FOURNIERca988662015-12-20 18:43:03 +01005512 if (!hlua_fetches_new(L, htxn, HLUA_F_MAY_USE_HTTP))
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01005513 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02005514 lua_rawset(L, -3);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01005515
5516 /* Create the "sf" field that contains a list of stringsafe fetches. */
5517 lua_pushstring(L, "sf");
Thierry FOURNIERca988662015-12-20 18:43:03 +01005518 if (!hlua_fetches_new(L, htxn, HLUA_F_MAY_USE_HTTP | HLUA_F_AS_STRING))
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01005519 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02005520 lua_rawset(L, -3);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01005521
Thierry FOURNIER594afe72015-03-10 23:58:30 +01005522 /* Create the "c" field that contains a list of converters. */
5523 lua_pushstring(L, "c");
Willy Tarreaude491382015-04-06 11:04:28 +02005524 if (!hlua_converters_new(L, htxn, 0))
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01005525 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02005526 lua_rawset(L, -3);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01005527
5528 /* Create the "sc" field that contains a list of stringsafe converters. */
5529 lua_pushstring(L, "sc");
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01005530 if (!hlua_converters_new(L, htxn, HLUA_F_AS_STRING))
Thierry FOURNIER594afe72015-03-10 23:58:30 +01005531 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02005532 lua_rawset(L, -3);
Thierry FOURNIER594afe72015-03-10 23:58:30 +01005533
Thierry FOURNIER397826a2015-03-11 19:39:09 +01005534 /* Create the "req" field that contains the request channel object. */
5535 lua_pushstring(L, "req");
Willy Tarreau2a71af42015-03-10 13:51:50 +01005536 if (!hlua_channel_new(L, &s->req))
Thierry FOURNIER397826a2015-03-11 19:39:09 +01005537 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02005538 lua_rawset(L, -3);
Thierry FOURNIER397826a2015-03-11 19:39:09 +01005539
5540 /* Create the "res" field that contains the response channel object. */
5541 lua_pushstring(L, "res");
Willy Tarreau2a71af42015-03-10 13:51:50 +01005542 if (!hlua_channel_new(L, &s->res))
Thierry FOURNIER397826a2015-03-11 19:39:09 +01005543 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02005544 lua_rawset(L, -3);
Thierry FOURNIER397826a2015-03-11 19:39:09 +01005545
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005546 /* Creates the HTTP object is the current proxy allows http. */
5547 lua_pushstring(L, "http");
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01005548 if (IS_HTX_STRM(s)) {
Willy Tarreaude491382015-04-06 11:04:28 +02005549 if (!hlua_http_new(L, htxn))
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005550 return 0;
5551 }
5552 else
5553 lua_pushnil(L);
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02005554 lua_rawset(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005555
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005556 /* Pop a class sesison metatable and affect it to the userdata. */
5557 lua_rawgeti(L, LUA_REGISTRYINDEX, class_txn_ref);
5558 lua_setmetatable(L, -2);
5559
5560 return 1;
5561}
5562
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01005563__LJMP static int hlua_txn_deflog(lua_State *L)
5564{
5565 const char *msg;
5566 struct hlua_txn *htxn;
5567
5568 MAY_LJMP(check_args(L, 2, "deflog"));
5569 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5570 msg = MAY_LJMP(luaL_checkstring(L, 2));
5571
5572 hlua_sendlog(htxn->s->be, htxn->s->logs.level, msg);
5573 return 0;
5574}
5575
5576__LJMP static int hlua_txn_log(lua_State *L)
5577{
5578 int level;
5579 const char *msg;
5580 struct hlua_txn *htxn;
5581
5582 MAY_LJMP(check_args(L, 3, "log"));
5583 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5584 level = MAY_LJMP(luaL_checkinteger(L, 2));
5585 msg = MAY_LJMP(luaL_checkstring(L, 3));
5586
5587 if (level < 0 || level >= NB_LOG_LEVELS)
5588 WILL_LJMP(luaL_argerror(L, 1, "Invalid loglevel."));
5589
5590 hlua_sendlog(htxn->s->be, level, msg);
5591 return 0;
5592}
5593
5594__LJMP static int hlua_txn_log_debug(lua_State *L)
5595{
5596 const char *msg;
5597 struct hlua_txn *htxn;
5598
5599 MAY_LJMP(check_args(L, 2, "Debug"));
5600 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5601 msg = MAY_LJMP(luaL_checkstring(L, 2));
5602 hlua_sendlog(htxn->s->be, LOG_DEBUG, msg);
5603 return 0;
5604}
5605
5606__LJMP static int hlua_txn_log_info(lua_State *L)
5607{
5608 const char *msg;
5609 struct hlua_txn *htxn;
5610
5611 MAY_LJMP(check_args(L, 2, "Info"));
5612 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5613 msg = MAY_LJMP(luaL_checkstring(L, 2));
5614 hlua_sendlog(htxn->s->be, LOG_INFO, msg);
5615 return 0;
5616}
5617
5618__LJMP static int hlua_txn_log_warning(lua_State *L)
5619{
5620 const char *msg;
5621 struct hlua_txn *htxn;
5622
5623 MAY_LJMP(check_args(L, 2, "Warning"));
5624 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5625 msg = MAY_LJMP(luaL_checkstring(L, 2));
5626 hlua_sendlog(htxn->s->be, LOG_WARNING, msg);
5627 return 0;
5628}
5629
5630__LJMP static int hlua_txn_log_alert(lua_State *L)
5631{
5632 const char *msg;
5633 struct hlua_txn *htxn;
5634
5635 MAY_LJMP(check_args(L, 2, "Alert"));
5636 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5637 msg = MAY_LJMP(luaL_checkstring(L, 2));
5638 hlua_sendlog(htxn->s->be, LOG_ALERT, msg);
5639 return 0;
5640}
5641
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01005642__LJMP static int hlua_txn_set_loglevel(lua_State *L)
5643{
5644 struct hlua_txn *htxn;
5645 int ll;
5646
5647 MAY_LJMP(check_args(L, 2, "set_loglevel"));
5648 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5649 ll = MAY_LJMP(luaL_checkinteger(L, 2));
5650
5651 if (ll < 0 || ll > 7)
5652 WILL_LJMP(luaL_argerror(L, 2, "Bad log level. It must be between 0 and 7"));
5653
5654 htxn->s->logs.level = ll;
5655 return 0;
5656}
5657
5658__LJMP static int hlua_txn_set_tos(lua_State *L)
5659{
5660 struct hlua_txn *htxn;
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01005661 int tos;
5662
5663 MAY_LJMP(check_args(L, 2, "set_tos"));
5664 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5665 tos = MAY_LJMP(luaL_checkinteger(L, 2));
5666
Willy Tarreau1a18b542018-12-11 16:37:42 +01005667 conn_set_tos(objt_conn(htxn->s->sess->origin), tos);
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01005668 return 0;
5669}
5670
5671__LJMP static int hlua_txn_set_mark(lua_State *L)
5672{
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01005673 struct hlua_txn *htxn;
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01005674 int mark;
5675
5676 MAY_LJMP(check_args(L, 2, "set_mark"));
5677 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5678 mark = MAY_LJMP(luaL_checkinteger(L, 2));
5679
Lukas Tribus579e3e32019-08-11 18:03:45 +02005680 conn_set_mark(objt_conn(htxn->s->sess->origin), mark);
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01005681 return 0;
5682}
5683
Patrick Hemmer268a7072018-05-11 12:52:31 -04005684__LJMP static int hlua_txn_set_priority_class(lua_State *L)
5685{
5686 struct hlua_txn *htxn;
5687
5688 MAY_LJMP(check_args(L, 2, "set_priority_class"));
5689 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5690 htxn->s->priority_class = queue_limit_class(MAY_LJMP(luaL_checkinteger(L, 2)));
5691 return 0;
5692}
5693
5694__LJMP static int hlua_txn_set_priority_offset(lua_State *L)
5695{
5696 struct hlua_txn *htxn;
5697
5698 MAY_LJMP(check_args(L, 2, "set_priority_offset"));
5699 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5700 htxn->s->priority_offset = queue_limit_offset(MAY_LJMP(luaL_checkinteger(L, 2)));
5701 return 0;
5702}
5703
Christopher Faulet700d9e82020-01-31 12:21:52 +01005704/* Forward the Reply object to the client. This function converts the reply in
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05005705 * HTX an push it to into the response channel. It is response to forward the
Christopher Faulet700d9e82020-01-31 12:21:52 +01005706 * message and terminate the transaction. It returns 1 on success and 0 on
5707 * error. The Reply must be on top of the stack.
5708 */
5709__LJMP static int hlua_txn_forward_reply(lua_State *L, struct stream *s)
5710{
5711 struct htx *htx;
5712 struct htx_sl *sl;
5713 struct h1m h1m;
5714 const char *status, *reason, *body;
5715 size_t status_len, reason_len, body_len;
5716 int ret, code, flags;
5717
5718 code = 200;
5719 status = "200";
5720 status_len = 3;
5721 ret = lua_getfield(L, -1, "status");
5722 if (ret == LUA_TNUMBER) {
5723 code = lua_tointeger(L, -1);
5724 status = lua_tolstring(L, -1, &status_len);
5725 }
5726 lua_pop(L, 1);
5727
5728 reason = http_get_reason(code);
5729 reason_len = strlen(reason);
5730 ret = lua_getfield(L, -1, "reason");
5731 if (ret == LUA_TSTRING)
5732 reason = lua_tolstring(L, -1, &reason_len);
5733 lua_pop(L, 1);
5734
5735 body = NULL;
5736 body_len = 0;
5737 ret = lua_getfield(L, -1, "body");
5738 if (ret == LUA_TSTRING)
5739 body = lua_tolstring(L, -1, &body_len);
5740 lua_pop(L, 1);
5741
5742 /* Prepare the response before inserting the headers */
5743 h1m_init_res(&h1m);
5744 htx = htx_from_buf(&s->res.buf);
5745 channel_htx_truncate(&s->res, htx);
5746 if (s->txn->req.flags & HTTP_MSGF_VER_11) {
5747 flags = (HTX_SL_F_IS_RESP|HTX_SL_F_VER_11);
5748 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.1"),
5749 ist2(status, status_len), ist2(reason, reason_len));
5750 }
5751 else {
5752 flags = HTX_SL_F_IS_RESP;
5753 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.0"),
5754 ist2(status, status_len), ist2(reason, reason_len));
5755 }
5756 if (!sl)
5757 goto fail;
5758 sl->info.res.status = code;
5759
5760 /* Push in the stack the "headers" entry. */
5761 ret = lua_getfield(L, -1, "headers");
5762 if (ret != LUA_TTABLE)
5763 goto skip_headers;
5764
5765 lua_pushnil(L);
5766 while (lua_next(L, -2) != 0) {
5767 struct ist name, value;
5768 const char *n, *v;
5769 size_t nlen, vlen;
5770
5771 if (!lua_isstring(L, -2) || !lua_istable(L, -1)) {
5772 /* Skip element if the key is not a string or if the value is not a table */
5773 goto next_hdr;
5774 }
5775
5776 n = lua_tolstring(L, -2, &nlen);
5777 name = ist2(n, nlen);
5778 if (isteqi(name, ist("content-length"))) {
5779 /* Always skip content-length header. It will be added
5780 * later with the correct len
5781 */
5782 goto next_hdr;
5783 }
5784
5785 /* Loop on header's values */
5786 lua_pushnil(L);
5787 while (lua_next(L, -2)) {
5788 if (!lua_isstring(L, -1)) {
5789 /* Skip the value if it is not a string */
5790 goto next_value;
5791 }
5792
5793 v = lua_tolstring(L, -1, &vlen);
5794 value = ist2(v, vlen);
5795
5796 if (isteqi(name, ist("transfer-encoding")))
5797 h1_parse_xfer_enc_header(&h1m, value);
5798 if (!htx_add_header(htx, ist2(n, nlen), ist2(v, vlen)))
5799 goto fail;
5800
5801 next_value:
5802 lua_pop(L, 1);
5803 }
5804
5805 next_hdr:
5806 lua_pop(L, 1);
5807 }
5808 skip_headers:
5809 lua_pop(L, 1);
5810
5811 /* Update h1m flags: CLEN is set if CHNK is not present */
5812 if (!(h1m.flags & H1_MF_CHNK)) {
5813 const char *clen = ultoa(body_len);
5814
5815 h1m.flags |= H1_MF_CLEN;
5816 if (!htx_add_header(htx, ist("content-length"), ist(clen)))
5817 goto fail;
5818 }
5819 if (h1m.flags & (H1_MF_CLEN|H1_MF_CHNK))
5820 h1m.flags |= H1_MF_XFER_LEN;
5821
5822 /* Update HTX start-line flags */
5823 if (h1m.flags & H1_MF_XFER_ENC)
5824 flags |= HTX_SL_F_XFER_ENC;
5825 if (h1m.flags & H1_MF_XFER_LEN) {
5826 flags |= HTX_SL_F_XFER_LEN;
5827 if (h1m.flags & H1_MF_CHNK)
5828 flags |= HTX_SL_F_CHNK;
5829 else if (h1m.flags & H1_MF_CLEN)
5830 flags |= HTX_SL_F_CLEN;
5831 if (h1m.body_len == 0)
5832 flags |= HTX_SL_F_BODYLESS;
5833 }
5834 sl->flags |= flags;
5835
5836
5837 if (!htx_add_endof(htx, HTX_BLK_EOH) ||
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01005838 (body_len && !htx_add_data_atonce(htx, ist2(body, body_len))))
Christopher Faulet700d9e82020-01-31 12:21:52 +01005839 goto fail;
5840
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01005841 htx->flags |= HTX_FL_EOM;
5842
Christopher Faulet700d9e82020-01-31 12:21:52 +01005843 /* Now, forward the response and terminate the transaction */
5844 s->txn->status = code;
5845 htx_to_buf(htx, &s->res.buf);
5846 if (!http_forward_proxy_resp(s, 1))
5847 goto fail;
5848
5849 return 1;
5850
5851 fail:
5852 channel_htx_truncate(&s->res, htx);
5853 return 0;
5854}
5855
5856/* Terminate a transaction if called from a lua action. For TCP streams,
5857 * processing is just aborted. Nothing is returned to the client and all
5858 * arguments are ignored. For HTTP streams, if a reply is passed as argument, it
5859 * is forwarded to the client before terminating the transaction. On success,
5860 * the function exits with ACT_RET_DONE code. If an error occurred, it exits
5861 * with ACT_RET_ERR code. If this function is not called from a lua action, it
5862 * just exits without any processing.
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01005863 */
Thierry FOURNIER4bb375c2015-08-26 08:42:21 +02005864__LJMP static int hlua_txn_done(lua_State *L)
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01005865{
Willy Tarreaub2ccb562015-04-06 11:11:15 +02005866 struct hlua_txn *htxn;
Christopher Faulet700d9e82020-01-31 12:21:52 +01005867 struct stream *s;
5868 int finst;
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01005869
Willy Tarreaub2ccb562015-04-06 11:11:15 +02005870 htxn = MAY_LJMP(hlua_checktxn(L, 1));
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01005871
Christopher Faulet700d9e82020-01-31 12:21:52 +01005872 /* If the flags NOTERM is set, we cannot terminate the session, so we
5873 * just end the execution of the current lua code. */
5874 if (htxn->flags & HLUA_TXN_NOTERM)
Thierry FOURNIERab00df62016-07-14 11:42:37 +02005875 WILL_LJMP(hlua_done(L));
Thierry FOURNIERab00df62016-07-14 11:42:37 +02005876
Christopher Faulet700d9e82020-01-31 12:21:52 +01005877 s = htxn->s;
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005878 if (!IS_HTX_STRM(htxn->s)) {
Christopher Faulet700d9e82020-01-31 12:21:52 +01005879 struct channel *req = &s->req;
5880 struct channel *res = &s->res;
Willy Tarreau81389672015-03-10 12:03:52 +01005881
Christopher Faulet700d9e82020-01-31 12:21:52 +01005882 channel_auto_read(req);
5883 channel_abort(req);
5884 channel_auto_close(req);
5885 channel_erase(req);
5886
5887 res->wex = tick_add_ifset(now_ms, res->wto);
5888 channel_auto_read(res);
5889 channel_auto_close(res);
5890 channel_shutr_now(res);
5891
5892 finst = ((htxn->dir == SMP_OPT_DIR_REQ) ? SF_FINST_R : SF_FINST_D);
5893 goto done;
Christopher Fauletfe6a71b2019-07-26 16:40:24 +02005894 }
Thierry FOURNIER10ec2142015-08-24 17:23:45 +02005895
Christopher Faulet700d9e82020-01-31 12:21:52 +01005896 if (lua_gettop(L) == 1 || !lua_istable(L, 2)) {
5897 /* No reply or invalid reply */
5898 s->txn->status = 0;
5899 http_reply_and_close(s, 0, NULL);
5900 }
5901 else {
5902 /* Remove extra args to have the reply on top of the stack */
5903 if (lua_gettop(L) > 2)
5904 lua_pop(L, lua_gettop(L) - 2);
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01005905
Christopher Faulet700d9e82020-01-31 12:21:52 +01005906 if (!hlua_txn_forward_reply(L, s)) {
5907 if (!(s->flags & SF_ERR_MASK))
5908 s->flags |= SF_ERR_PRXCOND;
5909 lua_pushinteger(L, ACT_RET_ERR);
5910 WILL_LJMP(hlua_done(L));
5911 return 0; /* Never reached */
5912 }
Christopher Faulet4d0e2632019-07-16 10:52:40 +02005913 }
Thierry FOURNIER4bb375c2015-08-26 08:42:21 +02005914
Christopher Faulet700d9e82020-01-31 12:21:52 +01005915 finst = ((htxn->dir == SMP_OPT_DIR_REQ) ? SF_FINST_R : SF_FINST_H);
5916 if (htxn->dir == SMP_OPT_DIR_REQ) {
5917 /* let's log the request time */
5918 s->logs.tv_request = now;
5919 if (s->sess->fe == s->be) /* report it if the request was intercepted by the frontend */
Willy Tarreau4781b152021-04-06 13:53:36 +02005920 _HA_ATOMIC_INC(&s->sess->fe->fe_counters.intercepted_req);
Christopher Faulet700d9e82020-01-31 12:21:52 +01005921 }
Christopher Fauletfe6a71b2019-07-26 16:40:24 +02005922
Christopher Faulet700d9e82020-01-31 12:21:52 +01005923 done:
5924 if (!(s->flags & SF_ERR_MASK))
5925 s->flags |= SF_ERR_LOCAL;
5926 if (!(s->flags & SF_FINST_MASK))
5927 s->flags |= finst;
Christopher Fauletfe6a71b2019-07-26 16:40:24 +02005928
Christopher Faulet4ad73102020-03-05 11:07:31 +01005929 lua_pushinteger(L, ACT_RET_ABRT);
Thierry FOURNIER4bb375c2015-08-26 08:42:21 +02005930 WILL_LJMP(hlua_done(L));
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01005931 return 0;
5932}
5933
Christopher Faulet700d9e82020-01-31 12:21:52 +01005934/*
5935 *
5936 *
5937 * Class REPLY
5938 *
5939 *
5940 */
5941
5942/* Pushes the TXN reply onto the top of the stack. If the stask does not have a
5943 * free slots, the function fails and returns 0;
5944 */
5945static int hlua_txn_reply_new(lua_State *L)
5946{
5947 struct hlua_txn *htxn;
5948 const char *reason, *body = NULL;
5949 int ret, status;
5950
5951 htxn = MAY_LJMP(hlua_checktxn(L, 1));
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005952 if (!IS_HTX_STRM(htxn->s)) {
Christopher Faulet700d9e82020-01-31 12:21:52 +01005953 hlua_pusherror(L, "txn object is not an HTTP transaction.");
5954 WILL_LJMP(lua_error(L));
5955 }
5956
5957 /* Default value */
5958 status = 200;
5959 reason = http_get_reason(status);
5960
5961 if (lua_istable(L, 2)) {
5962 /* load status and reason from the table argument at index 2 */
5963 ret = lua_getfield(L, 2, "status");
5964 if (ret == LUA_TNIL)
5965 goto reason;
5966 else if (ret != LUA_TNUMBER) {
5967 /* invalid status: ignore the reason */
5968 goto body;
5969 }
5970 status = lua_tointeger(L, -1);
5971
5972 reason:
5973 lua_pop(L, 1); /* restore the stack: remove status */
5974 ret = lua_getfield(L, 2, "reason");
5975 if (ret == LUA_TSTRING)
5976 reason = lua_tostring(L, -1);
5977
5978 body:
5979 lua_pop(L, 1); /* restore the stack: remove invalid status or reason */
5980 ret = lua_getfield(L, 2, "body");
5981 if (ret == LUA_TSTRING)
5982 body = lua_tostring(L, -1);
5983 lua_pop(L, 1); /* restore the stack: remove body */
5984 }
5985
5986 /* Create the Reply table */
5987 lua_newtable(L);
5988
5989 /* Add status element */
5990 lua_pushstring(L, "status");
5991 lua_pushinteger(L, status);
5992 lua_settable(L, -3);
5993
5994 /* Add reason element */
5995 reason = http_get_reason(status);
5996 lua_pushstring(L, "reason");
5997 lua_pushstring(L, reason);
5998 lua_settable(L, -3);
5999
6000 /* Add body element, nil if undefined */
6001 lua_pushstring(L, "body");
6002 if (body)
6003 lua_pushstring(L, body);
6004 else
6005 lua_pushnil(L);
6006 lua_settable(L, -3);
6007
6008 /* Add headers element */
6009 lua_pushstring(L, "headers");
6010 lua_newtable(L);
6011
6012 /* stack: [ txn, <Arg:table>, <Reply:table>, "headers", <headers:table> ] */
6013 if (lua_istable(L, 2)) {
6014 /* load headers from the table argument at index 2. If it is a table, copy it. */
6015 ret = lua_getfield(L, 2, "headers");
6016 if (ret == LUA_TTABLE) {
6017 /* stack: [ ... <headers:table>, <table> ] */
6018 lua_pushnil(L);
6019 while (lua_next(L, -2) != 0) {
6020 /* stack: [ ... <headers:table>, <table>, k, v] */
6021 if (!lua_isstring(L, -1) && !lua_istable(L, -1)) {
6022 /* invalid value type, skip it */
6023 lua_pop(L, 1);
6024 continue;
6025 }
6026
6027
6028 /* Duplicate the key and swap it with the value. */
6029 lua_pushvalue(L, -2);
6030 lua_insert(L, -2);
6031 /* stack: [ ... <headers:table>, <table>, k, k, v ] */
6032
6033 lua_newtable(L);
6034 lua_insert(L, -2);
6035 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table>, v ] */
6036
6037 if (lua_isstring(L, -1)) {
6038 /* push the value in the inner table */
6039 lua_rawseti(L, -2, 1);
6040 }
6041 else { /* table */
6042 lua_pushnil(L);
6043 while (lua_next(L, -2) != 0) {
6044 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table>, <v:table>, k2, v2 ] */
6045 if (!lua_isstring(L, -1)) {
6046 /* invalid value type, skip it*/
6047 lua_pop(L, 1);
6048 continue;
6049 }
6050 /* push the value in the inner table */
6051 lua_rawseti(L, -4, lua_rawlen(L, -4) + 1);
6052 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table>, <v:table>, k2 ] */
6053 }
6054 lua_pop(L, 1);
6055 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table> ] */
6056 }
6057
6058 /* push (k,v) on the stack in the headers table:
6059 * stack: [ ... <headers:table>, <table>, k, k, v ]
6060 */
6061 lua_settable(L, -5);
6062 /* stack: [ ... <headers:table>, <table>, k ] */
6063 }
6064 }
6065 lua_pop(L, 1);
6066 }
6067 /* stack: [ txn, <Arg:table>, <Reply:table>, "headers", <headers:table> ] */
6068 lua_settable(L, -3);
6069 /* stack: [ txn, <Arg:table>, <Reply:table> ] */
6070
6071 /* Pop a class sesison metatable and affect it to the userdata. */
6072 lua_rawgeti(L, LUA_REGISTRYINDEX, class_txn_reply_ref);
6073 lua_setmetatable(L, -2);
6074 return 1;
6075}
6076
6077/* Set the reply status code, and optionally the reason. If no reason is
6078 * provided, the default one corresponding to the status code is used.
6079 */
6080__LJMP static int hlua_txn_reply_set_status(lua_State *L)
6081{
6082 int status = MAY_LJMP(luaL_checkinteger(L, 2));
6083 const char *reason = MAY_LJMP(luaL_optlstring(L, 3, NULL, NULL));
6084
6085 /* First argument (self) must be a table */
6086 luaL_checktype(L, 1, LUA_TTABLE);
6087
6088 if (status < 100 || status > 599) {
6089 lua_pushboolean(L, 0);
6090 return 1;
6091 }
6092 if (!reason)
6093 reason = http_get_reason(status);
6094
6095 lua_pushinteger(L, status);
6096 lua_setfield(L, 1, "status");
6097
6098 lua_pushstring(L, reason);
6099 lua_setfield(L, 1, "reason");
6100
6101 lua_pushboolean(L, 1);
6102 return 1;
6103}
6104
6105/* Add a header into the reply object. Each header name is associated to an
6106 * array of values in the "headers" table. If the header name is not found, a
6107 * new entry is created.
6108 */
6109__LJMP static int hlua_txn_reply_add_header(lua_State *L)
6110{
6111 const char *name = MAY_LJMP(luaL_checkstring(L, 2));
6112 const char *value = MAY_LJMP(luaL_checkstring(L, 3));
6113 int ret;
6114
6115 /* First argument (self) must be a table */
6116 luaL_checktype(L, 1, LUA_TTABLE);
6117
6118 /* Push in the stack the "headers" entry. */
6119 ret = lua_getfield(L, 1, "headers");
6120 if (ret != LUA_TTABLE) {
6121 hlua_pusherror(L, "Reply['headers'] is expected to a an array. %s found", lua_typename(L, ret));
6122 WILL_LJMP(lua_error(L));
6123 }
6124
6125 /* check if the header is already registered. If not, register it. */
6126 ret = lua_getfield(L, -1, name);
6127 if (ret == LUA_TNIL) {
6128 /* Entry not found. */
6129 lua_pop(L, 1); /* remove the nil. The "headers" table is the top of the stack. */
6130
6131 /* Insert the new header name in the array in the top of the stack.
6132 * It left the new array in the top of the stack.
6133 */
6134 lua_newtable(L);
6135 lua_pushstring(L, name);
6136 lua_pushvalue(L, -2);
6137 lua_settable(L, -4);
6138 }
6139 else if (ret != LUA_TTABLE) {
6140 hlua_pusherror(L, "Reply['headers']['%s'] is expected to be an array. %s found", name, lua_typename(L, ret));
6141 WILL_LJMP(lua_error(L));
6142 }
6143
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07006144 /* Now the top of thestack is an array of values. We push
Christopher Faulet700d9e82020-01-31 12:21:52 +01006145 * the header value as new entry.
6146 */
6147 lua_pushstring(L, value);
6148 ret = lua_rawlen(L, -2);
6149 lua_rawseti(L, -2, ret + 1);
6150
6151 lua_pushboolean(L, 1);
6152 return 1;
6153}
6154
6155/* Remove all occurrences of a given header name. */
6156__LJMP static int hlua_txn_reply_del_header(lua_State *L)
6157{
6158 const char *name = MAY_LJMP(luaL_checkstring(L, 2));
6159 int ret;
6160
6161 /* First argument (self) must be a table */
6162 luaL_checktype(L, 1, LUA_TTABLE);
6163
6164 /* Push in the stack the "headers" entry. */
6165 ret = lua_getfield(L, 1, "headers");
6166 if (ret != LUA_TTABLE) {
6167 hlua_pusherror(L, "Reply['headers'] is expected to be an array. %s found", lua_typename(L, ret));
6168 WILL_LJMP(lua_error(L));
6169 }
6170
6171 lua_pushstring(L, name);
6172 lua_pushnil(L);
6173 lua_settable(L, -3);
6174
6175 lua_pushboolean(L, 1);
6176 return 1;
6177}
6178
6179/* Set the reply's body. Overwrite any existing entry. */
6180__LJMP static int hlua_txn_reply_set_body(lua_State *L)
6181{
6182 const char *payload = MAY_LJMP(luaL_checkstring(L, 2));
6183
6184 /* First argument (self) must be a table */
6185 luaL_checktype(L, 1, LUA_TTABLE);
6186
6187 lua_pushstring(L, payload);
6188 lua_setfield(L, 1, "body");
6189
6190 lua_pushboolean(L, 1);
6191 return 1;
6192}
6193
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01006194__LJMP static int hlua_log(lua_State *L)
6195{
6196 int level;
6197 const char *msg;
6198
6199 MAY_LJMP(check_args(L, 2, "log"));
6200 level = MAY_LJMP(luaL_checkinteger(L, 1));
6201 msg = MAY_LJMP(luaL_checkstring(L, 2));
6202
6203 if (level < 0 || level >= NB_LOG_LEVELS)
6204 WILL_LJMP(luaL_argerror(L, 1, "Invalid loglevel."));
6205
6206 hlua_sendlog(NULL, level, msg);
6207 return 0;
6208}
6209
6210__LJMP static int hlua_log_debug(lua_State *L)
6211{
6212 const char *msg;
6213
6214 MAY_LJMP(check_args(L, 1, "debug"));
6215 msg = MAY_LJMP(luaL_checkstring(L, 1));
6216 hlua_sendlog(NULL, LOG_DEBUG, msg);
6217 return 0;
6218}
6219
6220__LJMP static int hlua_log_info(lua_State *L)
6221{
6222 const char *msg;
6223
6224 MAY_LJMP(check_args(L, 1, "info"));
6225 msg = MAY_LJMP(luaL_checkstring(L, 1));
6226 hlua_sendlog(NULL, LOG_INFO, msg);
6227 return 0;
6228}
6229
6230__LJMP static int hlua_log_warning(lua_State *L)
6231{
6232 const char *msg;
6233
6234 MAY_LJMP(check_args(L, 1, "warning"));
6235 msg = MAY_LJMP(luaL_checkstring(L, 1));
6236 hlua_sendlog(NULL, LOG_WARNING, msg);
6237 return 0;
6238}
6239
6240__LJMP static int hlua_log_alert(lua_State *L)
6241{
6242 const char *msg;
6243
6244 MAY_LJMP(check_args(L, 1, "alert"));
6245 msg = MAY_LJMP(luaL_checkstring(L, 1));
6246 hlua_sendlog(NULL, LOG_ALERT, msg);
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01006247 return 0;
6248}
6249
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01006250__LJMP static int hlua_sleep_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006251{
6252 int wakeup_ms = lua_tointeger(L, -1);
6253 if (now_ms < wakeup_ms)
Willy Tarreau9635e032018-10-16 17:52:55 +02006254 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_sleep_yield, wakeup_ms, 0));
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006255 return 0;
6256}
6257
6258__LJMP static int hlua_sleep(lua_State *L)
6259{
6260 unsigned int delay;
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006261 unsigned int wakeup_ms;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006262
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006263 MAY_LJMP(check_args(L, 1, "sleep"));
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006264
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01006265 delay = MAY_LJMP(luaL_checkinteger(L, 1)) * 1000;
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006266 wakeup_ms = tick_add(now_ms, delay);
6267 lua_pushinteger(L, wakeup_ms);
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006268
Willy Tarreau9635e032018-10-16 17:52:55 +02006269 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_sleep_yield, wakeup_ms, 0));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006270 return 0;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006271}
6272
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006273__LJMP static int hlua_msleep(lua_State *L)
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006274{
6275 unsigned int delay;
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006276 unsigned int wakeup_ms;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006277
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006278 MAY_LJMP(check_args(L, 1, "msleep"));
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006279
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01006280 delay = MAY_LJMP(luaL_checkinteger(L, 1));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006281 wakeup_ms = tick_add(now_ms, delay);
6282 lua_pushinteger(L, wakeup_ms);
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006283
Willy Tarreau9635e032018-10-16 17:52:55 +02006284 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_sleep_yield, wakeup_ms, 0));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006285 return 0;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006286}
6287
Thierry FOURNIER13416fe2015-02-17 15:01:59 +01006288/* This functionis an LUA binding. it permits to give back
6289 * the hand at the HAProxy scheduler. It is used when the
6290 * LUA processing consumes a lot of time.
6291 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01006292__LJMP static int hlua_yield_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006293{
6294 return 0;
6295}
6296
Thierry FOURNIER13416fe2015-02-17 15:01:59 +01006297__LJMP static int hlua_yield(lua_State *L)
6298{
Willy Tarreau9635e032018-10-16 17:52:55 +02006299 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_yield_yield, TICK_ETERNITY, HLUA_CTRLYIELD));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006300 return 0;
Thierry FOURNIER13416fe2015-02-17 15:01:59 +01006301}
6302
Thierry FOURNIER37196f42015-02-16 19:34:56 +01006303/* This function change the nice of the currently executed
6304 * task. It is used set low or high priority at the current
6305 * task.
6306 */
Willy Tarreau59551662015-03-10 14:23:13 +01006307__LJMP static int hlua_set_nice(lua_State *L)
Thierry FOURNIER37196f42015-02-16 19:34:56 +01006308{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01006309 struct hlua *hlua;
6310 int nice;
Thierry FOURNIER37196f42015-02-16 19:34:56 +01006311
Willy Tarreau80f5fae2015-02-27 16:38:20 +01006312 MAY_LJMP(check_args(L, 1, "set_nice"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01006313 nice = MAY_LJMP(luaL_checkinteger(L, 1));
Thierry FOURNIER37196f42015-02-16 19:34:56 +01006314
Thierry Fournier4234dbd2020-11-28 13:18:23 +01006315 /* Get hlua struct, or NULL if we execute from main lua state */
6316 hlua = hlua_gethlua(L);
6317
6318 /* If the task is not set, I'm in a start mode. */
Thierry FOURNIER37196f42015-02-16 19:34:56 +01006319 if (!hlua || !hlua->task)
6320 return 0;
6321
6322 if (nice < -1024)
6323 nice = -1024;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01006324 else if (nice > 1024)
Thierry FOURNIER37196f42015-02-16 19:34:56 +01006325 nice = 1024;
6326
6327 hlua->task->nice = nice;
6328 return 0;
6329}
6330
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08006331/* This function is used as a callback of a task. It is called by the
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006332 * HAProxy task subsystem when the task is awaked. The LUA runtime can
6333 * return an E_AGAIN signal, the emmiter of this signal must set a
6334 * signal to wake the task.
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006335 *
6336 * Task wrapper are longjmp safe because the only one Lua code
6337 * executed is the safe hlua_ctx_resume();
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006338 */
Willy Tarreau144f84a2021-03-02 16:09:26 +01006339struct task *hlua_process_task(struct task *task, void *context, unsigned int state)
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006340{
Olivier Houchard9f6af332018-05-25 14:04:04 +02006341 struct hlua *hlua = context;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006342 enum hlua_exec status;
6343
Christopher Faulet5bc99722018-04-25 10:34:45 +02006344 if (task->thread_mask == MAX_THREADS_MASK)
6345 task_set_affinity(task, tid_bit);
6346
Thierry FOURNIERbd413492015-03-03 16:52:26 +01006347 /* If it is the first call to the task, we must initialize the
6348 * execution timeouts.
6349 */
6350 if (!HLUA_IS_RUNNING(hlua))
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02006351 hlua->max_time = hlua_timeout_task;
Thierry FOURNIERbd413492015-03-03 16:52:26 +01006352
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006353 /* Execute the Lua code. */
6354 status = hlua_ctx_resume(hlua, 1);
6355
6356 switch (status) {
6357 /* finished or yield */
6358 case HLUA_E_OK:
6359 hlua_ctx_destroy(hlua);
Olivier Houchard3f795f72019-04-17 22:51:06 +02006360 task_destroy(task);
Tim Duesterhuscd235c62018-04-24 13:56:01 +02006361 task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006362 break;
6363
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01006364 case HLUA_E_AGAIN: /* co process or timeout wake me later. */
Thierry FOURNIERcb146882017-12-10 17:10:57 +01006365 notification_gc(&hlua->com);
PiBa-NLfe971b32018-05-02 22:27:14 +02006366 task->expire = hlua->wake_time;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006367 break;
6368
6369 /* finished with error. */
6370 case HLUA_E_ERRMSG:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006371 SEND_ERR(NULL, "Lua task: %s.\n", lua_tostring(hlua->T, -1));
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006372 hlua_ctx_destroy(hlua);
Olivier Houchard3f795f72019-04-17 22:51:06 +02006373 task_destroy(task);
Emeric Brun253e53e2017-10-17 18:58:40 +02006374 task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006375 break;
6376
6377 case HLUA_E_ERR:
6378 default:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006379 SEND_ERR(NULL, "Lua task: unknown error.\n");
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006380 hlua_ctx_destroy(hlua);
Olivier Houchard3f795f72019-04-17 22:51:06 +02006381 task_destroy(task);
Emeric Brun253e53e2017-10-17 18:58:40 +02006382 task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006383 break;
6384 }
Emeric Brun253e53e2017-10-17 18:58:40 +02006385 return task;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006386}
6387
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01006388/* This function is an LUA binding that register LUA function to be
6389 * executed after the HAProxy configuration parsing and before the
6390 * HAProxy scheduler starts. This function expect only one LUA
6391 * argument that is a function. This function returns nothing, but
6392 * throws if an error is encountered.
6393 */
6394__LJMP static int hlua_register_init(lua_State *L)
6395{
6396 struct hlua_init_function *init;
6397 int ref;
6398
6399 MAY_LJMP(check_args(L, 1, "register_init"));
6400
6401 ref = MAY_LJMP(hlua_checkfunction(L, 1));
6402
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02006403 init = calloc(1, sizeof(*init));
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01006404 if (!init)
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01006405 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01006406
6407 init->function_ref = ref;
Willy Tarreau2b718102021-04-21 07:32:39 +02006408 LIST_APPEND(&hlua_init_functions[hlua_state_id], &init->l);
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01006409 return 0;
6410}
6411
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006412/* This functio is an LUA binding. It permits to register a task
6413 * executed in parallel of the main HAroxy activity. The task is
6414 * created and it is set in the HAProxy scheduler. It can be called
6415 * from the "init" section, "post init" or during the runtime.
6416 *
6417 * Lua prototype:
6418 *
6419 * <none> core.register_task(<function>)
6420 */
6421static int hlua_register_task(lua_State *L)
6422{
Christopher Faulet5294ec02021-04-12 12:24:47 +02006423 struct hlua *hlua = NULL;
6424 struct task *task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006425 int ref;
Thierry Fournier021d9862020-11-28 23:42:03 +01006426 int state_id;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006427
6428 MAY_LJMP(check_args(L, 1, "register_task"));
6429
6430 ref = MAY_LJMP(hlua_checkfunction(L, 1));
6431
Thierry Fournier75fc0292020-11-28 13:18:56 +01006432 /* Get the reference state. If the reference is NULL, L is the master
6433 * state, otherwise hlua->T is.
6434 */
6435 hlua = hlua_gethlua(L);
6436 if (hlua)
Thierry Fournier021d9862020-11-28 23:42:03 +01006437 /* we are in runtime processing */
6438 state_id = hlua->state_id;
Thierry Fournier75fc0292020-11-28 13:18:56 +01006439 else
Thierry Fournier021d9862020-11-28 23:42:03 +01006440 /* we are in initialization mode */
Thierry Fournierc7492592020-11-28 23:57:24 +01006441 state_id = hlua_state_id;
Thierry Fournier75fc0292020-11-28 13:18:56 +01006442
Willy Tarreaubafbe012017-11-24 17:34:44 +01006443 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006444 if (!hlua)
Christopher Faulet5294ec02021-04-12 12:24:47 +02006445 goto alloc_error;
Christopher Faulet1e8433f2021-03-24 15:03:01 +01006446 HLUA_INIT(hlua);
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006447
Thierry Fournier59f11be2020-11-29 00:37:41 +01006448 /* We are in the common lua state, execute the task anywhere,
6449 * otherwise, inherit the current thread identifier
6450 */
6451 if (state_id == 0)
6452 task = task_new(MAX_THREADS_MASK);
6453 else
6454 task = task_new(tid_bit);
Willy Tarreaue09101e2018-10-16 17:37:12 +02006455 if (!task)
Christopher Faulet5294ec02021-04-12 12:24:47 +02006456 goto alloc_error;
Willy Tarreaue09101e2018-10-16 17:37:12 +02006457
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006458 task->context = hlua;
6459 task->process = hlua_process_task;
6460
Thierry Fournier021d9862020-11-28 23:42:03 +01006461 if (!hlua_ctx_init(hlua, state_id, task, 1))
Christopher Faulet5294ec02021-04-12 12:24:47 +02006462 goto alloc_error;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006463
6464 /* Restore the function in the stack. */
6465 lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, ref);
6466 hlua->nargs = 0;
6467
6468 /* Schedule task. */
6469 task_schedule(task, now_ms);
6470
6471 return 0;
Christopher Faulet5294ec02021-04-12 12:24:47 +02006472
6473 alloc_error:
6474 task_destroy(task);
6475 hlua_ctx_destroy(hlua);
6476 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
6477 return 0; /* Never reached */
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006478}
6479
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006480/* Wrapper called by HAProxy to execute an LUA converter. This wrapper
6481 * doesn't allow "yield" functions because the HAProxy engine cannot
6482 * resume converters.
6483 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02006484static int hlua_sample_conv_wrapper(const struct arg *arg_p, struct sample *smp, void *private)
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006485{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02006486 struct hlua_function *fcn = private;
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02006487 struct stream *stream = smp->strm;
Thierry Fournierfd107a22016-02-19 19:57:23 +01006488 const char *error;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006489
Willy Tarreaube508f12016-03-10 11:47:01 +01006490 if (!stream)
6491 return 0;
6492
Willy Tarreau87b09662015-04-03 00:22:06 +02006493 /* In the execution wrappers linked with a stream, the
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01006494 * Lua context can be not initialized. This behavior
6495 * permits to save performances because a systematic
6496 * Lua initialization cause 5% performances loss.
6497 */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006498 if (!stream->hlua) {
Christopher Faulet1e8433f2021-03-24 15:03:01 +01006499 struct hlua *hlua;
6500
6501 hlua = pool_alloc(pool_head_hlua);
6502 if (!hlua) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006503 SEND_ERR(stream->be, "Lua converter '%s': can't initialize Lua context.\n", fcn->name);
6504 return 0;
6505 }
Christopher Faulet1e8433f2021-03-24 15:03:01 +01006506 HLUA_INIT(hlua);
6507 stream->hlua = hlua;
Thierry Fournierc7492592020-11-28 23:57:24 +01006508 if (!hlua_ctx_init(stream->hlua, fcn_ref_to_stack_id(fcn), stream->task, 0)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006509 SEND_ERR(stream->be, "Lua converter '%s': can't initialize Lua context.\n", fcn->name);
6510 return 0;
6511 }
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01006512 }
6513
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006514 /* If it is the first run, initialize the data for the call. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006515 if (!HLUA_IS_RUNNING(stream->hlua)) {
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006516
6517 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006518 if (!SET_SAFE_LJMP(stream->hlua)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006519 if (lua_type(stream->hlua->T, -1) == LUA_TSTRING)
6520 error = lua_tostring(stream->hlua->T, -1);
Thierry Fournierfd107a22016-02-19 19:57:23 +01006521 else
6522 error = "critical error";
6523 SEND_ERR(stream->be, "Lua converter '%s': %s.\n", fcn->name, error);
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006524 return 0;
6525 }
6526
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006527 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006528 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006529 SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006530 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006531 return 0;
6532 }
6533
6534 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +01006535 lua_rawgeti(stream->hlua->T, LUA_REGISTRYINDEX, fcn->function_ref[stream->hlua->state_id]);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006536
6537 /* convert input sample and pust-it in the stack. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006538 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006539 SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006540 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006541 return 0;
6542 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006543 hlua_smp2lua(stream->hlua->T, smp);
6544 stream->hlua->nargs = 1;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006545
6546 /* push keywords in the stack. */
6547 if (arg_p) {
6548 for (; arg_p->type != ARGT_STOP; arg_p++) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006549 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006550 SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006551 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006552 return 0;
6553 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006554 hlua_arg2lua(stream->hlua->T, arg_p);
6555 stream->hlua->nargs++;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006556 }
6557 }
6558
Thierry FOURNIERbd413492015-03-03 16:52:26 +01006559 /* We must initialize the execution timeouts. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006560 stream->hlua->max_time = hlua_timeout_session;
Thierry FOURNIERbd413492015-03-03 16:52:26 +01006561
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006562 /* At this point the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006563 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006564 }
6565
6566 /* Execute the function. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006567 switch (hlua_ctx_resume(stream->hlua, 0)) {
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006568 /* finished. */
6569 case HLUA_E_OK:
Thierry FOURNIERfd80df12017-05-12 16:32:20 +02006570 /* If the stack is empty, the function fails. */
6571 if (lua_gettop(stream->hlua->T) <= 0)
6572 return 0;
6573
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006574 /* Convert the returned value in sample. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006575 hlua_lua2smp(stream->hlua->T, -1, smp);
6576 lua_pop(stream->hlua->T, 1);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006577 return 1;
6578
6579 /* yield. */
6580 case HLUA_E_AGAIN:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006581 SEND_ERR(stream->be, "Lua converter '%s': cannot use yielded functions.\n", fcn->name);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006582 return 0;
6583
6584 /* finished with error. */
6585 case HLUA_E_ERRMSG:
6586 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006587 SEND_ERR(stream->be, "Lua converter '%s': %s.\n",
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006588 fcn->name, lua_tostring(stream->hlua->T, -1));
6589 lua_pop(stream->hlua->T, 1);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006590 return 0;
6591
Thierry Fournierd5b073c2018-05-21 19:42:47 +02006592 case HLUA_E_ETMOUT:
6593 SEND_ERR(stream->be, "Lua converter '%s': execution timeout.\n", fcn->name);
6594 return 0;
6595
6596 case HLUA_E_NOMEM:
6597 SEND_ERR(stream->be, "Lua converter '%s': out of memory error.\n", fcn->name);
6598 return 0;
6599
6600 case HLUA_E_YIELD:
6601 SEND_ERR(stream->be, "Lua converter '%s': yield functions like core.tcp() or core.sleep() are not allowed.\n", fcn->name);
6602 return 0;
6603
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006604 case HLUA_E_ERR:
6605 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006606 SEND_ERR(stream->be, "Lua converter '%s' returns an unknown error.\n", fcn->name);
Tim Duesterhus588b3142020-05-29 14:35:51 +02006607 /* fall through */
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006608
6609 default:
6610 return 0;
6611 }
6612}
6613
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006614/* Wrapper called by HAProxy to execute a sample-fetch. this wrapper
6615 * doesn't allow "yield" functions because the HAProxy engine cannot
Willy Tarreaube508f12016-03-10 11:47:01 +01006616 * resume sample-fetches. This function will be called by the sample
6617 * fetch engine to call lua-based fetch operations.
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006618 */
Thierry FOURNIER0786d052015-05-11 15:42:45 +02006619static int hlua_sample_fetch_wrapper(const struct arg *arg_p, struct sample *smp,
6620 const char *kw, void *private)
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006621{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02006622 struct hlua_function *fcn = private;
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02006623 struct stream *stream = smp->strm;
Thierry Fournierfd107a22016-02-19 19:57:23 +01006624 const char *error;
Christopher Fauletbfab2dd2019-07-26 15:09:53 +02006625 unsigned int hflags = HLUA_TXN_NOTERM;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006626
Willy Tarreaube508f12016-03-10 11:47:01 +01006627 if (!stream)
6628 return 0;
Christopher Fauletafd8f102018-11-08 11:34:21 +01006629
Willy Tarreau87b09662015-04-03 00:22:06 +02006630 /* In the execution wrappers linked with a stream, the
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01006631 * Lua context can be not initialized. This behavior
6632 * permits to save performances because a systematic
6633 * Lua initialization cause 5% performances loss.
6634 */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006635 if (!stream->hlua) {
Christopher Faulet1e8433f2021-03-24 15:03:01 +01006636 struct hlua *hlua;
6637
6638 hlua = pool_alloc(pool_head_hlua);
6639 if (!hlua) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006640 SEND_ERR(stream->be, "Lua sample-fetch '%s': can't initialize Lua context.\n", fcn->name);
6641 return 0;
6642 }
Christopher Faulet1e8433f2021-03-24 15:03:01 +01006643 hlua->T = NULL;
6644 stream->hlua = hlua;
Thierry Fournierc7492592020-11-28 23:57:24 +01006645 if (!hlua_ctx_init(stream->hlua, fcn_ref_to_stack_id(fcn), stream->task, 0)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006646 SEND_ERR(stream->be, "Lua sample-fetch '%s': can't initialize Lua context.\n", fcn->name);
6647 return 0;
6648 }
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01006649 }
6650
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006651 /* If it is the first run, initialize the data for the call. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006652 if (!HLUA_IS_RUNNING(stream->hlua)) {
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006653
6654 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006655 if (!SET_SAFE_LJMP(stream->hlua)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006656 if (lua_type(stream->hlua->T, -1) == LUA_TSTRING)
6657 error = lua_tostring(stream->hlua->T, -1);
Thierry Fournierfd107a22016-02-19 19:57:23 +01006658 else
6659 error = "critical error";
6660 SEND_ERR(smp->px, "Lua sample-fetch '%s': %s.\n", fcn->name, error);
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006661 return 0;
6662 }
6663
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006664 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006665 if (!lua_checkstack(stream->hlua->T, 2)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006666 SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006667 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006668 return 0;
6669 }
6670
6671 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +01006672 lua_rawgeti(stream->hlua->T, LUA_REGISTRYINDEX, fcn->function_ref[stream->hlua->state_id]);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006673
6674 /* push arguments in the stack. */
Christopher Fauletbfab2dd2019-07-26 15:09:53 +02006675 if (!hlua_txn_new(stream->hlua->T, stream, smp->px, smp->opt & SMP_OPT_DIR, hflags)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006676 SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006677 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006678 return 0;
6679 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006680 stream->hlua->nargs = 1;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006681
6682 /* push keywords in the stack. */
6683 for (; arg_p && arg_p->type != ARGT_STOP; arg_p++) {
6684 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006685 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006686 SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006687 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006688 return 0;
6689 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006690 hlua_arg2lua(stream->hlua->T, arg_p);
6691 stream->hlua->nargs++;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006692 }
6693
Thierry FOURNIERbd413492015-03-03 16:52:26 +01006694 /* We must initialize the execution timeouts. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006695 stream->hlua->max_time = hlua_timeout_session;
Thierry FOURNIERbd413492015-03-03 16:52:26 +01006696
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006697 /* At this point the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006698 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006699 }
6700
6701 /* Execute the function. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006702 switch (hlua_ctx_resume(stream->hlua, 0)) {
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006703 /* finished. */
6704 case HLUA_E_OK:
Thierry FOURNIERfd80df12017-05-12 16:32:20 +02006705 /* If the stack is empty, the function fails. */
6706 if (lua_gettop(stream->hlua->T) <= 0)
6707 return 0;
6708
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006709 /* Convert the returned value in sample. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006710 hlua_lua2smp(stream->hlua->T, -1, smp);
6711 lua_pop(stream->hlua->T, 1);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006712
6713 /* Set the end of execution flag. */
6714 smp->flags &= ~SMP_F_MAY_CHANGE;
6715 return 1;
6716
6717 /* yield. */
6718 case HLUA_E_AGAIN:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006719 SEND_ERR(smp->px, "Lua sample-fetch '%s': cannot use yielded functions.\n", fcn->name);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006720 return 0;
6721
6722 /* finished with error. */
6723 case HLUA_E_ERRMSG:
6724 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006725 SEND_ERR(smp->px, "Lua sample-fetch '%s': %s.\n",
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006726 fcn->name, lua_tostring(stream->hlua->T, -1));
6727 lua_pop(stream->hlua->T, 1);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006728 return 0;
6729
Thierry Fournierd5b073c2018-05-21 19:42:47 +02006730 case HLUA_E_ETMOUT:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02006731 SEND_ERR(smp->px, "Lua sample-fetch '%s': execution timeout.\n", fcn->name);
6732 return 0;
6733
6734 case HLUA_E_NOMEM:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02006735 SEND_ERR(smp->px, "Lua sample-fetch '%s': out of memory error.\n", fcn->name);
6736 return 0;
6737
6738 case HLUA_E_YIELD:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02006739 SEND_ERR(smp->px, "Lua sample-fetch '%s': yield not allowed.\n", fcn->name);
6740 return 0;
6741
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006742 case HLUA_E_ERR:
6743 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006744 SEND_ERR(smp->px, "Lua sample-fetch '%s' returns an unknown error.\n", fcn->name);
Tim Duesterhus588b3142020-05-29 14:35:51 +02006745 /* fall through */
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006746
6747 default:
6748 return 0;
6749 }
6750}
6751
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006752/* This function is an LUA binding used for registering
6753 * "sample-conv" functions. It expects a converter name used
6754 * in the haproxy configuration file, and an LUA function.
6755 */
6756__LJMP static int hlua_register_converters(lua_State *L)
6757{
6758 struct sample_conv_kw_list *sck;
6759 const char *name;
6760 int ref;
6761 int len;
Christopher Fauletaa224302021-04-12 14:08:21 +02006762 struct hlua_function *fcn = NULL;
Thierry Fournierf67442e2020-11-28 20:41:07 +01006763 struct sample_conv *sc;
6764 struct buffer *trash;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006765
6766 MAY_LJMP(check_args(L, 2, "register_converters"));
6767
6768 /* First argument : converter name. */
6769 name = MAY_LJMP(luaL_checkstring(L, 1));
6770
6771 /* Second argument : lua function. */
6772 ref = MAY_LJMP(hlua_checkfunction(L, 2));
6773
Thierry Fournierf67442e2020-11-28 20:41:07 +01006774 /* Check if the converter is already registered */
6775 trash = get_trash_chunk();
6776 chunk_printf(trash, "lua.%s", name);
6777 sc = find_sample_conv(trash->area, trash->data);
6778 if (sc != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +01006779 fcn = sc->private;
6780 if (fcn->function_ref[hlua_state_id] != -1) {
6781 ha_warning("Trying to register converter 'lua.%s' more than once. "
6782 "This will become a hard error in version 2.5.\n", name);
6783 }
6784 fcn->function_ref[hlua_state_id] = ref;
6785 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +01006786 }
6787
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006788 /* Allocate and fill the sample fetch keyword struct. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02006789 sck = calloc(1, sizeof(*sck) + sizeof(struct sample_conv) * 2);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006790 if (!sck)
Christopher Fauletaa224302021-04-12 14:08:21 +02006791 goto alloc_error;
Thierry Fournier62a22aa2020-11-28 21:06:35 +01006792 fcn = new_hlua_function();
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006793 if (!fcn)
Christopher Fauletaa224302021-04-12 14:08:21 +02006794 goto alloc_error;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006795
6796 /* Fill fcn. */
6797 fcn->name = strdup(name);
6798 if (!fcn->name)
Christopher Fauletaa224302021-04-12 14:08:21 +02006799 goto alloc_error;
Thierry Fournierc7492592020-11-28 23:57:24 +01006800 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006801
6802 /* List head */
6803 sck->list.n = sck->list.p = NULL;
6804
6805 /* converter keyword. */
6806 len = strlen("lua.") + strlen(name) + 1;
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02006807 sck->kw[0].kw = calloc(1, len);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006808 if (!sck->kw[0].kw)
Christopher Fauletaa224302021-04-12 14:08:21 +02006809 goto alloc_error;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006810
6811 snprintf((char *)sck->kw[0].kw, len, "lua.%s", name);
6812 sck->kw[0].process = hlua_sample_conv_wrapper;
David Carlier0c437f42016-04-27 16:21:56 +01006813 sck->kw[0].arg_mask = ARG12(0,STR,STR,STR,STR,STR,STR,STR,STR,STR,STR,STR,STR);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006814 sck->kw[0].val_args = NULL;
6815 sck->kw[0].in_type = SMP_T_STR;
6816 sck->kw[0].out_type = SMP_T_STR;
6817 sck->kw[0].private = fcn;
6818
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006819 /* Register this new converter */
6820 sample_register_convs(sck);
6821
6822 return 0;
Christopher Fauletaa224302021-04-12 14:08:21 +02006823
6824 alloc_error:
6825 release_hlua_function(fcn);
6826 ha_free(&sck);
6827 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
6828 return 0; /* Never reached */
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006829}
6830
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08006831/* This function is an LUA binding used for registering
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006832 * "sample-fetch" functions. It expects a converter name used
6833 * in the haproxy configuration file, and an LUA function.
6834 */
6835__LJMP static int hlua_register_fetches(lua_State *L)
6836{
6837 const char *name;
6838 int ref;
6839 int len;
6840 struct sample_fetch_kw_list *sfk;
Christopher Faulet2567f182021-04-12 14:11:50 +02006841 struct hlua_function *fcn = NULL;
Thierry Fournierf67442e2020-11-28 20:41:07 +01006842 struct sample_fetch *sf;
6843 struct buffer *trash;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006844
6845 MAY_LJMP(check_args(L, 2, "register_fetches"));
6846
6847 /* First argument : sample-fetch name. */
6848 name = MAY_LJMP(luaL_checkstring(L, 1));
6849
6850 /* Second argument : lua function. */
6851 ref = MAY_LJMP(hlua_checkfunction(L, 2));
6852
Thierry Fournierf67442e2020-11-28 20:41:07 +01006853 /* Check if the sample-fetch is already registered */
6854 trash = get_trash_chunk();
6855 chunk_printf(trash, "lua.%s", name);
6856 sf = find_sample_fetch(trash->area, trash->data);
6857 if (sf != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +01006858 fcn = sf->private;
6859 if (fcn->function_ref[hlua_state_id] != -1) {
6860 ha_warning("Trying to register sample-fetch 'lua.%s' more than once. "
6861 "This will become a hard error in version 2.5.\n", name);
6862 }
6863 fcn->function_ref[hlua_state_id] = ref;
6864 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +01006865 }
6866
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006867 /* Allocate and fill the sample fetch keyword struct. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02006868 sfk = calloc(1, sizeof(*sfk) + sizeof(struct sample_fetch) * 2);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006869 if (!sfk)
Christopher Faulet2567f182021-04-12 14:11:50 +02006870 goto alloc_error;
Thierry Fournier62a22aa2020-11-28 21:06:35 +01006871 fcn = new_hlua_function();
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006872 if (!fcn)
Christopher Faulet2567f182021-04-12 14:11:50 +02006873 goto alloc_error;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006874
6875 /* Fill fcn. */
6876 fcn->name = strdup(name);
6877 if (!fcn->name)
Christopher Faulet2567f182021-04-12 14:11:50 +02006878 goto alloc_error;
Thierry Fournierc7492592020-11-28 23:57:24 +01006879 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006880
6881 /* List head */
6882 sfk->list.n = sfk->list.p = NULL;
6883
6884 /* sample-fetch keyword. */
6885 len = strlen("lua.") + strlen(name) + 1;
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02006886 sfk->kw[0].kw = calloc(1, len);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006887 if (!sfk->kw[0].kw)
Christopher Faulet2567f182021-04-12 14:11:50 +02006888 goto alloc_error;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006889
6890 snprintf((char *)sfk->kw[0].kw, len, "lua.%s", name);
6891 sfk->kw[0].process = hlua_sample_fetch_wrapper;
David Carlier0c437f42016-04-27 16:21:56 +01006892 sfk->kw[0].arg_mask = ARG12(0,STR,STR,STR,STR,STR,STR,STR,STR,STR,STR,STR,STR);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006893 sfk->kw[0].val_args = NULL;
6894 sfk->kw[0].out_type = SMP_T_STR;
6895 sfk->kw[0].use = SMP_USE_HTTP_ANY;
6896 sfk->kw[0].val = 0;
6897 sfk->kw[0].private = fcn;
6898
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006899 /* Register this new fetch. */
6900 sample_register_fetches(sfk);
6901
6902 return 0;
Christopher Faulet2567f182021-04-12 14:11:50 +02006903
6904 alloc_error:
6905 release_hlua_function(fcn);
6906 ha_free(&sfk);
6907 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
6908 return 0; /* Never reached */
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006909}
6910
Christopher Faulet501465d2020-02-26 14:54:16 +01006911/* This function is a lua binding to set the wake_time.
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01006912 */
Christopher Faulet501465d2020-02-26 14:54:16 +01006913__LJMP static int hlua_set_wake_time(lua_State *L)
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01006914{
Thierry Fournier4234dbd2020-11-28 13:18:23 +01006915 struct hlua *hlua;
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01006916 unsigned int delay;
6917 unsigned int wakeup_ms;
6918
Thierry Fournier4234dbd2020-11-28 13:18:23 +01006919 /* Get hlua struct, or NULL if we execute from main lua state */
6920 hlua = hlua_gethlua(L);
6921 if (!hlua) {
6922 return 0;
6923 }
6924
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01006925 MAY_LJMP(check_args(L, 1, "wake_time"));
6926
6927 delay = MAY_LJMP(luaL_checkinteger(L, 1));
6928 wakeup_ms = tick_add(now_ms, delay);
6929 hlua->wake_time = wakeup_ms;
6930 return 0;
6931}
6932
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006933/* This function is a wrapper to execute each LUA function declared as an action
6934 * wrapper during the initialisation period. This function may return any
6935 * ACT_RET_* value. On error ACT_RET_CONT is returned and the action is
6936 * ignored. If the lua action yields, ACT_RET_YIELD is returned. On success, the
6937 * return value is the first element on the stack.
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006938 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02006939static enum act_return hlua_action(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02006940 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006941{
6942 char **arg;
Christopher Fauletbfab2dd2019-07-26 15:09:53 +02006943 unsigned int hflags = 0;
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006944 int dir, act_ret = ACT_RET_CONT;
Thierry Fournierfd107a22016-02-19 19:57:23 +01006945 const char *error;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02006946
6947 switch (rule->from) {
Christopher Fauletd8f0e072020-02-25 09:45:51 +01006948 case ACT_F_TCP_REQ_CNT: dir = SMP_OPT_DIR_REQ; break;
6949 case ACT_F_TCP_RES_CNT: dir = SMP_OPT_DIR_RES; break;
6950 case ACT_F_HTTP_REQ: dir = SMP_OPT_DIR_REQ; break;
6951 case ACT_F_HTTP_RES: dir = SMP_OPT_DIR_RES; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02006952 default:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006953 SEND_ERR(px, "Lua: internal error while execute action.\n");
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006954 goto end;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02006955 }
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006956
Willy Tarreau87b09662015-04-03 00:22:06 +02006957 /* In the execution wrappers linked with a stream, the
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01006958 * Lua context can be not initialized. This behavior
6959 * permits to save performances because a systematic
6960 * Lua initialization cause 5% performances loss.
6961 */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006962 if (!s->hlua) {
Christopher Faulet1e8433f2021-03-24 15:03:01 +01006963 struct hlua *hlua;
6964
6965 hlua = pool_alloc(pool_head_hlua);
6966 if (!hlua) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006967 SEND_ERR(px, "Lua action '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01006968 rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006969 goto end;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006970 }
Christopher Faulet1e8433f2021-03-24 15:03:01 +01006971 HLUA_INIT(hlua);
6972 s->hlua = hlua;
Thierry Fournierc7492592020-11-28 23:57:24 +01006973 if (!hlua_ctx_init(s->hlua, fcn_ref_to_stack_id(rule->arg.hlua_rule->fcn), s->task, 0)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006974 SEND_ERR(px, "Lua action '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01006975 rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006976 goto end;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006977 }
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01006978 }
6979
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006980 /* If it is the first run, initialize the data for the call. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006981 if (!HLUA_IS_RUNNING(s->hlua)) {
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006982
6983 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006984 if (!SET_SAFE_LJMP(s->hlua)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006985 if (lua_type(s->hlua->T, -1) == LUA_TSTRING)
6986 error = lua_tostring(s->hlua->T, -1);
Thierry Fournierfd107a22016-02-19 19:57:23 +01006987 else
6988 error = "critical error";
6989 SEND_ERR(px, "Lua function '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01006990 rule->arg.hlua_rule->fcn->name, error);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006991 goto end;
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006992 }
6993
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01006994 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006995 if (!lua_checkstack(s->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006996 SEND_ERR(px, "Lua function '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01006997 rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006998 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01006999 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007000 }
7001
7002 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +01007003 lua_rawgeti(s->hlua->T, LUA_REGISTRYINDEX, rule->arg.hlua_rule->fcn->function_ref[s->hlua->state_id]);
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007004
Willy Tarreau87b09662015-04-03 00:22:06 +02007005 /* Create and and push object stream in the stack. */
Christopher Fauletbfab2dd2019-07-26 15:09:53 +02007006 if (!hlua_txn_new(s->hlua->T, s, px, dir, hflags)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02007007 SEND_ERR(px, "Lua function '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007008 rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007009 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007010 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007011 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01007012 s->hlua->nargs = 1;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007013
7014 /* push keywords in the stack. */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007015 for (arg = rule->arg.hlua_rule->args; arg && *arg; arg++) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01007016 if (!lua_checkstack(s->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02007017 SEND_ERR(px, "Lua function '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007018 rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007019 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007020 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007021 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01007022 lua_pushstring(s->hlua->T, *arg);
7023 s->hlua->nargs++;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007024 }
7025
Thierry FOURNIERbabae282015-09-17 11:36:37 +02007026 /* Now the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007027 RESET_SAFE_LJMP(s->hlua);
Thierry FOURNIERbabae282015-09-17 11:36:37 +02007028
Thierry FOURNIERbd413492015-03-03 16:52:26 +01007029 /* We must initialize the execution timeouts. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01007030 s->hlua->max_time = hlua_timeout_session;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007031 }
7032
7033 /* Execute the function. */
Christopher Faulet105ba6c2019-12-18 14:41:51 +01007034 switch (hlua_ctx_resume(s->hlua, !(flags & ACT_OPT_FINAL))) {
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007035 /* finished. */
7036 case HLUA_E_OK:
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007037 /* Catch the return value */
7038 if (lua_gettop(s->hlua->T) > 0)
7039 act_ret = lua_tointeger(s->hlua->T, -1);
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007040
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01007041 /* Set timeout in the required channel. */
Christopher Faulet498c4832020-07-28 11:59:58 +02007042 if (act_ret == ACT_RET_YIELD) {
7043 if (flags & ACT_OPT_FINAL)
7044 goto err_yield;
7045
Christopher Faulet8f587ea2020-07-28 12:01:55 +02007046 if (dir == SMP_OPT_DIR_REQ)
7047 s->req.analyse_exp = tick_first((tick_is_expired(s->req.analyse_exp, now_ms) ? 0 : s->req.analyse_exp),
7048 s->hlua->wake_time);
7049 else
7050 s->res.analyse_exp = tick_first((tick_is_expired(s->res.analyse_exp, now_ms) ? 0 : s->res.analyse_exp),
7051 s->hlua->wake_time);
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01007052 }
7053 goto end;
7054
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007055 /* yield. */
7056 case HLUA_E_AGAIN:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01007057 /* Set timeout in the required channel. */
Christopher Faulet8f587ea2020-07-28 12:01:55 +02007058 if (dir == SMP_OPT_DIR_REQ)
7059 s->req.analyse_exp = tick_first((tick_is_expired(s->req.analyse_exp, now_ms) ? 0 : s->req.analyse_exp),
7060 s->hlua->wake_time);
7061 else
7062 s->res.analyse_exp = tick_first((tick_is_expired(s->res.analyse_exp, now_ms) ? 0 : s->res.analyse_exp),
7063 s->hlua->wake_time);
7064
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007065 /* Some actions can be wake up when a "write" event
7066 * is detected on a response channel. This is useful
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08007067 * only for actions targeted on the requests.
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007068 */
Christopher Faulet51fa3582019-07-26 14:54:52 +02007069 if (HLUA_IS_WAKERESWR(s->hlua))
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01007070 s->res.flags |= CF_WAKE_WRITE;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01007071 if (HLUA_IS_WAKEREQWR(s->hlua))
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01007072 s->req.flags |= CF_WAKE_WRITE;
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007073 act_ret = ACT_RET_YIELD;
7074 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007075
7076 /* finished with error. */
7077 case HLUA_E_ERRMSG:
7078 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02007079 SEND_ERR(px, "Lua function '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007080 rule->arg.hlua_rule->fcn->name, lua_tostring(s->hlua->T, -1));
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01007081 lua_pop(s->hlua->T, 1);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007082 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007083
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007084 case HLUA_E_ETMOUT:
Thierry Fournierad5345f2020-11-29 02:05:57 +01007085 SEND_ERR(px, "Lua function '%s': execution timeout.\n", rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007086 goto end;
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007087
7088 case HLUA_E_NOMEM:
Thierry Fournierad5345f2020-11-29 02:05:57 +01007089 SEND_ERR(px, "Lua function '%s': out of memory error.\n", rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007090 goto end;
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007091
7092 case HLUA_E_YIELD:
Christopher Faulet498c4832020-07-28 11:59:58 +02007093 err_yield:
7094 act_ret = ACT_RET_CONT;
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007095 SEND_ERR(px, "Lua function '%s': aborting Lua processing on expired timeout.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007096 rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007097 goto end;
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007098
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007099 case HLUA_E_ERR:
7100 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02007101 SEND_ERR(px, "Lua function '%s' return an unknown error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007102 rule->arg.hlua_rule->fcn->name);
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007103
7104 default:
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007105 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007106 }
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007107
7108 end:
Christopher Faulet2361fd92020-07-30 10:40:58 +02007109 if (act_ret != ACT_RET_YIELD && s->hlua)
Christopher Faulet8f587ea2020-07-28 12:01:55 +02007110 s->hlua->wake_time = TICK_ETERNITY;
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007111 return act_ret;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007112}
7113
Willy Tarreau144f84a2021-03-02 16:09:26 +01007114struct task *hlua_applet_wakeup(struct task *t, void *context, unsigned int state)
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007115{
Olivier Houchard9f6af332018-05-25 14:04:04 +02007116 struct appctx *ctx = context;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007117
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007118 appctx_wakeup(ctx);
Willy Tarreaud9587412017-08-23 16:07:33 +02007119 t->expire = TICK_ETERNITY;
Willy Tarreaud1aa41f2017-07-21 16:41:56 +02007120 return t;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007121}
7122
7123static int hlua_applet_tcp_init(struct appctx *ctx, struct proxy *px, struct stream *strm)
7124{
7125 struct stream_interface *si = ctx->owner;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007126 struct hlua *hlua;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007127 struct task *task;
7128 char **arg;
Thierry Fournierfd107a22016-02-19 19:57:23 +01007129 const char *error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007130
Willy Tarreaubafbe012017-11-24 17:34:44 +01007131 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007132 if (!hlua) {
7133 SEND_ERR(px, "Lua applet tcp '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007134 ctx->rule->arg.hlua_rule->fcn->name);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007135 return 0;
7136 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007137 HLUA_INIT(hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007138 ctx->ctx.hlua_apptcp.hlua = hlua;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007139 ctx->ctx.hlua_apptcp.flags = 0;
7140
7141 /* Create task used by signal to wakeup applets. */
Willy Tarreau5f4a47b2017-10-31 15:59:32 +01007142 task = task_new(tid_bit);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007143 if (!task) {
7144 SEND_ERR(px, "Lua applet tcp '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007145 ctx->rule->arg.hlua_rule->fcn->name);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007146 return 0;
7147 }
7148 task->nice = 0;
7149 task->context = ctx;
7150 task->process = hlua_applet_wakeup;
7151 ctx->ctx.hlua_apptcp.task = task;
7152
7153 /* In the execution wrappers linked with a stream, the
7154 * Lua context can be not initialized. This behavior
7155 * permits to save performances because a systematic
7156 * Lua initialization cause 5% performances loss.
7157 */
Thierry Fournierc7492592020-11-28 23:57:24 +01007158 if (!hlua_ctx_init(hlua, fcn_ref_to_stack_id(ctx->rule->arg.hlua_rule->fcn), task, 0)) {
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007159 SEND_ERR(px, "Lua applet tcp '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007160 ctx->rule->arg.hlua_rule->fcn->name);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007161 return 0;
7162 }
7163
7164 /* Set timeout according with the applet configuration. */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02007165 hlua->max_time = ctx->applet->timeout;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007166
7167 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007168 if (!SET_SAFE_LJMP(hlua)) {
Thierry Fournierfd107a22016-02-19 19:57:23 +01007169 if (lua_type(hlua->T, -1) == LUA_TSTRING)
7170 error = lua_tostring(hlua->T, -1);
7171 else
7172 error = "critical error";
7173 SEND_ERR(px, "Lua applet tcp '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007174 ctx->rule->arg.hlua_rule->fcn->name, error);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007175 return 0;
7176 }
7177
7178 /* Check stack available size. */
7179 if (!lua_checkstack(hlua->T, 1)) {
7180 SEND_ERR(px, "Lua applet tcp '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007181 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007182 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007183 return 0;
7184 }
7185
7186 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +01007187 lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, ctx->rule->arg.hlua_rule->fcn->function_ref[hlua->state_id]);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007188
7189 /* Create and and push object stream in the stack. */
7190 if (!hlua_applet_tcp_new(hlua->T, ctx)) {
7191 SEND_ERR(px, "Lua applet tcp '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007192 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007193 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007194 return 0;
7195 }
7196 hlua->nargs = 1;
7197
7198 /* push keywords in the stack. */
7199 for (arg = ctx->rule->arg.hlua_rule->args; arg && *arg; arg++) {
7200 if (!lua_checkstack(hlua->T, 1)) {
7201 SEND_ERR(px, "Lua applet tcp '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007202 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007203 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007204 return 0;
7205 }
7206 lua_pushstring(hlua->T, *arg);
7207 hlua->nargs++;
7208 }
7209
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007210 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007211
7212 /* Wakeup the applet ASAP. */
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01007213 si_cant_get(si);
Willy Tarreau3367d412018-11-15 10:57:41 +01007214 si_rx_endp_more(si);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007215
7216 return 1;
7217}
7218
Willy Tarreau60409db2019-08-21 14:14:50 +02007219void hlua_applet_tcp_fct(struct appctx *ctx)
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007220{
7221 struct stream_interface *si = ctx->owner;
7222 struct stream *strm = si_strm(si);
7223 struct channel *res = si_ic(si);
7224 struct act_rule *rule = ctx->rule;
7225 struct proxy *px = strm->be;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007226 struct hlua *hlua = ctx->ctx.hlua_apptcp.hlua;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007227
7228 /* The applet execution is already done. */
Olivier Houchard594c8c52018-08-28 14:41:31 +02007229 if (ctx->ctx.hlua_apptcp.flags & APPLET_DONE) {
7230 /* eat the whole request */
7231 co_skip(si_oc(si), co_data(si_oc(si)));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007232 return;
Olivier Houchard594c8c52018-08-28 14:41:31 +02007233 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007234
7235 /* If the stream is disconnect or closed, ldo nothing. */
7236 if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO))
7237 return;
7238
7239 /* Execute the function. */
7240 switch (hlua_ctx_resume(hlua, 1)) {
7241 /* finished. */
7242 case HLUA_E_OK:
7243 ctx->ctx.hlua_apptcp.flags |= APPLET_DONE;
7244
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007245 /* eat the whole request */
Willy Tarreaua79021a2018-06-15 18:07:57 +02007246 co_skip(si_oc(si), co_data(si_oc(si)));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007247 res->flags |= CF_READ_NULL;
7248 si_shutr(si);
7249 return;
7250
7251 /* yield. */
7252 case HLUA_E_AGAIN:
Thierry Fournier0164f202016-02-20 17:47:43 +01007253 if (hlua->wake_time != TICK_ETERNITY)
7254 task_schedule(ctx->ctx.hlua_apptcp.task, hlua->wake_time);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007255 return;
7256
7257 /* finished with error. */
7258 case HLUA_E_ERRMSG:
7259 /* Display log. */
7260 SEND_ERR(px, "Lua applet tcp '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007261 rule->arg.hlua_rule->fcn->name, lua_tostring(hlua->T, -1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007262 lua_pop(hlua->T, 1);
7263 goto error;
7264
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007265 case HLUA_E_ETMOUT:
7266 SEND_ERR(px, "Lua applet tcp '%s': execution timeout.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007267 rule->arg.hlua_rule->fcn->name);
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007268 goto error;
7269
7270 case HLUA_E_NOMEM:
7271 SEND_ERR(px, "Lua applet tcp '%s': out of memory error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007272 rule->arg.hlua_rule->fcn->name);
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007273 goto error;
7274
7275 case HLUA_E_YIELD: /* unexpected */
7276 SEND_ERR(px, "Lua applet tcp '%s': yield not allowed.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007277 rule->arg.hlua_rule->fcn->name);
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007278 goto error;
7279
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007280 case HLUA_E_ERR:
7281 /* Display log. */
7282 SEND_ERR(px, "Lua applet tcp '%s' return an unknown error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007283 rule->arg.hlua_rule->fcn->name);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007284 goto error;
7285
7286 default:
7287 goto error;
7288 }
7289
7290error:
7291
7292 /* For all other cases, just close the stream. */
7293 si_shutw(si);
7294 si_shutr(si);
7295 ctx->ctx.hlua_apptcp.flags |= APPLET_DONE;
7296}
7297
7298static void hlua_applet_tcp_release(struct appctx *ctx)
7299{
Olivier Houchard3f795f72019-04-17 22:51:06 +02007300 task_destroy(ctx->ctx.hlua_apptcp.task);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007301 ctx->ctx.hlua_apptcp.task = NULL;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007302 hlua_ctx_destroy(ctx->ctx.hlua_apptcp.hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007303 ctx->ctx.hlua_apptcp.hlua = NULL;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007304}
7305
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007306/* The function returns 1 if the initialisation is complete, 0 if
7307 * an errors occurs and -1 if more data are required for initializing
7308 * the applet.
7309 */
7310static int hlua_applet_http_init(struct appctx *ctx, struct proxy *px, struct stream *strm)
7311{
7312 struct stream_interface *si = ctx->owner;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007313 struct http_txn *txn;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007314 struct hlua *hlua;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007315 char **arg;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007316 struct task *task;
Thierry Fournierfd107a22016-02-19 19:57:23 +01007317 const char *error;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007318
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007319 txn = strm->txn;
Willy Tarreaubafbe012017-11-24 17:34:44 +01007320 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007321 if (!hlua) {
7322 SEND_ERR(px, "Lua applet http '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007323 ctx->rule->arg.hlua_rule->fcn->name);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007324 return 0;
7325 }
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007326 HLUA_INIT(hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007327 ctx->ctx.hlua_apphttp.hlua = hlua;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007328 ctx->ctx.hlua_apphttp.left_bytes = -1;
7329 ctx->ctx.hlua_apphttp.flags = 0;
7330
Thierry FOURNIERd93ea2b2015-12-20 19:14:52 +01007331 if (txn->req.flags & HTTP_MSGF_VER_11)
7332 ctx->ctx.hlua_apphttp.flags |= APPLET_HTTP11;
7333
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007334 /* Create task used by signal to wakeup applets. */
Willy Tarreau5f4a47b2017-10-31 15:59:32 +01007335 task = task_new(tid_bit);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007336 if (!task) {
7337 SEND_ERR(px, "Lua applet http '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007338 ctx->rule->arg.hlua_rule->fcn->name);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007339 return 0;
7340 }
7341 task->nice = 0;
7342 task->context = ctx;
7343 task->process = hlua_applet_wakeup;
7344 ctx->ctx.hlua_apphttp.task = task;
7345
7346 /* In the execution wrappers linked with a stream, the
7347 * Lua context can be not initialized. This behavior
7348 * permits to save performances because a systematic
7349 * Lua initialization cause 5% performances loss.
7350 */
Thierry Fournierc7492592020-11-28 23:57:24 +01007351 if (!hlua_ctx_init(hlua, fcn_ref_to_stack_id(ctx->rule->arg.hlua_rule->fcn), task, 0)) {
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007352 SEND_ERR(px, "Lua applet http '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007353 ctx->rule->arg.hlua_rule->fcn->name);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007354 return 0;
7355 }
7356
7357 /* Set timeout according with the applet configuration. */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02007358 hlua->max_time = ctx->applet->timeout;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007359
7360 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007361 if (!SET_SAFE_LJMP(hlua)) {
Thierry Fournierfd107a22016-02-19 19:57:23 +01007362 if (lua_type(hlua->T, -1) == LUA_TSTRING)
7363 error = lua_tostring(hlua->T, -1);
7364 else
7365 error = "critical error";
7366 SEND_ERR(px, "Lua applet http '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007367 ctx->rule->arg.hlua_rule->fcn->name, error);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007368 return 0;
7369 }
7370
7371 /* Check stack available size. */
7372 if (!lua_checkstack(hlua->T, 1)) {
7373 SEND_ERR(px, "Lua applet http '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007374 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007375 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007376 return 0;
7377 }
7378
7379 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +01007380 lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, ctx->rule->arg.hlua_rule->fcn->function_ref[hlua->state_id]);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007381
7382 /* Create and and push object stream in the stack. */
7383 if (!hlua_applet_http_new(hlua->T, ctx)) {
7384 SEND_ERR(px, "Lua applet http '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007385 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007386 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007387 return 0;
7388 }
7389 hlua->nargs = 1;
7390
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007391 /* push keywords in the stack. */
7392 for (arg = ctx->rule->arg.hlua_rule->args; arg && *arg; arg++) {
7393 if (!lua_checkstack(hlua->T, 1)) {
7394 SEND_ERR(px, "Lua applet http '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007395 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007396 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007397 return 0;
7398 }
7399 lua_pushstring(hlua->T, *arg);
7400 hlua->nargs++;
7401 }
7402
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007403 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007404
7405 /* Wakeup the applet when data is ready for read. */
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01007406 si_cant_get(si);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007407
7408 return 1;
7409}
7410
Willy Tarreau60409db2019-08-21 14:14:50 +02007411void hlua_applet_http_fct(struct appctx *ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007412{
7413 struct stream_interface *si = ctx->owner;
7414 struct stream *strm = si_strm(si);
7415 struct channel *req = si_oc(si);
7416 struct channel *res = si_ic(si);
7417 struct act_rule *rule = ctx->rule;
7418 struct proxy *px = strm->be;
7419 struct hlua *hlua = ctx->ctx.hlua_apphttp.hlua;
7420 struct htx *req_htx, *res_htx;
7421
7422 res_htx = htx_from_buf(&res->buf);
7423
7424 /* If the stream is disconnect or closed, ldo nothing. */
7425 if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO))
7426 goto out;
7427
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05007428 /* Check if the input buffer is available. */
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007429 if (!b_size(&res->buf)) {
7430 si_rx_room_blk(si);
7431 goto out;
7432 }
7433 /* check that the output is not closed */
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01007434 if (res->flags & (CF_SHUTW|CF_SHUTW_NOW|CF_SHUTR))
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007435 ctx->ctx.hlua_apphttp.flags |= APPLET_DONE;
7436
7437 /* Set the currently running flag. */
7438 if (!HLUA_IS_RUNNING(hlua) &&
7439 !(ctx->ctx.hlua_apphttp.flags & APPLET_DONE)) {
Christopher Fauletbd878d22021-04-28 10:50:21 +02007440 if (!co_data(req)) {
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007441 si_cant_get(si);
7442 goto out;
7443 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007444 }
7445
7446 /* Executes The applet if it is not done. */
7447 if (!(ctx->ctx.hlua_apphttp.flags & APPLET_DONE)) {
7448
7449 /* Execute the function. */
7450 switch (hlua_ctx_resume(hlua, 1)) {
7451 /* finished. */
7452 case HLUA_E_OK:
7453 ctx->ctx.hlua_apphttp.flags |= APPLET_DONE;
7454 break;
7455
7456 /* yield. */
7457 case HLUA_E_AGAIN:
7458 if (hlua->wake_time != TICK_ETERNITY)
7459 task_schedule(ctx->ctx.hlua_apphttp.task, hlua->wake_time);
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01007460 goto out;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007461
7462 /* finished with error. */
7463 case HLUA_E_ERRMSG:
7464 /* Display log. */
7465 SEND_ERR(px, "Lua applet http '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007466 rule->arg.hlua_rule->fcn->name, lua_tostring(hlua->T, -1));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007467 lua_pop(hlua->T, 1);
7468 goto error;
7469
7470 case HLUA_E_ETMOUT:
7471 SEND_ERR(px, "Lua applet http '%s': execution timeout.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007472 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007473 goto error;
7474
7475 case HLUA_E_NOMEM:
7476 SEND_ERR(px, "Lua applet http '%s': out of memory error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007477 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007478 goto error;
7479
7480 case HLUA_E_YIELD: /* unexpected */
7481 SEND_ERR(px, "Lua applet http '%s': yield not allowed.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007482 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007483 goto error;
7484
7485 case HLUA_E_ERR:
7486 /* Display log. */
7487 SEND_ERR(px, "Lua applet http '%s' return an unknown error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007488 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007489 goto error;
7490
7491 default:
7492 goto error;
7493 }
7494 }
7495
7496 if (ctx->ctx.hlua_apphttp.flags & APPLET_DONE) {
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01007497 if (ctx->ctx.hlua_apphttp.flags & APPLET_RSP_SENT)
7498 goto done;
7499
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007500 if (!(ctx->ctx.hlua_apphttp.flags & APPLET_HDR_SENT))
7501 goto error;
7502
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01007503 /* no more data are expected. Don't add TLR because mux-h1 will take care of it */
7504 res_htx->flags |= HTX_FL_EOM;
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01007505 strm->txn->status = ctx->ctx.hlua_apphttp.status;
7506 ctx->ctx.hlua_apphttp.flags |= APPLET_RSP_SENT;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007507 }
7508
7509 done:
7510 if (ctx->ctx.hlua_apphttp.flags & APPLET_DONE) {
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01007511 if (!(res->flags & CF_SHUTR)) {
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007512 res->flags |= CF_READ_NULL;
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01007513 si_shutr(si);
7514 }
7515
7516 /* eat the whole request */
7517 if (co_data(req)) {
7518 req_htx = htx_from_buf(&req->buf);
7519 co_htx_skip(req, req_htx, co_data(req));
7520 htx_to_buf(req_htx, &req->buf);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007521 }
7522 }
7523
7524 out:
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007525 htx_to_buf(res_htx, &res->buf);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007526 return;
7527
7528 error:
7529
7530 /* If we are in HTTP mode, and we are not send any
7531 * data, return a 500 server error in best effort:
7532 * if there is no room available in the buffer,
7533 * just close the connection.
7534 */
7535 if (!(ctx->ctx.hlua_apphttp.flags & APPLET_HDR_SENT)) {
Christopher Fauletf7346382019-07-17 22:02:08 +02007536 struct buffer *err = &http_err_chunks[HTTP_ERR_500];
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007537
7538 channel_erase(res);
7539 res->buf.data = b_data(err);
7540 memcpy(res->buf.area, b_head(err), b_data(err));
7541 res_htx = htx_from_buf(&res->buf);
Christopher Fauletf6cce3f2019-02-27 21:20:09 +01007542 channel_add_input(res, res_htx->data);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007543 }
7544 if (!(strm->flags & SF_ERR_MASK))
7545 strm->flags |= SF_ERR_RESOURCE;
7546 ctx->ctx.hlua_apphttp.flags |= APPLET_DONE;
7547 goto done;
7548}
7549
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007550static void hlua_applet_http_release(struct appctx *ctx)
7551{
Olivier Houchard3f795f72019-04-17 22:51:06 +02007552 task_destroy(ctx->ctx.hlua_apphttp.task);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007553 ctx->ctx.hlua_apphttp.task = NULL;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007554 hlua_ctx_destroy(ctx->ctx.hlua_apphttp.hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007555 ctx->ctx.hlua_apphttp.hlua = NULL;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007556}
7557
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007558/* global {tcp|http}-request parser. Return ACT_RET_PRS_OK in
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05007559 * success case, else return ACT_RET_PRS_ERR.
Thierry FOURNIERbabae282015-09-17 11:36:37 +02007560 *
7561 * This function can fail with an abort() due to an Lua critical error.
7562 * We are in the configuration parsing process of HAProxy, this abort() is
7563 * tolerated.
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007564 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007565static enum act_parse_ret action_register_lua(const char **args, int *cur_arg, struct proxy *px,
7566 struct act_rule *rule, char **err)
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007567{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02007568 struct hlua_function *fcn = rule->kw->private;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007569 int i;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007570
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007571 /* Memory for the rule. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02007572 rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007573 if (!rule->arg.hlua_rule) {
7574 memprintf(err, "out of memory error");
Christopher Faulet528526f2021-04-12 14:37:32 +02007575 goto error;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007576 }
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007577
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007578 /* Memory for arguments. */
Tim Duesterhuse52b6e52020-09-12 20:26:43 +02007579 rule->arg.hlua_rule->args = calloc(fcn->nargs + 1,
7580 sizeof(*rule->arg.hlua_rule->args));
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007581 if (!rule->arg.hlua_rule->args) {
7582 memprintf(err, "out of memory error");
Christopher Faulet528526f2021-04-12 14:37:32 +02007583 goto error;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007584 }
7585
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007586 /* Reference the Lua function and store the reference. */
Thierry Fournierad5345f2020-11-29 02:05:57 +01007587 rule->arg.hlua_rule->fcn = fcn;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007588
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007589 /* Expect some arguments */
7590 for (i = 0; i < fcn->nargs; i++) {
Thierry FOURNIER1725c2e2019-01-06 19:38:49 +01007591 if (*args[*cur_arg] == '\0') {
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007592 memprintf(err, "expect %d arguments", fcn->nargs);
Christopher Faulet528526f2021-04-12 14:37:32 +02007593 goto error;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007594 }
Thierry FOURNIER1725c2e2019-01-06 19:38:49 +01007595 rule->arg.hlua_rule->args[i] = strdup(args[*cur_arg]);
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007596 if (!rule->arg.hlua_rule->args[i]) {
7597 memprintf(err, "out of memory error");
Christopher Faulet528526f2021-04-12 14:37:32 +02007598 goto error;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007599 }
7600 (*cur_arg)++;
7601 }
7602 rule->arg.hlua_rule->args[i] = NULL;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007603
Thierry FOURNIER42148732015-09-02 17:17:33 +02007604 rule->action = ACT_CUSTOM;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007605 rule->action_ptr = hlua_action;
Thierry FOURNIERafa80492015-08-19 09:04:15 +02007606 return ACT_RET_PRS_OK;
Christopher Faulet528526f2021-04-12 14:37:32 +02007607
7608 error:
7609 if (rule->arg.hlua_rule) {
7610 if (rule->arg.hlua_rule->args) {
7611 for (i = 0; i < fcn->nargs; i++)
7612 ha_free(&rule->arg.hlua_rule->args[i]);
7613 ha_free(&rule->arg.hlua_rule->args);
7614 }
7615 ha_free(&rule->arg.hlua_rule);
7616 }
7617 return ACT_RET_PRS_ERR;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007618}
7619
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007620static enum act_parse_ret action_register_service_http(const char **args, int *cur_arg, struct proxy *px,
7621 struct act_rule *rule, char **err)
7622{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02007623 struct hlua_function *fcn = rule->kw->private;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007624
Thierry FOURNIER718e2a72015-12-20 20:13:14 +01007625 /* HTTP applets are forbidden in tcp-request rules.
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05007626 * HTTP applet request requires everything initialized by
Thierry FOURNIER718e2a72015-12-20 20:13:14 +01007627 * "http_process_request" (analyzer flag AN_REQ_HTTP_INNER).
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05007628 * The applet will be immediately initialized, but its before
Thierry FOURNIER718e2a72015-12-20 20:13:14 +01007629 * the call of this analyzer.
7630 */
7631 if (rule->from != ACT_F_HTTP_REQ) {
7632 memprintf(err, "HTTP applets are forbidden from 'tcp-request' rulesets");
7633 return ACT_RET_PRS_ERR;
7634 }
7635
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007636 /* Memory for the rule. */
7637 rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
7638 if (!rule->arg.hlua_rule) {
7639 memprintf(err, "out of memory error");
7640 return ACT_RET_PRS_ERR;
7641 }
7642
7643 /* Reference the Lua function and store the reference. */
Thierry Fournierad5345f2020-11-29 02:05:57 +01007644 rule->arg.hlua_rule->fcn = fcn;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007645
7646 /* TODO: later accept arguments. */
7647 rule->arg.hlua_rule->args = NULL;
7648
7649 /* Add applet pointer in the rule. */
7650 rule->applet.obj_type = OBJ_TYPE_APPLET;
7651 rule->applet.name = fcn->name;
7652 rule->applet.init = hlua_applet_http_init;
7653 rule->applet.fct = hlua_applet_http_fct;
7654 rule->applet.release = hlua_applet_http_release;
7655 rule->applet.timeout = hlua_timeout_applet;
7656
7657 return ACT_RET_PRS_OK;
7658}
7659
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007660/* This function is an LUA binding used for registering
7661 * "sample-conv" functions. It expects a converter name used
7662 * in the haproxy configuration file, and an LUA function.
7663 */
7664__LJMP static int hlua_register_action(lua_State *L)
7665{
Christopher Faulet4fc9da02021-04-12 15:08:12 +02007666 struct action_kw_list *akl = NULL;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007667 const char *name;
7668 int ref;
7669 int len;
Christopher Faulet4fc9da02021-04-12 15:08:12 +02007670 struct hlua_function *fcn = NULL;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007671 int nargs;
Thierry Fournierf67442e2020-11-28 20:41:07 +01007672 struct buffer *trash;
7673 struct action_kw *akw;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007674
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007675 /* Initialise the number of expected arguments at 0. */
7676 nargs = 0;
7677
7678 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
7679 WILL_LJMP(luaL_error(L, "'register_action' needs between 3 and 4 arguments"));
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007680
7681 /* First argument : converter name. */
7682 name = MAY_LJMP(luaL_checkstring(L, 1));
7683
7684 /* Second argument : environment. */
7685 if (lua_type(L, 2) != LUA_TTABLE)
7686 WILL_LJMP(luaL_error(L, "register_action: second argument must be a table of strings"));
7687
7688 /* Third argument : lua function. */
7689 ref = MAY_LJMP(hlua_checkfunction(L, 3));
7690
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08007691 /* Fourth argument : number of mandatory arguments expected on the configuration line. */
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007692 if (lua_gettop(L) >= 4)
7693 nargs = MAY_LJMP(luaL_checkinteger(L, 4));
7694
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08007695 /* browse the second argument as an array. */
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007696 lua_pushnil(L);
7697 while (lua_next(L, 2) != 0) {
7698 if (lua_type(L, -1) != LUA_TSTRING)
7699 WILL_LJMP(luaL_error(L, "register_action: second argument must be a table of strings"));
7700
Thierry Fournierf67442e2020-11-28 20:41:07 +01007701 /* Check if action exists */
7702 trash = get_trash_chunk();
7703 chunk_printf(trash, "lua.%s", name);
7704 if (strcmp(lua_tostring(L, -1), "tcp-req") == 0) {
7705 akw = tcp_req_cont_action(trash->area);
7706 } else if (strcmp(lua_tostring(L, -1), "tcp-res") == 0) {
7707 akw = tcp_res_cont_action(trash->area);
7708 } else if (strcmp(lua_tostring(L, -1), "http-req") == 0) {
7709 akw = action_http_req_custom(trash->area);
7710 } else if (strcmp(lua_tostring(L, -1), "http-res") == 0) {
7711 akw = action_http_res_custom(trash->area);
7712 } else {
7713 akw = NULL;
7714 }
7715 if (akw != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +01007716 fcn = akw->private;
7717 if (fcn->function_ref[hlua_state_id] != -1) {
7718 ha_warning("Trying to register action 'lua.%s' more than once. "
7719 "This will become a hard error in version 2.5.\n", name);
7720 }
7721 fcn->function_ref[hlua_state_id] = ref;
7722
7723 /* pop the environment string. */
7724 lua_pop(L, 1);
7725 continue;
Thierry Fournierf67442e2020-11-28 20:41:07 +01007726 }
7727
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007728 /* Check required environment. Only accepted "http" or "tcp". */
7729 /* Allocate and fill the sample fetch keyword struct. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02007730 akl = calloc(1, sizeof(*akl) + sizeof(struct action_kw) * 2);
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007731 if (!akl)
Christopher Faulet4fc9da02021-04-12 15:08:12 +02007732 goto alloc_error;;
Thierry Fournier62a22aa2020-11-28 21:06:35 +01007733 fcn = new_hlua_function();
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007734 if (!fcn)
Christopher Faulet4fc9da02021-04-12 15:08:12 +02007735 goto alloc_error;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007736
7737 /* Fill fcn. */
7738 fcn->name = strdup(name);
7739 if (!fcn->name)
Christopher Faulet4fc9da02021-04-12 15:08:12 +02007740 goto alloc_error;
Thierry Fournierc7492592020-11-28 23:57:24 +01007741 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007742
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07007743 /* Set the expected number of arguments. */
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007744 fcn->nargs = nargs;
7745
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007746 /* List head */
7747 akl->list.n = akl->list.p = NULL;
7748
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007749 /* action keyword. */
7750 len = strlen("lua.") + strlen(name) + 1;
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02007751 akl->kw[0].kw = calloc(1, len);
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007752 if (!akl->kw[0].kw)
Christopher Faulet4fc9da02021-04-12 15:08:12 +02007753 goto alloc_error;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007754
7755 snprintf((char *)akl->kw[0].kw, len, "lua.%s", name);
7756
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02007757 akl->kw[0].flags = 0;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007758 akl->kw[0].private = fcn;
7759 akl->kw[0].parse = action_register_lua;
7760
7761 /* select the action registering point. */
7762 if (strcmp(lua_tostring(L, -1), "tcp-req") == 0)
7763 tcp_req_cont_keywords_register(akl);
7764 else if (strcmp(lua_tostring(L, -1), "tcp-res") == 0)
7765 tcp_res_cont_keywords_register(akl);
7766 else if (strcmp(lua_tostring(L, -1), "http-req") == 0)
7767 http_req_keywords_register(akl);
7768 else if (strcmp(lua_tostring(L, -1), "http-res") == 0)
7769 http_res_keywords_register(akl);
Christopher Faulet4fc9da02021-04-12 15:08:12 +02007770 else {
7771 release_hlua_function(fcn);
7772 if (akl)
7773 ha_free((char **)&(akl->kw[0].kw));
7774 ha_free(&akl);
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01007775 WILL_LJMP(luaL_error(L, "Lua action environment '%s' is unknown. "
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007776 "'tcp-req', 'tcp-res', 'http-req' or 'http-res' "
7777 "are expected.", lua_tostring(L, -1)));
Christopher Faulet4fc9da02021-04-12 15:08:12 +02007778 }
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007779
7780 /* pop the environment string. */
7781 lua_pop(L, 1);
Christopher Faulet4fc9da02021-04-12 15:08:12 +02007782
7783 /* reset for next loop */
7784 akl = NULL;
7785 fcn = NULL;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007786 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007787 return ACT_RET_PRS_OK;
Christopher Faulet4fc9da02021-04-12 15:08:12 +02007788
7789 alloc_error:
7790 release_hlua_function(fcn);
7791 ha_free(&akl);
7792 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
7793 return 0; /* Never reached */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007794}
7795
7796static enum act_parse_ret action_register_service_tcp(const char **args, int *cur_arg, struct proxy *px,
7797 struct act_rule *rule, char **err)
7798{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02007799 struct hlua_function *fcn = rule->kw->private;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007800
Christopher Faulet280f85b2019-07-15 15:02:04 +02007801 if (px->mode == PR_MODE_HTTP) {
7802 memprintf(err, "Lua TCP services cannot be used on HTTP proxies");
Christopher Fauletafd8f102018-11-08 11:34:21 +01007803 return ACT_RET_PRS_ERR;
7804 }
7805
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007806 /* Memory for the rule. */
7807 rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
7808 if (!rule->arg.hlua_rule) {
7809 memprintf(err, "out of memory error");
7810 return ACT_RET_PRS_ERR;
7811 }
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007812
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007813 /* Reference the Lua function and store the reference. */
Thierry Fournierad5345f2020-11-29 02:05:57 +01007814 rule->arg.hlua_rule->fcn = fcn;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007815
7816 /* TODO: later accept arguments. */
7817 rule->arg.hlua_rule->args = NULL;
7818
7819 /* Add applet pointer in the rule. */
7820 rule->applet.obj_type = OBJ_TYPE_APPLET;
7821 rule->applet.name = fcn->name;
7822 rule->applet.init = hlua_applet_tcp_init;
7823 rule->applet.fct = hlua_applet_tcp_fct;
7824 rule->applet.release = hlua_applet_tcp_release;
7825 rule->applet.timeout = hlua_timeout_applet;
7826
7827 return 0;
7828}
7829
7830/* This function is an LUA binding used for registering
7831 * "sample-conv" functions. It expects a converter name used
7832 * in the haproxy configuration file, and an LUA function.
7833 */
7834__LJMP static int hlua_register_service(lua_State *L)
7835{
7836 struct action_kw_list *akl;
7837 const char *name;
7838 const char *env;
7839 int ref;
7840 int len;
Christopher Faulet5c028d72021-04-12 15:11:44 +02007841 struct hlua_function *fcn = NULL;
Thierry Fournierf67442e2020-11-28 20:41:07 +01007842 struct buffer *trash;
7843 struct action_kw *akw;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007844
7845 MAY_LJMP(check_args(L, 3, "register_service"));
7846
7847 /* First argument : converter name. */
7848 name = MAY_LJMP(luaL_checkstring(L, 1));
7849
7850 /* Second argument : environment. */
7851 env = MAY_LJMP(luaL_checkstring(L, 2));
7852
7853 /* Third argument : lua function. */
7854 ref = MAY_LJMP(hlua_checkfunction(L, 3));
7855
Thierry Fournierf67442e2020-11-28 20:41:07 +01007856 /* Check for service already registered */
7857 trash = get_trash_chunk();
7858 chunk_printf(trash, "lua.%s", name);
7859 akw = service_find(trash->area);
7860 if (akw != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +01007861 fcn = akw->private;
7862 if (fcn->function_ref[hlua_state_id] != -1) {
7863 ha_warning("Trying to register service 'lua.%s' more than once. "
7864 "This will become a hard error in version 2.5.\n", name);
7865 }
7866 fcn->function_ref[hlua_state_id] = ref;
7867 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +01007868 }
7869
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007870 /* Allocate and fill the sample fetch keyword struct. */
7871 akl = calloc(1, sizeof(*akl) + sizeof(struct action_kw) * 2);
7872 if (!akl)
Christopher Faulet5c028d72021-04-12 15:11:44 +02007873 goto alloc_error;
Thierry Fournier62a22aa2020-11-28 21:06:35 +01007874 fcn = new_hlua_function();
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007875 if (!fcn)
Christopher Faulet5c028d72021-04-12 15:11:44 +02007876 goto alloc_error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007877
7878 /* Fill fcn. */
7879 len = strlen("<lua.>") + strlen(name) + 1;
7880 fcn->name = calloc(1, len);
7881 if (!fcn->name)
Christopher Faulet5c028d72021-04-12 15:11:44 +02007882 goto alloc_error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007883 snprintf((char *)fcn->name, len, "<lua.%s>", name);
Thierry Fournierc7492592020-11-28 23:57:24 +01007884 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007885
7886 /* List head */
7887 akl->list.n = akl->list.p = NULL;
7888
7889 /* converter keyword. */
7890 len = strlen("lua.") + strlen(name) + 1;
7891 akl->kw[0].kw = calloc(1, len);
7892 if (!akl->kw[0].kw)
Christopher Faulet5c028d72021-04-12 15:11:44 +02007893 goto alloc_error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007894
7895 snprintf((char *)akl->kw[0].kw, len, "lua.%s", name);
7896
Thierry FOURNIER / OZON.IO02564fd2016-11-12 11:07:05 +01007897 /* Check required environment. Only accepted "http" or "tcp". */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007898 if (strcmp(env, "tcp") == 0)
7899 akl->kw[0].parse = action_register_service_tcp;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007900 else if (strcmp(env, "http") == 0)
7901 akl->kw[0].parse = action_register_service_http;
Christopher Faulet5c028d72021-04-12 15:11:44 +02007902 else {
7903 release_hlua_function(fcn);
7904 if (akl)
7905 ha_free((char **)&(akl->kw[0].kw));
7906 ha_free(&akl);
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01007907 WILL_LJMP(luaL_error(L, "Lua service environment '%s' is unknown. "
Eric Salamafe7456f2017-12-21 14:30:07 +01007908 "'tcp' or 'http' are expected.", env));
Christopher Faulet5c028d72021-04-12 15:11:44 +02007909 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007910
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02007911 akl->kw[0].flags = 0;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007912 akl->kw[0].private = fcn;
7913
7914 /* End of array. */
7915 memset(&akl->kw[1], 0, sizeof(*akl->kw));
7916
7917 /* Register this new converter */
7918 service_keywords_register(akl);
7919
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007920 return 0;
Christopher Faulet5c028d72021-04-12 15:11:44 +02007921
7922 alloc_error:
7923 release_hlua_function(fcn);
7924 ha_free(&akl);
7925 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
7926 return 0; /* Never reached */
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007927}
7928
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007929/* This function initialises Lua cli handler. It copies the
7930 * arguments in the Lua stack and create channel IO objects.
7931 */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02007932static int hlua_cli_parse_fct(char **args, char *payload, struct appctx *appctx, void *private)
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007933{
7934 struct hlua *hlua;
7935 struct hlua_function *fcn;
7936 int i;
7937 const char *error;
7938
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007939 fcn = private;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007940 appctx->ctx.hlua_cli.fcn = private;
7941
Willy Tarreaubafbe012017-11-24 17:34:44 +01007942 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007943 if (!hlua) {
7944 SEND_ERR(NULL, "Lua cli '%s': out of memory.\n", fcn->name);
Thierry FOURNIER1be34152016-12-17 12:09:51 +01007945 return 1;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007946 }
7947 HLUA_INIT(hlua);
7948 appctx->ctx.hlua_cli.hlua = hlua;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007949
7950 /* Create task used by signal to wakeup applets.
Ilya Shipitsind4259502020-04-08 01:07:56 +05007951 * We use the same wakeup function than the Lua applet_tcp and
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007952 * applet_http. It is absolutely compatible.
7953 */
Willy Tarreau5f4a47b2017-10-31 15:59:32 +01007954 appctx->ctx.hlua_cli.task = task_new(tid_bit);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007955 if (!appctx->ctx.hlua_cli.task) {
Thierry FOURNIERffbf5692016-12-16 11:14:06 +01007956 SEND_ERR(NULL, "Lua cli '%s': out of memory.\n", fcn->name);
Thierry FOURNIER1be34152016-12-17 12:09:51 +01007957 goto error;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007958 }
7959 appctx->ctx.hlua_cli.task->nice = 0;
7960 appctx->ctx.hlua_cli.task->context = appctx;
7961 appctx->ctx.hlua_cli.task->process = hlua_applet_wakeup;
7962
7963 /* Initialises the Lua context */
Thierry Fournierc7492592020-11-28 23:57:24 +01007964 if (!hlua_ctx_init(hlua, fcn_ref_to_stack_id(fcn), appctx->ctx.hlua_cli.task, 0)) {
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007965 SEND_ERR(NULL, "Lua cli '%s': can't initialize Lua context.\n", fcn->name);
Thierry FOURNIER1be34152016-12-17 12:09:51 +01007966 goto error;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007967 }
7968
7969 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007970 if (!SET_SAFE_LJMP(hlua)) {
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007971 if (lua_type(hlua->T, -1) == LUA_TSTRING)
7972 error = lua_tostring(hlua->T, -1);
7973 else
7974 error = "critical error";
7975 SEND_ERR(NULL, "Lua cli '%s': %s.\n", fcn->name, error);
7976 goto error;
7977 }
7978
7979 /* Check stack available size. */
7980 if (!lua_checkstack(hlua->T, 2)) {
7981 SEND_ERR(NULL, "Lua cli '%s': full stack.\n", fcn->name);
7982 goto error;
7983 }
7984
7985 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +01007986 lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, fcn->function_ref[hlua->state_id]);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007987
7988 /* Once the arguments parsed, the CLI is like an AppletTCP,
7989 * so push AppletTCP in the stack.
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01007990 */
7991 if (!hlua_applet_tcp_new(hlua->T, appctx)) {
7992 SEND_ERR(NULL, "Lua cli '%s': full stack.\n", fcn->name);
7993 goto error;
7994 }
7995 hlua->nargs = 1;
7996
7997 /* push keywords in the stack. */
7998 for (i = 0; *args[i]; i++) {
7999 /* Check stack available size. */
8000 if (!lua_checkstack(hlua->T, 1)) {
8001 SEND_ERR(NULL, "Lua cli '%s': full stack.\n", fcn->name);
8002 goto error;
8003 }
8004 lua_pushstring(hlua->T, args[i]);
8005 hlua->nargs++;
8006 }
8007
8008 /* We must initialize the execution timeouts. */
8009 hlua->max_time = hlua_timeout_session;
8010
8011 /* At this point the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008012 RESET_SAFE_LJMP(hlua);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008013
8014 /* It's ok */
8015 return 0;
8016
8017 /* It's not ok. */
8018error:
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008019 RESET_SAFE_LJMP(hlua);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008020 hlua_ctx_destroy(hlua);
Thierry FOURNIER1be34152016-12-17 12:09:51 +01008021 appctx->ctx.hlua_cli.hlua = NULL;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008022 return 1;
8023}
8024
8025static int hlua_cli_io_handler_fct(struct appctx *appctx)
8026{
8027 struct hlua *hlua;
8028 struct stream_interface *si;
8029 struct hlua_function *fcn;
8030
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01008031 hlua = appctx->ctx.hlua_cli.hlua;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008032 si = appctx->owner;
Willy Tarreau8ae4f752016-12-14 15:41:45 +01008033 fcn = appctx->ctx.hlua_cli.fcn;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008034
8035 /* If the stream is disconnect or closed, ldo nothing. */
8036 if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO))
8037 return 1;
8038
8039 /* Execute the function. */
8040 switch (hlua_ctx_resume(hlua, 1)) {
8041
8042 /* finished. */
8043 case HLUA_E_OK:
8044 return 1;
8045
8046 /* yield. */
8047 case HLUA_E_AGAIN:
8048 /* We want write. */
8049 if (HLUA_IS_WAKERESWR(hlua))
Willy Tarreaudb398432018-11-15 11:08:52 +01008050 si_rx_room_blk(si);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008051 /* Set the timeout. */
8052 if (hlua->wake_time != TICK_ETERNITY)
8053 task_schedule(hlua->task, hlua->wake_time);
8054 return 0;
8055
8056 /* finished with error. */
8057 case HLUA_E_ERRMSG:
8058 /* Display log. */
8059 SEND_ERR(NULL, "Lua cli '%s': %s.\n",
8060 fcn->name, lua_tostring(hlua->T, -1));
8061 lua_pop(hlua->T, 1);
8062 return 1;
8063
Thierry Fournierd5b073c2018-05-21 19:42:47 +02008064 case HLUA_E_ETMOUT:
8065 SEND_ERR(NULL, "Lua converter '%s': execution timeout.\n",
8066 fcn->name);
8067 return 1;
8068
8069 case HLUA_E_NOMEM:
8070 SEND_ERR(NULL, "Lua converter '%s': out of memory error.\n",
8071 fcn->name);
8072 return 1;
8073
8074 case HLUA_E_YIELD: /* unexpected */
8075 SEND_ERR(NULL, "Lua converter '%s': yield not allowed.\n",
8076 fcn->name);
8077 return 1;
8078
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008079 case HLUA_E_ERR:
8080 /* Display log. */
8081 SEND_ERR(NULL, "Lua cli '%s' return an unknown error.\n",
8082 fcn->name);
8083 return 1;
8084
8085 default:
8086 return 1;
8087 }
8088
8089 return 1;
8090}
8091
8092static void hlua_cli_io_release_fct(struct appctx *appctx)
8093{
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01008094 hlua_ctx_destroy(appctx->ctx.hlua_cli.hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01008095 appctx->ctx.hlua_cli.hlua = NULL;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008096}
8097
8098/* This function is an LUA binding used for registering
8099 * new keywords in the cli. It expects a list of keywords
8100 * which are the "path". It is limited to 5 keywords. A
8101 * description of the command, a function to be executed
8102 * for the parsing and a function for io handlers.
8103 */
8104__LJMP static int hlua_register_cli(lua_State *L)
8105{
8106 struct cli_kw_list *cli_kws;
8107 const char *message;
8108 int ref_io;
8109 int len;
Christopher Faulet3a9a12b2021-04-12 15:31:29 +02008110 struct hlua_function *fcn = NULL;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008111 int index;
8112 int i;
Thierry Fournierf67442e2020-11-28 20:41:07 +01008113 struct buffer *trash;
8114 const char *kw[5];
8115 struct cli_kw *cli_kw;
Christopher Faulet3a9a12b2021-04-12 15:31:29 +02008116 const char *errmsg;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008117
8118 MAY_LJMP(check_args(L, 3, "register_cli"));
8119
8120 /* First argument : an array of maximum 5 keywords. */
8121 if (!lua_istable(L, 1))
8122 WILL_LJMP(luaL_argerror(L, 1, "1st argument must be a table"));
8123
8124 /* Second argument : string with contextual message. */
8125 message = MAY_LJMP(luaL_checkstring(L, 2));
8126
8127 /* Third and fourth argument : lua function. */
8128 ref_io = MAY_LJMP(hlua_checkfunction(L, 3));
8129
Thierry Fournierf67442e2020-11-28 20:41:07 +01008130 /* Check for CLI service already registered */
8131 trash = get_trash_chunk();
8132 index = 0;
8133 lua_pushnil(L);
8134 memset(kw, 0, sizeof(kw));
8135 while (lua_next(L, 1) != 0) {
8136 if (index >= CLI_PREFIX_KW_NB)
8137 WILL_LJMP(luaL_argerror(L, 1, "1st argument must be a table with a maximum of 5 entries"));
8138 if (lua_type(L, -1) != LUA_TSTRING)
8139 WILL_LJMP(luaL_argerror(L, 1, "1st argument must be a table filled with strings"));
8140 kw[index] = lua_tostring(L, -1);
8141 if (index == 0)
8142 chunk_printf(trash, "%s", kw[index]);
8143 else
8144 chunk_appendf(trash, " %s", kw[index]);
8145 index++;
8146 lua_pop(L, 1);
8147 }
8148 cli_kw = cli_find_kw_exact((char **)kw);
8149 if (cli_kw != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +01008150 fcn = cli_kw->private;
8151 if (fcn->function_ref[hlua_state_id] != -1) {
8152 ha_warning("Trying to register CLI keyword 'lua.%s' more than once. "
8153 "This will become a hard error in version 2.5.\n", trash->area);
8154 }
8155 fcn->function_ref[hlua_state_id] = ref_io;
8156 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +01008157 }
8158
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008159 /* Allocate and fill the sample fetch keyword struct. */
8160 cli_kws = calloc(1, sizeof(*cli_kws) + sizeof(struct cli_kw) * 2);
Christopher Faulet3a9a12b2021-04-12 15:31:29 +02008161 if (!cli_kws) {
8162 errmsg = "Lua out of memory error.";
8163 goto error;
8164 }
Thierry Fournier62a22aa2020-11-28 21:06:35 +01008165 fcn = new_hlua_function();
Christopher Faulet3a9a12b2021-04-12 15:31:29 +02008166 if (!fcn) {
8167 errmsg = "Lua out of memory error.";
8168 goto error;
8169 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008170
8171 /* Fill path. */
8172 index = 0;
8173 lua_pushnil(L);
8174 while(lua_next(L, 1) != 0) {
Christopher Faulet3a9a12b2021-04-12 15:31:29 +02008175 if (index >= 5) {
8176 errmsg = "1st argument must be a table with a maximum of 5 entries";
8177 goto error;
8178 }
8179 if (lua_type(L, -1) != LUA_TSTRING) {
8180 errmsg = "1st argument must be a table filled with strings";
8181 goto error;
8182 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008183 cli_kws->kw[0].str_kw[index] = strdup(lua_tostring(L, -1));
Christopher Faulet3a9a12b2021-04-12 15:31:29 +02008184 if (!cli_kws->kw[0].str_kw[index]) {
8185 errmsg = "Lua out of memory error.";
8186 goto error;
8187 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008188 index++;
8189 lua_pop(L, 1);
8190 }
8191
8192 /* Copy help message. */
8193 cli_kws->kw[0].usage = strdup(message);
Christopher Faulet3a9a12b2021-04-12 15:31:29 +02008194 if (!cli_kws->kw[0].usage) {
8195 errmsg = "Lua out of memory error.";
8196 goto error;
8197 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008198
8199 /* Fill fcn io handler. */
8200 len = strlen("<lua.cli>") + 1;
8201 for (i = 0; i < index; i++)
8202 len += strlen(cli_kws->kw[0].str_kw[i]) + 1;
8203 fcn->name = calloc(1, len);
Christopher Faulet3a9a12b2021-04-12 15:31:29 +02008204 if (!fcn->name) {
8205 errmsg = "Lua out of memory error.";
8206 goto error;
8207 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008208 strncat((char *)fcn->name, "<lua.cli", len);
8209 for (i = 0; i < index; i++) {
8210 strncat((char *)fcn->name, ".", len);
8211 strncat((char *)fcn->name, cli_kws->kw[0].str_kw[i], len);
8212 }
8213 strncat((char *)fcn->name, ">", len);
Thierry Fournierc7492592020-11-28 23:57:24 +01008214 fcn->function_ref[hlua_state_id] = ref_io;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008215
8216 /* Fill last entries. */
8217 cli_kws->kw[0].private = fcn;
8218 cli_kws->kw[0].parse = hlua_cli_parse_fct;
8219 cli_kws->kw[0].io_handler = hlua_cli_io_handler_fct;
8220 cli_kws->kw[0].io_release = hlua_cli_io_release_fct;
8221
8222 /* Register this new converter */
8223 cli_register_kw(cli_kws);
8224
8225 return 0;
Christopher Faulet3a9a12b2021-04-12 15:31:29 +02008226
8227 error:
8228 release_hlua_function(fcn);
8229 if (cli_kws) {
8230 for (i = 0; i < index; i++)
8231 ha_free((char **)&(cli_kws->kw[0].str_kw[i]));
8232 ha_free((char **)&(cli_kws->kw[0].usage));
8233 }
8234 ha_free(&cli_kws);
8235 WILL_LJMP(luaL_error(L, errmsg));
8236 return 0; /* Never reached */
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008237}
8238
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008239static int hlua_read_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01008240 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008241 char **err, unsigned int *timeout)
8242{
8243 const char *error;
8244
8245 error = parse_time_err(args[1], timeout, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +02008246 if (error == PARSE_TIME_OVER) {
8247 memprintf(err, "timer overflow in argument <%s> to <%s> (maximum value is 2147483647 ms or ~24.8 days)",
8248 args[1], args[0]);
8249 return -1;
8250 }
8251 else if (error == PARSE_TIME_UNDER) {
8252 memprintf(err, "timer underflow in argument <%s> to <%s> (minimum non-null value is 1 ms)",
8253 args[1], args[0]);
8254 return -1;
8255 }
8256 else if (error) {
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008257 memprintf(err, "%s: invalid timeout", args[0]);
8258 return -1;
8259 }
8260 return 0;
8261}
8262
8263static int hlua_session_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01008264 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008265 char **err)
8266{
8267 return hlua_read_timeout(args, section_type, curpx, defpx,
8268 file, line, err, &hlua_timeout_session);
8269}
8270
8271static int hlua_task_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01008272 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008273 char **err)
8274{
8275 return hlua_read_timeout(args, section_type, curpx, defpx,
8276 file, line, err, &hlua_timeout_task);
8277}
8278
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02008279static int hlua_applet_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01008280 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02008281 char **err)
8282{
8283 return hlua_read_timeout(args, section_type, curpx, defpx,
8284 file, line, err, &hlua_timeout_applet);
8285}
8286
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01008287static int hlua_forced_yield(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01008288 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01008289 char **err)
8290{
8291 char *error;
8292
8293 hlua_nb_instruction = strtoll(args[1], &error, 10);
8294 if (*error != '\0') {
8295 memprintf(err, "%s: invalid number", args[0]);
8296 return -1;
8297 }
8298 return 0;
8299}
8300
Willy Tarreau32f61e22015-03-18 17:54:59 +01008301static int hlua_parse_maxmem(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01008302 const struct proxy *defpx, const char *file, int line,
Willy Tarreau32f61e22015-03-18 17:54:59 +01008303 char **err)
8304{
8305 char *error;
8306
8307 if (*(args[1]) == 0) {
8308 memprintf(err, "'%s' expects an integer argument (Lua memory size in MB).\n", args[0]);
8309 return -1;
8310 }
8311 hlua_global_allocator.limit = strtoll(args[1], &error, 10) * 1024L * 1024L;
8312 if (*error != '\0') {
8313 memprintf(err, "%s: invalid number %s (error at '%c')", args[0], args[1], *error);
8314 return -1;
8315 }
8316 return 0;
8317}
8318
8319
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008320/* This function is called by the main configuration key "lua-load". It loads and
8321 * execute an lua file during the parsing of the HAProxy configuration file. It is
8322 * the main lua entry point.
8323 *
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08008324 * This function runs with the HAProxy keywords API. It returns -1 if an error
8325 * occurs, otherwise it returns 0.
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008326 *
8327 * In some error case, LUA set an error message in top of the stack. This function
8328 * returns this error message in the HAProxy logs and pop it from the stack.
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008329 *
8330 * This function can fail with an abort() due to an Lua critical error.
8331 * We are in the configuration parsing process of HAProxy, this abort() is
8332 * tolerated.
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008333 */
Thierry Fournierc93c15c2020-11-28 15:02:13 +01008334static int hlua_load_state(char *filename, lua_State *L, char **err)
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008335{
8336 int error;
8337
8338 /* Just load and compile the file. */
Thierry Fournierc93c15c2020-11-28 15:02:13 +01008339 error = luaL_loadfile(L, filename);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008340 if (error) {
Thierry Fournierc93c15c2020-11-28 15:02:13 +01008341 memprintf(err, "error in Lua file '%s': %s", filename, lua_tostring(L, -1));
8342 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008343 return -1;
8344 }
8345
8346 /* If no syntax error where detected, execute the code. */
Thierry Fournierc93c15c2020-11-28 15:02:13 +01008347 error = lua_pcall(L, 0, LUA_MULTRET, 0);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008348 switch (error) {
8349 case LUA_OK:
8350 break;
8351 case LUA_ERRRUN:
Thierry Fournierc93c15c2020-11-28 15:02:13 +01008352 memprintf(err, "Lua runtime error: %s\n", lua_tostring(L, -1));
8353 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008354 return -1;
8355 case LUA_ERRMEM:
Thierry Fournierde6145f2020-11-29 00:55:53 +01008356 memprintf(err, "Lua out of memory error\n");
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008357 return -1;
8358 case LUA_ERRERR:
Thierry Fournierc93c15c2020-11-28 15:02:13 +01008359 memprintf(err, "Lua message handler error: %s\n", lua_tostring(L, -1));
8360 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008361 return -1;
Christopher Faulet08ed98f2020-07-28 10:33:25 +02008362#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 503
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008363 case LUA_ERRGCMM:
Thierry Fournierc93c15c2020-11-28 15:02:13 +01008364 memprintf(err, "Lua garbage collector error: %s\n", lua_tostring(L, -1));
8365 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008366 return -1;
Christopher Faulet08ed98f2020-07-28 10:33:25 +02008367#endif
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008368 default:
Thierry Fournierc93c15c2020-11-28 15:02:13 +01008369 memprintf(err, "Lua unknown error: %s\n", lua_tostring(L, -1));
8370 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008371 return -1;
8372 }
8373
8374 return 0;
8375}
8376
Thierry Fournierc93c15c2020-11-28 15:02:13 +01008377static int hlua_load(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01008378 const struct proxy *defpx, const char *file, int line,
Thierry Fournierc93c15c2020-11-28 15:02:13 +01008379 char **err)
8380{
8381 if (*(args[1]) == 0) {
8382 memprintf(err, "'%s' expects a file name as parameter.\n", args[0]);
8383 return -1;
8384 }
8385
Thierry Fournier59f11be2020-11-29 00:37:41 +01008386 /* loading for global state */
Thierry Fournierc7492592020-11-28 23:57:24 +01008387 hlua_state_id = 0;
Thierry Fournier59f11be2020-11-29 00:37:41 +01008388 ha_set_tid(0);
Thierry Fournierafc63e22020-11-28 17:06:51 +01008389 return hlua_load_state(args[1], hlua_states[0], err);
Thierry Fournierc93c15c2020-11-28 15:02:13 +01008390}
8391
Thierry Fournier59f11be2020-11-29 00:37:41 +01008392static int hlua_load_per_thread(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01008393 const struct proxy *defpx, const char *file, int line,
Thierry Fournier59f11be2020-11-29 00:37:41 +01008394 char **err)
8395{
8396 int len;
8397
8398 if (*(args[1]) == 0) {
8399 memprintf(err, "'%s' expects a file as parameter.\n", args[0]);
8400 return -1;
8401 }
8402
8403 if (per_thread_load == NULL) {
8404 /* allocate the first entry large enough to store the final NULL */
8405 per_thread_load = calloc(1, sizeof(*per_thread_load));
8406 if (per_thread_load == NULL) {
8407 memprintf(err, "out of memory error");
8408 return -1;
8409 }
8410 }
8411
8412 /* count used entries */
8413 for (len = 0; per_thread_load[len] != NULL; len++)
8414 ;
8415
8416 per_thread_load = realloc(per_thread_load, (len + 2) * sizeof(*per_thread_load));
8417 if (per_thread_load == NULL) {
8418 memprintf(err, "out of memory error");
8419 return -1;
8420 }
8421
8422 per_thread_load[len] = strdup(args[1]);
8423 per_thread_load[len + 1] = NULL;
8424
8425 if (per_thread_load[len] == NULL) {
8426 memprintf(err, "out of memory error");
8427 return -1;
8428 }
8429
8430 /* loading for thread 1 only */
8431 hlua_state_id = 1;
8432 ha_set_tid(0);
8433 return hlua_load_state(args[1], hlua_states[1], err);
8434}
8435
Tim Duesterhusc9fc9f22020-01-12 13:55:39 +01008436/* Prepend the given <path> followed by a semicolon to the `package.<type>` variable
8437 * in the given <ctx>.
8438 */
Thierry Fournier3fb9e512020-11-28 10:13:12 +01008439static int hlua_prepend_path(lua_State *L, char *type, char *path)
Tim Duesterhusc9fc9f22020-01-12 13:55:39 +01008440{
Thierry Fournier3fb9e512020-11-28 10:13:12 +01008441 lua_getglobal(L, "package"); /* push package variable */
8442 lua_pushstring(L, path); /* push given path */
8443 lua_pushstring(L, ";"); /* push semicolon */
8444 lua_getfield(L, -3, type); /* push old path */
8445 lua_concat(L, 3); /* concatenate to new path */
8446 lua_setfield(L, -2, type); /* store new path */
8447 lua_pop(L, 1); /* pop package variable */
Tim Duesterhusc9fc9f22020-01-12 13:55:39 +01008448
8449 return 0;
8450}
8451
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +01008452static int hlua_config_prepend_path(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01008453 const struct proxy *defpx, const char *file, int line,
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +01008454 char **err)
8455{
8456 char *path;
8457 char *type = "path";
Tim Duesterhus621e74a2021-01-03 20:04:36 +01008458 struct prepend_path *p = NULL;
Thierry Fournier59f11be2020-11-29 00:37:41 +01008459
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +01008460 if (too_many_args(2, args, err, NULL)) {
Tim Duesterhus621e74a2021-01-03 20:04:36 +01008461 goto err;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +01008462 }
8463
8464 if (!(*args[1])) {
8465 memprintf(err, "'%s' expects to receive a <path> as argument", args[0]);
Tim Duesterhus621e74a2021-01-03 20:04:36 +01008466 goto err;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +01008467 }
8468 path = args[1];
8469
8470 if (*args[2]) {
8471 if (strcmp(args[2], "path") != 0 && strcmp(args[2], "cpath") != 0) {
8472 memprintf(err, "'%s' expects <type> to either be 'path' or 'cpath'", args[0]);
Tim Duesterhus621e74a2021-01-03 20:04:36 +01008473 goto err;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +01008474 }
8475 type = args[2];
8476 }
8477
Thierry Fournier59f11be2020-11-29 00:37:41 +01008478 p = calloc(1, sizeof(*p));
8479 if (p == NULL) {
Tim Duesterhusf89d43a2021-01-03 20:04:37 +01008480 memprintf(err, "memory allocation failed");
Tim Duesterhus621e74a2021-01-03 20:04:36 +01008481 goto err;
Thierry Fournier59f11be2020-11-29 00:37:41 +01008482 }
8483 p->path = strdup(path);
8484 if (p->path == NULL) {
Tim Duesterhusf89d43a2021-01-03 20:04:37 +01008485 memprintf(err, "memory allocation failed");
Tim Duesterhus621e74a2021-01-03 20:04:36 +01008486 goto err2;
Thierry Fournier59f11be2020-11-29 00:37:41 +01008487 }
8488 p->type = strdup(type);
8489 if (p->type == NULL) {
Tim Duesterhusf89d43a2021-01-03 20:04:37 +01008490 memprintf(err, "memory allocation failed");
Tim Duesterhus621e74a2021-01-03 20:04:36 +01008491 goto err2;
Thierry Fournier59f11be2020-11-29 00:37:41 +01008492 }
Willy Tarreau2b718102021-04-21 07:32:39 +02008493 LIST_APPEND(&prepend_path_list, &p->l);
Thierry Fournier59f11be2020-11-29 00:37:41 +01008494
8495 hlua_prepend_path(hlua_states[0], type, path);
8496 hlua_prepend_path(hlua_states[1], type, path);
8497 return 0;
Tim Duesterhus621e74a2021-01-03 20:04:36 +01008498
8499err2:
8500 free(p->type);
8501 free(p->path);
8502err:
8503 free(p);
8504 return -1;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +01008505}
8506
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008507/* configuration keywords declaration */
8508static struct cfg_kw_list cfg_kws = {{ },{
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +01008509 { CFG_GLOBAL, "lua-prepend-path", hlua_config_prepend_path },
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008510 { CFG_GLOBAL, "lua-load", hlua_load },
Thierry Fournier59f11be2020-11-29 00:37:41 +01008511 { CFG_GLOBAL, "lua-load-per-thread", hlua_load_per_thread },
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008512 { CFG_GLOBAL, "tune.lua.session-timeout", hlua_session_timeout },
8513 { CFG_GLOBAL, "tune.lua.task-timeout", hlua_task_timeout },
Thierry FOURNIER56da1012015-10-01 08:42:31 +02008514 { CFG_GLOBAL, "tune.lua.service-timeout", hlua_applet_timeout },
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01008515 { CFG_GLOBAL, "tune.lua.forced-yield", hlua_forced_yield },
Willy Tarreau32f61e22015-03-18 17:54:59 +01008516 { CFG_GLOBAL, "tune.lua.maxmem", hlua_parse_maxmem },
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01008517 { 0, NULL, NULL },
8518}};
8519
Willy Tarreau0108d902018-11-25 19:14:37 +01008520INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
8521
Christopher Fauletafd8f102018-11-08 11:34:21 +01008522
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008523/* This function can fail with an abort() due to an Lua critical error.
8524 * We are in the initialisation process of HAProxy, this abort() is
8525 * tolerated.
8526 */
Thierry Fournierb8cef172020-11-28 15:37:17 +01008527int hlua_post_init_state(lua_State *L)
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008528{
8529 struct hlua_init_function *init;
8530 const char *msg;
8531 enum hlua_exec ret;
Thierry Fournierfd107a22016-02-19 19:57:23 +01008532 const char *error;
Thierry Fournier670db242020-11-28 10:49:59 +01008533 const char *kind;
8534 const char *trace;
8535 int return_status = 1;
8536#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
8537 int nres;
8538#endif
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008539
Willy Tarreaucdb53462020-12-02 12:12:00 +01008540 /* disable memory limit checks if limit is not set */
8541 if (!hlua_global_allocator.limit)
8542 hlua_global_allocator.limit = ~hlua_global_allocator.limit;
8543
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05008544 /* Call post initialisation function in safe environment. */
Thierry Fournier3c539322020-11-28 16:05:05 +01008545 if (setjmp(safe_ljmp_env) != 0) {
8546 lua_atpanic(L, hlua_panic_safe);
Thierry Fournierb8cef172020-11-28 15:37:17 +01008547 if (lua_type(L, -1) == LUA_TSTRING)
8548 error = lua_tostring(L, -1);
Thierry Fournier3d4a6752016-02-19 20:53:30 +01008549 else
8550 error = "critical error";
8551 fprintf(stderr, "Lua post-init: %s.\n", error);
8552 exit(1);
Thierry Fournier3c539322020-11-28 16:05:05 +01008553 } else {
8554 lua_atpanic(L, hlua_panic_ljmp);
Thierry Fournier3d4a6752016-02-19 20:53:30 +01008555 }
Frédéric Lécaille54f2bcf2018-08-29 13:46:24 +02008556
Thierry Fournierb8cef172020-11-28 15:37:17 +01008557 hlua_fcn_post_init(L);
Thierry Fournier3d4a6752016-02-19 20:53:30 +01008558
Thierry Fournierc7492592020-11-28 23:57:24 +01008559 list_for_each_entry(init, &hlua_init_functions[hlua_state_id], l) {
Thierry Fournierb8cef172020-11-28 15:37:17 +01008560 lua_rawgeti(L, LUA_REGISTRYINDEX, init->function_ref);
Thierry Fournier670db242020-11-28 10:49:59 +01008561
8562#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
Thierry Fournierb8cef172020-11-28 15:37:17 +01008563 ret = lua_resume(L, L, 0, &nres);
Thierry Fournier670db242020-11-28 10:49:59 +01008564#else
Thierry Fournierb8cef172020-11-28 15:37:17 +01008565 ret = lua_resume(L, L, 0);
Thierry Fournier670db242020-11-28 10:49:59 +01008566#endif
8567 kind = NULL;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008568 switch (ret) {
Thierry Fournier670db242020-11-28 10:49:59 +01008569
8570 case LUA_OK:
Thierry Fournierb8cef172020-11-28 15:37:17 +01008571 lua_pop(L, -1);
Thierry Fournier13d08b72020-11-28 11:02:58 +01008572 break;
Thierry Fournier670db242020-11-28 10:49:59 +01008573
8574 case LUA_ERRERR:
8575 kind = "message handler error";
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07008576 /* Fall through */
Thierry Fournier670db242020-11-28 10:49:59 +01008577 case LUA_ERRRUN:
8578 if (!kind)
8579 kind = "runtime error";
Thierry Fournierb8cef172020-11-28 15:37:17 +01008580 msg = lua_tostring(L, -1);
8581 lua_settop(L, 0); /* Empty the stack. */
8582 lua_pop(L, 1);
Christopher Fauletd09cc512021-03-24 14:48:45 +01008583 trace = hlua_traceback(L, ", ");
Thierry Fournier670db242020-11-28 10:49:59 +01008584 if (msg)
8585 ha_alert("Lua init: %s: '%s' from %s\n", kind, msg, trace);
8586 else
8587 ha_alert("Lua init: unknown %s from %s\n", kind, trace);
8588 return_status = 0;
8589 break;
8590
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008591 default:
Thierry Fournier670db242020-11-28 10:49:59 +01008592 /* Unknown error */
8593 kind = "Unknown error";
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07008594 /* Fall through */
Thierry Fournier670db242020-11-28 10:49:59 +01008595 case LUA_YIELD:
8596 /* yield is not configured at this step, this state doesn't happen */
8597 if (!kind)
8598 kind = "yield not allowed";
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07008599 /* Fall through */
Thierry Fournier670db242020-11-28 10:49:59 +01008600 case LUA_ERRMEM:
8601 if (!kind)
8602 kind = "out of memory error";
Thierry Fournierb8cef172020-11-28 15:37:17 +01008603 lua_settop(L, 0);
8604 lua_pop(L, 1);
Christopher Fauletd09cc512021-03-24 14:48:45 +01008605 trace = hlua_traceback(L, ", ");
Thierry Fournier670db242020-11-28 10:49:59 +01008606 ha_alert("Lua init: %s: %s\n", kind, trace);
8607 return_status = 0;
8608 break;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008609 }
Thierry Fournier670db242020-11-28 10:49:59 +01008610 if (!return_status)
8611 break;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008612 }
Thierry Fournier3c539322020-11-28 16:05:05 +01008613
8614 lua_atpanic(L, hlua_panic_safe);
Thierry Fournier670db242020-11-28 10:49:59 +01008615 return return_status;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008616}
8617
Thierry Fournierb8cef172020-11-28 15:37:17 +01008618int hlua_post_init()
8619{
Thierry Fournier59f11be2020-11-29 00:37:41 +01008620 int ret;
8621 int i;
8622 int errors;
8623 char *err = NULL;
8624 struct hlua_function *fcn;
8625
Thierry Fournierb8cef172020-11-28 15:37:17 +01008626#if USE_OPENSSL
8627 /* Initialize SSL server. */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +01008628 if (socket_ssl->xprt->prepare_srv) {
Thierry Fournierb8cef172020-11-28 15:37:17 +01008629 int saved_used_backed = global.ssl_used_backend;
8630 // don't affect maxconn automatic computation
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +01008631 socket_ssl->xprt->prepare_srv(socket_ssl);
Thierry Fournierb8cef172020-11-28 15:37:17 +01008632 global.ssl_used_backend = saved_used_backed;
8633 }
8634#endif
8635
Thierry Fournierc7492592020-11-28 23:57:24 +01008636 /* Perform post init of common thread */
8637 hlua_state_id = 0;
Thierry Fournier59f11be2020-11-29 00:37:41 +01008638 ha_set_tid(0);
8639 ret = hlua_post_init_state(hlua_states[hlua_state_id]);
8640 if (ret == 0)
8641 return 0;
8642
8643 /* init remaining lua states and load files */
8644 for (hlua_state_id = 2; hlua_state_id < global.nbthread + 1; hlua_state_id++) {
8645
8646 /* set thread context */
8647 ha_set_tid(hlua_state_id - 1);
8648
8649 /* Init lua state */
8650 hlua_states[hlua_state_id] = hlua_init_state(hlua_state_id);
8651
8652 /* Load lua files */
8653 for (i = 0; per_thread_load && per_thread_load[i]; i++) {
8654 ret = hlua_load_state(per_thread_load[i], hlua_states[hlua_state_id], &err);
8655 if (ret != 0) {
8656 ha_alert("Lua init: %s\n", err);
8657 return 0;
8658 }
8659 }
8660 }
8661
8662 /* Reset thread context */
8663 ha_set_tid(0);
8664
8665 /* Execute post init for all states */
8666 for (hlua_state_id = 1; hlua_state_id < global.nbthread + 1; hlua_state_id++) {
8667
8668 /* set thread context */
8669 ha_set_tid(hlua_state_id - 1);
8670
8671 /* run post init */
8672 ret = hlua_post_init_state(hlua_states[hlua_state_id]);
8673 if (ret == 0)
8674 return 0;
8675 }
8676
8677 /* Reset thread context */
8678 ha_set_tid(0);
8679
8680 /* control functions registering. Each function must have:
8681 * - only the function_ref[0] set positive and all other to -1
8682 * - only the function_ref[0] set to -1 and all other positive
8683 * This ensure a same reference is not used both in shared
8684 * lua state and thread dedicated lua state. Note: is the case
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05008685 * reach, the shared state is priority, but the bug will be
Thierry Fournier59f11be2020-11-29 00:37:41 +01008686 * complicated to found for the end user.
8687 */
8688 errors = 0;
8689 list_for_each_entry(fcn, &referenced_functions, l) {
8690 ret = 0;
8691 for (i = 1; i < global.nbthread + 1; i++) {
8692 if (fcn->function_ref[i] == -1)
8693 ret--;
8694 else
8695 ret++;
8696 }
8697 if (abs(ret) != global.nbthread) {
8698 ha_alert("Lua function '%s' is not referenced in all thread. "
8699 "Expect function in all thread or in none thread.\n", fcn->name);
8700 errors++;
8701 continue;
8702 }
8703
8704 if ((fcn->function_ref[0] == -1) == (ret < 0)) {
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05008705 ha_alert("Lua function '%s' is referenced both ins shared Lua context (through lua-load) "
8706 "and per-thread Lua context (through lua-load-per-thread). these two context "
Thierry Fournier59f11be2020-11-29 00:37:41 +01008707 "exclusive.\n", fcn->name);
8708 errors++;
8709 }
8710 }
8711
8712 if (errors > 0)
8713 return 0;
8714
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05008715 /* after this point, this global will no longer be used, so set to
Thierry Fournier59f11be2020-11-29 00:37:41 +01008716 * -1 in order to have probably a segfault if someone use it
8717 */
8718 hlua_state_id = -1;
8719
8720 return 1;
Thierry Fournierb8cef172020-11-28 15:37:17 +01008721}
8722
Willy Tarreau32f61e22015-03-18 17:54:59 +01008723/* The memory allocator used by the Lua stack. <ud> is a pointer to the
8724 * allocator's context. <ptr> is the pointer to alloc/free/realloc. <osize>
8725 * is the previously allocated size or the kind of object in case of a new
Willy Tarreaud36c7fa2020-12-02 12:26:29 +01008726 * allocation. <nsize> is the requested new size. A new allocation is
8727 * indicated by <ptr> being NULL. A free is indicated by <nsize> being
Willy Tarreaucdb53462020-12-02 12:12:00 +01008728 * zero. This one verifies that the limits are respected but is optimized
8729 * for the fast case where limits are not used, hence stats are not updated.
Willy Tarreau32f61e22015-03-18 17:54:59 +01008730 */
8731static void *hlua_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
8732{
8733 struct hlua_mem_allocator *zone = ud;
Willy Tarreaucdb53462020-12-02 12:12:00 +01008734 size_t limit, old, new;
8735
Tim Duesterhus22586522021-01-08 10:35:33 +01008736 if (unlikely(!ptr && !nsize))
8737 return NULL;
8738
Willy Tarreaucdb53462020-12-02 12:12:00 +01008739 /* a limit of ~0 means unlimited and boot complete, so there's no need
8740 * for accounting anymore.
8741 */
Christopher Fauletcc2c4f82021-03-24 14:52:24 +01008742 if (likely(~zone->limit == 0))
8743 return realloc(ptr, nsize);
Willy Tarreau32f61e22015-03-18 17:54:59 +01008744
Willy Tarreaud36c7fa2020-12-02 12:26:29 +01008745 if (!ptr)
8746 osize = 0;
Willy Tarreau32f61e22015-03-18 17:54:59 +01008747
Willy Tarreaucdb53462020-12-02 12:12:00 +01008748 /* enforce strict limits across all threads */
8749 limit = zone->limit;
8750 old = _HA_ATOMIC_LOAD(&zone->allocated);
8751 do {
8752 new = old + nsize - osize;
8753 if (unlikely(nsize && limit && new > limit))
8754 return NULL;
8755 } while (!_HA_ATOMIC_CAS(&zone->allocated, &old, new));
Willy Tarreau32f61e22015-03-18 17:54:59 +01008756
8757 ptr = realloc(ptr, nsize);
Willy Tarreaucdb53462020-12-02 12:12:00 +01008758
8759 if (unlikely(!ptr && nsize)) // failed
8760 _HA_ATOMIC_SUB(&zone->allocated, nsize - osize);
8761
8762 __ha_barrier_atomic_store();
Willy Tarreau32f61e22015-03-18 17:54:59 +01008763 return ptr;
8764}
8765
Thierry Fournierecb83c22020-11-28 15:49:44 +01008766/* This function can fail with an abort() due to a Lua critical error.
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008767 * We are in the initialisation process of HAProxy, this abort() is
8768 * tolerated.
8769 */
Thierry Fournierecb83c22020-11-28 15:49:44 +01008770lua_State *hlua_init_state(int thread_num)
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +01008771{
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +01008772 int i;
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +01008773 int idx;
8774 struct sample_fetch *sf;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01008775 struct sample_conv *sc;
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +01008776 char *p;
Thierry Fournierfd107a22016-02-19 19:57:23 +01008777 const char *error_msg;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01008778 void **context;
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008779 lua_State *L;
Thierry Fournier59f11be2020-11-29 00:37:41 +01008780 struct prepend_path *pp;
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +01008781
Thierry FOURNIER380d0932015-01-23 14:27:52 +01008782 /* Init main lua stack. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008783 L = lua_newstate(hlua_alloc, &hlua_global_allocator);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01008784
Thierry Fournier4234dbd2020-11-28 13:18:23 +01008785 /* Initialise Lua context to NULL */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008786 context = lua_getextraspace(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01008787 *context = NULL;
8788
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08008789 /* From this point, until the end of the initialisation function,
Thierry FOURNIERbabae282015-09-17 11:36:37 +02008790 * the Lua function can fail with an abort. We are in the initialisation
8791 * process of HAProxy, this abort() is tolerated.
8792 */
8793
Thierry Fournier3c539322020-11-28 16:05:05 +01008794 /* Call post initialisation function in safe environment. */
8795 if (setjmp(safe_ljmp_env) != 0) {
8796 lua_atpanic(L, hlua_panic_safe);
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008797 if (lua_type(L, -1) == LUA_TSTRING)
8798 error_msg = lua_tostring(L, -1);
Thierry Fournier2f05cc62020-11-28 16:08:02 +01008799 else
8800 error_msg = "critical error";
8801 fprintf(stderr, "Lua init: %s.\n", error_msg);
8802 exit(1);
Thierry Fournier3c539322020-11-28 16:05:05 +01008803 } else {
8804 lua_atpanic(L, hlua_panic_ljmp);
Thierry Fournier2f05cc62020-11-28 16:08:02 +01008805 }
8806
Thierry FOURNIER380d0932015-01-23 14:27:52 +01008807 /* Initialise lua. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008808 luaL_openlibs(L);
Tim Duesterhus541fe1e2020-01-12 13:55:41 +01008809#define HLUA_PREPEND_PATH_TOSTRING1(x) #x
8810#define HLUA_PREPEND_PATH_TOSTRING(x) HLUA_PREPEND_PATH_TOSTRING1(x)
8811#ifdef HLUA_PREPEND_PATH
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008812 hlua_prepend_path(L, "path", HLUA_PREPEND_PATH_TOSTRING(HLUA_PREPEND_PATH));
Tim Duesterhus541fe1e2020-01-12 13:55:41 +01008813#endif
8814#ifdef HLUA_PREPEND_CPATH
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008815 hlua_prepend_path(L, "cpath", HLUA_PREPEND_PATH_TOSTRING(HLUA_PREPEND_CPATH));
Tim Duesterhus541fe1e2020-01-12 13:55:41 +01008816#endif
8817#undef HLUA_PREPEND_PATH_TOSTRING
8818#undef HLUA_PREPEND_PATH_TOSTRING1
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +01008819
Thierry Fournier59f11be2020-11-29 00:37:41 +01008820 /* Apply configured prepend path */
8821 list_for_each_entry(pp, &prepend_path_list, l)
8822 hlua_prepend_path(L, pp->type, pp->path);
8823
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +01008824 /*
8825 *
8826 * Create "core" object.
8827 *
8828 */
8829
Thierry FOURNIERa2d8c652015-03-11 17:29:39 +01008830 /* This table entry is the object "core" base. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008831 lua_newtable(L);
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +01008832
Thierry Fournierecb83c22020-11-28 15:49:44 +01008833 /* set the thread id */
8834 hlua_class_const_int(L, "thread", thread_num);
8835
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +01008836 /* Push the loglevel constants. */
Willy Tarreau80f5fae2015-02-27 16:38:20 +01008837 for (i = 0; i < NB_LOG_LEVELS; i++)
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008838 hlua_class_const_int(L, log_levels[i], i);
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +01008839
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008840 /* Register special functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008841 hlua_class_function(L, "register_init", hlua_register_init);
8842 hlua_class_function(L, "register_task", hlua_register_task);
8843 hlua_class_function(L, "register_fetches", hlua_register_fetches);
8844 hlua_class_function(L, "register_converters", hlua_register_converters);
8845 hlua_class_function(L, "register_action", hlua_register_action);
8846 hlua_class_function(L, "register_service", hlua_register_service);
8847 hlua_class_function(L, "register_cli", hlua_register_cli);
8848 hlua_class_function(L, "yield", hlua_yield);
8849 hlua_class_function(L, "set_nice", hlua_set_nice);
8850 hlua_class_function(L, "sleep", hlua_sleep);
8851 hlua_class_function(L, "msleep", hlua_msleep);
8852 hlua_class_function(L, "add_acl", hlua_add_acl);
8853 hlua_class_function(L, "del_acl", hlua_del_acl);
8854 hlua_class_function(L, "set_map", hlua_set_map);
8855 hlua_class_function(L, "del_map", hlua_del_map);
8856 hlua_class_function(L, "tcp", hlua_socket_new);
8857 hlua_class_function(L, "log", hlua_log);
8858 hlua_class_function(L, "Debug", hlua_log_debug);
8859 hlua_class_function(L, "Info", hlua_log_info);
8860 hlua_class_function(L, "Warning", hlua_log_warning);
8861 hlua_class_function(L, "Alert", hlua_log_alert);
8862 hlua_class_function(L, "done", hlua_done);
8863 hlua_fcn_reg_core_fcn(L);
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01008864
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008865 lua_setglobal(L, "core");
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01008866
8867 /*
8868 *
Christopher Faulet0f3c8902020-01-31 18:57:12 +01008869 * Create "act" object.
8870 *
8871 */
8872
8873 /* This table entry is the object "act" base. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008874 lua_newtable(L);
Christopher Faulet0f3c8902020-01-31 18:57:12 +01008875
8876 /* push action return constants */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008877 hlua_class_const_int(L, "CONTINUE", ACT_RET_CONT);
8878 hlua_class_const_int(L, "STOP", ACT_RET_STOP);
8879 hlua_class_const_int(L, "YIELD", ACT_RET_YIELD);
8880 hlua_class_const_int(L, "ERROR", ACT_RET_ERR);
8881 hlua_class_const_int(L, "DONE", ACT_RET_DONE);
8882 hlua_class_const_int(L, "DENY", ACT_RET_DENY);
8883 hlua_class_const_int(L, "ABORT", ACT_RET_ABRT);
8884 hlua_class_const_int(L, "INVALID", ACT_RET_INV);
Christopher Faulet0f3c8902020-01-31 18:57:12 +01008885
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008886 hlua_class_function(L, "wake_time", hlua_set_wake_time);
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01008887
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008888 lua_setglobal(L, "act");
Christopher Faulet0f3c8902020-01-31 18:57:12 +01008889
8890 /*
8891 *
Thierry FOURNIER3def3932015-04-07 11:27:54 +02008892 * Register class Map
8893 *
8894 */
8895
8896 /* This table entry is the object "Map" base. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008897 lua_newtable(L);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02008898
8899 /* register pattern types. */
8900 for (i=0; i<PAT_MATCH_NUM; i++)
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008901 hlua_class_const_int(L, pat_match_names[i], i);
Thierry FOURNIER4dc71972017-01-28 08:33:08 +01008902 for (i=0; i<PAT_MATCH_NUM; i++) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02008903 snprintf(trash.area, trash.size, "_%s", pat_match_names[i]);
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008904 hlua_class_const_int(L, trash.area, i);
Thierry FOURNIER4dc71972017-01-28 08:33:08 +01008905 }
Thierry FOURNIER3def3932015-04-07 11:27:54 +02008906
8907 /* register constructor. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008908 hlua_class_function(L, "new", hlua_map_new);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02008909
8910 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008911 lua_newtable(L);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02008912
Ilya Shipitsind4259502020-04-08 01:07:56 +05008913 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008914 lua_pushstring(L, "__index");
8915 lua_newtable(L);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02008916
8917 /* Register . */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008918 hlua_class_function(L, "lookup", hlua_map_lookup);
8919 hlua_class_function(L, "slookup", hlua_map_slookup);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02008920
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008921 lua_rawset(L, -3);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02008922
Thierry Fournier45e78d72016-02-19 18:34:46 +01008923 /* Register previous table in the registry with reference and named entry.
8924 * The function hlua_register_metatable() pops the stack, so we
8925 * previously create a copy of the table.
8926 */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008927 lua_pushvalue(L, -1); /* Copy the -1 entry and push it on the stack. */
8928 class_map_ref = hlua_register_metatable(L, CLASS_MAP);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02008929
8930 /* Assign the metatable to the mai Map object. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008931 lua_setmetatable(L, -2);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02008932
8933 /* Set a name to the table. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008934 lua_setglobal(L, "Map");
Thierry FOURNIER3def3932015-04-07 11:27:54 +02008935
8936 /*
8937 *
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01008938 * Register class Channel
8939 *
8940 */
8941
8942 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008943 lua_newtable(L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01008944
Ilya Shipitsind4259502020-04-08 01:07:56 +05008945 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008946 lua_pushstring(L, "__index");
8947 lua_newtable(L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01008948
8949 /* Register . */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008950 hlua_class_function(L, "get", hlua_channel_get);
8951 hlua_class_function(L, "dup", hlua_channel_dup);
8952 hlua_class_function(L, "getline", hlua_channel_getline);
8953 hlua_class_function(L, "set", hlua_channel_set);
8954 hlua_class_function(L, "append", hlua_channel_append);
8955 hlua_class_function(L, "send", hlua_channel_send);
8956 hlua_class_function(L, "forward", hlua_channel_forward);
8957 hlua_class_function(L, "get_in_len", hlua_channel_get_in_len);
8958 hlua_class_function(L, "get_out_len", hlua_channel_get_out_len);
8959 hlua_class_function(L, "is_full", hlua_channel_is_full);
8960 hlua_class_function(L, "is_resp", hlua_channel_is_resp);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01008961
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008962 lua_rawset(L, -3);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01008963
8964 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008965 class_channel_ref = hlua_register_metatable(L, CLASS_CHANNEL);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01008966
8967 /*
8968 *
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01008969 * Register class Fetches
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01008970 *
8971 */
8972
8973 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008974 lua_newtable(L);
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01008975
Ilya Shipitsind4259502020-04-08 01:07:56 +05008976 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008977 lua_pushstring(L, "__index");
8978 lua_newtable(L);
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01008979
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +01008980 /* Browse existing fetches and create the associated
8981 * object method.
8982 */
8983 sf = NULL;
8984 while ((sf = sample_fetch_getnext(sf, &idx)) != NULL) {
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +01008985 /* gL.Tua doesn't support '.' and '-' in the function names, replace it
8986 * by an underscore.
8987 */
Willy Tarreaufa92f362021-08-26 16:48:53 +02008988 strlcpy2(trash.area, sf->kw, trash.size);
Willy Tarreau843b7cb2018-07-13 10:54:26 +02008989 for (p = trash.area; *p; p++)
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +01008990 if (*p == '.' || *p == '-' || *p == '+')
8991 *p = '_';
8992
8993 /* Register the function. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01008994 lua_pushstring(L, trash.area);
8995 lua_pushlightuserdata(L, sf);
8996 lua_pushcclosure(L, hlua_run_sample_fetch, 1);
8997 lua_rawset(L, -3);
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +01008998 }
8999
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009000 lua_rawset(L, -3);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01009001
9002 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009003 class_fetches_ref = hlua_register_metatable(L, CLASS_FETCHES);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01009004
9005 /*
9006 *
Thierry FOURNIER594afe72015-03-10 23:58:30 +01009007 * Register class Converters
9008 *
9009 */
9010
9011 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009012 lua_newtable(L);
Thierry FOURNIER594afe72015-03-10 23:58:30 +01009013
9014 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009015 lua_pushstring(L, "__index");
9016 lua_newtable(L);
Thierry FOURNIER594afe72015-03-10 23:58:30 +01009017
9018 /* Browse existing converters and create the associated
9019 * object method.
9020 */
9021 sc = NULL;
9022 while ((sc = sample_conv_getnext(sc, &idx)) != NULL) {
Thierry FOURNIER594afe72015-03-10 23:58:30 +01009023 /* gL.Tua doesn't support '.' and '-' in the function names, replace it
9024 * by an underscore.
9025 */
Willy Tarreaufa92f362021-08-26 16:48:53 +02009026 strlcpy2(trash.area, sc->kw, trash.size);
Willy Tarreau843b7cb2018-07-13 10:54:26 +02009027 for (p = trash.area; *p; p++)
Thierry FOURNIER594afe72015-03-10 23:58:30 +01009028 if (*p == '.' || *p == '-' || *p == '+')
9029 *p = '_';
9030
9031 /* Register the function. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009032 lua_pushstring(L, trash.area);
9033 lua_pushlightuserdata(L, sc);
9034 lua_pushcclosure(L, hlua_run_sample_conv, 1);
9035 lua_rawset(L, -3);
Thierry FOURNIER594afe72015-03-10 23:58:30 +01009036 }
9037
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009038 lua_rawset(L, -3);
Thierry FOURNIER594afe72015-03-10 23:58:30 +01009039
9040 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009041 class_converters_ref = hlua_register_metatable(L, CLASS_CONVERTERS);
Thierry FOURNIER594afe72015-03-10 23:58:30 +01009042
9043 /*
9044 *
Thierry FOURNIER08504f42015-03-16 14:17:08 +01009045 * Register class HTTP
9046 *
9047 */
9048
9049 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009050 lua_newtable(L);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01009051
Ilya Shipitsind4259502020-04-08 01:07:56 +05009052 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009053 lua_pushstring(L, "__index");
9054 lua_newtable(L);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01009055
9056 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009057 hlua_class_function(L, "req_get_headers",hlua_http_req_get_headers);
9058 hlua_class_function(L, "req_del_header", hlua_http_req_del_hdr);
9059 hlua_class_function(L, "req_rep_header", hlua_http_req_rep_hdr);
9060 hlua_class_function(L, "req_rep_value", hlua_http_req_rep_val);
9061 hlua_class_function(L, "req_add_header", hlua_http_req_add_hdr);
9062 hlua_class_function(L, "req_set_header", hlua_http_req_set_hdr);
9063 hlua_class_function(L, "req_set_method", hlua_http_req_set_meth);
9064 hlua_class_function(L, "req_set_path", hlua_http_req_set_path);
9065 hlua_class_function(L, "req_set_query", hlua_http_req_set_query);
9066 hlua_class_function(L, "req_set_uri", hlua_http_req_set_uri);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01009067
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009068 hlua_class_function(L, "res_get_headers",hlua_http_res_get_headers);
9069 hlua_class_function(L, "res_del_header", hlua_http_res_del_hdr);
9070 hlua_class_function(L, "res_rep_header", hlua_http_res_rep_hdr);
9071 hlua_class_function(L, "res_rep_value", hlua_http_res_rep_val);
9072 hlua_class_function(L, "res_add_header", hlua_http_res_add_hdr);
9073 hlua_class_function(L, "res_set_header", hlua_http_res_set_hdr);
9074 hlua_class_function(L, "res_set_status", hlua_http_res_set_status);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01009075
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009076 lua_rawset(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01009077
9078 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009079 class_http_ref = hlua_register_metatable(L, CLASS_HTTP);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01009080
9081 /*
9082 *
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009083 * Register class AppletTCP
9084 *
9085 */
9086
9087 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009088 lua_newtable(L);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009089
Ilya Shipitsind4259502020-04-08 01:07:56 +05009090 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009091 lua_pushstring(L, "__index");
9092 lua_newtable(L);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009093
9094 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009095 hlua_class_function(L, "getline", hlua_applet_tcp_getline);
9096 hlua_class_function(L, "receive", hlua_applet_tcp_recv);
9097 hlua_class_function(L, "send", hlua_applet_tcp_send);
9098 hlua_class_function(L, "set_priv", hlua_applet_tcp_set_priv);
9099 hlua_class_function(L, "get_priv", hlua_applet_tcp_get_priv);
9100 hlua_class_function(L, "set_var", hlua_applet_tcp_set_var);
9101 hlua_class_function(L, "unset_var", hlua_applet_tcp_unset_var);
9102 hlua_class_function(L, "get_var", hlua_applet_tcp_get_var);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009103
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009104 lua_settable(L, -3);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009105
9106 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009107 class_applet_tcp_ref = hlua_register_metatable(L, CLASS_APPLET_TCP);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009108
9109 /*
9110 *
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009111 * Register class AppletHTTP
9112 *
9113 */
9114
9115 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009116 lua_newtable(L);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009117
Ilya Shipitsind4259502020-04-08 01:07:56 +05009118 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009119 lua_pushstring(L, "__index");
9120 lua_newtable(L);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009121
9122 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009123 hlua_class_function(L, "set_priv", hlua_applet_http_set_priv);
9124 hlua_class_function(L, "get_priv", hlua_applet_http_get_priv);
9125 hlua_class_function(L, "set_var", hlua_applet_http_set_var);
9126 hlua_class_function(L, "unset_var", hlua_applet_http_unset_var);
9127 hlua_class_function(L, "get_var", hlua_applet_http_get_var);
9128 hlua_class_function(L, "getline", hlua_applet_http_getline);
9129 hlua_class_function(L, "receive", hlua_applet_http_recv);
9130 hlua_class_function(L, "send", hlua_applet_http_send);
9131 hlua_class_function(L, "add_header", hlua_applet_http_addheader);
9132 hlua_class_function(L, "set_status", hlua_applet_http_status);
9133 hlua_class_function(L, "start_response", hlua_applet_http_start_response);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009134
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009135 lua_settable(L, -3);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009136
9137 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009138 class_applet_http_ref = hlua_register_metatable(L, CLASS_APPLET_HTTP);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009139
9140 /*
9141 *
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01009142 * Register class TXN
9143 *
9144 */
9145
9146 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009147 lua_newtable(L);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01009148
Ilya Shipitsind4259502020-04-08 01:07:56 +05009149 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009150 lua_pushstring(L, "__index");
9151 lua_newtable(L);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01009152
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01009153 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009154 hlua_class_function(L, "set_priv", hlua_set_priv);
9155 hlua_class_function(L, "get_priv", hlua_get_priv);
9156 hlua_class_function(L, "set_var", hlua_set_var);
9157 hlua_class_function(L, "unset_var", hlua_unset_var);
9158 hlua_class_function(L, "get_var", hlua_get_var);
9159 hlua_class_function(L, "done", hlua_txn_done);
9160 hlua_class_function(L, "reply", hlua_txn_reply_new);
9161 hlua_class_function(L, "set_loglevel", hlua_txn_set_loglevel);
9162 hlua_class_function(L, "set_tos", hlua_txn_set_tos);
9163 hlua_class_function(L, "set_mark", hlua_txn_set_mark);
9164 hlua_class_function(L, "set_priority_class", hlua_txn_set_priority_class);
9165 hlua_class_function(L, "set_priority_offset", hlua_txn_set_priority_offset);
9166 hlua_class_function(L, "deflog", hlua_txn_deflog);
9167 hlua_class_function(L, "log", hlua_txn_log);
9168 hlua_class_function(L, "Debug", hlua_txn_log_debug);
9169 hlua_class_function(L, "Info", hlua_txn_log_info);
9170 hlua_class_function(L, "Warning", hlua_txn_log_warning);
9171 hlua_class_function(L, "Alert", hlua_txn_log_alert);
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01009172
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009173 lua_rawset(L, -3);
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01009174
9175 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009176 class_txn_ref = hlua_register_metatable(L, CLASS_TXN);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009177
9178 /*
9179 *
Christopher Faulet700d9e82020-01-31 12:21:52 +01009180 * Register class reply
9181 *
9182 */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009183 lua_newtable(L);
9184 lua_pushstring(L, "__index");
9185 lua_newtable(L);
9186 hlua_class_function(L, "set_status", hlua_txn_reply_set_status);
9187 hlua_class_function(L, "add_header", hlua_txn_reply_add_header);
9188 hlua_class_function(L, "del_header", hlua_txn_reply_del_header);
9189 hlua_class_function(L, "set_body", hlua_txn_reply_set_body);
9190 lua_settable(L, -3); /* Sets the __index entry. */
9191 class_txn_reply_ref = luaL_ref(L, LUA_REGISTRYINDEX);
Christopher Faulet700d9e82020-01-31 12:21:52 +01009192
9193
9194 /*
9195 *
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009196 * Register class Socket
9197 *
9198 */
9199
9200 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009201 lua_newtable(L);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009202
Ilya Shipitsind4259502020-04-08 01:07:56 +05009203 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009204 lua_pushstring(L, "__index");
9205 lua_newtable(L);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009206
Baptiste Assmann84bb4932015-03-02 21:40:06 +01009207#ifdef USE_OPENSSL
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009208 hlua_class_function(L, "connect_ssl", hlua_socket_connect_ssl);
Baptiste Assmann84bb4932015-03-02 21:40:06 +01009209#endif
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009210 hlua_class_function(L, "connect", hlua_socket_connect);
9211 hlua_class_function(L, "send", hlua_socket_send);
9212 hlua_class_function(L, "receive", hlua_socket_receive);
9213 hlua_class_function(L, "close", hlua_socket_close);
9214 hlua_class_function(L, "getpeername", hlua_socket_getpeername);
9215 hlua_class_function(L, "getsockname", hlua_socket_getsockname);
9216 hlua_class_function(L, "setoption", hlua_socket_setoption);
9217 hlua_class_function(L, "settimeout", hlua_socket_settimeout);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009218
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009219 lua_rawset(L, -3); /* Push the last 2 entries in the table at index -3 */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009220
9221 /* Register the garbage collector entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009222 lua_pushstring(L, "__gc");
9223 lua_pushcclosure(L, hlua_socket_gc, 0);
9224 lua_rawset(L, -3); /* Push the last 2 entries in the table at index -3 */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009225
9226 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009227 class_socket_ref = hlua_register_metatable(L, CLASS_SOCKET);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009228
Thierry Fournieraafc7772020-12-04 11:47:47 +01009229 lua_atpanic(L, hlua_panic_safe);
9230
9231 return L;
9232}
9233
9234void hlua_init(void) {
9235 int i;
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +01009236 char *errmsg;
Thierry Fournieraafc7772020-12-04 11:47:47 +01009237#ifdef USE_OPENSSL
9238 struct srv_kw *kw;
9239 int tmp_error;
9240 char *error;
9241 char *args[] = { /* SSL client configuration. */
9242 "ssl",
9243 "verify",
9244 "none",
9245 NULL
9246 };
9247#endif
9248
9249 /* Init post init function list head */
9250 for (i = 0; i < MAX_THREADS + 1; i++)
9251 LIST_INIT(&hlua_init_functions[i]);
9252
9253 /* Init state for common/shared lua parts */
9254 hlua_state_id = 0;
9255 ha_set_tid(0);
9256 hlua_states[0] = hlua_init_state(0);
9257
9258 /* Init state 1 for thread 0. We have at least one thread. */
9259 hlua_state_id = 1;
9260 ha_set_tid(0);
9261 hlua_states[1] = hlua_init_state(1);
9262
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009263 /* Proxy and server configuration initialisation. */
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +01009264 socket_proxy = alloc_new_proxy("LUA-SOCKET", PR_CAP_FE|PR_CAP_BE|PR_CAP_LUA, &errmsg);
9265 if (!socket_proxy) {
9266 fprintf(stderr, "Lua init: %s\n", errmsg);
9267 exit(1);
9268 }
9269 proxy_preset_defaults(socket_proxy);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009270
9271 /* Init TCP server: unchanged parameters */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +01009272 socket_tcp = new_server(socket_proxy);
9273 if (!socket_tcp) {
9274 fprintf(stderr, "Lua init: failed to allocate tcp server socket\n");
9275 exit(1);
9276 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009277
9278#ifdef USE_OPENSSL
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009279 /* Init TCP server: unchanged parameters */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +01009280 socket_ssl = new_server(socket_proxy);
9281 if (!socket_ssl) {
9282 fprintf(stderr, "Lua init: failed to allocate ssl server socket\n");
9283 exit(1);
9284 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009285
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +01009286 socket_ssl->use_ssl = 1;
9287 socket_ssl->xprt = xprt_get(XPRT_SSL);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009288
Bertrand Jacquin80839ff2021-01-21 19:14:46 +00009289 for (i = 0; args[i] != NULL; i++) {
9290 if ((kw = srv_find_kw(args[i])) != NULL) { /* Maybe it's registered server keyword */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009291 /*
9292 *
9293 * If the keyword is not known, we can search in the registered
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08009294 * server keywords. This is useful to configure special SSL
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009295 * features like client certificates and ssl_verify.
9296 *
9297 */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +01009298 tmp_error = kw->parse(args, &i, socket_proxy, socket_ssl, &error);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009299 if (tmp_error != 0) {
9300 fprintf(stderr, "INTERNAL ERROR: %s\n", error);
9301 abort(); /* This must be never arrives because the command line
9302 not editable by the user. */
9303 }
Bertrand Jacquin80839ff2021-01-21 19:14:46 +00009304 i += kw->skip;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009305 }
9306 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009307#endif
Thierry Fournier75933d42016-01-21 09:30:18 +01009308
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +01009309}
Willy Tarreaubb57d942016-12-21 19:04:56 +01009310
Tim Duesterhusd0c0ca22020-07-04 11:53:26 +02009311static void hlua_deinit()
9312{
Willy Tarreau186f3762020-12-04 11:48:12 +01009313 int thr;
9314
9315 for (thr = 0; thr < MAX_THREADS+1; thr++) {
9316 if (hlua_states[thr])
9317 lua_close(hlua_states[thr]);
9318 }
Willy Tarreau430bf4a2021-03-04 09:45:32 +01009319
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +01009320 free_server(socket_tcp);
Willy Tarreau430bf4a2021-03-04 09:45:32 +01009321
Willy Tarreau0f143af2021-03-05 10:41:48 +01009322#ifdef USE_OPENSSL
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +01009323 free_server(socket_ssl);
Willy Tarreau0f143af2021-03-05 10:41:48 +01009324#endif
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +01009325
9326 free_proxy(socket_proxy);
Tim Duesterhusd0c0ca22020-07-04 11:53:26 +02009327}
9328
9329REGISTER_POST_DEINIT(hlua_deinit);
9330
Willy Tarreau80713382018-11-26 10:19:54 +01009331static void hlua_register_build_options(void)
9332{
Willy Tarreaubb57d942016-12-21 19:04:56 +01009333 char *ptr = NULL;
Willy Tarreau80713382018-11-26 10:19:54 +01009334
Willy Tarreaubb57d942016-12-21 19:04:56 +01009335 memprintf(&ptr, "Built with Lua version : %s", LUA_RELEASE);
9336 hap_register_build_opts(ptr, 1);
9337}
Willy Tarreau80713382018-11-26 10:19:54 +01009338
9339INITCALL0(STG_REGISTER, hlua_register_build_options);