blob: a7ad97984da64877645b8fa985906e2e12f960d2 [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>
Christopher Faulet69c581a2021-05-31 08:54:04 +020036#include <haproxy/filters.h>
Willy Tarreau5413a872020-06-02 19:33:08 +020037#include <haproxy/h1.h>
Willy Tarreau86416052020-06-04 09:20:54 +020038#include <haproxy/hlua.h>
Willy Tarreau8c794002020-06-04 10:05:25 +020039#include <haproxy/hlua_fcn.h>
Willy Tarreauc2b1ff02020-06-04 21:21:03 +020040#include <haproxy/http_ana.h>
Willy Tarreau126ba3a2020-06-04 18:26:43 +020041#include <haproxy/http_fetch.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020042#include <haproxy/http_htx.h>
Willy Tarreauc761f842020-06-04 11:40:28 +020043#include <haproxy/http_rules.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020044#include <haproxy/log.h>
Willy Tarreau2cd58092020-06-04 15:10:43 +020045#include <haproxy/map.h>
Willy Tarreau8efbdfb2020-06-04 11:29:21 +020046#include <haproxy/obj_type.h>
Willy Tarreau225a90a2020-06-04 15:06:28 +020047#include <haproxy/pattern.h>
Willy Tarreau469509b2020-06-04 15:13:30 +020048#include <haproxy/payload.h>
Willy Tarreau3d6ee402021-05-08 20:28:07 +020049#include <haproxy/proxy.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020050#include <haproxy/regex.h>
Willy Tarreaue6ce10b2020-06-04 15:33:47 +020051#include <haproxy/sample.h>
Willy Tarreau198e92a2021-03-05 10:23:32 +010052#include <haproxy/server.h>
Willy Tarreau48d25b32020-06-04 18:58:52 +020053#include <haproxy/session.h>
Willy Tarreau2eec9b52020-06-04 19:58:55 +020054#include <haproxy/stats-t.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020055#include <haproxy/stream.h>
Willy Tarreau5e539c92020-06-04 20:45:39 +020056#include <haproxy/stream_interface.h>
Willy Tarreaucea0e1b2020-06-04 17:25:40 +020057#include <haproxy/task.h>
Willy Tarreau8b550af2020-06-04 17:42:48 +020058#include <haproxy/tcp_rules.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020059#include <haproxy/thread.h>
Willy Tarreau48fbcae2020-06-03 18:09:46 +020060#include <haproxy/tools.h>
Willy Tarreaua1718922020-06-04 16:25:31 +020061#include <haproxy/vars.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020062#include <haproxy/xref.h>
63
Thierry FOURNIER380d0932015-01-23 14:27:52 +010064
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +010065/* Lua uses longjmp to perform yield or throwing errors. This
66 * macro is used only for identifying the function that can
67 * not return because a longjmp is executed.
68 * __LJMP marks a prototype of hlua file that can use longjmp.
69 * WILL_LJMP() marks an lua function that will use longjmp.
70 * MAY_LJMP() marks an lua function that may use longjmp.
71 */
72#define __LJMP
Willy Tarreau4e7cc332018-10-20 17:45:48 +020073#define WILL_LJMP(func) do { func; my_unreachable(); } while(0)
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +010074#define MAY_LJMP(func) func
75
Thierry FOURNIERbabae282015-09-17 11:36:37 +020076/* This couple of function executes securely some Lua calls outside of
77 * the lua runtime environment. Each Lua call can return a longjmp
78 * if it encounter a memory error.
79 *
80 * Lua documentation extract:
81 *
82 * If an error happens outside any protected environment, Lua calls
83 * a panic function (see lua_atpanic) and then calls abort, thus
84 * exiting the host application. Your panic function can avoid this
85 * exit by never returning (e.g., doing a long jump to your own
86 * recovery point outside Lua).
87 *
88 * The panic function runs as if it were a message handler (see
89 * §2.3); in particular, the error message is at the top of the
90 * stack. However, there is no guarantee about stack space. To push
91 * anything on the stack, the panic function must first check the
92 * available space (see §4.2).
93 *
94 * We must check all the Lua entry point. This includes:
95 * - The include/proto/hlua.h exported functions
96 * - the task wrapper function
97 * - The action wrapper function
98 * - The converters wrapper function
99 * - The sample-fetch wrapper functions
100 *
Ilya Shipitsin46a030c2020-07-05 16:36:08 +0500101 * It is tolerated that the initialisation function returns an abort.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -0800102 * Before each Lua abort, an error message is written on stderr.
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200103 *
104 * The macro SET_SAFE_LJMP initialise the longjmp. The Macro
105 * RESET_SAFE_LJMP reset the longjmp. These function must be macro
106 * because they must be exists in the program stack when the longjmp
107 * is called.
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +0200108 *
109 * Note that the Lua processing is not really thread safe. It provides
110 * heavy system which consists to add our own lock function in the Lua
111 * code and recompile the library. This system will probably not accepted
112 * by maintainers of various distribs.
113 *
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500114 * Our main execution point of the Lua is the function lua_resume(). A
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +0200115 * quick looking on the Lua sources displays a lua_lock() a the start
116 * of function and a lua_unlock() at the end of the function. So I
117 * conclude that the Lua thread safe mode just perform a mutex around
118 * all execution. So I prefer to do this in the HAProxy code, it will be
119 * easier for distro maintainers.
120 *
121 * Note that the HAProxy lua functions rounded by the macro SET_SAFE_LJMP
122 * and RESET_SAFE_LJMP manipulates the Lua stack, so it will be careful
123 * to set mutex around these functions.
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200124 */
Willy Tarreau86abe442018-11-25 20:12:18 +0100125__decl_spinlock(hlua_global_lock);
Thierry FOURNIERffbad792017-07-12 11:39:04 +0200126THREAD_LOCAL jmp_buf safe_ljmp_env;
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200127static int hlua_panic_safe(lua_State *L) { return 0; }
Willy Tarreau6a510902021-07-14 19:41:25 +0200128static int hlua_panic_ljmp(lua_State *L) { WILL_LJMP(longjmp(safe_ljmp_env, 1)); return 0; }
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200129
Thierry Fournier62a22aa2020-11-28 21:06:35 +0100130/* This is the chained list of struct hlua_function referenced
131 * for haproxy action, sample-fetches, converters, cli and
132 * applet bindings. It is used for a post-initialisation control.
133 */
134static struct list referenced_functions = LIST_HEAD_INIT(referenced_functions);
135
Thierry Fournierc7492592020-11-28 23:57:24 +0100136/* This variable is used only during initialization to identify the Lua state
137 * currently being initialized. 0 is the common lua state, 1 to n are the Lua
138 * states dedicated to each thread (in this case hlua_state_id==tid+1).
139 */
140static int hlua_state_id;
141
Thierry Fournier59f11be2020-11-29 00:37:41 +0100142/* This is a NULL-terminated list of lua file which are referenced to load per thread */
143static char **per_thread_load = NULL;
144
145lua_State *hlua_init_state(int thread_id);
146
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100147#define SET_SAFE_LJMP_L(__L, __HLUA) \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200148 ({ \
149 int ret; \
Thierry Fournier021d9862020-11-28 23:42:03 +0100150 if ((__HLUA)->state_id == 0) \
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100151 HA_SPIN_LOCK(LUA_LOCK, &hlua_global_lock); \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200152 if (setjmp(safe_ljmp_env) != 0) { \
153 lua_atpanic(__L, hlua_panic_safe); \
154 ret = 0; \
Thierry Fournier021d9862020-11-28 23:42:03 +0100155 if ((__HLUA)->state_id == 0) \
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100156 HA_SPIN_UNLOCK(LUA_LOCK, &hlua_global_lock); \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200157 } else { \
158 lua_atpanic(__L, hlua_panic_ljmp); \
159 ret = 1; \
160 } \
161 ret; \
162 })
163
164/* If we are the last function catching Lua errors, we
165 * must reset the panic function.
166 */
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100167#define RESET_SAFE_LJMP_L(__L, __HLUA) \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200168 do { \
169 lua_atpanic(__L, hlua_panic_safe); \
Thierry Fournier021d9862020-11-28 23:42:03 +0100170 if ((__HLUA)->state_id == 0) \
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100171 HA_SPIN_UNLOCK(LUA_LOCK, &hlua_global_lock); \
Thierry FOURNIERbabae282015-09-17 11:36:37 +0200172 } while(0)
173
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100174#define SET_SAFE_LJMP(__HLUA) \
175 SET_SAFE_LJMP_L((__HLUA)->T, __HLUA)
176
177#define RESET_SAFE_LJMP(__HLUA) \
178 RESET_SAFE_LJMP_L((__HLUA)->T, __HLUA)
179
180#define SET_SAFE_LJMP_PARENT(__HLUA) \
Thierry Fournier021d9862020-11-28 23:42:03 +0100181 SET_SAFE_LJMP_L(hlua_states[(__HLUA)->state_id], __HLUA)
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100182
183#define RESET_SAFE_LJMP_PARENT(__HLUA) \
Thierry Fournier021d9862020-11-28 23:42:03 +0100184 RESET_SAFE_LJMP_L(hlua_states[(__HLUA)->state_id], __HLUA)
Thierry Fournier7cbe5042020-11-28 17:02:21 +0100185
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +0200186/* Applet status flags */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200187#define APPLET_DONE 0x01 /* applet processing is done. */
Christopher Faulet18c2e8d2019-03-01 12:02:08 +0100188/* unused: 0x02 */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200189#define APPLET_HDR_SENT 0x04 /* Response header sent. */
Christopher Fauleta2097962019-07-15 16:25:33 +0200190/* unused: 0x08, 0x10 */
Thierry FOURNIERd93ea2b2015-12-20 19:14:52 +0100191#define APPLET_HTTP11 0x20 /* Last chunk sent. */
Christopher Faulet56a3d6e2019-02-27 22:06:23 +0100192#define APPLET_RSP_SENT 0x40 /* The response was fully sent */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200193
Thierry Fournierafc63e22020-11-28 17:06:51 +0100194/* The main Lua execution context. The 0 index is the
195 * common state shared by all threads.
196 */
Willy Tarreau186f3762020-12-04 11:48:12 +0100197static lua_State *hlua_states[MAX_THREADS + 1];
Thierry FOURNIER380d0932015-01-23 14:27:52 +0100198
Christopher Faulet69c581a2021-05-31 08:54:04 +0200199struct hlua_reg_filter {
200 char *name;
201 int flt_ref[MAX_THREADS + 1];
202 int fun_ref[MAX_THREADS + 1];
203 struct list l;
204};
205
206struct hlua_flt_config {
207 struct hlua_reg_filter *reg;
208 int ref[MAX_THREADS + 1];
209 char **args;
210};
211
212struct hlua_flt_ctx {
213 int ref; /* ref to the filter lua object */
214 struct hlua *hlua[2]; /* lua runtime context (0: request, 1: response) */
215 unsigned int cur_off[2]; /* current offset (0: request, 1: response) */
216 unsigned int cur_len[2]; /* current forwardable length (0: request, 1: response) */
217 unsigned int flags; /* HLUA_FLT_CTX_FL_* */
218};
219
220DECLARE_STATIC_POOL(pool_head_hlua_flt_ctx, "hlua_flt_ctx", sizeof(struct hlua_flt_ctx));
221
222/* This is the chained list of struct hlua_flt referenced
223 * for haproxy filters. It is used for a post-initialisation control.
224 */
225static struct list referenced_filters = LIST_HEAD_INIT(referenced_filters);
226
227
Thierry FOURNIERebed6e92016-12-16 11:54:07 +0100228/* This is the memory pool containing struct lua for applets
229 * (including cli).
230 */
Willy Tarreau8ceae722018-11-26 11:58:30 +0100231DECLARE_STATIC_POOL(pool_head_hlua, "hlua", sizeof(struct hlua));
Thierry FOURNIERebed6e92016-12-16 11:54:07 +0100232
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +0100233/* Used for Socket connection. */
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +0100234static struct proxy *socket_proxy;
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +0100235static struct server *socket_tcp;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +0100236#ifdef USE_OPENSSL
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +0100237static struct server *socket_ssl;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +0100238#endif
239
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +0100240/* List head of the function called at the initialisation time. */
Thierry Fournierc7492592020-11-28 23:57:24 +0100241struct list hlua_init_functions[MAX_THREADS + 1];
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +0100242
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +0100243/* The following variables contains the reference of the different
244 * Lua classes. These references are useful for identify metadata
245 * associated with an object.
246 */
Thierry FOURNIER65f34c62015-02-16 20:11:43 +0100247static int class_txn_ref;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +0100248static int class_socket_ref;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +0100249static int class_channel_ref;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +0100250static int class_fetches_ref;
Thierry FOURNIER594afe72015-03-10 23:58:30 +0100251static int class_converters_ref;
Thierry FOURNIER08504f42015-03-16 14:17:08 +0100252static int class_http_ref;
Thierry FOURNIER3def3932015-04-07 11:27:54 +0200253static int class_map_ref;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +0200254static int class_applet_tcp_ref;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200255static int class_applet_http_ref;
Christopher Faulet700d9e82020-01-31 12:21:52 +0100256static int class_txn_reply_ref;
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +0100257
Thierry FOURNIERbd413492015-03-03 16:52:26 +0100258/* Global Lua execution timeout. By default Lua, execution linked
Willy Tarreau87b09662015-04-03 00:22:06 +0200259 * with stream (actions, sample-fetches and converters) have a
Thierry FOURNIERbd413492015-03-03 16:52:26 +0100260 * short timeout. Lua linked with tasks doesn't have a timeout
261 * because a task may remain alive during all the haproxy execution.
262 */
263static unsigned int hlua_timeout_session = 4000; /* session timeout. */
264static unsigned int hlua_timeout_task = TICK_ETERNITY; /* task timeout. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +0200265static unsigned int hlua_timeout_applet = 4000; /* applet timeout. */
Thierry FOURNIERbd413492015-03-03 16:52:26 +0100266
Thierry FOURNIERee9f8022015-03-03 17:37:37 +0100267/* Interrupts the Lua processing each "hlua_nb_instruction" instructions.
268 * it is used for preventing infinite loops.
269 *
270 * I test the scheer with an infinite loop containing one incrementation
271 * and one test. I run this loop between 10 seconds, I raise a ceil of
272 * 710M loops from one interrupt each 9000 instructions, so I fix the value
273 * to one interrupt each 10 000 instructions.
274 *
275 * configured | Number of
276 * instructions | loops executed
277 * between two | in milions
278 * forced yields |
279 * ---------------+---------------
280 * 10 | 160
281 * 500 | 670
282 * 1000 | 680
283 * 5000 | 700
284 * 7000 | 700
285 * 8000 | 700
286 * 9000 | 710 <- ceil
287 * 10000 | 710
288 * 100000 | 710
289 * 1000000 | 710
290 *
291 */
292static unsigned int hlua_nb_instruction = 10000;
293
Willy Tarreaucdb53462020-12-02 12:12:00 +0100294/* Descriptor for the memory allocation state. The limit is pre-initialised to
295 * 0 until it is replaced by "tune.lua.maxmem" during the config parsing, or it
296 * is replaced with ~0 during post_init after everything was loaded. This way
297 * it is guaranteed that if limit is ~0 the boot is complete and that if it's
298 * zero it's not yet limited and proper accounting is required.
Willy Tarreau32f61e22015-03-18 17:54:59 +0100299 */
300struct hlua_mem_allocator {
301 size_t allocated;
302 size_t limit;
303};
304
Willy Tarreaucdb53462020-12-02 12:12:00 +0100305static struct hlua_mem_allocator hlua_global_allocator THREAD_ALIGNED(64);
Willy Tarreau32f61e22015-03-18 17:54:59 +0100306
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100307/* These functions converts types between HAProxy internal args or
308 * sample and LUA types. Another function permits to check if the
309 * LUA stack contains arguments according with an required ARG_T
310 * format.
311 */
312static int hlua_arg2lua(lua_State *L, const struct arg *arg);
313static int hlua_lua2arg(lua_State *L, int ud, struct arg *arg);
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100314__LJMP static int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp,
David Carlier0c437f42016-04-27 16:21:56 +0100315 uint64_t mask, struct proxy *p);
Willy Tarreau5eadada2015-03-10 17:28:54 +0100316static int hlua_smp2lua(lua_State *L, struct sample *smp);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100317static int hlua_smp2lua_str(lua_State *L, struct sample *smp);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100318static int hlua_lua2smp(lua_State *L, int ud, struct sample *smp);
319
Christopher Faulet9d1332b2020-02-24 16:46:16 +0100320__LJMP static int hlua_http_get_headers(lua_State *L, struct http_msg *msg);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200321
Thierry Fournier59f11be2020-11-29 00:37:41 +0100322struct prepend_path {
323 struct list l;
324 char *type;
325 char *path;
326};
327
328static struct list prepend_path_list = LIST_HEAD_INIT(prepend_path_list);
329
Thierry FOURNIER23bc3752015-09-11 19:15:43 +0200330#define SEND_ERR(__be, __fmt, __args...) \
331 do { \
332 send_log(__be, LOG_ERR, __fmt, ## __args); \
333 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) \
Christopher Faulet767a84b2017-11-24 16:50:31 +0100334 ha_alert(__fmt, ## __args); \
Thierry FOURNIER23bc3752015-09-11 19:15:43 +0200335 } while (0)
336
Thierry Fournier62a22aa2020-11-28 21:06:35 +0100337static inline struct hlua_function *new_hlua_function()
338{
339 struct hlua_function *fcn;
Thierry Fournierc7492592020-11-28 23:57:24 +0100340 int i;
Thierry Fournier62a22aa2020-11-28 21:06:35 +0100341
342 fcn = calloc(1, sizeof(*fcn));
343 if (!fcn)
344 return NULL;
Willy Tarreau2b718102021-04-21 07:32:39 +0200345 LIST_APPEND(&referenced_functions, &fcn->l);
Thierry Fournierc7492592020-11-28 23:57:24 +0100346 for (i = 0; i < MAX_THREADS + 1; i++)
347 fcn->function_ref[i] = -1;
Thierry Fournier62a22aa2020-11-28 21:06:35 +0100348 return fcn;
349}
350
Christopher Fauletdda44442021-04-12 14:05:43 +0200351static inline void release_hlua_function(struct hlua_function *fcn)
352{
353 if (!fcn)
354 return;
355 if (fcn->name)
356 ha_free(&fcn->name);
Willy Tarreau2b718102021-04-21 07:32:39 +0200357 LIST_DELETE(&fcn->l);
Christopher Fauletdda44442021-04-12 14:05:43 +0200358 ha_free(&fcn);
359}
360
Thierry Fournierc7492592020-11-28 23:57:24 +0100361/* If the common state is set, the stack id is 0, otherwise it is the tid + 1 */
362static inline int fcn_ref_to_stack_id(struct hlua_function *fcn)
363{
364 if (fcn->function_ref[0] == -1)
365 return tid + 1;
366 return 0;
367}
368
Christopher Faulet69c581a2021-05-31 08:54:04 +0200369/* Create a new registered filter. Only its name is filled */
370static inline struct hlua_reg_filter *new_hlua_reg_filter(const char *name)
371{
372 struct hlua_reg_filter *reg_flt;
373 int i;
374
375 reg_flt = calloc(1, sizeof(*reg_flt));
376 if (!reg_flt)
377 return NULL;
378 reg_flt->name = strdup(name);
379 if (!reg_flt->name) {
380 free(reg_flt);
381 return NULL;
382 }
383 LIST_APPEND(&referenced_filters, &reg_flt->l);
384 for (i = 0; i < MAX_THREADS + 1; i++) {
385 reg_flt->flt_ref[i] = -1;
386 reg_flt->fun_ref[i] = -1;
387 }
388 return reg_flt;
389}
390
391/* Release a registered filter */
392static inline void release_hlua_reg_filter(struct hlua_reg_filter *reg_flt)
393{
394 if (!reg_flt)
395 return;
396 if (reg_flt->name)
397 ha_free(&reg_flt->name);
398 LIST_DELETE(&reg_flt->l);
399 ha_free(&reg_flt);
400}
401
402/* If the common state is set, the stack id is 0, otherwise it is the tid + 1 */
403static inline int reg_flt_to_stack_id(struct hlua_reg_filter *reg_flt)
404{
405 if (reg_flt->fun_ref[0] == -1)
406 return tid + 1;
407 return 0;
408}
409
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100410/* Used to check an Lua function type in the stack. It creates and
411 * returns a reference of the function. This function throws an
412 * error if the rgument is not a "function".
413 */
414__LJMP unsigned int hlua_checkfunction(lua_State *L, int argno)
415{
416 if (!lua_isfunction(L, argno)) {
Thierry FOURNIERfd1e9552018-02-23 18:41:18 +0100417 const char *msg = lua_pushfstring(L, "function expected, got %s", luaL_typename(L, argno));
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100418 WILL_LJMP(luaL_argerror(L, argno, msg));
419 }
420 lua_pushvalue(L, argno);
421 return luaL_ref(L, LUA_REGISTRYINDEX);
422}
423
Christopher Fauletba9e21d2020-02-25 10:20:04 +0100424/* Used to check an Lua table type in the stack. It creates and
425 * returns a reference of the table. This function throws an
426 * error if the rgument is not a "table".
427 */
428__LJMP unsigned int hlua_checktable(lua_State *L, int argno)
429{
430 if (!lua_istable(L, argno)) {
431 const char *msg = lua_pushfstring(L, "table expected, got %s", luaL_typename(L, argno));
432 WILL_LJMP(luaL_argerror(L, argno, msg));
433 }
434 lua_pushvalue(L, argno);
435 return luaL_ref(L, LUA_REGISTRYINDEX);
436}
437
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +0200438/* Return the string that is of the top of the stack. */
439const char *hlua_get_top_error_string(lua_State *L)
440{
441 if (lua_gettop(L) < 1)
442 return "unknown error";
443 if (lua_type(L, -1) != LUA_TSTRING)
444 return "unknown error";
445 return lua_tostring(L, -1);
446}
447
Christopher Fauletd09cc512021-03-24 14:48:45 +0100448__LJMP const char *hlua_traceback(lua_State *L, const char* sep)
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200449{
450 lua_Debug ar;
451 int level = 0;
Willy Tarreau83061a82018-07-13 11:56:34 +0200452 struct buffer *msg = get_trash_chunk();
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200453
454 while (lua_getstack(L, level++, &ar)) {
455
456 /* Add separator */
Christopher Fauletd09cc512021-03-24 14:48:45 +0100457 if (b_data(msg))
458 chunk_appendf(msg, "%s", sep);
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200459
460 /* Fill fields:
461 * 'S': fills in the fields source, short_src, linedefined, lastlinedefined, and what;
462 * 'l': fills in the field currentline;
463 * 'n': fills in the field name and namewhat;
464 * 't': fills in the field istailcall;
465 */
466 lua_getinfo(L, "Slnt", &ar);
467
468 /* Append code localisation */
469 if (ar.currentline > 0)
Christopher Fauletd09cc512021-03-24 14:48:45 +0100470 chunk_appendf(msg, "%s:%d: ", ar.short_src, ar.currentline);
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200471 else
Christopher Fauletd09cc512021-03-24 14:48:45 +0100472 chunk_appendf(msg, "%s: ", ar.short_src);
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200473
474 /*
475 * Get function name
476 *
477 * if namewhat is no empty, name is defined.
478 * what contains "Lua" for Lua function, "C" for C function,
479 * or "main" for main code.
480 */
481 if (*ar.namewhat != '\0' && ar.name != NULL) /* is there a name from code? */
Christopher Fauletd09cc512021-03-24 14:48:45 +0100482 chunk_appendf(msg, "in %s '%s'", ar.namewhat, ar.name); /* use it */
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200483
484 else if (*ar.what == 'm') /* "main", the code is not executed in a function */
Christopher Fauletd09cc512021-03-24 14:48:45 +0100485 chunk_appendf(msg, "in main chunk");
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200486
487 else if (*ar.what != 'C') /* for Lua functions, use <file:line> */
Christopher Fauletd09cc512021-03-24 14:48:45 +0100488 chunk_appendf(msg, "in function line %d", ar.linedefined);
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200489
490 else /* nothing left... */
491 chunk_appendf(msg, "?");
492
493
494 /* Display tailed call */
495 if (ar.istailcall)
496 chunk_appendf(msg, " ...");
497 }
498
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200499 return msg->area;
Thierry FOURNIERfc044c92018-06-07 14:40:48 +0200500}
501
502
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100503/* This function check the number of arguments available in the
504 * stack. If the number of arguments available is not the same
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +0500505 * then <nb> an error is thrown.
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100506 */
507__LJMP static inline void check_args(lua_State *L, int nb, char *fcn)
508{
509 if (lua_gettop(L) == nb)
510 return;
511 WILL_LJMP(luaL_error(L, "'%s' needs %d arguments", fcn, nb));
512}
513
Mark Lakes22154b42018-01-29 14:38:40 -0800514/* This function pushes an error string prefixed by the file name
Thierry FOURNIERe8b9a402015-02-25 18:48:12 +0100515 * and the line number where the error is encountered.
516 */
517static int hlua_pusherror(lua_State *L, const char *fmt, ...)
518{
519 va_list argp;
520 va_start(argp, fmt);
521 luaL_where(L, 1);
522 lua_pushvfstring(L, fmt, argp);
523 va_end(argp);
524 lua_concat(L, 2);
525 return 1;
526}
527
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100528/* This functions is used with sample fetch and converters. It
529 * converts the HAProxy configuration argument in a lua stack
530 * values.
531 *
532 * It takes an array of "arg", and each entry of the array is
533 * converted and pushed in the LUA stack.
534 */
535static int hlua_arg2lua(lua_State *L, const struct arg *arg)
536{
537 switch (arg->type) {
538 case ARGT_SINT:
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100539 case ARGT_TIME:
540 case ARGT_SIZE:
Thierry FOURNIERf90838b2015-03-06 13:48:32 +0100541 lua_pushinteger(L, arg->data.sint);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100542 break;
543
544 case ARGT_STR:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200545 lua_pushlstring(L, arg->data.str.area, arg->data.str.data);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100546 break;
547
548 case ARGT_IPV4:
549 case ARGT_IPV6:
550 case ARGT_MSK4:
551 case ARGT_MSK6:
552 case ARGT_FE:
553 case ARGT_BE:
554 case ARGT_TAB:
555 case ARGT_SRV:
556 case ARGT_USR:
557 case ARGT_MAP:
558 default:
559 lua_pushnil(L);
560 break;
561 }
562 return 1;
563}
564
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +0500565/* This function take one entry in an LUA stack at the index "ud",
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100566 * and try to convert it in an HAProxy argument entry. This is useful
Ilya Shipitsind4259502020-04-08 01:07:56 +0500567 * with sample fetch wrappers. The input arguments are given to the
568 * lua wrapper and converted as arg list by the function.
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100569 */
570static int hlua_lua2arg(lua_State *L, int ud, struct arg *arg)
571{
572 switch (lua_type(L, ud)) {
573
574 case LUA_TNUMBER:
575 case LUA_TBOOLEAN:
576 arg->type = ARGT_SINT;
577 arg->data.sint = lua_tointeger(L, ud);
578 break;
579
580 case LUA_TSTRING:
581 arg->type = ARGT_STR;
Tim Duesterhus2e89dec2019-09-29 23:03:08 +0200582 arg->data.str.area = (char *)lua_tolstring(L, ud, &arg->data.str.data);
Tim Duesterhus29d2e8a2019-09-29 23:03:07 +0200583 /* We don't know the actual size of the underlying allocation, so be conservative. */
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200584 arg->data.str.size = arg->data.str.data+1; /* count the terminating null byte */
Tim Duesterhus29d2e8a2019-09-29 23:03:07 +0200585 arg->data.str.head = 0;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100586 break;
587
588 case LUA_TUSERDATA:
589 case LUA_TNIL:
590 case LUA_TTABLE:
591 case LUA_TFUNCTION:
592 case LUA_TTHREAD:
593 case LUA_TLIGHTUSERDATA:
594 arg->type = ARGT_SINT;
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200595 arg->data.sint = 0;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100596 break;
597 }
598 return 1;
599}
600
601/* the following functions are used to convert a struct sample
602 * in Lua type. This useful to convert the return of the
Ilya Shipitsind4259502020-04-08 01:07:56 +0500603 * fetches or converters.
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100604 */
Willy Tarreau5eadada2015-03-10 17:28:54 +0100605static int hlua_smp2lua(lua_State *L, struct sample *smp)
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100606{
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200607 switch (smp->data.type) {
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100608 case SMP_T_SINT:
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100609 case SMP_T_BOOL:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200610 lua_pushinteger(L, smp->data.u.sint);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100611 break;
612
613 case SMP_T_BIN:
614 case SMP_T_STR:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200615 lua_pushlstring(L, smp->data.u.str.area, smp->data.u.str.data);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100616 break;
617
618 case SMP_T_METH:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200619 switch (smp->data.u.meth.meth) {
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100620 case HTTP_METH_OPTIONS: lua_pushstring(L, "OPTIONS"); break;
621 case HTTP_METH_GET: lua_pushstring(L, "GET"); break;
622 case HTTP_METH_HEAD: lua_pushstring(L, "HEAD"); break;
623 case HTTP_METH_POST: lua_pushstring(L, "POST"); break;
624 case HTTP_METH_PUT: lua_pushstring(L, "PUT"); break;
625 case HTTP_METH_DELETE: lua_pushstring(L, "DELETE"); break;
626 case HTTP_METH_TRACE: lua_pushstring(L, "TRACE"); break;
627 case HTTP_METH_CONNECT: lua_pushstring(L, "CONNECT"); break;
628 case HTTP_METH_OTHER:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200629 lua_pushlstring(L, smp->data.u.meth.str.area, smp->data.u.meth.str.data);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100630 break;
631 default:
632 lua_pushnil(L);
633 break;
634 }
635 break;
636
637 case SMP_T_IPV4:
638 case SMP_T_IPV6:
639 case SMP_T_ADDR: /* This type is never used to qualify a sample. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200640 if (sample_casts[smp->data.type][SMP_T_STR] &&
641 sample_casts[smp->data.type][SMP_T_STR](smp))
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200642 lua_pushlstring(L, smp->data.u.str.area, smp->data.u.str.data);
Willy Tarreau5eadada2015-03-10 17:28:54 +0100643 else
644 lua_pushnil(L);
645 break;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100646 default:
647 lua_pushnil(L);
648 break;
649 }
650 return 1;
651}
652
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100653/* the following functions are used to convert a struct sample
654 * in Lua strings. This is useful to convert the return of the
Ilya Shipitsind4259502020-04-08 01:07:56 +0500655 * fetches or converters.
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100656 */
657static int hlua_smp2lua_str(lua_State *L, struct sample *smp)
658{
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200659 switch (smp->data.type) {
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100660
661 case SMP_T_BIN:
662 case SMP_T_STR:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200663 lua_pushlstring(L, smp->data.u.str.area, smp->data.u.str.data);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100664 break;
665
666 case SMP_T_METH:
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200667 switch (smp->data.u.meth.meth) {
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100668 case HTTP_METH_OPTIONS: lua_pushstring(L, "OPTIONS"); break;
669 case HTTP_METH_GET: lua_pushstring(L, "GET"); break;
670 case HTTP_METH_HEAD: lua_pushstring(L, "HEAD"); break;
671 case HTTP_METH_POST: lua_pushstring(L, "POST"); break;
672 case HTTP_METH_PUT: lua_pushstring(L, "PUT"); break;
673 case HTTP_METH_DELETE: lua_pushstring(L, "DELETE"); break;
674 case HTTP_METH_TRACE: lua_pushstring(L, "TRACE"); break;
675 case HTTP_METH_CONNECT: lua_pushstring(L, "CONNECT"); break;
676 case HTTP_METH_OTHER:
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200677 lua_pushlstring(L, smp->data.u.meth.str.area, smp->data.u.meth.str.data);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100678 break;
679 default:
680 lua_pushstring(L, "");
681 break;
682 }
683 break;
684
685 case SMP_T_SINT:
686 case SMP_T_BOOL:
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100687 case SMP_T_IPV4:
688 case SMP_T_IPV6:
689 case SMP_T_ADDR: /* This type is never used to qualify a sample. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200690 if (sample_casts[smp->data.type][SMP_T_STR] &&
691 sample_casts[smp->data.type][SMP_T_STR](smp))
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200692 lua_pushlstring(L, smp->data.u.str.area, smp->data.u.str.data);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +0100693 else
694 lua_pushstring(L, "");
695 break;
696 default:
697 lua_pushstring(L, "");
698 break;
699 }
700 return 1;
701}
702
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100703/* the following functions are used to convert an Lua type in a
704 * struct sample. This is useful to provide data from a converter
705 * to the LUA code.
706 */
707static int hlua_lua2smp(lua_State *L, int ud, struct sample *smp)
708{
709 switch (lua_type(L, ud)) {
710
711 case LUA_TNUMBER:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200712 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200713 smp->data.u.sint = lua_tointeger(L, ud);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100714 break;
715
716
717 case LUA_TBOOLEAN:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200718 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200719 smp->data.u.sint = lua_toboolean(L, ud);
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100720 break;
721
722 case LUA_TSTRING:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200723 smp->data.type = SMP_T_STR;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100724 smp->flags |= SMP_F_CONST;
Tim Duesterhus2e89dec2019-09-29 23:03:08 +0200725 smp->data.u.str.area = (char *)lua_tolstring(L, ud, &smp->data.u.str.data);
Tim Duesterhus29d2e8a2019-09-29 23:03:07 +0200726 /* We don't know the actual size of the underlying allocation, so be conservative. */
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200727 smp->data.u.str.size = smp->data.u.str.data+1; /* count the terminating null byte */
Tim Duesterhus29d2e8a2019-09-29 23:03:07 +0200728 smp->data.u.str.head = 0;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100729 break;
730
731 case LUA_TUSERDATA:
732 case LUA_TNIL:
733 case LUA_TTABLE:
734 case LUA_TFUNCTION:
735 case LUA_TTHREAD:
736 case LUA_TLIGHTUSERDATA:
Thierry FOURNIER93405e12015-08-26 14:19:03 +0200737 case LUA_TNONE:
738 default:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200739 smp->data.type = SMP_T_BOOL;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200740 smp->data.u.sint = 0;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100741 break;
742 }
743 return 1;
744}
745
Ilya Shipitsind4259502020-04-08 01:07:56 +0500746/* This function check the "argp" built by another conversion function
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -0800747 * is in accord with the expected argp defined by the "mask". The function
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100748 * returns true or false. It can be adjust the types if there compatibles.
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100749 *
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +0500750 * This function assumes that the argp argument contains ARGM_NBARGS + 1
Willy Tarreauee0d7272021-07-16 10:26:56 +0200751 * entries and that there is at least one stop at the last position.
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100752 */
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100753__LJMP int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp,
David Carlier0c437f42016-04-27 16:21:56 +0100754 uint64_t mask, struct proxy *p)
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100755{
756 int min_arg;
Willy Tarreauee0d7272021-07-16 10:26:56 +0200757 int idx;
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100758 struct proxy *px;
Christopher Fauletd25d9262020-08-06 11:04:46 +0200759 struct userlist *ul;
Christopher Fauletfd2e9062020-08-06 11:10:57 +0200760 struct my_regex *reg;
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200761 const char *msg = NULL;
Christopher Fauletfd2e9062020-08-06 11:10:57 +0200762 char *sname, *pname, *err = NULL;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100763
764 idx = 0;
765 min_arg = ARGM(mask);
766 mask >>= ARGM_BITS;
767
768 while (1) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200769 struct buffer tmp = BUF_NULL;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100770
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100771 /* Check for mandatory arguments. */
772 if (argp[idx].type == ARGT_STOP) {
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100773 if (idx < min_arg) {
774
775 /* If miss other argument than the first one, we return an error. */
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200776 if (idx > 0) {
777 msg = "Mandatory argument expected";
778 goto error;
779 }
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100780
781 /* If first argument have a certain type, some default values
782 * may be used. See the function smp_resolve_args().
783 */
784 switch (mask & ARGT_MASK) {
785
786 case ARGT_FE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200787 if (!(p->cap & PR_CAP_FE)) {
788 msg = "Mandatory argument expected";
789 goto error;
790 }
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100791 argp[idx].data.prx = p;
792 argp[idx].type = ARGT_FE;
793 argp[idx+1].type = ARGT_STOP;
794 break;
795
796 case ARGT_BE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200797 if (!(p->cap & PR_CAP_BE)) {
798 msg = "Mandatory argument expected";
799 goto error;
800 }
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100801 argp[idx].data.prx = p;
802 argp[idx].type = ARGT_BE;
803 argp[idx+1].type = ARGT_STOP;
804 break;
805
806 case ARGT_TAB:
807 argp[idx].data.prx = p;
808 argp[idx].type = ARGT_TAB;
809 argp[idx+1].type = ARGT_STOP;
810 break;
811
812 default:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200813 msg = "Mandatory argument expected";
814 goto error;
Thierry FOURNIER3caa0392015-03-13 13:38:17 +0100815 break;
816 }
817 }
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200818 break;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100819 }
820
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500821 /* Check for exceed the number of required argument. */
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100822 if ((mask & ARGT_MASK) == ARGT_STOP &&
823 argp[idx].type != ARGT_STOP) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200824 msg = "Last argument expected";
825 goto error;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100826 }
827
828 if ((mask & ARGT_MASK) == ARGT_STOP &&
829 argp[idx].type == ARGT_STOP) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200830 break;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100831 }
832
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200833 /* Convert some argument types. All string in argp[] are for not
834 * duplicated yet.
835 */
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100836 switch (mask & ARGT_MASK) {
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100837 case ARGT_SINT:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200838 if (argp[idx].type != ARGT_SINT) {
839 msg = "integer expected";
840 goto error;
841 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100842 argp[idx].type = ARGT_SINT;
843 break;
844
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100845 case ARGT_TIME:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200846 if (argp[idx].type != ARGT_SINT) {
847 msg = "integer expected";
848 goto error;
849 }
Thierry FOURNIER29176f32015-07-07 00:41:29 +0200850 argp[idx].type = ARGT_TIME;
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100851 break;
852
853 case ARGT_SIZE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200854 if (argp[idx].type != ARGT_SINT) {
855 msg = "integer expected";
856 goto error;
857 }
Thierry FOURNIER29176f32015-07-07 00:41:29 +0200858 argp[idx].type = ARGT_SIZE;
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100859 break;
860
861 case ARGT_FE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200862 if (argp[idx].type != ARGT_STR) {
863 msg = "string expected";
864 goto error;
865 }
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200866 argp[idx].data.prx = proxy_fe_by_name(argp[idx].data.str.area);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200867 if (!argp[idx].data.prx) {
868 msg = "frontend doesn't exist";
869 goto error;
870 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100871 argp[idx].type = ARGT_FE;
872 break;
873
874 case ARGT_BE:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200875 if (argp[idx].type != ARGT_STR) {
876 msg = "string expected";
877 goto error;
878 }
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200879 argp[idx].data.prx = proxy_be_by_name(argp[idx].data.str.area);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200880 if (!argp[idx].data.prx) {
881 msg = "backend doesn't exist";
882 goto error;
883 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100884 argp[idx].type = ARGT_BE;
885 break;
886
887 case ARGT_TAB:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200888 if (argp[idx].type != ARGT_STR) {
889 msg = "string expected";
890 goto error;
891 }
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200892 argp[idx].data.t = stktable_find_by_name(argp[idx].data.str.area);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200893 if (!argp[idx].data.t) {
894 msg = "table doesn't exist";
895 goto error;
896 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100897 argp[idx].type = ARGT_TAB;
898 break;
899
900 case ARGT_SRV:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200901 if (argp[idx].type != ARGT_STR) {
902 msg = "string expected";
903 goto error;
904 }
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200905 sname = strrchr(argp[idx].data.str.area, '/');
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100906 if (sname) {
907 *sname++ = '\0';
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200908 pname = argp[idx].data.str.area;
Willy Tarreau9e0bb102015-05-26 11:24:42 +0200909 px = proxy_be_by_name(pname);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200910 if (!px) {
911 msg = "backend doesn't exist";
912 goto error;
913 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100914 }
915 else {
Christopher Fauletfdea1b62020-08-06 08:29:18 +0200916 sname = argp[idx].data.str.area;
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100917 px = p;
Thierry FOURNIER55da1652015-01-23 11:36:30 +0100918 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100919 argp[idx].data.srv = findserver(px, sname);
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200920 if (!argp[idx].data.srv) {
921 msg = "server doesn't exist";
922 goto error;
923 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100924 argp[idx].type = ARGT_SRV;
925 break;
926
927 case ARGT_IPV4:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200928 if (argp[idx].type != ARGT_STR) {
929 msg = "string expected";
930 goto error;
931 }
932 if (inet_pton(AF_INET, argp[idx].data.str.area, &argp[idx].data.ipv4)) {
933 msg = "invalid IPv4 address";
934 goto error;
935 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100936 argp[idx].type = ARGT_IPV4;
937 break;
938
939 case ARGT_MSK4:
Christopher Faulete663a6e2020-08-07 09:11:22 +0200940 if (argp[idx].type == ARGT_SINT)
941 len2mask4(argp[idx].data.sint, &argp[idx].data.ipv4);
942 else if (argp[idx].type == ARGT_STR) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200943 if (!str2mask(argp[idx].data.str.area, &argp[idx].data.ipv4)) {
944 msg = "invalid IPv4 mask";
945 goto error;
946 }
947 }
948 else {
949 msg = "integer or string expected";
950 goto error;
Christopher Faulete663a6e2020-08-07 09:11:22 +0200951 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100952 argp[idx].type = ARGT_MSK4;
953 break;
954
955 case ARGT_IPV6:
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200956 if (argp[idx].type != ARGT_STR) {
957 msg = "string expected";
958 goto error;
959 }
960 if (inet_pton(AF_INET6, argp[idx].data.str.area, &argp[idx].data.ipv6)) {
961 msg = "invalid IPv6 address";
962 goto error;
963 }
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100964 argp[idx].type = ARGT_IPV6;
965 break;
966
967 case ARGT_MSK6:
Christopher Faulete663a6e2020-08-07 09:11:22 +0200968 if (argp[idx].type == ARGT_SINT)
969 len2mask6(argp[idx].data.sint, &argp[idx].data.ipv6);
970 else if (argp[idx].type == ARGT_STR) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +0200971 if (!str2mask6(argp[idx].data.str.area, &argp[idx].data.ipv6)) {
972 msg = "invalid IPv6 mask";
973 goto error;
974 }
975 }
976 else {
977 msg = "integer or string expected";
978 goto error;
Christopher Faulete663a6e2020-08-07 09:11:22 +0200979 }
Tim Duesterhusb814da62018-01-25 16:24:50 +0100980 argp[idx].type = ARGT_MSK6;
981 break;
982
Christopher Fauletfd2e9062020-08-06 11:10:57 +0200983 case ARGT_REG:
984 if (argp[idx].type != ARGT_STR) {
985 msg = "string expected";
986 goto error;
987 }
988 reg = regex_comp(argp[idx].data.str.area, !(argp[idx].type_flags & ARGF_REG_ICASE), 1, &err);
989 if (!reg) {
990 msg = lua_pushfstring(L, "error compiling regex '%s' : '%s'",
991 argp[idx].data.str.area, err);
992 free(err);
993 goto error;
994 }
995 argp[idx].type = ARGT_REG;
996 argp[idx].data.reg = reg;
997 break;
998
Thierry FOURNIER7f4942a2015-03-12 18:28:50 +0100999 case ARGT_USR:
Christopher Fauletd25d9262020-08-06 11:04:46 +02001000 if (argp[idx].type != ARGT_STR) {
1001 msg = "string expected";
1002 goto error;
1003 }
1004 if (p->uri_auth && p->uri_auth->userlist &&
Tim Duesterhuse5ff1412021-01-02 22:31:53 +01001005 strcmp(p->uri_auth->userlist->name, argp[idx].data.str.area) == 0)
Christopher Fauletd25d9262020-08-06 11:04:46 +02001006 ul = p->uri_auth->userlist;
1007 else
1008 ul = auth_find_userlist(argp[idx].data.str.area);
1009
1010 if (!ul) {
1011 msg = lua_pushfstring(L, "unable to find userlist '%s'", argp[idx].data.str.area);
1012 goto error;
1013 }
1014 argp[idx].type = ARGT_USR;
1015 argp[idx].data.usr = ul;
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001016 break;
1017
1018 case ARGT_STR:
1019 if (!chunk_dup(&tmp, &argp[idx].data.str)) {
1020 msg = "unable to duplicate string arg";
1021 goto error;
1022 }
1023 argp[idx].data.str = tmp;
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001024 break;
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001025
Christopher Fauletd25d9262020-08-06 11:04:46 +02001026 case ARGT_MAP:
Christopher Fauletd25d9262020-08-06 11:04:46 +02001027 msg = "type not yet supported";
1028 goto error;
1029 break;
1030
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001031 }
1032
1033 /* Check for type of argument. */
1034 if ((mask & ARGT_MASK) != argp[idx].type) {
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001035 msg = lua_pushfstring(L, "'%s' expected, got '%s'",
1036 arg_type_names[(mask & ARGT_MASK)],
1037 arg_type_names[argp[idx].type & ARGT_MASK]);
1038 goto error;
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001039 }
1040
1041 /* Next argument. */
1042 mask >>= ARGT_BITS;
1043 idx++;
1044 }
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001045 return 0;
1046
1047 error:
Willy Tarreauee0d7272021-07-16 10:26:56 +02001048 free_args(argp);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02001049 WILL_LJMP(luaL_argerror(L, first + idx, msg));
1050 return 0; /* Never reached */
Thierry FOURNIER55da1652015-01-23 11:36:30 +01001051}
1052
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001053/*
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +05001054 * The following functions are used to make correspondence between the the
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001055 * executed lua pointer and the "struct hlua *" that contain the context.
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001056 *
1057 * - hlua_gethlua : return the hlua context associated with an lua_State.
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001058 * - hlua_sethlua : create the association between hlua context and lua_state.
1059 */
1060static inline struct hlua *hlua_gethlua(lua_State *L)
1061{
Thierry FOURNIER38c5fd62015-03-10 02:40:29 +01001062 struct hlua **hlua = lua_getextraspace(L);
1063 return *hlua;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001064}
1065static inline void hlua_sethlua(struct hlua *hlua)
1066{
Thierry FOURNIER38c5fd62015-03-10 02:40:29 +01001067 struct hlua **hlua_store = lua_getextraspace(hlua->T);
1068 *hlua_store = hlua;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001069}
1070
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001071/* This function is used to send logs. It try to send on screen (stderr)
1072 * and on the default syslog server.
1073 */
1074static inline void hlua_sendlog(struct proxy *px, int level, const char *msg)
1075{
1076 struct tm tm;
1077 char *p;
1078
1079 /* Cleanup the log message. */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001080 p = trash.area;
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001081 for (; *msg != '\0'; msg++, p++) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001082 if (p >= trash.area + trash.size - 1) {
Thierry FOURNIERccf00632015-09-16 12:47:03 +02001083 /* Break the message if exceed the buffer size. */
1084 *(p-4) = ' ';
1085 *(p-3) = '.';
1086 *(p-2) = '.';
1087 *(p-1) = '.';
1088 break;
1089 }
Willy Tarreau90807112020-02-25 08:16:33 +01001090 if (isprint((unsigned char)*msg))
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001091 *p = *msg;
1092 else
1093 *p = '.';
1094 }
1095 *p = '\0';
1096
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001097 send_log(px, level, "%s\n", trash.area);
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001098 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
Christopher Fauletf98d8212020-10-02 18:13:52 +02001099 if (level == LOG_DEBUG && !(global.mode & MODE_DEBUG))
1100 return;
1101
Willy Tarreaua678b432015-08-28 10:14:59 +02001102 get_localtime(date.tv_sec, &tm);
1103 fprintf(stderr, "[%s] %03d/%02d%02d%02d (%d) : %s\n",
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001104 log_levels[level], tm.tm_yday, tm.tm_hour, tm.tm_min, tm.tm_sec,
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001105 (int)getpid(), trash.area);
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01001106 fflush(stderr);
1107 }
1108}
1109
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001110/* This function just ensure that the yield will be always
1111 * returned with a timeout and permit to set some flags
1112 */
1113__LJMP void hlua_yieldk(lua_State *L, int nresults, int ctx,
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01001114 lua_KFunction k, int timeout, unsigned int flags)
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001115{
Thierry Fournier4234dbd2020-11-28 13:18:23 +01001116 struct hlua *hlua;
1117
1118 /* Get hlua struct, or NULL if we execute from main lua state */
1119 hlua = hlua_gethlua(L);
1120 if (!hlua) {
1121 return;
1122 }
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001123
1124 /* Set the wake timeout. If timeout is required, we set
1125 * the expiration time.
1126 */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001127 hlua->wake_time = timeout;
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001128
Thierry FOURNIER4abd3ae2015-03-03 17:29:06 +01001129 hlua->flags |= flags;
1130
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001131 /* Process the yield. */
Willy Tarreau9635e032018-10-16 17:52:55 +02001132 MAY_LJMP(lua_yieldk(L, nresults, ctx, k));
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001133}
1134
Willy Tarreau87b09662015-04-03 00:22:06 +02001135/* This function initialises the Lua environment stored in the stream.
1136 * It must be called at the start of the stream. This function creates
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001137 * an LUA coroutine. It can not be use to crete the main LUA context.
Thierry FOURNIERbabae282015-09-17 11:36:37 +02001138 *
1139 * This function is particular. it initialises a new Lua thread. If the
1140 * initialisation fails (example: out of memory error), the lua function
1141 * throws an error (longjmp).
1142 *
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001143 * In some case (at least one), this function can be called from safe
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001144 * environment, so we must not initialise it. While the support of
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001145 * threads appear, the safe environment set a lock to ensure only one
1146 * Lua execution at a time. If we initialize safe environment in another
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001147 * safe environment, we have a dead lock.
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001148 *
1149 * set "already_safe" true if the context is initialized form safe
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001150 * Lua function.
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001151 *
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001152 * This function manipulates two Lua stacks: the main and the thread. Only
Thierry FOURNIERbabae282015-09-17 11:36:37 +02001153 * the main stack can fail. The thread is not manipulated. This function
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001154 * MUST NOT manipulate the created thread stack state, because it is not
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001155 * protected against errors thrown by the thread stack.
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001156 */
Thierry Fournier021d9862020-11-28 23:42:03 +01001157int hlua_ctx_init(struct hlua *lua, int state_id, struct task *task, int already_safe)
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001158{
1159 lua->Mref = LUA_REFNIL;
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01001160 lua->flags = 0;
Willy Tarreauf31af932020-01-14 09:59:38 +01001161 lua->gc_count = 0;
Christopher Fauletbc275a92020-02-26 14:55:16 +01001162 lua->wake_time = TICK_ETERNITY;
Thierry Fournier021d9862020-11-28 23:42:03 +01001163 lua->state_id = state_id;
Thierry FOURNIER9ff7e6e2015-01-23 11:08:20 +01001164 LIST_INIT(&lua->com);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001165 if (!already_safe) {
1166 if (!SET_SAFE_LJMP_PARENT(lua)) {
1167 lua->Tref = LUA_REFNIL;
1168 return 0;
1169 }
1170 }
Thierry Fournier021d9862020-11-28 23:42:03 +01001171 lua->T = lua_newthread(hlua_states[state_id]);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001172 if (!lua->T) {
1173 lua->Tref = LUA_REFNIL;
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001174 if (!already_safe)
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001175 RESET_SAFE_LJMP_PARENT(lua);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001176 return 0;
1177 }
1178 hlua_sethlua(lua);
Thierry Fournier021d9862020-11-28 23:42:03 +01001179 lua->Tref = luaL_ref(hlua_states[state_id], LUA_REGISTRYINDEX);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001180 lua->task = task;
Thierry FOURNIERbf90ce12019-01-06 19:04:24 +01001181 if (!already_safe)
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001182 RESET_SAFE_LJMP_PARENT(lua);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001183 return 1;
1184}
1185
Willy Tarreau87b09662015-04-03 00:22:06 +02001186/* Used to destroy the Lua coroutine when the attached stream or task
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001187 * is destroyed. The destroy also the memory context. The struct "lua"
1188 * is not freed.
1189 */
1190void hlua_ctx_destroy(struct hlua *lua)
1191{
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01001192 if (!lua)
Thierry FOURNIERa718b292015-03-04 16:48:34 +01001193 return;
1194
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01001195 if (!lua->T)
1196 goto end;
1197
Thierry FOURNIER9ff7e6e2015-01-23 11:08:20 +01001198 /* Purge all the pending signals. */
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001199 notification_purge(&lua->com);
Thierry FOURNIER9ff7e6e2015-01-23 11:08:20 +01001200
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001201 if (!SET_SAFE_LJMP(lua))
Thierry FOURNIER75d02082017-07-12 13:41:33 +02001202 return;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001203 luaL_unref(lua->T, LUA_REGISTRYINDEX, lua->Mref);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001204 RESET_SAFE_LJMP(lua);
Thierry FOURNIER5a50a852015-09-23 16:59:28 +02001205
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001206 if (!SET_SAFE_LJMP_PARENT(lua))
Thierry FOURNIER75d02082017-07-12 13:41:33 +02001207 return;
Thierry Fournier021d9862020-11-28 23:42:03 +01001208 luaL_unref(hlua_states[lua->state_id], LUA_REGISTRYINDEX, lua->Tref);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001209 RESET_SAFE_LJMP_PARENT(lua);
Thierry FOURNIER5a50a852015-09-23 16:59:28 +02001210 /* Forces a garbage collecting process. If the Lua program is finished
1211 * without error, we run the GC on the thread pointer. Its freed all
1212 * the unused memory.
1213 * If the thread is finnish with an error or is currently yielded,
1214 * it seems that the GC applied on the thread doesn't clean anything,
1215 * so e run the GC on the main thread.
1216 * NOTE: maybe this action locks all the Lua threads untiml the en of
1217 * the garbage collection.
1218 */
Willy Tarreauf31af932020-01-14 09:59:38 +01001219 if (lua->gc_count) {
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001220 if (!SET_SAFE_LJMP_PARENT(lua))
Thierry FOURNIER75d02082017-07-12 13:41:33 +02001221 return;
Thierry Fournier021d9862020-11-28 23:42:03 +01001222 lua_gc(hlua_states[lua->state_id], LUA_GCCOLLECT, 0);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001223 RESET_SAFE_LJMP_PARENT(lua);
Thierry FOURNIER7c39ab42015-09-27 22:53:33 +02001224 }
Thierry FOURNIER5a50a852015-09-23 16:59:28 +02001225
Thierry FOURNIERa7b536b2015-09-21 22:50:24 +02001226 lua->T = NULL;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01001227
1228end:
Willy Tarreaubafbe012017-11-24 17:34:44 +01001229 pool_free(pool_head_hlua, lua);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001230}
1231
1232/* This function is used to restore the Lua context when a coroutine
1233 * fails. This function copy the common memory between old coroutine
1234 * and the new coroutine. The old coroutine is destroyed, and its
1235 * replaced by the new coroutine.
1236 * If the flag "keep_msg" is set, the last entry of the old is assumed
1237 * as string error message and it is copied in the new stack.
1238 */
1239static int hlua_ctx_renew(struct hlua *lua, int keep_msg)
1240{
1241 lua_State *T;
1242 int new_ref;
1243
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001244 /* New Lua coroutine. */
Thierry Fournier021d9862020-11-28 23:42:03 +01001245 T = lua_newthread(hlua_states[lua->state_id]);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001246 if (!T)
1247 return 0;
1248
1249 /* Copy last error message. */
1250 if (keep_msg)
1251 lua_xmove(lua->T, T, 1);
1252
1253 /* Copy data between the coroutines. */
1254 lua_rawgeti(lua->T, LUA_REGISTRYINDEX, lua->Mref);
1255 lua_xmove(lua->T, T, 1);
Ilya Shipitsin46a030c2020-07-05 16:36:08 +05001256 new_ref = luaL_ref(T, LUA_REGISTRYINDEX); /* Value popped. */
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001257
1258 /* Destroy old data. */
1259 luaL_unref(lua->T, LUA_REGISTRYINDEX, lua->Mref);
1260
1261 /* The thread is garbage collected by Lua. */
Thierry Fournier021d9862020-11-28 23:42:03 +01001262 luaL_unref(hlua_states[lua->state_id], LUA_REGISTRYINDEX, lua->Tref);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001263
1264 /* Fill the struct with the new coroutine values. */
1265 lua->Mref = new_ref;
1266 lua->T = T;
Thierry Fournier021d9862020-11-28 23:42:03 +01001267 lua->Tref = luaL_ref(hlua_states[lua->state_id], LUA_REGISTRYINDEX);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001268
1269 /* Set context. */
1270 hlua_sethlua(lua);
1271
1272 return 1;
1273}
1274
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001275void hlua_hook(lua_State *L, lua_Debug *ar)
1276{
Thierry Fournier4234dbd2020-11-28 13:18:23 +01001277 struct hlua *hlua;
1278
1279 /* Get hlua struct, or NULL if we execute from main lua state */
1280 hlua = hlua_gethlua(L);
1281 if (!hlua)
1282 return;
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001283
1284 /* Lua cannot yield when its returning from a function,
1285 * so, we can fix the interrupt hook to 1 instruction,
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001286 * expecting that the function is finished.
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001287 */
1288 if (lua_gethookmask(L) & LUA_MASKRET) {
1289 lua_sethook(hlua->T, hlua_hook, LUA_MASKCOUNT, 1);
1290 return;
1291 }
1292
1293 /* restore the interrupt condition. */
1294 lua_sethook(hlua->T, hlua_hook, LUA_MASKCOUNT, hlua_nb_instruction);
1295
1296 /* If we interrupt the Lua processing in yieldable state, we yield.
1297 * If the state is not yieldable, trying yield causes an error.
1298 */
1299 if (lua_isyieldable(L))
Willy Tarreau9635e032018-10-16 17:52:55 +02001300 MAY_LJMP(hlua_yieldk(L, 0, 0, NULL, TICK_ETERNITY, HLUA_CTRLYIELD));
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001301
Thierry FOURNIERa85cfb12015-03-13 14:50:06 +01001302 /* If we cannot yield, update the clock and check the timeout. */
1303 tv_update_date(0, 1);
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001304 hlua->run_time += now_ms - hlua->start_time;
1305 if (hlua->max_time && hlua->run_time >= hlua->max_time) {
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001306 lua_pushfstring(L, "execution timeout");
1307 WILL_LJMP(lua_error(L));
1308 }
1309
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001310 /* Update the start time. */
1311 hlua->start_time = now_ms;
1312
Thierry FOURNIERcae49c92015-03-06 14:05:24 +01001313 /* Try to interrupt the process at the end of the current
1314 * unyieldable function.
1315 */
1316 lua_sethook(hlua->T, hlua_hook, LUA_MASKRET|LUA_MASKCOUNT, hlua_nb_instruction);
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001317}
1318
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001319/* This function start or resumes the Lua stack execution. If the flag
1320 * "yield_allowed" if no set and the LUA stack execution returns a yield
1321 * The function return an error.
1322 *
1323 * The function can returns 4 values:
1324 * - HLUA_E_OK : The execution is terminated without any errors.
1325 * - HLUA_E_AGAIN : The execution must continue at the next associated
1326 * task wakeup.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001327 * - HLUA_E_ERRMSG : An error has occurred, an error message is set in
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001328 * the top of the stack.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001329 * - HLUA_E_ERR : An error has occurred without error message.
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001330 *
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001331 * If an error occurred, the stack is renewed and it is ready to run new
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001332 * LUA code.
1333 */
1334static enum hlua_exec hlua_ctx_resume(struct hlua *lua, int yield_allowed)
1335{
Christopher Faulet08ed98f2020-07-28 10:33:25 +02001336#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
1337 int nres;
1338#endif
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001339 int ret;
1340 const char *msg;
Thierry FOURNIERfc044c92018-06-07 14:40:48 +02001341 const char *trace;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001342
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001343 /* Initialise run time counter. */
1344 if (!HLUA_IS_RUNNING(lua))
1345 lua->run_time = 0;
Thierry FOURNIERdc9ca962015-03-05 11:16:52 +01001346
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +02001347 /* Lock the whole Lua execution. This lock must be before the
1348 * label "resume_execution".
1349 */
Thierry Fournier021d9862020-11-28 23:42:03 +01001350 if (lua->state_id == 0)
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001351 HA_SPIN_LOCK(LUA_LOCK, &hlua_global_lock);
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +02001352
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001353resume_execution:
1354
1355 /* This hook interrupts the Lua processing each 'hlua_nb_instruction'
1356 * instructions. it is used for preventing infinite loops.
1357 */
1358 lua_sethook(lua->T, hlua_hook, LUA_MASKCOUNT, hlua_nb_instruction);
1359
Thierry FOURNIER1bfc09b2015-03-05 17:10:14 +01001360 /* Remove all flags except the running flags. */
Thierry FOURNIER2f3867f2015-09-28 01:02:01 +02001361 HLUA_SET_RUN(lua);
1362 HLUA_CLR_CTRLYIELD(lua);
1363 HLUA_CLR_WAKERESWR(lua);
1364 HLUA_CLR_WAKEREQWR(lua);
Christopher Faulet1f43a342021-08-04 17:58:21 +02001365 HLUA_CLR_NOYIELD(lua);
1366 if (!yield_allowed)
1367 HLUA_SET_NOYIELD(lua);
Thierry FOURNIER1bfc09b2015-03-05 17:10:14 +01001368
Christopher Fauletbc275a92020-02-26 14:55:16 +01001369 /* Update the start time and reset wake_time. */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001370 lua->start_time = now_ms;
Christopher Fauletbc275a92020-02-26 14:55:16 +01001371 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001372
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001373 /* Call the function. */
Christopher Faulet08ed98f2020-07-28 10:33:25 +02001374#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
Thierry Fournier021d9862020-11-28 23:42:03 +01001375 ret = lua_resume(lua->T, hlua_states[lua->state_id], lua->nargs, &nres);
Christopher Faulet08ed98f2020-07-28 10:33:25 +02001376#else
Thierry Fournier021d9862020-11-28 23:42:03 +01001377 ret = lua_resume(lua->T, hlua_states[lua->state_id], lua->nargs);
Christopher Faulet08ed98f2020-07-28 10:33:25 +02001378#endif
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001379 switch (ret) {
1380
1381 case LUA_OK:
1382 ret = HLUA_E_OK;
1383 break;
1384
1385 case LUA_YIELD:
Thierry FOURNIERdc9ca962015-03-05 11:16:52 +01001386 /* Check if the execution timeout is expired. It it is the case, we
1387 * break the Lua execution.
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001388 */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02001389 tv_update_date(0, 1);
1390 lua->run_time += now_ms - lua->start_time;
1391 if (lua->max_time && lua->run_time > lua->max_time) {
Thierry FOURNIERdc9ca962015-03-05 11:16:52 +01001392 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001393 ret = HLUA_E_ETMOUT;
Thierry FOURNIERdc9ca962015-03-05 11:16:52 +01001394 break;
1395 }
1396 /* Process the forced yield. if the general yield is not allowed or
1397 * if no task were associated this the current Lua execution
1398 * coroutine, we resume the execution. Else we want to return in the
1399 * scheduler and we want to be waked up again, to continue the
1400 * current Lua execution. So we schedule our own task.
1401 */
1402 if (HLUA_IS_CTRLYIELDING(lua)) {
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001403 if (!yield_allowed || !lua->task)
1404 goto resume_execution;
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001405 task_wakeup(lua->task, TASK_WOKEN_MSG);
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01001406 }
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001407 if (!yield_allowed) {
1408 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001409 ret = HLUA_E_YIELD;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001410 break;
1411 }
1412 ret = HLUA_E_AGAIN;
1413 break;
1414
1415 case LUA_ERRRUN:
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001416
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001417 /* Special exit case. The traditional exit is returned as an error
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001418 * because the errors ares the only one mean to return immediately
1419 * from and lua execution.
1420 */
1421 if (lua->flags & HLUA_EXIT) {
1422 ret = HLUA_E_OK;
Christopher Faulet7716cdf2020-01-29 11:53:30 +01001423 hlua_ctx_renew(lua, 1);
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001424 break;
1425 }
1426
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001427 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001428 if (!lua_checkstack(lua->T, 1)) {
1429 ret = HLUA_E_ERR;
1430 break;
1431 }
1432 msg = lua_tostring(lua->T, -1);
1433 lua_settop(lua->T, 0); /* Empty the stack. */
1434 lua_pop(lua->T, 1);
Christopher Fauletd09cc512021-03-24 14:48:45 +01001435 trace = hlua_traceback(lua->T, ", ");
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001436 if (msg)
Thierry Fournier46278ff2020-11-29 11:48:12 +01001437 lua_pushfstring(lua->T, "[state-id %d] runtime error: %s from %s", lua->state_id, msg, trace);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001438 else
Thierry Fournier46278ff2020-11-29 11:48:12 +01001439 lua_pushfstring(lua->T, "[state-id %d] unknown runtime error from %s", lua->state_id, trace);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001440 ret = HLUA_E_ERRMSG;
1441 break;
1442
1443 case LUA_ERRMEM:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001444 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001445 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001446 ret = HLUA_E_NOMEM;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001447 break;
1448
1449 case LUA_ERRERR:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001450 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001451 if (!lua_checkstack(lua->T, 1)) {
1452 ret = HLUA_E_ERR;
1453 break;
1454 }
1455 msg = lua_tostring(lua->T, -1);
1456 lua_settop(lua->T, 0); /* Empty the stack. */
1457 lua_pop(lua->T, 1);
1458 if (msg)
Thierry Fournier46278ff2020-11-29 11:48:12 +01001459 lua_pushfstring(lua->T, "[state-id %d] message handler error: %s", lua->state_id, msg);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001460 else
Thierry Fournier46278ff2020-11-29 11:48:12 +01001461 lua_pushfstring(lua->T, "[state-id %d] message handler error", lua->state_id);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001462 ret = HLUA_E_ERRMSG;
1463 break;
1464
1465 default:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01001466 lua->wake_time = TICK_ETERNITY;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001467 lua_settop(lua->T, 0); /* Empty the stack. */
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001468 ret = HLUA_E_ERR;
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001469 break;
1470 }
1471
1472 switch (ret) {
1473 case HLUA_E_AGAIN:
1474 break;
1475
1476 case HLUA_E_ERRMSG:
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001477 notification_purge(&lua->com);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001478 hlua_ctx_renew(lua, 1);
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01001479 HLUA_CLR_RUN(lua);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001480 break;
1481
Thierry Fournierd5b073c2018-05-21 19:42:47 +02001482 case HLUA_E_ETMOUT:
1483 case HLUA_E_NOMEM:
1484 case HLUA_E_YIELD:
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001485 case HLUA_E_ERR:
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01001486 HLUA_CLR_RUN(lua);
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001487 notification_purge(&lua->com);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001488 hlua_ctx_renew(lua, 0);
1489 break;
1490
1491 case HLUA_E_OK:
Thierry FOURNIERa097fdf2015-03-03 15:17:35 +01001492 HLUA_CLR_RUN(lua);
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001493 notification_purge(&lua->com);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001494 break;
1495 }
1496
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +02001497 /* This is the main exit point, remove the Lua lock. */
Thierry Fournier021d9862020-11-28 23:42:03 +01001498 if (lua->state_id == 0)
Thierry Fournier7cbe5042020-11-28 17:02:21 +01001499 HA_SPIN_UNLOCK(LUA_LOCK, &hlua_global_lock);
Thierry FOURNIER61ba0e22017-07-12 11:41:21 +02001500
Thierry FOURNIER380d0932015-01-23 14:27:52 +01001501 return ret;
1502}
1503
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001504/* This function exit the current code. */
1505__LJMP static int hlua_done(lua_State *L)
1506{
Thierry Fournier4234dbd2020-11-28 13:18:23 +01001507 struct hlua *hlua;
1508
1509 /* Get hlua struct, or NULL if we execute from main lua state */
1510 hlua = hlua_gethlua(L);
1511 if (!hlua)
1512 return 0;
Thierry FOURNIER0a99b892015-08-26 00:14:17 +02001513
1514 hlua->flags |= HLUA_EXIT;
1515 WILL_LJMP(lua_error(L));
1516
1517 return 0;
1518}
1519
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001520/* This function is an LUA binding. It provides a function
1521 * for deleting ACL from a referenced ACL file.
1522 */
1523__LJMP static int hlua_del_acl(lua_State *L)
1524{
1525 const char *name;
1526 const char *key;
1527 struct pat_ref *ref;
1528
1529 MAY_LJMP(check_args(L, 2, "del_acl"));
1530
1531 name = MAY_LJMP(luaL_checkstring(L, 1));
1532 key = MAY_LJMP(luaL_checkstring(L, 2));
1533
1534 ref = pat_ref_lookup(name);
1535 if (!ref)
Vincent Bernata72db182015-10-06 16:05:59 +02001536 WILL_LJMP(luaL_error(L, "'del_acl': unknown acl file '%s'", name));
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001537
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001538 HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001539 pat_ref_delete(ref, key);
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001540 HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001541 return 0;
1542}
1543
1544/* This function is an LUA binding. It provides a function
1545 * for deleting map entry from a referenced map file.
1546 */
1547static int hlua_del_map(lua_State *L)
1548{
1549 const char *name;
1550 const char *key;
1551 struct pat_ref *ref;
1552
1553 MAY_LJMP(check_args(L, 2, "del_map"));
1554
1555 name = MAY_LJMP(luaL_checkstring(L, 1));
1556 key = MAY_LJMP(luaL_checkstring(L, 2));
1557
1558 ref = pat_ref_lookup(name);
1559 if (!ref)
Vincent Bernata72db182015-10-06 16:05:59 +02001560 WILL_LJMP(luaL_error(L, "'del_map': unknown acl file '%s'", name));
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001561
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001562 HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001563 pat_ref_delete(ref, key);
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001564 HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001565 return 0;
1566}
1567
1568/* This function is an LUA binding. It provides a function
1569 * for adding ACL pattern from a referenced ACL file.
1570 */
1571static int hlua_add_acl(lua_State *L)
1572{
1573 const char *name;
1574 const char *key;
1575 struct pat_ref *ref;
1576
1577 MAY_LJMP(check_args(L, 2, "add_acl"));
1578
1579 name = MAY_LJMP(luaL_checkstring(L, 1));
1580 key = MAY_LJMP(luaL_checkstring(L, 2));
1581
1582 ref = pat_ref_lookup(name);
1583 if (!ref)
Vincent Bernata72db182015-10-06 16:05:59 +02001584 WILL_LJMP(luaL_error(L, "'add_acl': unknown acl file '%s'", name));
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001585
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001586 HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001587 if (pat_ref_find_elt(ref, key) == NULL)
1588 pat_ref_add(ref, key, NULL, NULL);
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001589 HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001590 return 0;
1591}
1592
1593/* This function is an LUA binding. It provides a function
1594 * for setting map pattern and sample from a referenced map
1595 * file.
1596 */
1597static int hlua_set_map(lua_State *L)
1598{
1599 const char *name;
1600 const char *key;
1601 const char *value;
1602 struct pat_ref *ref;
1603
1604 MAY_LJMP(check_args(L, 3, "set_map"));
1605
1606 name = MAY_LJMP(luaL_checkstring(L, 1));
1607 key = MAY_LJMP(luaL_checkstring(L, 2));
1608 value = MAY_LJMP(luaL_checkstring(L, 3));
1609
1610 ref = pat_ref_lookup(name);
1611 if (!ref)
Vincent Bernata72db182015-10-06 16:05:59 +02001612 WILL_LJMP(luaL_error(L, "'set_map': unknown map file '%s'", name));
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001613
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001614 HA_SPIN_LOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001615 if (pat_ref_find_elt(ref, key) != NULL)
1616 pat_ref_set(ref, key, value, NULL);
1617 else
1618 pat_ref_add(ref, key, value, NULL);
Christopher Faulet5cf2dfc2020-06-03 18:39:16 +02001619 HA_SPIN_UNLOCK(PATREF_LOCK, &ref->lock);
Thierry FOURNIER83758bb2015-02-04 13:21:04 +01001620 return 0;
1621}
1622
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01001623/* A class is a lot of memory that contain data. This data can be a table,
1624 * an integer or user data. This data is associated with a metatable. This
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +05001625 * metatable have an original version registered in the global context with
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01001626 * the name of the object (_G[<name>] = <metable> ).
1627 *
1628 * A metable is a table that modify the standard behavior of a standard
1629 * access to the associated data. The entries of this new metatable are
1630 * defined as is:
1631 *
1632 * http://lua-users.org/wiki/MetatableEvents
1633 *
1634 * __index
1635 *
1636 * we access an absent field in a table, the result is nil. This is
1637 * true, but it is not the whole truth. Actually, such access triggers
1638 * the interpreter to look for an __index metamethod: If there is no
1639 * such method, as usually happens, then the access results in nil;
1640 * otherwise, the metamethod will provide the result.
1641 *
1642 * Control 'prototype' inheritance. When accessing "myTable[key]" and
1643 * the key does not appear in the table, but the metatable has an __index
1644 * property:
1645 *
1646 * - if the value is a function, the function is called, passing in the
1647 * table and the key; the return value of that function is returned as
1648 * the result.
1649 *
1650 * - if the value is another table, the value of the key in that table is
1651 * asked for and returned (and if it doesn't exist in that table, but that
1652 * table's metatable has an __index property, then it continues on up)
1653 *
1654 * - Use "rawget(myTable,key)" to skip this metamethod.
1655 *
1656 * http://www.lua.org/pil/13.4.1.html
1657 *
1658 * __newindex
1659 *
1660 * Like __index, but control property assignment.
1661 *
1662 * __mode - Control weak references. A string value with one or both
1663 * of the characters 'k' and 'v' which specifies that the the
1664 * keys and/or values in the table are weak references.
1665 *
1666 * __call - Treat a table like a function. When a table is followed by
1667 * parenthesis such as "myTable( 'foo' )" and the metatable has
1668 * a __call key pointing to a function, that function is invoked
1669 * (passing any specified arguments) and the return value is
1670 * returned.
1671 *
1672 * __metatable - Hide the metatable. When "getmetatable( myTable )" is
1673 * called, if the metatable for myTable has a __metatable
1674 * key, the value of that key is returned instead of the
1675 * actual metatable.
1676 *
1677 * __tostring - Control string representation. When the builtin
1678 * "tostring( myTable )" function is called, if the metatable
1679 * for myTable has a __tostring property set to a function,
1680 * that function is invoked (passing myTable to it) and the
1681 * return value is used as the string representation.
1682 *
1683 * __len - Control table length. When the table length is requested using
1684 * the length operator ( '#' ), if the metatable for myTable has
1685 * a __len key pointing to a function, that function is invoked
1686 * (passing myTable to it) and the return value used as the value
1687 * of "#myTable".
1688 *
1689 * __gc - Userdata finalizer code. When userdata is set to be garbage
1690 * collected, if the metatable has a __gc field pointing to a
1691 * function, that function is first invoked, passing the userdata
1692 * to it. The __gc metamethod is not called for tables.
1693 * (See http://lua-users.org/lists/lua-l/2006-11/msg00508.html)
1694 *
1695 * Special metamethods for redefining standard operators:
1696 * http://www.lua.org/pil/13.1.html
1697 *
1698 * __add "+"
1699 * __sub "-"
1700 * __mul "*"
1701 * __div "/"
1702 * __unm "!"
1703 * __pow "^"
1704 * __concat ".."
1705 *
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001706 * Special methods for redefining standard relations
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01001707 * http://www.lua.org/pil/13.2.html
1708 *
1709 * __eq "=="
1710 * __lt "<"
1711 * __le "<="
1712 */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001713
1714/*
1715 *
1716 *
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001717 * Class Map
1718 *
1719 *
1720 */
1721
1722/* Returns a struct hlua_map if the stack entry "ud" is
1723 * a class session, otherwise it throws an error.
1724 */
1725__LJMP static struct map_descriptor *hlua_checkmap(lua_State *L, int ud)
1726{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02001727 return MAY_LJMP(hlua_checkudata(L, ud, class_map_ref));
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001728}
1729
1730/* This function is the map constructor. It don't need
1731 * the class Map object. It creates and return a new Map
1732 * object. It must be called only during "body" or "init"
1733 * context because it process some filesystem accesses.
1734 */
1735__LJMP static int hlua_map_new(struct lua_State *L)
1736{
1737 const char *fn;
1738 int match = PAT_MATCH_STR;
1739 struct sample_conv conv;
1740 const char *file = "";
1741 int line = 0;
1742 lua_Debug ar;
1743 char *err = NULL;
1744 struct arg args[2];
1745
1746 if (lua_gettop(L) < 1 || lua_gettop(L) > 2)
1747 WILL_LJMP(luaL_error(L, "'new' needs at least 1 argument."));
1748
1749 fn = MAY_LJMP(luaL_checkstring(L, 1));
1750
1751 if (lua_gettop(L) >= 2) {
1752 match = MAY_LJMP(luaL_checkinteger(L, 2));
1753 if (match < 0 || match >= PAT_MATCH_NUM)
1754 WILL_LJMP(luaL_error(L, "'new' needs a valid match method."));
1755 }
1756
1757 /* Get Lua filename and line number. */
1758 if (lua_getstack(L, 1, &ar)) { /* check function at level */
1759 lua_getinfo(L, "Sl", &ar); /* get info about it */
1760 if (ar.currentline > 0) { /* is there info? */
1761 file = ar.short_src;
1762 line = ar.currentline;
1763 }
1764 }
1765
1766 /* fill fake sample_conv struct. */
1767 conv.kw = ""; /* unused. */
1768 conv.process = NULL; /* unused. */
1769 conv.arg_mask = 0; /* unused. */
1770 conv.val_args = NULL; /* unused. */
1771 conv.out_type = SMP_T_STR;
1772 conv.private = (void *)(long)match;
1773 switch (match) {
1774 case PAT_MATCH_STR: conv.in_type = SMP_T_STR; break;
1775 case PAT_MATCH_BEG: conv.in_type = SMP_T_STR; break;
1776 case PAT_MATCH_SUB: conv.in_type = SMP_T_STR; break;
1777 case PAT_MATCH_DIR: conv.in_type = SMP_T_STR; break;
1778 case PAT_MATCH_DOM: conv.in_type = SMP_T_STR; break;
1779 case PAT_MATCH_END: conv.in_type = SMP_T_STR; break;
1780 case PAT_MATCH_REG: conv.in_type = SMP_T_STR; break;
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001781 case PAT_MATCH_INT: conv.in_type = SMP_T_SINT; break;
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001782 case PAT_MATCH_IP: conv.in_type = SMP_T_ADDR; break;
1783 default:
1784 WILL_LJMP(luaL_error(L, "'new' doesn't support this match mode."));
1785 }
1786
1787 /* fill fake args. */
1788 args[0].type = ARGT_STR;
Christopher Faulet73292e92020-08-06 08:40:09 +02001789 args[0].data.str.area = strdup(fn);
1790 args[0].data.str.data = strlen(fn);
1791 args[0].data.str.size = args[0].data.str.data+1;
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001792 args[1].type = ARGT_STOP;
1793
1794 /* load the map. */
1795 if (!sample_load_map(args, &conv, file, line, &err)) {
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05001796 /* error case: we can't use luaL_error because we must
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001797 * free the err variable.
1798 */
1799 luaL_where(L, 1);
1800 lua_pushfstring(L, "'new': %s.", err);
1801 lua_concat(L, 2);
1802 free(err);
Christopher Faulet6ad7df42020-08-07 11:45:18 +02001803 chunk_destroy(&args[0].data.str);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001804 WILL_LJMP(lua_error(L));
1805 }
1806
1807 /* create the lua object. */
1808 lua_newtable(L);
1809 lua_pushlightuserdata(L, args[0].data.map);
1810 lua_rawseti(L, -2, 0);
1811
1812 /* Pop a class Map metatable and affect it to the userdata. */
1813 lua_rawgeti(L, LUA_REGISTRYINDEX, class_map_ref);
1814 lua_setmetatable(L, -2);
1815
1816
1817 return 1;
1818}
1819
1820__LJMP static inline int _hlua_map_lookup(struct lua_State *L, int str)
1821{
1822 struct map_descriptor *desc;
1823 struct pattern *pat;
1824 struct sample smp;
1825
1826 MAY_LJMP(check_args(L, 2, "lookup"));
1827 desc = MAY_LJMP(hlua_checkmap(L, 1));
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +02001828 if (desc->pat.expect_type == SMP_T_SINT) {
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001829 smp.data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +02001830 smp.data.u.sint = MAY_LJMP(luaL_checkinteger(L, 2));
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001831 }
1832 else {
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02001833 smp.data.type = SMP_T_STR;
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001834 smp.flags = SMP_F_CONST;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001835 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 +01001836 smp.data.u.str.size = smp.data.u.str.data + 1;
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001837 }
1838
1839 pat = pattern_exec_match(&desc->pat, &smp, 1);
Thierry FOURNIER503bb092015-08-19 08:35:43 +02001840 if (!pat || !pat->data) {
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001841 if (str)
1842 lua_pushstring(L, "");
1843 else
1844 lua_pushnil(L);
1845 return 1;
1846 }
1847
1848 /* The Lua pattern must return a string, so we can't check the returned type */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001849 lua_pushlstring(L, pat->data->u.str.area, pat->data->u.str.data);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02001850 return 1;
1851}
1852
1853__LJMP static int hlua_map_lookup(struct lua_State *L)
1854{
1855 return _hlua_map_lookup(L, 0);
1856}
1857
1858__LJMP static int hlua_map_slookup(struct lua_State *L)
1859{
1860 return _hlua_map_lookup(L, 1);
1861}
1862
1863/*
1864 *
1865 *
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001866 * Class Socket
1867 *
1868 *
1869 */
1870
1871__LJMP static struct hlua_socket *hlua_checksocket(lua_State *L, int ud)
1872{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02001873 return MAY_LJMP(hlua_checkudata(L, ud, class_socket_ref));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001874}
1875
1876/* This function is the handler called for each I/O on the established
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001877 * connection. It is used for notify space available to send or data
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001878 * received.
1879 */
Willy Tarreau00a37f02015-04-13 12:05:19 +02001880static void hlua_socket_handler(struct appctx *appctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001881{
Willy Tarreau00a37f02015-04-13 12:05:19 +02001882 struct stream_interface *si = appctx->owner;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001883
Thierry FOURNIERb13b20a2017-07-16 20:48:54 +02001884 if (appctx->ctx.hlua_cosocket.die) {
1885 si_shutw(si);
1886 si_shutr(si);
1887 si_ic(si)->flags |= CF_READ_NULL;
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001888 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_read);
1889 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_write);
Thierry FOURNIERb13b20a2017-07-16 20:48:54 +02001890 stream_shutdown(si_strm(si), SF_ERR_KILLED);
1891 }
1892
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05001893 /* If we can't write, wakeup the pending write signals. */
Thierry FOURNIER6d695e62015-09-27 19:29:38 +02001894 if (channel_output_closed(si_ic(si)))
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001895 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_write);
Thierry FOURNIER6d695e62015-09-27 19:29:38 +02001896
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05001897 /* If we can't read, wakeup the pending read signals. */
Thierry FOURNIER6d695e62015-09-27 19:29:38 +02001898 if (channel_input_closed(si_oc(si)))
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001899 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_read);
Thierry FOURNIER6d695e62015-09-27 19:29:38 +02001900
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02001901 /* if the connection is not established, inform the stream that we want
Thierry FOURNIER316e3192015-09-04 18:25:53 +02001902 * to be notified whenever the connection completes.
1903 */
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02001904 if (si_opposite(si)->state < SI_ST_EST) {
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01001905 si_cant_get(si);
Willy Tarreau12c24232018-12-06 15:29:50 +01001906 si_rx_conn_blk(si);
Willy Tarreau3367d412018-11-15 10:57:41 +01001907 si_rx_endp_more(si);
Willy Tarreaud4da1962015-04-20 01:31:23 +02001908 return;
Thierry FOURNIER316e3192015-09-04 18:25:53 +02001909 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001910
1911 /* This function is called after the connect. */
Thierry FOURNIER18d09902016-12-16 09:25:38 +01001912 appctx->ctx.hlua_cosocket.connected = 1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001913
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08001914 /* Wake the tasks which wants to write if the buffer have available space. */
Thierry FOURNIEReba6f642015-09-26 22:01:07 +02001915 if (channel_may_recv(si_ic(si)))
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001916 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_write);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001917
1918 /* Wake the tasks which wants to read if the buffer contains data. */
Thierry FOURNIEReba6f642015-09-26 22:01:07 +02001919 if (!channel_is_empty(si_oc(si)))
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001920 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_read);
Thierry FOURNIER101b9762018-05-27 01:27:40 +02001921
1922 /* Some data were injected in the buffer, notify the stream
1923 * interface.
1924 */
1925 if (!channel_is_empty(si_ic(si)))
Willy Tarreau14bfe9a2018-12-19 15:19:27 +01001926 si_update(si);
Thierry FOURNIER101b9762018-05-27 01:27:40 +02001927
1928 /* If write notifications are registered, we considers we want
Willy Tarreau3367d412018-11-15 10:57:41 +01001929 * to write, so we clear the blocking flag.
Thierry FOURNIER101b9762018-05-27 01:27:40 +02001930 */
1931 if (notification_registered(&appctx->ctx.hlua_cosocket.wake_on_write))
Willy Tarreau3367d412018-11-15 10:57:41 +01001932 si_rx_endp_more(si);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001933}
1934
Willy Tarreau87b09662015-04-03 00:22:06 +02001935/* This function is called when the "struct stream" is destroyed.
1936 * Remove the link from the object to this stream.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001937 * Wake all the pending signals.
1938 */
Willy Tarreau00a37f02015-04-13 12:05:19 +02001939static void hlua_socket_release(struct appctx *appctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001940{
Thierry FOURNIER952939d2017-09-01 14:17:32 +02001941 struct xref *peer;
1942
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001943 /* Remove my link in the original object. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02001944 peer = xref_get_peer_and_lock(&appctx->ctx.hlua_cosocket.xref);
1945 if (peer)
1946 xref_disconnect(&appctx->ctx.hlua_cosocket.xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001947
1948 /* Wake all the task waiting for me. */
Thierry FOURNIERd6975962017-07-12 14:31:10 +02001949 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_read);
1950 notification_wake(&appctx->ctx.hlua_cosocket.wake_on_write);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001951}
1952
1953/* If the garbage collectio of the object is launch, nobody
Willy Tarreau87b09662015-04-03 00:22:06 +02001954 * uses this object. If the stream does not exists, just quit.
1955 * Send the shutdown signal to the stream. In some cases,
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001956 * pending signal can rest in the read and write lists. destroy
1957 * it.
1958 */
1959__LJMP static int hlua_socket_gc(lua_State *L)
1960{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01001961 struct hlua_socket *socket;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001962 struct appctx *appctx;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001963 struct xref *peer;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001964
Willy Tarreau80f5fae2015-02-27 16:38:20 +01001965 MAY_LJMP(check_args(L, 1, "__gc"));
1966
1967 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02001968 peer = xref_get_peer_and_lock(&socket->xref);
1969 if (!peer)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001970 return 0;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001971 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001972
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001973 /* Set the flag which destroy the session. */
Thierry FOURNIERb13b20a2017-07-16 20:48:54 +02001974 appctx->ctx.hlua_cosocket.die = 1;
1975 appctx_wakeup(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001976
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001977 /* Remove all reference between the Lua stack and the coroutine stream. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02001978 xref_disconnect(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001979 return 0;
1980}
1981
1982/* The close function send shutdown signal and break the
Willy Tarreau87b09662015-04-03 00:22:06 +02001983 * links between the stream and the object.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001984 */
sada05ed3302018-05-11 11:48:18 -07001985__LJMP static int hlua_socket_close_helper(lua_State *L)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001986{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01001987 struct hlua_socket *socket;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001988 struct appctx *appctx;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02001989 struct xref *peer;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01001990 struct hlua *hlua;
1991
1992 /* Get hlua struct, or NULL if we execute from main lua state */
1993 hlua = hlua_gethlua(L);
1994 if (!hlua)
1995 return 0;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01001996
Willy Tarreau80f5fae2015-02-27 16:38:20 +01001997 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02001998
1999 /* Check if we run on the same thread than the xreator thread.
2000 * We cannot access to the socket if the thread is different.
2001 */
2002 if (socket->tid != tid)
2003 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2004
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002005 peer = xref_get_peer_and_lock(&socket->xref);
2006 if (!peer)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002007 return 0;
Willy Tarreauf31af932020-01-14 09:59:38 +01002008
2009 hlua->gc_count--;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002010 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002011
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002012 /* Set the flag which destroy the session. */
Thierry FOURNIERb13b20a2017-07-16 20:48:54 +02002013 appctx->ctx.hlua_cosocket.die = 1;
2014 appctx_wakeup(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002015
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002016 /* Remove all reference between the Lua stack and the coroutine stream. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002017 xref_disconnect(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002018 return 0;
2019}
2020
sada05ed3302018-05-11 11:48:18 -07002021/* The close function calls close_helper.
2022 */
2023__LJMP static int hlua_socket_close(lua_State *L)
2024{
2025 MAY_LJMP(check_args(L, 1, "close"));
2026 return hlua_socket_close_helper(L);
2027}
2028
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002029/* This Lua function assumes that the stack contain three parameters.
2030 * 1 - USERDATA containing a struct socket
2031 * 2 - INTEGER with values of the macro defined below
2032 * If the integer is -1, we must read at most one line.
2033 * If the integer is -2, we ust read all the data until the
2034 * end of the stream.
2035 * If the integer is positive value, we must read a number of
2036 * bytes corresponding to this value.
2037 */
2038#define HLSR_READ_LINE (-1)
2039#define HLSR_READ_ALL (-2)
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002040__LJMP static int hlua_socket_receive_yield(struct lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002041{
2042 struct hlua_socket *socket = MAY_LJMP(hlua_checksocket(L, 1));
2043 int wanted = lua_tointeger(L, 2);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002044 struct hlua *hlua;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002045 struct appctx *appctx;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02002046 size_t len;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002047 int nblk;
Willy Tarreau206ba832018-06-14 15:27:31 +02002048 const char *blk1;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02002049 size_t len1;
Willy Tarreau206ba832018-06-14 15:27:31 +02002050 const char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02002051 size_t len2;
Thierry FOURNIER00543922015-03-09 18:35:06 +01002052 int skip_at_end = 0;
Willy Tarreau81389672015-03-10 12:03:52 +01002053 struct channel *oc;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002054 struct stream_interface *si;
2055 struct stream *s;
2056 struct xref *peer;
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02002057 int missing_bytes;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002058
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002059 /* Get hlua struct, or NULL if we execute from main lua state */
2060 hlua = hlua_gethlua(L);
2061
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002062 /* Check if this lua stack is schedulable. */
2063 if (!hlua || !hlua->task)
2064 WILL_LJMP(luaL_error(L, "The 'receive' function is only allowed in "
2065 "'frontend', 'backend' or 'task'"));
2066
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002067 /* Check if we run on the same thread than the xreator thread.
2068 * We cannot access to the socket if the thread is different.
2069 */
2070 if (socket->tid != tid)
2071 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2072
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002073 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002074 peer = xref_get_peer_and_lock(&socket->xref);
2075 if (!peer)
2076 goto no_peer;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002077 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2078 si = appctx->owner;
2079 s = si_strm(si);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002080
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002081 oc = &s->res;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002082 if (wanted == HLSR_READ_LINE) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002083 /* Read line. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02002084 nblk = co_getline_nc(oc, &blk1, &len1, &blk2, &len2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002085 if (nblk < 0) /* Connection close. */
2086 goto connection_closed;
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002087 if (nblk == 0) /* No data available. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002088 goto connection_empty;
Thierry FOURNIER00543922015-03-09 18:35:06 +01002089
2090 /* remove final \r\n. */
2091 if (nblk == 1) {
2092 if (blk1[len1-1] == '\n') {
2093 len1--;
2094 skip_at_end++;
2095 if (blk1[len1-1] == '\r') {
2096 len1--;
2097 skip_at_end++;
2098 }
2099 }
2100 }
2101 else {
2102 if (blk2[len2-1] == '\n') {
2103 len2--;
2104 skip_at_end++;
2105 if (blk2[len2-1] == '\r') {
2106 len2--;
2107 skip_at_end++;
2108 }
2109 }
2110 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002111 }
2112
2113 else if (wanted == HLSR_READ_ALL) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002114 /* Read all the available data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02002115 nblk = co_getblk_nc(oc, &blk1, &len1, &blk2, &len2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002116 if (nblk < 0) /* Connection close. */
2117 goto connection_closed;
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002118 if (nblk == 0) /* No data available. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002119 goto connection_empty;
2120 }
2121
2122 else {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002123 /* Read a block of data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02002124 nblk = co_getblk_nc(oc, &blk1, &len1, &blk2, &len2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002125 if (nblk < 0) /* Connection close. */
2126 goto connection_closed;
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002127 if (nblk == 0) /* No data available. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002128 goto connection_empty;
2129
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02002130 missing_bytes = wanted - socket->b.n;
2131 if (len1 > missing_bytes) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002132 nblk = 1;
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02002133 len1 = missing_bytes;
2134 } if (nblk == 2 && len1 + len2 > missing_bytes)
2135 len2 = missing_bytes - len1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002136 }
2137
2138 len = len1;
2139
2140 luaL_addlstring(&socket->b, blk1, len1);
2141 if (nblk == 2) {
2142 len += len2;
2143 luaL_addlstring(&socket->b, blk2, len2);
2144 }
2145
2146 /* Consume data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02002147 co_skip(oc, len + skip_at_end);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002148
2149 /* Don't wait anything. */
Thierry FOURNIER7e4ee472018-05-25 15:03:50 +02002150 appctx_wakeup(appctx);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002151
2152 /* If the pattern reclaim to read all the data
2153 * in the connection, got out.
2154 */
2155 if (wanted == HLSR_READ_ALL)
2156 goto connection_empty;
Thierry FOURNIER8c126c72018-05-25 16:27:44 +02002157 else if (wanted >= 0 && socket->b.n < wanted)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002158 goto connection_empty;
2159
2160 /* Return result. */
2161 luaL_pushresult(&socket->b);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002162 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002163 return 1;
2164
2165connection_closed:
2166
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002167 xref_unlock(&socket->xref, peer);
2168
2169no_peer:
2170
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002171 /* If the buffer containds data. */
2172 if (socket->b.n > 0) {
2173 luaL_pushresult(&socket->b);
2174 return 1;
2175 }
2176 lua_pushnil(L);
2177 lua_pushstring(L, "connection closed.");
2178 return 2;
2179
2180connection_empty:
2181
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002182 if (!notification_new(&hlua->com, &appctx->ctx.hlua_cosocket.wake_on_read, hlua->task)) {
2183 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002184 WILL_LJMP(luaL_error(L, "out of memory"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002185 }
2186 xref_unlock(&socket->xref, peer);
Willy Tarreau9635e032018-10-16 17:52:55 +02002187 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_receive_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002188 return 0;
2189}
2190
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002191/* This Lua function gets two parameters. The first one can be string
2192 * or a number. If the string is "*l", the user requires one line. If
2193 * the string is "*a", the user requires all the contents of the stream.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002194 * If the value is a number, the user require a number of bytes equal
2195 * to the value. The default value is "*l" (a line).
2196 *
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002197 * This parameter with a variable type is converted in integer. This
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002198 * integer takes this values:
2199 * -1 : read a line
2200 * -2 : read all the stream
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002201 * >0 : amount of bytes.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002202 *
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002203 * The second parameter is optional. It contains a string that must be
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002204 * concatenated with the read data.
2205 */
2206__LJMP static int hlua_socket_receive(struct lua_State *L)
2207{
2208 int wanted = HLSR_READ_LINE;
2209 const char *pattern;
Christopher Fauletc31b2002021-05-03 10:11:13 +02002210 int lastarg, type;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002211 char *error;
2212 size_t len;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002213 struct hlua_socket *socket;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002214
2215 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
2216 WILL_LJMP(luaL_error(L, "The 'receive' function requires between 1 and 3 arguments."));
2217
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002218 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002219
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002220 /* Check if we run on the same thread than the xreator thread.
2221 * We cannot access to the socket if the thread is different.
2222 */
2223 if (socket->tid != tid)
2224 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2225
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002226 /* check for pattern. */
2227 if (lua_gettop(L) >= 2) {
2228 type = lua_type(L, 2);
2229 if (type == LUA_TSTRING) {
2230 pattern = lua_tostring(L, 2);
2231 if (strcmp(pattern, "*a") == 0)
2232 wanted = HLSR_READ_ALL;
2233 else if (strcmp(pattern, "*l") == 0)
2234 wanted = HLSR_READ_LINE;
2235 else {
2236 wanted = strtoll(pattern, &error, 10);
2237 if (*error != '\0')
2238 WILL_LJMP(luaL_error(L, "Unsupported pattern."));
2239 }
2240 }
2241 else if (type == LUA_TNUMBER) {
2242 wanted = lua_tointeger(L, 2);
2243 if (wanted < 0)
2244 WILL_LJMP(luaL_error(L, "Unsupported size."));
2245 }
2246 }
2247
2248 /* Set pattern. */
2249 lua_pushinteger(L, wanted);
Tim Duesterhusc6e377e2018-01-04 19:32:13 +01002250
2251 /* Check if we would replace the top by itself. */
2252 if (lua_gettop(L) != 2)
2253 lua_replace(L, 2);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002254
Christopher Fauletc31b2002021-05-03 10:11:13 +02002255 /* Save index of the top of the stack because since buffers are used, it
2256 * may change
2257 */
2258 lastarg = lua_gettop(L);
2259
Tim Duesterhusb33754c2018-01-04 19:32:14 +01002260 /* init buffer, and fill it with prefix. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002261 luaL_buffinit(L, &socket->b);
2262
2263 /* Check prefix. */
Christopher Fauletc31b2002021-05-03 10:11:13 +02002264 if (lastarg >= 3) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002265 if (lua_type(L, 3) != LUA_TSTRING)
2266 WILL_LJMP(luaL_error(L, "Expect a 'string' for the prefix"));
2267 pattern = lua_tolstring(L, 3, &len);
2268 luaL_addlstring(&socket->b, pattern, len);
2269 }
2270
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002271 return __LJMP(hlua_socket_receive_yield(L, 0, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002272}
2273
2274/* Write the Lua input string in the output buffer.
Mark Lakes22154b42018-01-29 14:38:40 -08002275 * This function returns a yield if no space is available.
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002276 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002277static int hlua_socket_write_yield(struct lua_State *L,int status, lua_KContext ctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002278{
2279 struct hlua_socket *socket;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002280 struct hlua *hlua;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002281 struct appctx *appctx;
2282 size_t buf_len;
2283 const char *buf;
2284 int len;
2285 int send_len;
2286 int sent;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002287 struct xref *peer;
2288 struct stream_interface *si;
2289 struct stream *s;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002290
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002291 /* Get hlua struct, or NULL if we execute from main lua state */
2292 hlua = hlua_gethlua(L);
2293
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002294 /* Check if this lua stack is schedulable. */
2295 if (!hlua || !hlua->task)
2296 WILL_LJMP(luaL_error(L, "The 'write' function is only allowed in "
2297 "'frontend', 'backend' or 'task'"));
2298
2299 /* Get object */
2300 socket = MAY_LJMP(hlua_checksocket(L, 1));
2301 buf = MAY_LJMP(luaL_checklstring(L, 2, &buf_len));
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002302 sent = MAY_LJMP(luaL_checkinteger(L, 3));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002303
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002304 /* Check if we run on the same thread than the xreator thread.
2305 * We cannot access to the socket if the thread is different.
2306 */
2307 if (socket->tid != tid)
2308 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2309
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002310 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002311 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002312 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002313 lua_pushinteger(L, -1);
2314 return 1;
2315 }
2316 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2317 si = appctx->owner;
2318 s = si_strm(si);
2319
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002320 /* Check for connection close. */
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002321 if (channel_output_closed(&s->req)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002322 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002323 lua_pushinteger(L, -1);
2324 return 1;
2325 }
2326
2327 /* Update the input buffer data. */
2328 buf += sent;
2329 send_len = buf_len - sent;
2330
2331 /* All the data are sent. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002332 if (sent >= buf_len) {
2333 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002334 return 1; /* Implicitly return the length sent. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002335 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002336
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002337 /* Check if the buffer is available because HAProxy doesn't allocate
Thierry FOURNIER486d52a2015-03-09 17:51:43 +01002338 * the request buffer if its not required.
2339 */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02002340 if (s->req.buf.size == 0) {
Willy Tarreau581abd32018-10-25 10:21:41 +02002341 if (!si_alloc_ibuf(si, &appctx->buffer_wait))
Christopher Faulet33834b12016-12-19 09:29:06 +01002342 goto hlua_socket_write_yield_return;
Thierry FOURNIER486d52a2015-03-09 17:51:43 +01002343 }
2344
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002345 /* Check for available space. */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02002346 len = b_room(&s->req.buf);
Christopher Faulet33834b12016-12-19 09:29:06 +01002347 if (len <= 0) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002348 goto hlua_socket_write_yield_return;
Christopher Faulet33834b12016-12-19 09:29:06 +01002349 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002350
2351 /* send data */
2352 if (len < send_len)
2353 send_len = len;
Thierry FOURNIER66b89192018-05-27 01:14:47 +02002354 len = ci_putblk(&s->req, buf, send_len);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002355
2356 /* "Not enough space" (-1), "Buffer too little to contain
2357 * the data" (-2) are not expected because the available length
2358 * is tested.
2359 * Other unknown error are also not expected.
2360 */
2361 if (len <= 0) {
Willy Tarreaubc18da12015-03-13 14:00:47 +01002362 if (len == -1)
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002363 s->req.flags |= CF_WAKE_WRITE;
Willy Tarreaubc18da12015-03-13 14:00:47 +01002364
sada05ed3302018-05-11 11:48:18 -07002365 MAY_LJMP(hlua_socket_close_helper(L));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002366 lua_pop(L, 1);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002367 lua_pushinteger(L, -1);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002368 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002369 return 1;
2370 }
2371
2372 /* update buffers. */
Thierry FOURNIER101b9762018-05-27 01:27:40 +02002373 appctx_wakeup(appctx);
Willy Tarreaude70fa12015-09-26 11:25:05 +02002374
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002375 s->req.rex = TICK_ETERNITY;
2376 s->res.wex = TICK_ETERNITY;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002377
2378 /* Update length sent. */
2379 lua_pop(L, 1);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002380 lua_pushinteger(L, sent + len);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002381
2382 /* All the data buffer is sent ? */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002383 if (sent + len >= buf_len) {
2384 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002385 return 1;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002386 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002387
2388hlua_socket_write_yield_return:
Thierry FOURNIERba42fcd2018-05-27 00:59:48 +02002389 if (!notification_new(&hlua->com, &appctx->ctx.hlua_cosocket.wake_on_write, hlua->task)) {
2390 xref_unlock(&socket->xref, peer);
2391 WILL_LJMP(luaL_error(L, "out of memory"));
2392 }
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002393 xref_unlock(&socket->xref, peer);
Willy Tarreau9635e032018-10-16 17:52:55 +02002394 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_write_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002395 return 0;
2396}
2397
2398/* This function initiate the send of data. It just check the input
2399 * parameters and push an integer in the Lua stack that contain the
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08002400 * amount of data written to the buffer. This is used by the function
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002401 * "hlua_socket_write_yield" that can yield.
2402 *
2403 * The Lua function gets between 3 and 4 parameters. The first one is
2404 * the associated object. The second is a string buffer. The third is
2405 * a facultative integer that represents where is the buffer position
2406 * of the start of the data that can send. The first byte is the
2407 * position "1". The default value is "1". The fourth argument is a
2408 * facultative integer that represents where is the buffer position
2409 * of the end of the data that can send. The default is the last byte.
2410 */
2411static int hlua_socket_send(struct lua_State *L)
2412{
2413 int i;
2414 int j;
2415 const char *buf;
2416 size_t buf_len;
2417
2418 /* Check number of arguments. */
2419 if (lua_gettop(L) < 2 || lua_gettop(L) > 4)
2420 WILL_LJMP(luaL_error(L, "'send' needs between 2 and 4 arguments"));
2421
2422 /* Get the string. */
2423 buf = MAY_LJMP(luaL_checklstring(L, 2, &buf_len));
2424
2425 /* Get and check j. */
2426 if (lua_gettop(L) == 4) {
2427 j = MAY_LJMP(luaL_checkinteger(L, 4));
2428 if (j < 0)
2429 j = buf_len + j + 1;
2430 if (j > buf_len)
2431 j = buf_len + 1;
2432 lua_pop(L, 1);
2433 }
2434 else
2435 j = buf_len;
2436
2437 /* Get and check i. */
2438 if (lua_gettop(L) == 3) {
2439 i = MAY_LJMP(luaL_checkinteger(L, 3));
2440 if (i < 0)
2441 i = buf_len + i + 1;
2442 if (i > buf_len)
2443 i = buf_len + 1;
2444 lua_pop(L, 1);
2445 } else
2446 i = 1;
2447
2448 /* Check bth i and j. */
2449 if (i > j) {
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002450 lua_pushinteger(L, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002451 return 1;
2452 }
2453 if (i == 0 && j == 0) {
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002454 lua_pushinteger(L, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002455 return 1;
2456 }
2457 if (i == 0)
2458 i = 1;
2459 if (j == 0)
2460 j = 1;
2461
2462 /* Pop the string. */
2463 lua_pop(L, 1);
2464
2465 /* Update the buffer length. */
2466 buf += i - 1;
2467 buf_len = j - i + 1;
2468 lua_pushlstring(L, buf, buf_len);
2469
2470 /* This unsigned is used to remember the amount of sent data. */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002471 lua_pushinteger(L, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002472
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002473 return MAY_LJMP(hlua_socket_write_yield(L, 0, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002474}
2475
Willy Tarreau22b0a682015-06-17 19:43:49 +02002476#define SOCKET_INFO_MAX_LEN sizeof("[0000:0000:0000:0000:0000:0000:0000:0000]:12345")
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002477__LJMP static inline int hlua_socket_info(struct lua_State *L, struct sockaddr_storage *addr)
2478{
2479 static char buffer[SOCKET_INFO_MAX_LEN];
2480 int ret;
2481 int len;
2482 char *p;
2483
2484 ret = addr_to_str(addr, buffer+1, SOCKET_INFO_MAX_LEN-1);
2485 if (ret <= 0) {
2486 lua_pushnil(L);
2487 return 1;
2488 }
2489
2490 if (ret == AF_UNIX) {
2491 lua_pushstring(L, buffer+1);
2492 return 1;
2493 }
2494 else if (ret == AF_INET6) {
2495 buffer[0] = '[';
2496 len = strlen(buffer);
2497 buffer[len] = ']';
2498 len++;
2499 buffer[len] = ':';
2500 len++;
2501 p = buffer;
2502 }
2503 else if (ret == AF_INET) {
2504 p = buffer + 1;
2505 len = strlen(p);
2506 p[len] = ':';
2507 len++;
2508 }
2509 else {
2510 lua_pushnil(L);
2511 return 1;
2512 }
2513
2514 if (port_to_str(addr, p + len, SOCKET_INFO_MAX_LEN-1 - len) <= 0) {
2515 lua_pushnil(L);
2516 return 1;
2517 }
2518
2519 lua_pushstring(L, p);
2520 return 1;
2521}
2522
2523/* Returns information about the peer of the connection. */
2524__LJMP static int hlua_socket_getpeername(struct lua_State *L)
2525{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002526 struct hlua_socket *socket;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002527 struct xref *peer;
2528 struct appctx *appctx;
2529 struct stream_interface *si;
2530 struct stream *s;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002531 int ret;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002532
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002533 MAY_LJMP(check_args(L, 1, "getpeername"));
2534
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002535 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002536
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002537 /* Check if we run on the same thread than the xreator thread.
2538 * We cannot access to the socket if the thread is different.
2539 */
2540 if (socket->tid != tid)
2541 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2542
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002543 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002544 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002545 if (!peer) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002546 lua_pushnil(L);
2547 return 1;
2548 }
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002549 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2550 si = appctx->owner;
2551 s = si_strm(si);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002552
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002553 if (!s->target_addr) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002554 xref_unlock(&socket->xref, peer);
Willy Tarreaua71f6422016-11-16 17:00:14 +01002555 lua_pushnil(L);
2556 return 1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002557 }
2558
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002559 ret = MAY_LJMP(hlua_socket_info(L, s->target_addr));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002560 xref_unlock(&socket->xref, peer);
2561 return ret;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002562}
2563
2564/* Returns information about my connection side. */
2565static int hlua_socket_getsockname(struct lua_State *L)
2566{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002567 struct hlua_socket *socket;
2568 struct connection *conn;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002569 struct appctx *appctx;
2570 struct xref *peer;
2571 struct stream_interface *si;
2572 struct stream *s;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002573 int ret;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002574
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002575 MAY_LJMP(check_args(L, 1, "getsockname"));
2576
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002577 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002578
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002579 /* Check if we run on the same thread than the xreator thread.
2580 * We cannot access to the socket if the thread is different.
2581 */
2582 if (socket->tid != tid)
2583 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2584
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002585 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002586 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002587 if (!peer) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002588 lua_pushnil(L);
2589 return 1;
2590 }
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002591 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2592 si = appctx->owner;
2593 s = si_strm(si);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002594
Olivier Houchard9aaf7782017-09-13 18:30:23 +02002595 conn = cs_conn(objt_cs(s->si[1].end));
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002596 if (!conn || !conn_get_src(conn)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002597 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002598 lua_pushnil(L);
2599 return 1;
2600 }
2601
Willy Tarreau9da9a6f2019-07-17 14:49:44 +02002602 ret = hlua_socket_info(L, conn->src);
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002603 xref_unlock(&socket->xref, peer);
2604 return ret;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002605}
2606
2607/* This struct define the applet. */
Willy Tarreau30576452015-04-13 13:50:30 +02002608static struct applet update_applet = {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002609 .obj_type = OBJ_TYPE_APPLET,
2610 .name = "<LUA_TCP>",
2611 .fct = hlua_socket_handler,
2612 .release = hlua_socket_release,
2613};
2614
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002615__LJMP static int hlua_socket_connect_yield(struct lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002616{
2617 struct hlua_socket *socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002618 struct hlua *hlua;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002619 struct xref *peer;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002620 struct appctx *appctx;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002621 struct stream_interface *si;
2622 struct stream *s;
2623
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002624 /* Get hlua struct, or NULL if we execute from main lua state */
2625 hlua = hlua_gethlua(L);
2626 if (!hlua)
2627 return 0;
2628
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002629 /* Check if we run on the same thread than the xreator thread.
2630 * We cannot access to the socket if the thread is different.
2631 */
2632 if (socket->tid != tid)
2633 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2634
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002635 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002636 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002637 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002638 lua_pushnil(L);
2639 lua_pushstring(L, "Can't connect");
2640 return 2;
2641 }
2642 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2643 si = appctx->owner;
2644 s = si_strm(si);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002645
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002646 /* Check if we run on the same thread than the xreator thread.
2647 * We cannot access to the socket if the thread is different.
2648 */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002649 if (socket->tid != tid) {
2650 xref_unlock(&socket->xref, peer);
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002651 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002652 }
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002653
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002654 /* Check for connection close. */
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002655 if (!hlua || channel_output_closed(&s->req)) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002656 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002657 lua_pushnil(L);
2658 lua_pushstring(L, "Can't connect");
2659 return 2;
2660 }
2661
Willy Tarreaue09101e2018-10-16 17:37:12 +02002662 appctx = __objt_appctx(s->si[0].end);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002663
2664 /* Check for connection established. */
Thierry FOURNIER18d09902016-12-16 09:25:38 +01002665 if (appctx->ctx.hlua_cosocket.connected) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002666 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002667 lua_pushinteger(L, 1);
2668 return 1;
2669 }
2670
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002671 if (!notification_new(&hlua->com, &appctx->ctx.hlua_cosocket.wake_on_write, hlua->task)) {
2672 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002673 WILL_LJMP(luaL_error(L, "out of memory error"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002674 }
2675 xref_unlock(&socket->xref, peer);
Willy Tarreau9635e032018-10-16 17:52:55 +02002676 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_connect_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002677 return 0;
2678}
2679
2680/* This function fail or initite the connection. */
2681__LJMP static int hlua_socket_connect(struct lua_State *L)
2682{
2683 struct hlua_socket *socket;
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002684 int port = -1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002685 const char *ip;
Thierry FOURNIER95ad96a2015-03-09 18:12:40 +01002686 struct hlua *hlua;
2687 struct appctx *appctx;
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002688 int low, high;
2689 struct sockaddr_storage *addr;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002690 struct xref *peer;
2691 struct stream_interface *si;
2692 struct stream *s;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002693
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002694 if (lua_gettop(L) < 2)
2695 WILL_LJMP(luaL_error(L, "connect: need at least 2 arguments"));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002696
2697 /* Get args. */
2698 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002699
2700 /* Check if we run on the same thread than the xreator thread.
2701 * We cannot access to the socket if the thread is different.
2702 */
2703 if (socket->tid != tid)
2704 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2705
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002706 ip = MAY_LJMP(luaL_checkstring(L, 2));
Tim Duesterhus6edab862018-01-06 19:04:45 +01002707 if (lua_gettop(L) >= 3) {
2708 luaL_Buffer b;
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002709 port = MAY_LJMP(luaL_checkinteger(L, 3));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002710
Tim Duesterhus6edab862018-01-06 19:04:45 +01002711 /* Force the ip to end with a colon, to support IPv6 addresses
2712 * that are not enclosed within square brackets.
2713 */
2714 if (port > 0) {
2715 luaL_buffinit(L, &b);
2716 luaL_addstring(&b, ip);
2717 luaL_addchar(&b, ':');
2718 luaL_pushresult(&b);
2719 ip = lua_tolstring(L, lua_gettop(L), NULL);
2720 }
2721 }
2722
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002723 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002724 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002725 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002726 lua_pushnil(L);
2727 return 1;
2728 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002729
2730 /* Parse ip address. */
Willy Tarreau5fc93282020-09-16 18:25:03 +02002731 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 +02002732 if (!addr) {
2733 xref_unlock(&socket->xref, peer);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002734 WILL_LJMP(luaL_error(L, "connect: cannot parse destination address '%s'", ip));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002735 }
Willy Tarreau9da9a6f2019-07-17 14:49:44 +02002736
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002737 /* Set port. */
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002738 if (low == 0) {
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002739 if (addr->ss_family == AF_INET) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002740 if (port == -1) {
2741 xref_unlock(&socket->xref, peer);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002742 WILL_LJMP(luaL_error(L, "connect: port missing"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002743 }
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002744 ((struct sockaddr_in *)addr)->sin_port = htons(port);
2745 } else if (addr->ss_family == AF_INET6) {
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002746 if (port == -1) {
2747 xref_unlock(&socket->xref, peer);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002748 WILL_LJMP(luaL_error(L, "connect: port missing"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002749 }
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002750 ((struct sockaddr_in6 *)addr)->sin6_port = htons(port);
Thierry FOURNIERc2f56532015-09-26 20:23:30 +02002751 }
2752 }
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002753
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002754 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2755 si = appctx->owner;
2756 s = si_strm(si);
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002757
Willy Tarreau9b7587a2020-10-15 07:32:10 +02002758 if (!sockaddr_alloc(&s->target_addr, addr, sizeof(*addr))) {
Willy Tarreau1c8d32b2019-07-18 15:47:45 +02002759 xref_unlock(&socket->xref, peer);
2760 WILL_LJMP(luaL_error(L, "connect: internal error"));
2761 }
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002762 s->flags |= SF_ADDR_SET;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002763
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002764 /* Get hlua struct, or NULL if we execute from main lua state */
Thierry FOURNIER95ad96a2015-03-09 18:12:40 +01002765 hlua = hlua_gethlua(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01002766 if (!hlua)
2767 return 0;
Willy Tarreaubdc97a82015-08-24 15:42:28 +02002768
2769 /* inform the stream that we want to be notified whenever the
2770 * connection completes.
2771 */
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01002772 si_cant_get(&s->si[0]);
Willy Tarreau3367d412018-11-15 10:57:41 +01002773 si_rx_endp_more(&s->si[0]);
Thierry FOURNIER8c8fbbe2015-09-26 17:02:35 +02002774 appctx_wakeup(appctx);
Willy Tarreaubdc97a82015-08-24 15:42:28 +02002775
Willy Tarreauf31af932020-01-14 09:59:38 +01002776 hlua->gc_count++;
Thierry FOURNIER7c39ab42015-09-27 22:53:33 +02002777
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002778 if (!notification_new(&hlua->com, &appctx->ctx.hlua_cosocket.wake_on_write, hlua->task)) {
2779 xref_unlock(&socket->xref, peer);
Thierry FOURNIER95ad96a2015-03-09 18:12:40 +01002780 WILL_LJMP(luaL_error(L, "out of memory"));
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002781 }
2782 xref_unlock(&socket->xref, peer);
PiBa-NL706d5ee2018-05-05 23:51:42 +02002783
2784 task_wakeup(s->task, TASK_WOKEN_INIT);
2785 /* Return yield waiting for connection. */
2786
Willy Tarreau9635e032018-10-16 17:52:55 +02002787 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_socket_connect_yield, TICK_ETERNITY, 0));
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002788
2789 return 0;
2790}
2791
Baptiste Assmann84bb4932015-03-02 21:40:06 +01002792#ifdef USE_OPENSSL
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002793__LJMP static int hlua_socket_connect_ssl(struct lua_State *L)
2794{
2795 struct hlua_socket *socket;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002796 struct xref *peer;
2797 struct appctx *appctx;
2798 struct stream_interface *si;
2799 struct stream *s;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002800
2801 MAY_LJMP(check_args(L, 3, "connect_ssl"));
2802 socket = MAY_LJMP(hlua_checksocket(L, 1));
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002803
2804 /* check for connection break. If some data where read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002805 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002806 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002807 lua_pushnil(L);
2808 return 1;
2809 }
2810 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2811 si = appctx->owner;
2812 s = si_strm(si);
2813
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +01002814 s->target = &socket_ssl->obj_type;
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002815 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002816 return MAY_LJMP(hlua_socket_connect(L));
2817}
Baptiste Assmann84bb4932015-03-02 21:40:06 +01002818#endif
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002819
2820__LJMP static int hlua_socket_setoption(struct lua_State *L)
2821{
2822 return 0;
2823}
2824
2825__LJMP static int hlua_socket_settimeout(struct lua_State *L)
2826{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002827 struct hlua_socket *socket;
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01002828 int tmout;
Mark Lakes56cc1252018-03-27 09:48:06 +02002829 double dtmout;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002830 struct xref *peer;
2831 struct appctx *appctx;
2832 struct stream_interface *si;
2833 struct stream *s;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002834
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002835 MAY_LJMP(check_args(L, 2, "settimeout"));
2836
Willy Tarreau80f5fae2015-02-27 16:38:20 +01002837 socket = MAY_LJMP(hlua_checksocket(L, 1));
Mark Lakes56cc1252018-03-27 09:48:06 +02002838
Cyril Bonté7ee465f2018-08-19 22:08:50 +02002839 /* convert the timeout to millis */
2840 dtmout = MAY_LJMP(luaL_checknumber(L, 2)) * 1000;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002841
Thierry Fournier17a921b2018-03-08 09:59:02 +01002842 /* Check for negative values */
Mark Lakes56cc1252018-03-27 09:48:06 +02002843 if (dtmout < 0)
Thierry Fournier17a921b2018-03-08 09:59:02 +01002844 WILL_LJMP(luaL_error(L, "settimeout: cannot set negatives values"));
2845
Mark Lakes56cc1252018-03-27 09:48:06 +02002846 if (dtmout > INT_MAX) /* overflow check */
Cyril Bonté7ee465f2018-08-19 22:08:50 +02002847 WILL_LJMP(luaL_error(L, "settimeout: cannot set values larger than %d ms", INT_MAX));
Mark Lakes56cc1252018-03-27 09:48:06 +02002848
2849 tmout = MS_TO_TICKS((int)dtmout);
Cyril Bonté7ee465f2018-08-19 22:08:50 +02002850 if (tmout == 0)
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05002851 tmout++; /* very small timeouts are adjusted to a minimum of 1ms */
Mark Lakes56cc1252018-03-27 09:48:06 +02002852
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002853 /* Check if we run on the same thread than the xreator thread.
2854 * We cannot access to the socket if the thread is different.
2855 */
2856 if (socket->tid != tid)
2857 WILL_LJMP(luaL_error(L, "connect: cannot use socket on other thread"));
2858
Mark Lakes56cc1252018-03-27 09:48:06 +02002859 /* check for connection break. If some data were read, return it. */
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002860 peer = xref_get_peer_and_lock(&socket->xref);
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002861 if (!peer) {
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002862 hlua_pusherror(L, "socket: not yet initialised, you can't set timeouts.");
2863 WILL_LJMP(lua_error(L));
2864 return 0;
2865 }
2866 appctx = container_of(peer, struct appctx, ctx.hlua_cosocket.xref);
2867 si = appctx->owner;
2868 s = si_strm(si);
2869
Cyril Bonté7bb63452018-08-17 23:51:02 +02002870 s->sess->fe->timeout.connect = tmout;
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002871 s->req.rto = tmout;
2872 s->req.wto = tmout;
2873 s->res.rto = tmout;
2874 s->res.wto = tmout;
Cyril Bonté7bb63452018-08-17 23:51:02 +02002875 s->req.rex = tick_add_ifset(now_ms, tmout);
2876 s->req.wex = tick_add_ifset(now_ms, tmout);
2877 s->res.rex = tick_add_ifset(now_ms, tmout);
2878 s->res.wex = tick_add_ifset(now_ms, tmout);
2879
2880 s->task->expire = tick_add_ifset(now_ms, tmout);
2881 task_queue(s->task);
2882
Thierry FOURNIER952939d2017-09-01 14:17:32 +02002883 xref_unlock(&socket->xref, peer);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002884
Thierry Fourniere9636f12018-03-08 09:54:32 +01002885 lua_pushinteger(L, 1);
Tim Duesterhus119a5f12018-01-06 19:16:25 +01002886 return 1;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002887}
2888
2889__LJMP static int hlua_socket_new(lua_State *L)
2890{
2891 struct hlua_socket *socket;
2892 struct appctx *appctx;
Willy Tarreau15b5e142015-04-04 14:38:25 +02002893 struct session *sess;
Willy Tarreau61cf7c82015-04-06 00:48:33 +02002894 struct stream *strm;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002895
2896 /* Check stack size. */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01002897 if (!lua_checkstack(L, 3)) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002898 hlua_pusherror(L, "socket: full stack");
2899 goto out_fail_conf;
2900 }
2901
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01002902 /* Create the object: obj[0] = userdata. */
2903 lua_newtable(L);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002904 socket = MAY_LJMP(lua_newuserdata(L, sizeof(*socket)));
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01002905 lua_rawseti(L, -2, 0);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002906 memset(socket, 0, sizeof(*socket));
Thierry FOURNIER94a6bfc2017-07-12 12:10:44 +02002907 socket->tid = tid;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002908
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05002909 /* Check if the various memory pools are initialized. */
Willy Tarreaubafbe012017-11-24 17:34:44 +01002910 if (!pool_head_stream || !pool_head_buffer) {
Thierry FOURNIER4a6170c2015-03-09 17:07:10 +01002911 hlua_pusherror(L, "socket: uninitialized pools.");
2912 goto out_fail_conf;
2913 }
2914
Willy Tarreau87b09662015-04-03 00:22:06 +02002915 /* Pop a class stream metatable and affect it to the userdata. */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002916 lua_rawgeti(L, LUA_REGISTRYINDEX, class_socket_ref);
2917 lua_setmetatable(L, -2);
2918
Willy Tarreaud420a972015-04-06 00:39:18 +02002919 /* Create the applet context */
Willy Tarreau5f4a47b2017-10-31 15:59:32 +01002920 appctx = appctx_new(&update_applet, tid_bit);
Willy Tarreau61cf7c82015-04-06 00:48:33 +02002921 if (!appctx) {
2922 hlua_pusherror(L, "socket: out of memory");
Willy Tarreaufeb76402015-04-03 14:10:06 +02002923 goto out_fail_conf;
Willy Tarreau61cf7c82015-04-06 00:48:33 +02002924 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002925
Thierry FOURNIER18d09902016-12-16 09:25:38 +01002926 appctx->ctx.hlua_cosocket.connected = 0;
Thierry FOURNIERb13b20a2017-07-16 20:48:54 +02002927 appctx->ctx.hlua_cosocket.die = 0;
Thierry FOURNIER18d09902016-12-16 09:25:38 +01002928 LIST_INIT(&appctx->ctx.hlua_cosocket.wake_on_write);
2929 LIST_INIT(&appctx->ctx.hlua_cosocket.wake_on_read);
Willy Tarreaub2bf8332015-04-04 15:58:58 +02002930
Willy Tarreaud420a972015-04-06 00:39:18 +02002931 /* Now create a session, task and stream for this applet */
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +01002932 sess = session_new(socket_proxy, NULL, &appctx->obj_type);
Willy Tarreaud420a972015-04-06 00:39:18 +02002933 if (!sess) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002934 hlua_pusherror(L, "socket: out of memory");
Willy Tarreaud420a972015-04-06 00:39:18 +02002935 goto out_fail_sess;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002936 }
2937
Christopher Faulet26256f82020-09-14 11:40:13 +02002938 strm = stream_new(sess, &appctx->obj_type, &BUF_NULL);
Willy Tarreau61cf7c82015-04-06 00:48:33 +02002939 if (!strm) {
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002940 hlua_pusherror(L, "socket: out of memory");
Willy Tarreaud420a972015-04-06 00:39:18 +02002941 goto out_fail_stream;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002942 }
2943
Thierry FOURNIER2da788e2017-09-11 18:37:23 +02002944 /* Initialise cross reference between stream and Lua socket object. */
2945 xref_create(&socket->xref, &appctx->ctx.hlua_cosocket.xref);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002946
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002947 /* Configure "right" stream interface. this "si" is used to connect
2948 * and retrieve data from the server. The connection is initialized
2949 * with the "struct server".
2950 */
Willy Tarreau61cf7c82015-04-06 00:48:33 +02002951 si_set_state(&strm->si[1], SI_ST_ASS);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002952
2953 /* Force destination server. */
Willy Tarreau5a0b25d2019-07-18 18:01:14 +02002954 strm->flags |= SF_DIRECT | SF_ASSIGNED | SF_BE_ASSIGNED;
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +01002955 strm->target = &socket_tcp->obj_type;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002956
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002957 return 1;
2958
Willy Tarreaud420a972015-04-06 00:39:18 +02002959 out_fail_stream:
Willy Tarreau11c36242015-04-04 15:54:03 +02002960 session_free(sess);
Willy Tarreaud420a972015-04-06 00:39:18 +02002961 out_fail_sess:
2962 appctx_free(appctx);
2963 out_fail_conf:
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01002964 WILL_LJMP(lua_error(L));
2965 return 0;
2966}
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01002967
2968/*
2969 *
2970 *
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002971 * Class Channel
2972 *
2973 *
2974 */
2975
2976/* Returns the struct hlua_channel join to the class channel in the
2977 * stack entry "ud" or throws an argument error.
2978 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01002979__LJMP static struct channel *hlua_checkchannel(lua_State *L, int ud)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002980{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02002981 return MAY_LJMP(hlua_checkudata(L, ud, class_channel_ref));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002982}
2983
Willy Tarreau47860ed2015-03-10 14:07:50 +01002984/* Pushes the channel onto the top of the stack. If the stask does not have a
2985 * free slots, the function fails and returns 0;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002986 */
Willy Tarreau2a71af42015-03-10 13:51:50 +01002987static int hlua_channel_new(lua_State *L, struct channel *channel)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002988{
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002989 /* Check stack size. */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01002990 if (!lua_checkstack(L, 3))
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002991 return 0;
2992
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01002993 lua_newtable(L);
Willy Tarreau47860ed2015-03-10 14:07:50 +01002994 lua_pushlightuserdata(L, channel);
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01002995 lua_rawseti(L, -2, 0);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01002996
2997 /* Pop a class sesison metatable and affect it to the userdata. */
2998 lua_rawgeti(L, LUA_REGISTRYINDEX, class_channel_ref);
2999 lua_setmetatable(L, -2);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003000 return 1;
3001}
3002
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003003/* Copies <len> bytes of data present in the channel's buffer, starting at the
3004* offset <offset>, and put it in a LUA string variable. It is the caller
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003005* responsibility to ensure <len> and <offset> are valid. It always return the
3006* length of the built string. <len> may be 0, in this case, an empty string is
3007* created and 0 is returned.
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003008*/
3009static inline int _hlua_channel_dup(struct channel *chn, lua_State *L, size_t offset, size_t len)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003010{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003011 size_t block1, block2;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003012 luaL_Buffer b;
3013
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003014 block1 = len;
3015 if (block1 > b_contig_data(&chn->buf, b_peek_ofs(&chn->buf, offset)))
3016 block1 = b_contig_data(&chn->buf, b_peek_ofs(&chn->buf, offset));
3017 block2 = len - block1;
3018
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003019 luaL_buffinit(L, &b);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003020 luaL_addlstring(&b, b_peek(&chn->buf, offset), block1);
3021 if (block2)
3022 luaL_addlstring(&b, b_orig(&chn->buf), block2);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003023 luaL_pushresult(&b);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003024 return len;
3025}
3026
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003027/* Inserts the string <str> to the channel's buffer at the offset <offset>. This
3028 * function returns -1 if data cannot be copied. Otherwise, it returns the
3029 * number of bytes copied.
3030 */
3031static int _hlua_channel_insert(struct channel *chn, lua_State *L, struct ist str, size_t offset)
3032{
3033 int ret = 0;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003034
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003035 /* Nothing to do, just return */
3036 if (unlikely(istlen(str) == 0))
3037 goto end;
3038
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003039 if (istlen(str) > c_room(chn)) {
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003040 ret = -1;
3041 goto end;
3042 }
3043 ret = b_insert_blk(&chn->buf, offset, istptr(str), istlen(str));
3044
3045 end:
3046 return ret;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003047}
3048
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003049/* Removes <len> bytes of data at the absolute position <offset>.
3050 */
3051static void _hlua_channel_delete(struct channel *chn, size_t offset, size_t len)
3052{
3053 size_t end = offset + len;
3054
3055 if (b_peek(&chn->buf, end) != b_tail(&chn->buf))
3056 b_move(&chn->buf, b_peek_ofs(&chn->buf, end),
3057 b_data(&chn->buf) - end, -len);
3058 b_sub(&chn->buf, len);
3059}
3060
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003061/* Copies input data in the channel's buffer. It is possible to set a specific
3062 * offset (0 by default) and a length (all remaining input data starting for the
3063 * offset by default). If there is not enough input data and more data can be
3064 * received, this function yields.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003065 */
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003066__LJMP static int hlua_channel_get_data_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003067{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003068 struct channel *chn;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003069 int offset = 0, len = 0;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003070
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003071 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003072
3073 if (!ci_data(chn) && channel_input_closed(chn)) {
3074 lua_pushnil(L);
3075 return 1;
3076 }
3077
3078 if (lua_gettop(L) > 1) {
3079 offset = MAY_LJMP(luaL_checkinteger(L, 2));
3080 if (offset < 0)
3081 offset = MAX(0, ci_data(chn) + offset);
3082 if (offset > ci_data(chn)) {
3083 lua_pushfstring(L, "offset out of range.");
3084 WILL_LJMP(lua_error(L));
3085 }
3086 }
3087 len = ci_data(chn) - offset;
3088 if (lua_gettop(L) == 3) {
3089 len = MAY_LJMP(luaL_checkinteger(L, 3));
3090 if (!len)
3091 goto dup;
3092 if (len == -1)
3093 len = global.tune.bufsize;
3094 if (len < 0) {
3095 lua_pushfstring(L, "length out of range.");
3096 WILL_LJMP(lua_error(L));
3097 }
3098 }
3099
3100 if (offset + len > ci_data(chn)) {
3101 if (!HLUA_CANT_YIELD(hlua_gethlua(L)) && !channel_input_closed(chn) && channel_may_recv(chn)) {
3102 /* Yield waiting for more data, as requested */
3103 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_get_data_yield, TICK_ETERNITY, 0));
3104 }
3105 len = ci_data(chn) - offset;
3106 }
3107
3108 dup:
3109 _hlua_channel_dup(chn, L, co_data(chn) + offset, len);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003110 return 1;
3111}
3112
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003113/* Copies the first line (including the trailing LF) of input data in the
3114 * channel's buffer. It is possible to set a specific offset (0 by default) and
3115 * a length (all remaining input data starting for the offset by default). If
3116 * there is not enough input data and more data can be received, the function
3117 * yields. If a length is explicitly specified, no more data are
3118 * copied. Otherwise, if no LF is found and more data can be received, this
3119 * function yields.
3120 */
3121__LJMP static int hlua_channel_get_line_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003122{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003123 struct channel *chn;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003124 int l, offset = 0, len = 0;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003125
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003126 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003127
3128 if (!ci_data(chn) && channel_input_closed(chn)) {
3129 lua_pushnil(L);
3130 return 1;
3131 }
3132
3133 if (lua_gettop(L) > 1) {
3134 offset = MAY_LJMP(luaL_checkinteger(L, 2));
3135 if (offset < 0)
3136 offset = MAX(0, ci_data(chn) + offset);
3137 if (offset > ci_data(chn)) {
3138 lua_pushfstring(L, "offset out of range.");
3139 WILL_LJMP(lua_error(L));
3140 }
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003141 }
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003142 len = ci_data(chn) - offset;
3143 if (lua_gettop(L) == 3) {
3144 len = MAY_LJMP(luaL_checkinteger(L, 3));
3145 if (!len)
3146 goto dup;
3147 if (len == -1)
3148 len = global.tune.bufsize;
3149 if (len < 0) {
3150 lua_pushfstring(L, "length out of range.");
3151 WILL_LJMP(lua_error(L));
3152 }
3153 }
3154
3155 for (l = 0; l < len; l++) {
3156 if (l + offset >= ci_data(chn))
3157 break;
3158 if (*(b_peek(&chn->buf, co_data(chn) + offset + l)) == '\n') {
3159 len = l+1;
3160 goto dup;
3161 }
3162 }
3163
3164 if (offset + len > ci_data(chn)) {
3165 if (!HLUA_CANT_YIELD(hlua_gethlua(L)) && !channel_input_closed(chn) && channel_may_recv(chn)) {
3166 /* Yield waiting for more data */
3167 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_get_line_yield, TICK_ETERNITY, 0));
3168 }
3169 len = ci_data(chn) - offset;
3170 }
3171
3172 dup:
3173 _hlua_channel_dup(chn, L, co_data(chn) + offset, len);
3174 return 1;
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003175}
3176
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003177/* [ DEPRECATED ]
3178 *
3179 * Duplicate all input data foud in the channel's buffer. The data are not
3180 * removed from the buffer. This function relies on _hlua_channel_dup().
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003181 */
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003182__LJMP static int hlua_channel_dup(lua_State *L)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003183{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003184 struct channel *chn;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003185 int offset = 0, len = 0;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003186
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003187 MAY_LJMP(check_args(L, 1, "dup"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003188 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003189 if (IS_HTX_STRM(chn_strm(chn))) {
3190 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3191 WILL_LJMP(lua_error(L));
3192 }
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003193 offset = co_data(chn);
3194 len = ci_data(chn);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003195
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003196 if (!ci_data(chn) && channel_input_closed(chn)) {
3197 lua_pushnil(L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003198 return 1;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003199 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003200
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003201 _hlua_channel_dup(chn, L, offset, len);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003202 return 1;
3203}
3204
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003205/* [ DEPRECATED ]
3206 *
3207 * Get all input data foud in the channel's buffer. The data are removed from
3208 * the buffer after the copy. This function relies on _hlua_channel_dup() and
3209 * _hlua_channel_delete().
3210 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003211__LJMP static int hlua_channel_get(lua_State *L)
3212{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003213 struct channel *chn;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003214 int offset = 0, len = 0;
3215 int ret;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003216
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003217 MAY_LJMP(check_args(L, 1, "get"));
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003218 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3219 if (IS_HTX_STRM(chn_strm(chn))) {
3220 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3221 WILL_LJMP(lua_error(L));
3222 }
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003223 offset = co_data(chn);
3224 len = ci_data(chn);
3225
3226 if (!ci_data(chn) && channel_input_closed(chn)) {
3227 lua_pushnil(L);
3228 return 1;
3229 }
3230
3231 ret = _hlua_channel_dup(chn, L, offset, len);
3232 _hlua_channel_delete(chn, offset, ret);
3233 return 1;
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003234}
3235
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003236/* This functions consumes and returns one line. If the channel is closed,
3237 * and the last data does not contains a final '\n', the data are returned
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003238 * without the final '\n'. When no more data are available, it returns nil
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003239 * value.
3240 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003241__LJMP static int hlua_channel_getline_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003242{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003243 struct channel *chn;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003244 size_t l;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003245 int offset = 0, len = 0;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003246 int ret;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003247
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003248 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003249 offset = co_data(chn);
3250 len = ci_data(chn);
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003251
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003252 if (!ci_data(chn) && channel_input_closed(chn)) {
3253 lua_pushnil(L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003254 return 1;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003255 }
3256
3257 for (l = 0; l < len; l++) {
3258 if (*(b_peek(&chn->buf, offset+l)) == '\n') {
3259 len = l+1;
3260 goto dup;
3261 }
3262 }
3263
3264 if (!HLUA_CANT_YIELD(hlua_gethlua(L)) && !channel_input_closed(chn) && channel_may_recv(chn)) {
3265 /* Yield waiting for more data */
3266 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_getline_yield, TICK_ETERNITY, 0));
3267 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003268
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003269 dup:
3270 ret = _hlua_channel_dup(chn, L, co_data(chn) + offset, len);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003271 _hlua_channel_delete(chn, offset, ret);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003272 return 1;
3273}
3274
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003275/* [ DEPRECATED ]
3276 *
3277 * Check arguments for the function "hlua_channel_getline_yield".
3278 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003279__LJMP static int hlua_channel_getline(lua_State *L)
3280{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003281 struct channel *chn;
3282
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003283 MAY_LJMP(check_args(L, 1, "getline"));
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003284 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3285 if (IS_HTX_STRM(chn_strm(chn))) {
3286 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3287 WILL_LJMP(lua_error(L));
3288 }
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003289 return MAY_LJMP(hlua_channel_getline_yield(L, 0, 0));
3290}
3291
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003292/* Retrieves a given amount of input data at the given offset. By default all
3293 * available input data are returned. The offset may be negactive to start from
3294 * the end of input data. The length may be -1 to set it to the maximum buffer
3295 * size.
3296 */
3297__LJMP static int hlua_channel_get_data(lua_State *L)
3298{
3299 struct channel *chn;
3300
3301 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
3302 WILL_LJMP(luaL_error(L, "'data' expects at most 2 arguments"));
3303 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3304 if (IS_HTX_STRM(chn_strm(chn))) {
3305 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3306 WILL_LJMP(lua_error(L));
3307 }
3308 return MAY_LJMP(hlua_channel_get_data_yield(L, 0, 0));
3309}
3310
3311/* Retrieves a given amount of input data at the given offset. By default all
3312 * available input data are returned. The offset may be negactive to start from
3313 * the end of input data. The length may be -1 to set it to the maximum buffer
3314 * size.
3315 */
3316__LJMP static int hlua_channel_get_line(lua_State *L)
3317{
3318 struct channel *chn;
3319
3320 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
3321 WILL_LJMP(luaL_error(L, "'line' expects at most 2 arguments"));
3322 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3323 if (IS_HTX_STRM(chn_strm(chn))) {
3324 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3325 WILL_LJMP(lua_error(L));
3326 }
3327 return MAY_LJMP(hlua_channel_get_line_yield(L, 0, 0));
3328}
3329
3330/* Appends a string into the input side of channel. It returns the length of the
3331 * written string, or -1 if the channel is closed or if the buffer size is too
3332 * little for the data. 0 may be returned if nothing is copied. This function
3333 * does not yield.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003334 */
Christopher Faulet23976d92021-08-06 09:59:49 +02003335__LJMP static int hlua_channel_append(lua_State *L)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003336{
Christopher Faulet23976d92021-08-06 09:59:49 +02003337 struct channel *chn;
3338 const char *str;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003339 size_t len;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003340 int ret;
Christopher Faulet23976d92021-08-06 09:59:49 +02003341
3342 MAY_LJMP(check_args(L, 2, "append"));
3343 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3344 str = MAY_LJMP(luaL_checklstring(L, 2, &len));
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01003345 if (IS_HTX_STRM(chn_strm(chn))) {
Thierry Fournier77016da2020-08-15 14:35:51 +02003346 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01003347 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02003348 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01003349
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003350 ret = _hlua_channel_insert(chn, L, ist2(str, len), co_data(chn) + ci_data(chn));
3351 lua_pushinteger(L, ret);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003352 return 1;
3353}
3354
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003355/* Prepends a string into the input side of channel. It returns the length of the
3356 * written string, or -1 if the channel is closed or if the buffer size is too
3357 * little for the data. 0 may be returned if nothing is copied. This function
3358 * does not yield.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003359 */
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003360__LJMP static int hlua_channel_prepend(lua_State *L)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003361{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003362 struct channel *chn;
Christopher Faulet23976d92021-08-06 09:59:49 +02003363 const char *str;
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003364 size_t sz;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003365 int ret;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003366
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003367 MAY_LJMP(check_args(L, 2, "prepend"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003368 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003369 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
3370 if (IS_HTX_STRM(chn_strm(chn))) {
3371 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3372 WILL_LJMP(lua_error(L));
3373 }
3374
3375 ret = _hlua_channel_insert(chn, L, ist2(str, sz), co_data(chn));
3376 lua_pushinteger(L, ret);
3377 return 1;
3378}
3379
3380/* Inserts a given amount of input data at the given offset by a string
3381 * content. By default the string is appended at the end of input data. It
3382 * returns the length of the written string, or -1 if the channel is closed or
3383 * if the buffer size is too little for the data.
3384 */
3385__LJMP static int hlua_channel_insert_data(lua_State *L)
3386{
3387 struct channel *chn;
3388 const char *str;
3389 size_t sz;
3390 int ret, offset;
3391
3392 if (lua_gettop(L) < 2 || lua_gettop(L) > 3)
3393 WILL_LJMP(luaL_error(L, "'insert' expects at least 1 argument and at most 2 arguments"));
3394 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3395 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
3396 offset = ci_data(chn);
3397 if (lua_gettop(L) > 2)
3398 offset = MAY_LJMP(luaL_checkinteger(L, 3));
3399 if (IS_HTX_STRM(chn_strm(chn))) {
3400 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3401 WILL_LJMP(lua_error(L));
3402 }
3403
3404 if (offset < 0)
3405 offset = MAX(0, ci_data(chn) + offset);
3406
3407 if (offset > ci_data(chn)) {
3408 lua_pushfstring(L, "offset out of range.");
3409 WILL_LJMP(lua_error(L));
3410 }
3411
3412 ret = _hlua_channel_insert(chn, L, ist2(str, sz), co_data(chn) + offset);
3413 lua_pushinteger(L, ret);
3414 return 1;
3415}
3416/* Replaces a given amount of input data at the given offset by a string
3417 * content. By default all remaining data are removed (offset = 0 and len =
3418 * -1). It returns the length of the written string, or -1 if the channel is
3419 * closed or if the buffer size is too little for the data.
3420 */
3421__LJMP static int hlua_channel_set_data(lua_State *L)
3422{
3423 struct channel *chn;
3424 const char *str;
3425 size_t sz;
3426 int ret, offset = 0, len = -1;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003427
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003428 if (lua_gettop(L) < 2 || lua_gettop(L) > 4)
3429 WILL_LJMP(luaL_error(L, "'set' expects at least 1 argument and at most 3 arguments"));
3430 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3431 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
3432 if (lua_gettop(L) > 2)
3433 offset = MAY_LJMP(luaL_checkinteger(L, 3));
3434 if (lua_gettop(L) == 4)
3435 len = MAY_LJMP(luaL_checkinteger(L, 4));
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01003436 if (IS_HTX_STRM(chn_strm(chn))) {
Thierry Fournier77016da2020-08-15 14:35:51 +02003437 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
Christopher Faulet3f829a42018-12-13 21:56:45 +01003438 WILL_LJMP(lua_error(L));
Thierry Fournier77016da2020-08-15 14:35:51 +02003439 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01003440
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003441 if (offset < 0)
3442 offset = MAX(0, ci_data(chn) + offset);
3443 if (len < 0)
3444 len = ci_data(chn) - offset;
3445
3446 if (offset + len > ci_data(chn)) {
3447 lua_pushfstring(L, "offset or length out of range.");
3448 WILL_LJMP(lua_error(L));
3449 }
3450
Christopher Faulet23976d92021-08-06 09:59:49 +02003451 /* Be sure we can copied the string once input data will be removed. */
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003452 if (sz > c_room(chn) + len)
Christopher Faulet23976d92021-08-06 09:59:49 +02003453 lua_pushinteger(L, -1);
3454 else {
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003455 _hlua_channel_delete(chn, co_data(chn) + offset, len);
3456 ret = _hlua_channel_insert(chn, L, ist2(str, sz), co_data(chn) + offset);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003457 lua_pushinteger(L, ret);
Christopher Faulet23976d92021-08-06 09:59:49 +02003458 }
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003459 return 1;
3460}
3461
3462/* Removes a given amount of input data at the given offset. By default all
3463 * intput data are removed (offset = 0 and len = -1). It returns the amount of
3464 * the removed data.
3465 */
3466__LJMP static int hlua_channel_del_data(lua_State *L)
3467{
3468 struct channel *chn;
3469 int offset = 0, len = -1;
3470
3471 if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
3472 WILL_LJMP(luaL_error(L, "'remove' expects at most 2 arguments"));
3473 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3474 if (lua_gettop(L) > 1)
3475 offset = MAY_LJMP(luaL_checkinteger(L, 2));
3476 if (lua_gettop(L) == 3)
3477 len = MAY_LJMP(luaL_checkinteger(L, 3));
3478 if (IS_HTX_STRM(chn_strm(chn))) {
3479 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3480 WILL_LJMP(lua_error(L));
3481 }
3482
3483 if (offset < 0)
3484 offset = MAX(0, ci_data(chn) + offset);
3485 if (len < 0)
3486 len = ci_data(chn) - offset;
3487
3488 if (offset + len > ci_data(chn)) {
3489 lua_pushfstring(L, "offset or length out of range.");
3490 WILL_LJMP(lua_error(L));
3491 }
3492
3493 _hlua_channel_delete(chn, co_data(chn) + offset, len);
3494 lua_pushinteger(L, len);
Christopher Faulet23976d92021-08-06 09:59:49 +02003495 return 1;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003496}
3497
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003498/* Append data in the output side of the buffer. This data is immediately
3499 * sent. The function returns the amount of data written. If the buffer
3500 * cannot contain the data, the function yields. The function returns -1
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003501 * if the channel is closed.
3502 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003503__LJMP static int hlua_channel_send_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003504{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003505 struct channel *chn;
3506 const char *str;
3507 size_t sz, len;
3508 int l, ret;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01003509 struct hlua *hlua;
3510
3511 /* Get hlua struct, or NULL if we execute from main lua state */
3512 hlua = hlua_gethlua(L);
3513 if (!hlua) {
3514 lua_pushnil(L);
3515 return 1;
3516 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003517
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003518 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3519 str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
3520 l = MAY_LJMP(luaL_checkinteger(L, 3));
Christopher Faulet3f829a42018-12-13 21:56:45 +01003521
Willy Tarreau47860ed2015-03-10 14:07:50 +01003522 if (unlikely(channel_output_closed(chn))) {
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003523 lua_pushinteger(L, -1);
3524 return 1;
3525 }
3526
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003527 /* Check if the buffer is available because HAProxy doesn't allocate
Thierry FOURNIER3e3a6082015-03-05 17:06:12 +01003528 * the request buffer if its not required.
3529 */
Willy Tarreauc9fa0482018-07-10 17:43:27 +02003530 if (chn->buf.size == 0) {
Christopher Faulet2e60aa42021-08-05 11:58:37 +02003531 if (HLUA_CANT_YIELD(hlua_gethlua(L)))
3532 return 1;
Willy Tarreau4b962a42018-11-15 11:03:21 +01003533 si_rx_buff_blk(chn_prod(chn));
Willy Tarreau9635e032018-10-16 17:52:55 +02003534 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_send_yield, TICK_ETERNITY, 0));
Thierry FOURNIER3e3a6082015-03-05 17:06:12 +01003535 }
3536
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003537 len = c_room(chn);
3538 if (len > sz - l)
3539 len = sz - l;
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003540
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003541 ret = _hlua_channel_insert(chn, L, ist2(str+l, len), co_data(chn));
3542 if (ret == -1) {
3543 lua_pop(L, 1);
3544 lua_pushinteger(L, -1);
Thierry FOURNIERdeb5d732015-03-06 01:07:45 +01003545 return 1;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003546 }
3547 if (ret) {
3548 c_adv(chn, ret);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003549
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003550 l += ret;
3551 lua_pop(L, 1);
3552 lua_pushinteger(L, l);
3553 }
3554 if (l < sz) {
3555 /* Yield only if the channel's output is not empty.
3556 * Otherwise it means we cannot add more data. */
3557 if (co_data(chn) == 0 || HLUA_CANT_YIELD(hlua_gethlua(L)))
Christopher Faulet2e60aa42021-08-05 11:58:37 +02003558 return 1;
3559
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003560 /* If we are waiting for space in the response buffer, we
3561 * must set the flag WAKERESWR. This flag required the task
3562 * wake up if any activity is detected on the response buffer.
3563 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01003564 if (chn->flags & CF_ISRESP)
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003565 HLUA_SET_WAKERESWR(hlua);
Thierry FOURNIER53e08ec2015-03-06 00:35:53 +01003566 else
3567 HLUA_SET_WAKEREQWR(hlua);
Willy Tarreau9635e032018-10-16 17:52:55 +02003568 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_send_yield, TICK_ETERNITY, 0));
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003569 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003570
3571 return 1;
3572}
3573
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003574/* Just a wrapper of "_hlua_channel_send". This wrapper permits
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003575 * yield the LUA process, and resume it without checking the
3576 * input arguments.
3577 */
3578__LJMP static int hlua_channel_send(lua_State *L)
3579{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003580 struct channel *chn;
3581
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003582 MAY_LJMP(check_args(L, 2, "send"));
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003583 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3584 if (IS_HTX_STRM(chn_strm(chn))) {
3585 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3586 WILL_LJMP(lua_error(L));
3587 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003588 lua_pushinteger(L, 0);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003589 return MAY_LJMP(hlua_channel_send_yield(L, 0, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003590}
3591
3592/* This function forward and amount of butes. The data pass from
3593 * the input side of the buffer to the output side, and can be
3594 * forwarded. This function never fails.
3595 *
3596 * The Lua function takes an amount of bytes to be forwarded in
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05003597 * input. It returns the number of bytes forwarded.
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003598 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003599__LJMP static int hlua_channel_forward_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003600{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003601 struct channel *chn;
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003602 size_t len;
3603 int l, max;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01003604 struct hlua *hlua;
3605
3606 /* Get hlua struct, or NULL if we execute from main lua state */
3607 hlua = hlua_gethlua(L);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003608 if (!hlua) {
3609 lua_pushnil(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01003610 return 1;
Thierry Fournier77016da2020-08-15 14:35:51 +02003611 }
Christopher Faulet3f829a42018-12-13 21:56:45 +01003612
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003613 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003614 len = MAY_LJMP(luaL_checkinteger(L, 2));
3615 l = MAY_LJMP(luaL_checkinteger(L, -1));
3616
3617 max = len - l;
Willy Tarreaua79021a2018-06-15 18:07:57 +02003618 if (max > ci_data(chn))
3619 max = ci_data(chn);
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003620
Willy Tarreau47860ed2015-03-10 14:07:50 +01003621 channel_forward(chn, max);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003622
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003623 l += max;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003624 lua_pop(L, 1);
3625 lua_pushinteger(L, l);
3626
3627 /* Check if it miss bytes to forward. */
3628 if (l < len) {
3629 /* The the input channel or the output channel are closed, we
3630 * must return the amount of data forwarded.
3631 */
Christopher Faulet2e60aa42021-08-05 11:58:37 +02003632 if (channel_input_closed(chn) || channel_output_closed(chn) || HLUA_CANT_YIELD(hlua_gethlua(L)))
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003633 return 1;
3634
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003635 /* If we are waiting for space data in the response buffer, we
3636 * must set the flag WAKERESWR. This flag required the task
3637 * wake up if any activity is detected on the response buffer.
3638 */
Willy Tarreau47860ed2015-03-10 14:07:50 +01003639 if (chn->flags & CF_ISRESP)
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003640 HLUA_SET_WAKERESWR(hlua);
Thierry FOURNIER53e08ec2015-03-06 00:35:53 +01003641 else
3642 HLUA_SET_WAKEREQWR(hlua);
Thierry FOURNIERef6a2112015-03-05 17:45:34 +01003643
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003644 /* Otherwise, we can yield waiting for new data in the inpout side. */
Willy Tarreau9635e032018-10-16 17:52:55 +02003645 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_forward_yield, TICK_ETERNITY, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003646 }
3647
3648 return 1;
3649}
3650
3651/* Just check the input and prepare the stack for the previous
3652 * function "hlua_channel_forward_yield"
3653 */
3654__LJMP static int hlua_channel_forward(lua_State *L)
3655{
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003656 struct channel *chn;
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003657
Christopher Faulet9a6ffda2021-08-06 13:49:54 +02003658 MAY_LJMP(check_args(L, 2, "forward"));
3659 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3660 if (IS_HTX_STRM(chn_strm(chn))) {
3661 lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
3662 WILL_LJMP(lua_error(L));
3663 }
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003664 lua_pushinteger(L, 0);
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01003665 return MAY_LJMP(hlua_channel_forward_yield(L, 0, 0));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003666}
3667
3668/* Just returns the number of bytes available in the input
3669 * side of the buffer. This function never fails.
3670 */
3671__LJMP static int hlua_channel_get_in_len(lua_State *L)
3672{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003673 struct channel *chn;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003674
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003675 MAY_LJMP(check_args(L, 1, "input"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003676 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Fauleta3ceac12018-12-14 13:39:09 +01003677 if (IS_HTX_STRM(chn_strm(chn))) {
3678 struct htx *htx = htxbuf(&chn->buf);
3679 lua_pushinteger(L, htx->data - co_data(chn));
3680 }
3681 else
3682 lua_pushinteger(L, ci_data(chn));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003683 return 1;
3684}
3685
Thierry FOURNIER / OZON.IO65192f32016-11-07 15:28:40 +01003686/* Returns true if the channel is full. */
3687__LJMP static int hlua_channel_is_full(lua_State *L)
3688{
3689 struct channel *chn;
Thierry FOURNIER / OZON.IO65192f32016-11-07 15:28:40 +01003690
3691 MAY_LJMP(check_args(L, 1, "is_full"));
3692 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Christopher Faulet0ec740e2020-02-26 11:59:19 +01003693 /* ignore the reserve, we are not on a producer side (ie in an
3694 * applet).
3695 */
3696 lua_pushboolean(L, channel_full(chn, 0));
Thierry FOURNIER / OZON.IO65192f32016-11-07 15:28:40 +01003697 return 1;
3698}
3699
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003700/* Returns true if the channel may still receive data. */
3701__LJMP static int hlua_channel_may_recv(lua_State *L)
3702{
3703 struct channel *chn;
3704
3705 MAY_LJMP(check_args(L, 1, "may_recv"));
3706 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3707 lua_pushboolean(L, (!channel_input_closed(chn) && channel_may_recv(chn)));
3708 return 1;
3709}
3710
Christopher Faulet2ac9ba22020-02-25 10:15:50 +01003711/* Returns true if the channel is the response channel. */
3712__LJMP static int hlua_channel_is_resp(lua_State *L)
3713{
3714 struct channel *chn;
3715
3716 MAY_LJMP(check_args(L, 1, "is_resp"));
3717 chn = MAY_LJMP(hlua_checkchannel(L, 1));
3718
3719 lua_pushboolean(L, !!(chn->flags & CF_ISRESP));
3720 return 1;
3721}
3722
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003723/* Just returns the number of bytes available in the output
3724 * side of the buffer. This function never fails.
3725 */
3726__LJMP static int hlua_channel_get_out_len(lua_State *L)
3727{
Willy Tarreau47860ed2015-03-10 14:07:50 +01003728 struct channel *chn;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003729
Christopher Faulet6a79fc12021-08-06 16:02:36 +02003730 MAY_LJMP(check_args(L, 1, "output"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01003731 chn = MAY_LJMP(hlua_checkchannel(L, 1));
Willy Tarreaua79021a2018-06-15 18:07:57 +02003732 lua_pushinteger(L, co_data(chn));
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003733 return 1;
3734}
3735
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003736/*
3737 *
3738 *
3739 * Class Fetches
3740 *
3741 *
3742 */
3743
3744/* Returns a struct hlua_session if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02003745 * a class stream, otherwise it throws an error.
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003746 */
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01003747__LJMP static struct hlua_smp *hlua_checkfetches(lua_State *L, int ud)
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003748{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02003749 return MAY_LJMP(hlua_checkudata(L, ud, class_fetches_ref));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003750}
3751
3752/* This function creates and push in the stack a fetch object according
3753 * with a current TXN.
3754 */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003755static int hlua_fetches_new(lua_State *L, struct hlua_txn *txn, unsigned int flags)
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003756{
Willy Tarreau7073c472015-04-06 11:15:40 +02003757 struct hlua_smp *hsmp;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003758
3759 /* Check stack size. */
3760 if (!lua_checkstack(L, 3))
3761 return 0;
3762
3763 /* Create the object: obj[0] = userdata.
3764 * Note that the base of the Fetches object is the
3765 * transaction object.
3766 */
3767 lua_newtable(L);
Willy Tarreau7073c472015-04-06 11:15:40 +02003768 hsmp = lua_newuserdata(L, sizeof(*hsmp));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003769 lua_rawseti(L, -2, 0);
3770
Willy Tarreau7073c472015-04-06 11:15:40 +02003771 hsmp->s = txn->s;
3772 hsmp->p = txn->p;
Thierry FOURNIERc4eebc82015-11-02 10:01:59 +01003773 hsmp->dir = txn->dir;
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003774 hsmp->flags = flags;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003775
3776 /* Pop a class sesison metatable and affect it to the userdata. */
3777 lua_rawgeti(L, LUA_REGISTRYINDEX, class_fetches_ref);
3778 lua_setmetatable(L, -2);
3779
3780 return 1;
3781}
3782
3783/* This function is an LUA binding. It is called with each sample-fetch.
3784 * It uses closure argument to store the associated sample-fetch. It
3785 * returns only one argument or throws an error. An error is thrown
3786 * only if an error is encountered during the argument parsing. If
3787 * the "sample-fetch" function fails, nil is returned.
3788 */
3789__LJMP static int hlua_run_sample_fetch(lua_State *L)
3790{
Willy Tarreaub2ccb562015-04-06 11:11:15 +02003791 struct hlua_smp *hsmp;
Willy Tarreau2ec22742015-03-10 14:27:20 +01003792 struct sample_fetch *f;
Frédéric Lécaillef874a832018-06-15 13:56:04 +02003793 struct arg args[ARGM_NBARGS + 1] = {{0}};
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003794 int i;
3795 struct sample smp;
3796
3797 /* Get closure arguments. */
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02003798 f = lua_touserdata(L, lua_upvalueindex(1));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003799
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003800 /* Get traditional arguments. */
Willy Tarreaub2ccb562015-04-06 11:11:15 +02003801 hsmp = MAY_LJMP(hlua_checkfetches(L, 1));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003802
Thierry FOURNIERca988662015-12-20 18:43:03 +01003803 /* Check execution authorization. */
3804 if (f->use & SMP_USE_HTTP_ANY &&
3805 !(hsmp->flags & HLUA_F_MAY_USE_HTTP)) {
3806 lua_pushfstring(L, "the sample-fetch '%s' needs an HTTP parser which "
3807 "is not available in Lua services", f->kw);
3808 WILL_LJMP(lua_error(L));
3809 }
3810
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003811 /* Get extra arguments. */
3812 for (i = 0; i < lua_gettop(L) - 1; i++) {
3813 if (i >= ARGM_NBARGS)
3814 break;
3815 hlua_lua2arg(L, i + 2, &args[i]);
3816 }
3817 args[i].type = ARGT_STOP;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02003818 args[i].data.str.area = NULL;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003819
3820 /* Check arguments. */
Willy Tarreaub2ccb562015-04-06 11:11:15 +02003821 MAY_LJMP(hlua_lua2arg_check(L, 2, args, f->arg_mask, hsmp->p));
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003822
3823 /* Run the special args checker. */
Willy Tarreau2ec22742015-03-10 14:27:20 +01003824 if (f->val_args && !f->val_args(args, NULL)) {
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003825 lua_pushfstring(L, "error in arguments");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003826 goto error;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003827 }
3828
3829 /* Initialise the sample. */
3830 memset(&smp, 0, sizeof(smp));
3831
3832 /* Run the sample fetch process. */
Willy Tarreau1777ea62016-03-10 16:15:46 +01003833 smp_set_owner(&smp, hsmp->p, hsmp->s->sess, hsmp->s, hsmp->dir & SMP_OPT_DIR);
Thierry FOURNIER0786d052015-05-11 15:42:45 +02003834 if (!f->process(args, &smp, f->kw, f->private)) {
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003835 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01003836 lua_pushstring(L, "");
3837 else
3838 lua_pushnil(L);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003839 goto end;
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003840 }
3841
3842 /* Convert the returned sample in lua value. */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003843 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01003844 hlua_smp2lua_str(L, &smp);
3845 else
3846 hlua_smp2lua(L, &smp);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003847
3848 end:
Willy Tarreauee0d7272021-07-16 10:26:56 +02003849 free_args(args);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003850 return 1;
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003851
3852 error:
Willy Tarreauee0d7272021-07-16 10:26:56 +02003853 free_args(args);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003854 WILL_LJMP(lua_error(L));
3855 return 0; /* Never reached */
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01003856}
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01003857
3858/*
3859 *
3860 *
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003861 * Class Converters
3862 *
3863 *
3864 */
3865
3866/* Returns a struct hlua_session if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02003867 * a class stream, otherwise it throws an error.
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003868 */
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01003869__LJMP static struct hlua_smp *hlua_checkconverters(lua_State *L, int ud)
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003870{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02003871 return MAY_LJMP(hlua_checkudata(L, ud, class_converters_ref));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003872}
3873
3874/* This function creates and push in the stack a Converters object
3875 * according with a current TXN.
3876 */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003877static int hlua_converters_new(lua_State *L, struct hlua_txn *txn, unsigned int flags)
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003878{
Willy Tarreau7073c472015-04-06 11:15:40 +02003879 struct hlua_smp *hsmp;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003880
3881 /* Check stack size. */
3882 if (!lua_checkstack(L, 3))
3883 return 0;
3884
3885 /* Create the object: obj[0] = userdata.
3886 * Note that the base of the Converters object is the
3887 * same than the TXN object.
3888 */
3889 lua_newtable(L);
Willy Tarreau7073c472015-04-06 11:15:40 +02003890 hsmp = lua_newuserdata(L, sizeof(*hsmp));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003891 lua_rawseti(L, -2, 0);
3892
Willy Tarreau7073c472015-04-06 11:15:40 +02003893 hsmp->s = txn->s;
3894 hsmp->p = txn->p;
Thierry FOURNIERc4eebc82015-11-02 10:01:59 +01003895 hsmp->dir = txn->dir;
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003896 hsmp->flags = flags;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003897
Willy Tarreau87b09662015-04-03 00:22:06 +02003898 /* Pop a class stream metatable and affect it to the table. */
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003899 lua_rawgeti(L, LUA_REGISTRYINDEX, class_converters_ref);
3900 lua_setmetatable(L, -2);
3901
3902 return 1;
3903}
3904
3905/* This function is an LUA binding. It is called with each converter.
3906 * It uses closure argument to store the associated converter. It
3907 * returns only one argument or throws an error. An error is thrown
3908 * only if an error is encountered during the argument parsing. If
3909 * the converter function function fails, nil is returned.
3910 */
3911__LJMP static int hlua_run_sample_conv(lua_State *L)
3912{
Willy Tarreauda5f1082015-04-06 11:17:13 +02003913 struct hlua_smp *hsmp;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003914 struct sample_conv *conv;
Frédéric Lécaillef874a832018-06-15 13:56:04 +02003915 struct arg args[ARGM_NBARGS + 1] = {{0}};
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003916 int i;
3917 struct sample smp;
3918
3919 /* Get closure arguments. */
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02003920 conv = lua_touserdata(L, lua_upvalueindex(1));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003921
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08003922 /* Get traditional arguments. */
Willy Tarreauda5f1082015-04-06 11:17:13 +02003923 hsmp = MAY_LJMP(hlua_checkconverters(L, 1));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003924
3925 /* Get extra arguments. */
3926 for (i = 0; i < lua_gettop(L) - 2; i++) {
3927 if (i >= ARGM_NBARGS)
3928 break;
3929 hlua_lua2arg(L, i + 3, &args[i]);
3930 }
3931 args[i].type = ARGT_STOP;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02003932 args[i].data.str.area = NULL;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003933
3934 /* Check arguments. */
Willy Tarreauda5f1082015-04-06 11:17:13 +02003935 MAY_LJMP(hlua_lua2arg_check(L, 3, args, conv->arg_mask, hsmp->p));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003936
3937 /* Run the special args checker. */
3938 if (conv->val_args && !conv->val_args(args, conv, "", 0, NULL)) {
3939 hlua_pusherror(L, "error in arguments");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003940 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003941 }
3942
3943 /* Initialise the sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01003944 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003945 if (!hlua_lua2smp(L, 2, &smp)) {
3946 hlua_pusherror(L, "error in the input argument");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003947 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003948 }
3949
Willy Tarreau1777ea62016-03-10 16:15:46 +01003950 smp_set_owner(&smp, hsmp->p, hsmp->s->sess, hsmp->s, hsmp->dir & SMP_OPT_DIR);
3951
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003952 /* Apply expected cast. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02003953 if (!sample_casts[smp.data.type][conv->in_type]) {
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003954 hlua_pusherror(L, "invalid input argument: cannot cast '%s' to '%s'",
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02003955 smp_to_type[smp.data.type], smp_to_type[conv->in_type]);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003956 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003957 }
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +02003958 if (sample_casts[smp.data.type][conv->in_type] != c_none &&
3959 !sample_casts[smp.data.type][conv->in_type](&smp)) {
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003960 hlua_pusherror(L, "error during the input argument casting");
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003961 goto error;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003962 }
3963
3964 /* Run the sample conversion process. */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02003965 if (!conv->process(args, &smp, conv->private)) {
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003966 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01003967 lua_pushstring(L, "");
3968 else
Willy Tarreaua678b432015-08-28 10:14:59 +02003969 lua_pushnil(L);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003970 goto end;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003971 }
3972
3973 /* Convert the returned sample in lua value. */
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01003974 if (hsmp->flags & HLUA_F_AS_STRING)
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01003975 hlua_smp2lua_str(L, &smp);
3976 else
3977 hlua_smp2lua(L, &smp);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003978 end:
Willy Tarreauee0d7272021-07-16 10:26:56 +02003979 free_args(args);
Willy Tarreaua678b432015-08-28 10:14:59 +02003980 return 1;
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003981
3982 error:
Willy Tarreauee0d7272021-07-16 10:26:56 +02003983 free_args(args);
Christopher Fauletaec27ef2020-08-06 08:54:25 +02003984 WILL_LJMP(lua_error(L));
3985 return 0; /* Never reached */
Thierry FOURNIER594afe72015-03-10 23:58:30 +01003986}
3987
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02003988/*
3989 *
3990 *
3991 * Class AppletTCP
3992 *
3993 *
3994 */
3995
3996/* Returns a struct hlua_txn if the stack entry "ud" is
3997 * a class stream, otherwise it throws an error.
3998 */
3999__LJMP static struct hlua_appctx *hlua_checkapplet_tcp(lua_State *L, int ud)
4000{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02004001 return MAY_LJMP(hlua_checkudata(L, ud, class_applet_tcp_ref));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004002}
4003
4004/* This function creates and push in the stack an Applet object
4005 * according with a current TXN.
4006 */
4007static int hlua_applet_tcp_new(lua_State *L, struct appctx *ctx)
4008{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004009 struct hlua_appctx *luactx;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004010 struct stream_interface *si = ctx->owner;
4011 struct stream *s = si_strm(si);
4012 struct proxy *p = s->be;
4013
4014 /* Check stack size. */
4015 if (!lua_checkstack(L, 3))
4016 return 0;
4017
4018 /* Create the object: obj[0] = userdata.
4019 * Note that the base of the Converters object is the
4020 * same than the TXN object.
4021 */
4022 lua_newtable(L);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004023 luactx = lua_newuserdata(L, sizeof(*luactx));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004024 lua_rawseti(L, -2, 0);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004025 luactx->appctx = ctx;
4026 luactx->htxn.s = s;
4027 luactx->htxn.p = p;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004028
4029 /* Create the "f" field that contains a list of fetches. */
4030 lua_pushstring(L, "f");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004031 if (!hlua_fetches_new(L, &luactx->htxn, 0))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004032 return 0;
4033 lua_settable(L, -3);
4034
4035 /* Create the "sf" field that contains a list of stringsafe fetches. */
4036 lua_pushstring(L, "sf");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004037 if (!hlua_fetches_new(L, &luactx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004038 return 0;
4039 lua_settable(L, -3);
4040
4041 /* Create the "c" field that contains a list of converters. */
4042 lua_pushstring(L, "c");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004043 if (!hlua_converters_new(L, &luactx->htxn, 0))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004044 return 0;
4045 lua_settable(L, -3);
4046
4047 /* Create the "sc" field that contains a list of stringsafe converters. */
4048 lua_pushstring(L, "sc");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004049 if (!hlua_converters_new(L, &luactx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004050 return 0;
4051 lua_settable(L, -3);
4052
4053 /* Pop a class stream metatable and affect it to the table. */
4054 lua_rawgeti(L, LUA_REGISTRYINDEX, class_applet_tcp_ref);
4055 lua_setmetatable(L, -2);
4056
4057 return 1;
4058}
4059
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004060__LJMP static int hlua_applet_tcp_set_var(lua_State *L)
4061{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004062 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004063 struct stream *s;
4064 const char *name;
4065 size_t len;
4066 struct sample smp;
4067
Tim Duesterhus4e172c92020-05-19 13:49:42 +02004068 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
4069 WILL_LJMP(luaL_error(L, "'set_var' needs between 3 and 4 arguments"));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004070
4071 /* It is useles to retrieve the stream, but this function
4072 * runs only in a stream context.
4073 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004074 luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004075 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004076 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004077
4078 /* Converts the third argument in a sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01004079 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004080 hlua_lua2smp(L, 3, &smp);
4081
4082 /* Store the sample in a variable. */
4083 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus4e172c92020-05-19 13:49:42 +02004084
4085 if (lua_gettop(L) == 4 && lua_toboolean(L, 4))
4086 lua_pushboolean(L, vars_set_by_name_ifexist(name, len, &smp) != 0);
4087 else
4088 lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
4089
Tim Duesterhus84ebc132020-05-19 13:49:41 +02004090 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004091}
4092
4093__LJMP static int hlua_applet_tcp_unset_var(lua_State *L)
4094{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004095 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004096 struct stream *s;
4097 const char *name;
4098 size_t len;
4099 struct sample smp;
4100
4101 MAY_LJMP(check_args(L, 2, "unset_var"));
4102
4103 /* It is useles to retrieve the stream, but this function
4104 * runs only in a stream context.
4105 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004106 luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004107 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004108 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004109
4110 /* Unset the variable. */
4111 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus84ebc132020-05-19 13:49:41 +02004112 lua_pushboolean(L, vars_unset_by_name_ifexist(name, len, &smp) != 0);
4113 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004114}
4115
4116__LJMP static int hlua_applet_tcp_get_var(lua_State *L)
4117{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004118 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004119 struct stream *s;
4120 const char *name;
4121 size_t len;
4122 struct sample smp;
4123
4124 MAY_LJMP(check_args(L, 2, "get_var"));
4125
4126 /* It is useles to retrieve the stream, but this function
4127 * runs only in a stream context.
4128 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004129 luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004130 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004131 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004132
4133 smp_set_owner(&smp, s->be, s->sess, s, 0);
4134 if (!vars_get_by_name(name, len, &smp)) {
4135 lua_pushnil(L);
4136 return 1;
4137 }
4138
4139 return hlua_smp2lua(L, &smp);
4140}
4141
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004142__LJMP static int hlua_applet_tcp_set_priv(lua_State *L)
4143{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004144 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
4145 struct stream *s = luactx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01004146 struct hlua *hlua;
4147
4148 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01004149 if (!s->hlua)
4150 return 0;
4151 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004152
4153 MAY_LJMP(check_args(L, 2, "set_priv"));
4154
4155 /* Remove previous value. */
Thierry FOURNIERe068b602017-04-26 13:27:05 +02004156 luaL_unref(L, LUA_REGISTRYINDEX, hlua->Mref);
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004157
4158 /* Get and store new value. */
4159 lua_pushvalue(L, 2); /* Copy the element 2 at the top of the stack. */
4160 hlua->Mref = luaL_ref(L, LUA_REGISTRYINDEX); /* pop the previously pushed value. */
4161
4162 return 0;
4163}
4164
4165__LJMP static int hlua_applet_tcp_get_priv(lua_State *L)
4166{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004167 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
4168 struct stream *s = luactx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01004169 struct hlua *hlua;
4170
4171 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01004172 if (!s->hlua) {
4173 lua_pushnil(L);
4174 return 1;
4175 }
4176 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004177
4178 /* Push configuration index in the stack. */
4179 lua_rawgeti(L, LUA_REGISTRYINDEX, hlua->Mref);
4180
4181 return 1;
4182}
4183
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004184/* If expected data not yet available, it returns a yield. This function
4185 * consumes the data in the buffer. It returns a string containing the
4186 * data. This string can be empty.
4187 */
4188__LJMP static int hlua_applet_tcp_getline_yield(lua_State *L, int status, lua_KContext ctx)
4189{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004190 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
4191 struct stream_interface *si = luactx->appctx->owner;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004192 int ret;
Willy Tarreau206ba832018-06-14 15:27:31 +02004193 const char *blk1;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02004194 size_t len1;
Willy Tarreau206ba832018-06-14 15:27:31 +02004195 const char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02004196 size_t len2;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004197
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004198 /* Read the maximum amount of data available. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02004199 ret = co_getline_nc(si_oc(si), &blk1, &len1, &blk2, &len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004200
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004201 /* Data not yet available. return yield. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004202 if (ret == 0) {
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01004203 si_cant_get(si);
Willy Tarreau9635e032018-10-16 17:52:55 +02004204 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_getline_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004205 }
4206
4207 /* End of data: commit the total strings and return. */
4208 if (ret < 0) {
Willy Tarreau7e702d12021-04-28 17:59:21 +02004209 luaL_pushresult(&luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004210 return 1;
4211 }
4212
4213 /* Ensure that the block 2 length is usable. */
4214 if (ret == 1)
4215 len2 = 0;
4216
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07004217 /* don't check the max length read and don't check. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004218 luaL_addlstring(&luactx->b, blk1, len1);
4219 luaL_addlstring(&luactx->b, blk2, len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004220
4221 /* Consume input channel output buffer data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02004222 co_skip(si_oc(si), len1 + len2);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004223 luaL_pushresult(&luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004224 return 1;
4225}
4226
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004227/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004228__LJMP static int hlua_applet_tcp_getline(lua_State *L)
4229{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004230 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004231
4232 /* Initialise the string catenation. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004233 luaL_buffinit(L, &luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004234
4235 return MAY_LJMP(hlua_applet_tcp_getline_yield(L, 0, 0));
4236}
4237
4238/* If expected data not yet available, it returns a yield. This function
4239 * consumes the data in the buffer. It returns a string containing the
4240 * data. This string can be empty.
4241 */
4242__LJMP static int hlua_applet_tcp_recv_yield(lua_State *L, int status, lua_KContext ctx)
4243{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004244 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
4245 struct stream_interface *si = luactx->appctx->owner;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02004246 size_t len = MAY_LJMP(luaL_checkinteger(L, 2));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004247 int ret;
Willy Tarreau206ba832018-06-14 15:27:31 +02004248 const char *blk1;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02004249 size_t len1;
Willy Tarreau206ba832018-06-14 15:27:31 +02004250 const char *blk2;
Willy Tarreau55f3ce12018-07-18 11:49:27 +02004251 size_t len2;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004252
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004253 /* Read the maximum amount of data available. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02004254 ret = co_getblk_nc(si_oc(si), &blk1, &len1, &blk2, &len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004255
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004256 /* Data not yet available. return yield. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004257 if (ret == 0) {
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01004258 si_cant_get(si);
Willy Tarreau9635e032018-10-16 17:52:55 +02004259 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004260 }
4261
4262 /* End of data: commit the total strings and return. */
4263 if (ret < 0) {
Willy Tarreau7e702d12021-04-28 17:59:21 +02004264 luaL_pushresult(&luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004265 return 1;
4266 }
4267
4268 /* Ensure that the block 2 length is usable. */
4269 if (ret == 1)
4270 len2 = 0;
4271
4272 if (len == -1) {
4273
4274 /* If len == -1, catenate all the data avalaile and
4275 * yield because we want to get all the data until
4276 * the end of data stream.
4277 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004278 luaL_addlstring(&luactx->b, blk1, len1);
4279 luaL_addlstring(&luactx->b, blk2, len2);
Willy Tarreau06d80a92017-10-19 14:32:15 +02004280 co_skip(si_oc(si), len1 + len2);
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01004281 si_cant_get(si);
Willy Tarreau9635e032018-10-16 17:52:55 +02004282 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004283
4284 } else {
4285
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05004286 /* Copy the first block caping to the length required. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004287 if (len1 > len)
4288 len1 = len;
Willy Tarreau7e702d12021-04-28 17:59:21 +02004289 luaL_addlstring(&luactx->b, blk1, len1);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004290 len -= len1;
4291
4292 /* Copy the second block. */
4293 if (len2 > len)
4294 len2 = len;
Willy Tarreau7e702d12021-04-28 17:59:21 +02004295 luaL_addlstring(&luactx->b, blk2, len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004296 len -= len2;
4297
4298 /* Consume input channel output buffer data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02004299 co_skip(si_oc(si), len1 + len2);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004300
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004301 /* If there is no other data available, yield waiting for new data. */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004302 if (len > 0) {
4303 lua_pushinteger(L, len);
4304 lua_replace(L, 2);
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01004305 si_cant_get(si);
Willy Tarreau9635e032018-10-16 17:52:55 +02004306 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004307 }
4308
4309 /* return the result. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004310 luaL_pushresult(&luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004311 return 1;
4312 }
4313
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004314 /* we never execute this */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004315 hlua_pusherror(L, "Lua: internal error");
4316 WILL_LJMP(lua_error(L));
4317 return 0;
4318}
4319
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004320/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004321__LJMP static int hlua_applet_tcp_recv(lua_State *L)
4322{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004323 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004324 int len = -1;
4325
4326 if (lua_gettop(L) > 2)
4327 WILL_LJMP(luaL_error(L, "The 'recv' function requires between 1 and 2 arguments."));
4328 if (lua_gettop(L) >= 2) {
4329 len = MAY_LJMP(luaL_checkinteger(L, 2));
4330 lua_pop(L, 1);
4331 }
4332
4333 /* Confirm or set the required length */
4334 lua_pushinteger(L, len);
4335
4336 /* Initialise the string catenation. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004337 luaL_buffinit(L, &luactx->b);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004338
4339 return MAY_LJMP(hlua_applet_tcp_recv_yield(L, 0, 0));
4340}
4341
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004342/* Append data in the output side of the buffer. This data is immediately
4343 * sent. The function returns the amount of data written. If the buffer
4344 * cannot contain the data, the function yields. The function returns -1
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004345 * if the channel is closed.
4346 */
4347__LJMP static int hlua_applet_tcp_send_yield(lua_State *L, int status, lua_KContext ctx)
4348{
4349 size_t len;
Willy Tarreau7e702d12021-04-28 17:59:21 +02004350 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_tcp(L, 1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004351 const char *str = MAY_LJMP(luaL_checklstring(L, 2, &len));
4352 int l = MAY_LJMP(luaL_checkinteger(L, 3));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004353 struct stream_interface *si = luactx->appctx->owner;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004354 struct channel *chn = si_ic(si);
4355 int max;
4356
4357 /* Get the max amount of data which can write as input in the channel. */
4358 max = channel_recv_max(chn);
4359 if (max > (len - l))
4360 max = len - l;
4361
4362 /* Copy data. */
Willy Tarreau06d80a92017-10-19 14:32:15 +02004363 ci_putblk(chn, str + l, max);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004364
4365 /* update counters. */
4366 l += max;
4367 lua_pop(L, 1);
4368 lua_pushinteger(L, l);
4369
4370 /* If some data is not send, declares the situation to the
4371 * applet, and returns a yield.
4372 */
4373 if (l < len) {
Willy Tarreaudb398432018-11-15 11:08:52 +01004374 si_rx_room_blk(si);
Willy Tarreau9635e032018-10-16 17:52:55 +02004375 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_tcp_send_yield, TICK_ETERNITY, 0));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004376 }
4377
4378 return 1;
4379}
4380
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05004381/* Just a wrapper of "hlua_applet_tcp_send_yield". This wrapper permits
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02004382 * yield the LUA process, and resume it without checking the
4383 * input arguments.
4384 */
4385__LJMP static int hlua_applet_tcp_send(lua_State *L)
4386{
4387 MAY_LJMP(check_args(L, 2, "send"));
4388 lua_pushinteger(L, 0);
4389
4390 return MAY_LJMP(hlua_applet_tcp_send_yield(L, 0, 0));
4391}
4392
Thierry FOURNIER594afe72015-03-10 23:58:30 +01004393/*
4394 *
4395 *
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004396 * Class AppletHTTP
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004397 *
4398 *
4399 */
4400
4401/* Returns a struct hlua_txn if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02004402 * a class stream, otherwise it throws an error.
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004403 */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004404__LJMP static struct hlua_appctx *hlua_checkapplet_http(lua_State *L, int ud)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004405{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02004406 return MAY_LJMP(hlua_checkudata(L, ud, class_applet_http_ref));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004407}
4408
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004409/* This function creates and push in the stack an Applet object
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004410 * according with a current TXN.
4411 */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004412static int hlua_applet_http_new(lua_State *L, struct appctx *ctx)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004413{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004414 struct hlua_appctx *luactx;
Thierry FOURNIER841475e2015-12-11 17:10:09 +01004415 struct hlua_txn htxn;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004416 struct stream_interface *si = ctx->owner;
4417 struct stream *s = si_strm(si);
4418 struct proxy *px = s->be;
Christopher Fauleta2097962019-07-15 16:25:33 +02004419 struct htx *htx;
4420 struct htx_blk *blk;
4421 struct htx_sl *sl;
4422 struct ist path;
4423 unsigned long long len = 0;
4424 int32_t pos;
Amaury Denoyellec453f952021-07-06 11:40:12 +02004425 struct http_uri_parser parser;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004426
4427 /* Check stack size. */
4428 if (!lua_checkstack(L, 3))
4429 return 0;
4430
4431 /* Create the object: obj[0] = userdata.
4432 * Note that the base of the Converters object is the
4433 * same than the TXN object.
4434 */
4435 lua_newtable(L);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004436 luactx = lua_newuserdata(L, sizeof(*luactx));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004437 lua_rawseti(L, -2, 0);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004438 luactx->appctx = ctx;
4439 luactx->appctx->ctx.hlua_apphttp.status = 200; /* Default status code returned. */
4440 luactx->appctx->ctx.hlua_apphttp.reason = NULL; /* Use default reason based on status */
4441 luactx->htxn.s = s;
4442 luactx->htxn.p = px;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004443
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004444 /* Create the "f" field that contains a list of fetches. */
4445 lua_pushstring(L, "f");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004446 if (!hlua_fetches_new(L, &luactx->htxn, 0))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004447 return 0;
4448 lua_settable(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004449
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004450 /* Create the "sf" field that contains a list of stringsafe fetches. */
4451 lua_pushstring(L, "sf");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004452 if (!hlua_fetches_new(L, &luactx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004453 return 0;
4454 lua_settable(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004455
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004456 /* Create the "c" field that contains a list of converters. */
4457 lua_pushstring(L, "c");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004458 if (!hlua_converters_new(L, &luactx->htxn, 0))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004459 return 0;
4460 lua_settable(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004461
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004462 /* Create the "sc" field that contains a list of stringsafe converters. */
4463 lua_pushstring(L, "sc");
Willy Tarreau7e702d12021-04-28 17:59:21 +02004464 if (!hlua_converters_new(L, &luactx->htxn, HLUA_F_AS_STRING))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004465 return 0;
4466 lua_settable(L, -3);
Willy Tarreaueee5b512015-04-03 23:46:31 +02004467
Christopher Fauleta2097962019-07-15 16:25:33 +02004468 htx = htxbuf(&s->req.buf);
4469 blk = htx_get_first_blk(htx);
Christopher Fauletea009732019-11-18 15:50:25 +01004470 BUG_ON(!blk || htx_get_blk_type(blk) != HTX_BLK_REQ_SL);
Christopher Fauleta2097962019-07-15 16:25:33 +02004471 sl = htx_get_blk_ptr(htx, blk);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004472
Christopher Fauleta2097962019-07-15 16:25:33 +02004473 /* Stores the request method. */
4474 lua_pushstring(L, "method");
4475 lua_pushlstring(L, HTX_SL_REQ_MPTR(sl), HTX_SL_REQ_MLEN(sl));
4476 lua_settable(L, -3);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004477
Christopher Fauleta2097962019-07-15 16:25:33 +02004478 /* Stores the http version. */
4479 lua_pushstring(L, "version");
4480 lua_pushlstring(L, HTX_SL_REQ_VPTR(sl), HTX_SL_REQ_VLEN(sl));
4481 lua_settable(L, -3);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004482
Christopher Fauleta2097962019-07-15 16:25:33 +02004483 /* creates an array of headers. hlua_http_get_headers() crates and push
4484 * the array on the top of the stack.
4485 */
4486 lua_pushstring(L, "headers");
4487 htxn.s = s;
4488 htxn.p = px;
4489 htxn.dir = SMP_OPT_DIR_REQ;
Christopher Faulet9d1332b2020-02-24 16:46:16 +01004490 if (!hlua_http_get_headers(L, &htxn.s->txn->req))
Christopher Fauleta2097962019-07-15 16:25:33 +02004491 return 0;
4492 lua_settable(L, -3);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004493
Amaury Denoyellec453f952021-07-06 11:40:12 +02004494 parser = http_uri_parser_init(htx_sl_req_uri(sl));
4495 path = http_parse_path(&parser);
Tim Duesterhused526372020-03-05 17:56:33 +01004496 if (isttest(path)) {
Christopher Fauleta2097962019-07-15 16:25:33 +02004497 char *p, *q, *end;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004498
Christopher Fauleta2097962019-07-15 16:25:33 +02004499 p = path.ptr;
4500 end = path.ptr + path.len;
4501 q = p;
4502 while (q < end && *q != '?')
4503 q++;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004504
Thierry FOURNIER7d388632017-02-22 02:06:16 +01004505 /* Stores the request path. */
Christopher Fauleta2097962019-07-15 16:25:33 +02004506 lua_pushstring(L, "path");
4507 lua_pushlstring(L, p, q - p);
Thierry FOURNIER7d388632017-02-22 02:06:16 +01004508 lua_settable(L, -3);
Thierry FOURNIER04c57b32015-03-18 13:43:10 +01004509
Christopher Fauleta2097962019-07-15 16:25:33 +02004510 /* Stores the query string. */
4511 lua_pushstring(L, "qs");
4512 if (*q == '?')
4513 q++;
4514 lua_pushlstring(L, q, end - q);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004515 lua_settable(L, -3);
Christopher Fauleta2097962019-07-15 16:25:33 +02004516 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004517
Christopher Fauleta2097962019-07-15 16:25:33 +02004518 for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
4519 struct htx_blk *blk = htx_get_blk(htx, pos);
4520 enum htx_blk_type type = htx_get_blk_type(blk);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004521
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01004522 if (type == HTX_BLK_TLR || type == HTX_BLK_EOT)
Christopher Fauleta2097962019-07-15 16:25:33 +02004523 break;
4524 if (type == HTX_BLK_DATA)
4525 len += htx_get_blksz(blk);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004526 }
Christopher Fauleta2097962019-07-15 16:25:33 +02004527 if (htx->extra != ULLONG_MAX)
4528 len += htx->extra;
4529
4530 /* Stores the request path. */
4531 lua_pushstring(L, "length");
4532 lua_pushinteger(L, len);
4533 lua_settable(L, -3);
Thierry FOURNIER04c57b32015-03-18 13:43:10 +01004534
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004535 /* Create an empty array of HTTP request headers. */
4536 lua_pushstring(L, "response");
4537 lua_newtable(L);
4538 lua_settable(L, -3);
Thierry FOURNIER04c57b32015-03-18 13:43:10 +01004539
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004540 /* Pop a class stream metatable and affect it to the table. */
4541 lua_rawgeti(L, LUA_REGISTRYINDEX, class_applet_http_ref);
4542 lua_setmetatable(L, -2);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004543
4544 return 1;
4545}
4546
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004547__LJMP static int hlua_applet_http_set_var(lua_State *L)
4548{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004549 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004550 struct stream *s;
4551 const char *name;
4552 size_t len;
4553 struct sample smp;
4554
Tim Duesterhus4e172c92020-05-19 13:49:42 +02004555 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
4556 WILL_LJMP(luaL_error(L, "'set_var' needs between 3 and 4 arguments"));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004557
4558 /* It is useles to retrieve the stream, but this function
4559 * runs only in a stream context.
4560 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004561 luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004562 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004563 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004564
4565 /* Converts the third argument in a sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01004566 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004567 hlua_lua2smp(L, 3, &smp);
4568
4569 /* Store the sample in a variable. */
4570 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus4e172c92020-05-19 13:49:42 +02004571
4572 if (lua_gettop(L) == 4 && lua_toboolean(L, 4))
4573 lua_pushboolean(L, vars_set_by_name_ifexist(name, len, &smp) != 0);
4574 else
4575 lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
4576
Tim Duesterhus84ebc132020-05-19 13:49:41 +02004577 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004578}
4579
4580__LJMP static int hlua_applet_http_unset_var(lua_State *L)
4581{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004582 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004583 struct stream *s;
4584 const char *name;
4585 size_t len;
4586 struct sample smp;
4587
4588 MAY_LJMP(check_args(L, 2, "unset_var"));
4589
4590 /* It is useles to retrieve the stream, but this function
4591 * runs only in a stream context.
4592 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004593 luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004594 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004595 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004596
4597 /* Unset the variable. */
4598 smp_set_owner(&smp, s->be, s->sess, s, 0);
Tim Duesterhus84ebc132020-05-19 13:49:41 +02004599 lua_pushboolean(L, vars_unset_by_name_ifexist(name, len, &smp) != 0);
4600 return 1;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004601}
4602
4603__LJMP static int hlua_applet_http_get_var(lua_State *L)
4604{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004605 struct hlua_appctx *luactx;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004606 struct stream *s;
4607 const char *name;
4608 size_t len;
4609 struct sample smp;
4610
4611 MAY_LJMP(check_args(L, 2, "get_var"));
4612
4613 /* It is useles to retrieve the stream, but this function
4614 * runs only in a stream context.
4615 */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004616 luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004617 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Willy Tarreau7e702d12021-04-28 17:59:21 +02004618 s = luactx->htxn.s;
Thierry FOURNIER / OZON.IO4394a2c2016-12-12 12:31:54 +01004619
4620 smp_set_owner(&smp, s->be, s->sess, s, 0);
4621 if (!vars_get_by_name(name, len, &smp)) {
4622 lua_pushnil(L);
4623 return 1;
4624 }
4625
4626 return hlua_smp2lua(L, &smp);
4627}
4628
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004629__LJMP static int hlua_applet_http_set_priv(lua_State *L)
4630{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004631 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4632 struct stream *s = luactx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01004633 struct hlua *hlua;
4634
4635 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01004636 if (!s->hlua)
4637 return 0;
4638 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004639
4640 MAY_LJMP(check_args(L, 2, "set_priv"));
4641
4642 /* Remove previous value. */
Thierry FOURNIERe068b602017-04-26 13:27:05 +02004643 luaL_unref(L, LUA_REGISTRYINDEX, hlua->Mref);
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004644
4645 /* Get and store new value. */
4646 lua_pushvalue(L, 2); /* Copy the element 2 at the top of the stack. */
4647 hlua->Mref = luaL_ref(L, LUA_REGISTRYINDEX); /* pop the previously pushed value. */
4648
4649 return 0;
4650}
4651
4652__LJMP static int hlua_applet_http_get_priv(lua_State *L)
4653{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004654 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4655 struct stream *s = luactx->htxn.s;
Thierry FOURNIER3b0a6d42016-12-16 08:48:32 +01004656 struct hlua *hlua;
4657
4658 /* Note that this hlua struct is from the session and not from the applet. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01004659 if (!s->hlua) {
4660 lua_pushnil(L);
4661 return 1;
4662 }
4663 hlua = s->hlua;
Thierry FOURNIER8db004c2015-12-25 01:33:18 +01004664
4665 /* Push configuration index in the stack. */
4666 lua_rawgeti(L, LUA_REGISTRYINDEX, hlua->Mref);
4667
4668 return 1;
4669}
4670
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004671/* If expected data not yet available, it returns a yield. This function
4672 * consumes the data in the buffer. It returns a string containing the
4673 * data. This string can be empty.
4674 */
Christopher Fauleta2097962019-07-15 16:25:33 +02004675__LJMP static int hlua_applet_http_getline_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004676{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004677 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4678 struct stream_interface *si = luactx->appctx->owner;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004679 struct channel *req = si_oc(si);
4680 struct htx *htx;
4681 struct htx_blk *blk;
4682 size_t count;
4683 int stop = 0;
4684
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004685 htx = htx_from_buf(&req->buf);
4686 count = co_data(req);
Christopher Fauleta3f15502019-05-13 15:27:23 +02004687 blk = htx_get_first_blk(htx);
Christopher Fauletcc26b132018-12-18 21:20:57 +01004688
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004689 while (count && !stop && blk) {
4690 enum htx_blk_type type = htx_get_blk_type(blk);
4691 uint32_t sz = htx_get_blksz(blk);
4692 struct ist v;
4693 uint32_t vlen;
4694 char *nl;
4695
4696 vlen = sz;
4697 if (vlen > count) {
4698 if (type != HTX_BLK_DATA)
4699 break;
4700 vlen = count;
4701 }
4702
4703 switch (type) {
4704 case HTX_BLK_UNUSED:
4705 break;
4706
4707 case HTX_BLK_DATA:
4708 v = htx_get_blk_value(htx, blk);
4709 v.len = vlen;
4710 nl = istchr(v, '\n');
4711 if (nl != NULL) {
4712 stop = 1;
4713 vlen = nl - v.ptr + 1;
4714 }
Willy Tarreau7e702d12021-04-28 17:59:21 +02004715 luaL_addlstring(&luactx->b, v.ptr, vlen);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004716 break;
4717
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004718 case HTX_BLK_TLR:
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01004719 case HTX_BLK_EOT:
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004720 stop = 1;
4721 break;
4722
4723 default:
4724 break;
4725 }
4726
4727 co_set_data(req, co_data(req) - vlen);
4728 count -= vlen;
4729 if (sz == vlen)
4730 blk = htx_remove_blk(htx, blk);
4731 else {
4732 htx_cut_data_blk(htx, blk, vlen);
4733 break;
4734 }
4735 }
4736
Christopher Fauleteccb31c2021-04-02 14:24:56 +02004737 /* The message was fully consumed and no more data are expected
4738 * (EOM flag set).
4739 */
4740 if (htx_is_empty(htx) && (htx->flags & HTX_FL_EOM))
4741 stop = 1;
4742
Christopher Faulet0ae79d02019-02-27 21:36:59 +01004743 htx_to_buf(htx, &req->buf);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004744 if (!stop) {
4745 si_cant_get(si);
Christopher Fauleta2097962019-07-15 16:25:33 +02004746 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_getline_yield, TICK_ETERNITY, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004747 }
4748
4749 /* return the result. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004750 luaL_pushresult(&luactx->b);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004751 return 1;
4752}
4753
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004754
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004755/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004756__LJMP static int hlua_applet_http_getline(lua_State *L)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004757{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004758 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004759
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004760 /* Initialise the string catenation. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004761 luaL_buffinit(L, &luactx->b);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004762
Christopher Fauleta2097962019-07-15 16:25:33 +02004763 return MAY_LJMP(hlua_applet_http_getline_yield(L, 0, 0));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01004764}
4765
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004766/* If expected data not yet available, it returns a yield. This function
4767 * consumes the data in the buffer. It returns a string containing the
4768 * data. This string can be empty.
4769 */
Christopher Fauleta2097962019-07-15 16:25:33 +02004770__LJMP static int hlua_applet_http_recv_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004771{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004772 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4773 struct stream_interface *si = luactx->appctx->owner;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004774 struct channel *req = si_oc(si);
4775 struct htx *htx;
4776 struct htx_blk *blk;
4777 size_t count;
4778 int len;
4779
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004780 htx = htx_from_buf(&req->buf);
4781 len = MAY_LJMP(luaL_checkinteger(L, 2));
4782 count = co_data(req);
Christopher Faulet29f17582019-05-23 11:03:26 +02004783 blk = htx_get_head_blk(htx);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004784 while (count && len && blk) {
4785 enum htx_blk_type type = htx_get_blk_type(blk);
4786 uint32_t sz = htx_get_blksz(blk);
4787 struct ist v;
4788 uint32_t vlen;
4789
4790 vlen = sz;
4791 if (len > 0 && vlen > len)
4792 vlen = len;
4793 if (vlen > count) {
4794 if (type != HTX_BLK_DATA)
4795 break;
4796 vlen = count;
4797 }
4798
4799 switch (type) {
4800 case HTX_BLK_UNUSED:
4801 break;
4802
4803 case HTX_BLK_DATA:
4804 v = htx_get_blk_value(htx, blk);
Willy Tarreau7e702d12021-04-28 17:59:21 +02004805 luaL_addlstring(&luactx->b, v.ptr, vlen);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004806 break;
4807
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004808 case HTX_BLK_TLR:
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01004809 case HTX_BLK_EOT:
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004810 len = 0;
4811 break;
4812
4813 default:
4814 break;
4815 }
4816
4817 co_set_data(req, co_data(req) - vlen);
4818 count -= vlen;
4819 if (len > 0)
4820 len -= vlen;
4821 if (sz == vlen)
4822 blk = htx_remove_blk(htx, blk);
4823 else {
4824 htx_cut_data_blk(htx, blk, vlen);
4825 break;
4826 }
4827 }
4828
Christopher Fauleteccb31c2021-04-02 14:24:56 +02004829 /* The message was fully consumed and no more data are expected
4830 * (EOM flag set).
4831 */
4832 if (htx_is_empty(htx) && (htx->flags & HTX_FL_EOM))
4833 len = 0;
4834
Christopher Faulet0ae79d02019-02-27 21:36:59 +01004835 htx_to_buf(htx, &req->buf);
4836
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004837 /* If we are no other data available, yield waiting for new data. */
4838 if (len) {
4839 if (len > 0) {
4840 lua_pushinteger(L, len);
4841 lua_replace(L, 2);
4842 }
4843 si_cant_get(si);
Willy Tarreau9635e032018-10-16 17:52:55 +02004844 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_recv_yield, TICK_ETERNITY, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004845 }
4846
4847 /* return the result. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004848 luaL_pushresult(&luactx->b);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004849 return 1;
4850}
4851
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08004852/* Check arguments for the function "hlua_channel_get_yield". */
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004853__LJMP static int hlua_applet_http_recv(lua_State *L)
4854{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004855 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004856 int len = -1;
4857
4858 /* Check arguments. */
4859 if (lua_gettop(L) > 2)
4860 WILL_LJMP(luaL_error(L, "The 'recv' function requires between 1 and 2 arguments."));
4861 if (lua_gettop(L) >= 2) {
4862 len = MAY_LJMP(luaL_checkinteger(L, 2));
4863 lua_pop(L, 1);
4864 }
4865
Christopher Fauleta2097962019-07-15 16:25:33 +02004866 lua_pushinteger(L, len);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004867
Christopher Fauleta2097962019-07-15 16:25:33 +02004868 /* Initialise the string catenation. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004869 luaL_buffinit(L, &luactx->b);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004870
Christopher Fauleta2097962019-07-15 16:25:33 +02004871 return MAY_LJMP(hlua_applet_http_recv_yield(L, 0, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004872}
4873
4874/* Append data in the output side of the buffer. This data is immediately
4875 * sent. The function returns the amount of data written. If the buffer
4876 * cannot contain the data, the function yields. The function returns -1
4877 * if the channel is closed.
4878 */
Christopher Fauleta2097962019-07-15 16:25:33 +02004879__LJMP static int hlua_applet_http_send_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004880{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004881 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
4882 struct stream_interface *si = luactx->appctx->owner;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004883 struct channel *res = si_ic(si);
4884 struct htx *htx = htx_from_buf(&res->buf);
4885 const char *data;
4886 size_t len;
4887 int l = MAY_LJMP(luaL_checkinteger(L, 3));
4888 int max;
4889
Christopher Faulet9060fc02019-07-03 11:39:30 +02004890 max = htx_get_max_blksz(htx, channel_htx_recv_max(res, htx));
Christopher Faulet4b0e9b22019-01-09 12:16:58 +01004891 if (!max)
4892 goto snd_yield;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004893
4894 data = MAY_LJMP(luaL_checklstring(L, 2, &len));
4895
4896 /* Get the max amount of data which can write as input in the channel. */
4897 if (max > (len - l))
4898 max = len - l;
4899
4900 /* Copy data. */
Willy Tarreau0a7ef022019-05-28 10:30:11 +02004901 max = htx_add_data(htx, ist2(data + l, max));
Christopher Fauletf6cce3f2019-02-27 21:20:09 +01004902 channel_add_input(res, max);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004903
4904 /* update counters. */
4905 l += max;
4906 lua_pop(L, 1);
4907 lua_pushinteger(L, l);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004908
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004909 /* If some data is not send, declares the situation to the
4910 * applet, and returns a yield.
4911 */
4912 if (l < len) {
Christopher Faulet4b0e9b22019-01-09 12:16:58 +01004913 snd_yield:
Christopher Faulet0ae79d02019-02-27 21:36:59 +01004914 htx_to_buf(htx, &res->buf);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004915 si_rx_room_blk(si);
Willy Tarreau9635e032018-10-16 17:52:55 +02004916 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_send_yield, TICK_ETERNITY, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004917 }
4918
Christopher Fauleta2097962019-07-15 16:25:33 +02004919 htx_to_buf(htx, &res->buf);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004920 return 1;
4921}
4922
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05004923/* Just a wrapper of "hlua_applet_send_yield". This wrapper permits
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004924 * yield the LUA process, and resume it without checking the
4925 * input arguments.
4926 */
4927__LJMP static int hlua_applet_http_send(lua_State *L)
4928{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004929 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004930
4931 /* We want to send some data. Headers must be sent. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02004932 if (!(luactx->appctx->ctx.hlua_apphttp.flags & APPLET_HDR_SENT)) {
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004933 hlua_pusherror(L, "Lua: 'send' you must call start_response() before sending data.");
4934 WILL_LJMP(lua_error(L));
4935 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004936
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05004937 /* This integer is used for followinf the amount of data sent. */
Christopher Fauleta2097962019-07-15 16:25:33 +02004938 lua_pushinteger(L, 0);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01004939
Christopher Fauleta2097962019-07-15 16:25:33 +02004940 return MAY_LJMP(hlua_applet_http_send_yield(L, 0, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004941}
4942
4943__LJMP static int hlua_applet_http_addheader(lua_State *L)
4944{
4945 const char *name;
4946 int ret;
4947
4948 MAY_LJMP(hlua_checkapplet_http(L, 1));
4949 name = MAY_LJMP(luaL_checkstring(L, 2));
4950 MAY_LJMP(luaL_checkstring(L, 3));
4951
4952 /* Push in the stack the "response" entry. */
4953 ret = lua_getfield(L, 1, "response");
4954 if (ret != LUA_TTABLE) {
4955 hlua_pusherror(L, "Lua: 'add_header' internal error: AppletHTTP['response'] "
4956 "is expected as an array. %s found", lua_typename(L, ret));
4957 WILL_LJMP(lua_error(L));
4958 }
4959
4960 /* check if the header is already registered if it is not
4961 * the case, register it.
4962 */
4963 ret = lua_getfield(L, -1, name);
4964 if (ret == LUA_TNIL) {
4965
4966 /* Entry not found. */
4967 lua_pop(L, 1); /* remove the nil. The "response" table is the top of the stack. */
4968
4969 /* Insert the new header name in the array in the top of the stack.
4970 * It left the new array in the top of the stack.
4971 */
4972 lua_newtable(L);
4973 lua_pushvalue(L, 2);
4974 lua_pushvalue(L, -2);
4975 lua_settable(L, -4);
4976
4977 } else if (ret != LUA_TTABLE) {
4978
4979 /* corruption error. */
4980 hlua_pusherror(L, "Lua: 'add_header' internal error: AppletHTTP['response']['%s'] "
4981 "is expected as an array. %s found", name, lua_typename(L, ret));
4982 WILL_LJMP(lua_error(L));
4983 }
4984
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07004985 /* Now the top of thestack is an array of values. We push
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004986 * the header value as new entry.
4987 */
4988 lua_pushvalue(L, 3);
4989 ret = lua_rawlen(L, -2);
4990 lua_rawseti(L, -2, ret + 1);
4991 lua_pushboolean(L, 1);
4992 return 1;
4993}
4994
4995__LJMP static int hlua_applet_http_status(lua_State *L)
4996{
Willy Tarreau7e702d12021-04-28 17:59:21 +02004997 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02004998 int status = MAY_LJMP(luaL_checkinteger(L, 2));
Robin H. Johnson52f5db22017-01-01 13:10:52 -08004999 const char *reason = MAY_LJMP(luaL_optlstring(L, 3, NULL, NULL));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005000
5001 if (status < 100 || status > 599) {
5002 lua_pushboolean(L, 0);
5003 return 1;
5004 }
5005
Willy Tarreau7e702d12021-04-28 17:59:21 +02005006 luactx->appctx->ctx.hlua_apphttp.status = status;
5007 luactx->appctx->ctx.hlua_apphttp.reason = reason;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005008 lua_pushboolean(L, 1);
5009 return 1;
5010}
5011
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005012
Christopher Fauleta2097962019-07-15 16:25:33 +02005013__LJMP static int hlua_applet_http_send_response(lua_State *L)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005014{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005015 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
5016 struct stream_interface *si = luactx->appctx->owner;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005017 struct channel *res = si_ic(si);
5018 struct htx *htx;
5019 struct htx_sl *sl;
5020 struct h1m h1m;
5021 const char *status, *reason;
5022 const char *name, *value;
5023 size_t nlen, vlen;
5024 unsigned int flags;
5025
5026 /* Send the message at once. */
5027 htx = htx_from_buf(&res->buf);
5028 h1m_init_res(&h1m);
5029
5030 /* Use the same http version than the request. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02005031 status = ultoa_r(luactx->appctx->ctx.hlua_apphttp.status, trash.area, trash.size);
5032 reason = luactx->appctx->ctx.hlua_apphttp.reason;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005033 if (reason == NULL)
Willy Tarreau7e702d12021-04-28 17:59:21 +02005034 reason = http_get_reason(luactx->appctx->ctx.hlua_apphttp.status);
5035 if (luactx->appctx->ctx.hlua_apphttp.flags & APPLET_HTTP11) {
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005036 flags = (HTX_SL_F_IS_RESP|HTX_SL_F_VER_11);
5037 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.1"), ist(status), ist(reason));
5038 }
5039 else {
5040 flags = HTX_SL_F_IS_RESP;
5041 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.0"), ist(status), ist(reason));
5042 }
5043 if (!sl) {
5044 hlua_pusherror(L, "Lua applet http '%s': Failed to create response.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005045 luactx->appctx->rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005046 WILL_LJMP(lua_error(L));
5047 }
Willy Tarreau7e702d12021-04-28 17:59:21 +02005048 sl->info.res.status = luactx->appctx->ctx.hlua_apphttp.status;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005049
5050 /* Get the array associated to the field "response" in the object AppletHTTP. */
5051 lua_pushvalue(L, 0);
5052 if (lua_getfield(L, 1, "response") != LUA_TTABLE) {
5053 hlua_pusherror(L, "Lua applet http '%s': AppletHTTP['response'] missing.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005054 luactx->appctx->rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005055 WILL_LJMP(lua_error(L));
5056 }
5057
5058 /* Browse the list of headers. */
5059 lua_pushnil(L);
5060 while(lua_next(L, -2) != 0) {
5061 /* We expect a string as -2. */
5062 if (lua_type(L, -2) != LUA_TSTRING) {
5063 hlua_pusherror(L, "Lua applet http '%s': AppletHTTP['response'][] element must be a string. got %s.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005064 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005065 lua_typename(L, lua_type(L, -2)));
5066 WILL_LJMP(lua_error(L));
5067 }
5068 name = lua_tolstring(L, -2, &nlen);
5069
5070 /* We expect an array as -1. */
5071 if (lua_type(L, -1) != LUA_TTABLE) {
5072 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 +02005073 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005074 name,
5075 lua_typename(L, lua_type(L, -1)));
5076 WILL_LJMP(lua_error(L));
5077 }
5078
5079 /* Browse the table who is on the top of the stack. */
5080 lua_pushnil(L);
5081 while(lua_next(L, -2) != 0) {
5082 int id;
5083
5084 /* We expect a number as -2. */
5085 if (lua_type(L, -2) != LUA_TNUMBER) {
5086 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 +02005087 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005088 name,
5089 lua_typename(L, lua_type(L, -2)));
5090 WILL_LJMP(lua_error(L));
5091 }
5092 id = lua_tointeger(L, -2);
5093
5094 /* We expect a string as -2. */
5095 if (lua_type(L, -1) != LUA_TSTRING) {
5096 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 +02005097 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005098 name, id,
5099 lua_typename(L, lua_type(L, -1)));
5100 WILL_LJMP(lua_error(L));
5101 }
5102 value = lua_tolstring(L, -1, &vlen);
5103
5104 /* Simple Protocol checks. */
5105 if (isteqi(ist2(name, nlen), ist("transfer-encoding")))
Christopher Faulet700d9e82020-01-31 12:21:52 +01005106 h1_parse_xfer_enc_header(&h1m, ist2(value, vlen));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005107 else if (isteqi(ist2(name, nlen), ist("content-length"))) {
5108 struct ist v = ist2(value, vlen);
5109 int ret;
5110
5111 ret = h1_parse_cont_len_header(&h1m, &v);
5112 if (ret < 0) {
5113 hlua_pusherror(L, "Lua applet http '%s': Invalid '%s' header.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005114 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005115 name);
5116 WILL_LJMP(lua_error(L));
5117 }
5118 else if (ret == 0)
5119 goto next; /* Skip it */
5120 }
5121
5122 /* Add a new header */
5123 if (!htx_add_header(htx, ist2(name, nlen), ist2(value, vlen))) {
5124 hlua_pusherror(L, "Lua applet http '%s': Failed to add header '%s' in the response.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005125 luactx->appctx->rule->arg.hlua_rule->fcn->name,
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005126 name);
5127 WILL_LJMP(lua_error(L));
5128 }
5129 next:
5130 /* Remove the array from the stack, and get next element with a remaining string. */
5131 lua_pop(L, 1);
5132 }
5133
5134 /* Remove the array from the stack, and get next element with a remaining string. */
5135 lua_pop(L, 1);
5136 }
5137
5138 if (h1m.flags & H1_MF_CHNK)
5139 h1m.flags &= ~H1_MF_CLEN;
5140 if (h1m.flags & (H1_MF_CLEN|H1_MF_CHNK))
5141 h1m.flags |= H1_MF_XFER_LEN;
5142
5143 /* Uset HTX start-line flags */
5144 if (h1m.flags & H1_MF_XFER_ENC)
5145 flags |= HTX_SL_F_XFER_ENC;
5146 if (h1m.flags & H1_MF_XFER_LEN) {
5147 flags |= HTX_SL_F_XFER_LEN;
5148 if (h1m.flags & H1_MF_CHNK)
5149 flags |= HTX_SL_F_CHNK;
5150 else if (h1m.flags & H1_MF_CLEN)
5151 flags |= HTX_SL_F_CLEN;
5152 if (h1m.body_len == 0)
5153 flags |= HTX_SL_F_BODYLESS;
5154 }
5155 sl->flags |= flags;
5156
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07005157 /* If we don't have a content-length set, and the HTTP version is 1.1
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005158 * and the status code implies the presence of a message body, we must
5159 * announce a transfer encoding chunked. This is required by haproxy
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05005160 * for the keepalive compliance. If the applet announces a transfer-encoding
5161 * chunked itself, don't do anything.
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005162 */
5163 if ((flags & (HTX_SL_F_VER_11|HTX_SL_F_XFER_LEN)) == HTX_SL_F_VER_11 &&
Willy Tarreau7e702d12021-04-28 17:59:21 +02005164 luactx->appctx->ctx.hlua_apphttp.status >= 200 &&
5165 luactx->appctx->ctx.hlua_apphttp.status != 204 &&
5166 luactx->appctx->ctx.hlua_apphttp.status != 304) {
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005167 /* Add a new header */
5168 sl->flags |= (HTX_SL_F_XFER_ENC|H1_MF_CHNK|H1_MF_XFER_LEN);
5169 if (!htx_add_header(htx, ist("transfer-encoding"), ist("chunked"))) {
5170 hlua_pusherror(L, "Lua applet http '%s': Failed to add header 'transfer-encoding' in the response.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005171 luactx->appctx->rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005172 WILL_LJMP(lua_error(L));
5173 }
5174 }
5175
5176 /* Finalize headers. */
5177 if (!htx_add_endof(htx, HTX_BLK_EOH)) {
5178 hlua_pusherror(L, "Lua applet http '%s': Failed create the response.\n",
Willy Tarreau7e702d12021-04-28 17:59:21 +02005179 luactx->appctx->rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005180 WILL_LJMP(lua_error(L));
5181 }
5182
5183 if (htx_used_space(htx) > b_size(&res->buf) - global.tune.maxrewrite) {
5184 b_reset(&res->buf);
5185 hlua_pusherror(L, "Lua: 'start_response': response header block too big");
5186 WILL_LJMP(lua_error(L));
5187 }
5188
5189 htx_to_buf(htx, &res->buf);
Christopher Fauletf6cce3f2019-02-27 21:20:09 +01005190 channel_add_input(res, htx->data);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005191
5192 /* Headers sent, set the flag. */
Willy Tarreau7e702d12021-04-28 17:59:21 +02005193 luactx->appctx->ctx.hlua_apphttp.flags |= APPLET_HDR_SENT;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005194 return 0;
5195
5196}
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005197/* We will build the status line and the headers of the HTTP response.
5198 * We will try send at once if its not possible, we give back the hand
5199 * waiting for more room.
5200 */
Christopher Fauleta2097962019-07-15 16:25:33 +02005201__LJMP static int hlua_applet_http_start_response_yield(lua_State *L, int status, lua_KContext ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005202{
Willy Tarreau7e702d12021-04-28 17:59:21 +02005203 struct hlua_appctx *luactx = MAY_LJMP(hlua_checkapplet_http(L, 1));
5204 struct stream_interface *si = luactx->appctx->owner;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005205 struct channel *res = si_ic(si);
5206
5207 if (co_data(res)) {
5208 si_rx_room_blk(si);
Christopher Fauleta2097962019-07-15 16:25:33 +02005209 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_start_response_yield, TICK_ETERNITY, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005210 }
Christopher Fauleta2097962019-07-15 16:25:33 +02005211 return MAY_LJMP(hlua_applet_http_send_response(L));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005212}
5213
5214
Christopher Fauleta2097962019-07-15 16:25:33 +02005215__LJMP static int hlua_applet_http_start_response(lua_State *L)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005216{
Christopher Fauleta2097962019-07-15 16:25:33 +02005217 return MAY_LJMP(hlua_applet_http_start_response_yield(L, 0, 0));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005218}
5219
Christopher Fauleta2097962019-07-15 16:25:33 +02005220/*
5221 *
5222 *
5223 * Class HTTP
5224 *
5225 *
Christopher Faulet9c832fc2018-12-14 13:34:05 +01005226 */
Christopher Fauleta2097962019-07-15 16:25:33 +02005227
5228/* Returns a struct hlua_txn if the stack entry "ud" is
5229 * a class stream, otherwise it throws an error.
5230 */
5231__LJMP static struct hlua_txn *hlua_checkhttp(lua_State *L, int ud)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005232{
Christopher Fauleta2097962019-07-15 16:25:33 +02005233 return MAY_LJMP(hlua_checkudata(L, ud, class_http_ref));
5234}
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005235
Christopher Fauleta2097962019-07-15 16:25:33 +02005236/* This function creates and push in the stack a HTTP object
5237 * according with a current TXN.
5238 */
5239static int hlua_http_new(lua_State *L, struct hlua_txn *txn)
5240{
5241 struct hlua_txn *htxn;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005242
Christopher Fauleta2097962019-07-15 16:25:33 +02005243 /* Check stack size. */
5244 if (!lua_checkstack(L, 3))
5245 return 0;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005246
Christopher Fauleta2097962019-07-15 16:25:33 +02005247 /* Create the object: obj[0] = userdata.
5248 * Note that the base of the Converters object is the
5249 * same than the TXN object.
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005250 */
Christopher Fauleta2097962019-07-15 16:25:33 +02005251 lua_newtable(L);
5252 htxn = lua_newuserdata(L, sizeof(*htxn));
5253 lua_rawseti(L, -2, 0);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005254
5255 htxn->s = txn->s;
5256 htxn->p = txn->p;
Christopher Faulet256b69a2019-05-23 11:14:21 +02005257 htxn->dir = txn->dir;
5258 htxn->flags = txn->flags;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005259
5260 /* Pop a class stream metatable and affect it to the table. */
5261 lua_rawgeti(L, LUA_REGISTRYINDEX, class_http_ref);
5262 lua_setmetatable(L, -2);
5263
5264 return 1;
5265}
5266
5267/* This function creates ans returns an array of HTTP headers.
5268 * This function does not fails. It is used as wrapper with the
5269 * 2 following functions.
5270 */
Christopher Faulet9d1332b2020-02-24 16:46:16 +01005271__LJMP static int hlua_http_get_headers(lua_State *L, struct http_msg *msg)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005272{
Christopher Fauleta2097962019-07-15 16:25:33 +02005273 struct htx *htx;
5274 int32_t pos;
5275
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005276 /* Create the table. */
5277 lua_newtable(L);
5278
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005279
Christopher Fauleta2097962019-07-15 16:25:33 +02005280 htx = htxbuf(&msg->chn->buf);
5281 for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
5282 struct htx_blk *blk = htx_get_blk(htx, pos);
5283 enum htx_blk_type type = htx_get_blk_type(blk);
5284 struct ist n, v;
5285 int len;
Christopher Faulet724a12c2018-12-13 22:12:15 +01005286
Christopher Fauleta2097962019-07-15 16:25:33 +02005287 if (type == HTX_BLK_HDR) {
5288 n = htx_get_blk_name(htx,blk);
5289 v = htx_get_blk_value(htx, blk);
Christopher Faulet724a12c2018-12-13 22:12:15 +01005290 }
Christopher Fauleta2097962019-07-15 16:25:33 +02005291 else if (type == HTX_BLK_EOH)
5292 break;
5293 else
5294 continue;
Christopher Faulet724a12c2018-12-13 22:12:15 +01005295
Christopher Fauleta2097962019-07-15 16:25:33 +02005296 /* Check for existing entry:
5297 * assume that the table is on the top of the stack, and
5298 * push the key in the stack, the function lua_gettable()
5299 * perform the lookup.
5300 */
5301 lua_pushlstring(L, n.ptr, n.len);
5302 lua_gettable(L, -2);
Christopher Faulet724a12c2018-12-13 22:12:15 +01005303
Christopher Fauleta2097962019-07-15 16:25:33 +02005304 switch (lua_type(L, -1)) {
5305 case LUA_TNIL:
5306 /* Table not found, create it. */
5307 lua_pop(L, 1); /* remove the nil value. */
5308 lua_pushlstring(L, n.ptr, n.len); /* push the header name as key. */
5309 lua_newtable(L); /* create and push empty table. */
5310 lua_pushlstring(L, v.ptr, v.len); /* push header value. */
5311 lua_rawseti(L, -2, 0); /* index header value (pop it). */
5312 lua_rawset(L, -3); /* index new table with header name (pop the values). */
Christopher Faulet724a12c2018-12-13 22:12:15 +01005313 break;
Christopher Faulet724a12c2018-12-13 22:12:15 +01005314
Christopher Fauleta2097962019-07-15 16:25:33 +02005315 case LUA_TTABLE:
5316 /* Entry found: push the value in the table. */
5317 len = lua_rawlen(L, -1);
5318 lua_pushlstring(L, v.ptr, v.len); /* push header value. */
5319 lua_rawseti(L, -2, len+1); /* index header value (pop it). */
5320 lua_pop(L, 1); /* remove the table (it is stored in the main table). */
5321 break;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005322
Christopher Fauleta2097962019-07-15 16:25:33 +02005323 default:
5324 /* Other cases are errors. */
5325 hlua_pusherror(L, "internal error during the parsing of headers.");
5326 WILL_LJMP(lua_error(L));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005327 }
5328 }
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005329 return 1;
5330}
5331
5332__LJMP static int hlua_http_req_get_headers(lua_State *L)
5333{
5334 struct hlua_txn *htxn;
5335
5336 MAY_LJMP(check_args(L, 1, "req_get_headers"));
5337 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5338
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005339 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005340 WILL_LJMP(lua_error(L));
5341
Christopher Faulet9d1332b2020-02-24 16:46:16 +01005342 return hlua_http_get_headers(L, &htxn->s->txn->req);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005343}
5344
5345__LJMP static int hlua_http_res_get_headers(lua_State *L)
5346{
5347 struct hlua_txn *htxn;
5348
5349 MAY_LJMP(check_args(L, 1, "res_get_headers"));
5350 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5351
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005352 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005353 WILL_LJMP(lua_error(L));
5354
Christopher Faulet9d1332b2020-02-24 16:46:16 +01005355 return hlua_http_get_headers(L, &htxn->s->txn->rsp);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005356}
5357
5358/* This function replace full header, or just a value in
5359 * the request or in the response. It is a wrapper fir the
5360 * 4 following functions.
5361 */
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005362__LJMP static inline int hlua_http_rep_hdr(lua_State *L, struct http_msg *msg, int full)
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005363{
5364 size_t name_len;
5365 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
5366 const char *reg = MAY_LJMP(luaL_checkstring(L, 3));
5367 const char *value = MAY_LJMP(luaL_checkstring(L, 4));
Christopher Fauleta2097962019-07-15 16:25:33 +02005368 struct htx *htx;
Dragan Dosen26743032019-04-30 15:54:36 +02005369 struct my_regex *re;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005370
Dragan Dosen26743032019-04-30 15:54:36 +02005371 if (!(re = regex_comp(reg, 1, 1, NULL)))
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005372 WILL_LJMP(luaL_argerror(L, 3, "invalid regex"));
5373
Christopher Fauleta2097962019-07-15 16:25:33 +02005374 htx = htxbuf(&msg->chn->buf);
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005375 http_replace_hdrs(chn_strm(msg->chn), htx, ist2(name, name_len), value, re, full);
Dragan Dosen26743032019-04-30 15:54:36 +02005376 regex_free(re);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005377 return 0;
5378}
5379
5380__LJMP static int hlua_http_req_rep_hdr(lua_State *L)
5381{
5382 struct hlua_txn *htxn;
5383
5384 MAY_LJMP(check_args(L, 4, "req_rep_hdr"));
5385 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5386
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005387 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005388 WILL_LJMP(lua_error(L));
5389
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005390 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->req, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005391}
5392
5393__LJMP static int hlua_http_res_rep_hdr(lua_State *L)
5394{
5395 struct hlua_txn *htxn;
5396
5397 MAY_LJMP(check_args(L, 4, "res_rep_hdr"));
5398 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5399
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005400 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005401 WILL_LJMP(lua_error(L));
5402
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005403 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->rsp, 1));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005404}
5405
5406__LJMP static int hlua_http_req_rep_val(lua_State *L)
5407{
5408 struct hlua_txn *htxn;
5409
5410 MAY_LJMP(check_args(L, 4, "req_rep_hdr"));
5411 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5412
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005413 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005414 WILL_LJMP(lua_error(L));
5415
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005416 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->req, 0));
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02005417}
5418
5419__LJMP static int hlua_http_res_rep_val(lua_State *L)
5420{
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005421 struct hlua_txn *htxn;
5422
5423 MAY_LJMP(check_args(L, 4, "res_rep_val"));
5424 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5425
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005426 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005427 WILL_LJMP(lua_error(L));
5428
Christopher Fauletd1914aa2020-02-24 16:52:46 +01005429 return MAY_LJMP(hlua_http_rep_hdr(L, &htxn->s->txn->rsp, 0));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005430}
5431
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08005432/* This function deletes all the occurrences of an header.
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005433 * It is a wrapper for the 2 following functions.
5434 */
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005435__LJMP static inline int hlua_http_del_hdr(lua_State *L, struct http_msg *msg)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005436{
5437 size_t len;
5438 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &len));
Christopher Fauleta2097962019-07-15 16:25:33 +02005439 struct htx *htx = htxbuf(&msg->chn->buf);
5440 struct http_hdr_ctx ctx;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005441
Christopher Fauleta2097962019-07-15 16:25:33 +02005442 ctx.blk = NULL;
5443 while (http_find_header(htx, ist2(name, len), &ctx, 1))
5444 http_remove_header(htx, &ctx);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005445 return 0;
5446}
5447
5448__LJMP static int hlua_http_req_del_hdr(lua_State *L)
5449{
5450 struct hlua_txn *htxn;
5451
5452 MAY_LJMP(check_args(L, 2, "req_del_hdr"));
5453 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5454
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005455 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005456 WILL_LJMP(lua_error(L));
5457
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005458 return hlua_http_del_hdr(L, &htxn->s->txn->req);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005459}
5460
5461__LJMP static int hlua_http_res_del_hdr(lua_State *L)
5462{
5463 struct hlua_txn *htxn;
5464
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005465 MAY_LJMP(check_args(L, 2, "res_del_hdr"));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005466 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5467
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005468 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005469 WILL_LJMP(lua_error(L));
5470
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005471 return hlua_http_del_hdr(L, &htxn->s->txn->rsp);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005472}
5473
5474/* This function adds an header. It is a wrapper used by
5475 * the 2 following functions.
5476 */
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005477__LJMP static inline int hlua_http_add_hdr(lua_State *L, struct http_msg *msg)
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005478{
5479 size_t name_len;
5480 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
5481 size_t value_len;
5482 const char *value = MAY_LJMP(luaL_checklstring(L, 3, &value_len));
Christopher Fauleta2097962019-07-15 16:25:33 +02005483 struct htx *htx = htxbuf(&msg->chn->buf);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005484
Christopher Fauleta2097962019-07-15 16:25:33 +02005485 lua_pushboolean(L, http_add_header(htx, ist2(name, name_len),
5486 ist2(value, value_len)));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005487 return 0;
5488}
5489
5490__LJMP static int hlua_http_req_add_hdr(lua_State *L)
5491{
5492 struct hlua_txn *htxn;
5493
5494 MAY_LJMP(check_args(L, 3, "req_add_hdr"));
5495 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5496
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005497 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005498 WILL_LJMP(lua_error(L));
5499
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005500 return hlua_http_add_hdr(L, &htxn->s->txn->req);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005501}
5502
5503__LJMP static int hlua_http_res_add_hdr(lua_State *L)
5504{
5505 struct hlua_txn *htxn;
5506
5507 MAY_LJMP(check_args(L, 3, "res_add_hdr"));
5508 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5509
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005510 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005511 WILL_LJMP(lua_error(L));
5512
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005513 return hlua_http_add_hdr(L, &htxn->s->txn->rsp);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005514}
5515
5516static int hlua_http_req_set_hdr(lua_State *L)
5517{
5518 struct hlua_txn *htxn;
5519
5520 MAY_LJMP(check_args(L, 3, "req_set_hdr"));
5521 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5522
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005523 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005524 WILL_LJMP(lua_error(L));
5525
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005526 hlua_http_del_hdr(L, &htxn->s->txn->req);
5527 return hlua_http_add_hdr(L, &htxn->s->txn->req);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005528}
5529
5530static int hlua_http_res_set_hdr(lua_State *L)
5531{
5532 struct hlua_txn *htxn;
5533
5534 MAY_LJMP(check_args(L, 3, "res_set_hdr"));
5535 htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5536
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005537 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005538 WILL_LJMP(lua_error(L));
5539
Christopher Fauletd31c7b32020-02-25 09:37:57 +01005540 hlua_http_del_hdr(L, &htxn->s->txn->rsp);
5541 return hlua_http_add_hdr(L, &htxn->s->txn->rsp);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005542}
5543
5544/* This function set the method. */
5545static int hlua_http_req_set_meth(lua_State *L)
5546{
Willy Tarreaubcb39cc2015-04-06 11:21:44 +02005547 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005548 size_t name_len;
5549 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005550
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005551 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005552 WILL_LJMP(lua_error(L));
5553
Christopher Fauletfc9cfe42019-07-16 14:54:53 +02005554 lua_pushboolean(L, http_req_replace_stline(0, name, name_len, htxn->p, htxn->s) != -1);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005555 return 1;
5556}
5557
5558/* This function set the method. */
5559static int hlua_http_req_set_path(lua_State *L)
5560{
Willy Tarreaubcb39cc2015-04-06 11:21:44 +02005561 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005562 size_t name_len;
5563 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
Thierry FOURNIER / OZON.IOb84ae922016-08-02 23:44:58 +02005564
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005565 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005566 WILL_LJMP(lua_error(L));
5567
Christopher Fauletfc9cfe42019-07-16 14:54:53 +02005568 lua_pushboolean(L, http_req_replace_stline(1, name, name_len, htxn->p, htxn->s) != -1);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005569 return 1;
5570}
5571
5572/* This function set the query-string. */
5573static int hlua_http_req_set_query(lua_State *L)
5574{
Willy Tarreaubcb39cc2015-04-06 11:21:44 +02005575 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005576 size_t name_len;
5577 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005578
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005579 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005580 WILL_LJMP(lua_error(L));
5581
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005582 /* Check length. */
5583 if (name_len > trash.size - 1) {
5584 lua_pushboolean(L, 0);
5585 return 1;
5586 }
5587
5588 /* Add the mark question as prefix. */
5589 chunk_reset(&trash);
Willy Tarreau843b7cb2018-07-13 10:54:26 +02005590 trash.area[trash.data++] = '?';
5591 memcpy(trash.area + trash.data, name, name_len);
5592 trash.data += name_len;
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005593
Willy Tarreau843b7cb2018-07-13 10:54:26 +02005594 lua_pushboolean(L,
Christopher Fauletfc9cfe42019-07-16 14:54:53 +02005595 http_req_replace_stline(2, trash.area, trash.data, htxn->p, htxn->s) != -1);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005596 return 1;
5597}
5598
5599/* This function set the uri. */
5600static int hlua_http_req_set_uri(lua_State *L)
5601{
Willy Tarreaubcb39cc2015-04-06 11:21:44 +02005602 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005603 size_t name_len;
5604 const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005605
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005606 if (htxn->dir != SMP_OPT_DIR_REQ || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005607 WILL_LJMP(lua_error(L));
5608
Christopher Fauletfc9cfe42019-07-16 14:54:53 +02005609 lua_pushboolean(L, http_req_replace_stline(3, name, name_len, htxn->p, htxn->s) != -1);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005610 return 1;
5611}
5612
Robin H. Johnson52f5db22017-01-01 13:10:52 -08005613/* This function set the response code & optionally reason. */
Thierry FOURNIER35d70ef2015-08-26 16:21:56 +02005614static int hlua_http_res_set_status(lua_State *L)
5615{
5616 struct hlua_txn *htxn = MAY_LJMP(hlua_checkhttp(L, 1));
5617 unsigned int code = MAY_LJMP(luaL_checkinteger(L, 2));
Christopher Faulet96bff762019-12-17 13:46:18 +01005618 const char *str = MAY_LJMP(luaL_optlstring(L, 3, NULL, NULL));
5619 const struct ist reason = ist2(str, (str ? strlen(str) : 0));
Thierry FOURNIER35d70ef2015-08-26 16:21:56 +02005620
Christopher Fauletd8f0e072020-02-25 09:45:51 +01005621 if (htxn->dir != SMP_OPT_DIR_RES || !IS_HTX_STRM(htxn->s))
Christopher Faulet84a6d5b2019-07-26 16:17:01 +02005622 WILL_LJMP(lua_error(L));
5623
Christopher Fauletfc9cfe42019-07-16 14:54:53 +02005624 http_res_set_status(code, reason, htxn->s);
Thierry FOURNIER35d70ef2015-08-26 16:21:56 +02005625 return 0;
5626}
5627
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005628/*
5629 *
5630 *
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005631 * Class TXN
5632 *
5633 *
5634 */
5635
5636/* Returns a struct hlua_session if the stack entry "ud" is
Willy Tarreau87b09662015-04-03 00:22:06 +02005637 * a class stream, otherwise it throws an error.
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005638 */
5639__LJMP static struct hlua_txn *hlua_checktxn(lua_State *L, int ud)
5640{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02005641 return MAY_LJMP(hlua_checkudata(L, ud, class_txn_ref));
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005642}
5643
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02005644__LJMP static int hlua_set_var(lua_State *L)
5645{
5646 struct hlua_txn *htxn;
5647 const char *name;
5648 size_t len;
5649 struct sample smp;
5650
Tim Duesterhus4e172c92020-05-19 13:49:42 +02005651 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
5652 WILL_LJMP(luaL_error(L, "'set_var' needs between 3 and 4 arguments"));
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02005653
5654 /* It is useles to retrieve the stream, but this function
5655 * runs only in a stream context.
5656 */
5657 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5658 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
5659
5660 /* Converts the third argument in a sample. */
Amaury Denoyellebc0af6a2020-10-29 17:21:20 +01005661 memset(&smp, 0, sizeof(smp));
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02005662 hlua_lua2smp(L, 3, &smp);
5663
5664 /* Store the sample in a variable. */
Willy Tarreau7560dd42016-03-10 16:28:58 +01005665 smp_set_owner(&smp, htxn->p, htxn->s->sess, htxn->s, htxn->dir & SMP_OPT_DIR);
Tim Duesterhus4e172c92020-05-19 13:49:42 +02005666
5667 if (lua_gettop(L) == 4 && lua_toboolean(L, 4))
5668 lua_pushboolean(L, vars_set_by_name_ifexist(name, len, &smp) != 0);
5669 else
5670 lua_pushboolean(L, vars_set_by_name(name, len, &smp) != 0);
5671
Tim Duesterhus84ebc132020-05-19 13:49:41 +02005672 return 1;
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02005673}
5674
Christopher Faulet85d79c92016-11-09 16:54:56 +01005675__LJMP static int hlua_unset_var(lua_State *L)
5676{
5677 struct hlua_txn *htxn;
5678 const char *name;
5679 size_t len;
5680 struct sample smp;
5681
5682 MAY_LJMP(check_args(L, 2, "unset_var"));
5683
5684 /* It is useles to retrieve the stream, but this function
5685 * runs only in a stream context.
5686 */
5687 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5688 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
5689
5690 /* Unset the variable. */
5691 smp_set_owner(&smp, htxn->p, htxn->s->sess, htxn->s, htxn->dir & SMP_OPT_DIR);
Tim Duesterhus84ebc132020-05-19 13:49:41 +02005692 lua_pushboolean(L, vars_unset_by_name_ifexist(name, len, &smp) != 0);
5693 return 1;
Christopher Faulet85d79c92016-11-09 16:54:56 +01005694}
5695
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02005696__LJMP static int hlua_get_var(lua_State *L)
5697{
5698 struct hlua_txn *htxn;
5699 const char *name;
5700 size_t len;
5701 struct sample smp;
5702
5703 MAY_LJMP(check_args(L, 2, "get_var"));
5704
5705 /* It is useles to retrieve the stream, but this function
5706 * runs only in a stream context.
5707 */
5708 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5709 name = MAY_LJMP(luaL_checklstring(L, 2, &len));
5710
Willy Tarreau7560dd42016-03-10 16:28:58 +01005711 smp_set_owner(&smp, htxn->p, htxn->s->sess, htxn->s, htxn->dir & SMP_OPT_DIR);
Willy Tarreau6204cd92016-03-10 16:33:04 +01005712 if (!vars_get_by_name(name, len, &smp)) {
Thierry FOURNIER053ba8ad2015-06-08 13:05:33 +02005713 lua_pushnil(L);
5714 return 1;
5715 }
5716
5717 return hlua_smp2lua(L, &smp);
5718}
5719
Willy Tarreau59551662015-03-10 14:23:13 +01005720__LJMP static int hlua_set_priv(lua_State *L)
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005721{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01005722 struct hlua *hlua;
5723
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005724 MAY_LJMP(check_args(L, 2, "set_priv"));
5725
Willy Tarreau87b09662015-04-03 00:22:06 +02005726 /* It is useles to retrieve the stream, but this function
5727 * runs only in a stream context.
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005728 */
5729 MAY_LJMP(hlua_checktxn(L, 1));
Thierry Fournier4234dbd2020-11-28 13:18:23 +01005730
5731 /* Get hlua struct, or NULL if we execute from main lua state */
Willy Tarreau80f5fae2015-02-27 16:38:20 +01005732 hlua = hlua_gethlua(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01005733 if (!hlua)
5734 return 0;
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005735
5736 /* Remove previous value. */
Thierry FOURNIERe068b602017-04-26 13:27:05 +02005737 luaL_unref(L, LUA_REGISTRYINDEX, hlua->Mref);
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005738
5739 /* Get and store new value. */
5740 lua_pushvalue(L, 2); /* Copy the element 2 at the top of the stack. */
5741 hlua->Mref = luaL_ref(L, LUA_REGISTRYINDEX); /* pop the previously pushed value. */
5742
5743 return 0;
5744}
5745
Willy Tarreau59551662015-03-10 14:23:13 +01005746__LJMP static int hlua_get_priv(lua_State *L)
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005747{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01005748 struct hlua *hlua;
5749
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005750 MAY_LJMP(check_args(L, 1, "get_priv"));
5751
Willy Tarreau87b09662015-04-03 00:22:06 +02005752 /* It is useles to retrieve the stream, but this function
5753 * runs only in a stream context.
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005754 */
5755 MAY_LJMP(hlua_checktxn(L, 1));
Thierry Fournier4234dbd2020-11-28 13:18:23 +01005756
5757 /* Get hlua struct, or NULL if we execute from main lua state */
Willy Tarreau80f5fae2015-02-27 16:38:20 +01005758 hlua = hlua_gethlua(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01005759 if (!hlua) {
5760 lua_pushnil(L);
5761 return 1;
5762 }
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01005763
5764 /* Push configuration index in the stack. */
5765 lua_rawgeti(L, LUA_REGISTRYINDEX, hlua->Mref);
5766
5767 return 1;
5768}
5769
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005770/* Create stack entry containing a class TXN. This function
5771 * return 0 if the stack does not contains free slots,
5772 * otherwise it returns 1.
5773 */
Thierry FOURNIERab00df62016-07-14 11:42:37 +02005774static int hlua_txn_new(lua_State *L, struct stream *s, struct proxy *p, int dir, int flags)
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005775{
Willy Tarreaude491382015-04-06 11:04:28 +02005776 struct hlua_txn *htxn;
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005777
5778 /* Check stack size. */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01005779 if (!lua_checkstack(L, 3))
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005780 return 0;
5781
5782 /* NOTE: The allocation never fails. The failure
5783 * throw an error, and the function never returns.
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08005784 * if the throw is not available, the process is aborted.
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005785 */
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01005786 /* Create the object: obj[0] = userdata. */
5787 lua_newtable(L);
Willy Tarreaude491382015-04-06 11:04:28 +02005788 htxn = lua_newuserdata(L, sizeof(*htxn));
Thierry FOURNIER2297bc22015-03-11 17:43:33 +01005789 lua_rawseti(L, -2, 0);
5790
Willy Tarreaude491382015-04-06 11:04:28 +02005791 htxn->s = s;
5792 htxn->p = p;
Thierry FOURNIERc4eebc82015-11-02 10:01:59 +01005793 htxn->dir = dir;
Thierry FOURNIERab00df62016-07-14 11:42:37 +02005794 htxn->flags = flags;
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005795
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01005796 /* Create the "f" field that contains a list of fetches. */
5797 lua_pushstring(L, "f");
Thierry FOURNIERca988662015-12-20 18:43:03 +01005798 if (!hlua_fetches_new(L, htxn, HLUA_F_MAY_USE_HTTP))
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01005799 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02005800 lua_rawset(L, -3);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01005801
5802 /* Create the "sf" field that contains a list of stringsafe fetches. */
5803 lua_pushstring(L, "sf");
Thierry FOURNIERca988662015-12-20 18:43:03 +01005804 if (!hlua_fetches_new(L, htxn, HLUA_F_MAY_USE_HTTP | HLUA_F_AS_STRING))
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01005805 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02005806 lua_rawset(L, -3);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01005807
Thierry FOURNIER594afe72015-03-10 23:58:30 +01005808 /* Create the "c" field that contains a list of converters. */
5809 lua_pushstring(L, "c");
Willy Tarreaude491382015-04-06 11:04:28 +02005810 if (!hlua_converters_new(L, htxn, 0))
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01005811 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02005812 lua_rawset(L, -3);
Thierry FOURNIER2694a1a2015-03-11 20:13:36 +01005813
5814 /* Create the "sc" field that contains a list of stringsafe converters. */
5815 lua_pushstring(L, "sc");
Thierry FOURNIER7fa05492015-12-20 18:42:25 +01005816 if (!hlua_converters_new(L, htxn, HLUA_F_AS_STRING))
Thierry FOURNIER594afe72015-03-10 23:58:30 +01005817 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02005818 lua_rawset(L, -3);
Thierry FOURNIER594afe72015-03-10 23:58:30 +01005819
Thierry FOURNIER397826a2015-03-11 19:39:09 +01005820 /* Create the "req" field that contains the request channel object. */
5821 lua_pushstring(L, "req");
Willy Tarreau2a71af42015-03-10 13:51:50 +01005822 if (!hlua_channel_new(L, &s->req))
Thierry FOURNIER397826a2015-03-11 19:39:09 +01005823 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02005824 lua_rawset(L, -3);
Thierry FOURNIER397826a2015-03-11 19:39:09 +01005825
5826 /* Create the "res" field that contains the response channel object. */
5827 lua_pushstring(L, "res");
Willy Tarreau2a71af42015-03-10 13:51:50 +01005828 if (!hlua_channel_new(L, &s->res))
Thierry FOURNIER397826a2015-03-11 19:39:09 +01005829 return 0;
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02005830 lua_rawset(L, -3);
Thierry FOURNIER397826a2015-03-11 19:39:09 +01005831
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005832 /* Creates the HTTP object is the current proxy allows http. */
5833 lua_pushstring(L, "http");
Christopher Faulet1bb6afa2021-03-08 17:57:53 +01005834 if (IS_HTX_STRM(s)) {
Willy Tarreaude491382015-04-06 11:04:28 +02005835 if (!hlua_http_new(L, htxn))
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005836 return 0;
5837 }
5838 else
5839 lua_pushnil(L);
Thierry FOURNIER84e73c82015-09-25 22:13:32 +02005840 lua_rawset(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01005841
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01005842 /* Pop a class sesison metatable and affect it to the userdata. */
5843 lua_rawgeti(L, LUA_REGISTRYINDEX, class_txn_ref);
5844 lua_setmetatable(L, -2);
5845
5846 return 1;
5847}
5848
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01005849__LJMP static int hlua_txn_deflog(lua_State *L)
5850{
5851 const char *msg;
5852 struct hlua_txn *htxn;
5853
5854 MAY_LJMP(check_args(L, 2, "deflog"));
5855 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5856 msg = MAY_LJMP(luaL_checkstring(L, 2));
5857
5858 hlua_sendlog(htxn->s->be, htxn->s->logs.level, msg);
5859 return 0;
5860}
5861
5862__LJMP static int hlua_txn_log(lua_State *L)
5863{
5864 int level;
5865 const char *msg;
5866 struct hlua_txn *htxn;
5867
5868 MAY_LJMP(check_args(L, 3, "log"));
5869 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5870 level = MAY_LJMP(luaL_checkinteger(L, 2));
5871 msg = MAY_LJMP(luaL_checkstring(L, 3));
5872
5873 if (level < 0 || level >= NB_LOG_LEVELS)
5874 WILL_LJMP(luaL_argerror(L, 1, "Invalid loglevel."));
5875
5876 hlua_sendlog(htxn->s->be, level, msg);
5877 return 0;
5878}
5879
5880__LJMP static int hlua_txn_log_debug(lua_State *L)
5881{
5882 const char *msg;
5883 struct hlua_txn *htxn;
5884
5885 MAY_LJMP(check_args(L, 2, "Debug"));
5886 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5887 msg = MAY_LJMP(luaL_checkstring(L, 2));
5888 hlua_sendlog(htxn->s->be, LOG_DEBUG, msg);
5889 return 0;
5890}
5891
5892__LJMP static int hlua_txn_log_info(lua_State *L)
5893{
5894 const char *msg;
5895 struct hlua_txn *htxn;
5896
5897 MAY_LJMP(check_args(L, 2, "Info"));
5898 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5899 msg = MAY_LJMP(luaL_checkstring(L, 2));
5900 hlua_sendlog(htxn->s->be, LOG_INFO, msg);
5901 return 0;
5902}
5903
5904__LJMP static int hlua_txn_log_warning(lua_State *L)
5905{
5906 const char *msg;
5907 struct hlua_txn *htxn;
5908
5909 MAY_LJMP(check_args(L, 2, "Warning"));
5910 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5911 msg = MAY_LJMP(luaL_checkstring(L, 2));
5912 hlua_sendlog(htxn->s->be, LOG_WARNING, msg);
5913 return 0;
5914}
5915
5916__LJMP static int hlua_txn_log_alert(lua_State *L)
5917{
5918 const char *msg;
5919 struct hlua_txn *htxn;
5920
5921 MAY_LJMP(check_args(L, 2, "Alert"));
5922 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5923 msg = MAY_LJMP(luaL_checkstring(L, 2));
5924 hlua_sendlog(htxn->s->be, LOG_ALERT, msg);
5925 return 0;
5926}
5927
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01005928__LJMP static int hlua_txn_set_loglevel(lua_State *L)
5929{
5930 struct hlua_txn *htxn;
5931 int ll;
5932
5933 MAY_LJMP(check_args(L, 2, "set_loglevel"));
5934 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5935 ll = MAY_LJMP(luaL_checkinteger(L, 2));
5936
5937 if (ll < 0 || ll > 7)
5938 WILL_LJMP(luaL_argerror(L, 2, "Bad log level. It must be between 0 and 7"));
5939
5940 htxn->s->logs.level = ll;
5941 return 0;
5942}
5943
5944__LJMP static int hlua_txn_set_tos(lua_State *L)
5945{
5946 struct hlua_txn *htxn;
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01005947 int tos;
5948
5949 MAY_LJMP(check_args(L, 2, "set_tos"));
5950 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5951 tos = MAY_LJMP(luaL_checkinteger(L, 2));
5952
Willy Tarreau1a18b542018-12-11 16:37:42 +01005953 conn_set_tos(objt_conn(htxn->s->sess->origin), tos);
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01005954 return 0;
5955}
5956
5957__LJMP static int hlua_txn_set_mark(lua_State *L)
5958{
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01005959 struct hlua_txn *htxn;
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01005960 int mark;
5961
5962 MAY_LJMP(check_args(L, 2, "set_mark"));
5963 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5964 mark = MAY_LJMP(luaL_checkinteger(L, 2));
5965
Lukas Tribus579e3e32019-08-11 18:03:45 +02005966 conn_set_mark(objt_conn(htxn->s->sess->origin), mark);
Thierry FOURNIER2cce3532015-03-16 12:04:16 +01005967 return 0;
5968}
5969
Patrick Hemmer268a7072018-05-11 12:52:31 -04005970__LJMP static int hlua_txn_set_priority_class(lua_State *L)
5971{
5972 struct hlua_txn *htxn;
5973
5974 MAY_LJMP(check_args(L, 2, "set_priority_class"));
5975 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5976 htxn->s->priority_class = queue_limit_class(MAY_LJMP(luaL_checkinteger(L, 2)));
5977 return 0;
5978}
5979
5980__LJMP static int hlua_txn_set_priority_offset(lua_State *L)
5981{
5982 struct hlua_txn *htxn;
5983
5984 MAY_LJMP(check_args(L, 2, "set_priority_offset"));
5985 htxn = MAY_LJMP(hlua_checktxn(L, 1));
5986 htxn->s->priority_offset = queue_limit_offset(MAY_LJMP(luaL_checkinteger(L, 2)));
5987 return 0;
5988}
5989
Christopher Faulet700d9e82020-01-31 12:21:52 +01005990/* Forward the Reply object to the client. This function converts the reply in
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05005991 * HTX an push it to into the response channel. It is response to forward the
Christopher Faulet700d9e82020-01-31 12:21:52 +01005992 * message and terminate the transaction. It returns 1 on success and 0 on
5993 * error. The Reply must be on top of the stack.
5994 */
5995__LJMP static int hlua_txn_forward_reply(lua_State *L, struct stream *s)
5996{
5997 struct htx *htx;
5998 struct htx_sl *sl;
5999 struct h1m h1m;
6000 const char *status, *reason, *body;
6001 size_t status_len, reason_len, body_len;
6002 int ret, code, flags;
6003
6004 code = 200;
6005 status = "200";
6006 status_len = 3;
6007 ret = lua_getfield(L, -1, "status");
6008 if (ret == LUA_TNUMBER) {
6009 code = lua_tointeger(L, -1);
6010 status = lua_tolstring(L, -1, &status_len);
6011 }
6012 lua_pop(L, 1);
6013
6014 reason = http_get_reason(code);
6015 reason_len = strlen(reason);
6016 ret = lua_getfield(L, -1, "reason");
6017 if (ret == LUA_TSTRING)
6018 reason = lua_tolstring(L, -1, &reason_len);
6019 lua_pop(L, 1);
6020
6021 body = NULL;
6022 body_len = 0;
6023 ret = lua_getfield(L, -1, "body");
6024 if (ret == LUA_TSTRING)
6025 body = lua_tolstring(L, -1, &body_len);
6026 lua_pop(L, 1);
6027
6028 /* Prepare the response before inserting the headers */
6029 h1m_init_res(&h1m);
6030 htx = htx_from_buf(&s->res.buf);
6031 channel_htx_truncate(&s->res, htx);
6032 if (s->txn->req.flags & HTTP_MSGF_VER_11) {
6033 flags = (HTX_SL_F_IS_RESP|HTX_SL_F_VER_11);
6034 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.1"),
6035 ist2(status, status_len), ist2(reason, reason_len));
6036 }
6037 else {
6038 flags = HTX_SL_F_IS_RESP;
6039 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.0"),
6040 ist2(status, status_len), ist2(reason, reason_len));
6041 }
6042 if (!sl)
6043 goto fail;
6044 sl->info.res.status = code;
6045
6046 /* Push in the stack the "headers" entry. */
6047 ret = lua_getfield(L, -1, "headers");
6048 if (ret != LUA_TTABLE)
6049 goto skip_headers;
6050
6051 lua_pushnil(L);
6052 while (lua_next(L, -2) != 0) {
6053 struct ist name, value;
6054 const char *n, *v;
6055 size_t nlen, vlen;
6056
6057 if (!lua_isstring(L, -2) || !lua_istable(L, -1)) {
6058 /* Skip element if the key is not a string or if the value is not a table */
6059 goto next_hdr;
6060 }
6061
6062 n = lua_tolstring(L, -2, &nlen);
6063 name = ist2(n, nlen);
6064 if (isteqi(name, ist("content-length"))) {
6065 /* Always skip content-length header. It will be added
6066 * later with the correct len
6067 */
6068 goto next_hdr;
6069 }
6070
6071 /* Loop on header's values */
6072 lua_pushnil(L);
6073 while (lua_next(L, -2)) {
6074 if (!lua_isstring(L, -1)) {
6075 /* Skip the value if it is not a string */
6076 goto next_value;
6077 }
6078
6079 v = lua_tolstring(L, -1, &vlen);
6080 value = ist2(v, vlen);
6081
6082 if (isteqi(name, ist("transfer-encoding")))
6083 h1_parse_xfer_enc_header(&h1m, value);
6084 if (!htx_add_header(htx, ist2(n, nlen), ist2(v, vlen)))
6085 goto fail;
6086
6087 next_value:
6088 lua_pop(L, 1);
6089 }
6090
6091 next_hdr:
6092 lua_pop(L, 1);
6093 }
6094 skip_headers:
6095 lua_pop(L, 1);
6096
6097 /* Update h1m flags: CLEN is set if CHNK is not present */
6098 if (!(h1m.flags & H1_MF_CHNK)) {
6099 const char *clen = ultoa(body_len);
6100
6101 h1m.flags |= H1_MF_CLEN;
6102 if (!htx_add_header(htx, ist("content-length"), ist(clen)))
6103 goto fail;
6104 }
6105 if (h1m.flags & (H1_MF_CLEN|H1_MF_CHNK))
6106 h1m.flags |= H1_MF_XFER_LEN;
6107
6108 /* Update HTX start-line flags */
6109 if (h1m.flags & H1_MF_XFER_ENC)
6110 flags |= HTX_SL_F_XFER_ENC;
6111 if (h1m.flags & H1_MF_XFER_LEN) {
6112 flags |= HTX_SL_F_XFER_LEN;
6113 if (h1m.flags & H1_MF_CHNK)
6114 flags |= HTX_SL_F_CHNK;
6115 else if (h1m.flags & H1_MF_CLEN)
6116 flags |= HTX_SL_F_CLEN;
6117 if (h1m.body_len == 0)
6118 flags |= HTX_SL_F_BODYLESS;
6119 }
6120 sl->flags |= flags;
6121
6122
6123 if (!htx_add_endof(htx, HTX_BLK_EOH) ||
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01006124 (body_len && !htx_add_data_atonce(htx, ist2(body, body_len))))
Christopher Faulet700d9e82020-01-31 12:21:52 +01006125 goto fail;
6126
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01006127 htx->flags |= HTX_FL_EOM;
6128
Christopher Faulet700d9e82020-01-31 12:21:52 +01006129 /* Now, forward the response and terminate the transaction */
6130 s->txn->status = code;
6131 htx_to_buf(htx, &s->res.buf);
6132 if (!http_forward_proxy_resp(s, 1))
6133 goto fail;
6134
6135 return 1;
6136
6137 fail:
6138 channel_htx_truncate(&s->res, htx);
6139 return 0;
6140}
6141
6142/* Terminate a transaction if called from a lua action. For TCP streams,
6143 * processing is just aborted. Nothing is returned to the client and all
6144 * arguments are ignored. For HTTP streams, if a reply is passed as argument, it
6145 * is forwarded to the client before terminating the transaction. On success,
6146 * the function exits with ACT_RET_DONE code. If an error occurred, it exits
6147 * with ACT_RET_ERR code. If this function is not called from a lua action, it
6148 * just exits without any processing.
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01006149 */
Thierry FOURNIER4bb375c2015-08-26 08:42:21 +02006150__LJMP static int hlua_txn_done(lua_State *L)
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01006151{
Willy Tarreaub2ccb562015-04-06 11:11:15 +02006152 struct hlua_txn *htxn;
Christopher Faulet700d9e82020-01-31 12:21:52 +01006153 struct stream *s;
6154 int finst;
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01006155
Willy Tarreaub2ccb562015-04-06 11:11:15 +02006156 htxn = MAY_LJMP(hlua_checktxn(L, 1));
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01006157
Christopher Faulet700d9e82020-01-31 12:21:52 +01006158 /* If the flags NOTERM is set, we cannot terminate the session, so we
6159 * just end the execution of the current lua code. */
6160 if (htxn->flags & HLUA_TXN_NOTERM)
Thierry FOURNIERab00df62016-07-14 11:42:37 +02006161 WILL_LJMP(hlua_done(L));
Thierry FOURNIERab00df62016-07-14 11:42:37 +02006162
Christopher Faulet700d9e82020-01-31 12:21:52 +01006163 s = htxn->s;
Christopher Fauletd8f0e072020-02-25 09:45:51 +01006164 if (!IS_HTX_STRM(htxn->s)) {
Christopher Faulet700d9e82020-01-31 12:21:52 +01006165 struct channel *req = &s->req;
6166 struct channel *res = &s->res;
Willy Tarreau81389672015-03-10 12:03:52 +01006167
Christopher Faulet700d9e82020-01-31 12:21:52 +01006168 channel_auto_read(req);
6169 channel_abort(req);
6170 channel_auto_close(req);
6171 channel_erase(req);
6172
6173 res->wex = tick_add_ifset(now_ms, res->wto);
6174 channel_auto_read(res);
6175 channel_auto_close(res);
6176 channel_shutr_now(res);
6177
6178 finst = ((htxn->dir == SMP_OPT_DIR_REQ) ? SF_FINST_R : SF_FINST_D);
6179 goto done;
Christopher Fauletfe6a71b2019-07-26 16:40:24 +02006180 }
Thierry FOURNIER10ec2142015-08-24 17:23:45 +02006181
Christopher Faulet700d9e82020-01-31 12:21:52 +01006182 if (lua_gettop(L) == 1 || !lua_istable(L, 2)) {
6183 /* No reply or invalid reply */
6184 s->txn->status = 0;
6185 http_reply_and_close(s, 0, NULL);
6186 }
6187 else {
6188 /* Remove extra args to have the reply on top of the stack */
6189 if (lua_gettop(L) > 2)
6190 lua_pop(L, lua_gettop(L) - 2);
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01006191
Christopher Faulet700d9e82020-01-31 12:21:52 +01006192 if (!hlua_txn_forward_reply(L, s)) {
6193 if (!(s->flags & SF_ERR_MASK))
6194 s->flags |= SF_ERR_PRXCOND;
6195 lua_pushinteger(L, ACT_RET_ERR);
6196 WILL_LJMP(hlua_done(L));
6197 return 0; /* Never reached */
6198 }
Christopher Faulet4d0e2632019-07-16 10:52:40 +02006199 }
Thierry FOURNIER4bb375c2015-08-26 08:42:21 +02006200
Christopher Faulet700d9e82020-01-31 12:21:52 +01006201 finst = ((htxn->dir == SMP_OPT_DIR_REQ) ? SF_FINST_R : SF_FINST_H);
6202 if (htxn->dir == SMP_OPT_DIR_REQ) {
6203 /* let's log the request time */
6204 s->logs.tv_request = now;
6205 if (s->sess->fe == s->be) /* report it if the request was intercepted by the frontend */
Willy Tarreau4781b152021-04-06 13:53:36 +02006206 _HA_ATOMIC_INC(&s->sess->fe->fe_counters.intercepted_req);
Christopher Faulet700d9e82020-01-31 12:21:52 +01006207 }
Christopher Fauletfe6a71b2019-07-26 16:40:24 +02006208
Christopher Faulet700d9e82020-01-31 12:21:52 +01006209 done:
6210 if (!(s->flags & SF_ERR_MASK))
6211 s->flags |= SF_ERR_LOCAL;
6212 if (!(s->flags & SF_FINST_MASK))
6213 s->flags |= finst;
Christopher Fauletfe6a71b2019-07-26 16:40:24 +02006214
Christopher Faulet4ad73102020-03-05 11:07:31 +01006215 lua_pushinteger(L, ACT_RET_ABRT);
Thierry FOURNIER4bb375c2015-08-26 08:42:21 +02006216 WILL_LJMP(hlua_done(L));
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01006217 return 0;
6218}
6219
Christopher Faulet700d9e82020-01-31 12:21:52 +01006220/*
6221 *
6222 *
6223 * Class REPLY
6224 *
6225 *
6226 */
6227
6228/* Pushes the TXN reply onto the top of the stack. If the stask does not have a
6229 * free slots, the function fails and returns 0;
6230 */
6231static int hlua_txn_reply_new(lua_State *L)
6232{
6233 struct hlua_txn *htxn;
6234 const char *reason, *body = NULL;
6235 int ret, status;
6236
6237 htxn = MAY_LJMP(hlua_checktxn(L, 1));
Christopher Fauletd8f0e072020-02-25 09:45:51 +01006238 if (!IS_HTX_STRM(htxn->s)) {
Christopher Faulet700d9e82020-01-31 12:21:52 +01006239 hlua_pusherror(L, "txn object is not an HTTP transaction.");
6240 WILL_LJMP(lua_error(L));
6241 }
6242
6243 /* Default value */
6244 status = 200;
6245 reason = http_get_reason(status);
6246
6247 if (lua_istable(L, 2)) {
6248 /* load status and reason from the table argument at index 2 */
6249 ret = lua_getfield(L, 2, "status");
6250 if (ret == LUA_TNIL)
6251 goto reason;
6252 else if (ret != LUA_TNUMBER) {
6253 /* invalid status: ignore the reason */
6254 goto body;
6255 }
6256 status = lua_tointeger(L, -1);
6257
6258 reason:
6259 lua_pop(L, 1); /* restore the stack: remove status */
6260 ret = lua_getfield(L, 2, "reason");
6261 if (ret == LUA_TSTRING)
6262 reason = lua_tostring(L, -1);
6263
6264 body:
6265 lua_pop(L, 1); /* restore the stack: remove invalid status or reason */
6266 ret = lua_getfield(L, 2, "body");
6267 if (ret == LUA_TSTRING)
6268 body = lua_tostring(L, -1);
6269 lua_pop(L, 1); /* restore the stack: remove body */
6270 }
6271
6272 /* Create the Reply table */
6273 lua_newtable(L);
6274
6275 /* Add status element */
6276 lua_pushstring(L, "status");
6277 lua_pushinteger(L, status);
6278 lua_settable(L, -3);
6279
6280 /* Add reason element */
6281 reason = http_get_reason(status);
6282 lua_pushstring(L, "reason");
6283 lua_pushstring(L, reason);
6284 lua_settable(L, -3);
6285
6286 /* Add body element, nil if undefined */
6287 lua_pushstring(L, "body");
6288 if (body)
6289 lua_pushstring(L, body);
6290 else
6291 lua_pushnil(L);
6292 lua_settable(L, -3);
6293
6294 /* Add headers element */
6295 lua_pushstring(L, "headers");
6296 lua_newtable(L);
6297
6298 /* stack: [ txn, <Arg:table>, <Reply:table>, "headers", <headers:table> ] */
6299 if (lua_istable(L, 2)) {
6300 /* load headers from the table argument at index 2. If it is a table, copy it. */
6301 ret = lua_getfield(L, 2, "headers");
6302 if (ret == LUA_TTABLE) {
6303 /* stack: [ ... <headers:table>, <table> ] */
6304 lua_pushnil(L);
6305 while (lua_next(L, -2) != 0) {
6306 /* stack: [ ... <headers:table>, <table>, k, v] */
6307 if (!lua_isstring(L, -1) && !lua_istable(L, -1)) {
6308 /* invalid value type, skip it */
6309 lua_pop(L, 1);
6310 continue;
6311 }
6312
6313
6314 /* Duplicate the key and swap it with the value. */
6315 lua_pushvalue(L, -2);
6316 lua_insert(L, -2);
6317 /* stack: [ ... <headers:table>, <table>, k, k, v ] */
6318
6319 lua_newtable(L);
6320 lua_insert(L, -2);
6321 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table>, v ] */
6322
6323 if (lua_isstring(L, -1)) {
6324 /* push the value in the inner table */
6325 lua_rawseti(L, -2, 1);
6326 }
6327 else { /* table */
6328 lua_pushnil(L);
6329 while (lua_next(L, -2) != 0) {
6330 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table>, <v:table>, k2, v2 ] */
6331 if (!lua_isstring(L, -1)) {
6332 /* invalid value type, skip it*/
6333 lua_pop(L, 1);
6334 continue;
6335 }
6336 /* push the value in the inner table */
6337 lua_rawseti(L, -4, lua_rawlen(L, -4) + 1);
6338 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table>, <v:table>, k2 ] */
6339 }
6340 lua_pop(L, 1);
6341 /* stack: [ ... <headers:table>, <table>, k, k, <inner:table> ] */
6342 }
6343
6344 /* push (k,v) on the stack in the headers table:
6345 * stack: [ ... <headers:table>, <table>, k, k, v ]
6346 */
6347 lua_settable(L, -5);
6348 /* stack: [ ... <headers:table>, <table>, k ] */
6349 }
6350 }
6351 lua_pop(L, 1);
6352 }
6353 /* stack: [ txn, <Arg:table>, <Reply:table>, "headers", <headers:table> ] */
6354 lua_settable(L, -3);
6355 /* stack: [ txn, <Arg:table>, <Reply:table> ] */
6356
6357 /* Pop a class sesison metatable and affect it to the userdata. */
6358 lua_rawgeti(L, LUA_REGISTRYINDEX, class_txn_reply_ref);
6359 lua_setmetatable(L, -2);
6360 return 1;
6361}
6362
6363/* Set the reply status code, and optionally the reason. If no reason is
6364 * provided, the default one corresponding to the status code is used.
6365 */
6366__LJMP static int hlua_txn_reply_set_status(lua_State *L)
6367{
6368 int status = MAY_LJMP(luaL_checkinteger(L, 2));
6369 const char *reason = MAY_LJMP(luaL_optlstring(L, 3, NULL, NULL));
6370
6371 /* First argument (self) must be a table */
6372 luaL_checktype(L, 1, LUA_TTABLE);
6373
6374 if (status < 100 || status > 599) {
6375 lua_pushboolean(L, 0);
6376 return 1;
6377 }
6378 if (!reason)
6379 reason = http_get_reason(status);
6380
6381 lua_pushinteger(L, status);
6382 lua_setfield(L, 1, "status");
6383
6384 lua_pushstring(L, reason);
6385 lua_setfield(L, 1, "reason");
6386
6387 lua_pushboolean(L, 1);
6388 return 1;
6389}
6390
6391/* Add a header into the reply object. Each header name is associated to an
6392 * array of values in the "headers" table. If the header name is not found, a
6393 * new entry is created.
6394 */
6395__LJMP static int hlua_txn_reply_add_header(lua_State *L)
6396{
6397 const char *name = MAY_LJMP(luaL_checkstring(L, 2));
6398 const char *value = MAY_LJMP(luaL_checkstring(L, 3));
6399 int ret;
6400
6401 /* First argument (self) must be a table */
6402 luaL_checktype(L, 1, LUA_TTABLE);
6403
6404 /* Push in the stack the "headers" entry. */
6405 ret = lua_getfield(L, 1, "headers");
6406 if (ret != LUA_TTABLE) {
6407 hlua_pusherror(L, "Reply['headers'] is expected to a an array. %s found", lua_typename(L, ret));
6408 WILL_LJMP(lua_error(L));
6409 }
6410
6411 /* check if the header is already registered. If not, register it. */
6412 ret = lua_getfield(L, -1, name);
6413 if (ret == LUA_TNIL) {
6414 /* Entry not found. */
6415 lua_pop(L, 1); /* remove the nil. The "headers" table is the top of the stack. */
6416
6417 /* Insert the new header name in the array in the top of the stack.
6418 * It left the new array in the top of the stack.
6419 */
6420 lua_newtable(L);
6421 lua_pushstring(L, name);
6422 lua_pushvalue(L, -2);
6423 lua_settable(L, -4);
6424 }
6425 else if (ret != LUA_TTABLE) {
6426 hlua_pusherror(L, "Reply['headers']['%s'] is expected to be an array. %s found", name, lua_typename(L, ret));
6427 WILL_LJMP(lua_error(L));
6428 }
6429
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07006430 /* Now the top of thestack is an array of values. We push
Christopher Faulet700d9e82020-01-31 12:21:52 +01006431 * the header value as new entry.
6432 */
6433 lua_pushstring(L, value);
6434 ret = lua_rawlen(L, -2);
6435 lua_rawseti(L, -2, ret + 1);
6436
6437 lua_pushboolean(L, 1);
6438 return 1;
6439}
6440
6441/* Remove all occurrences of a given header name. */
6442__LJMP static int hlua_txn_reply_del_header(lua_State *L)
6443{
6444 const char *name = MAY_LJMP(luaL_checkstring(L, 2));
6445 int ret;
6446
6447 /* First argument (self) must be a table */
6448 luaL_checktype(L, 1, LUA_TTABLE);
6449
6450 /* Push in the stack the "headers" entry. */
6451 ret = lua_getfield(L, 1, "headers");
6452 if (ret != LUA_TTABLE) {
6453 hlua_pusherror(L, "Reply['headers'] is expected to be an array. %s found", lua_typename(L, ret));
6454 WILL_LJMP(lua_error(L));
6455 }
6456
6457 lua_pushstring(L, name);
6458 lua_pushnil(L);
6459 lua_settable(L, -3);
6460
6461 lua_pushboolean(L, 1);
6462 return 1;
6463}
6464
6465/* Set the reply's body. Overwrite any existing entry. */
6466__LJMP static int hlua_txn_reply_set_body(lua_State *L)
6467{
6468 const char *payload = MAY_LJMP(luaL_checkstring(L, 2));
6469
6470 /* First argument (self) must be a table */
6471 luaL_checktype(L, 1, LUA_TTABLE);
6472
6473 lua_pushstring(L, payload);
6474 lua_setfield(L, 1, "body");
6475
6476 lua_pushboolean(L, 1);
6477 return 1;
6478}
6479
Thierry FOURNIERc798b5d2015-03-17 01:09:57 +01006480__LJMP static int hlua_log(lua_State *L)
6481{
6482 int level;
6483 const char *msg;
6484
6485 MAY_LJMP(check_args(L, 2, "log"));
6486 level = MAY_LJMP(luaL_checkinteger(L, 1));
6487 msg = MAY_LJMP(luaL_checkstring(L, 2));
6488
6489 if (level < 0 || level >= NB_LOG_LEVELS)
6490 WILL_LJMP(luaL_argerror(L, 1, "Invalid loglevel."));
6491
6492 hlua_sendlog(NULL, level, msg);
6493 return 0;
6494}
6495
6496__LJMP static int hlua_log_debug(lua_State *L)
6497{
6498 const char *msg;
6499
6500 MAY_LJMP(check_args(L, 1, "debug"));
6501 msg = MAY_LJMP(luaL_checkstring(L, 1));
6502 hlua_sendlog(NULL, LOG_DEBUG, msg);
6503 return 0;
6504}
6505
6506__LJMP static int hlua_log_info(lua_State *L)
6507{
6508 const char *msg;
6509
6510 MAY_LJMP(check_args(L, 1, "info"));
6511 msg = MAY_LJMP(luaL_checkstring(L, 1));
6512 hlua_sendlog(NULL, LOG_INFO, msg);
6513 return 0;
6514}
6515
6516__LJMP static int hlua_log_warning(lua_State *L)
6517{
6518 const char *msg;
6519
6520 MAY_LJMP(check_args(L, 1, "warning"));
6521 msg = MAY_LJMP(luaL_checkstring(L, 1));
6522 hlua_sendlog(NULL, LOG_WARNING, msg);
6523 return 0;
6524}
6525
6526__LJMP static int hlua_log_alert(lua_State *L)
6527{
6528 const char *msg;
6529
6530 MAY_LJMP(check_args(L, 1, "alert"));
6531 msg = MAY_LJMP(luaL_checkstring(L, 1));
6532 hlua_sendlog(NULL, LOG_ALERT, msg);
Thierry FOURNIER893bfa32015-02-17 18:42:34 +01006533 return 0;
6534}
6535
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01006536__LJMP static int hlua_sleep_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006537{
6538 int wakeup_ms = lua_tointeger(L, -1);
6539 if (now_ms < wakeup_ms)
Willy Tarreau9635e032018-10-16 17:52:55 +02006540 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_sleep_yield, wakeup_ms, 0));
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006541 return 0;
6542}
6543
6544__LJMP static int hlua_sleep(lua_State *L)
6545{
6546 unsigned int delay;
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006547 unsigned int wakeup_ms;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006548
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006549 MAY_LJMP(check_args(L, 1, "sleep"));
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006550
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01006551 delay = MAY_LJMP(luaL_checkinteger(L, 1)) * 1000;
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006552 wakeup_ms = tick_add(now_ms, delay);
6553 lua_pushinteger(L, wakeup_ms);
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006554
Willy Tarreau9635e032018-10-16 17:52:55 +02006555 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_sleep_yield, wakeup_ms, 0));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006556 return 0;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006557}
6558
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006559__LJMP static int hlua_msleep(lua_State *L)
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006560{
6561 unsigned int delay;
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006562 unsigned int wakeup_ms;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006563
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006564 MAY_LJMP(check_args(L, 1, "msleep"));
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006565
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01006566 delay = MAY_LJMP(luaL_checkinteger(L, 1));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006567 wakeup_ms = tick_add(now_ms, delay);
6568 lua_pushinteger(L, wakeup_ms);
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006569
Willy Tarreau9635e032018-10-16 17:52:55 +02006570 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_sleep_yield, wakeup_ms, 0));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006571 return 0;
Thierry FOURNIER5b8608f2015-02-16 19:43:25 +01006572}
6573
Thierry FOURNIER13416fe2015-02-17 15:01:59 +01006574/* This functionis an LUA binding. it permits to give back
6575 * the hand at the HAProxy scheduler. It is used when the
6576 * LUA processing consumes a lot of time.
6577 */
Thierry FOURNIERf90838b2015-03-06 13:48:32 +01006578__LJMP static int hlua_yield_yield(lua_State *L, int status, lua_KContext ctx)
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006579{
6580 return 0;
6581}
6582
Thierry FOURNIER13416fe2015-02-17 15:01:59 +01006583__LJMP static int hlua_yield(lua_State *L)
6584{
Willy Tarreau9635e032018-10-16 17:52:55 +02006585 MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_yield_yield, TICK_ETERNITY, HLUA_CTRLYIELD));
Thierry FOURNIERd44731f2015-03-04 15:51:09 +01006586 return 0;
Thierry FOURNIER13416fe2015-02-17 15:01:59 +01006587}
6588
Thierry FOURNIER37196f42015-02-16 19:34:56 +01006589/* This function change the nice of the currently executed
6590 * task. It is used set low or high priority at the current
6591 * task.
6592 */
Willy Tarreau59551662015-03-10 14:23:13 +01006593__LJMP static int hlua_set_nice(lua_State *L)
Thierry FOURNIER37196f42015-02-16 19:34:56 +01006594{
Willy Tarreau80f5fae2015-02-27 16:38:20 +01006595 struct hlua *hlua;
6596 int nice;
Thierry FOURNIER37196f42015-02-16 19:34:56 +01006597
Willy Tarreau80f5fae2015-02-27 16:38:20 +01006598 MAY_LJMP(check_args(L, 1, "set_nice"));
Willy Tarreau80f5fae2015-02-27 16:38:20 +01006599 nice = MAY_LJMP(luaL_checkinteger(L, 1));
Thierry FOURNIER37196f42015-02-16 19:34:56 +01006600
Thierry Fournier4234dbd2020-11-28 13:18:23 +01006601 /* Get hlua struct, or NULL if we execute from main lua state */
6602 hlua = hlua_gethlua(L);
6603
6604 /* If the task is not set, I'm in a start mode. */
Thierry FOURNIER37196f42015-02-16 19:34:56 +01006605 if (!hlua || !hlua->task)
6606 return 0;
6607
6608 if (nice < -1024)
6609 nice = -1024;
Willy Tarreau80f5fae2015-02-27 16:38:20 +01006610 else if (nice > 1024)
Thierry FOURNIER37196f42015-02-16 19:34:56 +01006611 nice = 1024;
6612
6613 hlua->task->nice = nice;
6614 return 0;
6615}
6616
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08006617/* This function is used as a callback of a task. It is called by the
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006618 * HAProxy task subsystem when the task is awaked. The LUA runtime can
6619 * return an E_AGAIN signal, the emmiter of this signal must set a
6620 * signal to wake the task.
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006621 *
6622 * Task wrapper are longjmp safe because the only one Lua code
6623 * executed is the safe hlua_ctx_resume();
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006624 */
Willy Tarreau144f84a2021-03-02 16:09:26 +01006625struct task *hlua_process_task(struct task *task, void *context, unsigned int state)
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006626{
Olivier Houchard9f6af332018-05-25 14:04:04 +02006627 struct hlua *hlua = context;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006628 enum hlua_exec status;
6629
Christopher Faulet5bc99722018-04-25 10:34:45 +02006630 if (task->thread_mask == MAX_THREADS_MASK)
6631 task_set_affinity(task, tid_bit);
6632
Thierry FOURNIERbd413492015-03-03 16:52:26 +01006633 /* If it is the first call to the task, we must initialize the
6634 * execution timeouts.
6635 */
6636 if (!HLUA_IS_RUNNING(hlua))
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02006637 hlua->max_time = hlua_timeout_task;
Thierry FOURNIERbd413492015-03-03 16:52:26 +01006638
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006639 /* Execute the Lua code. */
6640 status = hlua_ctx_resume(hlua, 1);
6641
6642 switch (status) {
6643 /* finished or yield */
6644 case HLUA_E_OK:
6645 hlua_ctx_destroy(hlua);
Olivier Houchard3f795f72019-04-17 22:51:06 +02006646 task_destroy(task);
Tim Duesterhuscd235c62018-04-24 13:56:01 +02006647 task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006648 break;
6649
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01006650 case HLUA_E_AGAIN: /* co process or timeout wake me later. */
Thierry FOURNIERcb146882017-12-10 17:10:57 +01006651 notification_gc(&hlua->com);
PiBa-NLfe971b32018-05-02 22:27:14 +02006652 task->expire = hlua->wake_time;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006653 break;
6654
6655 /* finished with error. */
6656 case HLUA_E_ERRMSG:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006657 SEND_ERR(NULL, "Lua task: %s.\n", lua_tostring(hlua->T, -1));
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006658 hlua_ctx_destroy(hlua);
Olivier Houchard3f795f72019-04-17 22:51:06 +02006659 task_destroy(task);
Emeric Brun253e53e2017-10-17 18:58:40 +02006660 task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006661 break;
6662
6663 case HLUA_E_ERR:
6664 default:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006665 SEND_ERR(NULL, "Lua task: unknown error.\n");
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006666 hlua_ctx_destroy(hlua);
Olivier Houchard3f795f72019-04-17 22:51:06 +02006667 task_destroy(task);
Emeric Brun253e53e2017-10-17 18:58:40 +02006668 task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006669 break;
6670 }
Emeric Brun253e53e2017-10-17 18:58:40 +02006671 return task;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006672}
6673
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01006674/* This function is an LUA binding that register LUA function to be
6675 * executed after the HAProxy configuration parsing and before the
6676 * HAProxy scheduler starts. This function expect only one LUA
6677 * argument that is a function. This function returns nothing, but
6678 * throws if an error is encountered.
6679 */
6680__LJMP static int hlua_register_init(lua_State *L)
6681{
6682 struct hlua_init_function *init;
6683 int ref;
6684
6685 MAY_LJMP(check_args(L, 1, "register_init"));
6686
6687 ref = MAY_LJMP(hlua_checkfunction(L, 1));
6688
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02006689 init = calloc(1, sizeof(*init));
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01006690 if (!init)
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01006691 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01006692
6693 init->function_ref = ref;
Willy Tarreau2b718102021-04-21 07:32:39 +02006694 LIST_APPEND(&hlua_init_functions[hlua_state_id], &init->l);
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01006695 return 0;
6696}
6697
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006698/* This functio is an LUA binding. It permits to register a task
6699 * executed in parallel of the main HAroxy activity. The task is
6700 * created and it is set in the HAProxy scheduler. It can be called
6701 * from the "init" section, "post init" or during the runtime.
6702 *
6703 * Lua prototype:
6704 *
6705 * <none> core.register_task(<function>)
6706 */
6707static int hlua_register_task(lua_State *L)
6708{
Christopher Faulet5294ec02021-04-12 12:24:47 +02006709 struct hlua *hlua = NULL;
6710 struct task *task = NULL;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006711 int ref;
Thierry Fournier021d9862020-11-28 23:42:03 +01006712 int state_id;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006713
6714 MAY_LJMP(check_args(L, 1, "register_task"));
6715
6716 ref = MAY_LJMP(hlua_checkfunction(L, 1));
6717
Thierry Fournier75fc0292020-11-28 13:18:56 +01006718 /* Get the reference state. If the reference is NULL, L is the master
6719 * state, otherwise hlua->T is.
6720 */
6721 hlua = hlua_gethlua(L);
6722 if (hlua)
Thierry Fournier021d9862020-11-28 23:42:03 +01006723 /* we are in runtime processing */
6724 state_id = hlua->state_id;
Thierry Fournier75fc0292020-11-28 13:18:56 +01006725 else
Thierry Fournier021d9862020-11-28 23:42:03 +01006726 /* we are in initialization mode */
Thierry Fournierc7492592020-11-28 23:57:24 +01006727 state_id = hlua_state_id;
Thierry Fournier75fc0292020-11-28 13:18:56 +01006728
Willy Tarreaubafbe012017-11-24 17:34:44 +01006729 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006730 if (!hlua)
Christopher Faulet5294ec02021-04-12 12:24:47 +02006731 goto alloc_error;
Christopher Faulet1e8433f2021-03-24 15:03:01 +01006732 HLUA_INIT(hlua);
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006733
Thierry Fournier59f11be2020-11-29 00:37:41 +01006734 /* We are in the common lua state, execute the task anywhere,
6735 * otherwise, inherit the current thread identifier
6736 */
6737 if (state_id == 0)
6738 task = task_new(MAX_THREADS_MASK);
6739 else
6740 task = task_new(tid_bit);
Willy Tarreaue09101e2018-10-16 17:37:12 +02006741 if (!task)
Christopher Faulet5294ec02021-04-12 12:24:47 +02006742 goto alloc_error;
Willy Tarreaue09101e2018-10-16 17:37:12 +02006743
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006744 task->context = hlua;
6745 task->process = hlua_process_task;
6746
Thierry Fournier021d9862020-11-28 23:42:03 +01006747 if (!hlua_ctx_init(hlua, state_id, task, 1))
Christopher Faulet5294ec02021-04-12 12:24:47 +02006748 goto alloc_error;
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006749
6750 /* Restore the function in the stack. */
6751 lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, ref);
6752 hlua->nargs = 0;
6753
6754 /* Schedule task. */
6755 task_schedule(task, now_ms);
6756
6757 return 0;
Christopher Faulet5294ec02021-04-12 12:24:47 +02006758
6759 alloc_error:
6760 task_destroy(task);
6761 hlua_ctx_destroy(hlua);
6762 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
6763 return 0; /* Never reached */
Thierry FOURNIER24f33532015-01-23 12:13:00 +01006764}
6765
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006766/* Wrapper called by HAProxy to execute an LUA converter. This wrapper
6767 * doesn't allow "yield" functions because the HAProxy engine cannot
6768 * resume converters.
6769 */
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02006770static int hlua_sample_conv_wrapper(const struct arg *arg_p, struct sample *smp, void *private)
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006771{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02006772 struct hlua_function *fcn = private;
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02006773 struct stream *stream = smp->strm;
Thierry Fournierfd107a22016-02-19 19:57:23 +01006774 const char *error;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006775
Willy Tarreaube508f12016-03-10 11:47:01 +01006776 if (!stream)
6777 return 0;
6778
Willy Tarreau87b09662015-04-03 00:22:06 +02006779 /* In the execution wrappers linked with a stream, the
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01006780 * Lua context can be not initialized. This behavior
6781 * permits to save performances because a systematic
6782 * Lua initialization cause 5% performances loss.
6783 */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006784 if (!stream->hlua) {
Christopher Faulet1e8433f2021-03-24 15:03:01 +01006785 struct hlua *hlua;
6786
6787 hlua = pool_alloc(pool_head_hlua);
6788 if (!hlua) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006789 SEND_ERR(stream->be, "Lua converter '%s': can't initialize Lua context.\n", fcn->name);
6790 return 0;
6791 }
Christopher Faulet1e8433f2021-03-24 15:03:01 +01006792 HLUA_INIT(hlua);
6793 stream->hlua = hlua;
Thierry Fournierc7492592020-11-28 23:57:24 +01006794 if (!hlua_ctx_init(stream->hlua, fcn_ref_to_stack_id(fcn), stream->task, 0)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006795 SEND_ERR(stream->be, "Lua converter '%s': can't initialize Lua context.\n", fcn->name);
6796 return 0;
6797 }
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01006798 }
6799
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006800 /* If it is the first run, initialize the data for the call. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006801 if (!HLUA_IS_RUNNING(stream->hlua)) {
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006802
6803 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006804 if (!SET_SAFE_LJMP(stream->hlua)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006805 if (lua_type(stream->hlua->T, -1) == LUA_TSTRING)
6806 error = lua_tostring(stream->hlua->T, -1);
Thierry Fournierfd107a22016-02-19 19:57:23 +01006807 else
6808 error = "critical error";
6809 SEND_ERR(stream->be, "Lua converter '%s': %s.\n", fcn->name, error);
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006810 return 0;
6811 }
6812
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006813 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006814 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006815 SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006816 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006817 return 0;
6818 }
6819
6820 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +01006821 lua_rawgeti(stream->hlua->T, LUA_REGISTRYINDEX, fcn->function_ref[stream->hlua->state_id]);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006822
6823 /* convert input sample and pust-it in the stack. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006824 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006825 SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006826 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006827 return 0;
6828 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006829 hlua_smp2lua(stream->hlua->T, smp);
6830 stream->hlua->nargs = 1;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006831
6832 /* push keywords in the stack. */
6833 if (arg_p) {
6834 for (; arg_p->type != ARGT_STOP; arg_p++) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006835 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006836 SEND_ERR(stream->be, "Lua converter '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006837 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006838 return 0;
6839 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006840 hlua_arg2lua(stream->hlua->T, arg_p);
6841 stream->hlua->nargs++;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006842 }
6843 }
6844
Thierry FOURNIERbd413492015-03-03 16:52:26 +01006845 /* We must initialize the execution timeouts. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006846 stream->hlua->max_time = hlua_timeout_session;
Thierry FOURNIERbd413492015-03-03 16:52:26 +01006847
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006848 /* At this point the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006849 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006850 }
6851
6852 /* Execute the function. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006853 switch (hlua_ctx_resume(stream->hlua, 0)) {
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006854 /* finished. */
6855 case HLUA_E_OK:
Thierry FOURNIERfd80df12017-05-12 16:32:20 +02006856 /* If the stack is empty, the function fails. */
6857 if (lua_gettop(stream->hlua->T) <= 0)
6858 return 0;
6859
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006860 /* Convert the returned value in sample. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006861 hlua_lua2smp(stream->hlua->T, -1, smp);
6862 lua_pop(stream->hlua->T, 1);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006863 return 1;
6864
6865 /* yield. */
6866 case HLUA_E_AGAIN:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006867 SEND_ERR(stream->be, "Lua converter '%s': cannot use yielded functions.\n", fcn->name);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006868 return 0;
6869
6870 /* finished with error. */
6871 case HLUA_E_ERRMSG:
6872 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006873 SEND_ERR(stream->be, "Lua converter '%s': %s.\n",
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006874 fcn->name, lua_tostring(stream->hlua->T, -1));
6875 lua_pop(stream->hlua->T, 1);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006876 return 0;
6877
Thierry Fournierd5b073c2018-05-21 19:42:47 +02006878 case HLUA_E_ETMOUT:
6879 SEND_ERR(stream->be, "Lua converter '%s': execution timeout.\n", fcn->name);
6880 return 0;
6881
6882 case HLUA_E_NOMEM:
6883 SEND_ERR(stream->be, "Lua converter '%s': out of memory error.\n", fcn->name);
6884 return 0;
6885
6886 case HLUA_E_YIELD:
6887 SEND_ERR(stream->be, "Lua converter '%s': yield functions like core.tcp() or core.sleep() are not allowed.\n", fcn->name);
6888 return 0;
6889
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006890 case HLUA_E_ERR:
6891 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006892 SEND_ERR(stream->be, "Lua converter '%s' returns an unknown error.\n", fcn->name);
Tim Duesterhus588b3142020-05-29 14:35:51 +02006893 /* fall through */
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01006894
6895 default:
6896 return 0;
6897 }
6898}
6899
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006900/* Wrapper called by HAProxy to execute a sample-fetch. this wrapper
6901 * doesn't allow "yield" functions because the HAProxy engine cannot
Willy Tarreaube508f12016-03-10 11:47:01 +01006902 * resume sample-fetches. This function will be called by the sample
6903 * fetch engine to call lua-based fetch operations.
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006904 */
Thierry FOURNIER0786d052015-05-11 15:42:45 +02006905static int hlua_sample_fetch_wrapper(const struct arg *arg_p, struct sample *smp,
6906 const char *kw, void *private)
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006907{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02006908 struct hlua_function *fcn = private;
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +02006909 struct stream *stream = smp->strm;
Thierry Fournierfd107a22016-02-19 19:57:23 +01006910 const char *error;
Christopher Fauletbfab2dd2019-07-26 15:09:53 +02006911 unsigned int hflags = HLUA_TXN_NOTERM;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006912
Willy Tarreaube508f12016-03-10 11:47:01 +01006913 if (!stream)
6914 return 0;
Christopher Fauletafd8f102018-11-08 11:34:21 +01006915
Willy Tarreau87b09662015-04-03 00:22:06 +02006916 /* In the execution wrappers linked with a stream, the
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01006917 * Lua context can be not initialized. This behavior
6918 * permits to save performances because a systematic
6919 * Lua initialization cause 5% performances loss.
6920 */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006921 if (!stream->hlua) {
Christopher Faulet1e8433f2021-03-24 15:03:01 +01006922 struct hlua *hlua;
6923
6924 hlua = pool_alloc(pool_head_hlua);
6925 if (!hlua) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006926 SEND_ERR(stream->be, "Lua sample-fetch '%s': can't initialize Lua context.\n", fcn->name);
6927 return 0;
6928 }
Christopher Faulet1e8433f2021-03-24 15:03:01 +01006929 hlua->T = NULL;
6930 stream->hlua = hlua;
Thierry Fournierc7492592020-11-28 23:57:24 +01006931 if (!hlua_ctx_init(stream->hlua, fcn_ref_to_stack_id(fcn), stream->task, 0)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006932 SEND_ERR(stream->be, "Lua sample-fetch '%s': can't initialize Lua context.\n", fcn->name);
6933 return 0;
6934 }
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01006935 }
6936
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006937 /* If it is the first run, initialize the data for the call. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006938 if (!HLUA_IS_RUNNING(stream->hlua)) {
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006939
6940 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006941 if (!SET_SAFE_LJMP(stream->hlua)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006942 if (lua_type(stream->hlua->T, -1) == LUA_TSTRING)
6943 error = lua_tostring(stream->hlua->T, -1);
Thierry Fournierfd107a22016-02-19 19:57:23 +01006944 else
6945 error = "critical error";
6946 SEND_ERR(smp->px, "Lua sample-fetch '%s': %s.\n", fcn->name, error);
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006947 return 0;
6948 }
6949
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006950 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006951 if (!lua_checkstack(stream->hlua->T, 2)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006952 SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006953 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006954 return 0;
6955 }
6956
6957 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +01006958 lua_rawgeti(stream->hlua->T, LUA_REGISTRYINDEX, fcn->function_ref[stream->hlua->state_id]);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006959
6960 /* push arguments in the stack. */
Christopher Fauletbfab2dd2019-07-26 15:09:53 +02006961 if (!hlua_txn_new(stream->hlua->T, stream, smp->px, smp->opt & SMP_OPT_DIR, hflags)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006962 SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006963 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006964 return 0;
6965 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006966 stream->hlua->nargs = 1;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006967
6968 /* push keywords in the stack. */
6969 for (; arg_p && arg_p->type != ARGT_STOP; arg_p++) {
6970 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006971 if (!lua_checkstack(stream->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02006972 SEND_ERR(smp->px, "Lua sample-fetch '%s': full stack.\n", fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006973 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006974 return 0;
6975 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006976 hlua_arg2lua(stream->hlua->T, arg_p);
6977 stream->hlua->nargs++;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006978 }
6979
Thierry FOURNIERbd413492015-03-03 16:52:26 +01006980 /* We must initialize the execution timeouts. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006981 stream->hlua->max_time = hlua_timeout_session;
Thierry FOURNIERbd413492015-03-03 16:52:26 +01006982
Thierry FOURNIERbabae282015-09-17 11:36:37 +02006983 /* At this point the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01006984 RESET_SAFE_LJMP(stream->hlua);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006985 }
6986
6987 /* Execute the function. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006988 switch (hlua_ctx_resume(stream->hlua, 0)) {
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006989 /* finished. */
6990 case HLUA_E_OK:
Thierry FOURNIERfd80df12017-05-12 16:32:20 +02006991 /* If the stack is empty, the function fails. */
6992 if (lua_gettop(stream->hlua->T) <= 0)
6993 return 0;
6994
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006995 /* Convert the returned value in sample. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01006996 hlua_lua2smp(stream->hlua->T, -1, smp);
6997 lua_pop(stream->hlua->T, 1);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01006998
6999 /* Set the end of execution flag. */
7000 smp->flags &= ~SMP_F_MAY_CHANGE;
7001 return 1;
7002
7003 /* yield. */
7004 case HLUA_E_AGAIN:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02007005 SEND_ERR(smp->px, "Lua sample-fetch '%s': cannot use yielded functions.\n", fcn->name);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01007006 return 0;
7007
7008 /* finished with error. */
7009 case HLUA_E_ERRMSG:
7010 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02007011 SEND_ERR(smp->px, "Lua sample-fetch '%s': %s.\n",
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01007012 fcn->name, lua_tostring(stream->hlua->T, -1));
7013 lua_pop(stream->hlua->T, 1);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01007014 return 0;
7015
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007016 case HLUA_E_ETMOUT:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007017 SEND_ERR(smp->px, "Lua sample-fetch '%s': execution timeout.\n", fcn->name);
7018 return 0;
7019
7020 case HLUA_E_NOMEM:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007021 SEND_ERR(smp->px, "Lua sample-fetch '%s': out of memory error.\n", fcn->name);
7022 return 0;
7023
7024 case HLUA_E_YIELD:
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007025 SEND_ERR(smp->px, "Lua sample-fetch '%s': yield not allowed.\n", fcn->name);
7026 return 0;
7027
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01007028 case HLUA_E_ERR:
7029 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02007030 SEND_ERR(smp->px, "Lua sample-fetch '%s' returns an unknown error.\n", fcn->name);
Tim Duesterhus588b3142020-05-29 14:35:51 +02007031 /* fall through */
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01007032
7033 default:
7034 return 0;
7035 }
7036}
7037
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01007038/* This function is an LUA binding used for registering
7039 * "sample-conv" functions. It expects a converter name used
7040 * in the haproxy configuration file, and an LUA function.
7041 */
7042__LJMP static int hlua_register_converters(lua_State *L)
7043{
7044 struct sample_conv_kw_list *sck;
7045 const char *name;
7046 int ref;
7047 int len;
Christopher Fauletaa224302021-04-12 14:08:21 +02007048 struct hlua_function *fcn = NULL;
Thierry Fournierf67442e2020-11-28 20:41:07 +01007049 struct sample_conv *sc;
7050 struct buffer *trash;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01007051
7052 MAY_LJMP(check_args(L, 2, "register_converters"));
7053
7054 /* First argument : converter name. */
7055 name = MAY_LJMP(luaL_checkstring(L, 1));
7056
7057 /* Second argument : lua function. */
7058 ref = MAY_LJMP(hlua_checkfunction(L, 2));
7059
Thierry Fournierf67442e2020-11-28 20:41:07 +01007060 /* Check if the converter is already registered */
7061 trash = get_trash_chunk();
7062 chunk_printf(trash, "lua.%s", name);
7063 sc = find_sample_conv(trash->area, trash->data);
7064 if (sc != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +01007065 fcn = sc->private;
7066 if (fcn->function_ref[hlua_state_id] != -1) {
7067 ha_warning("Trying to register converter 'lua.%s' more than once. "
7068 "This will become a hard error in version 2.5.\n", name);
7069 }
7070 fcn->function_ref[hlua_state_id] = ref;
7071 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +01007072 }
7073
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01007074 /* Allocate and fill the sample fetch keyword struct. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02007075 sck = calloc(1, sizeof(*sck) + sizeof(struct sample_conv) * 2);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01007076 if (!sck)
Christopher Fauletaa224302021-04-12 14:08:21 +02007077 goto alloc_error;
Thierry Fournier62a22aa2020-11-28 21:06:35 +01007078 fcn = new_hlua_function();
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01007079 if (!fcn)
Christopher Fauletaa224302021-04-12 14:08:21 +02007080 goto alloc_error;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01007081
7082 /* Fill fcn. */
7083 fcn->name = strdup(name);
7084 if (!fcn->name)
Christopher Fauletaa224302021-04-12 14:08:21 +02007085 goto alloc_error;
Thierry Fournierc7492592020-11-28 23:57:24 +01007086 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01007087
7088 /* List head */
7089 sck->list.n = sck->list.p = NULL;
7090
7091 /* converter keyword. */
7092 len = strlen("lua.") + strlen(name) + 1;
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02007093 sck->kw[0].kw = calloc(1, len);
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01007094 if (!sck->kw[0].kw)
Christopher Fauletaa224302021-04-12 14:08:21 +02007095 goto alloc_error;
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01007096
7097 snprintf((char *)sck->kw[0].kw, len, "lua.%s", name);
7098 sck->kw[0].process = hlua_sample_conv_wrapper;
David Carlier0c437f42016-04-27 16:21:56 +01007099 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 +01007100 sck->kw[0].val_args = NULL;
7101 sck->kw[0].in_type = SMP_T_STR;
7102 sck->kw[0].out_type = SMP_T_STR;
7103 sck->kw[0].private = fcn;
7104
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01007105 /* Register this new converter */
7106 sample_register_convs(sck);
7107
7108 return 0;
Christopher Fauletaa224302021-04-12 14:08:21 +02007109
7110 alloc_error:
7111 release_hlua_function(fcn);
7112 ha_free(&sck);
7113 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
7114 return 0; /* Never reached */
Thierry FOURNIER9be813f2015-02-16 20:21:12 +01007115}
7116
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08007117/* This function is an LUA binding used for registering
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01007118 * "sample-fetch" functions. It expects a converter name used
7119 * in the haproxy configuration file, and an LUA function.
7120 */
7121__LJMP static int hlua_register_fetches(lua_State *L)
7122{
7123 const char *name;
7124 int ref;
7125 int len;
7126 struct sample_fetch_kw_list *sfk;
Christopher Faulet2567f182021-04-12 14:11:50 +02007127 struct hlua_function *fcn = NULL;
Thierry Fournierf67442e2020-11-28 20:41:07 +01007128 struct sample_fetch *sf;
7129 struct buffer *trash;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01007130
7131 MAY_LJMP(check_args(L, 2, "register_fetches"));
7132
7133 /* First argument : sample-fetch name. */
7134 name = MAY_LJMP(luaL_checkstring(L, 1));
7135
7136 /* Second argument : lua function. */
7137 ref = MAY_LJMP(hlua_checkfunction(L, 2));
7138
Thierry Fournierf67442e2020-11-28 20:41:07 +01007139 /* Check if the sample-fetch is already registered */
7140 trash = get_trash_chunk();
7141 chunk_printf(trash, "lua.%s", name);
7142 sf = find_sample_fetch(trash->area, trash->data);
7143 if (sf != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +01007144 fcn = sf->private;
7145 if (fcn->function_ref[hlua_state_id] != -1) {
7146 ha_warning("Trying to register sample-fetch 'lua.%s' more than once. "
7147 "This will become a hard error in version 2.5.\n", name);
7148 }
7149 fcn->function_ref[hlua_state_id] = ref;
7150 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +01007151 }
7152
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01007153 /* Allocate and fill the sample fetch keyword struct. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02007154 sfk = calloc(1, sizeof(*sfk) + sizeof(struct sample_fetch) * 2);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01007155 if (!sfk)
Christopher Faulet2567f182021-04-12 14:11:50 +02007156 goto alloc_error;
Thierry Fournier62a22aa2020-11-28 21:06:35 +01007157 fcn = new_hlua_function();
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01007158 if (!fcn)
Christopher Faulet2567f182021-04-12 14:11:50 +02007159 goto alloc_error;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01007160
7161 /* Fill fcn. */
7162 fcn->name = strdup(name);
7163 if (!fcn->name)
Christopher Faulet2567f182021-04-12 14:11:50 +02007164 goto alloc_error;
Thierry Fournierc7492592020-11-28 23:57:24 +01007165 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01007166
7167 /* List head */
7168 sfk->list.n = sfk->list.p = NULL;
7169
7170 /* sample-fetch keyword. */
7171 len = strlen("lua.") + strlen(name) + 1;
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02007172 sfk->kw[0].kw = calloc(1, len);
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01007173 if (!sfk->kw[0].kw)
Christopher Faulet2567f182021-04-12 14:11:50 +02007174 goto alloc_error;
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01007175
7176 snprintf((char *)sfk->kw[0].kw, len, "lua.%s", name);
7177 sfk->kw[0].process = hlua_sample_fetch_wrapper;
David Carlier0c437f42016-04-27 16:21:56 +01007178 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 +01007179 sfk->kw[0].val_args = NULL;
7180 sfk->kw[0].out_type = SMP_T_STR;
7181 sfk->kw[0].use = SMP_USE_HTTP_ANY;
7182 sfk->kw[0].val = 0;
7183 sfk->kw[0].private = fcn;
7184
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01007185 /* Register this new fetch. */
7186 sample_register_fetches(sfk);
7187
7188 return 0;
Christopher Faulet2567f182021-04-12 14:11:50 +02007189
7190 alloc_error:
7191 release_hlua_function(fcn);
7192 ha_free(&sfk);
7193 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
7194 return 0; /* Never reached */
Thierry FOURNIERfa0e5dd2015-02-16 20:19:18 +01007195}
7196
Christopher Faulet501465d2020-02-26 14:54:16 +01007197/* This function is a lua binding to set the wake_time.
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01007198 */
Christopher Faulet501465d2020-02-26 14:54:16 +01007199__LJMP static int hlua_set_wake_time(lua_State *L)
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01007200{
Thierry Fournier4234dbd2020-11-28 13:18:23 +01007201 struct hlua *hlua;
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01007202 unsigned int delay;
7203 unsigned int wakeup_ms;
7204
Thierry Fournier4234dbd2020-11-28 13:18:23 +01007205 /* Get hlua struct, or NULL if we execute from main lua state */
7206 hlua = hlua_gethlua(L);
7207 if (!hlua) {
7208 return 0;
7209 }
7210
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01007211 MAY_LJMP(check_args(L, 1, "wake_time"));
7212
7213 delay = MAY_LJMP(luaL_checkinteger(L, 1));
7214 wakeup_ms = tick_add(now_ms, delay);
7215 hlua->wake_time = wakeup_ms;
7216 return 0;
7217}
7218
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007219/* This function is a wrapper to execute each LUA function declared as an action
7220 * wrapper during the initialisation period. This function may return any
7221 * ACT_RET_* value. On error ACT_RET_CONT is returned and the action is
7222 * ignored. If the lua action yields, ACT_RET_YIELD is returned. On success, the
7223 * return value is the first element on the stack.
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007224 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007225static enum act_return hlua_action(struct act_rule *rule, struct proxy *px,
Willy Tarreau658b85b2015-09-27 10:00:49 +02007226 struct session *sess, struct stream *s, int flags)
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007227{
7228 char **arg;
Christopher Fauletbfab2dd2019-07-26 15:09:53 +02007229 unsigned int hflags = 0;
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007230 int dir, act_ret = ACT_RET_CONT;
Thierry Fournierfd107a22016-02-19 19:57:23 +01007231 const char *error;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007232
7233 switch (rule->from) {
Christopher Fauletd8f0e072020-02-25 09:45:51 +01007234 case ACT_F_TCP_REQ_CNT: dir = SMP_OPT_DIR_REQ; break;
7235 case ACT_F_TCP_RES_CNT: dir = SMP_OPT_DIR_RES; break;
7236 case ACT_F_HTTP_REQ: dir = SMP_OPT_DIR_REQ; break;
7237 case ACT_F_HTTP_RES: dir = SMP_OPT_DIR_RES; break;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007238 default:
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02007239 SEND_ERR(px, "Lua: internal error while execute action.\n");
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007240 goto end;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007241 }
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007242
Willy Tarreau87b09662015-04-03 00:22:06 +02007243 /* In the execution wrappers linked with a stream, the
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01007244 * Lua context can be not initialized. This behavior
7245 * permits to save performances because a systematic
7246 * Lua initialization cause 5% performances loss.
7247 */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01007248 if (!s->hlua) {
Christopher Faulet1e8433f2021-03-24 15:03:01 +01007249 struct hlua *hlua;
7250
7251 hlua = pool_alloc(pool_head_hlua);
7252 if (!hlua) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01007253 SEND_ERR(px, "Lua action '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007254 rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007255 goto end;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01007256 }
Christopher Faulet1e8433f2021-03-24 15:03:01 +01007257 HLUA_INIT(hlua);
7258 s->hlua = hlua;
Thierry Fournierc7492592020-11-28 23:57:24 +01007259 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 +01007260 SEND_ERR(px, "Lua action '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007261 rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007262 goto end;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01007263 }
Thierry FOURNIER05ac4242015-02-27 18:37:27 +01007264 }
7265
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007266 /* If it is the first run, initialize the data for the call. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01007267 if (!HLUA_IS_RUNNING(s->hlua)) {
Thierry FOURNIERbabae282015-09-17 11:36:37 +02007268
7269 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007270 if (!SET_SAFE_LJMP(s->hlua)) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01007271 if (lua_type(s->hlua->T, -1) == LUA_TSTRING)
7272 error = lua_tostring(s->hlua->T, -1);
Thierry Fournierfd107a22016-02-19 19:57:23 +01007273 else
7274 error = "critical error";
7275 SEND_ERR(px, "Lua function '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007276 rule->arg.hlua_rule->fcn->name, error);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007277 goto end;
Thierry FOURNIERbabae282015-09-17 11:36:37 +02007278 }
7279
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007280 /* Check stack available size. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01007281 if (!lua_checkstack(s->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02007282 SEND_ERR(px, "Lua function '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007283 rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007284 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007285 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007286 }
7287
7288 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +01007289 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 +01007290
Willy Tarreau87b09662015-04-03 00:22:06 +02007291 /* Create and and push object stream in the stack. */
Christopher Fauletbfab2dd2019-07-26 15:09:53 +02007292 if (!hlua_txn_new(s->hlua->T, s, px, dir, hflags)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02007293 SEND_ERR(px, "Lua function '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007294 rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007295 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007296 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007297 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01007298 s->hlua->nargs = 1;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007299
7300 /* push keywords in the stack. */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007301 for (arg = rule->arg.hlua_rule->args; arg && *arg; arg++) {
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01007302 if (!lua_checkstack(s->hlua->T, 1)) {
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02007303 SEND_ERR(px, "Lua function '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007304 rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007305 RESET_SAFE_LJMP(s->hlua);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007306 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007307 }
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01007308 lua_pushstring(s->hlua->T, *arg);
7309 s->hlua->nargs++;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007310 }
7311
Thierry FOURNIERbabae282015-09-17 11:36:37 +02007312 /* Now the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007313 RESET_SAFE_LJMP(s->hlua);
Thierry FOURNIERbabae282015-09-17 11:36:37 +02007314
Thierry FOURNIERbd413492015-03-03 16:52:26 +01007315 /* We must initialize the execution timeouts. */
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01007316 s->hlua->max_time = hlua_timeout_session;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007317 }
7318
7319 /* Execute the function. */
Christopher Faulet105ba6c2019-12-18 14:41:51 +01007320 switch (hlua_ctx_resume(s->hlua, !(flags & ACT_OPT_FINAL))) {
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007321 /* finished. */
7322 case HLUA_E_OK:
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007323 /* Catch the return value */
7324 if (lua_gettop(s->hlua->T) > 0)
7325 act_ret = lua_tointeger(s->hlua->T, -1);
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007326
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01007327 /* Set timeout in the required channel. */
Christopher Faulet498c4832020-07-28 11:59:58 +02007328 if (act_ret == ACT_RET_YIELD) {
7329 if (flags & ACT_OPT_FINAL)
7330 goto err_yield;
7331
Christopher Faulet8f587ea2020-07-28 12:01:55 +02007332 if (dir == SMP_OPT_DIR_REQ)
7333 s->req.analyse_exp = tick_first((tick_is_expired(s->req.analyse_exp, now_ms) ? 0 : s->req.analyse_exp),
7334 s->hlua->wake_time);
7335 else
7336 s->res.analyse_exp = tick_first((tick_is_expired(s->res.analyse_exp, now_ms) ? 0 : s->res.analyse_exp),
7337 s->hlua->wake_time);
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01007338 }
7339 goto end;
7340
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007341 /* yield. */
7342 case HLUA_E_AGAIN:
Thierry FOURNIERc42c1ae2015-03-03 17:17:55 +01007343 /* Set timeout in the required channel. */
Christopher Faulet8f587ea2020-07-28 12:01:55 +02007344 if (dir == SMP_OPT_DIR_REQ)
7345 s->req.analyse_exp = tick_first((tick_is_expired(s->req.analyse_exp, now_ms) ? 0 : s->req.analyse_exp),
7346 s->hlua->wake_time);
7347 else
7348 s->res.analyse_exp = tick_first((tick_is_expired(s->res.analyse_exp, now_ms) ? 0 : s->res.analyse_exp),
7349 s->hlua->wake_time);
7350
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007351 /* Some actions can be wake up when a "write" event
7352 * is detected on a response channel. This is useful
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08007353 * only for actions targeted on the requests.
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007354 */
Christopher Faulet51fa3582019-07-26 14:54:52 +02007355 if (HLUA_IS_WAKERESWR(s->hlua))
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01007356 s->res.flags |= CF_WAKE_WRITE;
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01007357 if (HLUA_IS_WAKEREQWR(s->hlua))
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01007358 s->req.flags |= CF_WAKE_WRITE;
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007359 act_ret = ACT_RET_YIELD;
7360 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007361
7362 /* finished with error. */
7363 case HLUA_E_ERRMSG:
7364 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02007365 SEND_ERR(px, "Lua function '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007366 rule->arg.hlua_rule->fcn->name, lua_tostring(s->hlua->T, -1));
Thierry FOURNIER2c8b54e2016-12-17 12:45:32 +01007367 lua_pop(s->hlua->T, 1);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007368 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007369
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007370 case HLUA_E_ETMOUT:
Thierry Fournierad5345f2020-11-29 02:05:57 +01007371 SEND_ERR(px, "Lua function '%s': execution timeout.\n", rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007372 goto end;
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007373
7374 case HLUA_E_NOMEM:
Thierry Fournierad5345f2020-11-29 02:05:57 +01007375 SEND_ERR(px, "Lua function '%s': out of memory error.\n", rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007376 goto end;
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007377
7378 case HLUA_E_YIELD:
Christopher Faulet498c4832020-07-28 11:59:58 +02007379 err_yield:
7380 act_ret = ACT_RET_CONT;
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007381 SEND_ERR(px, "Lua function '%s': aborting Lua processing on expired timeout.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007382 rule->arg.hlua_rule->fcn->name);
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007383 goto end;
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007384
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007385 case HLUA_E_ERR:
7386 /* Display log. */
Thierry FOURNIER23bc3752015-09-11 19:15:43 +02007387 SEND_ERR(px, "Lua function '%s' return an unknown error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007388 rule->arg.hlua_rule->fcn->name);
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007389
7390 default:
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007391 goto end;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007392 }
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007393
7394 end:
Christopher Faulet2361fd92020-07-30 10:40:58 +02007395 if (act_ret != ACT_RET_YIELD && s->hlua)
Christopher Faulet8f587ea2020-07-28 12:01:55 +02007396 s->hlua->wake_time = TICK_ETERNITY;
Christopher Faulet7716cdf2020-01-29 11:53:30 +01007397 return act_ret;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007398}
7399
Willy Tarreau144f84a2021-03-02 16:09:26 +01007400struct task *hlua_applet_wakeup(struct task *t, void *context, unsigned int state)
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007401{
Olivier Houchard9f6af332018-05-25 14:04:04 +02007402 struct appctx *ctx = context;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007403
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007404 appctx_wakeup(ctx);
Willy Tarreaud9587412017-08-23 16:07:33 +02007405 t->expire = TICK_ETERNITY;
Willy Tarreaud1aa41f2017-07-21 16:41:56 +02007406 return t;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007407}
7408
7409static int hlua_applet_tcp_init(struct appctx *ctx, struct proxy *px, struct stream *strm)
7410{
7411 struct stream_interface *si = ctx->owner;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007412 struct hlua *hlua;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007413 struct task *task;
7414 char **arg;
Thierry Fournierfd107a22016-02-19 19:57:23 +01007415 const char *error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007416
Willy Tarreaubafbe012017-11-24 17:34:44 +01007417 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007418 if (!hlua) {
7419 SEND_ERR(px, "Lua applet tcp '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007420 ctx->rule->arg.hlua_rule->fcn->name);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007421 return 0;
7422 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007423 HLUA_INIT(hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007424 ctx->ctx.hlua_apptcp.hlua = hlua;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007425 ctx->ctx.hlua_apptcp.flags = 0;
7426
7427 /* Create task used by signal to wakeup applets. */
Willy Tarreau5f4a47b2017-10-31 15:59:32 +01007428 task = task_new(tid_bit);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007429 if (!task) {
7430 SEND_ERR(px, "Lua applet tcp '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007431 ctx->rule->arg.hlua_rule->fcn->name);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007432 return 0;
7433 }
7434 task->nice = 0;
7435 task->context = ctx;
7436 task->process = hlua_applet_wakeup;
7437 ctx->ctx.hlua_apptcp.task = task;
7438
7439 /* In the execution wrappers linked with a stream, the
7440 * Lua context can be not initialized. This behavior
7441 * permits to save performances because a systematic
7442 * Lua initialization cause 5% performances loss.
7443 */
Thierry Fournierc7492592020-11-28 23:57:24 +01007444 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 +02007445 SEND_ERR(px, "Lua applet tcp '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007446 ctx->rule->arg.hlua_rule->fcn->name);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007447 return 0;
7448 }
7449
7450 /* Set timeout according with the applet configuration. */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02007451 hlua->max_time = ctx->applet->timeout;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007452
7453 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007454 if (!SET_SAFE_LJMP(hlua)) {
Thierry Fournierfd107a22016-02-19 19:57:23 +01007455 if (lua_type(hlua->T, -1) == LUA_TSTRING)
7456 error = lua_tostring(hlua->T, -1);
7457 else
7458 error = "critical error";
7459 SEND_ERR(px, "Lua applet tcp '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007460 ctx->rule->arg.hlua_rule->fcn->name, error);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007461 return 0;
7462 }
7463
7464 /* Check stack available size. */
7465 if (!lua_checkstack(hlua->T, 1)) {
7466 SEND_ERR(px, "Lua applet tcp '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007467 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007468 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007469 return 0;
7470 }
7471
7472 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +01007473 lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, ctx->rule->arg.hlua_rule->fcn->function_ref[hlua->state_id]);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007474
7475 /* Create and and push object stream in the stack. */
7476 if (!hlua_applet_tcp_new(hlua->T, ctx)) {
7477 SEND_ERR(px, "Lua applet tcp '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007478 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007479 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007480 return 0;
7481 }
7482 hlua->nargs = 1;
7483
7484 /* push keywords in the stack. */
7485 for (arg = ctx->rule->arg.hlua_rule->args; arg && *arg; arg++) {
7486 if (!lua_checkstack(hlua->T, 1)) {
7487 SEND_ERR(px, "Lua applet tcp '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007488 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007489 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007490 return 0;
7491 }
7492 lua_pushstring(hlua->T, *arg);
7493 hlua->nargs++;
7494 }
7495
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007496 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007497
7498 /* Wakeup the applet ASAP. */
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01007499 si_cant_get(si);
Willy Tarreau3367d412018-11-15 10:57:41 +01007500 si_rx_endp_more(si);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007501
7502 return 1;
7503}
7504
Willy Tarreau60409db2019-08-21 14:14:50 +02007505void hlua_applet_tcp_fct(struct appctx *ctx)
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007506{
7507 struct stream_interface *si = ctx->owner;
7508 struct stream *strm = si_strm(si);
7509 struct channel *res = si_ic(si);
7510 struct act_rule *rule = ctx->rule;
7511 struct proxy *px = strm->be;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007512 struct hlua *hlua = ctx->ctx.hlua_apptcp.hlua;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007513
7514 /* The applet execution is already done. */
Olivier Houchard594c8c52018-08-28 14:41:31 +02007515 if (ctx->ctx.hlua_apptcp.flags & APPLET_DONE) {
7516 /* eat the whole request */
7517 co_skip(si_oc(si), co_data(si_oc(si)));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007518 return;
Olivier Houchard594c8c52018-08-28 14:41:31 +02007519 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007520
7521 /* If the stream is disconnect or closed, ldo nothing. */
7522 if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO))
7523 return;
7524
7525 /* Execute the function. */
7526 switch (hlua_ctx_resume(hlua, 1)) {
7527 /* finished. */
7528 case HLUA_E_OK:
7529 ctx->ctx.hlua_apptcp.flags |= APPLET_DONE;
7530
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007531 /* eat the whole request */
Willy Tarreaua79021a2018-06-15 18:07:57 +02007532 co_skip(si_oc(si), co_data(si_oc(si)));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007533 res->flags |= CF_READ_NULL;
7534 si_shutr(si);
7535 return;
7536
7537 /* yield. */
7538 case HLUA_E_AGAIN:
Thierry Fournier0164f202016-02-20 17:47:43 +01007539 if (hlua->wake_time != TICK_ETERNITY)
7540 task_schedule(ctx->ctx.hlua_apptcp.task, hlua->wake_time);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007541 return;
7542
7543 /* finished with error. */
7544 case HLUA_E_ERRMSG:
7545 /* Display log. */
7546 SEND_ERR(px, "Lua applet tcp '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007547 rule->arg.hlua_rule->fcn->name, lua_tostring(hlua->T, -1));
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007548 lua_pop(hlua->T, 1);
7549 goto error;
7550
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007551 case HLUA_E_ETMOUT:
7552 SEND_ERR(px, "Lua applet tcp '%s': execution timeout.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007553 rule->arg.hlua_rule->fcn->name);
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007554 goto error;
7555
7556 case HLUA_E_NOMEM:
7557 SEND_ERR(px, "Lua applet tcp '%s': out of memory error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007558 rule->arg.hlua_rule->fcn->name);
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007559 goto error;
7560
7561 case HLUA_E_YIELD: /* unexpected */
7562 SEND_ERR(px, "Lua applet tcp '%s': yield not allowed.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007563 rule->arg.hlua_rule->fcn->name);
Thierry Fournierd5b073c2018-05-21 19:42:47 +02007564 goto error;
7565
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007566 case HLUA_E_ERR:
7567 /* Display log. */
7568 SEND_ERR(px, "Lua applet tcp '%s' return an unknown error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007569 rule->arg.hlua_rule->fcn->name);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007570 goto error;
7571
7572 default:
7573 goto error;
7574 }
7575
7576error:
7577
7578 /* For all other cases, just close the stream. */
7579 si_shutw(si);
7580 si_shutr(si);
7581 ctx->ctx.hlua_apptcp.flags |= APPLET_DONE;
7582}
7583
7584static void hlua_applet_tcp_release(struct appctx *ctx)
7585{
Olivier Houchard3f795f72019-04-17 22:51:06 +02007586 task_destroy(ctx->ctx.hlua_apptcp.task);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007587 ctx->ctx.hlua_apptcp.task = NULL;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007588 hlua_ctx_destroy(ctx->ctx.hlua_apptcp.hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007589 ctx->ctx.hlua_apptcp.hlua = NULL;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02007590}
7591
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007592/* The function returns 1 if the initialisation is complete, 0 if
7593 * an errors occurs and -1 if more data are required for initializing
7594 * the applet.
7595 */
7596static int hlua_applet_http_init(struct appctx *ctx, struct proxy *px, struct stream *strm)
7597{
7598 struct stream_interface *si = ctx->owner;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007599 struct http_txn *txn;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007600 struct hlua *hlua;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007601 char **arg;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007602 struct task *task;
Thierry Fournierfd107a22016-02-19 19:57:23 +01007603 const char *error;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007604
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007605 txn = strm->txn;
Willy Tarreaubafbe012017-11-24 17:34:44 +01007606 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007607 if (!hlua) {
7608 SEND_ERR(px, "Lua applet http '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007609 ctx->rule->arg.hlua_rule->fcn->name);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007610 return 0;
7611 }
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007612 HLUA_INIT(hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007613 ctx->ctx.hlua_apphttp.hlua = hlua;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007614 ctx->ctx.hlua_apphttp.left_bytes = -1;
7615 ctx->ctx.hlua_apphttp.flags = 0;
7616
Thierry FOURNIERd93ea2b2015-12-20 19:14:52 +01007617 if (txn->req.flags & HTTP_MSGF_VER_11)
7618 ctx->ctx.hlua_apphttp.flags |= APPLET_HTTP11;
7619
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007620 /* Create task used by signal to wakeup applets. */
Willy Tarreau5f4a47b2017-10-31 15:59:32 +01007621 task = task_new(tid_bit);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007622 if (!task) {
7623 SEND_ERR(px, "Lua applet http '%s': out of memory.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007624 ctx->rule->arg.hlua_rule->fcn->name);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007625 return 0;
7626 }
7627 task->nice = 0;
7628 task->context = ctx;
7629 task->process = hlua_applet_wakeup;
7630 ctx->ctx.hlua_apphttp.task = task;
7631
7632 /* In the execution wrappers linked with a stream, the
7633 * Lua context can be not initialized. This behavior
7634 * permits to save performances because a systematic
7635 * Lua initialization cause 5% performances loss.
7636 */
Thierry Fournierc7492592020-11-28 23:57:24 +01007637 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 +02007638 SEND_ERR(px, "Lua applet http '%s': can't initialize Lua context.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007639 ctx->rule->arg.hlua_rule->fcn->name);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007640 return 0;
7641 }
7642
7643 /* Set timeout according with the applet configuration. */
Thierry FOURNIER10770fa2015-09-29 01:59:42 +02007644 hlua->max_time = ctx->applet->timeout;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007645
7646 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007647 if (!SET_SAFE_LJMP(hlua)) {
Thierry Fournierfd107a22016-02-19 19:57:23 +01007648 if (lua_type(hlua->T, -1) == LUA_TSTRING)
7649 error = lua_tostring(hlua->T, -1);
7650 else
7651 error = "critical error";
7652 SEND_ERR(px, "Lua applet http '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007653 ctx->rule->arg.hlua_rule->fcn->name, error);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007654 return 0;
7655 }
7656
7657 /* Check stack available size. */
7658 if (!lua_checkstack(hlua->T, 1)) {
7659 SEND_ERR(px, "Lua applet http '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007660 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007661 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007662 return 0;
7663 }
7664
7665 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +01007666 lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, ctx->rule->arg.hlua_rule->fcn->function_ref[hlua->state_id]);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007667
7668 /* Create and and push object stream in the stack. */
7669 if (!hlua_applet_http_new(hlua->T, ctx)) {
7670 SEND_ERR(px, "Lua applet http '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007671 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007672 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007673 return 0;
7674 }
7675 hlua->nargs = 1;
7676
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007677 /* push keywords in the stack. */
7678 for (arg = ctx->rule->arg.hlua_rule->args; arg && *arg; arg++) {
7679 if (!lua_checkstack(hlua->T, 1)) {
7680 SEND_ERR(px, "Lua applet http '%s': full stack.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007681 ctx->rule->arg.hlua_rule->fcn->name);
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007682 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007683 return 0;
7684 }
7685 lua_pushstring(hlua->T, *arg);
7686 hlua->nargs++;
7687 }
7688
Thierry Fournier7cbe5042020-11-28 17:02:21 +01007689 RESET_SAFE_LJMP(hlua);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007690
7691 /* Wakeup the applet when data is ready for read. */
Willy Tarreau0cd3bd62018-11-06 18:46:37 +01007692 si_cant_get(si);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007693
7694 return 1;
7695}
7696
Willy Tarreau60409db2019-08-21 14:14:50 +02007697void hlua_applet_http_fct(struct appctx *ctx)
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007698{
7699 struct stream_interface *si = ctx->owner;
7700 struct stream *strm = si_strm(si);
7701 struct channel *req = si_oc(si);
7702 struct channel *res = si_ic(si);
7703 struct act_rule *rule = ctx->rule;
7704 struct proxy *px = strm->be;
7705 struct hlua *hlua = ctx->ctx.hlua_apphttp.hlua;
7706 struct htx *req_htx, *res_htx;
7707
7708 res_htx = htx_from_buf(&res->buf);
7709
7710 /* If the stream is disconnect or closed, ldo nothing. */
7711 if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO))
7712 goto out;
7713
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05007714 /* Check if the input buffer is available. */
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007715 if (!b_size(&res->buf)) {
7716 si_rx_room_blk(si);
7717 goto out;
7718 }
7719 /* check that the output is not closed */
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01007720 if (res->flags & (CF_SHUTW|CF_SHUTW_NOW|CF_SHUTR))
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007721 ctx->ctx.hlua_apphttp.flags |= APPLET_DONE;
7722
7723 /* Set the currently running flag. */
7724 if (!HLUA_IS_RUNNING(hlua) &&
7725 !(ctx->ctx.hlua_apphttp.flags & APPLET_DONE)) {
Christopher Fauletbd878d22021-04-28 10:50:21 +02007726 if (!co_data(req)) {
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007727 si_cant_get(si);
7728 goto out;
7729 }
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007730 }
7731
7732 /* Executes The applet if it is not done. */
7733 if (!(ctx->ctx.hlua_apphttp.flags & APPLET_DONE)) {
7734
7735 /* Execute the function. */
7736 switch (hlua_ctx_resume(hlua, 1)) {
7737 /* finished. */
7738 case HLUA_E_OK:
7739 ctx->ctx.hlua_apphttp.flags |= APPLET_DONE;
7740 break;
7741
7742 /* yield. */
7743 case HLUA_E_AGAIN:
7744 if (hlua->wake_time != TICK_ETERNITY)
7745 task_schedule(ctx->ctx.hlua_apphttp.task, hlua->wake_time);
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01007746 goto out;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007747
7748 /* finished with error. */
7749 case HLUA_E_ERRMSG:
7750 /* Display log. */
7751 SEND_ERR(px, "Lua applet http '%s': %s.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007752 rule->arg.hlua_rule->fcn->name, lua_tostring(hlua->T, -1));
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007753 lua_pop(hlua->T, 1);
7754 goto error;
7755
7756 case HLUA_E_ETMOUT:
7757 SEND_ERR(px, "Lua applet http '%s': execution timeout.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007758 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007759 goto error;
7760
7761 case HLUA_E_NOMEM:
7762 SEND_ERR(px, "Lua applet http '%s': out of memory error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007763 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007764 goto error;
7765
7766 case HLUA_E_YIELD: /* unexpected */
7767 SEND_ERR(px, "Lua applet http '%s': yield not allowed.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007768 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007769 goto error;
7770
7771 case HLUA_E_ERR:
7772 /* Display log. */
7773 SEND_ERR(px, "Lua applet http '%s' return an unknown error.\n",
Thierry Fournierad5345f2020-11-29 02:05:57 +01007774 rule->arg.hlua_rule->fcn->name);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007775 goto error;
7776
7777 default:
7778 goto error;
7779 }
7780 }
7781
7782 if (ctx->ctx.hlua_apphttp.flags & APPLET_DONE) {
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01007783 if (ctx->ctx.hlua_apphttp.flags & APPLET_RSP_SENT)
7784 goto done;
7785
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007786 if (!(ctx->ctx.hlua_apphttp.flags & APPLET_HDR_SENT))
7787 goto error;
7788
Christopher Fauletd1ac2b92020-12-02 19:12:22 +01007789 /* no more data are expected. Don't add TLR because mux-h1 will take care of it */
7790 res_htx->flags |= HTX_FL_EOM;
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01007791 strm->txn->status = ctx->ctx.hlua_apphttp.status;
7792 ctx->ctx.hlua_apphttp.flags |= APPLET_RSP_SENT;
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007793 }
7794
7795 done:
7796 if (ctx->ctx.hlua_apphttp.flags & APPLET_DONE) {
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01007797 if (!(res->flags & CF_SHUTR)) {
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007798 res->flags |= CF_READ_NULL;
Christopher Faulet56a3d6e2019-02-27 22:06:23 +01007799 si_shutr(si);
7800 }
7801
7802 /* eat the whole request */
7803 if (co_data(req)) {
7804 req_htx = htx_from_buf(&req->buf);
7805 co_htx_skip(req, req_htx, co_data(req));
7806 htx_to_buf(req_htx, &req->buf);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007807 }
7808 }
7809
7810 out:
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007811 htx_to_buf(res_htx, &res->buf);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007812 return;
7813
7814 error:
7815
7816 /* If we are in HTTP mode, and we are not send any
7817 * data, return a 500 server error in best effort:
7818 * if there is no room available in the buffer,
7819 * just close the connection.
7820 */
7821 if (!(ctx->ctx.hlua_apphttp.flags & APPLET_HDR_SENT)) {
Christopher Fauletf7346382019-07-17 22:02:08 +02007822 struct buffer *err = &http_err_chunks[HTTP_ERR_500];
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007823
7824 channel_erase(res);
7825 res->buf.data = b_data(err);
7826 memcpy(res->buf.area, b_head(err), b_data(err));
7827 res_htx = htx_from_buf(&res->buf);
Christopher Fauletf6cce3f2019-02-27 21:20:09 +01007828 channel_add_input(res, res_htx->data);
Christopher Faulet9c832fc2018-12-14 13:34:05 +01007829 }
7830 if (!(strm->flags & SF_ERR_MASK))
7831 strm->flags |= SF_ERR_RESOURCE;
7832 ctx->ctx.hlua_apphttp.flags |= APPLET_DONE;
7833 goto done;
7834}
7835
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007836static void hlua_applet_http_release(struct appctx *ctx)
7837{
Olivier Houchard3f795f72019-04-17 22:51:06 +02007838 task_destroy(ctx->ctx.hlua_apphttp.task);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007839 ctx->ctx.hlua_apphttp.task = NULL;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007840 hlua_ctx_destroy(ctx->ctx.hlua_apphttp.hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01007841 ctx->ctx.hlua_apphttp.hlua = NULL;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007842}
7843
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007844/* global {tcp|http}-request parser. Return ACT_RET_PRS_OK in
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05007845 * success case, else return ACT_RET_PRS_ERR.
Thierry FOURNIERbabae282015-09-17 11:36:37 +02007846 *
7847 * This function can fail with an abort() due to an Lua critical error.
7848 * We are in the configuration parsing process of HAProxy, this abort() is
7849 * tolerated.
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007850 */
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007851static enum act_parse_ret action_register_lua(const char **args, int *cur_arg, struct proxy *px,
7852 struct act_rule *rule, char **err)
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007853{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02007854 struct hlua_function *fcn = rule->kw->private;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007855 int i;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007856
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007857 /* Memory for the rule. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02007858 rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007859 if (!rule->arg.hlua_rule) {
7860 memprintf(err, "out of memory error");
Christopher Faulet528526f2021-04-12 14:37:32 +02007861 goto error;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007862 }
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007863
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007864 /* Memory for arguments. */
Tim Duesterhuse52b6e52020-09-12 20:26:43 +02007865 rule->arg.hlua_rule->args = calloc(fcn->nargs + 1,
7866 sizeof(*rule->arg.hlua_rule->args));
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007867 if (!rule->arg.hlua_rule->args) {
7868 memprintf(err, "out of memory error");
Christopher Faulet528526f2021-04-12 14:37:32 +02007869 goto error;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007870 }
7871
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007872 /* Reference the Lua function and store the reference. */
Thierry Fournierad5345f2020-11-29 02:05:57 +01007873 rule->arg.hlua_rule->fcn = fcn;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007874
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007875 /* Expect some arguments */
7876 for (i = 0; i < fcn->nargs; i++) {
Thierry FOURNIER1725c2e2019-01-06 19:38:49 +01007877 if (*args[*cur_arg] == '\0') {
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007878 memprintf(err, "expect %d arguments", fcn->nargs);
Christopher Faulet528526f2021-04-12 14:37:32 +02007879 goto error;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007880 }
Thierry FOURNIER1725c2e2019-01-06 19:38:49 +01007881 rule->arg.hlua_rule->args[i] = strdup(args[*cur_arg]);
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007882 if (!rule->arg.hlua_rule->args[i]) {
7883 memprintf(err, "out of memory error");
Christopher Faulet528526f2021-04-12 14:37:32 +02007884 goto error;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007885 }
7886 (*cur_arg)++;
7887 }
7888 rule->arg.hlua_rule->args[i] = NULL;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007889
Thierry FOURNIER42148732015-09-02 17:17:33 +02007890 rule->action = ACT_CUSTOM;
Thierry FOURNIER4dc15d12015-08-06 18:25:56 +02007891 rule->action_ptr = hlua_action;
Thierry FOURNIERafa80492015-08-19 09:04:15 +02007892 return ACT_RET_PRS_OK;
Christopher Faulet528526f2021-04-12 14:37:32 +02007893
7894 error:
7895 if (rule->arg.hlua_rule) {
7896 if (rule->arg.hlua_rule->args) {
7897 for (i = 0; i < fcn->nargs; i++)
7898 ha_free(&rule->arg.hlua_rule->args[i]);
7899 ha_free(&rule->arg.hlua_rule->args);
7900 }
7901 ha_free(&rule->arg.hlua_rule);
7902 }
7903 return ACT_RET_PRS_ERR;
Thierry FOURNIER258d8aa2015-02-16 20:23:40 +01007904}
7905
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007906static enum act_parse_ret action_register_service_http(const char **args, int *cur_arg, struct proxy *px,
7907 struct act_rule *rule, char **err)
7908{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02007909 struct hlua_function *fcn = rule->kw->private;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007910
Thierry FOURNIER718e2a72015-12-20 20:13:14 +01007911 /* HTTP applets are forbidden in tcp-request rules.
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05007912 * HTTP applet request requires everything initialized by
Thierry FOURNIER718e2a72015-12-20 20:13:14 +01007913 * "http_process_request" (analyzer flag AN_REQ_HTTP_INNER).
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05007914 * The applet will be immediately initialized, but its before
Thierry FOURNIER718e2a72015-12-20 20:13:14 +01007915 * the call of this analyzer.
7916 */
7917 if (rule->from != ACT_F_HTTP_REQ) {
7918 memprintf(err, "HTTP applets are forbidden from 'tcp-request' rulesets");
7919 return ACT_RET_PRS_ERR;
7920 }
7921
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007922 /* Memory for the rule. */
7923 rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
7924 if (!rule->arg.hlua_rule) {
7925 memprintf(err, "out of memory error");
7926 return ACT_RET_PRS_ERR;
7927 }
7928
7929 /* Reference the Lua function and store the reference. */
Thierry Fournierad5345f2020-11-29 02:05:57 +01007930 rule->arg.hlua_rule->fcn = fcn;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02007931
7932 /* TODO: later accept arguments. */
7933 rule->arg.hlua_rule->args = NULL;
7934
7935 /* Add applet pointer in the rule. */
7936 rule->applet.obj_type = OBJ_TYPE_APPLET;
7937 rule->applet.name = fcn->name;
7938 rule->applet.init = hlua_applet_http_init;
7939 rule->applet.fct = hlua_applet_http_fct;
7940 rule->applet.release = hlua_applet_http_release;
7941 rule->applet.timeout = hlua_timeout_applet;
7942
7943 return ACT_RET_PRS_OK;
7944}
7945
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007946/* This function is an LUA binding used for registering
7947 * "sample-conv" functions. It expects a converter name used
7948 * in the haproxy configuration file, and an LUA function.
7949 */
7950__LJMP static int hlua_register_action(lua_State *L)
7951{
Christopher Faulet4fc9da02021-04-12 15:08:12 +02007952 struct action_kw_list *akl = NULL;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007953 const char *name;
7954 int ref;
7955 int len;
Christopher Faulet4fc9da02021-04-12 15:08:12 +02007956 struct hlua_function *fcn = NULL;
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007957 int nargs;
Thierry Fournierf67442e2020-11-28 20:41:07 +01007958 struct buffer *trash;
7959 struct action_kw *akw;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007960
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007961 /* Initialise the number of expected arguments at 0. */
7962 nargs = 0;
7963
7964 if (lua_gettop(L) < 3 || lua_gettop(L) > 4)
7965 WILL_LJMP(luaL_error(L, "'register_action' needs between 3 and 4 arguments"));
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007966
7967 /* First argument : converter name. */
7968 name = MAY_LJMP(luaL_checkstring(L, 1));
7969
7970 /* Second argument : environment. */
7971 if (lua_type(L, 2) != LUA_TTABLE)
7972 WILL_LJMP(luaL_error(L, "register_action: second argument must be a table of strings"));
7973
7974 /* Third argument : lua function. */
7975 ref = MAY_LJMP(hlua_checkfunction(L, 3));
7976
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08007977 /* Fourth argument : number of mandatory arguments expected on the configuration line. */
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01007978 if (lua_gettop(L) >= 4)
7979 nargs = MAY_LJMP(luaL_checkinteger(L, 4));
7980
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08007981 /* browse the second argument as an array. */
Thierry FOURNIER8255a752015-09-23 21:03:35 +02007982 lua_pushnil(L);
7983 while (lua_next(L, 2) != 0) {
7984 if (lua_type(L, -1) != LUA_TSTRING)
7985 WILL_LJMP(luaL_error(L, "register_action: second argument must be a table of strings"));
7986
Thierry Fournierf67442e2020-11-28 20:41:07 +01007987 /* Check if action exists */
7988 trash = get_trash_chunk();
7989 chunk_printf(trash, "lua.%s", name);
7990 if (strcmp(lua_tostring(L, -1), "tcp-req") == 0) {
7991 akw = tcp_req_cont_action(trash->area);
7992 } else if (strcmp(lua_tostring(L, -1), "tcp-res") == 0) {
7993 akw = tcp_res_cont_action(trash->area);
7994 } else if (strcmp(lua_tostring(L, -1), "http-req") == 0) {
7995 akw = action_http_req_custom(trash->area);
7996 } else if (strcmp(lua_tostring(L, -1), "http-res") == 0) {
7997 akw = action_http_res_custom(trash->area);
7998 } else {
7999 akw = NULL;
8000 }
8001 if (akw != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +01008002 fcn = akw->private;
8003 if (fcn->function_ref[hlua_state_id] != -1) {
8004 ha_warning("Trying to register action 'lua.%s' more than once. "
8005 "This will become a hard error in version 2.5.\n", name);
8006 }
8007 fcn->function_ref[hlua_state_id] = ref;
8008
8009 /* pop the environment string. */
8010 lua_pop(L, 1);
8011 continue;
Thierry Fournierf67442e2020-11-28 20:41:07 +01008012 }
8013
Thierry FOURNIER8255a752015-09-23 21:03:35 +02008014 /* Check required environment. Only accepted "http" or "tcp". */
8015 /* Allocate and fill the sample fetch keyword struct. */
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02008016 akl = calloc(1, sizeof(*akl) + sizeof(struct action_kw) * 2);
Thierry FOURNIER8255a752015-09-23 21:03:35 +02008017 if (!akl)
Christopher Faulet4fc9da02021-04-12 15:08:12 +02008018 goto alloc_error;;
Thierry Fournier62a22aa2020-11-28 21:06:35 +01008019 fcn = new_hlua_function();
Thierry FOURNIER8255a752015-09-23 21:03:35 +02008020 if (!fcn)
Christopher Faulet4fc9da02021-04-12 15:08:12 +02008021 goto alloc_error;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02008022
8023 /* Fill fcn. */
8024 fcn->name = strdup(name);
8025 if (!fcn->name)
Christopher Faulet4fc9da02021-04-12 15:08:12 +02008026 goto alloc_error;
Thierry Fournierc7492592020-11-28 23:57:24 +01008027 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02008028
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07008029 /* Set the expected number of arguments. */
Thierry FOURNIER / OZON.IO4b123be2016-12-09 18:03:31 +01008030 fcn->nargs = nargs;
8031
Thierry FOURNIER8255a752015-09-23 21:03:35 +02008032 /* List head */
8033 akl->list.n = akl->list.p = NULL;
8034
Thierry FOURNIER8255a752015-09-23 21:03:35 +02008035 /* action keyword. */
8036 len = strlen("lua.") + strlen(name) + 1;
Thierry FOURNIER3c7a77c2015-09-26 00:51:16 +02008037 akl->kw[0].kw = calloc(1, len);
Thierry FOURNIER8255a752015-09-23 21:03:35 +02008038 if (!akl->kw[0].kw)
Christopher Faulet4fc9da02021-04-12 15:08:12 +02008039 goto alloc_error;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02008040
8041 snprintf((char *)akl->kw[0].kw, len, "lua.%s", name);
8042
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02008043 akl->kw[0].flags = 0;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02008044 akl->kw[0].private = fcn;
8045 akl->kw[0].parse = action_register_lua;
8046
8047 /* select the action registering point. */
8048 if (strcmp(lua_tostring(L, -1), "tcp-req") == 0)
8049 tcp_req_cont_keywords_register(akl);
8050 else if (strcmp(lua_tostring(L, -1), "tcp-res") == 0)
8051 tcp_res_cont_keywords_register(akl);
8052 else if (strcmp(lua_tostring(L, -1), "http-req") == 0)
8053 http_req_keywords_register(akl);
8054 else if (strcmp(lua_tostring(L, -1), "http-res") == 0)
8055 http_res_keywords_register(akl);
Christopher Faulet4fc9da02021-04-12 15:08:12 +02008056 else {
8057 release_hlua_function(fcn);
8058 if (akl)
8059 ha_free((char **)&(akl->kw[0].kw));
8060 ha_free(&akl);
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01008061 WILL_LJMP(luaL_error(L, "Lua action environment '%s' is unknown. "
Thierry FOURNIER8255a752015-09-23 21:03:35 +02008062 "'tcp-req', 'tcp-res', 'http-req' or 'http-res' "
8063 "are expected.", lua_tostring(L, -1)));
Christopher Faulet4fc9da02021-04-12 15:08:12 +02008064 }
Thierry FOURNIER8255a752015-09-23 21:03:35 +02008065
8066 /* pop the environment string. */
8067 lua_pop(L, 1);
Christopher Faulet4fc9da02021-04-12 15:08:12 +02008068
8069 /* reset for next loop */
8070 akl = NULL;
8071 fcn = NULL;
Thierry FOURNIER8255a752015-09-23 21:03:35 +02008072 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02008073 return ACT_RET_PRS_OK;
Christopher Faulet4fc9da02021-04-12 15:08:12 +02008074
8075 alloc_error:
8076 release_hlua_function(fcn);
8077 ha_free(&akl);
8078 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
8079 return 0; /* Never reached */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02008080}
8081
8082static enum act_parse_ret action_register_service_tcp(const char **args, int *cur_arg, struct proxy *px,
8083 struct act_rule *rule, char **err)
8084{
Vincent Bernat3c2f2f22016-04-03 13:48:42 +02008085 struct hlua_function *fcn = rule->kw->private;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02008086
Christopher Faulet280f85b2019-07-15 15:02:04 +02008087 if (px->mode == PR_MODE_HTTP) {
8088 memprintf(err, "Lua TCP services cannot be used on HTTP proxies");
Christopher Fauletafd8f102018-11-08 11:34:21 +01008089 return ACT_RET_PRS_ERR;
8090 }
8091
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02008092 /* Memory for the rule. */
8093 rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
8094 if (!rule->arg.hlua_rule) {
8095 memprintf(err, "out of memory error");
8096 return ACT_RET_PRS_ERR;
8097 }
Thierry FOURNIER8255a752015-09-23 21:03:35 +02008098
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02008099 /* Reference the Lua function and store the reference. */
Thierry Fournierad5345f2020-11-29 02:05:57 +01008100 rule->arg.hlua_rule->fcn = fcn;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02008101
8102 /* TODO: later accept arguments. */
8103 rule->arg.hlua_rule->args = NULL;
8104
8105 /* Add applet pointer in the rule. */
8106 rule->applet.obj_type = OBJ_TYPE_APPLET;
8107 rule->applet.name = fcn->name;
8108 rule->applet.init = hlua_applet_tcp_init;
8109 rule->applet.fct = hlua_applet_tcp_fct;
8110 rule->applet.release = hlua_applet_tcp_release;
8111 rule->applet.timeout = hlua_timeout_applet;
8112
8113 return 0;
8114}
8115
8116/* This function is an LUA binding used for registering
8117 * "sample-conv" functions. It expects a converter name used
8118 * in the haproxy configuration file, and an LUA function.
8119 */
8120__LJMP static int hlua_register_service(lua_State *L)
8121{
8122 struct action_kw_list *akl;
8123 const char *name;
8124 const char *env;
8125 int ref;
8126 int len;
Christopher Faulet5c028d72021-04-12 15:11:44 +02008127 struct hlua_function *fcn = NULL;
Thierry Fournierf67442e2020-11-28 20:41:07 +01008128 struct buffer *trash;
8129 struct action_kw *akw;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02008130
8131 MAY_LJMP(check_args(L, 3, "register_service"));
8132
8133 /* First argument : converter name. */
8134 name = MAY_LJMP(luaL_checkstring(L, 1));
8135
8136 /* Second argument : environment. */
8137 env = MAY_LJMP(luaL_checkstring(L, 2));
8138
8139 /* Third argument : lua function. */
8140 ref = MAY_LJMP(hlua_checkfunction(L, 3));
8141
Thierry Fournierf67442e2020-11-28 20:41:07 +01008142 /* Check for service already registered */
8143 trash = get_trash_chunk();
8144 chunk_printf(trash, "lua.%s", name);
8145 akw = service_find(trash->area);
8146 if (akw != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +01008147 fcn = akw->private;
8148 if (fcn->function_ref[hlua_state_id] != -1) {
8149 ha_warning("Trying to register service 'lua.%s' more than once. "
8150 "This will become a hard error in version 2.5.\n", name);
8151 }
8152 fcn->function_ref[hlua_state_id] = ref;
8153 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +01008154 }
8155
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02008156 /* Allocate and fill the sample fetch keyword struct. */
8157 akl = calloc(1, sizeof(*akl) + sizeof(struct action_kw) * 2);
8158 if (!akl)
Christopher Faulet5c028d72021-04-12 15:11:44 +02008159 goto alloc_error;
Thierry Fournier62a22aa2020-11-28 21:06:35 +01008160 fcn = new_hlua_function();
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02008161 if (!fcn)
Christopher Faulet5c028d72021-04-12 15:11:44 +02008162 goto alloc_error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02008163
8164 /* Fill fcn. */
8165 len = strlen("<lua.>") + strlen(name) + 1;
8166 fcn->name = calloc(1, len);
8167 if (!fcn->name)
Christopher Faulet5c028d72021-04-12 15:11:44 +02008168 goto alloc_error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02008169 snprintf((char *)fcn->name, len, "<lua.%s>", name);
Thierry Fournierc7492592020-11-28 23:57:24 +01008170 fcn->function_ref[hlua_state_id] = ref;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02008171
8172 /* List head */
8173 akl->list.n = akl->list.p = NULL;
8174
8175 /* converter keyword. */
8176 len = strlen("lua.") + strlen(name) + 1;
8177 akl->kw[0].kw = calloc(1, len);
8178 if (!akl->kw[0].kw)
Christopher Faulet5c028d72021-04-12 15:11:44 +02008179 goto alloc_error;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02008180
8181 snprintf((char *)akl->kw[0].kw, len, "lua.%s", name);
8182
Thierry FOURNIER / OZON.IO02564fd2016-11-12 11:07:05 +01008183 /* Check required environment. Only accepted "http" or "tcp". */
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02008184 if (strcmp(env, "tcp") == 0)
8185 akl->kw[0].parse = action_register_service_tcp;
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02008186 else if (strcmp(env, "http") == 0)
8187 akl->kw[0].parse = action_register_service_http;
Christopher Faulet5c028d72021-04-12 15:11:44 +02008188 else {
8189 release_hlua_function(fcn);
8190 if (akl)
8191 ha_free((char **)&(akl->kw[0].kw));
8192 ha_free(&akl);
Thierry FOURNIER2986c0d2018-02-25 14:32:36 +01008193 WILL_LJMP(luaL_error(L, "Lua service environment '%s' is unknown. "
Eric Salamafe7456f2017-12-21 14:30:07 +01008194 "'tcp' or 'http' are expected.", env));
Christopher Faulet5c028d72021-04-12 15:11:44 +02008195 }
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02008196
Amaury Denoyellee4a617c2021-05-06 15:33:09 +02008197 akl->kw[0].flags = 0;
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02008198 akl->kw[0].private = fcn;
8199
8200 /* End of array. */
8201 memset(&akl->kw[1], 0, sizeof(*akl->kw));
8202
8203 /* Register this new converter */
8204 service_keywords_register(akl);
8205
Thierry FOURNIER8255a752015-09-23 21:03:35 +02008206 return 0;
Christopher Faulet5c028d72021-04-12 15:11:44 +02008207
8208 alloc_error:
8209 release_hlua_function(fcn);
8210 ha_free(&akl);
8211 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
8212 return 0; /* Never reached */
Thierry FOURNIER8255a752015-09-23 21:03:35 +02008213}
8214
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008215/* This function initialises Lua cli handler. It copies the
8216 * arguments in the Lua stack and create channel IO objects.
8217 */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02008218static int hlua_cli_parse_fct(char **args, char *payload, struct appctx *appctx, void *private)
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008219{
8220 struct hlua *hlua;
8221 struct hlua_function *fcn;
8222 int i;
8223 const char *error;
8224
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008225 fcn = private;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01008226 appctx->ctx.hlua_cli.fcn = private;
8227
Willy Tarreaubafbe012017-11-24 17:34:44 +01008228 hlua = pool_alloc(pool_head_hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01008229 if (!hlua) {
8230 SEND_ERR(NULL, "Lua cli '%s': out of memory.\n", fcn->name);
Thierry FOURNIER1be34152016-12-17 12:09:51 +01008231 return 1;
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01008232 }
8233 HLUA_INIT(hlua);
8234 appctx->ctx.hlua_cli.hlua = hlua;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008235
8236 /* Create task used by signal to wakeup applets.
Ilya Shipitsind4259502020-04-08 01:07:56 +05008237 * We use the same wakeup function than the Lua applet_tcp and
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008238 * applet_http. It is absolutely compatible.
8239 */
Willy Tarreau5f4a47b2017-10-31 15:59:32 +01008240 appctx->ctx.hlua_cli.task = task_new(tid_bit);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008241 if (!appctx->ctx.hlua_cli.task) {
Thierry FOURNIERffbf5692016-12-16 11:14:06 +01008242 SEND_ERR(NULL, "Lua cli '%s': out of memory.\n", fcn->name);
Thierry FOURNIER1be34152016-12-17 12:09:51 +01008243 goto error;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008244 }
8245 appctx->ctx.hlua_cli.task->nice = 0;
8246 appctx->ctx.hlua_cli.task->context = appctx;
8247 appctx->ctx.hlua_cli.task->process = hlua_applet_wakeup;
8248
8249 /* Initialises the Lua context */
Thierry Fournierc7492592020-11-28 23:57:24 +01008250 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 +01008251 SEND_ERR(NULL, "Lua cli '%s': can't initialize Lua context.\n", fcn->name);
Thierry FOURNIER1be34152016-12-17 12:09:51 +01008252 goto error;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008253 }
8254
8255 /* The following Lua calls can fail. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008256 if (!SET_SAFE_LJMP(hlua)) {
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008257 if (lua_type(hlua->T, -1) == LUA_TSTRING)
8258 error = lua_tostring(hlua->T, -1);
8259 else
8260 error = "critical error";
8261 SEND_ERR(NULL, "Lua cli '%s': %s.\n", fcn->name, error);
8262 goto error;
8263 }
8264
8265 /* Check stack available size. */
8266 if (!lua_checkstack(hlua->T, 2)) {
8267 SEND_ERR(NULL, "Lua cli '%s': full stack.\n", fcn->name);
8268 goto error;
8269 }
8270
8271 /* Restore the function in the stack. */
Thierry Fournierc7492592020-11-28 23:57:24 +01008272 lua_rawgeti(hlua->T, LUA_REGISTRYINDEX, fcn->function_ref[hlua->state_id]);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008273
8274 /* Once the arguments parsed, the CLI is like an AppletTCP,
8275 * so push AppletTCP in the stack.
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008276 */
8277 if (!hlua_applet_tcp_new(hlua->T, appctx)) {
8278 SEND_ERR(NULL, "Lua cli '%s': full stack.\n", fcn->name);
8279 goto error;
8280 }
8281 hlua->nargs = 1;
8282
8283 /* push keywords in the stack. */
8284 for (i = 0; *args[i]; i++) {
8285 /* Check stack available size. */
8286 if (!lua_checkstack(hlua->T, 1)) {
8287 SEND_ERR(NULL, "Lua cli '%s': full stack.\n", fcn->name);
8288 goto error;
8289 }
8290 lua_pushstring(hlua->T, args[i]);
8291 hlua->nargs++;
8292 }
8293
8294 /* We must initialize the execution timeouts. */
8295 hlua->max_time = hlua_timeout_session;
8296
8297 /* At this point the execution is safe. */
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008298 RESET_SAFE_LJMP(hlua);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008299
8300 /* It's ok */
8301 return 0;
8302
8303 /* It's not ok. */
8304error:
Thierry Fournier7cbe5042020-11-28 17:02:21 +01008305 RESET_SAFE_LJMP(hlua);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008306 hlua_ctx_destroy(hlua);
Thierry FOURNIER1be34152016-12-17 12:09:51 +01008307 appctx->ctx.hlua_cli.hlua = NULL;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008308 return 1;
8309}
8310
8311static int hlua_cli_io_handler_fct(struct appctx *appctx)
8312{
8313 struct hlua *hlua;
8314 struct stream_interface *si;
8315 struct hlua_function *fcn;
8316
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01008317 hlua = appctx->ctx.hlua_cli.hlua;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008318 si = appctx->owner;
Willy Tarreau8ae4f752016-12-14 15:41:45 +01008319 fcn = appctx->ctx.hlua_cli.fcn;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008320
8321 /* If the stream is disconnect or closed, ldo nothing. */
8322 if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO))
8323 return 1;
8324
8325 /* Execute the function. */
8326 switch (hlua_ctx_resume(hlua, 1)) {
8327
8328 /* finished. */
8329 case HLUA_E_OK:
8330 return 1;
8331
8332 /* yield. */
8333 case HLUA_E_AGAIN:
8334 /* We want write. */
8335 if (HLUA_IS_WAKERESWR(hlua))
Willy Tarreaudb398432018-11-15 11:08:52 +01008336 si_rx_room_blk(si);
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008337 /* Set the timeout. */
8338 if (hlua->wake_time != TICK_ETERNITY)
8339 task_schedule(hlua->task, hlua->wake_time);
8340 return 0;
8341
8342 /* finished with error. */
8343 case HLUA_E_ERRMSG:
8344 /* Display log. */
8345 SEND_ERR(NULL, "Lua cli '%s': %s.\n",
8346 fcn->name, lua_tostring(hlua->T, -1));
8347 lua_pop(hlua->T, 1);
8348 return 1;
8349
Thierry Fournierd5b073c2018-05-21 19:42:47 +02008350 case HLUA_E_ETMOUT:
8351 SEND_ERR(NULL, "Lua converter '%s': execution timeout.\n",
8352 fcn->name);
8353 return 1;
8354
8355 case HLUA_E_NOMEM:
8356 SEND_ERR(NULL, "Lua converter '%s': out of memory error.\n",
8357 fcn->name);
8358 return 1;
8359
8360 case HLUA_E_YIELD: /* unexpected */
8361 SEND_ERR(NULL, "Lua converter '%s': yield not allowed.\n",
8362 fcn->name);
8363 return 1;
8364
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008365 case HLUA_E_ERR:
8366 /* Display log. */
8367 SEND_ERR(NULL, "Lua cli '%s' return an unknown error.\n",
8368 fcn->name);
8369 return 1;
8370
8371 default:
8372 return 1;
8373 }
8374
8375 return 1;
8376}
8377
8378static void hlua_cli_io_release_fct(struct appctx *appctx)
8379{
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01008380 hlua_ctx_destroy(appctx->ctx.hlua_cli.hlua);
Thierry FOURNIERebed6e92016-12-16 11:54:07 +01008381 appctx->ctx.hlua_cli.hlua = NULL;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008382}
8383
8384/* This function is an LUA binding used for registering
8385 * new keywords in the cli. It expects a list of keywords
8386 * which are the "path". It is limited to 5 keywords. A
8387 * description of the command, a function to be executed
8388 * for the parsing and a function for io handlers.
8389 */
8390__LJMP static int hlua_register_cli(lua_State *L)
8391{
8392 struct cli_kw_list *cli_kws;
8393 const char *message;
8394 int ref_io;
8395 int len;
Christopher Faulet3a9a12b2021-04-12 15:31:29 +02008396 struct hlua_function *fcn = NULL;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008397 int index;
8398 int i;
Thierry Fournierf67442e2020-11-28 20:41:07 +01008399 struct buffer *trash;
8400 const char *kw[5];
8401 struct cli_kw *cli_kw;
Christopher Faulet3a9a12b2021-04-12 15:31:29 +02008402 const char *errmsg;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008403
8404 MAY_LJMP(check_args(L, 3, "register_cli"));
8405
8406 /* First argument : an array of maximum 5 keywords. */
8407 if (!lua_istable(L, 1))
8408 WILL_LJMP(luaL_argerror(L, 1, "1st argument must be a table"));
8409
8410 /* Second argument : string with contextual message. */
8411 message = MAY_LJMP(luaL_checkstring(L, 2));
8412
8413 /* Third and fourth argument : lua function. */
8414 ref_io = MAY_LJMP(hlua_checkfunction(L, 3));
8415
Thierry Fournierf67442e2020-11-28 20:41:07 +01008416 /* Check for CLI service already registered */
8417 trash = get_trash_chunk();
8418 index = 0;
8419 lua_pushnil(L);
8420 memset(kw, 0, sizeof(kw));
8421 while (lua_next(L, 1) != 0) {
8422 if (index >= CLI_PREFIX_KW_NB)
8423 WILL_LJMP(luaL_argerror(L, 1, "1st argument must be a table with a maximum of 5 entries"));
8424 if (lua_type(L, -1) != LUA_TSTRING)
8425 WILL_LJMP(luaL_argerror(L, 1, "1st argument must be a table filled with strings"));
8426 kw[index] = lua_tostring(L, -1);
8427 if (index == 0)
8428 chunk_printf(trash, "%s", kw[index]);
8429 else
8430 chunk_appendf(trash, " %s", kw[index]);
8431 index++;
8432 lua_pop(L, 1);
8433 }
8434 cli_kw = cli_find_kw_exact((char **)kw);
8435 if (cli_kw != NULL) {
Thierry Fournier59f11be2020-11-29 00:37:41 +01008436 fcn = cli_kw->private;
8437 if (fcn->function_ref[hlua_state_id] != -1) {
8438 ha_warning("Trying to register CLI keyword 'lua.%s' more than once. "
8439 "This will become a hard error in version 2.5.\n", trash->area);
8440 }
8441 fcn->function_ref[hlua_state_id] = ref_io;
8442 return 0;
Thierry Fournierf67442e2020-11-28 20:41:07 +01008443 }
8444
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008445 /* Allocate and fill the sample fetch keyword struct. */
8446 cli_kws = calloc(1, sizeof(*cli_kws) + sizeof(struct cli_kw) * 2);
Christopher Faulet3a9a12b2021-04-12 15:31:29 +02008447 if (!cli_kws) {
8448 errmsg = "Lua out of memory error.";
8449 goto error;
8450 }
Thierry Fournier62a22aa2020-11-28 21:06:35 +01008451 fcn = new_hlua_function();
Christopher Faulet3a9a12b2021-04-12 15:31:29 +02008452 if (!fcn) {
8453 errmsg = "Lua out of memory error.";
8454 goto error;
8455 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008456
8457 /* Fill path. */
8458 index = 0;
8459 lua_pushnil(L);
8460 while(lua_next(L, 1) != 0) {
Christopher Faulet3a9a12b2021-04-12 15:31:29 +02008461 if (index >= 5) {
8462 errmsg = "1st argument must be a table with a maximum of 5 entries";
8463 goto error;
8464 }
8465 if (lua_type(L, -1) != LUA_TSTRING) {
8466 errmsg = "1st argument must be a table filled with strings";
8467 goto error;
8468 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008469 cli_kws->kw[0].str_kw[index] = strdup(lua_tostring(L, -1));
Christopher Faulet3a9a12b2021-04-12 15:31:29 +02008470 if (!cli_kws->kw[0].str_kw[index]) {
8471 errmsg = "Lua out of memory error.";
8472 goto error;
8473 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008474 index++;
8475 lua_pop(L, 1);
8476 }
8477
8478 /* Copy help message. */
8479 cli_kws->kw[0].usage = strdup(message);
Christopher Faulet3a9a12b2021-04-12 15:31:29 +02008480 if (!cli_kws->kw[0].usage) {
8481 errmsg = "Lua out of memory error.";
8482 goto error;
8483 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008484
8485 /* Fill fcn io handler. */
8486 len = strlen("<lua.cli>") + 1;
8487 for (i = 0; i < index; i++)
8488 len += strlen(cli_kws->kw[0].str_kw[i]) + 1;
8489 fcn->name = calloc(1, len);
Christopher Faulet3a9a12b2021-04-12 15:31:29 +02008490 if (!fcn->name) {
8491 errmsg = "Lua out of memory error.";
8492 goto error;
8493 }
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008494 strncat((char *)fcn->name, "<lua.cli", len);
8495 for (i = 0; i < index; i++) {
8496 strncat((char *)fcn->name, ".", len);
8497 strncat((char *)fcn->name, cli_kws->kw[0].str_kw[i], len);
8498 }
8499 strncat((char *)fcn->name, ">", len);
Thierry Fournierc7492592020-11-28 23:57:24 +01008500 fcn->function_ref[hlua_state_id] = ref_io;
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008501
8502 /* Fill last entries. */
8503 cli_kws->kw[0].private = fcn;
8504 cli_kws->kw[0].parse = hlua_cli_parse_fct;
8505 cli_kws->kw[0].io_handler = hlua_cli_io_handler_fct;
8506 cli_kws->kw[0].io_release = hlua_cli_io_release_fct;
8507
8508 /* Register this new converter */
8509 cli_register_kw(cli_kws);
8510
8511 return 0;
Christopher Faulet3a9a12b2021-04-12 15:31:29 +02008512
8513 error:
8514 release_hlua_function(fcn);
8515 if (cli_kws) {
8516 for (i = 0; i < index; i++)
8517 ha_free((char **)&(cli_kws->kw[0].str_kw[i]));
8518 ha_free((char **)&(cli_kws->kw[0].usage));
8519 }
8520 ha_free(&cli_kws);
8521 WILL_LJMP(luaL_error(L, errmsg));
8522 return 0; /* Never reached */
Thierry FOURNIER / OZON.IOa44fdd92016-11-13 13:19:20 +01008523}
8524
Christopher Faulet69c581a2021-05-31 08:54:04 +02008525static int hlua_filter_init_per_thread(struct proxy *px, struct flt_conf *fconf)
8526{
8527 struct hlua_flt_config *conf = fconf->conf;
8528 lua_State *L;
8529 int error, pos, state_id, flt_ref;
8530
8531 state_id = reg_flt_to_stack_id(conf->reg);
8532 L = hlua_states[state_id];
8533 pos = lua_gettop(L);
8534
8535 /* The filter parsing function */
8536 lua_rawgeti(L, LUA_REGISTRYINDEX, conf->reg->fun_ref[state_id]);
8537
8538 /* Push the filter class on the stack and resolve all callbacks */
8539 lua_rawgeti(L, LUA_REGISTRYINDEX, conf->reg->flt_ref[state_id]);
8540
8541 /* Duplicate the filter class so each filter will have its own copy */
8542 lua_newtable(L);
8543 lua_pushnil(L);
8544
8545 while (lua_next(L, pos+2)) {
8546 lua_pushvalue(L, -2);
8547 lua_insert(L, -2);
8548 lua_settable(L, -4);
8549 }
8550 flt_ref = luaL_ref(L, LUA_REGISTRYINDEX);
8551
8552 /* Remove the original lua filter class from the stack */
8553 lua_pop(L, 1);
8554
8555 /* Push the copy on the stack */
8556 lua_rawgeti(L, LUA_REGISTRYINDEX, flt_ref);
8557
8558 /* extra args are pushed in a table */
8559 lua_newtable(L);
8560 for (pos = 0; conf->args[pos]; pos++) {
8561 /* Check stack available size. */
8562 if (!lua_checkstack(L, 1)) {
8563 ha_alert("Lua filter '%s' : Lua error : full stack.", conf->reg->name);
8564 goto error;
8565 }
8566 lua_pushstring(L, conf->args[pos]);
8567 lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
8568 }
8569
8570 error = lua_pcall(L, 2, LUA_MULTRET, 0);
8571 switch (error) {
8572 case LUA_OK:
8573 /* replace the filter ref */
8574 conf->ref[state_id] = flt_ref;
8575 break;
8576 case LUA_ERRRUN:
8577 ha_alert("Lua filter '%s' : runtime error : %s", conf->reg->name, lua_tostring(L, -1));
8578 goto error;
8579 case LUA_ERRMEM:
8580 ha_alert("Lua filter '%s' : out of memory error", conf->reg->name);
8581 goto error;
8582 case LUA_ERRERR:
8583 ha_alert("Lua filter '%s' : message handler error : %s", conf->reg->name, lua_tostring(L, -1));
8584 goto error;
8585#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 503
8586 case LUA_ERRGCMM:
8587 ha_alert("Lua filter '%s' : garbage collector error : %s", conf->reg->name, lua_tostring(L, -1));
8588 goto error;
8589#endif
8590 default:
8591 ha_alert("Lua filter '%s' : unknonwn error : %s", conf->reg->name, lua_tostring(L, -1));
8592 goto error;
8593 }
8594
8595 lua_settop(L, 0);
8596 return 0;
8597
8598 error:
8599 lua_settop(L, 0);
8600 return -1;
8601}
8602
8603static void hlua_filter_deinit_per_thread(struct proxy *px, struct flt_conf *fconf)
8604{
8605 struct hlua_flt_config *conf = fconf->conf;
8606 lua_State *L;
8607 int state_id;
8608
8609 if (!conf)
8610 return;
8611
8612 state_id = reg_flt_to_stack_id(conf->reg);
8613 L = hlua_states[state_id];
8614 luaL_unref(L, LUA_REGISTRYINDEX, conf->ref[state_id]);
8615}
8616
8617static int hlua_filter_init(struct proxy *px, struct flt_conf *fconf)
8618{
8619 struct hlua_flt_config *conf = fconf->conf;
8620 int state_id = reg_flt_to_stack_id(conf->reg);
8621
8622 /* Rely on per-thread init for global scripts */
8623 if (!state_id)
8624 return hlua_filter_init_per_thread(px, fconf);
8625 return 0;
8626}
8627
8628static void hlua_filter_deinit(struct proxy *px, struct flt_conf *fconf)
8629{
8630
8631 if (fconf->conf) {
8632 struct hlua_flt_config *conf = fconf->conf;
8633 int state_id = reg_flt_to_stack_id(conf->reg);
8634 int pos;
8635
8636 /* Rely on per-thread deinit for global scripts */
8637 if (!state_id)
8638 hlua_filter_deinit_per_thread(px, fconf);
8639
8640 for (pos = 0; conf->args[pos]; pos++)
8641 free(conf->args[pos]);
8642 free(conf->args);
8643 }
8644 ha_free(&fconf->conf);
8645 ha_free((char **)&fconf->id);
8646 ha_free(&fconf->ops);
8647}
8648
8649static int hlua_filter_new(struct stream *s, struct filter *filter)
8650{
8651 struct hlua_flt_config *conf = FLT_CONF(filter);
8652 struct hlua_flt_ctx *flt_ctx = NULL;
8653 int ret = 1;
8654
8655 /* In the execution wrappers linked with a stream, the
8656 * Lua context can be not initialized. This behavior
8657 * permits to save performances because a systematic
8658 * Lua initialization cause 5% performances loss.
8659 */
8660 if (!s->hlua) {
8661 struct hlua *hlua;
8662
8663 hlua = pool_alloc(pool_head_hlua);
8664 if (!hlua) {
8665 SEND_ERR(s->be, "Lua filter '%s': can't initialize Lua context.\n",
8666 conf->reg->name);
8667 ret = 0;
8668 goto end;
8669 }
8670 HLUA_INIT(hlua);
8671 s->hlua = hlua;
8672 if (!hlua_ctx_init(s->hlua, reg_flt_to_stack_id(conf->reg), s->task, 0)) {
8673 SEND_ERR(s->be, "Lua filter '%s': can't initialize Lua context.\n",
8674 conf->reg->name);
8675 ret = 0;
8676 goto end;
8677 }
8678 }
8679
8680 flt_ctx = pool_zalloc(pool_head_hlua_flt_ctx);
8681 if (!flt_ctx) {
8682 SEND_ERR(s->be, "Lua filter '%s': can't initialize filter Lua context.\n",
8683 conf->reg->name);
8684 ret = 0;
8685 goto end;
8686 }
8687 flt_ctx->hlua[0] = pool_alloc(pool_head_hlua);
8688 flt_ctx->hlua[1] = pool_alloc(pool_head_hlua);
8689 if (!flt_ctx->hlua[0] || !flt_ctx->hlua[1]) {
8690 SEND_ERR(s->be, "Lua filter '%s': can't initialize filter Lua context.\n",
8691 conf->reg->name);
8692 ret = 0;
8693 goto end;
8694 }
8695 HLUA_INIT(flt_ctx->hlua[0]);
8696 HLUA_INIT(flt_ctx->hlua[1]);
8697 if (!hlua_ctx_init(flt_ctx->hlua[0], reg_flt_to_stack_id(conf->reg), s->task, 0) ||
8698 !hlua_ctx_init(flt_ctx->hlua[1], reg_flt_to_stack_id(conf->reg), s->task, 0)) {
8699 SEND_ERR(s->be, "Lua filter '%s': can't initialize filter Lua context.\n",
8700 conf->reg->name);
8701 ret = 0;
8702 goto end;
8703 }
8704
8705 if (!HLUA_IS_RUNNING(s->hlua)) {
8706 /* The following Lua calls can fail. */
8707 if (!SET_SAFE_LJMP(s->hlua)) {
8708 const char *error;
8709
8710 if (lua_type(s->hlua->T, -1) == LUA_TSTRING)
8711 error = lua_tostring(s->hlua->T, -1);
8712 else
8713 error = "critical error";
8714 SEND_ERR(s->be, "Lua filter '%s': %s.\n", conf->reg->name, error);
8715 ret = 0;
8716 goto end;
8717 }
8718
8719 /* Check stack size. */
8720 if (!lua_checkstack(s->hlua->T, 1)) {
8721 SEND_ERR(s->be, "Lua filter '%s': full stack.\n", conf->reg->name);
8722 ret = 0;
8723 goto end;
8724 }
8725
8726 lua_rawgeti(s->hlua->T, LUA_REGISTRYINDEX, conf->ref[s->hlua->state_id]);
8727 if (lua_getfield(s->hlua->T, -1, "new") != LUA_TFUNCTION) {
8728 SEND_ERR(s->be, "Lua filter '%s': 'new' field is not a function.\n",
8729 conf->reg->name);
8730 RESET_SAFE_LJMP(s->hlua);
8731 ret = 0;
8732 goto end;
8733 }
8734 lua_insert(s->hlua->T, -2);
8735
8736 /* Push the copy on the stack */
8737 s->hlua->nargs = 1;
8738
8739 /* We must initialize the execution timeouts. */
8740 s->hlua->max_time = hlua_timeout_session;
8741
8742 /* At this point the execution is safe. */
8743 RESET_SAFE_LJMP(s->hlua);
8744 }
8745
8746 switch (hlua_ctx_resume(s->hlua, 0)) {
8747 case HLUA_E_OK:
8748 /* Nothing returned or not a table, ignore the filter for current stream */
8749 if (!lua_gettop(s->hlua->T) || !lua_istable(s->hlua->T, 1)) {
8750 ret = 0;
8751 goto end;
8752 }
8753
8754 /* Attached the filter pointer to the ctx */
8755 lua_pushstring(s->hlua->T, "__filter");
8756 lua_pushlightuserdata(s->hlua->T, filter);
8757 lua_settable(s->hlua->T, -3);
8758
8759 /* Save a ref on the filter ctx */
8760 lua_pushvalue(s->hlua->T, 1);
8761 flt_ctx->ref = luaL_ref(s->hlua->T, LUA_REGISTRYINDEX);
8762 filter->ctx = flt_ctx;
8763 break;
8764 case HLUA_E_ERRMSG:
8765 SEND_ERR(s->be, "Lua filter '%s' : %s.\n", conf->reg->name, lua_tostring(s->hlua->T, -1));
8766 ret = -1;
8767 goto end;
8768 case HLUA_E_ETMOUT:
8769 SEND_ERR(s->be, "Lua filter '%s' : 'new' execution timeout.\n", conf->reg->name);
8770 ret = 0;
8771 goto end;
8772 case HLUA_E_NOMEM:
8773 SEND_ERR(s->be, "Lua filter '%s' : out of memory error.\n", conf->reg->name);
8774 ret = 0;
8775 goto end;
8776 case HLUA_E_AGAIN:
8777 case HLUA_E_YIELD:
8778 SEND_ERR(s->be, "Lua filter '%s': yield functions like core.tcp() or core.sleep()"
8779 " are not allowed from 'new' function.\n", conf->reg->name);
8780 ret = 0;
8781 goto end;
8782 case HLUA_E_ERR:
8783 SEND_ERR(s->be, "Lua filter '%s': 'new' returns an unknown error.\n", conf->reg->name);
8784 ret = 0;
8785 goto end;
8786 default:
8787 ret = 0;
8788 goto end;
8789 }
8790
8791 end:
8792 if (s->hlua)
8793 lua_settop(s->hlua->T, 0);
8794 if (ret <= 0) {
8795 if (flt_ctx) {
8796 hlua_ctx_destroy(flt_ctx->hlua[0]);
8797 hlua_ctx_destroy(flt_ctx->hlua[1]);
8798 pool_free(pool_head_hlua_flt_ctx, flt_ctx);
8799 }
8800 }
8801 return ret;
8802}
8803
8804static void hlua_filter_delete(struct stream *s, struct filter *filter)
8805{
8806 struct hlua_flt_ctx *flt_ctx = filter->ctx;
8807
8808 luaL_unref(s->hlua->T, LUA_REGISTRYINDEX, flt_ctx->ref);
8809 hlua_ctx_destroy(flt_ctx->hlua[0]);
8810 hlua_ctx_destroy(flt_ctx->hlua[1]);
8811 pool_free(pool_head_hlua_flt_ctx, flt_ctx);
8812 filter->ctx = NULL;
8813}
8814
8815static int hlua_filter_parse_fct(char **args, int *cur_arg, struct proxy *px,
8816 struct flt_conf *fconf, char **err, void *private)
8817{
8818 struct hlua_reg_filter *reg_flt = private;
8819 lua_State *L;
8820 struct hlua_flt_config *conf = NULL;
8821 const char *flt_id = NULL;
8822 int state_id, pos, flt_flags = 0;
8823 struct flt_ops *hlua_flt_ops = NULL;
8824
8825 state_id = reg_flt_to_stack_id(reg_flt);
8826 L = hlua_states[state_id];
8827
8828 /* Initialize the filter ops with default callbacks */
8829 hlua_flt_ops = calloc(1, sizeof(*hlua_flt_ops));
8830 if (!hlua_flt_ops) {
8831 memprintf(err, "Lua filter '%s' : Lua out of memory error", reg_flt->name);
8832 return -1;
8833 }
8834 hlua_flt_ops->init = hlua_filter_init;
8835 hlua_flt_ops->deinit = hlua_filter_deinit;
8836 if (state_id) {
8837 /* Set per-thread callback if script is loaded per-thread */
8838 hlua_flt_ops->init_per_thread = hlua_filter_init_per_thread;
8839 hlua_flt_ops->deinit_per_thread = hlua_filter_deinit_per_thread;
8840 }
8841 hlua_flt_ops->attach = hlua_filter_new;
8842 hlua_flt_ops->detach = hlua_filter_delete;
8843
8844 /* Push the filter class on the stack and resolve all callbacks */
8845 lua_rawgeti(L, LUA_REGISTRYINDEX, reg_flt->flt_ref[state_id]);
8846
8847 /*
8848 * XXX: no callback supported for now
8849 */
8850
8851 /* Get id and flags of the filter class */
8852 if (lua_getfield(L, -1, "id") == LUA_TSTRING)
8853 flt_id = lua_tostring(L, -1);
8854 lua_pop(L, 1);
8855 if (lua_getfield(L, -1, "flags") == LUA_TNUMBER)
8856 flt_flags = lua_tointeger(L, -1);
8857 lua_pop(L, 1);
8858
8859 /* Create the filter config */
8860 conf = calloc(1, sizeof(*conf));
8861 if (!conf) {
8862 memprintf(err, "Lua filter '%s' : Lua out of memory error", reg_flt->name);
8863 goto error;
8864 }
8865 conf->reg = reg_flt;
8866
8867 /* duplicate args */
8868 for (pos = 0; *args[*cur_arg + 1 + pos]; pos++);
8869 conf->args = calloc(pos + 1, sizeof(*conf->args));
8870 for (pos = 0; *args[*cur_arg + 1 + pos]; pos++)
8871 conf->args[pos] = strdup(args[*cur_arg + 1 + pos]);
8872 conf->args[pos] = NULL;
8873 *cur_arg += pos + 1;
8874
8875 fconf->id = strdup(flt_id);
8876 fconf->flags = flt_flags;
8877 fconf->conf = conf;
8878 fconf->ops = hlua_flt_ops;
8879
8880 lua_settop(L, 0);
8881 return 0;
8882
8883 error:
8884 free(hlua_flt_ops);
8885 free(conf);
8886 lua_settop(L, 0);
8887 return -1;
8888}
8889
8890/* This function is an LUA binding used for registering a filter. It expects a
8891 * fileter name used in the haproxy configuration file and a LUA function to
8892 * parse configuration arguments.
8893 */
8894__LJMP static int hlua_register_filter(lua_State *L)
8895{
8896 struct buffer *trash;
8897 struct flt_kw_list *fkl;
8898 struct flt_kw *fkw;
8899 const char *name;
8900 struct hlua_reg_filter *reg_flt= NULL;
8901 int flt_ref, fun_ref;
8902 int len;
8903
8904 MAY_LJMP(check_args(L, 3, "register_filter"));
8905
8906 /* First argument : filter name. */
8907 name = MAY_LJMP(luaL_checkstring(L, 1));
8908
8909 /* Second argument : The filter class */
8910 flt_ref = MAY_LJMP(hlua_checktable(L, 2));
8911
8912 /* Third argument : lua function. */
8913 fun_ref = MAY_LJMP(hlua_checkfunction(L, 3));
8914
8915 trash = get_trash_chunk();
8916 chunk_printf(trash, "lua.%s", name);
8917 fkw = flt_find_kw(trash->area);
8918 if (fkw != NULL) {
8919 reg_flt = fkw->private;
8920 if (reg_flt->flt_ref[hlua_state_id] != -1 || reg_flt->fun_ref[hlua_state_id] != -1) {
8921 ha_warning("Trying to register filter 'lua.%s' more than once. "
8922 "This will become a hard error in version 2.5.\n", name);
8923 }
8924 reg_flt->flt_ref[hlua_state_id] = flt_ref;
8925 reg_flt->fun_ref[hlua_state_id] = fun_ref;
8926 return 0;
8927 }
8928
8929 fkl = calloc(1, sizeof(*fkl) + sizeof(struct flt_kw) * 2);
8930 if (!fkl)
8931 goto alloc_error;
8932 fkl->scope = "HLUA";
8933
8934 reg_flt = new_hlua_reg_filter(name);
8935 if (!reg_flt)
8936 goto alloc_error;
8937
8938 reg_flt->flt_ref[hlua_state_id] = flt_ref;
8939 reg_flt->fun_ref[hlua_state_id] = fun_ref;
8940
8941 /* The filter keyword */
8942 len = strlen("lua.") + strlen(name) + 1;
8943 fkl->kw[0].kw = calloc(1, len);
8944 if (!fkl->kw[0].kw)
8945 goto alloc_error;
8946
8947 snprintf((char *)fkl->kw[0].kw, len, "lua.%s", name);
8948
8949 fkl->kw[0].parse = hlua_filter_parse_fct;
8950 fkl->kw[0].private = reg_flt;
8951 memset(&fkl->kw[1], 0, sizeof(*fkl->kw));
8952
8953 /* Register this new filter */
8954 flt_register_keywords(fkl);
8955
8956 return 0;
8957
8958 alloc_error:
8959 release_hlua_reg_filter(reg_flt);
8960 ha_free(&fkl);
8961 WILL_LJMP(luaL_error(L, "Lua out of memory error."));
8962 return 0; /* Never reached */
8963}
8964
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008965static int hlua_read_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01008966 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008967 char **err, unsigned int *timeout)
8968{
8969 const char *error;
8970
8971 error = parse_time_err(args[1], timeout, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +02008972 if (error == PARSE_TIME_OVER) {
8973 memprintf(err, "timer overflow in argument <%s> to <%s> (maximum value is 2147483647 ms or ~24.8 days)",
8974 args[1], args[0]);
8975 return -1;
8976 }
8977 else if (error == PARSE_TIME_UNDER) {
8978 memprintf(err, "timer underflow in argument <%s> to <%s> (minimum non-null value is 1 ms)",
8979 args[1], args[0]);
8980 return -1;
8981 }
8982 else if (error) {
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008983 memprintf(err, "%s: invalid timeout", args[0]);
8984 return -1;
8985 }
8986 return 0;
8987}
8988
8989static int hlua_session_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01008990 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008991 char **err)
8992{
8993 return hlua_read_timeout(args, section_type, curpx, defpx,
8994 file, line, err, &hlua_timeout_session);
8995}
8996
8997static int hlua_task_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01008998 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERbd413492015-03-03 16:52:26 +01008999 char **err)
9000{
9001 return hlua_read_timeout(args, section_type, curpx, defpx,
9002 file, line, err, &hlua_timeout_task);
9003}
9004
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009005static int hlua_applet_timeout(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01009006 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009007 char **err)
9008{
9009 return hlua_read_timeout(args, section_type, curpx, defpx,
9010 file, line, err, &hlua_timeout_applet);
9011}
9012
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01009013static int hlua_forced_yield(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01009014 const struct proxy *defpx, const char *file, int line,
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01009015 char **err)
9016{
9017 char *error;
9018
9019 hlua_nb_instruction = strtoll(args[1], &error, 10);
9020 if (*error != '\0') {
9021 memprintf(err, "%s: invalid number", args[0]);
9022 return -1;
9023 }
9024 return 0;
9025}
9026
Willy Tarreau32f61e22015-03-18 17:54:59 +01009027static int hlua_parse_maxmem(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01009028 const struct proxy *defpx, const char *file, int line,
Willy Tarreau32f61e22015-03-18 17:54:59 +01009029 char **err)
9030{
9031 char *error;
9032
9033 if (*(args[1]) == 0) {
9034 memprintf(err, "'%s' expects an integer argument (Lua memory size in MB).\n", args[0]);
9035 return -1;
9036 }
9037 hlua_global_allocator.limit = strtoll(args[1], &error, 10) * 1024L * 1024L;
9038 if (*error != '\0') {
9039 memprintf(err, "%s: invalid number %s (error at '%c')", args[0], args[1], *error);
9040 return -1;
9041 }
9042 return 0;
9043}
9044
9045
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01009046/* This function is called by the main configuration key "lua-load". It loads and
9047 * execute an lua file during the parsing of the HAProxy configuration file. It is
9048 * the main lua entry point.
9049 *
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08009050 * This function runs with the HAProxy keywords API. It returns -1 if an error
9051 * occurs, otherwise it returns 0.
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01009052 *
9053 * In some error case, LUA set an error message in top of the stack. This function
9054 * returns this error message in the HAProxy logs and pop it from the stack.
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009055 *
9056 * This function can fail with an abort() due to an Lua critical error.
9057 * We are in the configuration parsing process of HAProxy, this abort() is
9058 * tolerated.
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01009059 */
Thierry Fournierc93c15c2020-11-28 15:02:13 +01009060static int hlua_load_state(char *filename, lua_State *L, char **err)
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01009061{
9062 int error;
9063
9064 /* Just load and compile the file. */
Thierry Fournierc93c15c2020-11-28 15:02:13 +01009065 error = luaL_loadfile(L, filename);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01009066 if (error) {
Thierry Fournierc93c15c2020-11-28 15:02:13 +01009067 memprintf(err, "error in Lua file '%s': %s", filename, lua_tostring(L, -1));
9068 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01009069 return -1;
9070 }
9071
9072 /* If no syntax error where detected, execute the code. */
Thierry Fournierc93c15c2020-11-28 15:02:13 +01009073 error = lua_pcall(L, 0, LUA_MULTRET, 0);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01009074 switch (error) {
9075 case LUA_OK:
9076 break;
9077 case LUA_ERRRUN:
Thierry Fournierc93c15c2020-11-28 15:02:13 +01009078 memprintf(err, "Lua runtime error: %s\n", lua_tostring(L, -1));
9079 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01009080 return -1;
9081 case LUA_ERRMEM:
Thierry Fournierde6145f2020-11-29 00:55:53 +01009082 memprintf(err, "Lua out of memory error\n");
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01009083 return -1;
9084 case LUA_ERRERR:
Thierry Fournierc93c15c2020-11-28 15:02:13 +01009085 memprintf(err, "Lua message handler error: %s\n", lua_tostring(L, -1));
9086 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01009087 return -1;
Christopher Faulet08ed98f2020-07-28 10:33:25 +02009088#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 503
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01009089 case LUA_ERRGCMM:
Thierry Fournierc93c15c2020-11-28 15:02:13 +01009090 memprintf(err, "Lua garbage collector error: %s\n", lua_tostring(L, -1));
9091 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01009092 return -1;
Christopher Faulet08ed98f2020-07-28 10:33:25 +02009093#endif
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01009094 default:
Thierry Fournierc93c15c2020-11-28 15:02:13 +01009095 memprintf(err, "Lua unknown error: %s\n", lua_tostring(L, -1));
9096 lua_pop(L, 1);
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01009097 return -1;
9098 }
9099
9100 return 0;
9101}
9102
Thierry Fournierc93c15c2020-11-28 15:02:13 +01009103static int hlua_load(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01009104 const struct proxy *defpx, const char *file, int line,
Thierry Fournierc93c15c2020-11-28 15:02:13 +01009105 char **err)
9106{
9107 if (*(args[1]) == 0) {
9108 memprintf(err, "'%s' expects a file name as parameter.\n", args[0]);
9109 return -1;
9110 }
9111
Thierry Fournier59f11be2020-11-29 00:37:41 +01009112 /* loading for global state */
Thierry Fournierc7492592020-11-28 23:57:24 +01009113 hlua_state_id = 0;
Thierry Fournier59f11be2020-11-29 00:37:41 +01009114 ha_set_tid(0);
Thierry Fournierafc63e22020-11-28 17:06:51 +01009115 return hlua_load_state(args[1], hlua_states[0], err);
Thierry Fournierc93c15c2020-11-28 15:02:13 +01009116}
9117
Thierry Fournier59f11be2020-11-29 00:37:41 +01009118static int hlua_load_per_thread(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01009119 const struct proxy *defpx, const char *file, int line,
Thierry Fournier59f11be2020-11-29 00:37:41 +01009120 char **err)
9121{
9122 int len;
9123
9124 if (*(args[1]) == 0) {
9125 memprintf(err, "'%s' expects a file as parameter.\n", args[0]);
9126 return -1;
9127 }
9128
9129 if (per_thread_load == NULL) {
9130 /* allocate the first entry large enough to store the final NULL */
9131 per_thread_load = calloc(1, sizeof(*per_thread_load));
9132 if (per_thread_load == NULL) {
9133 memprintf(err, "out of memory error");
9134 return -1;
9135 }
9136 }
9137
9138 /* count used entries */
9139 for (len = 0; per_thread_load[len] != NULL; len++)
9140 ;
9141
9142 per_thread_load = realloc(per_thread_load, (len + 2) * sizeof(*per_thread_load));
9143 if (per_thread_load == NULL) {
9144 memprintf(err, "out of memory error");
9145 return -1;
9146 }
9147
9148 per_thread_load[len] = strdup(args[1]);
9149 per_thread_load[len + 1] = NULL;
9150
9151 if (per_thread_load[len] == NULL) {
9152 memprintf(err, "out of memory error");
9153 return -1;
9154 }
9155
9156 /* loading for thread 1 only */
9157 hlua_state_id = 1;
9158 ha_set_tid(0);
9159 return hlua_load_state(args[1], hlua_states[1], err);
9160}
9161
Tim Duesterhusc9fc9f22020-01-12 13:55:39 +01009162/* Prepend the given <path> followed by a semicolon to the `package.<type>` variable
9163 * in the given <ctx>.
9164 */
Thierry Fournier3fb9e512020-11-28 10:13:12 +01009165static int hlua_prepend_path(lua_State *L, char *type, char *path)
Tim Duesterhusc9fc9f22020-01-12 13:55:39 +01009166{
Thierry Fournier3fb9e512020-11-28 10:13:12 +01009167 lua_getglobal(L, "package"); /* push package variable */
9168 lua_pushstring(L, path); /* push given path */
9169 lua_pushstring(L, ";"); /* push semicolon */
9170 lua_getfield(L, -3, type); /* push old path */
9171 lua_concat(L, 3); /* concatenate to new path */
9172 lua_setfield(L, -2, type); /* store new path */
9173 lua_pop(L, 1); /* pop package variable */
Tim Duesterhusc9fc9f22020-01-12 13:55:39 +01009174
9175 return 0;
9176}
9177
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +01009178static int hlua_config_prepend_path(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01009179 const struct proxy *defpx, const char *file, int line,
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +01009180 char **err)
9181{
9182 char *path;
9183 char *type = "path";
Tim Duesterhus621e74a2021-01-03 20:04:36 +01009184 struct prepend_path *p = NULL;
Thierry Fournier59f11be2020-11-29 00:37:41 +01009185
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +01009186 if (too_many_args(2, args, err, NULL)) {
Tim Duesterhus621e74a2021-01-03 20:04:36 +01009187 goto err;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +01009188 }
9189
9190 if (!(*args[1])) {
9191 memprintf(err, "'%s' expects to receive a <path> as argument", args[0]);
Tim Duesterhus621e74a2021-01-03 20:04:36 +01009192 goto err;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +01009193 }
9194 path = args[1];
9195
9196 if (*args[2]) {
9197 if (strcmp(args[2], "path") != 0 && strcmp(args[2], "cpath") != 0) {
9198 memprintf(err, "'%s' expects <type> to either be 'path' or 'cpath'", args[0]);
Tim Duesterhus621e74a2021-01-03 20:04:36 +01009199 goto err;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +01009200 }
9201 type = args[2];
9202 }
9203
Thierry Fournier59f11be2020-11-29 00:37:41 +01009204 p = calloc(1, sizeof(*p));
9205 if (p == NULL) {
Tim Duesterhusf89d43a2021-01-03 20:04:37 +01009206 memprintf(err, "memory allocation failed");
Tim Duesterhus621e74a2021-01-03 20:04:36 +01009207 goto err;
Thierry Fournier59f11be2020-11-29 00:37:41 +01009208 }
9209 p->path = strdup(path);
9210 if (p->path == NULL) {
Tim Duesterhusf89d43a2021-01-03 20:04:37 +01009211 memprintf(err, "memory allocation failed");
Tim Duesterhus621e74a2021-01-03 20:04:36 +01009212 goto err2;
Thierry Fournier59f11be2020-11-29 00:37:41 +01009213 }
9214 p->type = strdup(type);
9215 if (p->type == NULL) {
Tim Duesterhusf89d43a2021-01-03 20:04:37 +01009216 memprintf(err, "memory allocation failed");
Tim Duesterhus621e74a2021-01-03 20:04:36 +01009217 goto err2;
Thierry Fournier59f11be2020-11-29 00:37:41 +01009218 }
Willy Tarreau2b718102021-04-21 07:32:39 +02009219 LIST_APPEND(&prepend_path_list, &p->l);
Thierry Fournier59f11be2020-11-29 00:37:41 +01009220
9221 hlua_prepend_path(hlua_states[0], type, path);
9222 hlua_prepend_path(hlua_states[1], type, path);
9223 return 0;
Tim Duesterhus621e74a2021-01-03 20:04:36 +01009224
9225err2:
9226 free(p->type);
9227 free(p->path);
9228err:
9229 free(p);
9230 return -1;
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +01009231}
9232
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01009233/* configuration keywords declaration */
9234static struct cfg_kw_list cfg_kws = {{ },{
Tim Duesterhusdd74b5f2020-01-12 13:55:40 +01009235 { CFG_GLOBAL, "lua-prepend-path", hlua_config_prepend_path },
Thierry FOURNIERbd413492015-03-03 16:52:26 +01009236 { CFG_GLOBAL, "lua-load", hlua_load },
Thierry Fournier59f11be2020-11-29 00:37:41 +01009237 { CFG_GLOBAL, "lua-load-per-thread", hlua_load_per_thread },
Thierry FOURNIERbd413492015-03-03 16:52:26 +01009238 { CFG_GLOBAL, "tune.lua.session-timeout", hlua_session_timeout },
9239 { CFG_GLOBAL, "tune.lua.task-timeout", hlua_task_timeout },
Thierry FOURNIER56da1012015-10-01 08:42:31 +02009240 { CFG_GLOBAL, "tune.lua.service-timeout", hlua_applet_timeout },
Thierry FOURNIERee9f8022015-03-03 17:37:37 +01009241 { CFG_GLOBAL, "tune.lua.forced-yield", hlua_forced_yield },
Willy Tarreau32f61e22015-03-18 17:54:59 +01009242 { CFG_GLOBAL, "tune.lua.maxmem", hlua_parse_maxmem },
Thierry FOURNIER6c9b52c2015-01-23 15:57:06 +01009243 { 0, NULL, NULL },
9244}};
9245
Willy Tarreau0108d902018-11-25 19:14:37 +01009246INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
9247
Christopher Fauletafd8f102018-11-08 11:34:21 +01009248
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009249/* This function can fail with an abort() due to an Lua critical error.
9250 * We are in the initialisation process of HAProxy, this abort() is
9251 * tolerated.
9252 */
Thierry Fournierb8cef172020-11-28 15:37:17 +01009253int hlua_post_init_state(lua_State *L)
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01009254{
9255 struct hlua_init_function *init;
9256 const char *msg;
9257 enum hlua_exec ret;
Thierry Fournierfd107a22016-02-19 19:57:23 +01009258 const char *error;
Thierry Fournier670db242020-11-28 10:49:59 +01009259 const char *kind;
9260 const char *trace;
9261 int return_status = 1;
9262#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
9263 int nres;
9264#endif
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01009265
Willy Tarreaucdb53462020-12-02 12:12:00 +01009266 /* disable memory limit checks if limit is not set */
9267 if (!hlua_global_allocator.limit)
9268 hlua_global_allocator.limit = ~hlua_global_allocator.limit;
9269
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05009270 /* Call post initialisation function in safe environment. */
Thierry Fournier3c539322020-11-28 16:05:05 +01009271 if (setjmp(safe_ljmp_env) != 0) {
9272 lua_atpanic(L, hlua_panic_safe);
Thierry Fournierb8cef172020-11-28 15:37:17 +01009273 if (lua_type(L, -1) == LUA_TSTRING)
9274 error = lua_tostring(L, -1);
Thierry Fournier3d4a6752016-02-19 20:53:30 +01009275 else
9276 error = "critical error";
9277 fprintf(stderr, "Lua post-init: %s.\n", error);
9278 exit(1);
Thierry Fournier3c539322020-11-28 16:05:05 +01009279 } else {
9280 lua_atpanic(L, hlua_panic_ljmp);
Thierry Fournier3d4a6752016-02-19 20:53:30 +01009281 }
Frédéric Lécaille54f2bcf2018-08-29 13:46:24 +02009282
Thierry Fournierb8cef172020-11-28 15:37:17 +01009283 hlua_fcn_post_init(L);
Thierry Fournier3d4a6752016-02-19 20:53:30 +01009284
Thierry Fournierc7492592020-11-28 23:57:24 +01009285 list_for_each_entry(init, &hlua_init_functions[hlua_state_id], l) {
Thierry Fournierb8cef172020-11-28 15:37:17 +01009286 lua_rawgeti(L, LUA_REGISTRYINDEX, init->function_ref);
Thierry Fournier670db242020-11-28 10:49:59 +01009287
9288#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 504
Thierry Fournierb8cef172020-11-28 15:37:17 +01009289 ret = lua_resume(L, L, 0, &nres);
Thierry Fournier670db242020-11-28 10:49:59 +01009290#else
Thierry Fournierb8cef172020-11-28 15:37:17 +01009291 ret = lua_resume(L, L, 0);
Thierry Fournier670db242020-11-28 10:49:59 +01009292#endif
9293 kind = NULL;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01009294 switch (ret) {
Thierry Fournier670db242020-11-28 10:49:59 +01009295
9296 case LUA_OK:
Thierry Fournierb8cef172020-11-28 15:37:17 +01009297 lua_pop(L, -1);
Thierry Fournier13d08b72020-11-28 11:02:58 +01009298 break;
Thierry Fournier670db242020-11-28 10:49:59 +01009299
9300 case LUA_ERRERR:
9301 kind = "message handler error";
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07009302 /* Fall through */
Thierry Fournier670db242020-11-28 10:49:59 +01009303 case LUA_ERRRUN:
9304 if (!kind)
9305 kind = "runtime error";
Thierry Fournierb8cef172020-11-28 15:37:17 +01009306 msg = lua_tostring(L, -1);
9307 lua_settop(L, 0); /* Empty the stack. */
9308 lua_pop(L, 1);
Christopher Fauletd09cc512021-03-24 14:48:45 +01009309 trace = hlua_traceback(L, ", ");
Thierry Fournier670db242020-11-28 10:49:59 +01009310 if (msg)
9311 ha_alert("Lua init: %s: '%s' from %s\n", kind, msg, trace);
9312 else
9313 ha_alert("Lua init: unknown %s from %s\n", kind, trace);
9314 return_status = 0;
9315 break;
9316
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01009317 default:
Thierry Fournier670db242020-11-28 10:49:59 +01009318 /* Unknown error */
9319 kind = "Unknown error";
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07009320 /* Fall through */
Thierry Fournier670db242020-11-28 10:49:59 +01009321 case LUA_YIELD:
9322 /* yield is not configured at this step, this state doesn't happen */
9323 if (!kind)
9324 kind = "yield not allowed";
Thayne McCombs8f0cc5c2021-01-07 21:35:52 -07009325 /* Fall through */
Thierry Fournier670db242020-11-28 10:49:59 +01009326 case LUA_ERRMEM:
9327 if (!kind)
9328 kind = "out of memory error";
Thierry Fournierb8cef172020-11-28 15:37:17 +01009329 lua_settop(L, 0);
9330 lua_pop(L, 1);
Christopher Fauletd09cc512021-03-24 14:48:45 +01009331 trace = hlua_traceback(L, ", ");
Thierry Fournier670db242020-11-28 10:49:59 +01009332 ha_alert("Lua init: %s: %s\n", kind, trace);
9333 return_status = 0;
9334 break;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01009335 }
Thierry Fournier670db242020-11-28 10:49:59 +01009336 if (!return_status)
9337 break;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01009338 }
Thierry Fournier3c539322020-11-28 16:05:05 +01009339
9340 lua_atpanic(L, hlua_panic_safe);
Thierry Fournier670db242020-11-28 10:49:59 +01009341 return return_status;
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01009342}
9343
Thierry Fournierb8cef172020-11-28 15:37:17 +01009344int hlua_post_init()
9345{
Thierry Fournier59f11be2020-11-29 00:37:41 +01009346 int ret;
9347 int i;
9348 int errors;
9349 char *err = NULL;
9350 struct hlua_function *fcn;
Christopher Faulet69c581a2021-05-31 08:54:04 +02009351 struct hlua_reg_filter *reg_flt;
Thierry Fournier59f11be2020-11-29 00:37:41 +01009352
Thierry Fournierb8cef172020-11-28 15:37:17 +01009353#if USE_OPENSSL
9354 /* Initialize SSL server. */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +01009355 if (socket_ssl->xprt->prepare_srv) {
Thierry Fournierb8cef172020-11-28 15:37:17 +01009356 int saved_used_backed = global.ssl_used_backend;
9357 // don't affect maxconn automatic computation
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +01009358 socket_ssl->xprt->prepare_srv(socket_ssl);
Thierry Fournierb8cef172020-11-28 15:37:17 +01009359 global.ssl_used_backend = saved_used_backed;
9360 }
9361#endif
9362
Thierry Fournierc7492592020-11-28 23:57:24 +01009363 /* Perform post init of common thread */
9364 hlua_state_id = 0;
Thierry Fournier59f11be2020-11-29 00:37:41 +01009365 ha_set_tid(0);
9366 ret = hlua_post_init_state(hlua_states[hlua_state_id]);
9367 if (ret == 0)
9368 return 0;
9369
9370 /* init remaining lua states and load files */
9371 for (hlua_state_id = 2; hlua_state_id < global.nbthread + 1; hlua_state_id++) {
9372
9373 /* set thread context */
9374 ha_set_tid(hlua_state_id - 1);
9375
9376 /* Init lua state */
9377 hlua_states[hlua_state_id] = hlua_init_state(hlua_state_id);
9378
9379 /* Load lua files */
9380 for (i = 0; per_thread_load && per_thread_load[i]; i++) {
9381 ret = hlua_load_state(per_thread_load[i], hlua_states[hlua_state_id], &err);
9382 if (ret != 0) {
9383 ha_alert("Lua init: %s\n", err);
9384 return 0;
9385 }
9386 }
9387 }
9388
9389 /* Reset thread context */
9390 ha_set_tid(0);
9391
9392 /* Execute post init for all states */
9393 for (hlua_state_id = 1; hlua_state_id < global.nbthread + 1; hlua_state_id++) {
9394
9395 /* set thread context */
9396 ha_set_tid(hlua_state_id - 1);
9397
9398 /* run post init */
9399 ret = hlua_post_init_state(hlua_states[hlua_state_id]);
9400 if (ret == 0)
9401 return 0;
9402 }
9403
9404 /* Reset thread context */
9405 ha_set_tid(0);
9406
9407 /* control functions registering. Each function must have:
9408 * - only the function_ref[0] set positive and all other to -1
9409 * - only the function_ref[0] set to -1 and all other positive
9410 * This ensure a same reference is not used both in shared
9411 * lua state and thread dedicated lua state. Note: is the case
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05009412 * reach, the shared state is priority, but the bug will be
Thierry Fournier59f11be2020-11-29 00:37:41 +01009413 * complicated to found for the end user.
9414 */
9415 errors = 0;
9416 list_for_each_entry(fcn, &referenced_functions, l) {
9417 ret = 0;
9418 for (i = 1; i < global.nbthread + 1; i++) {
9419 if (fcn->function_ref[i] == -1)
9420 ret--;
9421 else
9422 ret++;
9423 }
9424 if (abs(ret) != global.nbthread) {
9425 ha_alert("Lua function '%s' is not referenced in all thread. "
9426 "Expect function in all thread or in none thread.\n", fcn->name);
9427 errors++;
9428 continue;
9429 }
9430
9431 if ((fcn->function_ref[0] == -1) == (ret < 0)) {
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05009432 ha_alert("Lua function '%s' is referenced both ins shared Lua context (through lua-load) "
9433 "and per-thread Lua context (through lua-load-per-thread). these two context "
Thierry Fournier59f11be2020-11-29 00:37:41 +01009434 "exclusive.\n", fcn->name);
9435 errors++;
9436 }
9437 }
9438
Christopher Faulet69c581a2021-05-31 08:54:04 +02009439 /* Do the same with registered filters */
9440 list_for_each_entry(reg_flt, &referenced_filters, l) {
9441 ret = 0;
9442 for (i = 1; i < global.nbthread + 1; i++) {
9443 if (reg_flt->flt_ref[i] == -1)
9444 ret--;
9445 else
9446 ret++;
9447 }
9448 if (abs(ret) != global.nbthread) {
9449 ha_alert("Lua filter '%s' is not referenced in all thread. "
9450 "Expect function in all thread or in none thread.\n", reg_flt->name);
9451 errors++;
9452 continue;
9453 }
9454
9455 if ((reg_flt->flt_ref[0] == -1) == (ret < 0)) {
9456 ha_alert("Lua filter '%s' is referenced both ins shared Lua context (through lua-load) "
9457 "and per-thread Lua context (through lua-load-per-thread). these two context "
9458 "exclusive.\n", fcn->name);
9459 errors++;
9460 }
9461 }
9462
9463
Thierry Fournier59f11be2020-11-29 00:37:41 +01009464 if (errors > 0)
9465 return 0;
9466
Ilya Shipitsinb8888ab2021-01-06 21:20:16 +05009467 /* after this point, this global will no longer be used, so set to
Thierry Fournier59f11be2020-11-29 00:37:41 +01009468 * -1 in order to have probably a segfault if someone use it
9469 */
9470 hlua_state_id = -1;
9471
9472 return 1;
Thierry Fournierb8cef172020-11-28 15:37:17 +01009473}
9474
Willy Tarreau32f61e22015-03-18 17:54:59 +01009475/* The memory allocator used by the Lua stack. <ud> is a pointer to the
9476 * allocator's context. <ptr> is the pointer to alloc/free/realloc. <osize>
9477 * is the previously allocated size or the kind of object in case of a new
Willy Tarreaud36c7fa2020-12-02 12:26:29 +01009478 * allocation. <nsize> is the requested new size. A new allocation is
9479 * indicated by <ptr> being NULL. A free is indicated by <nsize> being
Willy Tarreaucdb53462020-12-02 12:12:00 +01009480 * zero. This one verifies that the limits are respected but is optimized
9481 * for the fast case where limits are not used, hence stats are not updated.
Willy Tarreau32f61e22015-03-18 17:54:59 +01009482 */
9483static void *hlua_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
9484{
9485 struct hlua_mem_allocator *zone = ud;
Willy Tarreaucdb53462020-12-02 12:12:00 +01009486 size_t limit, old, new;
9487
Tim Duesterhus22586522021-01-08 10:35:33 +01009488 if (unlikely(!ptr && !nsize))
9489 return NULL;
9490
Willy Tarreaucdb53462020-12-02 12:12:00 +01009491 /* a limit of ~0 means unlimited and boot complete, so there's no need
9492 * for accounting anymore.
9493 */
Christopher Fauletcc2c4f82021-03-24 14:52:24 +01009494 if (likely(~zone->limit == 0))
9495 return realloc(ptr, nsize);
Willy Tarreau32f61e22015-03-18 17:54:59 +01009496
Willy Tarreaud36c7fa2020-12-02 12:26:29 +01009497 if (!ptr)
9498 osize = 0;
Willy Tarreau32f61e22015-03-18 17:54:59 +01009499
Willy Tarreaucdb53462020-12-02 12:12:00 +01009500 /* enforce strict limits across all threads */
9501 limit = zone->limit;
9502 old = _HA_ATOMIC_LOAD(&zone->allocated);
9503 do {
9504 new = old + nsize - osize;
9505 if (unlikely(nsize && limit && new > limit))
9506 return NULL;
9507 } while (!_HA_ATOMIC_CAS(&zone->allocated, &old, new));
Willy Tarreau32f61e22015-03-18 17:54:59 +01009508
9509 ptr = realloc(ptr, nsize);
Willy Tarreaucdb53462020-12-02 12:12:00 +01009510
9511 if (unlikely(!ptr && nsize)) // failed
9512 _HA_ATOMIC_SUB(&zone->allocated, nsize - osize);
9513
9514 __ha_barrier_atomic_store();
Willy Tarreau32f61e22015-03-18 17:54:59 +01009515 return ptr;
9516}
9517
Thierry Fournierecb83c22020-11-28 15:49:44 +01009518/* This function can fail with an abort() due to a Lua critical error.
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009519 * We are in the initialisation process of HAProxy, this abort() is
9520 * tolerated.
9521 */
Thierry Fournierecb83c22020-11-28 15:49:44 +01009522lua_State *hlua_init_state(int thread_num)
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +01009523{
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +01009524 int i;
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +01009525 int idx;
9526 struct sample_fetch *sf;
Thierry FOURNIER594afe72015-03-10 23:58:30 +01009527 struct sample_conv *sc;
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +01009528 char *p;
Thierry Fournierfd107a22016-02-19 19:57:23 +01009529 const char *error_msg;
Thierry Fournier4234dbd2020-11-28 13:18:23 +01009530 void **context;
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009531 lua_State *L;
Thierry Fournier59f11be2020-11-29 00:37:41 +01009532 struct prepend_path *pp;
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +01009533
Thierry FOURNIER380d0932015-01-23 14:27:52 +01009534 /* Init main lua stack. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009535 L = lua_newstate(hlua_alloc, &hlua_global_allocator);
Thierry FOURNIER380d0932015-01-23 14:27:52 +01009536
Thierry Fournier4234dbd2020-11-28 13:18:23 +01009537 /* Initialise Lua context to NULL */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009538 context = lua_getextraspace(L);
Thierry Fournier4234dbd2020-11-28 13:18:23 +01009539 *context = NULL;
9540
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -08009541 /* From this point, until the end of the initialisation function,
Thierry FOURNIERbabae282015-09-17 11:36:37 +02009542 * the Lua function can fail with an abort. We are in the initialisation
9543 * process of HAProxy, this abort() is tolerated.
9544 */
9545
Thierry Fournier3c539322020-11-28 16:05:05 +01009546 /* Call post initialisation function in safe environment. */
9547 if (setjmp(safe_ljmp_env) != 0) {
9548 lua_atpanic(L, hlua_panic_safe);
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009549 if (lua_type(L, -1) == LUA_TSTRING)
9550 error_msg = lua_tostring(L, -1);
Thierry Fournier2f05cc62020-11-28 16:08:02 +01009551 else
9552 error_msg = "critical error";
9553 fprintf(stderr, "Lua init: %s.\n", error_msg);
9554 exit(1);
Thierry Fournier3c539322020-11-28 16:05:05 +01009555 } else {
9556 lua_atpanic(L, hlua_panic_ljmp);
Thierry Fournier2f05cc62020-11-28 16:08:02 +01009557 }
9558
Thierry FOURNIER380d0932015-01-23 14:27:52 +01009559 /* Initialise lua. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009560 luaL_openlibs(L);
Tim Duesterhus541fe1e2020-01-12 13:55:41 +01009561#define HLUA_PREPEND_PATH_TOSTRING1(x) #x
9562#define HLUA_PREPEND_PATH_TOSTRING(x) HLUA_PREPEND_PATH_TOSTRING1(x)
9563#ifdef HLUA_PREPEND_PATH
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009564 hlua_prepend_path(L, "path", HLUA_PREPEND_PATH_TOSTRING(HLUA_PREPEND_PATH));
Tim Duesterhus541fe1e2020-01-12 13:55:41 +01009565#endif
9566#ifdef HLUA_PREPEND_CPATH
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009567 hlua_prepend_path(L, "cpath", HLUA_PREPEND_PATH_TOSTRING(HLUA_PREPEND_CPATH));
Tim Duesterhus541fe1e2020-01-12 13:55:41 +01009568#endif
9569#undef HLUA_PREPEND_PATH_TOSTRING
9570#undef HLUA_PREPEND_PATH_TOSTRING1
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +01009571
Thierry Fournier59f11be2020-11-29 00:37:41 +01009572 /* Apply configured prepend path */
9573 list_for_each_entry(pp, &prepend_path_list, l)
9574 hlua_prepend_path(L, pp->type, pp->path);
9575
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +01009576 /*
9577 *
9578 * Create "core" object.
9579 *
9580 */
9581
Thierry FOURNIERa2d8c652015-03-11 17:29:39 +01009582 /* This table entry is the object "core" base. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009583 lua_newtable(L);
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +01009584
Thierry Fournierecb83c22020-11-28 15:49:44 +01009585 /* set the thread id */
9586 hlua_class_const_int(L, "thread", thread_num);
9587
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +01009588 /* Push the loglevel constants. */
Willy Tarreau80f5fae2015-02-27 16:38:20 +01009589 for (i = 0; i < NB_LOG_LEVELS; i++)
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009590 hlua_class_const_int(L, log_levels[i], i);
Thierry FOURNIER2ba18a22015-01-23 14:07:08 +01009591
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01009592 /* Register special functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009593 hlua_class_function(L, "register_init", hlua_register_init);
9594 hlua_class_function(L, "register_task", hlua_register_task);
9595 hlua_class_function(L, "register_fetches", hlua_register_fetches);
9596 hlua_class_function(L, "register_converters", hlua_register_converters);
9597 hlua_class_function(L, "register_action", hlua_register_action);
9598 hlua_class_function(L, "register_service", hlua_register_service);
9599 hlua_class_function(L, "register_cli", hlua_register_cli);
Christopher Faulet69c581a2021-05-31 08:54:04 +02009600 hlua_class_function(L, "register_filter", hlua_register_filter);
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009601 hlua_class_function(L, "yield", hlua_yield);
9602 hlua_class_function(L, "set_nice", hlua_set_nice);
9603 hlua_class_function(L, "sleep", hlua_sleep);
9604 hlua_class_function(L, "msleep", hlua_msleep);
9605 hlua_class_function(L, "add_acl", hlua_add_acl);
9606 hlua_class_function(L, "del_acl", hlua_del_acl);
9607 hlua_class_function(L, "set_map", hlua_set_map);
9608 hlua_class_function(L, "del_map", hlua_del_map);
9609 hlua_class_function(L, "tcp", hlua_socket_new);
9610 hlua_class_function(L, "log", hlua_log);
9611 hlua_class_function(L, "Debug", hlua_log_debug);
9612 hlua_class_function(L, "Info", hlua_log_info);
9613 hlua_class_function(L, "Warning", hlua_log_warning);
9614 hlua_class_function(L, "Alert", hlua_log_alert);
9615 hlua_class_function(L, "done", hlua_done);
9616 hlua_fcn_reg_core_fcn(L);
Thierry FOURNIERa4a0f3d2015-01-23 12:08:30 +01009617
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009618 lua_setglobal(L, "core");
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01009619
9620 /*
9621 *
Christopher Faulet0f3c8902020-01-31 18:57:12 +01009622 * Create "act" object.
9623 *
9624 */
9625
9626 /* This table entry is the object "act" base. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009627 lua_newtable(L);
Christopher Faulet0f3c8902020-01-31 18:57:12 +01009628
9629 /* push action return constants */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009630 hlua_class_const_int(L, "CONTINUE", ACT_RET_CONT);
9631 hlua_class_const_int(L, "STOP", ACT_RET_STOP);
9632 hlua_class_const_int(L, "YIELD", ACT_RET_YIELD);
9633 hlua_class_const_int(L, "ERROR", ACT_RET_ERR);
9634 hlua_class_const_int(L, "DONE", ACT_RET_DONE);
9635 hlua_class_const_int(L, "DENY", ACT_RET_DENY);
9636 hlua_class_const_int(L, "ABORT", ACT_RET_ABRT);
9637 hlua_class_const_int(L, "INVALID", ACT_RET_INV);
Christopher Faulet0f3c8902020-01-31 18:57:12 +01009638
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009639 hlua_class_function(L, "wake_time", hlua_set_wake_time);
Christopher Faulet2c2c2e32020-01-31 19:07:52 +01009640
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009641 lua_setglobal(L, "act");
Christopher Faulet0f3c8902020-01-31 18:57:12 +01009642
9643 /*
9644 *
Christopher Faulet69c581a2021-05-31 08:54:04 +02009645 * Create "Filter" object.
9646 *
9647 */
9648
9649 /* This table entry is the object "filter" base. */
9650 lua_newtable(L);
9651
9652 /* push flags and constants */
9653 hlua_class_const_int(L, "CONTINUE", 1);
9654 hlua_class_const_int(L, "WAIT", 0);
9655 hlua_class_const_int(L, "ERROR", -1);
9656
9657 hlua_class_const_int(L, "FLT_CFG_FL_HTX", FLT_CFG_FL_HTX);
9658
9659 lua_setglobal(L, "filter");
9660
9661 /*
9662 *
Thierry FOURNIER3def3932015-04-07 11:27:54 +02009663 * Register class Map
9664 *
9665 */
9666
9667 /* This table entry is the object "Map" base. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009668 lua_newtable(L);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02009669
9670 /* register pattern types. */
9671 for (i=0; i<PAT_MATCH_NUM; i++)
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009672 hlua_class_const_int(L, pat_match_names[i], i);
Thierry FOURNIER4dc71972017-01-28 08:33:08 +01009673 for (i=0; i<PAT_MATCH_NUM; i++) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02009674 snprintf(trash.area, trash.size, "_%s", pat_match_names[i]);
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009675 hlua_class_const_int(L, trash.area, i);
Thierry FOURNIER4dc71972017-01-28 08:33:08 +01009676 }
Thierry FOURNIER3def3932015-04-07 11:27:54 +02009677
9678 /* register constructor. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009679 hlua_class_function(L, "new", hlua_map_new);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02009680
9681 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009682 lua_newtable(L);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02009683
Ilya Shipitsind4259502020-04-08 01:07:56 +05009684 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009685 lua_pushstring(L, "__index");
9686 lua_newtable(L);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02009687
9688 /* Register . */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009689 hlua_class_function(L, "lookup", hlua_map_lookup);
9690 hlua_class_function(L, "slookup", hlua_map_slookup);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02009691
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009692 lua_rawset(L, -3);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02009693
Thierry Fournier45e78d72016-02-19 18:34:46 +01009694 /* Register previous table in the registry with reference and named entry.
9695 * The function hlua_register_metatable() pops the stack, so we
9696 * previously create a copy of the table.
9697 */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009698 lua_pushvalue(L, -1); /* Copy the -1 entry and push it on the stack. */
9699 class_map_ref = hlua_register_metatable(L, CLASS_MAP);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02009700
9701 /* Assign the metatable to the mai Map object. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009702 lua_setmetatable(L, -2);
Thierry FOURNIER3def3932015-04-07 11:27:54 +02009703
9704 /* Set a name to the table. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009705 lua_setglobal(L, "Map");
Thierry FOURNIER3def3932015-04-07 11:27:54 +02009706
9707 /*
9708 *
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01009709 * Register class Channel
9710 *
9711 */
9712
9713 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009714 lua_newtable(L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01009715
Ilya Shipitsind4259502020-04-08 01:07:56 +05009716 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009717 lua_pushstring(L, "__index");
9718 lua_newtable(L);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01009719
9720 /* Register . */
Christopher Faulet6a79fc12021-08-06 16:02:36 +02009721 hlua_class_function(L, "data", hlua_channel_get_data);
9722 hlua_class_function(L, "line", hlua_channel_get_line);
9723 hlua_class_function(L, "set", hlua_channel_set_data);
9724 hlua_class_function(L, "remove", hlua_channel_del_data);
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009725 hlua_class_function(L, "append", hlua_channel_append);
Christopher Faulet6a79fc12021-08-06 16:02:36 +02009726 hlua_class_function(L, "prepend", hlua_channel_prepend);
9727 hlua_class_function(L, "insert", hlua_channel_insert_data);
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009728 hlua_class_function(L, "send", hlua_channel_send);
9729 hlua_class_function(L, "forward", hlua_channel_forward);
Christopher Faulet6a79fc12021-08-06 16:02:36 +02009730 hlua_class_function(L, "input", hlua_channel_get_in_len);
9731 hlua_class_function(L, "output", hlua_channel_get_out_len);
9732 hlua_class_function(L, "may_recv", hlua_channel_may_recv);
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009733 hlua_class_function(L, "is_full", hlua_channel_is_full);
9734 hlua_class_function(L, "is_resp", hlua_channel_is_resp);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01009735
Christopher Faulet6a79fc12021-08-06 16:02:36 +02009736 /* Deprecated API */
9737 hlua_class_function(L, "get", hlua_channel_get);
9738 hlua_class_function(L, "dup", hlua_channel_dup);
9739 hlua_class_function(L, "getline", hlua_channel_getline);
9740 hlua_class_function(L, "get_in_len", hlua_channel_get_in_len);
9741 hlua_class_function(L, "get_out_len", hlua_channel_get_out_len);
9742
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009743 lua_rawset(L, -3);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01009744
9745 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009746 class_channel_ref = hlua_register_metatable(L, CLASS_CHANNEL);
Thierry FOURNIER5a6d3fd2015-02-09 16:38:34 +01009747
9748 /*
9749 *
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01009750 * Register class Fetches
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01009751 *
9752 */
9753
9754 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009755 lua_newtable(L);
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01009756
Ilya Shipitsind4259502020-04-08 01:07:56 +05009757 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009758 lua_pushstring(L, "__index");
9759 lua_newtable(L);
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01009760
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +01009761 /* Browse existing fetches and create the associated
9762 * object method.
9763 */
9764 sf = NULL;
9765 while ((sf = sample_fetch_getnext(sf, &idx)) != NULL) {
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +01009766 /* gL.Tua doesn't support '.' and '-' in the function names, replace it
9767 * by an underscore.
9768 */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02009769 strncpy(trash.area, sf->kw, trash.size);
9770 trash.area[trash.size - 1] = '\0';
9771 for (p = trash.area; *p; p++)
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +01009772 if (*p == '.' || *p == '-' || *p == '+')
9773 *p = '_';
9774
9775 /* Register the function. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009776 lua_pushstring(L, trash.area);
9777 lua_pushlightuserdata(L, sf);
9778 lua_pushcclosure(L, hlua_run_sample_fetch, 1);
9779 lua_rawset(L, -3);
Thierry FOURNIERd0fa5382015-02-16 20:14:51 +01009780 }
9781
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009782 lua_rawset(L, -3);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01009783
9784 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009785 class_fetches_ref = hlua_register_metatable(L, CLASS_FETCHES);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01009786
9787 /*
9788 *
Thierry FOURNIER594afe72015-03-10 23:58:30 +01009789 * Register class Converters
9790 *
9791 */
9792
9793 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009794 lua_newtable(L);
Thierry FOURNIER594afe72015-03-10 23:58:30 +01009795
9796 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009797 lua_pushstring(L, "__index");
9798 lua_newtable(L);
Thierry FOURNIER594afe72015-03-10 23:58:30 +01009799
9800 /* Browse existing converters and create the associated
9801 * object method.
9802 */
9803 sc = NULL;
9804 while ((sc = sample_conv_getnext(sc, &idx)) != NULL) {
Thierry FOURNIER594afe72015-03-10 23:58:30 +01009805 /* gL.Tua doesn't support '.' and '-' in the function names, replace it
9806 * by an underscore.
9807 */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02009808 strncpy(trash.area, sc->kw, trash.size);
9809 trash.area[trash.size - 1] = '\0';
9810 for (p = trash.area; *p; p++)
Thierry FOURNIER594afe72015-03-10 23:58:30 +01009811 if (*p == '.' || *p == '-' || *p == '+')
9812 *p = '_';
9813
9814 /* Register the function. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009815 lua_pushstring(L, trash.area);
9816 lua_pushlightuserdata(L, sc);
9817 lua_pushcclosure(L, hlua_run_sample_conv, 1);
9818 lua_rawset(L, -3);
Thierry FOURNIER594afe72015-03-10 23:58:30 +01009819 }
9820
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009821 lua_rawset(L, -3);
Thierry FOURNIER594afe72015-03-10 23:58:30 +01009822
9823 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009824 class_converters_ref = hlua_register_metatable(L, CLASS_CONVERTERS);
Thierry FOURNIER594afe72015-03-10 23:58:30 +01009825
9826 /*
9827 *
Thierry FOURNIER08504f42015-03-16 14:17:08 +01009828 * Register class HTTP
9829 *
9830 */
9831
9832 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009833 lua_newtable(L);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01009834
Ilya Shipitsind4259502020-04-08 01:07:56 +05009835 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009836 lua_pushstring(L, "__index");
9837 lua_newtable(L);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01009838
9839 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009840 hlua_class_function(L, "req_get_headers",hlua_http_req_get_headers);
9841 hlua_class_function(L, "req_del_header", hlua_http_req_del_hdr);
9842 hlua_class_function(L, "req_rep_header", hlua_http_req_rep_hdr);
9843 hlua_class_function(L, "req_rep_value", hlua_http_req_rep_val);
9844 hlua_class_function(L, "req_add_header", hlua_http_req_add_hdr);
9845 hlua_class_function(L, "req_set_header", hlua_http_req_set_hdr);
9846 hlua_class_function(L, "req_set_method", hlua_http_req_set_meth);
9847 hlua_class_function(L, "req_set_path", hlua_http_req_set_path);
9848 hlua_class_function(L, "req_set_query", hlua_http_req_set_query);
9849 hlua_class_function(L, "req_set_uri", hlua_http_req_set_uri);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01009850
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009851 hlua_class_function(L, "res_get_headers",hlua_http_res_get_headers);
9852 hlua_class_function(L, "res_del_header", hlua_http_res_del_hdr);
9853 hlua_class_function(L, "res_rep_header", hlua_http_res_rep_hdr);
9854 hlua_class_function(L, "res_rep_value", hlua_http_res_rep_val);
9855 hlua_class_function(L, "res_add_header", hlua_http_res_add_hdr);
9856 hlua_class_function(L, "res_set_header", hlua_http_res_set_hdr);
9857 hlua_class_function(L, "res_set_status", hlua_http_res_set_status);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01009858
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009859 lua_rawset(L, -3);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01009860
9861 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009862 class_http_ref = hlua_register_metatable(L, CLASS_HTTP);
Thierry FOURNIER08504f42015-03-16 14:17:08 +01009863
9864 /*
9865 *
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009866 * Register class AppletTCP
9867 *
9868 */
9869
9870 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009871 lua_newtable(L);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009872
Ilya Shipitsind4259502020-04-08 01:07:56 +05009873 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009874 lua_pushstring(L, "__index");
9875 lua_newtable(L);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009876
9877 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009878 hlua_class_function(L, "getline", hlua_applet_tcp_getline);
9879 hlua_class_function(L, "receive", hlua_applet_tcp_recv);
9880 hlua_class_function(L, "send", hlua_applet_tcp_send);
9881 hlua_class_function(L, "set_priv", hlua_applet_tcp_set_priv);
9882 hlua_class_function(L, "get_priv", hlua_applet_tcp_get_priv);
9883 hlua_class_function(L, "set_var", hlua_applet_tcp_set_var);
9884 hlua_class_function(L, "unset_var", hlua_applet_tcp_unset_var);
9885 hlua_class_function(L, "get_var", hlua_applet_tcp_get_var);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009886
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009887 lua_settable(L, -3);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009888
9889 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009890 class_applet_tcp_ref = hlua_register_metatable(L, CLASS_APPLET_TCP);
Thierry FOURNIERf0a64b62015-09-19 12:36:17 +02009891
9892 /*
9893 *
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009894 * Register class AppletHTTP
9895 *
9896 */
9897
9898 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009899 lua_newtable(L);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009900
Ilya Shipitsind4259502020-04-08 01:07:56 +05009901 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009902 lua_pushstring(L, "__index");
9903 lua_newtable(L);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009904
9905 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009906 hlua_class_function(L, "set_priv", hlua_applet_http_set_priv);
9907 hlua_class_function(L, "get_priv", hlua_applet_http_get_priv);
9908 hlua_class_function(L, "set_var", hlua_applet_http_set_var);
9909 hlua_class_function(L, "unset_var", hlua_applet_http_unset_var);
9910 hlua_class_function(L, "get_var", hlua_applet_http_get_var);
9911 hlua_class_function(L, "getline", hlua_applet_http_getline);
9912 hlua_class_function(L, "receive", hlua_applet_http_recv);
9913 hlua_class_function(L, "send", hlua_applet_http_send);
9914 hlua_class_function(L, "add_header", hlua_applet_http_addheader);
9915 hlua_class_function(L, "set_status", hlua_applet_http_status);
9916 hlua_class_function(L, "start_response", hlua_applet_http_start_response);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009917
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009918 lua_settable(L, -3);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009919
9920 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009921 class_applet_http_ref = hlua_register_metatable(L, CLASS_APPLET_HTTP);
Thierry FOURNIERa30b5db2015-09-18 09:04:27 +02009922
9923 /*
9924 *
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01009925 * Register class TXN
9926 *
9927 */
9928
9929 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009930 lua_newtable(L);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01009931
Ilya Shipitsind4259502020-04-08 01:07:56 +05009932 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009933 lua_pushstring(L, "__index");
9934 lua_newtable(L);
Thierry FOURNIERbb53c7b2015-03-11 18:28:02 +01009935
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01009936 /* Register Lua functions. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009937 hlua_class_function(L, "set_priv", hlua_set_priv);
9938 hlua_class_function(L, "get_priv", hlua_get_priv);
9939 hlua_class_function(L, "set_var", hlua_set_var);
9940 hlua_class_function(L, "unset_var", hlua_unset_var);
9941 hlua_class_function(L, "get_var", hlua_get_var);
9942 hlua_class_function(L, "done", hlua_txn_done);
9943 hlua_class_function(L, "reply", hlua_txn_reply_new);
9944 hlua_class_function(L, "set_loglevel", hlua_txn_set_loglevel);
9945 hlua_class_function(L, "set_tos", hlua_txn_set_tos);
9946 hlua_class_function(L, "set_mark", hlua_txn_set_mark);
9947 hlua_class_function(L, "set_priority_class", hlua_txn_set_priority_class);
9948 hlua_class_function(L, "set_priority_offset", hlua_txn_set_priority_offset);
9949 hlua_class_function(L, "deflog", hlua_txn_deflog);
9950 hlua_class_function(L, "log", hlua_txn_log);
9951 hlua_class_function(L, "Debug", hlua_txn_log_debug);
9952 hlua_class_function(L, "Info", hlua_txn_log_info);
9953 hlua_class_function(L, "Warning", hlua_txn_log_warning);
9954 hlua_class_function(L, "Alert", hlua_txn_log_alert);
Thierry FOURNIER05c0b8a2015-02-25 11:43:21 +01009955
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009956 lua_rawset(L, -3);
Thierry FOURNIER65f34c62015-02-16 20:11:43 +01009957
9958 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009959 class_txn_ref = hlua_register_metatable(L, CLASS_TXN);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009960
9961 /*
9962 *
Christopher Faulet700d9e82020-01-31 12:21:52 +01009963 * Register class reply
9964 *
9965 */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009966 lua_newtable(L);
9967 lua_pushstring(L, "__index");
9968 lua_newtable(L);
9969 hlua_class_function(L, "set_status", hlua_txn_reply_set_status);
9970 hlua_class_function(L, "add_header", hlua_txn_reply_add_header);
9971 hlua_class_function(L, "del_header", hlua_txn_reply_del_header);
9972 hlua_class_function(L, "set_body", hlua_txn_reply_set_body);
9973 lua_settable(L, -3); /* Sets the __index entry. */
9974 class_txn_reply_ref = luaL_ref(L, LUA_REGISTRYINDEX);
Christopher Faulet700d9e82020-01-31 12:21:52 +01009975
9976
9977 /*
9978 *
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009979 * Register class Socket
9980 *
9981 */
9982
9983 /* Create and fill the metatable. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009984 lua_newtable(L);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009985
Ilya Shipitsind4259502020-04-08 01:07:56 +05009986 /* Create and fill the __index entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009987 lua_pushstring(L, "__index");
9988 lua_newtable(L);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +01009989
Baptiste Assmann84bb4932015-03-02 21:40:06 +01009990#ifdef USE_OPENSSL
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009991 hlua_class_function(L, "connect_ssl", hlua_socket_connect_ssl);
Baptiste Assmann84bb4932015-03-02 21:40:06 +01009992#endif
Thierry Fournier1eac28f2020-11-28 12:26:24 +01009993 hlua_class_function(L, "connect", hlua_socket_connect);
9994 hlua_class_function(L, "send", hlua_socket_send);
9995 hlua_class_function(L, "receive", hlua_socket_receive);
9996 hlua_class_function(L, "close", hlua_socket_close);
9997 hlua_class_function(L, "getpeername", hlua_socket_getpeername);
9998 hlua_class_function(L, "getsockname", hlua_socket_getsockname);
9999 hlua_class_function(L, "setoption", hlua_socket_setoption);
10000 hlua_class_function(L, "settimeout", hlua_socket_settimeout);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010010001
Thierry Fournier1eac28f2020-11-28 12:26:24 +010010002 lua_rawset(L, -3); /* Push the last 2 entries in the table at index -3 */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010010003
10004 /* Register the garbage collector entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010010005 lua_pushstring(L, "__gc");
10006 lua_pushcclosure(L, hlua_socket_gc, 0);
10007 lua_rawset(L, -3); /* Push the last 2 entries in the table at index -3 */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010010008
10009 /* Register previous table in the registry with reference and named entry. */
Thierry Fournier1eac28f2020-11-28 12:26:24 +010010010 class_socket_ref = hlua_register_metatable(L, CLASS_SOCKET);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010010011
Thierry Fournieraafc7772020-12-04 11:47:47 +010010012 lua_atpanic(L, hlua_panic_safe);
10013
10014 return L;
10015}
10016
10017void hlua_init(void) {
10018 int i;
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +010010019 char *errmsg;
Thierry Fournieraafc7772020-12-04 11:47:47 +010010020#ifdef USE_OPENSSL
10021 struct srv_kw *kw;
10022 int tmp_error;
10023 char *error;
10024 char *args[] = { /* SSL client configuration. */
10025 "ssl",
10026 "verify",
10027 "none",
10028 NULL
10029 };
10030#endif
10031
10032 /* Init post init function list head */
10033 for (i = 0; i < MAX_THREADS + 1; i++)
10034 LIST_INIT(&hlua_init_functions[i]);
10035
10036 /* Init state for common/shared lua parts */
10037 hlua_state_id = 0;
10038 ha_set_tid(0);
10039 hlua_states[0] = hlua_init_state(0);
10040
10041 /* Init state 1 for thread 0. We have at least one thread. */
10042 hlua_state_id = 1;
10043 ha_set_tid(0);
10044 hlua_states[1] = hlua_init_state(1);
10045
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010010046 /* Proxy and server configuration initialisation. */
William Lallemand6bb77b92021-07-28 15:48:16 +020010047 socket_proxy = alloc_new_proxy("LUA-SOCKET", PR_CAP_FE|PR_CAP_BE|PR_CAP_INT, &errmsg);
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +010010048 if (!socket_proxy) {
10049 fprintf(stderr, "Lua init: %s\n", errmsg);
10050 exit(1);
10051 }
10052 proxy_preset_defaults(socket_proxy);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010010053
10054 /* Init TCP server: unchanged parameters */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010010055 socket_tcp = new_server(socket_proxy);
10056 if (!socket_tcp) {
10057 fprintf(stderr, "Lua init: failed to allocate tcp server socket\n");
10058 exit(1);
10059 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010010060
10061#ifdef USE_OPENSSL
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010010062 /* Init TCP server: unchanged parameters */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010010063 socket_ssl = new_server(socket_proxy);
10064 if (!socket_ssl) {
10065 fprintf(stderr, "Lua init: failed to allocate ssl server socket\n");
10066 exit(1);
10067 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010010068
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010010069 socket_ssl->use_ssl = 1;
10070 socket_ssl->xprt = xprt_get(XPRT_SSL);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010010071
Bertrand Jacquin80839ff2021-01-21 19:14:46 +000010072 for (i = 0; args[i] != NULL; i++) {
10073 if ((kw = srv_find_kw(args[i])) != NULL) { /* Maybe it's registered server keyword */
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010010074 /*
10075 *
10076 * If the keyword is not known, we can search in the registered
Joseph Herlantb8f9c5e2018-11-15 10:06:08 -080010077 * server keywords. This is useful to configure special SSL
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010010078 * features like client certificates and ssl_verify.
10079 *
10080 */
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010010081 tmp_error = kw->parse(args, &i, socket_proxy, socket_ssl, &error);
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010010082 if (tmp_error != 0) {
10083 fprintf(stderr, "INTERNAL ERROR: %s\n", error);
10084 abort(); /* This must be never arrives because the command line
10085 not editable by the user. */
10086 }
Bertrand Jacquin80839ff2021-01-21 19:14:46 +000010087 i += kw->skip;
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010010088 }
10089 }
Thierry FOURNIER7e7ac322015-02-16 19:27:16 +010010090#endif
Thierry Fournier75933d42016-01-21 09:30:18 +010010091
Thierry FOURNIER6f1fd482015-01-23 14:06:13 +010010092}
Willy Tarreaubb57d942016-12-21 19:04:56 +010010093
Tim Duesterhusd0c0ca22020-07-04 11:53:26 +020010094static void hlua_deinit()
10095{
Willy Tarreau186f3762020-12-04 11:48:12 +010010096 int thr;
Christopher Faulet69c581a2021-05-31 08:54:04 +020010097 struct hlua_reg_filter *reg_flt, *reg_flt_bck;
10098
10099 list_for_each_entry_safe(reg_flt, reg_flt_bck, &referenced_filters, l)
10100 release_hlua_reg_filter(reg_flt);
Willy Tarreau186f3762020-12-04 11:48:12 +010010101
10102 for (thr = 0; thr < MAX_THREADS+1; thr++) {
10103 if (hlua_states[thr])
10104 lua_close(hlua_states[thr]);
10105 }
Willy Tarreau430bf4a2021-03-04 09:45:32 +010010106
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010010107 free_server(socket_tcp);
Willy Tarreau430bf4a2021-03-04 09:45:32 +010010108
Willy Tarreau0f143af2021-03-05 10:41:48 +010010109#ifdef USE_OPENSSL
Amaury Denoyelle704ba1d2021-03-24 17:57:47 +010010110 free_server(socket_ssl);
Willy Tarreau0f143af2021-03-05 10:41:48 +010010111#endif
Amaury Denoyelle239fdbf2021-03-24 10:22:03 +010010112
10113 free_proxy(socket_proxy);
Tim Duesterhusd0c0ca22020-07-04 11:53:26 +020010114}
10115
10116REGISTER_POST_DEINIT(hlua_deinit);
10117
Willy Tarreau80713382018-11-26 10:19:54 +010010118static void hlua_register_build_options(void)
10119{
Willy Tarreaubb57d942016-12-21 19:04:56 +010010120 char *ptr = NULL;
Willy Tarreau80713382018-11-26 10:19:54 +010010121
Willy Tarreaubb57d942016-12-21 19:04:56 +010010122 memprintf(&ptr, "Built with Lua version : %s", LUA_RELEASE);
10123 hap_register_build_opts(ptr, 1);
10124}
Willy Tarreau80713382018-11-26 10:19:54 +010010125
10126INITCALL0(STG_REGISTER, hlua_register_build_options);